diff options
-rw-r--r-- | lib/lib.h | 2 | ||||
-rw-r--r-- | lib/xwrap.c | 61 | ||||
-rw-r--r-- | toys/pending/mount.c | 111 |
3 files changed, 164 insertions, 10 deletions
@@ -94,6 +94,8 @@ void xflush(void); pid_t xfork(void); void xexec_optargs(int skip); void xexec(char **argv); +pid_t xpopen(char **argv, int *pipes); +int xpclose(pid_t pid, int *pipes); void xaccess(char *path, int flags); void xunlink(char *path); int xcreate(char *path, int flags, int mode); diff --git a/lib/xwrap.c b/lib/xwrap.c index 3e146fb7..7e495caf 100644 --- a/lib/xwrap.c +++ b/lib/xwrap.c @@ -143,6 +143,67 @@ void xexec(char **argv) perror_exit("exec %s", argv[0]); } +// Spawn child process, capturing stdin/stdout. +// argv[]: command to exec. If null, child returns to original program. +// pipes[]: stdin, stdout of new process. If null, block and wait for child. +// return: pid of child process +pid_t xpopen(char **argv, int *pipes) +{ + int cestnepasun[4], pid; + + // Make the pipes? + if (pipes) { + if (pipe(cestnepasun) || pipe(cestnepasun+2)) perror_exit("pipe"); + pipes[0] = cestnepasun[1]; + pipes[1] = cestnepasun[2]; + } + + // Child process + if (!(pid = xfork())) { + // Dance of the stdin/stdout redirection. + if (pipes) { + close(cestnepasun[1]); + close(cestnepasun[2]); + // if we had no stdin/out, pipe handles could overlap, so test for that + if (cestnepasun[0]) { + dup2(cestnepasun[0], 0); + close(cestnepasun[0]); + } + dup2(cestnepasun[3], 1); + dup2(cestnepasun[3], 2); + if (cestnepasun[3] > 2) close(cestnepasun[3]); + } + if (argv) { + if (CFG_TOYBOX) toy_exec(argv); + execvp(argv[0], argv); + _exit(127); + } + return 0; + + // Parent process + } else { + if (pipes) { + close(cestnepasun[0]); + close(cestnepasun[3]); + } + + return pid; + } +} + +int xpclose(pid_t pid, int *pipes) +{ + int rc = 127; + + if (pipes) { + close(pipes[0]); + close(pipes[1]); + } + waitpid(pid, &rc, 0); + + return WIFEXITED(rc) ? WEXITSTATUS(rc) : WTERMSIG(rc) + 127; +} + void xaccess(char *path, int flags) { if (access(path, flags)) perror_exit("Can't access '%s'", path); diff --git a/toys/pending/mount.c b/toys/pending/mount.c index 089293c7..3cec481b 100644 --- a/toys/pending/mount.c +++ b/toys/pending/mount.c @@ -6,7 +6,7 @@ * Note: -hV is bad spec, haven't implemented -FsLU yet * no mtab (/proc/mounts does it) so -n is NOP. -USE_MOUNT(NEWTOY(mount, ">2afnrvwt:o*[-rw]", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT)) +USE_MOUNT(NEWTOY(mount, "?>2afnrvwt:o*[-rw]", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT)) config MOUNT bool "mount" @@ -27,12 +27,6 @@ config MOUNT OPTIONS is a comma separated list of options, which can also be supplied as --longopts. - - -config MOUNT_AUTODETECT - help - usage: mount - This mount autodetects loopback mounts (a file on a directory) and bind mounts (file on file, directory on directory), so you don't need to say --bind or --loop. @@ -49,14 +43,99 @@ GLOBALS( char *opts; ) -static void do_mount(char *dev, char *dir, char *type, unsigned long flags, char *opts) +// Strip flags out of comma separated list of options. +// Return flags, +static long parse_opts(char *new, long flags, char **more) +{ + struct { + char *name; + long flags; + } opts[] = { + // NOPs (we autodetect --loop and --bind) + {"loop", 0}, {"bind", 0}, {"defaults", 0}, {"quiet", 0}, +// {"noauto", 0}, {"swap", 0}, + {"ro", MS_RDONLY}, {"rw", ~MS_RDONLY}, + {"nosuid", MS_NOSUID}, {"suid", ~MS_NOSUID}, + {"nodev", MS_NODEV}, {"dev", ~MS_NODEV}, + {"noexec", MS_NOEXEC}, {"exec", ~MS_NOEXEC}, + {"sync", MS_SYNCHRONOUS}, {"async", ~MS_SYNCHRONOUS}, + {"noatime", MS_NOATIME}, {"atime", ~MS_NOATIME}, + {"nodiratime", MS_NODIRATIME}, {"diratime", ~MS_NODIRATIME}, + {"loud", ~MS_SILENT}, + {"shared", MS_SHARED}, {"rshared", MS_SHARED|MS_REC}, + {"slave", MS_SLAVE}, {"rslave", MS_SLAVE|MS_REC}, + {"private", MS_PRIVATE}, {"rprivate", MS_SLAVE|MS_REC}, + {"unbindable", MS_UNBINDABLE}, {"runbindable", MS_UNBINDABLE|MS_REC}, + {"remount", MS_REMOUNT}, {"bind", MS_BIND}, {"move", MS_MOVE}, + // mand dirsync rec iversion strictatime + }; + + for (;;) { + char *comma = strchr(new, ','); + int i; + + if (comma) *comma = 0; + + // If we recognize an option, apply flags + for (i = 0; i < ARRAY_LEN(opts); i++) if (!strcasecmp(opts[i].name, new)) { + long ll = opts[i].flags; + + if (ll < 0) flags &= ll; + else flags |= ll; + + break; + } + + // If we didn't recognize it, keep string version + if (more && i == ARRAY_LEN(opts)) { + i = *more ? strlen(*more) : 0; + *more = xrealloc(*more, i + strlen(new) + 2); + if (i) (*more)[i++] = ','; + strcpy(i+*more, new); + } + + if (!comma) break; + *comma = ','; + new = comma + 1; + } + + return flags; +} + +static void mount_filesystem(char *dev, char *dir, char *type, + unsigned long flags, char *opts) { FILE *fp = 0; int rc = EINVAL; if (toys.optflags & FLAG_f) return; - if (!TT.type) fp = xfopen("/proc/filesystems", "r"); + if (!type) { + struct stat stdev, stdir; + + if (!stat(dev, &stdev) && !stat(dir, &stdir)) { + if (S_ISREG(stdev.st_mode)) { + // Loopback mount? + if (S_ISDIR(stdir.st_mode)) { + char *losetup[] = {"losetup", "-fs", dev, 0}; + int pipes[2], len; + pid_t pid; + + if (flags & MS_RDONLY) losetup[1] = "-fsr"; + pid = xpopen(losetup, pipes); + len = readall(pipes[1], toybuf, sizeof(toybuf)-1); + if (!xpclose(pid, pipes) && len > 1) { + if (toybuf[len-1] == '\n') --len; + toybuf[len] = 0; + dev = toybuf; + } else error_msg("losetup failed %d", len); + } else if (S_ISREG(stdir.st_mode)) flags |= MS_BIND; + } else if (S_ISDIR(stdev.st_mode) && S_ISDIR(stdir.st_mode)) + flags |= MS_BIND; + } + + if (!(flags & MS_BIND)) fp = xfopen("/proc/filesystems", "r"); + } for (;;) { char *buf = 0; @@ -77,6 +156,8 @@ static void do_mount(char *dev, char *dir, char *type, unsigned long flags, char i = strlen(type); if (i) type[i-1] = 0; } + if (toys.optflags & FLAG_v) + printf("try '%s' type '%s' on '%s'\n", dev, type, dir); rc = mount(dev, dir, type, flags, opts); if (!fp || (rc && errno != EINVAL)) break; free(buf); @@ -88,11 +169,20 @@ static void do_mount(char *dev, char *dir, char *type, unsigned long flags, char void mount_main(void) { + long flags = MS_SILENT; + struct arg_list *o; + char *opts = 0; + if (toys.optflags & FLAG_a) { fprintf(stderr, "not yet\n"); return; } + if (toys.optflags & FLAG_r) flags |= MS_RDONLY; + if (toys.optflags & FLAG_w) flags &= ~MS_RDONLY; + for (o = TT.optlist; o; o = o->next) + flags = parse_opts(o->arg, flags, &opts); + // show mounts if (!toys.optc) { struct mtab_list *mtl = xgetmountlist(0), *m; @@ -112,5 +202,6 @@ void mount_main(void) fprintf(stderr, "not yet\n"); return; // two arguments - } else do_mount(toys.optargs[0], toys.optargs[1], TT.type, 0, ""); + } else mount_filesystem(toys.optargs[0], toys.optargs[1], TT.type, + flags, opts ? opts : ""); } |