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