Whamcloud - gitweb
1ad7759e1de50763fae825d2d2dbcc7ae2708ac9
[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                                 if (lmd->lmd_nal < 0) {
289                                         fprintf(stderr, "%s: can't parse NET "
290                                                 "%s\n", progname, opteq + 1);
291                                         return (-1);
292                                 }
293                         } else if(!strcmp(opt, "cluster_id")) {
294                                 if (ptl_parse_nid(&cluster_id, opteq+1) != 0) {
295                                         fprintf (stderr, "%s: can't parse NID "
296                                                  "%s\n", progname, opteq+1);
297                                         return (-1);
298                                 }
299                                 lmd_cluster_id = cluster_id;
300                         } else if(!strcmp(opt, "route")) {
301                                 if (!(opttgts = strchr(opteq + 1, ':'))) {
302                                         fprintf(stderr, "%s: Route must be "
303                                                 "of the form: route="
304                                                 "<gw>[-<gw>]:<low>[-<high>]\n",
305                                                 progname);
306                                         return(-1);
307                                 }
308                                 parse_route(opteq, opttgts);
309                         } else if (!strcmp(opt, "local_nid")) {
310                                 if (ptl_parse_nid(&nid, opteq + 1) != 0) {
311                                         fprintf (stderr, "%s: "
312                                                  "can't parse NID %s\n",
313                                                  progname,
314                                                  opteq+1);
315                                         return (-1);
316                                 }
317                                 lmd->lmd_local_nid = nid;
318                         } else if (!strcmp(opt, "server_nid")) {
319                                 if (ptl_parse_nid(&nid, opteq + 1) != 0) {
320                                         fprintf (stderr, "%s: "
321                                                  "can't parse NID %s\n",
322                                                  progname, opteq + 1);
323                                         return (-1);
324                                 }
325                                 lmd->lmd_server_nid = nid;
326                         } else if (!strcmp(opt, "port")) {
327                                 lmd->lmd_port = val;
328                         } else if (!strcmp(opt, "sec")) {
329                                 strncpy(lmd->lmd_security, opteq + 1,
330                                         sizeof(lmd->lmd_security));
331                         } else if (!strcmp(opt, "nllu")) {
332                                 if (parse_nllu(lmd, opteq + 1)) {
333                                         fprintf(stderr, "%s: "
334                                                 "can't parse user: %s\n",
335                                                 progname, opteq + 1);
336                                         return (-1);
337                                 }
338                         } else if (!strcmp(opt, "nllg")) {
339                                 if (parse_nllg(lmd, opteq + 1)) {
340                                         fprintf(stderr, "%s: "
341                                                 "can't parse group: %s\n",
342                                                 progname, opteq + 1);
343                                         return (-1);
344                                 }
345                         }
346                 } else {
347                         val = 1;
348                         if (!strncmp(opt, "no", 2)) {
349                                 val = 0;
350                                 opt += 2;
351                         }
352                         if (!strcmp(opt, "debug")) {
353                                 debug = val;
354                         } else if (!strcmp(opt, "async")) {
355                                 lmd->lmd_async = 1;
356                         }
357                 }
358         }
359         return 0;
360 }
361
362 int
363 get_local_elan_id(char *fname, char *buf)
364 {
365         FILE *fp = fopen(fname, "r");
366         int   rc;
367
368         if (fp == NULL)
369                 return -1;
370
371         rc = fscanf(fp, "NodeId %255s", buf);
372
373         fclose(fp);
374
375         return (rc == 1) ? 0 : -1;
376 }
377
378 int
379 set_local(struct lustre_mount_data *lmd)
380 {
381         /* XXX ClusterID?
382          * XXX PtlGetId() will be safer if portals is loaded and
383          * initialised correctly at this time... */
384         char buf[256];
385         ptl_nid_t nid;
386         int rc;
387
388         if (lmd->lmd_local_nid != PTL_NID_ANY)
389                 return 0;
390
391         memset(buf, 0, sizeof(buf));
392
393         switch (lmd->lmd_nal) {
394         default:
395                 fprintf(stderr, "%s: Unknown network type: %d\n",
396                         progname, lmd->lmd_nal);
397                 return 1;
398
399 #if CRAY_PORTALS
400         case CRAY_KB_SSNAL:
401                 return 0;
402
403         case CRAY_KB_ERNAL:
404 #else
405         case SOCKNAL:
406         case TCPNAL:
407         case OPENIBNAL:
408         case IIBNAL:
409         case VIBNAL:
410         case RANAL:
411 #endif
412         {
413                 struct utsname uts;
414
415                 rc = gethostname(buf, sizeof(buf) - 1);
416                 if (rc) {
417                         fprintf(stderr, "%s: can't get hostname: %s\n",
418                                 progname, strerror(rc));
419                         return rc;
420                 }
421
422                 rc = uname(&uts);
423                 /* for 2.6 kernels, reserve at least 8MB free, or we will
424                  * go OOM during heavy read load */
425                 if (rc == 0 && strncmp(uts.release, "2.6", 3) == 0) {
426                         int f, minfree = 32768;
427                         char name[40], val[40];
428                         FILE *meminfo;
429
430                         meminfo = fopen("/proc/meminfo", "r");
431                         if (meminfo != NULL) {
432                                 while (fscanf(meminfo, "%s %s %*s\n", name, val) != EOF) {
433                                         if (strcmp(name, "MemTotal:") == 0) {
434                                                 f = strtol(val, NULL, 0);
435                                                 if (f > 0 && f < 8 * minfree)
436                                                         minfree = f / 16;
437                                                 break;
438                                         }
439                                 }
440                                 fclose(meminfo);
441                         }
442                         f = open("/proc/sys/vm/min_free_kbytes", O_WRONLY);
443                         if (f >= 0) {
444                                 sprintf(val, "%d", minfree);
445                                 write(f, val, strlen(val));
446                                 close(f);
447                         }
448                 }
449                 break;
450         }
451 #if !CRAY_PORTALS
452         case QSWNAL:
453         {
454                 char *pfiles[] = {"/proc/qsnet/elan3/device0/position",
455                                   "/proc/qsnet/elan4/device0/position",
456                                   "/proc/elan/device0/position",
457                                   NULL};
458                 int   i = 0;
459
460                 do {
461                         rc = get_local_elan_id(pfiles[i], buf);
462                 } while (rc != 0 && pfiles[++i] != NULL);
463
464                 if (rc != 0) {
465                         fprintf(stderr, "%s: can't read Elan ID from /proc\n",
466                                 progname);
467
468                         return -1;
469                 }
470                 break;
471         }
472 #endif
473         }
474
475         if (ptl_parse_nid (&nid, buf) != 0) {
476                 fprintf (stderr, "%s: can't parse NID %s\n", progname, buf);
477                 return (-1);
478         }
479
480         lmd->lmd_local_nid = nid + lmd_cluster_id;
481         return 0;
482 }
483
484 int
485 set_peer(char *hostname, struct lustre_mount_data *lmd)
486 {
487         ptl_nid_t nid = 0;
488         int rc;
489
490         switch (lmd->lmd_nal) {
491         default:
492                 fprintf(stderr, "%s: Unknown network type: %d\n",
493                         progname, lmd->lmd_nal);
494                 return 1;
495
496 #if CRAY_PORTALS
497         case CRAY_KB_SSNAL:
498                 lmd->lmd_server_nid = strtoll(hostname,0,0);
499                 return 0;
500
501         case CRAY_KB_ERNAL:
502 #else
503         case IIBNAL:
504                 if (lmd->lmd_server_nid != PTL_NID_ANY)
505                         break;
506                 if (ptl_parse_nid (&nid, hostname) != 0) {
507                         fprintf (stderr, "%s: can't parse NID %s\n",
508                                  progname, hostname);
509                         return (1);
510                 }
511                 lmd->lmd_server_nid = nid;
512                 break;
513
514         case SOCKNAL:
515         case TCPNAL:
516         case OPENIBNAL:
517         case VIBNAL:
518         case RANAL:
519 #endif
520                 if (lmd->lmd_server_nid == PTL_NID_ANY) {
521                         if (ptl_parse_nid (&nid, hostname) != 0) {
522                                 fprintf (stderr, "%s: can't parse NID %s\n",
523                                          progname, hostname);
524                                 return (1);
525                         }
526                         lmd->lmd_server_nid = nid;
527                 }
528
529                 if (ptl_parse_ipaddr(&lmd->lmd_server_ipaddr, hostname) != 0) {
530                         fprintf (stderr, "%s: can't parse host %s\n",
531                                  progname, hostname);
532                         return (-1);
533                 }
534
535                 break;
536
537 #if !CRAY_PORTALS
538         case QSWNAL: {
539                 char buf[64];
540                 if (lmd->lmd_server_nid != PTL_NID_ANY)
541                         break;
542
543                 rc = sscanf(hostname, "%*[^0-9]%63[0-9]", buf);
544                 if (rc != 1) {
545                         fprintf (stderr, "%s: can't get elan id from host %s\n",
546                                  progname, hostname);
547                         return -1;
548                 }
549                 if (ptl_parse_nid (&nid, buf) != 0) {
550                         fprintf (stderr, "%s: can't parse NID %s\n",
551                                  progname, hostname);
552                         return (-1);
553                 }
554                 lmd->lmd_server_nid = nid;
555
556                 break;
557         }
558 #endif
559         }
560         return 0;
561 }
562
563 int
564 build_data(char *source, char *options, struct lustre_mount_data *lmd)
565 {
566         char buf[1024];
567         char *hostname = NULL, *mds = NULL, *profile = NULL, *s;
568         int rc;
569
570         if (lmd_bad_magic(lmd))
571                 return 4;
572
573         if (strlen(source) > sizeof(buf) + 1) {
574                 fprintf(stderr, "%s: host:/mds/profile argument too long\n",
575                         progname);
576                 return 1;
577         }
578         strcpy(buf, source);
579         if ((s = strchr(buf, ':'))) {
580                 hostname = buf;
581                 *s = '\0';
582
583                 while (*++s == '/')
584                         ;
585                 mds = s;
586                 if ((s = strchr(mds, '/'))) {
587                         *s = '\0';
588                         profile = s + 1;
589                 } else {
590                         fprintf(stderr, "%s: directory to mount not in "
591                                 "host:/mds/profile format\n",
592                                 progname);
593                         return(1);
594                 }
595         } else {
596                 fprintf(stderr, "%s: "
597                         "directory to mount not in host:/mds/profile format\n",
598                         progname);
599                 return(1);
600         }
601
602         rc = parse_options(options, lmd);
603         if (rc)
604                 return rc;
605
606         rc = set_local(lmd);
607         if (rc)
608                 return rc;
609
610         rc = set_peer(hostname, lmd);
611         if (rc)
612                 return rc;
613         if (strlen(mds) > sizeof(lmd->lmd_mds) + 1) {
614                 fprintf(stderr, "%s: mds name too long\n", progname);
615                 return(1);
616         }
617         strcpy(lmd->lmd_mds, mds);
618
619         if (strlen(profile) > sizeof(lmd->lmd_profile) + 1) {
620                 fprintf(stderr, "%s: profile name too long\n", progname);
621                 return(1);
622         }
623         strcpy(lmd->lmd_profile, profile);
624
625         if (verbose)
626                 print_options(lmd);
627         return 0;
628 }
629
630 static int set_routes(struct lustre_mount_data *lmd) {
631        struct portals_cfg pcfg;
632        struct portal_ioctl_data data;
633        int i, j, route_exists, rc, err = 0;
634
635        register_ioc_dev(PORTALS_DEV_ID, PORTALS_DEV_PATH);
636
637        for (i = 0; i < route_index; i++) {
638
639                /* Check for existing routes so as not to add duplicates */
640               for (j = 0; ; j++) {
641                       PCFG_INIT(pcfg, NAL_CMD_GET_ROUTE);
642                       pcfg.pcfg_nal = ROUTER;
643                       pcfg.pcfg_count = j;
644
645                       PORTAL_IOC_INIT(data);
646                       data.ioc_pbuf1 = (char*)&pcfg;
647                       data.ioc_plen1 = sizeof(pcfg);
648                       data.ioc_nid = pcfg.pcfg_nid;
649
650                       rc = l_ioctl(PORTALS_DEV_ID, IOC_PORTAL_NAL_CMD, &data);
651                       if (rc != 0) {
652                               route_exists = 0;
653                               break;
654                       }
655
656                       if ((pcfg.pcfg_gw_nal == lmd->lmd_nal) &&
657                           (pcfg.pcfg_nid    == routes[i].gw) &&
658                           (pcfg.pcfg_nid2   == routes[i].lo) &&
659                           (pcfg.pcfg_nid3   == routes[i].hi)) {
660                               route_exists = 1;
661                               break;
662                       }
663               }
664
665               if (route_exists)
666                       continue;
667
668               PCFG_INIT(pcfg, NAL_CMD_ADD_ROUTE);
669               pcfg.pcfg_nid = routes[i].gw;
670               pcfg.pcfg_nal = ROUTER;
671               pcfg.pcfg_gw_nal = lmd->lmd_nal;
672               pcfg.pcfg_nid2 = MIN(routes[i].lo, routes[i].hi);
673               pcfg.pcfg_nid3 = MAX(routes[i].lo, routes[i].hi);
674
675               PORTAL_IOC_INIT(data);
676               data.ioc_pbuf1 = (char*)&pcfg;
677               data.ioc_plen1 = sizeof(pcfg);
678               data.ioc_nid = pcfg.pcfg_nid;
679
680               rc = l_ioctl(PORTALS_DEV_ID, IOC_PORTAL_NAL_CMD, &data);
681               if (rc != 0) {
682                       fprintf(stderr, "%s: Unable to add route "
683                               LPX64" : "LPX64" - "LPX64"\n[%d] %s\n",
684                               progname, routes[i].gw, routes[i].lo,
685                               routes[i].hi, errno, strerror(errno));
686                       err = -1;
687                       break;
688               }
689        }
690
691        unregister_ioc_dev(PORTALS_DEV_ID);
692        return err;
693 }
694
695 void usage(FILE *out)
696 {
697         fprintf(out, "usage: %s <source> <target> [-f] [-v] [-n] [-o mntopt]\n",
698                 progname);
699         exit(out != stdout);
700 }
701
702 int main(int argc, char *const argv[])
703 {
704         char *source, *target, *options = "";
705         int i, nargs = 3, opt, rc;
706         struct lustre_mount_data lmd;
707         static struct option long_opt[] = {
708                 {"force", 0, 0, 'f'},
709                 {"help", 0, 0, 'h'},
710                 {"nomtab", 0, 0, 'n'},
711                 {"options", 1, 0, 'o'},
712                 {"verbose", 0, 0, 'v'},
713                 {0, 0, 0, 0}
714         };
715
716         progname = strrchr(argv[0], '/');
717         progname = progname ? progname + 1 : argv[0];
718
719         while ((opt = getopt_long(argc, argv, "fno:v", long_opt, NULL)) != EOF){
720                 switch (opt) {
721                 case 'f':
722                         ++force;
723                         printf("force: %d\n", force);
724                         nargs++;
725                         break;
726                 case 'h':
727                         usage(stdout);
728                         break;
729                 case 'n':
730                         ++nomtab;
731                         printf("nomtab: %d\n", nomtab);
732                         nargs++;
733                         break;
734                 case 'o':
735                         options = optarg;
736                         nargs++;
737                         break;
738                 case 'v':
739                         ++verbose;
740                         printf("verbose: %d\n", verbose);
741                         nargs++;
742                         break;
743                 default:
744                         fprintf(stderr, "%s: unknown option '%c'\n",
745                                 progname, opt);
746                         usage(stderr);
747                         break;
748                 }
749         }
750
751         if (optind + 2 > argc) {
752                 fprintf(stderr, "%s: too few arguments\n", progname);
753                 usage(stderr);
754         }
755
756         source = argv[optind];
757         target = argv[optind + 1];
758
759         if (verbose) {
760                 for (i = 0; i < argc; i++)
761                         printf("arg[%d] = %s\n", i, argv[i]);
762                 printf("source = %s, target = %s\n", source, target);
763         }
764
765         if (check_mtab_entry(source, target, "lustre"))
766                 exit(32);
767
768         init_options(&lmd);
769         rc = build_data(source, options, &lmd);
770         if (rc) {
771                 exit(rc);
772         }
773
774         rc = set_routes(&lmd);
775         if (rc) {
776                 exit(rc);
777         }
778
779         if (debug) {
780                 printf("%s: debug mode, not mounting\n", progname);
781                 exit(0);
782         }
783
784         rc = access(target, F_OK);
785         if (rc) {
786                 rc = errno;
787                 fprintf(stderr, "%s: %s inaccessible: %s\n", progname, target,
788                         strerror(errno));
789                 return rc;
790         }
791
792         rc = mount(source, target, "lustre", 0, (void *)&lmd);
793         if (rc) {
794                 rc = errno;
795                 perror(argv[0]);
796                 fprintf(stderr, "%s: mount(%s, %s) failed: %s\n", source,
797                         target, progname, strerror(errno));
798                 if (rc == ENODEV)
799                         fprintf(stderr, "Are the lustre modules loaded?\n"
800                              "Check /etc/modules.conf and /proc/filesystems\n");
801                 return 2;
802         }
803         update_mtab_entry(source, target, "lustre", options, 0, 0, 0);
804         return 0;
805 }