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