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