Whamcloud - gitweb
324535142ee5916031bdb0b1ed164ff022030d30
[fs/lustre-release.git] / lustre / utils / mount_lustre.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  Copyright (C) 2002 Cluster File Systems, Inc.
5  *   Author: Robert Read <rread@clusterfs.com>
6  *   Author: Nathan Rutman <nathan@clusterfs.com>
7  *
8  *   This file is part of Lustre, http://www.lustre.org.
9  *
10  *   Lustre is free software; you can redistribute it and/or
11  *   modify it under the terms of version 2 of the GNU General Public
12  *   License as published by the Free Software Foundation.
13  *
14  *   Lustre is distributed in the hope that it will be useful,
15  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *   GNU General Public License for more details.
18  *
19  *   You should have received a copy of the GNU General Public License
20  *   along with Lustre; if not, write to the Free Software
21  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22  *
23  */
24
25
26 #define _GNU_SOURCE
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <unistd.h>
30 #include <fcntl.h>
31 #include <errno.h>
32 #include <string.h>
33 #include <sys/mount.h>
34 #include <mntent.h>
35 #include <getopt.h>
36 #include <sys/utsname.h>
37
38 #include "obdctl.h"
39
40 int          verbose;
41 int          nomtab;
42 int          fake;
43 int          force;
44 static char *progname = NULL;
45
46 void usage(FILE *out)
47 {
48         fprintf(out, "%s v1.%d\n", progname, LMD_MAGIC & 0xFF);
49         fprintf(out, "usage: %s <mgmtnid>[:<altmgtnid>...]:/<filesystem>[/<cfgname>] <mountpt> "
50                 "[-fhnv] [-o mntopt]\n", progname);
51         fprintf(out, "\t<mdsnode>: nid of MDS (config) node\n"
52                 "\t<filesystem>: name of the Lustre filesystem (e.g. lustre1)\n"
53                 "\t<cfgname>: name of client config (e.g. client)\n"
54                 "\t<mountpt>: filesystem mountpoint (e.g. /mnt/lustre)\n"
55                 "\t-f|--fake: fake mount (updates /etc/mtab)\n"
56                 "\t--force: force mount even if already in /etc/mtab\n"
57                 "\t-h|--help: print this usage message\n"
58                 "\t-n|--nomtab: do not update /etc/mtab after mount\n"
59                 "\t-v|--verbose: print verbose config settings\n");
60         exit((out != stdout) ? EINVAL : 0);
61 }
62
63 static int check_mtab_entry(char *spec, char *mtpt, char *type)
64 {
65         FILE *fp;
66         struct mntent *mnt;
67
68         if (force)
69                 return (0);
70
71         fp = setmntent(MOUNTED, "r");
72         if (fp == NULL)
73                 return(0);
74
75         while ((mnt = getmntent(fp)) != NULL) {
76                 if (strcmp(mnt->mnt_fsname, spec) == 0 &&
77                         strcmp(mnt->mnt_dir, mtpt) == 0 &&
78                         strcmp(mnt->mnt_type, type) == 0) {
79                         fprintf(stderr, "%s: according to %s %s is "
80                                 "already mounted on %s\n",
81                                 progname, MOUNTED, spec, mtpt);
82                         return(1); /* or should we return an error? */
83                 }
84         }
85         endmntent(fp);
86
87         return(0);
88 }
89
90 static int
91 update_mtab_entry(char *spec, char *mtpt, char *type, char *opts,
92                   int flags, int freq, int pass)
93 {
94         FILE *fp;
95         struct mntent mnt;
96         int rc = 0;
97
98         mnt.mnt_fsname = spec;
99         mnt.mnt_dir = mtpt;
100         mnt.mnt_type = type;
101         mnt.mnt_opts = opts ? opts : "";
102         mnt.mnt_freq = freq;
103         mnt.mnt_passno = pass;
104
105         fp = setmntent(MOUNTED, "a+");
106         if (fp == NULL) {
107                 fprintf(stderr, "%s: setmntent(%s): %s:",
108                         progname, MOUNTED, strerror (errno));
109                 rc = 16;
110         } else {
111                 if ((addmntent(fp, &mnt)) == 1) {
112                         fprintf(stderr, "%s: addmntent: %s:",
113                                 progname, strerror (errno));
114                         rc = 16;
115                 }
116                 endmntent(fp);
117         }
118
119         return rc;
120 }
121
122 /* Get rid of symbolic hostnames for tcp */
123 #define MAXNIDSTR 1024
124 static char *convert_hostnames(char *s1)
125 {
126         char *converted, *s2 = 0, *c;
127         int left = MAXNIDSTR;
128         lnet_nid_t nid;
129         
130         converted = malloc(left);
131         c = converted;
132         while ((left > 0) && ((s2 = strsep(&s1, ",:")))) {
133                 nid = libcfs_str2nid(s2);
134                 if (nid == LNET_NID_ANY) {
135                         if (*s2 == '/') 
136                                 /* end of nids */
137                                 break;
138                         fprintf(stderr, "%s: Can't parse NID '%s'\n", 
139                                 progname, s2);
140                         free(converted);
141                         return NULL;
142                 }
143                 if (LNET_NETTYP(LNET_NIDNET(nid)) == SOCKLND) {
144                         __u32 addr = LNET_NIDADDR(nid);
145                         c += snprintf(c, left, "%u.%u.%u.%u@%s%u:",
146                                       (addr >> 24) & 0xff, (addr >> 16) & 0xff,
147                                       (addr >> 8) & 0xff, addr & 0xff,
148                                       libcfs_lnd2str(SOCKLND), 
149                                       LNET_NETNUM(LNET_NIDNET(nid)));
150                 } else {
151                         c += snprintf(converted, left, "%s:", s2);
152                 }
153                 left = converted + MAXNIDSTR - c;
154         }
155         snprintf(c, left, "%s", s2);
156         return converted;
157 }
158
159 /*****************************************************************************
160  *
161  * This part was cribbed from util-linux/mount/mount.c.  There was no clear
162  * license information, but many other files in the package are identified as
163  * GNU GPL, so it's a pretty safe bet that was their intent.
164  *
165  ****************************************************************************/
166 struct opt_map {
167         const char *opt;        /* option name */
168         int skip;               /* skip in mtab option string */
169         int inv;                /* true if flag value should be inverted */
170         int mask;               /* flag mask value */
171 };
172
173 /* These flags are parsed by mount, not lustre */
174 static const struct opt_map opt_map[] = {
175   { "defaults", 0, 0, 0         },      /* default options */
176   { "rw",       1, 1, MS_RDONLY },      /* read-write */
177   { "ro",       0, 0, MS_RDONLY },      /* read-only */
178   { "exec",     0, 1, MS_NOEXEC },      /* permit execution of binaries */
179   { "noexec",   0, 0, MS_NOEXEC },      /* don't execute binaries */
180   { "suid",     0, 1, MS_NOSUID },      /* honor suid executables */
181   { "nosuid",   0, 0, MS_NOSUID },      /* don't honor suid executables */
182   { "dev",      0, 1, MS_NODEV  },      /* interpret device files  */
183   { "nodev",    0, 0, MS_NODEV  },      /* don't interpret devices */
184   { "async",    0, 1, MS_SYNCHRONOUS},  /* asynchronous I/O */
185   { "auto",     0, 0, 0         },      /* Can be mounted using -a */
186   { "noauto",   0, 0, 0         },      /* Can  only be mounted explicitly */
187   { "nousers",  0, 1, 0         },      /* Forbid ordinary user to mount */
188   { "nouser",   0, 1, 0         },      /* Forbid ordinary user to mount */
189   { "noowner",  0, 1, 0         },      /* Device owner has no special privs */
190   { "_netdev",  0, 0, 0         },      /* Device accessible only via network */
191   { "flock",    0, 0, 0         },      /* Enable flock support */
192   { "noflock",  1, 1, 0         },      /* Disable flock support */
193   { "user_xattr",   0, 0, 0     },      /* Enable get/set user xattr */
194   { "nouser_xattr", 1, 1, 0     },      /* Disable user xattr */
195   { "nosvc",    0, 0, 0         },      /* Only start MGS/MGC, no other services */
196   { NULL,       0, 0, 0         }
197 };
198 /****************************************************************************/
199
200 static int parse_one_option(const char *check, int *flagp)
201 {
202         const struct opt_map *opt;
203
204         for (opt = &opt_map[0]; opt->opt != NULL; opt++) {
205                 if (strncmp(check, opt->opt, strlen(opt->opt)) == 0) {
206                         if (!opt->mask) 
207                                 return -1;
208                         if (opt->inv)
209                                 *flagp &= ~(opt->mask);
210                         else
211                                 *flagp |= opt->mask;
212                         return 1;
213                 }
214         }
215         fprintf(stderr, "%s: unknown option '%s', continuing\n", progname,
216                 check);
217         return 0;
218 }
219
220 int parse_options(char *orig_options, int *flagp)
221 {
222         char *options, *opt, *nextopt;
223
224         options = calloc(strlen(orig_options) + 1, 1);
225         *flagp = 0;
226         nextopt = orig_options;
227         while ((opt = strsep(&nextopt, ","))) {
228                 if (!*opt) 
229                         /* empty option */
230                         continue;
231                 if (parse_one_option(opt, flagp) > 0)
232                         continue;
233                 /* no mount flags set, so pass this on as an option */
234                 if (*options)
235                         strcat(options, ",");
236                 strcat(options, opt);
237         }
238         /* options will always be <= orig_options */
239         strcpy(orig_options, options);
240         free(options);
241         return 0;
242 }
243
244
245 int main(int argc, char *const argv[])
246 {
247         char default_options[] = "";
248         char *source, *target, *options = default_options, *optcopy;
249         int i, nargs = 3, opt, rc, flags, optlen;
250         static struct option long_opt[] = {
251                 {"fake", 0, 0, 'f'},
252                 {"force", 0, 0, 1},
253                 {"help", 0, 0, 'h'},
254                 {"nomtab", 0, 0, 'n'},
255                 {"options", 1, 0, 'o'},
256                 {"verbose", 0, 0, 'v'},
257                 {0, 0, 0, 0}
258         };
259
260         progname = strrchr(argv[0], '/');
261         progname = progname ? progname + 1 : argv[0];
262
263         while ((opt = getopt_long(argc, argv, "fhno:v",
264                                   long_opt, NULL)) != EOF){
265                 switch (opt) {
266                 case 1:
267                         ++force;
268                         printf("force: %d\n", force);
269                         nargs++;
270                         break;
271                 case 'f':
272                         ++fake;
273                         printf("fake: %d\n", fake);
274                         nargs++;
275                         break;
276                 case 'h':
277                         usage(stdout);
278                         break;
279                 case 'n':
280                         ++nomtab;
281                         printf("nomtab: %d\n", nomtab);
282                         nargs++;
283                         break;
284                 case 'o':
285                         options = optarg;
286                         nargs++;
287                         break;
288                 case 'v':
289                         ++verbose;
290                         printf("verbose: %d\n", verbose);
291                         nargs++;
292                         break;
293                 default:
294                         fprintf(stderr, "%s: unknown option '%c'\n",
295                                 progname, opt);
296                         usage(stderr);
297                         break;
298                 }
299         }
300
301         if (optind + 2 > argc) {
302                 fprintf(stderr, "%s: too few arguments\n", progname);
303                 usage(stderr);
304         }
305
306         source = convert_hostnames(argv[optind]);
307         target = argv[optind + 1];
308
309         if (!source) {
310                 usage(stderr);
311         }
312
313         if (verbose) {
314                 for (i = 0; i < argc; i++)
315                         printf("arg[%d] = %s\n", i, argv[i]);
316                 printf("source = %s, target = %s\n", source, target);
317         }
318
319         if (!force && check_mtab_entry(source, target, "lustre"))
320                 return(EEXIST);
321
322         rc = parse_options(options, &flags); 
323         if (rc) {
324                 fprintf(stderr, "%s: can't parse options: %s\n",
325                         progname, options);
326                 return(EINVAL);
327         }
328
329         rc = access(target, F_OK);
330         if (rc) {
331                 rc = errno;
332                 fprintf(stderr, "%s: %s inaccessible: %s\n", progname, target,
333                         strerror(errno));
334                 return rc;
335         }
336
337         /* In Linux 2.4, the target device doesn't get passed to any of our
338            functions.  So we'll stick it on the end of the options. */
339         optlen = strlen(options) + strlen(",device=") + strlen(source) + 1;
340         optcopy = malloc(optlen);
341         strcpy(optcopy, options);
342         if (*optcopy)
343                 strcat(optcopy, ",");
344         strcat(optcopy, "device=");
345         strcat(optcopy, source);
346
347         if (verbose) 
348                 printf("mounting devce %s at %s, flags=%#x options=%s\n",
349                        source, target, flags, optcopy);
350         
351         if (!fake)
352                 /* flags and target get to lustre_get_sb, but not 
353                    lustre_fill_super.  Lustre ignores the flags, but mount 
354                    does not. */
355                 rc = mount(source, target, "lustre", flags, (void *)optcopy);
356
357         if (rc) {
358                 fprintf(stderr, "%s: mount(%s, %s) failed: %s\n", progname, 
359                         source, target, strerror(errno));
360                 if (errno == ENODEV)
361                         fprintf(stderr, "Are the lustre modules loaded?\n"
362                              "Check /etc/modules.conf and /proc/filesystems\n");
363                 rc = 32;
364         } else if (!nomtab) {
365                 rc = update_mtab_entry(source, target, "lustre", options,0,0,0);
366         }
367
368         free(optcopy);
369         free(source);
370         return rc;
371 }