ubase

suckless linux base utils
git clone git://git.2f30.org/ubase.git
Log | Files | Refs | README | LICENSE

commit 4d76ce2d16f1dba4c1ec0342954cfb19a5baf558
parent a308fc1df4d5d30fa681a13775ccc39574c31b1e
Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date:   Sun, 10 May 2015 18:19:15 +0200

mount: helper support + improvements

- helper support (mount.type).
  - helpers need to be in $PATH, if needed we can add a check for
    /sbin/mount.XXXX
  - pass -B, -M, -R to helper, its more reliable to pass these named
    options with -o however.
- allow prefix "no" for which type no action should be taken:
  mount -a -t nonfs,ext4

fix bugs:
- dont modify me->mnt_opts (used strtok).

Diffstat:
mount.8 | 18+++++++++++++++++-
mount.c | 153+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
2 files changed, 139 insertions(+), 32 deletions(-)

diff --git a/mount.8 b/mount.8 @@ -36,7 +36,23 @@ This is the default action. .It Fl o Ar options Specify a comma separated string of filesystem specific options. .It Fl t Ar fstype -Set the filesystem type. +Set the filesystem type. More than one type may be specified in a comma +separated list. The list of file system types can be prefixed with "no" to +specify the file system types for which action should not be taken. For +example, the +.Nm +command: +.Bd -literal +# mount -a -t nonfs,ext4 + +.Ed +mounts all file systems except those of type NFS and EXT4. +.Nm +will attempt to execute a program in your +.Ev PATH +mount.XXX where XXX is replaced by the type name. For example, NFS file +systems are mounted by the program +.Pa mount.nfs . .El .Sh SEE ALSO .Xr mount 2 , diff --git a/mount.c b/mount.c @@ -2,7 +2,9 @@ #include <sys/mount.h> #include <sys/stat.h> #include <sys/types.h> +#include <sys/wait.h> +#include <errno.h> #include <limits.h> #include <mntent.h> #include <stdio.h> @@ -34,41 +36,117 @@ struct { { NULL, NULL, 0 } }; +static unsigned long argflags = 0; +static char *argopts = NULL; + +static char * +findtype(const char *types, const char *t) +{ + const char *p; + size_t len; + + for (len = strlen(t); (p = strstr(types, t)); types = p + len) { + if (!strncmp(p, t, len) && (p[len] == '\0' || p[len] == ',')) + return (char *)p; + } + return NULL; +} + static void -parseopts(char *popts, unsigned long *flags, char *data, size_t datasiz) +parseopts(const char *popts, unsigned long *flags, char *data, size_t datasiz) { unsigned int i, validopt; size_t optlen, dlen = 0; - char *name; + const char *name, *e; + name = popts; data[0] = '\0'; - for (name = strtok(popts, ","); name; name = strtok(NULL, ",")) { + do { + if ((e = strstr(name, ","))) + optlen = e - name; + else + optlen = strlen(name); + validopt = 0; for (i = 0; optnames[i].opt; i++) { - if (optnames[i].opt && strcmp(name, optnames[i].opt) == 0) { + if (optnames[i].opt && + !strncmp(name, optnames[i].opt, optlen)) { *flags |= optnames[i].v; validopt = 1; break; } - if (optnames[i].notopt && strcmp(name, optnames[i].notopt) == 0) { + if (optnames[i].notopt && + !strncmp(name, optnames[i].notopt, optlen)) { *flags &= ~optnames[i].v; validopt = 1; break; } } - if (!validopt) { + + if (!validopt && optlen > 0) { /* unknown option, pass as data option to mount() */ - if ((optlen = strlen(name))) { - if (dlen + optlen + 2 >= datasiz) - return; /* prevent overflow */ - if (dlen) - data[dlen++] = ','; - memcpy(&data[dlen], name, optlen); - dlen += optlen; - data[dlen] = '\0'; - } + if (dlen + optlen + 2 >= datasiz) + return; /* prevent overflow */ + if (dlen) + data[dlen++] = ','; + memcpy(&data[dlen], name, optlen); + dlen += optlen; + data[dlen] = '\0'; + } + name = e + 1; + } while (e); +} + +static int +mounthelper(const char *fsname, const char *dir, const char *fstype) +{ + pid_t pid; + char eprog[PATH_MAX]; + char const *eargv[10]; + int status, i; + + pid = fork(); + switch(pid) { + case -1: + break; + case 0: + snprintf(eprog, sizeof(eprog), "mount.%s", fstype); + + i = 0; + eargv[i++] = eprog; + if (argflags & MS_BIND) + eargv[i++] = "-B"; + if (argflags & MS_MOVE) + eargv[i++] = "-M"; + if (argflags & MS_REC) + eargv[i++] = "-R"; + + if (argopts) { + eargv[i++] = "-o"; + eargv[i++] = argopts; + } + eargv[i++] = fsname; + eargv[i++] = dir; + eargv[i] = NULL; + + execvp(eprog, (char * const *)eargv); + if (errno == ENOENT) + _exit(1); + weprintf("execvp:"); + _exit(1); + break; + default: + if (waitpid(pid, &status, 0) < 0) { + weprintf("waitpid:"); + return -1; } + if (WIFEXITED(status)) + return WEXITSTATUS(status); + else if (WIFSIGNALED(status)) + return 1; + break; } + return 0; } static int @@ -96,6 +174,7 @@ mounted(const char *dir) return 1; } endmntent(fp); + return 0; } @@ -103,37 +182,37 @@ static void usage(void) { eprintf("usage: %s [-BMRan] [-t fstype] [-o options] [source] [target]\n", - argv0); + argv0); } int main(int argc, char *argv[]) { - int aflag = 0, oflag = 0, status = 0, i; - unsigned long flags = 0; char *types = NULL, data[512] = "", *resolvpath = NULL; char *files[] = { "/proc/mounts", "/etc/fstab", NULL }; - size_t datasiz = sizeof(data); const char *source, *target; struct mntent *me = NULL; + int aflag = 0, oflag = 0, status = 0, i, r; + unsigned long flags = 0; FILE *fp; ARGBEGIN { case 'B': - flags |= MS_BIND; + argflags |= MS_BIND; break; case 'M': - flags |= MS_MOVE; + argflags |= MS_MOVE; break; case 'R': - flags |= MS_REC; + argflags |= MS_REC; break; case 'a': aflag = 1; break; case 'o': oflag = 1; - parseopts(EARGF(usage()), &flags, data, datasiz); + argopts = EARGF(usage()); + parseopts(argopts, &flags, data, sizeof(data)); break; case 't': types = EARGF(usage()); @@ -182,7 +261,7 @@ main(int argc, char *argv[]) source = me->mnt_fsname; } if (!oflag) - parseopts(me->mnt_opts, &flags, data, datasiz); + parseopts(me->mnt_opts, &flags, data, sizeof(data)); if (!types) types = me->mnt_type; goto mountsingle; @@ -195,7 +274,10 @@ main(int argc, char *argv[]) eprintf("can't find %s in /etc/fstab\n", target); mountsingle: - if (mount(source, target, types, flags, data) < 0) { + r = mounthelper(source, target, types); + if (r == -1) + status = 1; + if (r > 0 && mount(source, target, types, argflags | flags, data) < 0) { weprintf("mount: %s:", source); status = 1; } @@ -208,14 +290,23 @@ mountall: if (!(fp = setmntent("/etc/fstab", "r"))) eprintf("setmntent %s:", "/etc/fstab"); while ((me = getmntent(fp))) { - if (hasmntopt(me, MNTOPT_NOAUTO)) - continue; - /* already mounted, skip */ - if (mounted(me->mnt_dir)) + /* has "noauto" option or already mounted: skip */ + if (hasmntopt(me, MNTOPT_NOAUTO) || mounted(me->mnt_dir)) continue; flags = 0; - parseopts(me->mnt_opts, &flags, data, datasiz); - if (mount(me->mnt_fsname, me->mnt_dir, me->mnt_type, flags, data) < 0) { + parseopts(me->mnt_opts, &flags, data, sizeof(data)); + /* if -t types specified: + * if non-match, skip + * if match and prefixed with "no", skip */ + if (types && + ((types[0] == 'n' && types[1] == 'o' && + findtype(types + 2, me->mnt_type)) || + (!findtype(types, me->mnt_type)))) + continue; + + r = mounthelper(me->mnt_fsname, me->mnt_dir, me->mnt_type); + if (r > 0 && mount(me->mnt_fsname, me->mnt_dir, me->mnt_type, + argflags | flags, data) < 0) { weprintf("mount: %s:", me->mnt_fsname); status = 1; }