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 "obdctl.h"
39 #include <portals/ptlctl.h>
40 #include <linux/lustre_disk.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                 if (lmd->u.srv.disk_type & MDS_DISK_TYPE)
113                         rc = load_module("mds");
114                 if (rc) return rc;
115                 if (lmd->u.srv.disk_type & OST_DISK_TYPE) 
116                         rc = load_module("oss");
117         }
118         return rc;
119 }
120
121 static int check_mtab_entry(char *spec, char *mtpt, char *type)
122 {
123         FILE *fp;
124         struct mntent *mnt;
125
126         if (force)
127                 return (0);
128
129         fp = setmntent(MOUNTED, "r");
130         if (fp == NULL)
131                 return(0);
132
133         while ((mnt = getmntent(fp)) != NULL) {
134                 if (strcmp(mnt->mnt_fsname, spec) == 0 &&
135                         strcmp(mnt->mnt_dir, mtpt) == 0 &&
136                         strcmp(mnt->mnt_type, type) == 0) {
137                         fprintf(stderr, "%s: according to %s %s is "
138                                 "already mounted on %s\n",
139                                 progname, MOUNTED, spec, mtpt);
140                         return(1); /* or should we return an error? */
141                 }
142         }
143         endmntent(fp);
144
145         return(0);
146 }
147
148 static int
149 update_mtab_entry(char *spec, char *mtpt, char *type, char *opts,
150                   int flags, int freq, int pass)
151 {
152         FILE *fp;
153         struct mntent mnt;
154         int rc = 0;
155
156         mnt.mnt_fsname = spec;
157         mnt.mnt_dir = mtpt;
158         mnt.mnt_type = type;
159         mnt.mnt_opts = opts ? opts : "";
160         mnt.mnt_freq = freq;
161         mnt.mnt_passno = pass;
162
163         fp = setmntent(MOUNTED, "a+");
164         if (fp == NULL) {
165                 fprintf(stderr, "%s: setmntent(%s): %s:",
166                         progname, MOUNTED, strerror (errno));
167                 rc = 16;
168         } else {
169                 if ((addmntent(fp, &mnt)) == 1) {
170                         fprintf(stderr, "%s: addmntent: %s:",
171                                 progname, strerror (errno));
172                         rc = 16;
173                 }
174                 endmntent(fp);
175         }
176
177         return rc;
178 }
179
180 int
181 init_options(struct lustre_mount_data *lmd)
182 {
183         memset(lmd, 0, sizeof(*lmd));
184         //gethostname(lmd->lmd_hostname, sizeof lmd->lmd_hostname);
185         //lmd->lmd_server_nid = PTL_NID_ANY;
186         //ptl_parse_nid(&lmd->lmd_nid, lmd->lmd_hostname);
187         //lmd->lmd_port = 988;    /* XXX define LUSTRE_DEFAULT_PORT */
188         //lmd->lmd_nal = SOCKNAL;
189         //ptl_parse_ipaddr(&lmd->lmd_ipaddr, lmd->lmd_hostname); 
190         //lmd->u.cli.lmd_async = 0;
191         lmd->lmd_magic = LMD_MAGIC;
192         lmd->lmd_nid = PTL_NID_ANY;
193         return 0;
194 }
195
196 int
197 print_options(struct lustre_mount_data *lmd)
198 {
199         printf("nid:             %s\n", libcfs_nid2str(lmd->lmd_nid));
200         
201         if (lmd_is_client(lmd)) {
202                 printf("CLIENT\n");
203                 printf("mds:             %s\n", lmd->u.cli.lmd_mds);
204                 printf("profile:         %s\n", lmd->u.cli.lmd_profile);
205         } else {
206                 printf("SERVER\n");
207                 printf("service type:    %x\n", lmd->u.srv.disk_type);
208                 printf("device:          %s\n", lmd->u.srv.lmd_source);
209                 printf("fs type:         %s\n", lmd->u.srv.lmd_fstype);
210                 printf("fs opts:         %s\n", lmd->u.srv.lmd_fsopts);
211         }
212
213         return 0;
214 }
215
216 /*****************************************************************************
217  *
218  * This part was cribbed from util-linux/mount/mount.c.  There was no clear
219  * license information, but many other files in the package are identified as
220  * GNU GPL, so it's a pretty safe bet that was their intent.
221  *
222  ****************************************************************************/
223 struct opt_map {
224         const char *opt;        /* option name */
225         int skip;               /* skip in mtab option string */
226         int inv;                /* true if flag value should be inverted */
227         int mask;               /* flag mask value */
228 };
229
230 static const struct opt_map opt_map[] = {
231   { "defaults", 0, 0, 0         },      /* default options */
232   { "rw",       1, 1, MS_RDONLY },      /* read-write */
233   { "ro",       0, 0, MS_RDONLY },      /* read-only */
234   { "exec",     0, 1, MS_NOEXEC },      /* permit execution of binaries */
235   { "noexec",   0, 0, MS_NOEXEC },      /* don't execute binaries */
236   { "suid",     0, 1, MS_NOSUID },      /* honor suid executables */
237   { "nosuid",   0, 0, MS_NOSUID },      /* don't honor suid executables */
238   { "dev",      0, 1, MS_NODEV  },      /* interpret device files  */
239   { "nodev",    0, 0, MS_NODEV  },      /* don't interpret devices */
240   { "async",    0, 1, MS_SYNCHRONOUS},  /* asynchronous I/O */
241   { "auto",     0, 0, 0         },      /* Can be mounted using -a */
242   { "noauto",   0, 0, 0         },      /* Can  only be mounted explicitly */
243   { "nousers",  0, 1, 0         },      /* Forbid ordinary user to mount */
244   { "nouser",   0, 1, 0         },      /* Forbid ordinary user to mount */
245   { "noowner",  0, 1, 0         },      /* Device owner has no special privs */
246   { "_netdev",  0, 0, 0         },      /* Device accessible only via network */
247   { NULL,       0, 0, 0         }
248 };
249 /****************************************************************************/
250
251 static int parse_one_option(const char *check, int *flagp)
252 {
253         const struct opt_map *opt;
254
255         for (opt = &opt_map[0]; opt->opt != NULL; opt++) {
256                 if (strcmp(check, opt->opt) == 0) {
257                         if (opt->inv)
258                                 *flagp &= ~(opt->mask);
259                         else
260                                 *flagp |= opt->mask;
261                         return 1;
262                 }
263         }
264         return 0;
265 }
266
267 int parse_options(char *options, struct lustre_mount_data *lmd, int *flagp)
268 {
269         int val;
270         char *opt, *opteq;
271
272         *flagp = 0;
273         /* parsing ideas here taken from util-linux/mount/nfsmount.c */
274         for (opt = strtok(options, ","); opt; opt = strtok(NULL, ",")) {
275                 if ((opteq = strchr(opt, '='))) {
276                         val = atoi(opteq + 1);
277                         *opteq = '\0';
278                         if (0) {
279                                 /* All the network options have gone :)) */
280                         } else {
281                                 fprintf(stderr, "%s: unknown option '%s'\n",
282                                         progname, opt);
283                                 usage(stderr);
284                         }
285                 } else {
286                         if (parse_one_option(opt, flagp))
287                                 continue;
288
289                         fprintf(stderr, "%s: unknown option '%s'\n",
290                                 progname, opt);
291                         usage(stderr);
292                 }
293         }
294         return 0;
295 }
296
297 int read_mount_options(char *source, char *target, 
298                        struct lustre_mount_data *lmd)
299 {
300         char cmd[512];
301         char opfilenm[255];
302         FILE *opfile;
303         __u32 lddmagic;
304         int ret;
305         
306         if ( strlen(lmd->u.srv.lmd_source) == 0) {
307                 strcpy(lmd->u.srv.lmd_source, source);
308                 sprintf(cmd, "mount -t ext3  %s %s", lmd->u.srv.lmd_source, target);
309         }
310         else
311                 sprintf(cmd, "mount -o loop  %s %s", lmd->u.srv.lmd_source, target);
312            
313         ret = system(cmd);
314         if (ret) {
315                 fprintf(stderr, "Unable to mount %s\n", lmd->u.srv.lmd_source);
316                 return errno;
317         }
318
319         /* mounted, now read the options file */
320         sprintf(opfilenm, "%s/%s", target, MOUNTOPTS_FILE_NAME);
321         opfile = fopen(opfilenm, "r");
322         if (!opfile) {
323                 fprintf(stderr,"Unable to open options file %s: %s\n", 
324                         opfilenm, strerror(errno));
325                 ret = errno;
326                 goto out_umnt;
327         }
328
329         ret = fscanf(opfile, "%x\n", &lddmagic);
330         if (ret < 1) {
331                 fprintf(stderr, "Can't read options file %s\n", opfilenm);
332                 goto out_close;
333         }
334         if (lddmagic != LDD_MAGIC) {
335                 fprintf(stderr, "Bad magic in options file %s\n", opfilenm);
336                 goto out_close;
337         }
338
339         fscanf(opfile, "%s\n", lmd->u.srv.lmd_fstype);
340         fscanf(opfile, "%s\n", lmd->u.srv.lmd_fsopts);
341         fscanf(opfile, "%x\n", &lmd->u.srv.disk_type);
342         //fread(&data->mgt.host, sizeof(data->mgt.host), 1, opfile);
343         ret = 0;
344
345 out_close:
346         fclose(opfile);
347 out_umnt:
348         sprintf(cmd, "umount %s", target);
349         system(cmd);
350         return ret;
351 }
352
353 int
354 build_data(char *source, char *target, char *options, 
355            struct lustre_mount_data *lmd, int *flagp)
356 {
357         char  buf[1024];
358         char *nid = NULL;
359         char *mgmt = NULL;
360         char *s;
361         int   rc;
362
363         if (lmd_bad_magic(lmd))
364                 return 4;
365
366         if (strlen(source) >= sizeof(buf)) {
367                 fprintf(stderr, "%s: nid:/fsname argument too long\n",
368                         progname);
369                 return 1;
370         }
371         strcpy(buf, source);
372
373         if ((s = strchr(buf, ':'))) {
374                 /* Client */
375                 if (verbose)
376                         printf("CLIENT\n");
377                 lmd->lmd_type = 
378
379                 nid = buf;
380                 *s = '\0';
381
382                 while (*++s == '/')
383                         ;
384                 mgmt = s;
385
386                 rc = parse_options(options, lmd, flagp);
387                 if (rc)
388                         return rc;
389
390                 lmd->lmd_nid = libcfs_str2nid(nid);
391                 if (lmd->lmd_nid == PTL_NID_ANY) {
392                         fprintf(stderr, "%s: can't parse nid '%s'\n",
393                                 progname, libcfs_nid2str(lmd->lmd_nid));
394                         return 1;
395                 }
396
397                 if (strlen(mgmt) + 4 > sizeof(lmd->lmd_mgmt)) {
398                         fprintf(stderr, "%s: mgmt name too long\n", progname);
399                         return(1);
400                 }
401                 strcpy(lmd->lmd_mds, mgmt);
402         } else {
403                 /* Server */
404                 if (verbose)
405                         printf("SERVER\n");
406                 lmd->lmd_magic = LMD_SERVER_MAGIC;
407
408                 if (strlen(source) + 1 > sizeof(lmd->u.srv.lmd_source)) {
409                         fprintf(stderr, "%s: source name too long\n", progname);
410                         return(1);
411                 }
412
413                 /* We have to keep the loop= option in the mtab file
414                    in order for umount to free the loop device. The strtok
415                    in parse_options terminates the options list at the first
416                    comma, so we're saving a local copy here. */
417                 strcpy(buf, options);
418                 rc = parse_options(options, lmd, flagp); 
419                 fprintf(stderr, "source = %s \n",lmd->u.srv.lmd_source);
420                 print_options(lmd);
421                 if (rc)
422                         return rc;
423                 strcpy(options, buf);
424
425                 rc = read_mount_options(source, target, lmd);
426                 if (rc)
427                         return rc;
428         }
429
430         if (verbose)
431                 print_options(lmd);
432         return 0;
433 }
434
435 int main(int argc, char *const argv[])
436 {
437         char *source, *target, *options = "";
438         int i, nargs = 3, opt, rc, flags;
439         struct lustre_mount_data lmd;
440         static struct option long_opt[] = {
441                 {"fake", 0, 0, 'f'},
442                 {"force", 0, 0, 1},
443                 {"help", 0, 0, 'h'},
444                 {"nomtab", 0, 0, 'n'},
445                 {"options", 1, 0, 'o'},
446                 {"verbose", 0, 0, 'v'},
447                 {0, 0, 0, 0}
448         };
449
450         progname = strrchr(argv[0], '/');
451         progname = progname ? progname + 1 : argv[0];
452
453         while ((opt = getopt_long(argc, argv, "fhno:v",
454                                   long_opt, NULL)) != EOF){
455                 switch (opt) {
456                 case 1:
457                         ++force;
458                         printf("force: %d\n", force);
459                         nargs++;
460                         break;
461                 case 'f':
462                         ++fake;
463                         printf("fake: %d\n", fake);
464                         nargs++;
465                         break;
466                 case 'h':
467                         usage(stdout);
468                         break;
469                 case 'n':
470                         ++nomtab;
471                         printf("nomtab: %d\n", nomtab);
472                         nargs++;
473                         break;
474                 case 'o':
475                         options = optarg;
476                         nargs++;
477                         break;
478                 case 'v':
479                         ++verbose;
480                         printf("verbose: %d\n", verbose);
481                         nargs++;
482                         break;
483                 default:
484                         fprintf(stderr, "%s: unknown option '%c'\n",
485                                 progname, opt);
486                         usage(stderr);
487                         break;
488                 }
489         }
490
491         if (optind + 2 > argc) {
492                 fprintf(stderr, "%s: too few arguments\n", progname);
493                 usage(stderr);
494         }
495
496         source = argv[optind];
497         target = argv[optind + 1];
498
499         if (verbose) {
500                 for (i = 0; i < argc; i++)
501                         printf("arg[%d] = %s\n", i, argv[i]);
502                 printf("source = %s, target = %s\n", source, target);
503         }
504
505         if (!force && check_mtab_entry(source, target, "lustre"))
506                 exit(32);
507
508         init_options(&lmd);
509         rc = build_data(source, target, options, &lmd, &flags);
510         if (rc) {
511                 exit(1);
512         }
513
514         rc = access(target, F_OK);
515         if (rc) {
516                 rc = errno;
517                 fprintf(stderr, "%s: %s inaccessible: %s\n", progname, target,
518                         strerror(errno));
519                 return 1;
520         }
521
522         if ((rc = load_modules(&lmd))) {
523                 return rc;
524         }
525
526         if (!fake)
527                 rc = mount(source, target, "lustre", flags, (void *)&lmd);
528         if (rc) {
529                 fprintf(stderr, "%s: mount(%s, %s) failed: %s\n", source,
530                         target, progname, strerror(errno));
531                 if (errno == ENODEV)
532                         fprintf(stderr, "Are the lustre modules loaded?\n"
533                              "Check /etc/modules.conf and /proc/filesystems\n");
534                 rc = 32;
535         } else if (!nomtab) {
536                 rc = update_mtab_entry(source, target, "lustre", options,0,0,0);
537         }
538
539         return rc;
540 }