Whamcloud - gitweb
* Added check that network parses OK in llmount.c
[fs/lustre-release.git] / lustre / utils / llmount.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  *
7  *   This file is part of Lustre, http://www.lustre.org.
8  *
9  *   Lustre is free software; you can redistribute it and/or
10  *   modify it under the terms of version 2 of the GNU General Public
11  *   License as published by the Free Software Foundation.
12  *
13  *   Lustre is distributed in the hope that it will be useful,
14  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *   GNU General Public License for more details.
17  *
18  *   You should have received a copy of the GNU General Public License
19  *   along with Lustre; if not, write to the Free Software
20  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  *
22  */
23
24
25 #define _GNU_SOURCE
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <unistd.h>
29 #include <errno.h>
30 #include <string.h>
31 #include <sys/mount.h>
32 #include <mntent.h>
33 #include <getopt.h>
34
35 #include "obdctl.h"
36 #include <portals/ptlctl.h>
37
38 int verbose;
39 int nomtab;
40 int fake;
41 int force;
42 static char *progname = NULL;
43
44 typedef struct {
45         ptl_nid_t gw;
46         ptl_nid_t lo;
47         ptl_nid_t hi;
48 } llmount_route_t;
49
50 #define MAX_ROUTES  1024
51 int route_index;
52 ptl_nid_t lmd_cluster_id = 0;
53 llmount_route_t routes[MAX_ROUTES];
54
55 void usage(FILE *out)
56 {
57         fprintf(out, "usage: %s <mdsnode>:/<mdsname>/<cfgname> <mountpt> "
58                 "[-fhnv] [-o mntopt]\n", progname);
59         fprintf(out, "\t<mdsnode>: hostname or nid of MDS (config) node\n"
60                 "\t<mdsname>: name of MDS service (e.g. mds1)\n"
61                 "\t<cfgname>: name of client config (e.g. client)\n"
62                 "\t<mountpt>: filesystem mountpoint (e.g. /mnt/lustre)\n"
63                 "\t-f|--fake: fake mount (updates /etc/mtab)\n"
64                 "\t--force: force mount even if already in /etc/mtab\n"
65                 "\t-h|--help: print this usage message\n"
66                 "\t-n|--nomtab: do not update /etc/mtab after mount\n"
67                 "\t-v|--verbose: print verbose config settings\n"
68                 "\t-o: filesystem mount options:\n"
69                 "\t\tnettype={tcp,elan,iibnal,lonal}: network type\n"
70                 "\t\tcluster_id=0xNNNN: cluster this node is part of\n"
71                 "\t\tlocal_nid=0xNNNN: client ID (default ipaddr or nodenum)\n"
72                 "\t\tserver_nid=0xNNNN: server node ID (default mdsnode)\n"
73                 "\t\tport=NNN: server port (default 988 for tcp)\n"
74                 "\t\troute=<gw>[-<gw>]:<low>[-<high>]: portal route to MDS\n");
75         exit(out != stdout);
76 }
77
78 static int check_mtab_entry(char *spec, char *mtpt, char *type)
79 {
80         FILE *fp;
81         struct mntent *mnt;
82
83         if (!force) {
84                 fp = setmntent(MOUNTED, "r");
85                 if (fp == NULL)
86                         return(0);
87
88                 while ((mnt = getmntent(fp)) != NULL) {
89                         if (strcmp(mnt->mnt_fsname, spec) == 0 &&
90                             strcmp(mnt->mnt_dir, mtpt) == 0 &&
91                             strcmp(mnt->mnt_type, type) == 0) {
92                                 fprintf(stderr, "%s: according to %s %s is "
93                                         "already mounted on %s\n",
94                                         progname, MOUNTED, spec, mtpt);
95                                 return(1); /* or should we return an error? */
96                         }
97                 }
98                 endmntent(fp);
99         }
100         return(0);
101 }
102
103 static int
104 update_mtab_entry(char *spec, char *mtpt, char *type, char *opts,
105                   int flags, int freq, int pass)
106 {
107         FILE *fp;
108         struct mntent mnt;
109         int rc = 0;
110
111         mnt.mnt_fsname = spec;
112         mnt.mnt_dir = mtpt;
113         mnt.mnt_type = type;
114         mnt.mnt_opts = opts ? opts : "";
115         mnt.mnt_freq = freq;
116         mnt.mnt_passno = pass;
117
118         fp = setmntent(MOUNTED, "a+");
119         if (fp == NULL) {
120                 fprintf(stderr, "%s: setmntent(%s): %s:",
121                         progname, MOUNTED, strerror (errno));
122                 rc = 16;
123         } else {
124                 if ((addmntent(fp, &mnt)) == 1) {
125                         fprintf(stderr, "%s: addmntent: %s:",
126                                 progname, strerror (errno));
127                         rc = 16;
128                 }
129                 endmntent(fp);
130         }
131
132         return rc;
133 }
134
135 int
136 init_options(struct lustre_mount_data *lmd)
137 {
138         memset(lmd, 0, sizeof(*lmd));
139         lmd->lmd_magic = LMD_MAGIC;
140         lmd->lmd_server_nid = PTL_NID_ANY;
141         lmd->lmd_local_nid = PTL_NID_ANY;
142         lmd->lmd_port = 988;    /* XXX define LUSTRE_DEFAULT_PORT */
143         lmd->lmd_nal = SOCKNAL;
144         return 0;
145 }
146
147 int
148 print_options(struct lustre_mount_data *lmd)
149 {
150         int i;
151
152         printf("mds:             %s\n", lmd->lmd_mds);
153         printf("profile:         %s\n", lmd->lmd_profile);
154         printf("server_nid:      "LPX64"\n", lmd->lmd_server_nid);
155         printf("local_nid:       "LPX64"\n", lmd->lmd_local_nid);
156         printf("nal:             %x\n", lmd->lmd_nal);
157         printf("server_ipaddr:   0x%x\n", lmd->lmd_server_ipaddr);
158         printf("port:            %d\n", lmd->lmd_port);
159
160         for (i = 0; i < route_index; i++)
161                 printf("route:           "LPX64" : "LPX64" - "LPX64"\n",
162                        routes[i].gw, routes[i].lo, routes[i].hi);
163
164         return 0;
165 }
166
167 static int parse_route(char *opteq, char *opttgts)
168 {
169         char *gw_lo_ptr, *gw_hi_ptr, *tgt_lo_ptr, *tgt_hi_ptr;
170         ptl_nid_t gw_lo, gw_hi, tgt_lo, tgt_hi;
171
172         opttgts[0] = '\0';
173         gw_lo_ptr = opteq + 1;
174         if (!(gw_hi_ptr = strchr(gw_lo_ptr, '-'))) {
175                 gw_hi_ptr = gw_lo_ptr;
176         } else {
177                 gw_hi_ptr[0] = '\0';
178                 gw_hi_ptr++;
179         }
180
181         if (ptl_parse_nid(&gw_lo, gw_lo_ptr) != 0) {
182                 fprintf(stderr, "%s: can't parse NID %s\n", progname,gw_lo_ptr);
183                 return(1);
184         }
185
186         if (ptl_parse_nid(&gw_hi, gw_hi_ptr) != 0) {
187                 fprintf(stderr, "%s: can't parse NID %s\n", progname,gw_hi_ptr);
188                 return(1);
189         }
190
191         tgt_lo_ptr = opttgts + 1;
192         if (!(tgt_hi_ptr = strchr(tgt_lo_ptr, '-'))) {
193                 tgt_hi_ptr = tgt_lo_ptr;
194         } else {
195                 tgt_hi_ptr[0] = '\0';
196                 tgt_hi_ptr++;
197         }
198
199         if (ptl_parse_nid(&tgt_lo, tgt_lo_ptr) != 0) {
200                 fprintf(stderr, "%s: can't parse NID %s\n",progname,tgt_lo_ptr);
201                 return(1);
202         }
203
204         if (ptl_parse_nid(&tgt_hi, tgt_hi_ptr) != 0) {
205                 fprintf(stderr, "%s: can't parse NID %s\n",progname,tgt_hi_ptr);
206                 return(1);
207         }
208
209         while (gw_lo <= gw_hi) {
210                 if (route_index >= MAX_ROUTES) {
211                         fprintf(stderr, "%s: to many routes %d\n",
212                                 progname, MAX_ROUTES);
213                         return(-1);
214                 }
215
216                 routes[route_index].gw = gw_lo;
217                 routes[route_index].lo = tgt_lo;
218                 routes[route_index].hi = tgt_hi;
219                 route_index++;
220                 gw_lo++;
221         }
222
223         return(0);
224 }
225
226 /*****************************************************************************
227  *
228  * This part was cribbed from util-linux/mount/mount.c.  There was no clear
229  * license information, but many other files in the package are identified as
230  * GNU GPL, so it's a pretty safe bet that was their intent.
231  *
232  ****************************************************************************/
233 struct opt_map {
234   const char *opt;              /* option name */
235   int  skip;                    /* skip in mtab option string */
236   int  inv;                     /* true if flag value should be inverted */
237   int  mask;                    /* flag mask value */
238 };
239
240 static const struct opt_map opt_map[] = {
241   { "defaults", 0, 0, 0         },      /* default options */
242   { "rw",       1, 1, MS_RDONLY },      /* read-write */
243   { "exec",     0, 1, MS_NOEXEC },      /* permit execution of binaries */
244   { "noexec",   0, 0, MS_NOEXEC },      /* don't execute binaries */
245   { "suid",     0, 1, MS_NOSUID },      /* honor suid executables */
246   { "nosuid",   0, 0, MS_NOSUID },      /* don't honor suid executables */
247   { "dev",      0, 1, MS_NODEV  },      /* interpret device files  */
248   { "nodev",    0, 0, MS_NODEV  },      /* don't interpret devices */
249   { "async",    0, 1, MS_SYNCHRONOUS},  /* asynchronous I/O */
250   { "auto",     0, 0, 0         },      /* Can be mounted using -a */
251   { "noauto",   0, 0, 0         },      /* Can  only be mounted explicitly */
252   { "nousers",  0, 1, 0         },      /* Forbid ordinary user to mount */
253   { "nouser",   0, 1, 0         },      /* Forbid ordinary user to mount */
254   { "noowner",  0, 1, 0         },      /* Device owner has no special privs */
255   { "_netdev",  0, 0, 0         },      /* Device accessible only via network */
256   { NULL,       0, 0, 0         }
257 };
258 /****************************************************************************/
259
260 static int parse_one_option(const char *check, int *flagp)
261 {
262         const struct opt_map *opt;
263
264         for (opt = &opt_map[0]; opt->opt != NULL; opt++) {
265                 if (strcmp(check, opt->opt) == 0) {
266                         if (opt->inv)
267                                 *flagp &= ~(opt->mask);
268                         else
269                                 *flagp |= opt->mask;
270                         return 1;
271                 }
272         }
273         return 0;
274 }
275
276 int parse_options(char *options, struct lustre_mount_data *lmd, int *flagp)
277 {
278         ptl_nid_t nid = 0, cluster_id = 0;
279         int val;
280         char *opt, *opteq, *opttgts;
281
282         *flagp = 0;
283         /* parsing ideas here taken from util-linux/mount/nfsmount.c */
284         for (opt = strtok(options, ","); opt; opt = strtok(NULL, ",")) {
285                 if ((opteq = strchr(opt, '='))) {
286                         val = atoi(opteq + 1);
287                         *opteq = '\0';
288                         if (!strcmp(opt, "nettype")) {
289                                 lmd->lmd_nal = ptl_name2nal(opteq + 1);
290                                 if (lmd->lmd_nal < 0) {
291                                         fprintf(stderr, "%s: can't parse NET "
292                                                 "%s\n", progname, opteq + 1);
293                                         return (1);
294                                 }
295                         } else if(!strcmp(opt, "cluster_id")) {
296                                 if (ptl_parse_nid(&cluster_id, opteq+1) != 0) {
297                                         fprintf(stderr, "%s: can't parse NID "
298                                                 "%s\n", progname, opteq+1);
299                                         return (1);
300                                 }
301                                 lmd_cluster_id = cluster_id;
302                         } else if(!strcmp(opt, "route")) {
303                                 if (!(opttgts = strchr(opteq + 1, ':'))) {
304                                         fprintf(stderr, "%s: Route must be "
305                                                 "of the form: route="
306                                                 "<gw>[-<gw>]:<low>[-<high>]\n",
307                                                 progname);
308                                         return(1);
309                                 }
310                                 parse_route(opteq, opttgts);
311                         } else if (!strcmp(opt, "local_nid")) {
312                                 if (ptl_parse_nid(&nid, opteq + 1) != 0) {
313                                         fprintf(stderr, "%s: "
314                                                 "can't parse NID %s\n",
315                                                 progname,
316                                                 opteq+1);
317                                         return (1);
318                                 }
319                                 lmd->lmd_local_nid = nid;
320                         } else if (!strcmp(opt, "server_nid")) {
321                                 if (ptl_parse_nid(&nid, opteq + 1) != 0) {
322                                         fprintf(stderr, "%s: "
323                                                 "can't parse NID %s\n",
324                                                 progname, opteq + 1);
325                                         return (1);
326                                 }
327                                 lmd->lmd_server_nid = nid;
328                         } else if (!strcmp(opt, "port")) {
329                                 lmd->lmd_port = val;
330                         } else {
331                                 fprintf(stderr, "%s: unknown option '%s'\n",
332                                         progname, opt);
333                                 usage(stderr);
334                         }
335                 } else {
336                         if (parse_one_option(opt, flagp))
337                                 continue;
338
339                         fprintf(stderr, "%s: unknown option '%s'\n",
340                                 progname, opt);
341                         usage(stderr);
342                 }
343         }
344         return 0;
345 }
346
347 int
348 get_local_elan_id(char *fname, char *buf)
349 {
350         FILE *fp = fopen(fname, "r");
351         int   rc;
352
353         if (fp == NULL)
354                 return 1;
355
356         rc = fscanf(fp, "NodeId %255s", buf);
357
358         fclose(fp);
359
360         return (rc == 1) ? 0 : -1;
361 }
362
363 int
364 set_local(struct lustre_mount_data *lmd)
365 {
366         /* XXX ClusterID?
367          * XXX PtlGetId() will be safer if portals is loaded and
368          * initialised correctly at this time... */
369         char buf[256], *ptr = buf;
370         ptl_nid_t nid;
371         int rc;
372
373         if (lmd->lmd_local_nid != PTL_NID_ANY)
374                 return 0;
375
376         memset(buf, 0, sizeof(buf));
377
378         switch (lmd->lmd_nal) {
379         default:
380                 fprintf(stderr, "%s: Unknown network type: %d\n",
381                         progname, lmd->lmd_nal);
382                 return 1;
383
384         case SOCKNAL:
385         case TCPNAL:
386         case OPENIBNAL:
387         case IIBNAL:
388         case VIBNAL:
389         case RANAL:
390                 rc = gethostname(buf, sizeof(buf) - 1);
391                 if (rc) {
392                         fprintf (stderr, "%s: can't get local buf: %d\n",
393                                  progname, rc);
394                         return rc;
395                 }
396                 break;
397         case QSWNAL: {
398                 char *pfiles[] = {"/proc/qsnet/elan3/device0/position",
399                                   "/proc/qsnet/elan4/device0/position",
400                                   "/proc/elan/device0/position",
401                                   NULL};
402                 int   i = 0;
403
404                 do {
405                         rc = get_local_elan_id(pfiles[i], buf);
406                 } while (rc != 0 && pfiles[++i] != NULL);
407
408                 if (rc != 0) {
409                         rc = gethostname(buf, sizeof(buf) - 1);
410                         if (rc == 0) {
411                                 char *tmp = ptr;
412                                 while ((*tmp >= 'a' && *tmp <= 'z') ||
413                                        (*tmp >= 'A' && *tmp <= 'Z'))
414                                         tmp++;
415                                 ptr = strsep(&tmp, ".");
416                         } else {
417                                 fprintf(stderr,
418                                         "%s: can't read Elan ID from /proc\n",
419                                         progname);
420                                 return 1;
421                         }
422                 }
423                 break;
424         }
425         }
426
427         if (ptl_parse_nid (&nid, ptr) != 0) {
428                 fprintf (stderr, "%s: can't parse NID %s\n", progname, buf);
429                 return (1);
430         }
431
432         lmd->lmd_local_nid = nid + lmd_cluster_id;
433         return 0;
434 }
435
436 int
437 set_peer(char *hostname, struct lustre_mount_data *lmd)
438 {
439         ptl_nid_t nid = 0;
440         int rc;
441
442         switch (lmd->lmd_nal) {
443         default:
444                 fprintf(stderr, "%s: Unknown network type: %d\n",
445                         progname, lmd->lmd_nal);
446                 return 1;
447
448         case IIBNAL:
449         case VIBNAL:
450                 if (lmd->lmd_server_nid != PTL_NID_ANY)
451                         break;
452                 if (ptl_parse_nid (&nid, hostname) != 0) {
453                         fprintf (stderr, "%s: can't parse NID %s\n",
454                                  progname, hostname);
455                         return (1);
456                 }
457                 lmd->lmd_server_nid = nid;
458                 break;
459
460         case SOCKNAL:
461         case TCPNAL:
462         case OPENIBNAL:
463         case RANAL:
464                 if (lmd->lmd_server_nid == PTL_NID_ANY) {
465                         if (ptl_parse_nid (&nid, hostname) != 0) {
466                                 fprintf (stderr, "%s: can't parse NID %s\n",
467                                          progname, hostname);
468                                 return (1);
469                         }
470                         lmd->lmd_server_nid = nid;
471                 }
472
473                 if (ptl_parse_ipaddr(&lmd->lmd_server_ipaddr, hostname) != 0) {
474                         fprintf (stderr, "%s: can't parse host %s\n",
475                                  progname, hostname);
476                         return (1);
477                 }
478                 break;
479         case QSWNAL: {
480                 char buf[64];
481
482                 if (lmd->lmd_server_nid != PTL_NID_ANY)
483                         break;
484
485                 rc = sscanf(hostname, "%*[^0-9]%63[0-9]", buf);
486                 if (rc != 1) {
487                         fprintf (stderr, "%s: can't get elan id from host %s\n",
488                                  progname, hostname);
489                         return 1;
490                 }
491                 if (ptl_parse_nid (&nid, buf) != 0) {
492                         fprintf (stderr, "%s: can't parse NID %s\n",
493                                  progname, hostname);
494                         return (1);
495                 }
496                 lmd->lmd_server_nid = nid;
497
498                 break;
499         }
500         }
501
502         return 0;
503 }
504
505 int
506 build_data(char *source, char *options, struct lustre_mount_data *lmd,
507            int *flagp)
508 {
509         char buf[1024];
510         char *hostname = NULL, *mds = NULL, *profile = NULL, *s;
511         int rc;
512
513         if (lmd_bad_magic(lmd))
514                 return -EINVAL;
515
516         if (strlen(source) >= sizeof(buf)) {
517                 fprintf(stderr, "%s: host:/mds/profile argument too long\n",
518                         progname);
519                 return -EINVAL;
520         }
521         strcpy(buf, source);
522         if ((s = strchr(buf, ':'))) {
523                 hostname = buf;
524                 *s = '\0';
525
526                 while (*++s == '/')
527                         ;
528                 mds = s;
529                 if ((s = strchr(mds, '/'))) {
530                         *s = '\0';
531                         profile = s + 1;
532                 } else {
533                         fprintf(stderr, "%s: directory to mount not in "
534                                 "host:/mds/profile format\n",
535                                 progname);
536                         return(1);
537                 }
538         } else {
539                 fprintf(stderr, "%s: "
540                         "directory to mount not in host:/mds/profile format\n",
541                         progname);
542                 return(1);
543         }
544
545         rc = parse_options(options, lmd, flagp);
546         if (rc)
547                 return rc;
548
549         rc = set_local(lmd);
550         if (rc)
551                 return rc;
552
553         rc = set_peer(hostname, lmd);
554         if (rc)
555                 return rc;
556         if (strlen(mds) > sizeof(lmd->lmd_mds) + 1) {
557                 fprintf(stderr, "%s: mds name too long\n", progname);
558                 return(1);
559         }
560         strcpy(lmd->lmd_mds, mds);
561
562         if (strlen(profile) > sizeof(lmd->lmd_profile) + 1) {
563                 fprintf(stderr, "%s: profile name too long\n", progname);
564                 return(1);
565         }
566         strcpy(lmd->lmd_profile, profile);
567
568         if (verbose)
569                 print_options(lmd);
570         return 0;
571 }
572
573 static int set_routes(struct lustre_mount_data *lmd) {
574        struct portals_cfg pcfg;
575        struct portal_ioctl_data data;
576        int i, j, route_exists, rc, err = 0;
577
578        register_ioc_dev(PORTALS_DEV_ID, PORTALS_DEV_PATH);
579
580        for (i = 0; i < route_index; i++) {
581
582                /* Check for existing routes so as not to add duplicates */
583               for (j = 0; ; j++) {
584                       PCFG_INIT(pcfg, NAL_CMD_GET_ROUTE);
585                       pcfg.pcfg_nal = ROUTER;
586                       pcfg.pcfg_count = j;
587
588                       PORTAL_IOC_INIT(data);
589                       data.ioc_pbuf1 = (char*)&pcfg;
590                       data.ioc_plen1 = sizeof(pcfg);
591                       data.ioc_nid = pcfg.pcfg_nid;
592
593                       rc = l_ioctl(PORTALS_DEV_ID, IOC_PORTAL_NAL_CMD, &data);
594                       if (rc != 0) {
595                               route_exists = 0;
596                               break;
597                       }
598
599                       if ((pcfg.pcfg_gw_nal == lmd->lmd_nal) &&
600                           (pcfg.pcfg_nid    == routes[i].gw) &&
601                           (pcfg.pcfg_nid2   == routes[i].lo) &&
602                           (pcfg.pcfg_nid3   == routes[i].hi)) {
603                               route_exists = 1;
604                               break;
605                       }
606               }
607
608               if (route_exists)
609                       continue;
610
611               PCFG_INIT(pcfg, NAL_CMD_ADD_ROUTE);
612               pcfg.pcfg_nid = routes[i].gw;
613               pcfg.pcfg_nal = ROUTER;
614               pcfg.pcfg_gw_nal = lmd->lmd_nal;
615               pcfg.pcfg_nid2 = MIN(routes[i].lo, routes[i].hi);
616               pcfg.pcfg_nid3 = MAX(routes[i].lo, routes[i].hi);
617
618               PORTAL_IOC_INIT(data);
619               data.ioc_pbuf1 = (char*)&pcfg;
620               data.ioc_plen1 = sizeof(pcfg);
621               data.ioc_nid = pcfg.pcfg_nid;
622
623               rc = l_ioctl(PORTALS_DEV_ID, IOC_PORTAL_NAL_CMD, &data);
624               if (rc != 0) {
625                       fprintf(stderr, "%s: Unable to add route "
626                               LPX64" : "LPX64" - "LPX64"\n[%d] %s\n",
627                               progname, routes[i].gw, routes[i].lo,
628                               routes[i].hi, errno, strerror(errno));
629                       err = 2;
630                       break;
631               }
632        }
633
634        unregister_ioc_dev(PORTALS_DEV_ID);
635        return err;
636 }
637
638 int main(int argc, char *const argv[])
639 {
640         char *source, *target, *options = "";
641         int i, nargs = 3, opt, rc, flags;
642         struct lustre_mount_data lmd;
643         static struct option long_opt[] = {
644                 {"fake", 0, 0, 'f'},
645                 {"force", 0, 0, 1},
646                 {"help", 0, 0, 'h'},
647                 {"nomtab", 0, 0, 'n'},
648                 {"options", 1, 0, 'o'},
649                 {"verbose", 0, 0, 'v'},
650                 {0, 0, 0, 0}
651         };
652
653         progname = strrchr(argv[0], '/');
654         progname = progname ? progname + 1 : argv[0];
655
656         while ((opt = getopt_long(argc, argv, "fhno:v", long_opt,NULL)) != EOF){
657                 switch (opt) {
658                 case 1:
659                         ++force;
660                         printf("force: %d\n", force);
661                         nargs++;
662                         break;
663                 case 'f':
664                         ++fake;
665                         printf("fake: %d\n", fake);
666                         nargs++;
667                         break;
668                 case 'h':
669                         usage(stdout);
670                         break;
671                 case 'n':
672                         ++nomtab;
673                         printf("nomtab: %d\n", nomtab);
674                         nargs++;
675                         break;
676                 case 'o':
677                         options = optarg;
678                         nargs++;
679                         break;
680                 case 'v':
681                         ++verbose;
682                         printf("verbose: %d\n", verbose);
683                         nargs++;
684                         break;
685                 default:
686                         fprintf(stderr, "%s: unknown option '%c'\n",
687                                 progname, opt);
688                         usage(stderr);
689                         break;
690                 }
691         }
692
693         if (optind + 2 > argc) {
694                 fprintf(stderr, "%s: too few arguments\n", progname);
695                 usage(stderr);
696         }
697
698         source = argv[optind];
699         target = argv[optind + 1];
700
701         if (verbose) {
702                 for (i = 0; i < argc; i++)
703                         printf("arg[%d] = %s\n", i, argv[i]);
704                 printf("source = %s, target = %s\n", source, target);
705         }
706
707         if (!force && check_mtab_entry(source, target, "lustre"))
708                 exit(32);
709
710         init_options(&lmd);
711         rc = build_data(source, options, &lmd, &flags);
712         if (rc) {
713                 exit(1);
714         }
715
716         if (!fake) {
717                 rc = set_routes(&lmd);
718                 if (rc)
719                         exit(2);
720         }
721
722         rc = access(target, F_OK);
723         if (rc) {
724                 rc = errno;
725                 fprintf(stderr, "%s: %s inaccessible: %s\n", progname, target,
726                         strerror(errno));
727                 return 1;
728         }
729
730         if (!fake)
731                 rc = mount(source, target, "lustre", flags, (void *)&lmd);
732         if (rc) {
733                 fprintf(stderr, "%s: mount(%s, %s) failed: %s\n", source,
734                         target, progname, strerror(errno));
735                 if (errno == ENODEV)
736                         fprintf(stderr, "Are the lustre modules loaded?\n"
737                              "Check /etc/modules.conf and /proc/filesystems\n");
738                 rc = 32;
739         } else if (!nomtab) {
740                 rc = update_mtab_entry(source, target, "lustre", options,0,0,0);
741         }
742         return rc;
743 }