Whamcloud - gitweb
Branch b1_4_newconfig2
[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 <linux/lustre_disk.h>
39 #include <portals/ptlctl.h>
40 #include "obdctl.h"
41
42 int          verbose;
43 int          nomtab;
44 int          fake;
45 int          force;
46 static char *progname = NULL;
47
48 void usage(FILE *out)
49 {
50         fprintf(out, "usage: %s <mdsnode>:/<mdsname>/<cfgname> <mountpt> "
51                 "[-fhnv] [-o mntopt]\n", progname);
52         fprintf(out, "\t<mdsnode>: nid of MDS (config) node\n"
53                 "\t<mdsname>: name of MDS service (e.g. mds1)\n"
54                 "\t<cfgname>: name of client config (e.g. client)\n"
55                 "\t<mountpt>: filesystem mountpoint (e.g. /mnt/lustre)\n"
56                 "\t-f|--fake: fake mount (updates /etc/mtab)\n"
57                 "\t--force: force mount even if already in /etc/mtab\n"
58                 "\t-h|--help: print this usage message\n"
59                 "\t-n|--nomtab: do not update /etc/mtab after mount\n"
60                 "\t-v|--verbose: print verbose config settings\n");
61         exit(out != stdout);
62 }
63
64 int get_os_version()
65 {
66         static int version = 0;
67
68         if (!version) {
69                 int fd;
70                 char release[4] = "";
71
72                 fd = open("/proc/sys/kernel/osrelease", O_RDONLY);
73                 if (fd < 0) 
74                         fprintf(stderr, "Warning: Can't resolve kernel version,"
75                         " assuming 2.6\n");
76                 else {
77                         read(fd, release, 4);
78                         close(fd);
79                 }
80                 if (strncmp(release, "2.4.", 4) == 0) 
81                         version = 24;
82                 else 
83                         version = 26;
84         }
85         return version;
86 }
87
88 static int load_module(char *module_name)
89 {
90         char buf[256];
91         int rc;
92         
93         if (verbose)
94                 printf("loading %s\n", module_name);
95         sprintf(buf, "/sbin/modprobe %s", module_name);
96         rc = system(buf);
97         if (rc) {
98                 fprintf(stderr, "%s: failed to modprobe %s: %s\n", 
99                         progname, module_name, strerror(errno));
100                 fprintf(stderr, "Check /etc/modules.conf\n");
101         }
102         return rc;
103 }
104
105 static int load_modules(struct lustre_mount_data *lmd)
106 {
107         int rc = 0;
108
109         if (lmd_is_client(lmd)) {
110                 rc = load_module("lustre");
111         } else {
112                 rc = load_module("mds");
113                 if (rc) return rc;
114                 rc = load_module("oss");
115         }
116         return rc;
117 }
118
119 static int check_mtab_entry(char *spec, char *mtpt, char *type)
120 {
121         FILE *fp;
122         struct mntent *mnt;
123
124         if (force)
125                 return (0);
126
127         fp = setmntent(MOUNTED, "r");
128         if (fp == NULL)
129                 return(0);
130
131         while ((mnt = getmntent(fp)) != NULL) {
132                 if (strcmp(mnt->mnt_fsname, spec) == 0 &&
133                         strcmp(mnt->mnt_dir, mtpt) == 0 &&
134                         strcmp(mnt->mnt_type, type) == 0) {
135                         fprintf(stderr, "%s: according to %s %s is "
136                                 "already mounted on %s\n",
137                                 progname, MOUNTED, spec, mtpt);
138                         return(1); /* or should we return an error? */
139                 }
140         }
141         endmntent(fp);
142
143         return(0);
144 }
145
146 static int
147 update_mtab_entry(char *spec, char *mtpt, char *type, char *opts,
148                   int flags, int freq, int pass)
149 {
150         FILE *fp;
151         struct mntent mnt;
152         int rc = 0;
153
154         mnt.mnt_fsname = spec;
155         mnt.mnt_dir = mtpt;
156         mnt.mnt_type = type;
157         mnt.mnt_opts = opts ? opts : "";
158         mnt.mnt_freq = freq;
159         mnt.mnt_passno = pass;
160
161         fp = setmntent(MOUNTED, "a+");
162         if (fp == NULL) {
163                 fprintf(stderr, "%s: setmntent(%s): %s:",
164                         progname, MOUNTED, strerror (errno));
165                 rc = 16;
166         } else {
167                 if ((addmntent(fp, &mnt)) == 1) {
168                         fprintf(stderr, "%s: addmntent: %s:",
169                                 progname, strerror (errno));
170                         rc = 16;
171                 }
172                 endmntent(fp);
173         }
174
175         return rc;
176 }
177
178 int
179 init_options(struct lustre_mount_data *lmd)
180 {
181         memset(lmd, 0, sizeof(*lmd));
182         //gethostname(lmd->lmd_hostname, sizeof lmd->lmd_hostname);
183         //lmd->lmd_server_nid = PTL_NID_ANY;
184         //ptl_parse_nid(&lmd->lmd_nid, lmd->lmd_hostname);
185         //lmd->lmd_port = 988;    /* XXX define LUSTRE_DEFAULT_PORT */
186         //lmd->lmd_nal = SOCKNAL;
187         //ptl_parse_ipaddr(&lmd->lmd_ipaddr, lmd->lmd_hostname); 
188         lmd->lmd_magic = LMD_MAGIC;
189         lmd->lmd_flags = LMD_FLG_MNTCNF;
190         lmd->lmd_mgmtnid.primary = PTL_NID_ANY;
191         lmd->lmd_mgmtnid.backup  = PTL_NID_ANY;
192         return 0;
193 }
194
195 int
196 print_options(struct lustre_mount_data *lmd)
197 {
198         printf("mgmt primary nid: %x\n", /*libcfs_nid2str*/(lmd->lmd_mgmtnid.primary));
199         printf("mgmt backup nid:  %x\n", /*libcfs_nid2str*/(lmd->lmd_mgmtnid.backup));
200         printf("device:           %s\n", lmd->lmd_dev);
201         printf("mount point:      %s\n", lmd->lmd_mtpt);
202         printf("options:          %s\n", lmd->lmd_opts);
203         printf("flags:            %x\n", lmd->lmd_flags);
204         if (lmd_is_client(lmd)) 
205                 printf("CLIENT\n");
206         else 
207                 printf("SERVER\n");
208
209         return 0;
210 }
211
212 /*****************************************************************************
213  *
214  * This part was cribbed from util-linux/mount/mount.c.  There was no clear
215  * license information, but many other files in the package are identified as
216  * GNU GPL, so it's a pretty safe bet that was their intent.
217  *
218  ****************************************************************************/
219 struct opt_map {
220         const char *opt;        /* option name */
221         int skip;               /* skip in mtab option string */
222         int inv;                /* true if flag value should be inverted */
223         int mask;               /* flag mask value */
224 };
225
226 static const struct opt_map opt_map[] = {
227   { "defaults", 0, 0, 0         },      /* default options */
228   { "rw",       1, 1, MS_RDONLY },      /* read-write */
229   { "ro",       0, 0, MS_RDONLY },      /* read-only */
230   { "exec",     0, 1, MS_NOEXEC },      /* permit execution of binaries */
231   { "noexec",   0, 0, MS_NOEXEC },      /* don't execute binaries */
232   { "suid",     0, 1, MS_NOSUID },      /* honor suid executables */
233   { "nosuid",   0, 0, MS_NOSUID },      /* don't honor suid executables */
234   { "dev",      0, 1, MS_NODEV  },      /* interpret device files  */
235   { "nodev",    0, 0, MS_NODEV  },      /* don't interpret devices */
236   { "async",    0, 1, MS_SYNCHRONOUS},  /* asynchronous I/O */
237   { "auto",     0, 0, 0         },      /* Can be mounted using -a */
238   { "noauto",   0, 0, 0         },      /* Can  only be mounted explicitly */
239   { "nousers",  0, 1, 0         },      /* Forbid ordinary user to mount */
240   { "nouser",   0, 1, 0         },      /* Forbid ordinary user to mount */
241   { "noowner",  0, 1, 0         },      /* Device owner has no special privs */
242   { "_netdev",  0, 0, 0         },      /* Device accessible only via network */
243   { NULL,       0, 0, 0         }
244 };
245 /****************************************************************************/
246
247 static int parse_one_option(const char *check, int *flagp)
248 {
249         const struct opt_map *opt;
250
251         for (opt = &opt_map[0]; opt->opt != NULL; opt++) {
252                 if (strcmp(check, opt->opt) == 0) {
253                         if (opt->inv)
254                                 *flagp &= ~(opt->mask);
255                         else
256                                 *flagp |= opt->mask;
257                         return 1;
258                 }
259         }
260         return 0;
261 }
262
263 int parse_options(char *options, struct lustre_mount_data *lmd, int *flagp)
264 {
265         int val;
266         char *opt, *opteq;
267
268         *flagp = 0;
269         /* parsing ideas here taken from util-linux/mount/nfsmount.c */
270         for (opt = strtok(options, ","); opt; opt = strtok(NULL, ",")) {
271                 if ((opteq = strchr(opt, '='))) {
272                         val = atoi(opteq + 1);
273                         *opteq = '\0';
274                         if (0) {
275                                 /* All the network options have gone :)) */
276                         } else {
277                                 fprintf(stderr, "%s: unknown option '%s'\n",
278                                         progname, opt);
279                                 usage(stderr);
280                         }
281                 } else {
282                         if (parse_one_option(opt, flagp))
283                                 continue;
284
285                         fprintf(stderr, "%s: unknown option '%s'\n",
286                                 progname, opt);
287                         usage(stderr);
288                 }
289         }
290         return 0;
291 }
292
293 int
294 build_data(char *source, char *target, char *options, 
295            struct lustre_mount_data *lmd, int *flagp)
296 {
297         char  buf[1024];
298         char *nid = NULL;
299         char *devname = NULL;
300         char *s;
301         int   rc;
302
303         if (lmd_bad_magic(lmd))
304                 return 4;
305
306         if (strlen(source) >= sizeof(buf)) {
307                 fprintf(stderr, "%s: device name too long\n",
308                         progname);
309                 return 1;
310         }
311         strcpy(buf, source);
312
313         if ((s = strchr(buf, ':'))) {
314                 /* Client */
315                 if (verbose)
316                         printf("CLIENT\n");
317                 lmd->lmd_flags |= LMD_FLG_CLIENT;
318
319                 /* <mgmtnid>[,<alt mgmtnid>]:/fsname[/fsetname[/subdir/]]
320                    nid=mgmtnid, devname=fsname */
321                 nid = buf;
322                 *s = '\0';
323                 while (*++s == '/') /*spin*/;
324                 devname = s;
325
326                 rc = parse_options(options, lmd, flagp);
327                 if (rc)
328                         return rc;
329
330                 if (lmd->lmd_mgmtnid.primary != PTL_NID_ANY)
331                         /* In case it was defined as -o mgmtnode= */
332                         //FIXME set_nid_pair(&lmd->lmd_mgmtnid, nid);
333                 if (lmd->lmd_mgmtnid.primary == PTL_NID_ANY) {
334                         fprintf(stderr, "%s: can't parse nid '%s'\n",
335                                 progname, nid);
336                         return 1;
337                 }
338         } else {
339                 /* Server */
340                 if (verbose)
341                         printf("SERVER\n");
342
343                 devname = source;
344
345                 /* We have to keep the loop= option in the mtab file
346                    in order for umount to free the loop device. The strtok
347                    in parse_options terminates the options list at the first
348                    comma, so we're saving a local copy here. */
349                 strcpy(buf, options);
350                 rc = parse_options(options, lmd, flagp); 
351                 if (rc)
352                         return rc;
353                 strcpy(options, buf);
354
355                 // move into lustre: rc = read_mount_options(source, target, lmd);
356         }
357
358         if (strlen(devname) + 1 > sizeof(lmd->lmd_dev)) {
359                 fprintf(stderr, "%s: device name too long\n", progname);
360                 return(1);
361         }
362         strcpy(lmd->lmd_dev, devname);
363
364         if (strlen(target) + 1 > sizeof(lmd->lmd_mtpt)) {
365                 fprintf(stderr, "%s: mount point too long\n", progname);
366                 return(1);
367         }
368         strcpy(lmd->lmd_mtpt, target);
369         
370         if (verbose)
371                 print_options(lmd);
372         return 0;
373 }
374
375 int main(int argc, char *const argv[])
376 {
377         char *source, *target, *options = "";
378         int i, nargs = 3, opt, rc, flags;
379         struct lustre_mount_data lmd;
380         static struct option long_opt[] = {
381                 {"fake", 0, 0, 'f'},
382                 {"force", 0, 0, 1},
383                 {"help", 0, 0, 'h'},
384                 {"nomtab", 0, 0, 'n'},
385                 {"options", 1, 0, 'o'},
386                 {"verbose", 0, 0, 'v'},
387                 {0, 0, 0, 0}
388         };
389
390         progname = strrchr(argv[0], '/');
391         progname = progname ? progname + 1 : argv[0];
392
393         while ((opt = getopt_long(argc, argv, "fhno:v",
394                                   long_opt, NULL)) != EOF){
395                 switch (opt) {
396                 case 1:
397                         ++force;
398                         printf("force: %d\n", force);
399                         nargs++;
400                         break;
401                 case 'f':
402                         ++fake;
403                         printf("fake: %d\n", fake);
404                         nargs++;
405                         break;
406                 case 'h':
407                         usage(stdout);
408                         break;
409                 case 'n':
410                         ++nomtab;
411                         printf("nomtab: %d\n", nomtab);
412                         nargs++;
413                         break;
414                 case 'o':
415                         options = optarg;
416                         nargs++;
417                         break;
418                 case 'v':
419                         ++verbose;
420                         printf("verbose: %d\n", verbose);
421                         nargs++;
422                         break;
423                 default:
424                         fprintf(stderr, "%s: unknown option '%c'\n",
425                                 progname, opt);
426                         usage(stderr);
427                         break;
428                 }
429         }
430
431         if (optind + 2 > argc) {
432                 fprintf(stderr, "%s: too few arguments\n", progname);
433                 usage(stderr);
434         }
435
436         source = argv[optind];
437         target = argv[optind + 1];
438
439         if (verbose) {
440                 for (i = 0; i < argc; i++)
441                         printf("arg[%d] = %s\n", i, argv[i]);
442                 printf("source = %s, target = %s\n", source, target);
443         }
444
445         if (!force && check_mtab_entry(source, target, "lustre"))
446                 exit(32);
447
448         init_options(&lmd);
449         rc = build_data(source, target, options, &lmd, &flags);
450         if (rc) {
451                 exit(1);
452         }
453
454         rc = access(target, F_OK);
455         if (rc) {
456                 rc = errno;
457                 fprintf(stderr, "%s: %s inaccessible: %s\n", progname, target,
458                         strerror(errno));
459                 return 1;
460         }
461
462         /* FIXME remove */
463         if ((rc = load_modules(&lmd))) {
464                 return rc;
465         }
466
467         if (!fake)
468                 /* flags and target get to lustre_get_sb, but not 
469                    lustre_fill_super.  Lustre ignores the flags, but mount 
470                    does not. */
471                 rc = mount(source, target, "lustre", flags, (void *)&lmd);
472         if (rc) {
473                 fprintf(stderr, "%s: mount(%s, %s) failed: %s\n", source,
474                         target, progname, strerror(errno));
475                 if (errno == ENODEV)
476                         fprintf(stderr, "Are the lustre modules loaded?\n"
477                              "Check /etc/modules.conf and /proc/filesystems\n");
478                 rc = 32;
479         } else if (!nomtab) {
480                 rc = update_mtab_entry(source, target, "lustre", options,0,0,0);
481         }
482
483         return rc;
484 }