diff --git a/mount.c b/mount.c index 87365ae..afcfee4 100644 --- a/mount.c +++ b/mount.c @@ -15,46 +15,79 @@ struct { const char *notopt; unsigned long v; } optnames[] = { - { "remount", NULL, MS_REMOUNT }, - { "ro", "rw", MS_RDONLY }, - { "sync", "async", MS_SYNCHRONOUS }, - { "dirsync", NULL, MS_DIRSYNC }, - { "nodev", "dev", MS_NODEV }, - { "noatime", "atime", MS_NOATIME }, - { "nodiratime", "diratime", MS_NODIRATIME }, - { "noexec", "exec", MS_NOEXEC }, - { "nosuid", "suid", MS_NOSUID }, - { "mand", "nomand", MS_MANDLOCK }, - { "relatime", "norelatime", MS_RELATIME }, - { NULL, NULL, 0 } + { "remount", NULL, MS_REMOUNT }, + { "ro", "rw", MS_RDONLY }, + { "sync", "async", MS_SYNCHRONOUS }, + { "dirsync", NULL, MS_DIRSYNC }, + { "nodev", "dev", MS_NODEV }, + { "noatime", "atime", MS_NOATIME }, + { "nodiratime", "diratime", MS_NODIRATIME }, + { "noexec", "exec", MS_NOEXEC }, + { "nosuid", "suid", MS_NOSUID }, + { "mand", "nomand", MS_MANDLOCK }, + { "relatime", "norelatime", MS_RELATIME }, + { "bind", NULL, MS_BIND }, + { NULL, NULL, 0 } }; -static struct option { +static void +parseopts(char *popts, unsigned long *flags, char *data, size_t bufsiz) +{ + unsigned int i, validopt; + size_t optlen, dlen = 0; char *name; - struct option *next; -} *opthead; + + data[0] = '\0'; + for(name = strtok(popts, ","); name; name = strtok(NULL, ",")) { + validopt = 0; + for(i = 0; optnames[i].v; i++) { + if(optnames[i].opt && strcmp(name, optnames[i].opt) == 0) { + *flags |= optnames[i].v; + validopt = 1; + break; + } + if(optnames[i].notopt && strcmp(name, optnames[i].notopt) == 0) { + *flags &= ~optnames[i].v; + validopt = 1; + break; + } + } + if(!validopt) { + /* unknown option, pass as data option to mount() */ + if((optlen = strlen(name))) { + if(dlen + optlen + 2 >= bufsiz) + return; /* prevent overflow */ + if(dlen) + data[dlen++] = ','; + memcpy(&data[dlen], name, optlen); + dlen += optlen; + data[dlen] = '\0'; + } + } + } +} static void usage(void) { - eprintf("usage: %s [-BMRadn] [-t fstype] [-o options] [source] [target]\n", + eprintf("usage: %s [-BMRan] [-t fstype] [-o options] [source] [target]\n", argv0); } int main(int argc, char *argv[]) { - int i, validopt; - int oflag = 0, aflag = 0; + int aflag = 0, i; unsigned long flags = 0; - char *types = NULL, *arg = NULL, *p; - const char *source; - const char *target; - struct stat st1, st2; - void *data = NULL; + char *types = NULL, data[512]; + char *files[] = { "/proc/mounts", "/etc/fstab", NULL }; + size_t datasiz = sizeof(data); + const char *source, *target; + struct stat st; struct mntent *me = NULL; FILE *fp; - struct option *opt, *tmp; + + data[0] = '\0'; ARGBEGIN { case 'B': @@ -69,22 +102,8 @@ main(int argc, char *argv[]) case 'a': aflag = 1; break; - case 'd': - data = EARGF(usage()); - break; case 'o': - oflag = 1; - arg = EARGF(usage()); - for (p = strtok(arg, ","); p; p = strtok(NULL, ",")) { - opt = malloc(sizeof(*opt)); - if (!opt) - eprintf("malloc:"); - opt->name = strdup(p); - if (!opt->name) - eprintf("strdup:"); - opt->next = opthead; - opthead = opt; - } + parseopts(EARGF(usage()), &flags, data, datasiz); break; case 't': types = EARGF(usage()); @@ -95,85 +114,60 @@ main(int argc, char *argv[]) usage(); } ARGEND; - if (argc < 1 && aflag == 0) + if(argc < 1 && aflag == 0) usage(); - for (opt = opthead; opt; opt = opt->next) { - validopt = 0; - for (i = 0; optnames[i].v; i++) { - if (optnames[i].opt) { - if (!strcmp(opt->name, - optnames[i].opt)) { - flags |= optnames[i].v; - validopt = 1; - break; - } - } - if (optnames[i].notopt) { - if (!strcmp(opt->name, - optnames[i].notopt)) { - flags &= ~optnames[i].v; - validopt = 1; - break; - } - } - } - if (!validopt) - break; - } - if (oflag && !validopt) - eprintf("unknown option: %s\n", opt->name); - - if (aflag == 1) - goto domount; + if(aflag == 1) + goto mountall; source = argv[0]; target = argv[1]; - if (!target) { + if(!target) { target = argv[0]; source = NULL; - if (stat(target, &st1) < 0) + if(stat(target, &st) < 0) eprintf("stat %s:", target); - fp = setmntent("/proc/mounts", "r"); - if (!fp) - eprintf("setmntent %s:", "/proc/mounts"); - while ((me = getmntent(fp))) { - if (stat(me->mnt_dir, &st2) < 0) - eprintf("stat %s:", me->mnt_dir); - if (st1.st_dev == st2.st_dev && - st1.st_ino == st2.st_ino) { - source = strdup(me->mnt_fsname); - break; + } + + for(i = 0; files[i]; i++) { + if((fp = setmntent(files[i], "r"))) { + while((me = getmntent(fp))) { + if(strcmp(me->mnt_dir, target) == 0 || + strcmp(me->mnt_fsname, target) == 0) { + source = me->mnt_fsname; + target = me->mnt_dir; + if(!types) + types = me->mnt_type; + goto mountsingle; + } } + endmntent(fp); + fp = NULL; + } else { + fprintf(stderr, "setmntent %s: %s\n", files[i], strerror(errno)); } - endmntent(fp); - if (!source) - eprintf("can't find %s mountpoint\n", target); } + if(!source) + eprintf("can't find %s mountpoint\n", target); - if (mount(source, target, types, flags, data) < 0) +mountsingle: + if(mount(source, target, types, flags, data) < 0) eprintf("mount:"); - -domount: - if (aflag == 1) { - fp = setmntent("/etc/fstab", "r"); - if (!fp) - eprintf("setmntent %s:", "/etc/fstab"); - while ((me = getmntent(fp))) - if (mount(me->mnt_fsname, me->mnt_dir, me->mnt_type, - 0, me->mnt_opts) < 0) - fprintf(stderr, "mount: %s\n", strerror(errno)); + if(fp) endmntent(fp); - } + return EXIT_SUCCESS; - opt = opthead; - while (opt) { - tmp = opt->next; - free(opt->name); - free(opt); - opt = tmp; +mountall: + if(!(fp = setmntent("/etc/fstab", "r"))) + eprintf("setmntent %s:", "/etc/fstab"); + while((me = getmntent(fp))) { + flags = 0; + parseopts(me->mnt_opts, &flags, data, datasiz); + if(mount(me->mnt_fsname, me->mnt_dir, me->mnt_type, flags, data) < 0) + fprintf(stderr, "mount: %s\n", strerror(errno)); } + endmntent(fp); return EXIT_SUCCESS; }