comparison toys/lsb/mount.c @ 1594:9b906eb047e8 draft

Don't mount a filesystem over an existing one with the same /dev and /dir. The OS mostly catches this for block devices, but calling "mount -a" twice shouldn't overmount tmpfs entries with new tmpfs instances. (This needs a test suite entry, and the test suite needs a root context to run in...)
author Rob Landley <rob@landley.net>
date Tue, 02 Dec 2014 03:17:34 -0600
parents 22691dfb17b9
children 58d9f1b61f0a
comparison
equal deleted inserted replaced
1593:f2cac60ab2d3 1594:9b906eb047e8
5 * See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/mount.html 5 * See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/mount.html
6 * Note: -hV is bad spec, haven't implemented -FsLU yet 6 * Note: -hV is bad spec, haven't implemented -FsLU yet
7 * no mtab (/proc/mounts does it) so -n is NOP. 7 * no mtab (/proc/mounts does it) so -n is NOP.
8 8
9 USE_MOUNT(NEWTOY(mount, "?O:afnrvwt:o*[-rw]", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT)) 9 USE_MOUNT(NEWTOY(mount, "?O:afnrvwt:o*[-rw]", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT))
10 USE_NFSMOUNT(NEWTOY(nfsmount, "?<2>2", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT)) 10 //USE_NFSMOUNT(NEWTOY(nfsmount, "?<2>2", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT))
11 11
12 config MOUNT 12 config MOUNT
13 bool "mount" 13 bool "mount"
14 default y 14 default y
15 help 15 help
32 This mount autodetects loopback mounts (a file on a directory) and 32 This mount autodetects loopback mounts (a file on a directory) and
33 bind mounts (file on file, directory on directory), so you don't need 33 bind mounts (file on file, directory on directory), so you don't need
34 to say --bind or --loop. You can also "mount -a /path" to mount everything 34 to say --bind or --loop. You can also "mount -a /path" to mount everything
35 in /etc/fstab under /path, even if it's noauto. 35 in /etc/fstab under /path, even if it's noauto.
36 36
37 config NFSMOUNT 37 #config NFSMOUNT
38 bool "nfsmount" 38 # bool "nfsmount"
39 default n 39 # default n
40 help 40 # help
41 usage: nfsmount SHARE DIR 41 # usage: nfsmount SHARE DIR
42 42 #
43 Invoke an eldrich horror from the dawn of time. 43 # Invoke an eldrich horror from the dawn of time.
44 */ 44 */
45 45
46 #define FOR_mount 46 #define FOR_mount
47 #include "toys.h" 47 #include "toys.h"
48 48
244 void mount_main(void) 244 void mount_main(void)
245 { 245 {
246 char *opts = 0, *dev = 0, *dir = 0, **ss; 246 char *opts = 0, *dev = 0, *dir = 0, **ss;
247 long flags = MS_SILENT; 247 long flags = MS_SILENT;
248 struct arg_list *o; 248 struct arg_list *o;
249 struct mtab_list *mtl, *mm, *remount = 0; 249 struct mtab_list *mtl, *mtl2 = 0, *mm, *remount;
250 250
251 // TODO
251 // remount 252 // remount
252 // - overmounts 253 // - overmounts
253 // shared subtree 254 // shared subtree
254 // -o parsed after fstab options 255 // -o parsed after fstab options
255 // test if mountpoint already exists (-o noremount?) 256 // test if mountpoint already exists (-o noremount?)
273 } 274 }
274 275
275 if ((toys.optflags & FLAG_a) && dir) error_exit("-a with >1 arg"); 276 if ((toys.optflags & FLAG_a) && dir) error_exit("-a with >1 arg");
276 277
277 // For remount we need _last_ match (in case of overmounts), so traverse 278 // For remount we need _last_ match (in case of overmounts), so traverse
278 // in reverse order. 279 // in reverse order. (Yes I'm using remount as a boolean for a bit here,
279 if (comma_scan(opts, "remount", 1)) 280 // the double cast is to get gcc to shut up about it.)
280 remount = dlist_terminate(mtl = xgetmountlist("/proc/mounts")); 281 remount = (void *)(long)comma_scan(opts, "remount", 1);
282 if (((toys.optflags & FLAG_a) && !access("/proc/mounts", R_OK)) || remount) {
283 mm = dlist_terminate(mtl = mtl2 = xgetmountlist(0));
284 if (remount) remount = mm;
285 }
281 286
282 // Do we need to do an /etc/fstab trawl? 287 // Do we need to do an /etc/fstab trawl?
283 // This covers -a, -o remount, one argument, all user mounts 288 // This covers -a, -o remount, one argument, all user mounts
284 if ((toys.optflags & FLAG_a) || (dev && (!dir || getuid() || remount))) { 289 if ((toys.optflags & FLAG_a) || (dev && (!dir || getuid() || remount))) {
285 if (!remount) dlist_terminate(mtl = xgetmountlist("/etc/fstab")); 290 if (!remount) dlist_terminate(mtl = xgetmountlist("/etc/fstab"));
286 291
287 for (mm = remount ? remount : mtl; mm; mm = (remount ? mm->prev : mm->next)) 292 for (mm = remount ? remount : mtl; mm; mm = (remount ? mm->prev : mm->next))
288 { 293 {
294 char *aopts = 0;
295 struct mtab_list *mmm = 0;
289 int aflags, noauto, len; 296 int aflags, noauto, len;
290 char *aopts = 0;
291 297
292 // Check for noauto and get it out of the option list. (Unknown options 298 // Check for noauto and get it out of the option list. (Unknown options
293 // that make it to the kernel give filesystem drivers indigestion.) 299 // that make it to the kernel give filesystem drivers indigestion.)
294 noauto = comma_scan(mm->opts, "noauto", 1); 300 noauto = comma_scan(mm->opts, "noauto", 1);
301
295 if (toys.optflags & FLAG_a) { 302 if (toys.optflags & FLAG_a) {
296 // "mount -a /path" to mount all entries under /path 303 // "mount -a /path" to mount all entries under /path
297 if (dev) { 304 if (dev) {
298 len = strlen(dev); 305 len = strlen(dev);
299 if (strncmp(dev, mm->dir, len) 306 if (strncmp(dev, mm->dir, len)
305 if (dir && strcmp(dir, mm->dir)) continue; 312 if (dir && strcmp(dir, mm->dir)) continue;
306 if (dev && strcmp(dev, mm->device) && (dir || strcmp(dev, mm->dir))) 313 if (dev && strcmp(dev, mm->device) && (dir || strcmp(dev, mm->dir)))
307 continue; 314 continue;
308 } 315 }
309 316
317 // Don't overmount the same dev on the same directory
318 // (Unless root explicitly says to in non -a mode.)
319 if (mtl2 && !remount)
320 for (mmm = mtl2; mmm; mmm = mmm->next)
321 if (!strcmp(mm->dir, mmm->dir) && !strcmp(mm->device, mmm->device))
322 break;
323
310 // user only counts from fstab, not opts. 324 // user only counts from fstab, not opts.
311 TT.okuser = comma_scan(mm->opts, "user", 1); 325 if (!mmm) {
312 aflags = flag_opts(mm->opts, flags, &aopts); 326 TT.okuser = comma_scan(mm->opts, "user", 1);
313 aflags = flag_opts(opts, aflags, &aopts); 327 aflags = flag_opts(mm->opts, flags, &aopts);
314 328 aflags = flag_opts(opts, aflags, &aopts);
315 mount_filesystem(mm->device, mm->dir, mm->type, aflags, aopts); 329
330 mount_filesystem(mm->device, mm->dir, mm->type, aflags, aopts);
331 } // TODO else if (getuid()) error_msg("already there") ?
316 free(aopts); 332 free(aopts);
317 333
318 if (!(toys.optflags & FLAG_a)) break; 334 if (!(toys.optflags & FLAG_a)) break;
319 } 335 }
320 if (CFG_TOYBOX_FREE) llist_traverse(mtl, free); 336 if (CFG_TOYBOX_FREE) {
337 llist_traverse(mtl, free);
338 llist_traverse(mtl2, free);
339 }
321 if (!mm && !(toys.optflags & FLAG_a)) 340 if (!mm && !(toys.optflags & FLAG_a))
322 error_exit("'%s' not in %s", dir ? dir : dev, 341 error_exit("'%s' not in %s", dir ? dir : dev,
323 remount ? "/proc/mounts" : "fstab"); 342 remount ? "/proc/mounts" : "fstab");
324 343
325 // show mounts from /proc/mounts 344 // show mounts from /proc/mounts