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