diff options
author | Grigoriy Orlov <gluk@cvs.openbsd.org> | 2002-11-06 14:14:49 +0000 |
---|---|---|
committer | Grigoriy Orlov <gluk@cvs.openbsd.org> | 2002-11-06 14:14:49 +0000 |
commit | 4094ed9326c8b5a416bc0ade46fcf0ed57938b7a (patch) | |
tree | 0b341214d0f6651080b0323719b8328d764becfe | |
parent | 4387fa2aa68f3690a23bc4f8ace9b339e79a3c7f (diff) |
- make -u identical with "-o update". The same for -f,-r,-w.
- mount point may be specified with trailing slash in all cases
(including fstab).
- mount doesn't look in fstab at "-o update". So update doesn't fails
for fs which isn't listed in fstab.
- 'mount -o update' only changes options which supplied via command line
and preserves options which currently in use.
- fix argv[] buffer overflow in mountfs/mangle.
- correct usage.
- Other improvements and fixes which I can't remember.
Thanks to everyone who test this patch.
miod@ ok.
-rw-r--r-- | sbin/mount/mount.c | 222 |
1 files changed, 126 insertions, 96 deletions
diff --git a/sbin/mount/mount.c b/sbin/mount/mount.c index a28dd8e432f..0b3e718205d 100644 --- a/sbin/mount/mount.c +++ b/sbin/mount/mount.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mount.c,v 1.28 2002/07/03 22:32:33 deraadt Exp $ */ +/* $OpenBSD: mount.c,v 1.29 2002/11/06 14:14:48 gluk Exp $ */ /* $NetBSD: mount.c,v 1.24 1995/11/18 03:34:29 cgd Exp $ */ /* @@ -44,7 +44,7 @@ static char copyright[] = #if 0 static char sccsid[] = "@(#)mount.c 8.19 (Berkeley) 4/19/94"; #else -static char rcsid[] = "$OpenBSD: mount.c,v 1.28 2002/07/03 22:32:33 deraadt Exp $"; +static char rcsid[] = "$OpenBSD: mount.c,v 1.29 2002/11/06 14:14:48 gluk Exp $"; #endif #endif /* not lint */ @@ -77,42 +77,44 @@ char **typelist = NULL; int selected(const char *); char *catopt(char *, const char *); +char *flags2opts(u_int32_t); struct statfs *getmntpt(const char *); int hasopt(const char *, const char *); void maketypelist(char *); -void mangle(char *, int *, const char **); -int mountfs(const char *, const char *, const char *, int, const char *, +void mangle(char *, int *, const char **, int); +int mountfs(const char *, const char *, const char *, const char *, const char *, int); void prmount(struct statfs *); int disklabelcheck(struct fstab *); -void usage(void); +__dead void usage(void); /* Map from mount options to printable formats. */ static struct opt { int o_opt; int o_silent; const char *o_name; + const char *o_optname; } optnames[] = { - { MNT_ASYNC, 0, "asynchronous" }, - { MNT_DEFEXPORTED, 1, "exported to the world" }, - { MNT_EXKERB, 1, "kerberos uid mapping" }, - { MNT_EXPORTED, 0, "NFS exported" }, - { MNT_EXPORTANON, 1, "anon uid mapping" }, - { MNT_EXRDONLY, 1, "exported read-only" }, - { MNT_LOCAL, 0, "local" }, - { MNT_NOATIME, 0, "noatime" }, - { MNT_NOATIME, 0, "noaccesstime" }, - { MNT_NODEV, 0, "nodev" }, - { MNT_NOEXEC, 0, "noexec" }, - { MNT_NOSUID, 0, "nosuid" }, - { MNT_QUOTA, 0, "with quotas" }, - { MNT_RDONLY, 0, "read-only" }, - { MNT_ROOTFS, 1, "root file system" }, - { MNT_SYNCHRONOUS, 0, "synchronous" }, - { MNT_SOFTDEP, 0, "softdep" }, - { MNT_UNION, 0, "union" }, - { NULL } + { MNT_ASYNC, 0, "asynchronous", "async" }, + { MNT_DEFEXPORTED, 1, "exported to the world", "" }, + { MNT_EXKERB, 1, "kerberos uid mapping", "" }, + { MNT_EXPORTED, 0, "NFS exported", "" }, + { MNT_EXPORTANON, 1, "anon uid mapping", "" }, + { MNT_EXRDONLY, 1, "exported read-only", "" }, + { MNT_LOCAL, 0, "local", "" }, + { MNT_NOATIME, 0, "noatime", "noatime" }, + { MNT_NOATIME, 0, "noaccesstime", "" }, + { MNT_NODEV, 0, "nodev", "nodev" }, + { MNT_NOEXEC, 0, "noexec", "noexec" }, + { MNT_NOSUID, 0, "nosuid", "nosuid" }, + { MNT_QUOTA, 0, "with quotas", "" }, + { MNT_RDONLY, 0, "read-only", "ro" }, + { MNT_ROOTFS, 1, "root file system", "" }, + { MNT_SYNCHRONOUS, 0, "synchronous", "sync" }, + { MNT_SOFTDEP, 0, "softdep", "softdep" }, + { MNT_UNION, 0, "union", "" }, + { NULL, 0, "", "" } }; int @@ -123,10 +125,10 @@ main(int argc, char * const argv[]) struct statfs *mntbuf; FILE *mountdfp; pid_t pid; - int all, ch, forceall, i, init_flags, mntsize, rval; - char *options; + int all, ch, forceall, i, mntsize, rval, new; + char *options, mntpath[MAXPATHLEN]; - all = forceall = init_flags = 0; + all = forceall = 0; options = NULL; vfstype = "ffs"; while ((ch = getopt(argc, argv, "Aadfo:rwt:uv")) != -1) @@ -141,14 +143,16 @@ main(int argc, char * const argv[]) debug = 1; break; case 'f': - init_flags |= MNT_FORCE; + if (!hasopt(options, "force")) + options = catopt(options, "force"); break; case 'o': if (*optarg) options = catopt(options, optarg); break; case 'r': - init_flags |= MNT_RDONLY; + if (!hasopt(options, "ro")) + options = catopt(options, "ro"); break; case 't': if (typelist != NULL) @@ -157,13 +161,15 @@ main(int argc, char * const argv[]) vfstype = optarg; break; case 'u': - init_flags |= MNT_UPDATE; + if (!hasopt(options, "update")) + options = catopt(options, "update"); break; case 'v': verbose = 1; break; case 'w': - init_flags &= ~MNT_RDONLY; + if (!hasopt(options, "rw")) + options = catopt(options, "rw"); break; case '?': default: @@ -178,6 +184,7 @@ main(int argc, char * const argv[]) strcmp(type, FSTAB_RW) && strcmp(type, FSTAB_RQ)) rval = 0; + new = 0; switch (argc) { case 0: if (all) @@ -191,9 +198,11 @@ main(int argc, char * const argv[]) if (disklabelcheck(fs)) continue; if (mountfs(fs->fs_vfstype, fs->fs_spec, - fs->fs_file, init_flags, options, + fs->fs_file, options, fs->fs_mntops, !forceall)) rval = 1; + else + ++new; } else { if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) @@ -204,27 +213,44 @@ main(int argc, char * const argv[]) prmount(&mntbuf[i]); } } - exit(rval); + break; case 1: if (typelist != NULL) usage(); - if (init_flags & MNT_UPDATE) { - if ((mntbuf = getmntpt(*argv)) == NULL) + if (realpath(*argv, mntpath) == NULL) + err(1, "realpath %s", mntpath); + if (hasopt(options, "update")) { + if ((mntbuf = getmntpt(mntpath)) == NULL) errx(1, "unknown special file or file system %s.", *argv); - if ((fs = getfsfile(mntbuf->f_mntonname)) == NULL) - errx(1, "can't find fstab entry for %s.", - *argv); - /* If it's an update, ignore the fstab file options. */ - fs->fs_mntops = NULL; + if ((mntbuf->f_flags & MNT_ROOTFS) && + !strcmp(mntbuf->f_mntfromname, "root_device")) { + /* Lookup fstab for name of root device. */ + fs = getfsfile(mntbuf->f_mntonname); + if (fs == NULL) + errx(1, + "can't find fstab entry for %s.", + *argv); + } else { + fs = malloc(sizeof(*fs)); + if (fs == NULL) + err(1, "malloc"); + fs->fs_vfstype = mntbuf->f_fstypename; + fs->fs_spec = mntbuf->f_mntfromname; + } + /* + * It's an update, ignore the fstab file options. + * Get the current options, so we can change only + * the options which given via a command line. + */ + fs->fs_mntops = flags2opts(mntbuf->f_flags); mntonname = mntbuf->f_mntonname; } else { - if ((fs = getfsfile(*argv)) == NULL && - (fs = getfsspec(*argv)) == NULL) - errx(1, - "%s: unknown special file or file system.", + if ((fs = getfsfile(mntpath)) == NULL && + (fs = getfsspec(mntpath)) == NULL) + errx(1, "can't find fstab entry for %s.", *argv); if (BADTYPE(fs->fs_type)) errx(1, "%s has unknown file system type.", @@ -232,7 +258,7 @@ main(int argc, char * const argv[]) mntonname = fs->fs_file; } rval = mountfs(fs->fs_vfstype, fs->fs_spec, - mntonname, init_flags, options, fs->fs_mntops, 0); + mntonname, options, fs->fs_mntops, 0); break; case 2: /* @@ -250,9 +276,8 @@ main(int argc, char * const argv[]) vfstype = labelfs; } } - rval = mountfs(vfstype, - argv[0], argv[1], init_flags, options, NULL, 0); + argv[0], argv[1], options, NULL, 0); break; default: usage(); @@ -262,8 +287,9 @@ main(int argc, char * const argv[]) /* * If the mount was successfully, and done by root, tell mountd the * good news. Pid checks are probably unnecessary, but don't hurt. + * XXX This should be done from kernel. */ - if (rval == 0 && getuid() == 0 && + if ((rval == 0 || new) && getuid() == 0 && (mountdfp = fopen(_PATH_MOUNTDPID, "r")) != NULL) { if (fscanf(mountdfp, "%d", &pid) == 1 && pid > 0 && kill(pid, SIGHUP) == -1 && errno != ESRCH) @@ -277,29 +303,39 @@ main(int argc, char * const argv[]) int hasopt(const char *mntopts, const char *option) { - int negative, found; + int found; char *opt, *optbuf; - if (option[0] == 'n' && option[1] == 'o') { - negative = 1; - option += 2; - } else - negative = 0; + if (mntopts == NULL) + return (0); optbuf = strdup(mntopts); found = 0; - for (opt = optbuf; (opt = strtok(opt, ",")) != NULL; opt = NULL) { - if (opt[0] == 'n' && opt[1] == 'o') { - if (!strcasecmp(opt + 2, option)) - found = negative; - } else if (!strcasecmp(opt, option)) - found = !negative; - } + for (opt = optbuf; !found && opt != NULL; strsep(&opt, ",")) + found = !strncmp(opt, option, strlen(option)); free(optbuf); return (found); } +/* + * Convert mount(2) flags to list of mount(8) options. + */ +char* +flags2opts(u_int32_t flags) +{ + char *optlist; + struct opt *p; + + optlist = NULL; + for (p = optnames; p->o_opt; p++) { + if (flags & p->o_opt && *p->o_optname) + optlist = catopt(optlist, p->o_optname); + } + + return(optlist); +} + int -mountfs(const char *vfstype, const char *spec, const char *name, int flags, +mountfs(const char *vfstype, const char *spec, const char *name, const char *options, const char *mntopts, int skipmounted) { /* List of directories containing mount_xxx subcommands. */ @@ -308,15 +344,14 @@ mountfs(const char *vfstype, const char *spec, const char *name, int flags, _PATH_USRSBIN, NULL }; - const char *argv[100], **edir; + const char **argv, **edir; struct statfs sf; pid_t pid; - int argc, i, status; + int argc, i, status, argvsize; char *optbuf, execname[MAXPATHLEN], mntpath[MAXPATHLEN]; - char mountname[MAXPATHLEN]; if (realpath(name, mntpath) == NULL) { - warn("realpath %s", name); + warn("realpath %s", mntpath); return (1); } @@ -324,6 +359,7 @@ mountfs(const char *vfstype, const char *spec, const char *name, int flags, if (mntopts == NULL) mntopts = ""; + if (options == NULL) { if (*mntopts == '\0') options = "rw"; @@ -332,15 +368,16 @@ mountfs(const char *vfstype, const char *spec, const char *name, int flags, mntopts = ""; } } + + /* options follows after mntopts, so they get priority over mntopts */ optbuf = catopt(strdup(mntopts), options); - if (strcmp(name, "/") == 0) - flags |= MNT_UPDATE; - else if (skipmounted) { - if (statfs(name, &sf) < 0) { - warn("statfs %s", name); - return (1); - } + if (strcmp(name, "/") == 0) { + if (!hasopt(optbuf, "update")) + optbuf = catopt(optbuf, "update"); + } else if (skipmounted) { + if (statfs(name, &sf) < 0) + err(1, "statfs %s", name); /* XXX can't check f_mntfromname, thanks to mfs, union, etc. */ if (strncmp(name, sf.f_mntonname, MNAMELEN) == 0 && strncmp(vfstype, sf.f_fstypename, MFSNAMELEN) == 0) { @@ -352,25 +389,13 @@ mountfs(const char *vfstype, const char *spec, const char *name, int flags, return (0); } } - if (flags & MNT_FORCE) - optbuf = catopt(optbuf, "force"); - if (flags & MNT_RDONLY) - optbuf = catopt(optbuf, "ro"); - /* - * XXX - * The mount_mfs (newfs) command uses -o to select the - * optimisation mode. We don't pass the default "-o rw" - * for that reason. - */ - if (flags & MNT_UPDATE) - optbuf = catopt(optbuf, "update"); - - (void)snprintf(mountname, - sizeof(mountname), "mount_%s", vfstype); + argvsize = 64; + if((argv = malloc(argvsize * sizeof(char*))) == NULL) + err(1, "malloc"); argc = 0; - argv[argc++] = mountname; - mangle(optbuf, &argc, argv); + argv[argc++] = NULL; /* this should be a full path name */ + mangle(optbuf, &argc, argv, argvsize - 4); argv[argc++] = spec; argv[argc++] = name; argv[argc] = NULL; @@ -380,6 +405,8 @@ mountfs(const char *vfstype, const char *spec, const char *name, int flags, for (i = 1; i < argc; i++) (void)printf(" %s", argv[i]); (void)printf("\n"); + free(optbuf); + free(argv); return (0); } @@ -394,6 +421,7 @@ mountfs(const char *vfstype, const char *spec, const char *name, int flags, do { (void)snprintf(execname, sizeof(execname), "%s/mount_%s", *edir, vfstype); + argv[0] = execname; execv(execname, (char * const *)argv); if (errno != ENOENT) warn("exec %s for %s", execname, name); @@ -405,6 +433,7 @@ mountfs(const char *vfstype, const char *spec, const char *name, int flags, /* NOTREACHED */ default: /* Parent. */ free(optbuf); + free(argv); if (waitpid(pid, &status, 0) < 0) { warn("waitpid"); @@ -600,7 +629,7 @@ maketypelist(char *fslist) /* * XXX * Note: the syntax is "noxxx,yyy" for no xxx's and - * no yyy's, not the more intuitive "noyyy,noyyy". + * no yyy's, not the more intuitive "noxxx,noyyy". */ if (fslist[0] == 'n' && fslist[1] == 'o') { fslist += 2; @@ -644,22 +673,23 @@ catopt(char *s0, const char *s1) } void -mangle(char *options, int *argcp, const char **argv) +mangle(char *options, int *argcp, const char **argv, int argcmax) { char *p, *s; int argc; + argcmax -= 2; argc = *argcp; - for (s = options; (p = strsep(&s, ",")) != NULL;) + for (s = options; argc <= argcmax && (p = strsep(&s, ",")) != NULL;) if (*p != '\0') { if (*p == '-') { argv[argc++] = p; p = strchr(p, '='); if (p) { *p = '\0'; - argv[argc++] = p+1; + argv[argc++] = p + 1; } - } else if (strcmp(p, "rw") != 0) { + } else { argv[argc++] = "-o"; argv[argc++] = p; } @@ -676,7 +706,7 @@ usage(void) "usage: mount %s %s\n mount %s\n mount %s\n", "[-dfruvw] [-o options] [-t ffs | external_type]", "special node", - "[-adfruvw] [-t ffs | external_type]", + "[-Aadfruvw] [-t ffs | external_type]", "[-dfruvw] special | node"); exit(1); } |