mount: helper support + improvements - ubase - suckless linux base utils | |
git clone git://git.suckless.org/ubase | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
commit 71da5628d18492f48369d0d00cd86551ec7798d0 | |
parent ee5b04a7a3d12e8eeac9c9aa0f1ea45e644f854a | |
Author: Hiltjo Posthuma <[email protected]> | |
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: | |
M mount.8 | 18 +++++++++++++++++- | |
M 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) =… | |
+ 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].not… | |
+ 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]… | |
- 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, … | |
+ parseopts(me->mnt_opts, &flags, 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, da… | |
+ 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; | |
} |