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