aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/lib.h2
-rw-r--r--lib/xwrap.c61
-rw-r--r--toys/pending/mount.c111
3 files changed, 164 insertions, 10 deletions
diff --git a/lib/lib.h b/lib/lib.h
index 3ca631b6..a246618b 100644
--- a/lib/lib.h
+++ b/lib/lib.h
@@ -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 : "");
}