Whamcloud - gitweb
- landed b_hd_cray_merge3
[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 #include <stdlib.h>
26 #include <stdio.h>
27 #include <unistd.h>
28 #include <fcntl.h>
29 #include <errno.h>
30 #include <string.h>
31 #include <sys/mount.h>
32 #include <mntent.h>
33 #define _GNU_SOURCE
34 #include <getopt.h>
35 #include <sys/utsname.h>
36 #include <pwd.h>
37 #include <grp.h>
38
39 #include "obdctl.h"
40 #include <portals/ptlctl.h>
41
42 int debug;
43 int verbose;
44 int nomtab;
45 int force;
46 static char *progname = NULL;
47
48 typedef struct {
49         ptl_nid_t gw;
50         ptl_nid_t lo;
51         ptl_nid_t hi;
52 } llmount_route_t;
53
54 #define MAX_ROUTES  1024
55 int route_index;
56 ptl_nid_t lmd_cluster_id = 0;
57 llmount_route_t routes[MAX_ROUTES];
58
59 static int check_mtab_entry(char *spec, char *mtpt, char *type)
60 {
61         FILE *fp;
62         struct mntent *mnt;
63
64         if (!force) {
65                 fp = setmntent(MOUNTED, "r");
66                 if (fp == NULL)
67                         return(0);
68
69                 while ((mnt = getmntent(fp)) != NULL) {
70                         if (strcmp(mnt->mnt_fsname, spec) == 0 &&
71                             strcmp(mnt->mnt_dir, mtpt) == 0 &&
72                             strcmp(mnt->mnt_type, type) == 0) {
73                                 fprintf(stderr, "%s: according to %s %s is "
74                                         "already mounted on %s\n",
75                                         progname, MOUNTED, spec, mtpt);
76                                 return(1); /* or should we return an error? */
77                         }
78                 }
79                 endmntent(fp);
80         }
81         return(0);
82 }
83
84 static void
85 update_mtab_entry(char *spec, char *mtpt, char *type, char *opts,
86                   int flags, int freq, int pass)
87 {
88         FILE *fp;
89         struct mntent mnt;
90
91         mnt.mnt_fsname = spec;
92         mnt.mnt_dir = mtpt;
93         mnt.mnt_type = type;
94         mnt.mnt_opts = opts ? opts : "";
95         mnt.mnt_freq = freq;
96         mnt.mnt_passno = pass;
97
98         if (!nomtab) {
99                 fp = setmntent(MOUNTED, "a+");
100                 if (fp == NULL) {
101                         fprintf(stderr, "%s: setmntent(%s): %s:",
102                                 progname, MOUNTED, strerror (errno));
103                 } else {
104                         if ((addmntent (fp, &mnt)) == 1) {
105                                 fprintf(stderr, "%s: addmntent: %s:",
106                                         progname, strerror (errno));
107                         }
108                         endmntent(fp);
109                 }
110         }
111 }
112
113 int
114 init_options(struct lustre_mount_data *lmd)
115 {
116         memset(lmd, 0, sizeof(*lmd));
117         lmd->lmd_magic = LMD_MAGIC;
118         lmd->lmd_server_nid = PTL_NID_ANY;
119         lmd->lmd_local_nid = PTL_NID_ANY;
120         lmd->lmd_port = 988;    /* XXX define LUSTRE_DEFAULT_PORT */
121         lmd->lmd_nal = SOCKNAL;
122         lmd->lmd_async = 0;
123         lmd->lmd_nllu = 99;
124         lmd->lmd_nllg = 99;
125         strncpy(lmd->lmd_security, "null", sizeof(lmd->lmd_security));
126         return 0;
127 }
128
129 int
130 print_options(struct lustre_mount_data *lmd)
131 {
132         int i;
133
134         printf("mds:             %s\n", lmd->lmd_mds);
135         printf("profile:         %s\n", lmd->lmd_profile);
136         printf("sec_flavor:      %s\n", lmd->lmd_security);
137         printf("server_nid:      "LPX64"\n", lmd->lmd_server_nid);
138 #ifdef CRAY_PORTALS
139         if (lmd->lmd_nal != CRAY_KB_SSNAL) {
140 #endif
141                 printf("local_nid:       "LPX64"\n", lmd->lmd_local_nid);
142 #ifdef CRAY_PORTALS
143         }
144 #endif
145         printf("nal:             %x\n", lmd->lmd_nal);
146 #ifdef CRAY_PORTALS
147         if (lmd->lmd_nal != CRAY_KB_SSNAL) {
148 #endif
149                 printf("server_ipaddr:   0x%x\n", lmd->lmd_server_ipaddr);
150                 printf("port:            %d\n", lmd->lmd_port);
151 #ifdef CRAY_PORTALS
152         }
153 #endif
154
155         for (i = 0; i < route_index; i++)
156                 printf("route:           "LPX64" : "LPX64" - "LPX64"\n",
157                        routes[i].gw, routes[i].lo, routes[i].hi);
158
159         return 0;
160 }
161
162 static int parse_route(char *opteq, char *opttgts)
163 {
164         char *gw_lo_ptr, *gw_hi_ptr, *tgt_lo_ptr, *tgt_hi_ptr;
165         ptl_nid_t gw_lo, gw_hi, tgt_lo, tgt_hi;
166
167         opttgts[0] = '\0';
168         gw_lo_ptr = opteq + 1;
169         if (!(gw_hi_ptr = strchr(gw_lo_ptr, '-'))) {
170                 gw_hi_ptr = gw_lo_ptr;
171         } else {
172                 gw_hi_ptr[0] = '\0';
173                 gw_hi_ptr++;
174         }
175
176         if (ptl_parse_nid(&gw_lo, gw_lo_ptr) != 0) {
177                 fprintf(stderr, "%s: can't parse NID %s\n", progname,gw_lo_ptr);
178                 return(-1);
179         }
180
181         if (ptl_parse_nid(&gw_hi, gw_hi_ptr) != 0) {
182                 fprintf(stderr, "%s: can't parse NID %s\n", progname,gw_hi_ptr);
183                 return(-1);
184         }
185
186         tgt_lo_ptr = opttgts + 1;
187         if (!(tgt_hi_ptr = strchr(tgt_lo_ptr, '-'))) {
188                 tgt_hi_ptr = tgt_lo_ptr;
189         } else {
190                 tgt_hi_ptr[0] = '\0';
191                 tgt_hi_ptr++;
192         }
193
194         if (ptl_parse_nid(&tgt_lo, tgt_lo_ptr) != 0) {
195                 fprintf(stderr, "%s: can't parse NID %s\n",progname,tgt_lo_ptr);
196                 return(-1);
197         }
198
199         if (ptl_parse_nid(&tgt_hi, tgt_hi_ptr) != 0) {
200                 fprintf(stderr, "%s: can't parse NID %s\n",progname,tgt_hi_ptr);
201                 return(-1);
202         }
203
204         while (gw_lo <= gw_hi) {
205                 if (route_index >= MAX_ROUTES) {
206                         fprintf(stderr, "%s: to many routes %d\n",
207                                 progname, MAX_ROUTES);
208                         return(-1);
209                 }
210
211                 routes[route_index].gw = gw_lo;
212                 routes[route_index].lo = tgt_lo;
213                 routes[route_index].hi = tgt_hi;
214                 route_index++;
215                 gw_lo++;
216         }
217
218         return(0);
219 }
220
221 /*
222  * here all what we do is gurantee the result is exactly
223  * what user intend to get, no ambiguous. maybe there have
224  * simpler library call could do the same job for us?
225  */
226 static int parse_u32(char *str, uint32_t *res)
227 {
228         unsigned long id;
229         char *endptr = NULL;
230
231         id = strtol(str, &endptr, 0);
232         if (endptr && *endptr != 0)
233                 return -1;
234
235         if (id == LONG_MAX || id == LONG_MIN)
236                 return -1;
237
238         if ((uint32_t)id != id)
239                 return -1;
240
241         *res = (uint32_t) id;
242         return 0;
243 }
244
245 static int parse_nllu(struct lustre_mount_data *lmd, char *str_nllu)
246 {
247         struct passwd *pass;
248
249         if (parse_u32(str_nllu, &lmd->lmd_nllu) == 0)
250                 return 0;
251
252         pass = getpwnam(str_nllu);
253         if (pass == NULL)
254                 return -1;
255
256         lmd->lmd_nllu = pass->pw_uid;
257         return 0;
258 }
259
260 static int parse_nllg(struct lustre_mount_data *lmd, char *str_nllg)
261 {
262         struct group *grp;
263
264         if (parse_u32(str_nllg, &lmd->lmd_nllg) == 0)
265                 return 0;
266
267         grp = getgrnam(str_nllg);
268         if (grp == NULL)
269                 return -1;
270
271         lmd->lmd_nllg = grp->gr_gid;
272         return 0;
273 }
274
275 int parse_options(char * options, struct lustre_mount_data *lmd)
276 {
277         ptl_nid_t nid = 0, cluster_id = 0;
278         int val;
279         char *opt, *opteq, *opttgts;
280
281         /* parsing ideas here taken from util-linux/mount/nfsmount.c */
282         for (opt = strtok(options, ","); opt; opt = strtok(NULL, ",")) {
283                 if ((opteq = strchr(opt, '='))) {
284                         val = atoi(opteq + 1);
285                         *opteq = '\0';
286                         if (!strcmp(opt, "nettype")) {
287                                 lmd->lmd_nal = ptl_name2nal(opteq + 1);
288                         } else if(!strcmp(opt, "cluster_id")) {
289                                 if (ptl_parse_nid(&cluster_id, opteq+1) != 0) {
290                                         fprintf (stderr, "%s: can't parse NID "
291                                                  "%s\n", progname, opteq+1);
292                                         return (-1);
293                                 }
294                                 lmd_cluster_id = cluster_id;
295                         } else if(!strcmp(opt, "route")) {
296                                 if (!(opttgts = strchr(opteq + 1, ':'))) {
297                                         fprintf(stderr, "%s: Route must be "
298                                                 "of the form: route="
299                                                 "<gw>[-<gw>]:<low>[-<high>]\n",
300                                                 progname);
301                                         return(-1);
302                                 }
303                                 parse_route(opteq, opttgts);
304                         } else if (!strcmp(opt, "local_nid")) {
305                                 if (ptl_parse_nid(&nid, opteq + 1) != 0) {
306                                         fprintf (stderr, "%s: "
307                                                  "can't parse NID %s\n",
308                                                  progname,
309                                                  opteq+1);
310                                         return (-1);
311                                 }
312                                 lmd->lmd_local_nid = nid;
313                         } else if (!strcmp(opt, "server_nid")) {
314                                 if (ptl_parse_nid(&nid, opteq + 1) != 0) {
315                                         fprintf (stderr, "%s: "
316                                                  "can't parse NID %s\n",
317                                                  progname, opteq + 1);
318                                         return (-1);
319                                 }
320                                 lmd->lmd_server_nid = nid;
321                         } else if (!strcmp(opt, "port")) {
322                                 lmd->lmd_port = val;
323                         } else if (!strcmp(opt, "sec")) {
324                                 strncpy(lmd->lmd_security, opteq + 1,
325                                         sizeof(lmd->lmd_security));
326                         } else if (!strcmp(opt, "nllu")) {
327                                 if (parse_nllu(lmd, opteq + 1)) {
328                                         fprintf(stderr, "%s: "
329                                                 "can't parse user: %s\n",
330                                                 progname, opteq + 1);
331                                         return (-1);
332                                 }
333                         } else if (!strcmp(opt, "nllg")) {
334                                 if (parse_nllg(lmd, opteq + 1)) {
335                                         fprintf(stderr, "%s: "
336                                                 "can't parse group: %s\n",
337                                                 progname, opteq + 1);
338                                         return (-1);
339                                 }
340                         }
341                 } else {
342                         val = 1;
343                         if (!strncmp(opt, "no", 2)) {
344                                 val = 0;
345                                 opt += 2;
346                         }
347                         if (!strcmp(opt, "debug")) {
348                                 debug = val;
349                         } else if (!strcmp(opt, "async")) {
350                                 lmd->lmd_async = 1;
351                         }
352                 }
353         }
354         return 0;
355 }
356
357 int
358 get_local_elan_id(char *fname, char *buf)
359 {
360         FILE *fp = fopen(fname, "r");
361         int   rc;
362
363         if (fp == NULL)
364                 return -1;
365
366         rc = fscanf(fp, "NodeId %255s", buf);
367
368         fclose(fp);
369
370         return (rc == 1) ? 0 : -1;
371 }
372
373 int
374 set_local(struct lustre_mount_data *lmd)
375 {
376         /* XXX ClusterID?
377          * XXX PtlGetId() will be safer if portals is loaded and
378          * initialised correctly at this time... */
379         char buf[256];
380         ptl_nid_t nid;
381         int rc;
382
383         if (lmd->lmd_local_nid != PTL_NID_ANY)
384                 return 0;
385
386         memset(buf, 0, sizeof(buf));
387
388 #ifdef CRAY_PORTALS
389         if (lmd->lmd_nal == CRAY_KB_ERNAL) {
390 #else
391         if (lmd->lmd_nal == SOCKNAL || lmd->lmd_nal == TCPNAL ||
392             lmd->lmd_nal == OPENIBNAL || lmd->lmd_nal == IIBNAL) {
393 #endif
394                 struct utsname uts;
395
396                 rc = gethostname(buf, sizeof(buf) - 1);
397                 if (rc) {
398                         fprintf(stderr, "%s: can't get hostname: %s\n",
399                                 progname, strerror(rc));
400                         return rc;
401                 }
402
403                 rc = uname(&uts);
404                 /* for 2.6 kernels, reserve at least 8MB free, or we will
405                  * go OOM during heavy read load */
406                 if (rc == 0 && strncmp(uts.release, "2.6", 3) == 0) {
407                         int f, minfree = 32768;
408                         char name[40], val[40];
409                         FILE *meminfo;
410
411                         meminfo = fopen("/proc/meminfo", "r");
412                         if (meminfo != NULL) {
413                                 while (fscanf(meminfo, "%s %s %*s\n", name, val) != EOF) {
414                                         if (strcmp(name, "MemTotal:") == 0) {
415                                                 f = strtol(val, NULL, 0);
416                                                 if (f > 0 && f < 8 * minfree)
417                                                         minfree = f / 16;
418                                                 break;
419                                         }
420                                 }
421                                 fclose(meminfo);
422                         }
423                         f = open("/proc/sys/vm/min_free_kbytes", O_WRONLY);
424                         if (f >= 0) {
425                                 sprintf(val, "%d", minfree);
426                                 write(f, val, strlen(val));
427                                 close(f);
428                         }
429                 }
430 #ifndef CRAY_PORTALS
431         } else if (lmd->lmd_nal == QSWNAL) {
432                 char *pfiles[] = {"/proc/qsnet/elan3/device0/position",
433                                   "/proc/qsnet/elan4/device0/position",
434                                   "/proc/elan/device0/position",
435                                   NULL};
436                 int   i = 0;
437
438                 do {
439                         rc = get_local_elan_id(pfiles[i], buf);
440                 } while (rc != 0 && pfiles[++i] != NULL);
441
442                 if (rc != 0) {
443                         fprintf(stderr, "%s: can't read Elan ID from /proc\n",
444                                 progname);
445
446                         return -1;
447                 }
448 #else
449         } else if (lmd->lmd_nal == CRAY_KB_SSNAL) {
450                 return 0;
451 #endif
452         }
453
454         if (ptl_parse_nid (&nid, buf) != 0) {
455                 fprintf (stderr, "%s: can't parse NID %s\n", progname, buf);
456                 return (-1);
457         }
458
459         lmd->lmd_local_nid = nid + lmd_cluster_id;
460         return 0;
461 }
462
463 int
464 set_peer(char *hostname, struct lustre_mount_data *lmd)
465 {
466         ptl_nid_t nid = 0;
467         int rc;
468
469 #ifdef CRAY_PORTALS
470         if (lmd->lmd_nal == CRAY_KB_ERNAL) {
471 #else
472         if (lmd->lmd_nal == SOCKNAL || lmd->lmd_nal == TCPNAL ||
473             lmd->lmd_nal == OPENIBNAL || lmd->lmd_nal == IIBNAL) {
474 #endif
475                 if (lmd->lmd_server_nid == PTL_NID_ANY) {
476                         if (ptl_parse_nid (&nid, hostname) != 0) {
477                                 fprintf (stderr, "%s: can't parse NID %s\n",
478                                          progname, hostname);
479                                 return (-1);
480                         }
481                         lmd->lmd_server_nid = nid;
482                 }
483
484                 if (ptl_parse_ipaddr(&lmd->lmd_server_ipaddr, hostname) != 0) {
485                         fprintf (stderr, "%s: can't parse host %s\n",
486                                  progname, hostname);
487                         return (-1);
488                 }
489 #ifndef CRAY_PORTALS
490         } else if (lmd->lmd_nal == QSWNAL &&lmd->lmd_server_nid == PTL_NID_ANY){
491                 char buf[64];
492                 rc = sscanf(hostname, "%*[^0-9]%63[0-9]", buf);
493                 if (rc != 1) {
494                         fprintf (stderr, "%s: can't get elan id from host %s\n",
495                                  progname, hostname);
496                         return -1;
497                 }
498                 if (ptl_parse_nid (&nid, buf) != 0) {
499                         fprintf (stderr, "%s: can't parse NID %s\n",
500                                  progname, hostname);
501                         return (-1);
502                 }
503                 lmd->lmd_server_nid = nid;
504 #else
505         } else if (lmd->lmd_nal == CRAY_KB_SSNAL) {
506                 lmd->lmd_server_nid = strtoll(hostname,0,0);
507 #endif
508         }
509
510
511         return 0;
512 }
513
514 int
515 build_data(char *source, char *options, struct lustre_mount_data *lmd)
516 {
517         char buf[1024];
518         char *hostname = NULL, *mds = NULL, *profile = NULL, *s;
519         int rc;
520
521         if (lmd_bad_magic(lmd))
522                 return 4;
523
524         if (strlen(source) > sizeof(buf) + 1) {
525                 fprintf(stderr, "%s: host:/mds/profile argument too long\n",
526                         progname);
527                 return 1;
528         }
529         strcpy(buf, source);
530         if ((s = strchr(buf, ':'))) {
531                 hostname = buf;
532                 *s = '\0';
533
534                 while (*++s == '/')
535                         ;
536                 mds = s;
537                 if ((s = strchr(mds, '/'))) {
538                         *s = '\0';
539                         profile = s + 1;
540                 } else {
541                         fprintf(stderr, "%s: directory to mount not in "
542                                 "host:/mds/profile format\n",
543                                 progname);
544                         return(1);
545                 }
546         } else {
547                 fprintf(stderr, "%s: "
548                         "directory to mount not in host:/mds/profile format\n",
549                         progname);
550                 return(1);
551         }
552
553         rc = parse_options(options, lmd);
554         if (rc)
555                 return rc;
556
557         rc = set_local(lmd);
558         if (rc)
559                 return rc;
560
561         rc = set_peer(hostname, lmd);
562         if (rc)
563                 return rc;
564         if (strlen(mds) > sizeof(lmd->lmd_mds) + 1) {
565                 fprintf(stderr, "%s: mds name too long\n", progname);
566                 return(1);
567         }
568         strcpy(lmd->lmd_mds, mds);
569
570         if (strlen(profile) > sizeof(lmd->lmd_profile) + 1) {
571                 fprintf(stderr, "%s: profile name too long\n", progname);
572                 return(1);
573         }
574         strcpy(lmd->lmd_profile, profile);
575
576         if (verbose)
577                 print_options(lmd);
578         return 0;
579 }
580
581 static int set_routes(struct lustre_mount_data *lmd) {
582        struct portals_cfg pcfg;
583        struct portal_ioctl_data data;
584        int i, j, route_exists, rc, err = 0;
585
586        register_ioc_dev(PORTALS_DEV_ID, PORTALS_DEV_PATH);
587
588        for (i = 0; i < route_index; i++) {
589
590                /* Check for existing routes so as not to add duplicates */
591               for (j = 0; ; j++) {
592                       PCFG_INIT(pcfg, NAL_CMD_GET_ROUTE);
593                       pcfg.pcfg_nal = ROUTER;
594                       pcfg.pcfg_count = j;
595
596                       PORTAL_IOC_INIT(data);
597                       data.ioc_pbuf1 = (char*)&pcfg;
598                       data.ioc_plen1 = sizeof(pcfg);
599                       data.ioc_nid = pcfg.pcfg_nid;
600
601                       rc = l_ioctl(PORTALS_DEV_ID, IOC_PORTAL_NAL_CMD, &data);
602                       if (rc != 0) {
603                               route_exists = 0;
604                               break;
605                       }
606
607                       if ((pcfg.pcfg_gw_nal == lmd->lmd_nal) &&
608                           (pcfg.pcfg_nid    == routes[i].gw) &&
609                           (pcfg.pcfg_nid2   == routes[i].lo) &&
610                           (pcfg.pcfg_nid3   == routes[i].hi)) {
611                               route_exists = 1;
612                               break;
613                       }
614               }
615
616               if (route_exists)
617                       continue;
618
619               PCFG_INIT(pcfg, NAL_CMD_ADD_ROUTE);
620               pcfg.pcfg_nid = routes[i].gw;
621               pcfg.pcfg_nal = ROUTER;
622               pcfg.pcfg_gw_nal = lmd->lmd_nal;
623               pcfg.pcfg_nid2 = MIN(routes[i].lo, routes[i].hi);
624               pcfg.pcfg_nid3 = MAX(routes[i].lo, routes[i].hi);
625
626               PORTAL_IOC_INIT(data);
627               data.ioc_pbuf1 = (char*)&pcfg;
628               data.ioc_plen1 = sizeof(pcfg);
629               data.ioc_nid = pcfg.pcfg_nid;
630
631               rc = l_ioctl(PORTALS_DEV_ID, IOC_PORTAL_NAL_CMD, &data);
632               if (rc != 0) {
633                       fprintf(stderr, "%s: Unable to add route "
634                               LPX64" : "LPX64" - "LPX64"\n[%d] %s\n",
635                               progname, routes[i].gw, routes[i].lo,
636                               routes[i].hi, errno, strerror(errno));
637                       err = -1;
638                       break;
639               }
640        }
641
642        unregister_ioc_dev(PORTALS_DEV_ID);
643        return err;
644 }
645
646 void usage(FILE *out)
647 {
648         fprintf(out, "usage: %s <source> <target> [-f] [-v] [-n] [-o mntopt]\n",
649                 progname);
650         exit(out != stdout);
651 }
652
653 int main(int argc, char *const argv[])
654 {
655         char *source, *target, *options = "";
656         int i, nargs = 3, opt, rc;
657         struct lustre_mount_data lmd;
658         static struct option long_opt[] = {
659                 {"force", 0, 0, 'f'},
660                 {"help", 0, 0, 'h'},
661                 {"nomtab", 0, 0, 'n'},
662                 {"options", 1, 0, 'o'},
663                 {"verbose", 0, 0, 'v'},
664                 {0, 0, 0, 0}
665         };
666
667         progname = strrchr(argv[0], '/');
668         progname = progname ? progname + 1 : argv[0];
669
670         while ((opt = getopt_long(argc, argv, "fno:v", long_opt, NULL)) != EOF){
671                 switch (opt) {
672                 case 'f':
673                         ++force;
674                         printf("force: %d\n", force);
675                         nargs++;
676                         break;
677                 case 'h':
678                         usage(stdout);
679                         break;
680                 case 'n':
681                         ++nomtab;
682                         printf("nomtab: %d\n", nomtab);
683                         nargs++;
684                         break;
685                 case 'o':
686                         options = optarg;
687                         nargs++;
688                         break;
689                 case 'v':
690                         ++verbose;
691                         printf("verbose: %d\n", verbose);
692                         nargs++;
693                         break;
694                 default:
695                         fprintf(stderr, "%s: unknown option '%c'\n",
696                                 progname, opt);
697                         usage(stderr);
698                         break;
699                 }
700         }
701
702         if (optind + 2 > argc) {
703                 fprintf(stderr, "%s: too few arguments\n", progname);
704                 usage(stderr);
705         }
706
707         source = argv[optind];
708         target = argv[optind + 1];
709
710         if (verbose) {
711                 for (i = 0; i < argc; i++)
712                         printf("arg[%d] = %s\n", i, argv[i]);
713                 printf("source = %s, target = %s\n", source, target);
714         }
715
716         if (check_mtab_entry(source, target, "lustre"))
717                 exit(32);
718
719         init_options(&lmd);
720         rc = build_data(source, options, &lmd);
721         if (rc) {
722                 exit(rc);
723         }
724
725         rc = set_routes(&lmd);
726         if (rc) {
727                 exit(rc);
728         }
729
730         if (debug) {
731                 printf("%s: debug mode, not mounting\n", progname);
732                 exit(0);
733         }
734
735         rc = access(target, F_OK);
736         if (rc) {
737                 rc = errno;
738                 fprintf(stderr, "%s: %s inaccessible: %s\n", progname, target,
739                         strerror(errno));
740                 return rc;
741         }
742
743         rc = mount(source, target, "lustre", 0, (void *)&lmd);
744         if (rc) {
745                 rc = errno;
746                 perror(argv[0]);
747                 fprintf(stderr, "%s: mount(%s, %s) failed: %s\n", source,
748                         target, progname, strerror(errno));
749                 if (rc == ENODEV)
750                         fprintf(stderr, "Are the lustre modules loaded?\n"
751                              "Check /etc/modules.conf and /proc/filesystems\n");
752                 return 2;
753         }
754         update_mtab_entry(source, target, "lustre", options, 0, 0, 0);
755         return 0;
756 }