1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
4 * Copyright (C) 2002 Cluster File Systems, Inc.
5 * Author: Robert Read <rread@clusterfs.com>
7 * This file is part of Lustre, http://www.lustre.org.
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.
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.
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.
32 #include <sys/mount.h>
35 #include <sys/utsname.h>
38 #include <lnet/lnetctl.h>
45 static char *progname = NULL;
46 #define MAX_RETRIES 99
50 fprintf(out, "%s v1.%d\n", progname, LMD_MAGIC & 0xFF);
51 fprintf(out, "usage: %s <mdsnode>[,<altmdsnode>]:/<mdsname>/<cfgname>"
52 " <mountpt> [-fhnv] [-o mntopt]\n", progname);
53 fprintf(out, "\t<mdsnode>: nid of MDS (config) node\n"
54 "\t<mdsname>: name of MDS service (e.g. mds1)\n"
55 "\t<cfgname>: name of client config (e.g. client)\n"
56 "\t<mountpt>: filesystem mountpoint (e.g. /mnt/lustre)\n"
57 "\t-f|--fake: fake mount (updates /etc/mtab)\n"
58 "\t--force: force mount even if already in /etc/mtab\n"
59 "\t-h|--help: print this usage message\n"
60 "\t-n|--nomtab: do not update /etc/mtab after mount\n"
61 "\t-v|--verbose: print verbose config settings\n"
62 "\t-o: filesystem mount options:\n"
63 "\t\tflock/noflock: enable/disable flock support\n"
64 "\t\troute=<gw>[-<gw>]:<low>[-<high>]: portal route to MDS\n"
65 "\t\tuser_xattr/nouser_xattr: enable/disable user extended "
71 static int check_mtab_entry(char *spec, char *mtpt, char *type)
77 fp = setmntent(MOUNTED, "r");
81 while ((mnt = getmntent(fp)) != NULL) {
82 if (strcmp(mnt->mnt_fsname, spec) == 0 &&
83 strcmp(mnt->mnt_dir, mtpt) == 0 &&
84 strcmp(mnt->mnt_type, type) == 0) {
85 fprintf(stderr, "%s: according to %s %s is "
86 "already mounted on %s\n",
87 progname, MOUNTED, spec, mtpt);
88 return(1); /* or should we return an error? */
97 update_mtab_entry(char *spec, char *mtpt, char *type, char *opts,
98 int flags, int freq, int pass)
104 mnt.mnt_fsname = spec;
107 mnt.mnt_opts = opts ? opts : "";
109 mnt.mnt_passno = pass;
111 fp = setmntent(MOUNTED, "a+");
113 fprintf(stderr, "%s: setmntent(%s): %s:",
114 progname, MOUNTED, strerror (errno));
117 if ((addmntent(fp, &mnt)) == 1) {
118 fprintf(stderr, "%s: addmntent: %s:",
119 progname, strerror (errno));
121 } else if (verbose > 1) {
122 fprintf(stderr, "%s: added %s on %s to %s\n",
123 progname, spec, mtpt, MOUNTED);
132 init_options(struct lustre_mount_data *lmd)
134 memset(lmd, 0, sizeof(*lmd));
135 lmd->lmd_magic = LMD_MAGIC;
140 print_options(FILE *out, struct lustre_mount_data *lmd, const char *options)
143 for (i = 0; i < lmd->lmd_nid_count; i++) {
144 fprintf(out, "mds nid %d: %s\n", i,
145 libcfs_nid2str(lmd->lmd_nid[i]));
147 fprintf(out, "mds name: %s\n", lmd->lmd_mds);
148 fprintf(out, "profile: %s\n", lmd->lmd_profile);
149 fprintf(out, "options: %s\n", options);
150 fprintf(out, "retry: %d\n", retry);
155 static int parse_nids(struct lustre_mount_data *lmd, char *nids)
161 while ((tmp = strsep(&nids, ",:"))) {
162 nid = libcfs_str2nid(tmp);
163 if (nid == LNET_NID_ANY) {
164 fprintf(stderr, "%s: Can't parse NID '%s'\n",
168 lmd->lmd_nid[lmd->lmd_nid_count++] = nid;
169 if (lmd->lmd_nid_count >= MAX_FAILOVER_NIDS) {
170 fprintf(stderr, "%s: Too many target NIDs: "
171 "ignoring nids after %s\n",
176 return (lmd->lmd_nid_count);
180 /*****************************************************************************
182 * This part was cribbed from util-linux/mount/mount.c. There was no clear
183 * license information, but many other files in the package are identified as
184 * GNU GPL, so it's a pretty safe bet that was their intent.
186 ****************************************************************************/
188 const char *opt; /* option name */
189 int skip; /* skip in mtab option string */
190 int inv; /* true if flag value should be inverted */
191 int ms_mask; /* MS flag mask value */
192 int lmd_mask; /* LMD flag mask value */
195 static const struct opt_map opt_map[] = {
196 { "defaults", 0, 0, 0, 0 }, /* default options */
197 { "rw", 1, 1, MS_RDONLY, 0 }, /* read-write */
198 { "ro", 0, 0, MS_RDONLY, 0 }, /* read-only */
199 { "exec", 0, 1, MS_NOEXEC, 0 }, /* permit execution of binaries */
200 { "noexec", 0, 0, MS_NOEXEC, 0 }, /* don't execute binaries */
201 { "suid", 0, 1, MS_NOSUID, 0 }, /* honor suid executables */
202 { "nosuid", 0, 0, MS_NOSUID, 0 }, /* don't honor suid executables */
203 { "dev", 0, 1, MS_NODEV, 0 }, /* interpret device files */
204 { "nodev", 0, 0, MS_NODEV, 0 }, /* don't interpret devices */
205 { "async", 0, 1, MS_SYNCHRONOUS, 0}, /* asynchronous I/O */
206 { "auto", 0, 0, 0, 0 }, /* Can be mounted using -a */
207 { "noauto", 0, 0, 0, 0 }, /* Can only be mounted explicitly */
208 { "nousers", 0, 1, 0, 0 }, /* Forbid ordinary user to mount */
209 { "nouser", 0, 1, 0, 0 }, /* Forbid ordinary user to mount */
210 { "noowner", 0, 1, 0, 0 }, /* Device owner has no special privs */
211 { "_netdev", 0, 0, 0, 0 }, /* Device accessible only via network */
212 { "flock", 0, 0, 0, LMD_FLG_FLOCK}, /* Enable flock support */
213 { "noflock", 1, 1, 0, LMD_FLG_FLOCK}, /* Disable flock support */
214 { "user_xattr", 0, 0, 0, LMD_FLG_USER_XATTR}, /* Enable get/set user xattr */
215 { "nouser_xattr", 1, 1, 0, LMD_FLG_USER_XATTR}, /* Disable user xattr */
216 { "acl", 0, 0, 0, LMD_FLG_ACL}, /* Enable ACL support */
217 { "noacl", 1, 1, 0, LMD_FLG_ACL}, /* Disable ACL support */
218 /* please add new mount options to usage message */
221 /****************************************************************************/
223 static int parse_one_option(const char *check, int *ms_flags, int *lmd_flags)
225 const struct opt_map *opt;
227 for (opt = &opt_map[0]; opt->opt != NULL; opt++) {
228 if (strcmp(check, opt->opt) == 0) {
230 *ms_flags &= ~(opt->ms_mask);
231 *lmd_flags &= ~(opt->lmd_mask);
233 *ms_flags |= opt->ms_mask;
234 *lmd_flags |= opt->lmd_mask;
242 int parse_options(char *options, struct lustre_mount_data *lmd, int *flagp)
248 /* parsing ideas here taken from util-linux/mount/nfsmount.c */
249 for (opt = strtok(options, ","); opt; opt = strtok(NULL, ",")) {
250 if ((opteq = strchr(opt, '='))) {
251 val = atoi(opteq + 1);
253 if (!strcmp(opt, "retry")) {
254 if (val >= 0 || val < MAX_RETRIES)
259 fprintf(stderr, "%s: unknown option '%s'. "
260 "Ignoring.\n", progname, opt);
261 /* Ignore old nettype= for now
266 if (parse_one_option(opt, flagp, &lmd->lmd_flags))
269 fprintf(stderr, "%s: unknown option '%s'\n",
278 build_data(char *source, char *options, struct lustre_mount_data *lmd,
284 char *profile = NULL;
288 if (lmd_bad_magic(lmd))
291 if (strlen(source) >= sizeof(buf)) {
292 fprintf(stderr, "%s: nid:/mds/profile argument too long\n",
297 if ((s = strchr(buf, ':'))) {
304 if ((s = strchr(mds, '/'))) {
308 fprintf(stderr, "%s: directory to mount not in "
309 "nid:/mds/profile format\n",
314 fprintf(stderr, "%s: "
315 "directory to mount not in nid:/mds/profile format\n",
320 rc = parse_options(options, lmd, flagp);
324 if (parse_nids(lmd, nid) == 0) {
325 fprintf(stderr, "%s: Can't parse any mds nids\n", progname);
329 if (strlen(mds) + 1 > sizeof(lmd->lmd_mds)) {
330 fprintf(stderr, "%s: mds name too long\n", progname);
333 strcpy(lmd->lmd_mds, mds);
335 if (strlen(profile) + 1 > sizeof(lmd->lmd_profile)) {
336 fprintf(stderr, "%s: profile name too long\n", progname);
339 strcpy(lmd->lmd_profile, profile);
344 int main(int argc, char *const argv[])
346 char *source, *target, *options = "", optbuf[65536] = { '\0' };
347 int i, nargs = 3, opt, rc, flags, buflen = sizeof(optbuf) - 1;
348 struct lustre_mount_data lmd;
349 static struct option long_opt[] = {
353 {"nomtab", 0, 0, 'n'},
354 {"options", 1, 0, 'o'},
355 {"verbose", 0, 0, 'v'},
359 progname = strrchr(argv[0], '/');
360 progname = progname ? progname + 1 : argv[0];
362 while ((opt = getopt_long(argc, argv, "fhno:v", long_opt,NULL)) != EOF){
367 printf("force: %d\n", force);
373 printf("fake: %d\n", fake);
382 printf("nomtab: %d\n", nomtab);
391 printf("verbose: %d\n", verbose);
395 fprintf(stderr, "%s: unknown option '%c'\n",
402 if (optind + 2 > argc) {
403 fprintf(stderr, "%s: too few arguments\n", progname);
407 source = argv[optind];
408 target = argv[optind + 1];
411 for (i = 0; i < argc; i++)
412 printf("arg[%d] = %s\n", i, argv[i]);
413 printf("source = %s, target = %s\n", source, target);
416 if (!force && check_mtab_entry(source, target, "lustre"))
421 /* need to copy options, as parse_options->strtok() clobbers it
422 * and we can't use it later to put in /etc/mtab. */
423 if (strlen(options) > buflen)
424 fprintf(stderr, "%s: options too long (%d > %d), ignore last\n",
425 progname, strlen(options), buflen);
426 strncpy(optbuf, options, buflen);
428 rc = build_data(source, optbuf, &lmd, &flags);
434 print_options(stdout, &lmd, options);
436 rc = access(target, F_OK);
439 fprintf(stderr, "%s: %s inaccessible: %s\n", progname, target,
445 FILE *modpipe = popen("/sbin/modprobe -q llite", "r");
448 /* use <= to include the initial mount before we retry */
449 for (i = 0, rc = -EAGAIN; i <= retry && rc != 0; i++)
450 rc = mount(source, target, "lustre", flags, &lmd);
453 fprintf(stderr, "%s: mount(%s, %s) failed: %s\n", progname,
454 source, target, strerror(errno));
455 print_options(stderr, &lmd, options);
456 if (errno == ENODEV) {
457 struct utsname unamebuf;
458 char *modfile = "/etc/modutils.conf";
460 if (uname(&unamebuf) == 0 &&
461 strncmp(unamebuf.release, "2.4", 3) == 0)
462 modfile = "/etc/modules.conf";
464 fprintf(stderr, "Are the lustre modules loaded?\n"
465 "Check %s and /proc/filesystems\n");
468 } else if (!nomtab) {
469 rc = update_mtab_entry(source, target, "lustre", options,0,0,0);