• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* umount.c - Unmount a mount point.
2  *
3  * Copyright 2012 Rob Landley <rob@landley.net>
4  *
5  * See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/umount.html
6  *
7  * Note: -n (/etc/mtab) is obsolete, /proc/mounts replaced it. Neither chroot
8  * nor per-process mount namespaces can work sanely with mtab. The kernel
9  * tracks mount points now, a userspace application can't do so anymore.
10 
11 USE_UMOUNT(NEWTOY(umount, "cndDflrat*v[!na]", TOYFLAG_BIN|TOYFLAG_STAYROOT))
12 
13 config UMOUNT
14   bool "umount"
15   default y
16   help
17     usage: umount [-a [-t TYPE[,TYPE...]]] [-f] [DIR...]
18 
19     Unmount the listed filesystems.
20 
21     -a	Unmount all mounts in /proc/mounts instead of command line list
22     -t	Restrict "all" to mounts of TYPE (or use "noTYPE" to skip)
23 */
24 
25 #define FOR_umount
26 #include "toys.h"
27 
GLOBALS(struct arg_list * t;char * types;)28 GLOBALS(
29   struct arg_list *t;
30 
31   char *types;
32 )
33 
34 // todo (done?)
35 //   borrow df code to identify filesystem?
36 //   umount -a from fstab
37 //   umount when getpid() not 0, according to fstab
38 //   lookup mount: losetup -d, bind, file, block
39 //   loopback delete
40 //   fstab -o user
41 
42 // TODO
43 // swapon, swapoff
44 
45 static void do_umount(char *dir, char *dev, int flags)
46 {
47   if (!umount2(dir, flags)) {
48     if (toys.optflags & FLAG_v) xprintf("%s unmounted\n", dir);
49 
50     // Attempt to disassociate loopback device. This ioctl should be ignored
51     // for anything else, because lanana allocated ioctl range 'L' to loopback
52     if (dev && !(toys.optflags & FLAG_D)) {
53       int lfd = open(dev, O_RDONLY);
54 
55       if (lfd != -1) {
56         // This is LOOP_CLR_FD, fetching it from headers is awkward
57         if (!ioctl(lfd, 0x4C01) && (toys.optflags & FLAG_v))
58           xprintf("%s cleared\n", dev);
59         close(lfd);
60       }
61     }
62     xprintf("umount ok\n");
63     return;
64   }
65 
66   if (toys.optflags & FLAG_r) {
67     if (!mount("", dir, "", MS_REMOUNT|MS_RDONLY, "")) {
68       if (toys.optflags & FLAG_v) xprintf("%s remounted ro\n", dir);
69       return;
70     }
71   }
72 
73   perror_msg_raw(dir);
74 }
75 
umount_main(void)76 void umount_main(void)
77 {
78   char **optargs, *pm = "/proc/mounts";
79   struct mtab_list *mlsave = 0, *mlrev = 0, *ml;
80   int flags=0;
81 
82   if (!toys.optc && !(toys.optflags & FLAG_a))
83     help_exit("Need 1 arg or -a");
84 
85   if (toys.optflags & FLAG_f) flags |= MNT_FORCE;
86   if (toys.optflags & FLAG_l) flags |= MNT_DETACH;
87 
88   // Load /proc/mounts and get a reversed list (newest first)
89   // We use the list both for -a, and to umount /dev/name or do losetup -d
90   if (!(toys.optflags & FLAG_n) && !access(pm, R_OK))
91     mlrev = dlist_terminate(mlsave = xgetmountlist(pm));
92 
93   // Unmount all: loop through mounted filesystems, skip -t, unmount the rest
94   if (toys.optflags & FLAG_a) {
95     char *typestr = 0;
96     struct arg_list *tal;
97 
98     for (tal = TT.t; tal; tal = tal->next) comma_collate(&typestr, tal->arg);
99     for (ml = mlrev; ml; ml = ml->prev)
100       if (mountlist_istype(ml, typestr)) do_umount(ml->dir, ml->device, flags);
101     if (CFG_TOYBOX_FREE) {
102       free(typestr);
103       llist_traverse(mlsave, free);
104     }
105   // TODO: under what circumstances do we umount non-absolute path?
106   } else for (optargs = toys.optargs; *optargs; optargs++) {
107     char *abs = xabspath(*optargs, 0);
108 
109     for (ml = abs ? mlrev : 0; ml; ml = ml->prev) {
110       if (!strcmp(ml->dir, abs)) break;
111       if (!strcmp(ml->device, abs)) {
112         free(abs);
113         abs = ml->dir;
114         break;
115       }
116     }
117 
118     do_umount(abs ? abs : *optargs, ml ? ml->device : 0, flags);
119     if (ml && abs != ml->dir) free(abs);
120   }
121 }
122