mount.c revision cc3bf66666cb0d2c8937b1a60c2be8d3f5a49d04
1414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley/* mount.c - mount filesystems
2414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley *
3414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley * Copyright 2014 Rob Landley <rob@landley.net>
4414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley *
5414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley * See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/mount.html
6414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley * Note: -hV is bad spec, haven't implemented -FsLU yet
7414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley * no mtab (/proc/mounts does it) so -n is NOP.
8414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley
9e996bddf88a946a8ac8338c02e14add57e3d588cRob LandleyUSE_MOUNT(NEWTOY(mount, "?O:afnrvwt:o*[-rw]", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT))
10414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley
11414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landleyconfig MOUNT
12414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley  bool "mount"
13414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley  default n
14414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley  help
15414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley    usage: mount [-afFrsvw] [-t TYPE] [-o OPTIONS...] [[DEVICE] DIR]
16414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley
17414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley    Mount new filesystem(s) on directories. With no arguments, display existing
18414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley    mounts.
19414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley
20414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley    -a	mount all entries in /etc/fstab (with -t, only entries of that TYPE)
21e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley    -O	only mount -a entries that have this option
22414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley    -f	fake it (don't actually mount)
23414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley    -r	read only (same as -o ro)
24414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley    -w	read/write (default, same as -o rw)
25414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley    -t	specify filesystem type
26414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley    -v	verbose
27414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley
28414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley    OPTIONS is a comma separated list of options, which can also be supplied
29414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley    as --longopts.
30414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley
31414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley    This mount autodetects loopback mounts (a file on a directory) and
32414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley    bind mounts (file on file, directory on directory), so you don't need
33e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley    to say --bind or --loop. You can also "mount -a /path" to mount everything
34e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley    in /etc/fstab under /path, even if it's noauto.
35414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley*/
36414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley
37414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley#define FOR_mount
38414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley#include "toys.h"
39414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley
40414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob LandleyGLOBALS(
41414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley  struct arg_list *optlist;
42414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley  char *type;
43e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley  char *bigO;
44414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley
45414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley  unsigned long flags;
46414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley  char *opts;
47e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley  int okuser;
48414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley)
49414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley
50e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley// TODO detect existing identical mount (procfs with different dev name?)
51e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley// TODO user, users, owner, group, nofail
52e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley// TODO -p (passfd)
53e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley// TODO -a -t notype,type2
54e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley// TODO --subtree
55e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley// TODO --rbind, -R
56e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley// TODO make "mount --bind,ro old new" work (implicit -o remount)
57e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley// TODO mount -a
58e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley// TODO mount -o remount
59e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley// TODO fstab: lookup default options for mount
60e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley// TODO implement -v
6172e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley// TODO "mount -a -o remount,ro" should detect overmounts
6272e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley// TODO work out how that differs from "mount -ar"
6372e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley// TODO what if you --bind mount a block device somewhere (file, dir, dev)
6472e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley// TODO "touch servername; mount -t cifs servername path"
65e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley
66e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley// Strip flags out of comma separated list of options, return flags,.
67e996bddf88a946a8ac8338c02e14add57e3d588cRob Landleystatic long flag_opts(char *new, long flags, char **more)
6844e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley{
6944e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley  struct {
7044e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley    char *name;
7144e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley    long flags;
7244e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley  } opts[] = {
7344e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley    // NOPs (we autodetect --loop and --bind)
7444e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley    {"loop", 0}, {"bind", 0}, {"defaults", 0}, {"quiet", 0},
75e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley    {"user", 0}, {"nouser", 0}, // checked in fstab, ignored in -o
7644e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley//    {"noauto", 0}, {"swap", 0},
7744e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley    {"ro", MS_RDONLY}, {"rw", ~MS_RDONLY},
7844e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley    {"nosuid", MS_NOSUID}, {"suid", ~MS_NOSUID},
7944e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley    {"nodev", MS_NODEV}, {"dev", ~MS_NODEV},
8044e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley    {"noexec", MS_NOEXEC}, {"exec", ~MS_NOEXEC},
8144e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley    {"sync", MS_SYNCHRONOUS}, {"async", ~MS_SYNCHRONOUS},
8244e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley    {"noatime", MS_NOATIME}, {"atime", ~MS_NOATIME},
8344e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley    {"nodiratime", MS_NODIRATIME}, {"diratime", ~MS_NODIRATIME},
8444e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley    {"loud", ~MS_SILENT},
8544e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley    {"shared", MS_SHARED}, {"rshared", MS_SHARED|MS_REC},
8644e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley    {"slave", MS_SLAVE}, {"rslave", MS_SLAVE|MS_REC},
8744e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley    {"private", MS_PRIVATE}, {"rprivate", MS_SLAVE|MS_REC},
8844e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley    {"unbindable", MS_UNBINDABLE}, {"runbindable", MS_UNBINDABLE|MS_REC},
89056d0a00de99639fb39d19e984dd66fe82be7820Rob Landley    {"remount", MS_REMOUNT}, {"move", MS_MOVE},
9044e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley    // mand dirsync rec iversion strictatime
9144e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley  };
9244e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley
93e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley  if (new) for (;;) {
9444e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley    char *comma = strchr(new, ',');
9544e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley    int i;
9644e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley
9744e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley    if (comma) *comma = 0;
9844e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley
9944e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley    // If we recognize an option, apply flags
10044e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley    for (i = 0; i < ARRAY_LEN(opts); i++) if (!strcasecmp(opts[i].name, new)) {
10144e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley      long ll = opts[i].flags;
10244e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley
10344e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley      if (ll < 0) flags &= ll;
10444e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley      else flags |= ll;
10544e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley
10644e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley      break;
10744e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley    }
10844e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley
10944e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley    // If we didn't recognize it, keep string version
11044e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley    if (more && i == ARRAY_LEN(opts)) {
11144e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley      i = *more ? strlen(*more) : 0;
11244e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley      *more = xrealloc(*more, i + strlen(new) + 2);
11344e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley      if (i) (*more)[i++] = ',';
11444e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley      strcpy(i+*more, new);
11544e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley    }
11644e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley
11744e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley    if (!comma) break;
11844e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley    *comma = ',';
11944e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley    new = comma + 1;
12044e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley  }
12144e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley
12244e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley  return flags;
12344e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley}
12444e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley
12544e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landleystatic void mount_filesystem(char *dev, char *dir, char *type,
12644e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley  unsigned long flags, char *opts)
127414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley{
128414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley  FILE *fp = 0;
129414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley  int rc = EINVAL;
130414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley
131414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley  if (toys.optflags & FLAG_f) return;
132414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley
133e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley  if (getuid()) {
134e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley    if (TT.okuser) TT.okuser = 0;
135e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley    else {
136e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley      error_msg("'%s' not user mountable in fstab");
137e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley      return;
138e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley    }
139e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley  }
140e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley
141056d0a00de99639fb39d19e984dd66fe82be7820Rob Landley  // Autodetect bind mount or filesystem type
142cc3bf66666cb0d2c8937b1a60c2be8d3f5a49d04Rob Landley
143cc3bf66666cb0d2c8937b1a60c2be8d3f5a49d04Rob Landley  if (type && !strcmp(type, "auto")) type = 0;
144cc3bf66666cb0d2c8937b1a60c2be8d3f5a49d04Rob Landley  if (flags & MS_MOVE) {
145cc3bf66666cb0d2c8937b1a60c2be8d3f5a49d04Rob Landley    if (type) error_exit("--move with -t");
146cc3bf66666cb0d2c8937b1a60c2be8d3f5a49d04Rob Landley  } else if (!type) {
14744e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley    struct stat stdev, stdir;
14844e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley
149e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley    // file on file or dir on dir is a --bind mount.
150056d0a00de99639fb39d19e984dd66fe82be7820Rob Landley    if (!stat(dev, &stdev) && !stat(dir, &stdir)
151056d0a00de99639fb39d19e984dd66fe82be7820Rob Landley        && ((S_ISREG(stdev.st_mode) && S_ISREG(stdir.st_mode))
152056d0a00de99639fb39d19e984dd66fe82be7820Rob Landley            || (S_ISDIR(stdev.st_mode) && S_ISDIR(stdir.st_mode))))
153056d0a00de99639fb39d19e984dd66fe82be7820Rob Landley    {
154056d0a00de99639fb39d19e984dd66fe82be7820Rob Landley      flags |= MS_BIND;
155056d0a00de99639fb39d19e984dd66fe82be7820Rob Landley    } else fp = xfopen("/proc/filesystems", "r");
156e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley  } else if (!strcmp(type, "ignore")) return;
157e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley  else if (!strcmp(type, "swap"))
158e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley    toys.exitval |= xpclose(xpopen((char *[]){"swapon", "--", dev, 0}, 0), 0);
159414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley
160414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley  for (;;) {
161414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley    char *buf = 0;
162414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley
163414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley    // If type wasn't specified, try all of them in order.
164414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley    if (fp) {
165414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley      size_t i;
166414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley
167414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley      if (getline(&buf, &i, fp)<0) break;
168414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley      type = buf;
169414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley      // skip nodev devices
170414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley      if (!isspace(*type)) {
171414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley        free(buf);
172414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley        continue;
173414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley      }
174414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley      // trim whitespace
175414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley      while (isspace(*type)) type++;
176414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley      i = strlen(type);
177414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley      if (i) type[i-1] = 0;
178414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley    }
17944e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley    if (toys.optflags & FLAG_v)
18044e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley      printf("try '%s' type '%s' on '%s'\n", dev, type, dir);
18172e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley    for (;;) {
18272e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley      rc = mount(dev, dir, type, flags, opts);
18372e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley      if ((rc != EACCES && rc != EROFS) || (flags & MS_RDONLY)) break;
18472e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley      fprintf(stderr, "'%s' is read-only", dev);
18572e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley      flags |= MS_RDONLY;
186056d0a00de99639fb39d19e984dd66fe82be7820Rob Landley    }
187414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley    free(buf);
18872e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley
18925fe0e0bea85f1d851ce03a90c0f1bf41ab431f2Rob Landley    if (!rc) break;
19025fe0e0bea85f1d851ce03a90c0f1bf41ab431f2Rob Landley
19125fe0e0bea85f1d851ce03a90c0f1bf41ab431f2Rob Landley    // Trying to autodetect loop mounts like bind mounts above (file on dir)
19225fe0e0bea85f1d851ce03a90c0f1bf41ab431f2Rob Landley    // isn't good enough because "mount -t ext2 fs.img dir" is valid, but if
19325fe0e0bea85f1d851ce03a90c0f1bf41ab431f2Rob Landley    // you _do_ accept loop mounts with -t how do you tell "-t cifs" isn't
19425fe0e0bea85f1d851ce03a90c0f1bf41ab431f2Rob Landley    // looking for a block device if it's not in /proc/filesystems yet
19525fe0e0bea85f1d851ce03a90c0f1bf41ab431f2Rob Landley    // because the module that won't be loaded until you try the mount, and
19625fe0e0bea85f1d851ce03a90c0f1bf41ab431f2Rob Landley    // if you can't then DEVICE existing as a file would cause a false
19725fe0e0bea85f1d851ce03a90c0f1bf41ab431f2Rob Landley    // positive loopback mount (so "touch servername" becomes a potential
19825fe0e0bea85f1d851ce03a90c0f1bf41ab431f2Rob Landley    // denial of service attack...)
19925fe0e0bea85f1d851ce03a90c0f1bf41ab431f2Rob Landley    //
20025fe0e0bea85f1d851ce03a90c0f1bf41ab431f2Rob Landley    // Solution: try the mount, let the kernel tell us it wanted a block
20125fe0e0bea85f1d851ce03a90c0f1bf41ab431f2Rob Landley    // device, then do the loopback setup and retry the mount.
20225fe0e0bea85f1d851ce03a90c0f1bf41ab431f2Rob Landley
20325fe0e0bea85f1d851ce03a90c0f1bf41ab431f2Rob Landley    if (fp && errno == EINVAL) continue;
20425fe0e0bea85f1d851ce03a90c0f1bf41ab431f2Rob Landley
20525fe0e0bea85f1d851ce03a90c0f1bf41ab431f2Rob Landley    if (errno == ENOTBLK) {
20625fe0e0bea85f1d851ce03a90c0f1bf41ab431f2Rob Landley      char *losetup[] = {"losetup", "-fs", dev, 0};
20725fe0e0bea85f1d851ce03a90c0f1bf41ab431f2Rob Landley      int pipes[2], len;
20825fe0e0bea85f1d851ce03a90c0f1bf41ab431f2Rob Landley      pid_t pid;
20925fe0e0bea85f1d851ce03a90c0f1bf41ab431f2Rob Landley
21025fe0e0bea85f1d851ce03a90c0f1bf41ab431f2Rob Landley      if (flags & MS_RDONLY) losetup[1] = "-fsr";
21125fe0e0bea85f1d851ce03a90c0f1bf41ab431f2Rob Landley      pid = xpopen(losetup, pipes);
21225fe0e0bea85f1d851ce03a90c0f1bf41ab431f2Rob Landley      len = readall(pipes[1], toybuf, sizeof(toybuf)-1);
21325fe0e0bea85f1d851ce03a90c0f1bf41ab431f2Rob Landley      rc = xpclose(pid, pipes);
21425fe0e0bea85f1d851ce03a90c0f1bf41ab431f2Rob Landley      if (!rc && len > 1) {
21525fe0e0bea85f1d851ce03a90c0f1bf41ab431f2Rob Landley        if (toybuf[len-1] == '\n') --len;
21625fe0e0bea85f1d851ce03a90c0f1bf41ab431f2Rob Landley        toybuf[len] = 0;
21725fe0e0bea85f1d851ce03a90c0f1bf41ab431f2Rob Landley        dev = toybuf;
21872e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley
21925fe0e0bea85f1d851ce03a90c0f1bf41ab431f2Rob Landley        continue;
22025fe0e0bea85f1d851ce03a90c0f1bf41ab431f2Rob Landley      } else error_msg("losetup failed %d", rc);
22125fe0e0bea85f1d851ce03a90c0f1bf41ab431f2Rob Landley    } else perror_msg("'%s'->'%s'", dev, dir);
22225fe0e0bea85f1d851ce03a90c0f1bf41ab431f2Rob Landley
22325fe0e0bea85f1d851ce03a90c0f1bf41ab431f2Rob Landley    break;
224414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley  }
225414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley  if (fp) fclose(fp);
226414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley}
227414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley
228414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landleyvoid mount_main(void)
229414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley{
230e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley  char *opts = 0, *dev = 0, *dir = 0, **ss;
23144e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley  long flags = MS_SILENT;
23244e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley  struct arg_list *o;
23372e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley  struct mtab_list *mtl, *mm, *remount = 0;
234414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley
23572e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley// remount
23672e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley//   - overmounts
23772e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley// shared subtree
23872e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley// -o parsed after fstab options
23972e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley// test if mountpoint already exists (-o noremount?)
24072e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley
24172e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley  // First pass; just accumulate string, don't parse flags yet. (This is so
24272e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley  // we can modify fstab entries with -a, or mtab with remount.)
24372e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley  for (o = TT.optlist; o; o = o->next) comma_collate(&opts, o->arg);
24472e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley  if (toys.optflags & FLAG_r) comma_collate(&opts, "ro");
24572e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley  if (toys.optflags & FLAG_w) comma_collate(&opts, "rw");
24644e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley
247e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley  // Treat each --option as -o option
248e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley  for (ss = toys.optargs; *ss; ss++) {
24972e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley    char *sss = *ss;
25072e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley
25172e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley    // If you realy, really want to mount a file named "--", we support it.
25272e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley    if (sss[0]=='-' && sss[1]=='-' && sss[2]) comma_collate(&opts, sss+2);
25372e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley    else if (!dev) dev = sss;
25472e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley    else if (!dir) dir = sss;
255e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley    // same message as lib/args.c ">2" which we can't use because --opts count
256e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley    else error_exit("Max 2 arguments\n");
257e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley  }
258414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley
25972e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley  if ((toys.optflags & FLAG_a) && dir) error_exit("-a with >1 arg");
26072e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley
26172e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley  // For remount we need _last_ match (in case of overmounts), so traverse
26272e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley  // in reverse order.
26372e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley  if (comma_scan(opts, "remount", 1))
26472e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley    remount = dlist_terminate(mtl = xgetmountlist("/proc/mounts"));
265e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley
266e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley  // Do we need to do an /etc/fstab trawl?
26772e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley  // This covers -a, -o remount, one argument, all user mounts
26825fe0e0bea85f1d851ce03a90c0f1bf41ab431f2Rob Landley  if ((toys.optflags & FLAG_a) || (dev && (!dir || getuid() || remount))) {
26972e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley    if (!remount) mtl = xgetmountlist("/etc/fstab");
27025fe0e0bea85f1d851ce03a90c0f1bf41ab431f2Rob Landley
27172e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley    for (mm = remount ? remount : mtl; mm; mm = (remount ? mm->prev : mm->next))
272e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley    {
27372e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley      int aflags, noauto, len;
27472e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley      char *aopts = 0;
275e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley
27672e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley      // Check for noauto and get it out of the option list. (Unknown options
27772e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley      // that make it to the kernel give filesystem drivers indigestion.)
27872e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley      noauto = comma_scan(mm->opts, "noauto", 1);
279e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley      if (toys.optflags & FLAG_a) {
28072e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley        // "mount -a /path" to mount all entries under /path
28172e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley        if (dev) {
28272e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley           len = strlen(dev);
28372e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley           if (strncmp(dev, mm->dir, len)
28472e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley               || (mm->dir[len] && mm->dir[len] != '/')) continue;
28572e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley        } else if (noauto) continue; // never present in the remount case
28672e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley        if (!mountlist_istype(mm,TT.type) || !comma_scanall(mm->opts,TT.bigO))
287e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley          continue;
288e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley      } else {
28972e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley        if (dir && strcmp(dir, mm->dir)) continue;
29072e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley        if (dev && strcmp(dev, mm->device) && (dir || strcmp(dev, mm->dir)))
291e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley          continue;
292e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley      }
293e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley
294e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley      // user only counts from fstab, not opts.
29572e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley      TT.okuser = comma_scan(mm->opts, "user", 1);
29672e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley      aflags = flag_opts(mm->opts, flags, &aopts);
29772e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley      aflags = flag_opts(opts, aflags, &aopts);
298e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley
29972e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley      mount_filesystem(mm->device, mm->dir, mm->type, aflags, aopts);
300e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley      free(aopts);
30172e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley
30272e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley      if (!(toys.optflags & FLAG_a)) break;
303e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley    }
30472e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley    if (CFG_TOYBOX_FREE) llist_traverse(mtl, free);
305e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley
30672e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley  // show mounts from /proc/mounts
30772e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley  } else if (!dev) {
308e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley    for (mtl = xgetmountlist(0); mtl && (mm = dlist_pop(&mtl)); free(mm)) {
309414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley      char *s = 0;
310414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley
311e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley      if (TT.type && strcmp(TT.type, mm->type)) continue;
312e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley      if (*mm->device == '/') s = xabspath(mm->device, 0);
313414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley      xprintf("%s on %s type %s (%s)\n",
314e996bddf88a946a8ac8338c02e14add57e3d588cRob Landley              s ? s : mm->device, mm->dir, mm->type, mm->opts);
315414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley      free(s);
316414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley    }
317414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley
318414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley  // two arguments
31972e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley  } else {
32072e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley    char *more = 0;
32172e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley
32272e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley    mount_filesystem(dev, dir, TT.type, flag_opts(opts, flags, &more), more);
32372e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley    if (CFG_TOYBOX_FREE) free(more);
32472e84a2f3b758026dcb37abdb8c8383c9a07ec94Rob Landley  }
325414c0cf9f5e91f7d755ba935595bbd7f3fd7c29eRob Landley}
326