# HG changeset patch # User Rob Landley # Date 1404708209 18000 # Node ID ffc015bddb26e2d3cf06c9bf0bf1d61177fab8fd # Parent 4a74383074292def3c959853fce46c7608c657ee Autodetect --bind and --loop mounts in a way that doesn't interfere with network filesystems or -t newtype mounts that trigger a module load. diff -r 4a7438307429 -r ffc015bddb26 toys/pending/mount.c --- a/toys/pending/mount.c Sun Jul 06 23:21:13 2014 -0500 +++ b/toys/pending/mount.c Sun Jul 06 23:43:29 2014 -0500 @@ -66,7 +66,7 @@ {"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}, + {"remount", MS_REMOUNT}, {"move", MS_MOVE}, // mand dirsync rec iversion strictatime }; @@ -110,31 +110,16 @@ if (toys.optflags & FLAG_f) return; + // Autodetect bind mount or filesystem type 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"); + if (!stat(dev, &stdev) && !stat(dir, &stdir) + && ((S_ISREG(stdev.st_mode) && S_ISREG(stdir.st_mode)) + || (S_ISDIR(stdev.st_mode) && S_ISDIR(stdir.st_mode)))) + { + flags |= MS_BIND; + } else fp = xfopen("/proc/filesystems", "r"); } for (;;) { @@ -159,6 +144,33 @@ if (toys.optflags & FLAG_v) printf("try '%s' type '%s' on '%s'\n", dev, type, dir); rc = mount(dev, dir, type, flags, opts); + + // Looking for bind mounts in autodetect above isn't good enough because + // "mount -t ext2 fs.img dir" is valid, but if you _do_ accept bind mounts + // with -t how do you tell "-t cifs" isn't looking for a block device if + // it's not in /proc/filesystems yet because the module that won't be + // loaded until you try the mount, and if you can't then DEVICE + // existing as a file would cause a false positive loopback mount. + // + // Solution: try mount, let the kernel tell us it wanted a block device, + // do the loopback setup and retry the mount. + if (rc && errno == ENOTBLK) { + 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; + + continue; + } else error_msg("losetup failed %d", len); + } + if (!fp || (rc && errno != EINVAL)) break; free(buf); }