aboutsummaryrefslogtreecommitdiff
path: root/util-linux/umount.c
diff options
context:
space:
mode:
Diffstat (limited to 'util-linux/umount.c')
-rw-r--r--util-linux/umount.c370
1 files changed, 107 insertions, 263 deletions
diff --git a/util-linux/umount.c b/util-linux/umount.c
index 21c2e6e4d..6de71b4ab 100644
--- a/util-linux/umount.c
+++ b/util-linux/umount.c
@@ -3,20 +3,11 @@
3 * Mini umount implementation for busybox 3 * Mini umount implementation for busybox
4 * 4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> 5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 * 6 * Copyright (C) 2005 by Rob Landley <rob@landley.net>
7 * This program is free software; you can redistribute it and/or modify 7 *
8 * it under the terms of the GNU General Public License as published by 8 * This program is licensed under the GNU General Public license (GPL)
9 * the Free Software Foundation; either version 2 of the License, or 9 * version 2 or later, see http://www.fsf.org/licensing/licenses/gpl.html
10 * (at your option) any later version. 10 * or the file "LICENSE" in the busybox source tarball for the full text.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * 11 *
21 */ 12 */
22 13
@@ -26,273 +17,126 @@
26#include <errno.h> 17#include <errno.h>
27#include <string.h> 18#include <string.h>
28#include <stdlib.h> 19#include <stdlib.h>
20#include <sys/mount.h>
29#include "busybox.h" 21#include "busybox.h"
30 22
31/* Teach libc5 about realpath -- it includes it but the 23extern int umount_main(int argc, char **argv)
32 * prototype is missing... */
33#if (__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 1)
34extern char *realpath(const char *path, char *resolved_path);
35#endif
36
37static const int MNT_FORCE = 1;
38static const int MS_MGC_VAL = 0xc0ed0000; /* Magic number indicatng "new" flags */
39static const int MS_REMOUNT = 32; /* Alter flags of a mounted FS. */
40static const int MS_RDONLY = 1; /* Mount read-only. */
41
42extern int mount (__const char *__special_file, __const char *__dir,
43 __const char *__fstype, unsigned long int __rwflag,
44 __const void *__data);
45extern int umount (__const char *__special_file);
46extern int umount2 (__const char *__special_file, int __flags);
47
48struct _mtab_entry_t {
49 char *device;
50 char *mountpt;
51 struct _mtab_entry_t *next;
52};
53
54static struct _mtab_entry_t *mtab_cache = NULL;
55
56
57
58#if defined CONFIG_FEATURE_MOUNT_FORCE
59static int doForce = FALSE;
60#endif
61#if defined CONFIG_FEATURE_MOUNT_LOOP
62static int freeLoop = TRUE;
63#endif
64#if defined CONFIG_FEATURE_MTAB_SUPPORT
65static int useMtab = TRUE;
66#endif
67static int umountAll = FALSE;
68static int doRemount = FALSE;
69
70
71
72/* These functions are here because the getmntent functions do not appear
73 * to be re-entrant, which leads to all sorts of problems when we try to
74 * use them recursively - randolph
75 *
76 * TODO: Perhaps switch to using Glibc's getmntent_r
77 * -Erik
78 */
79static void mtab_read(void)
80{ 24{
81 struct _mtab_entry_t *entry = NULL; 25 int doForce = 0;
82 struct mntent *e; 26 int freeLoop = ENABLE_FEATURE_MOUNT_LOOP;
27 int useMtab = ENABLE_FEATURE_MTAB_SUPPORT;
28 int umountAll = FALSE;
29 int doRemount = FALSE;
30 char path[2*PATH_MAX];
31 struct mntent me;
83 FILE *fp; 32 FILE *fp;
84 33 int status=EXIT_SUCCESS;
85 if (mtab_cache != NULL) 34 struct mtab_list {
86 return; 35 char *dir;
87 36 char *device;
88 if ((fp = setmntent(bb_path_mtab_file, "r")) == NULL) { 37 struct mtab_list *next;
89 bb_error_msg("Cannot open %s", bb_path_mtab_file); 38 } *mtl, *m;
90 return; 39
91 } 40 if(argc < 2) bb_show_usage();
92 while ((e = getmntent(fp))) { 41
93 entry = xmalloc(sizeof(struct _mtab_entry_t)); 42 /* Parse any options */
94 entry->device = strdup(e->mnt_fsname); 43 while (--argc > 0 && **(++argv) == '-') {
95 entry->mountpt = strdup(e->mnt_dir); 44 while (*++(*argv)) {
96 entry->next = mtab_cache; 45 if(**argv=='a') umountAll = TRUE;
97 mtab_cache = entry; 46 else if(ENABLE_FEATURE_MOUNT_LOOP && **argv=='D') freeLoop = FALSE;
98 } 47 else if(ENABLE_FEATURE_MTAB_SUPPORT && **argv=='n') useMtab = FALSE;
99 endmntent(fp); 48 else if(**argv=='f') doForce = 1; // MNT_FORCE
100} 49 else if(**argv=='l') doForce = 2; // MNT_DETACH
101 50 else if(**argv=='r') doRemount = TRUE;
102static char *mtab_getinfo(const char *match, const char which) 51 else if(**argv=='v');
103{ 52 else bb_show_usage();
104 struct _mtab_entry_t *cur = mtab_cache;
105
106 while (cur) {
107 if (strcmp(cur->mountpt, match) == 0 ||
108 strcmp(cur->device, match) == 0) {
109 if (which == MTAB_GETMOUNTPT) {
110 return cur->mountpt;
111 } else {
112#if !defined CONFIG_FEATURE_MTAB_SUPPORT
113 if (strcmp(cur->device, "rootfs") == 0) {
114 continue;
115 } else if (strcmp(cur->device, "/dev/root") == 0) {
116 /* Adjusts device to be the real root device,
117 * or leaves device alone if it can't find it */
118 cur->device = find_real_root_device_name();
119 }
120#endif
121 return cur->device;
122 }
123 } 53 }
124 cur = cur->next;
125 } 54 }
126 return NULL;
127}
128
129static char *mtab_next(void **iter)
130{
131 char *mp;
132 55
133 if (iter == NULL || *iter == NULL) 56 /* Get a list of mount points from mtab. We read them all in now mostly
134 return NULL; 57 * for umount -a (so we don't have to worry about the list changing while
135 mp = ((struct _mtab_entry_t *) (*iter))->mountpt; 58 * we iterate over it, or about getting stuck in a loop on the same failing
136 *iter = (void *) ((struct _mtab_entry_t *) (*iter))->next; 59 * entry. Notice that this also naturally reverses the list so that -a
137 return mp; 60 * umounts the most recent entries first. */
138} 61
139 62 m=mtl=0;
140static char *mtab_first(void **iter) 63 if(!(fp = setmntent(bb_path_mtab_file, "r")))
141{ 64 bb_error_msg_and_die("Cannot open %s", bb_path_mtab_file);
142 struct _mtab_entry_t *mtab_iter; 65 while (getmntent_r(fp,&me,path,sizeof(path))) {
143 66 m=xmalloc(sizeof(struct mtab_list));
144 if (!iter) 67 m->next=mtl;
145 return NULL; 68 m->device=bb_xstrdup(me.mnt_fsname);
146 mtab_iter = mtab_cache; 69 m->dir=bb_xstrdup(me.mnt_dir);
147 *iter = (void *) mtab_iter; 70 mtl=m;
148 return mtab_next(iter);
149}
150
151/* Don't bother to clean up, since exit() does that
152 * automagically, so we can save a few bytes */
153#ifdef CONFIG_FEATURE_CLEAN_UP
154static void mtab_free(void)
155{
156 struct _mtab_entry_t *this, *next;
157
158 this = mtab_cache;
159 while (this) {
160 next = this->next;
161 free(this->device);
162 free(this->mountpt);
163 free(this);
164 this = next;
165 } 71 }
166} 72 endmntent(fp);
167#endif
168
169static int do_umount(const char *name)
170{
171 int status;
172 char *blockDevice = mtab_getinfo(name, MTAB_GETDEVICE);
173
174 if (blockDevice && strcmp(blockDevice, name) == 0)
175 name = mtab_getinfo(blockDevice, MTAB_GETMOUNTPT);
176
177 status = umount(name);
178 73
179#if defined CONFIG_FEATURE_MOUNT_LOOP 74 /* If we're umounting all, then m points to the start of the list and
180 if (freeLoop && blockDevice != NULL && !strncmp("/dev/loop", blockDevice, 9)) 75 * the argument list should be empty (which will match all). */
181 /* this was a loop device, delete it */ 76 if(!umountAll) m=0;
182 del_loop(blockDevice); 77
183#endif 78 // Loop through everything we're supposed to umount, and do so.
184#if defined CONFIG_FEATURE_MOUNT_FORCE 79 for(;;) {
185 if (status != 0 && doForce) { 80 int curstat;
186 status = umount2(blockDevice, MNT_FORCE); 81
187 if (status != 0) { 82 // Do we alrady know what to umount this time through the loop?
188 bb_error_msg_and_die("forced umount of %s failed!", blockDevice); 83 if(m) safe_strncpy(path,m->dir,PATH_MAX);
189 } 84 // For umountAll, end of mtab means time to exit.
190 } 85 else if(umountAll) break;
191#endif 86 // Get next command line argument (and look it up in mtab list)
192 if (status != 0 && doRemount && errno == EBUSY) { 87 else if(!argc--) break;
193 status = mount(blockDevice, name, NULL, 88 else {
194 MS_MGC_VAL | MS_REMOUNT | MS_RDONLY, NULL); 89 // Get next command line argument (and look it up in mtab list)
195 if (status == 0) { 90 realpath(*argv++, path);
196 bb_error_msg("%s busy - remounted read-only", blockDevice); 91 for(m = mtl; m; m = m->next)
197 } else { 92 if(!strcmp(path, m->dir) || !strcmp(path, m->device))
198 bb_error_msg("Cannot remount %s read-only", blockDevice); 93 break;
199 } 94 }
200 }
201 if (status == 0) {
202#if defined CONFIG_FEATURE_MTAB_SUPPORT
203 if (useMtab)
204 erase_mtab(name);
205#endif
206 return (TRUE);
207 }
208 return (FALSE);
209}
210 95
211static int umount_all(void) 96 // Let's ask the thing nicely to unmount.
212{ 97 curstat = umount(path);
213 int status = TRUE;
214 char *mountpt;
215 void *iter;
216 98
217 for (mountpt = mtab_first(&iter); mountpt; mountpt = mtab_next(&iter)) { 99 // Force the unmount, if necessary.
218 /* Never umount /proc on a umount -a */ 100 if(curstat && doForce) {
219 if (strstr(mountpt, "proc")!= NULL) 101 curstat = umount2(path, doForce);
220 continue; 102 if(curstat)
221 if (!do_umount(mountpt)) { 103 bb_error_msg_and_die("forced umount of %s failed!", path);
222 /* Don't bother retrying the umount on busy devices */
223 if (errno == EBUSY) {
224 bb_perror_msg("%s", mountpt);
225 status = FALSE;
226 continue;
227 }
228 if (!do_umount(mountpt)) {
229 printf("Couldn't umount %s on %s: %s\n",
230 mountpt, mtab_getinfo(mountpt, MTAB_GETDEVICE),
231 strerror(errno));
232 status = FALSE;
233 }
234 } 104 }
235 }
236 return (status);
237}
238 105
239extern int umount_main(int argc, char **argv) 106 // If still can't umount, maybe remount read-only?
240{ 107 if (curstat && doRemount && errno == EBUSY && m) {
241 char path[PATH_MAX], result = 0; 108 curstat = mount(m->device, path, NULL, MS_REMOUNT|MS_RDONLY, NULL);
109 bb_error_msg(curstat ? "Cannot remount %s read-only" :
110 "%s busy - remounted read-only", m->device);
111 }
242 112
243 if (argc < 2) { 113 /* De-allcate the loop device. This ioctl should be ignored on any
244 bb_show_usage(); 114 * non-loop block devices. */
245 } 115 if(ENABLE_FEATURE_MOUNT_LOOP && freeLoop && m)
246#ifdef CONFIG_FEATURE_CLEAN_UP 116 del_loop(m->device);
247 atexit(mtab_free);
248#endif
249 117
250 /* Parse any options */ 118 if(curstat) {
251 while (--argc > 0 && **(++argv) == '-') { 119 if(useMtab && m) erase_mtab(m->dir);
252 while (*++(*argv)) 120 status = EXIT_FAILURE;
253 switch (**argv) { 121 bb_perror_msg("Couldn't umount %s\n", path);
254 case 'a': 122 }
255 umountAll = TRUE; 123 // Find next matching mtab entry for -a or umount /dev
256 break; 124 while(m && (m = m->next))
257#if defined CONFIG_FEATURE_MOUNT_LOOP 125 if(umountAll || !strcmp(path,m->device))
258 case 'l': 126 break;
259 freeLoop = FALSE;
260 break;
261#endif
262#ifdef CONFIG_FEATURE_MTAB_SUPPORT
263 case 'n':
264 useMtab = FALSE;
265 break;
266#endif
267#ifdef CONFIG_FEATURE_MOUNT_FORCE
268 case 'f':
269 doForce = TRUE;
270 break;
271#endif
272 case 'r':
273 doRemount = TRUE;
274 break;
275 case 'v':
276 break; /* ignore -v */
277 default:
278 bb_show_usage();
279 }
280 } 127 }
281 128
282 mtab_read(); 129 // Free mtab list if necessary
283 if (umountAll) { 130
284 if (umount_all()) 131 if(ENABLE_FEATURE_CLEAN_UP) {
285 return EXIT_SUCCESS; 132 while(mtl) {
286 else 133 m=mtl->next;
287 return EXIT_FAILURE; 134 free(mtl->device);
135 free(mtl->dir);
136 free(mtl);
137 mtl=m;
138 }
288 } 139 }
289 140
290 do { 141 return status;
291 if (realpath(*argv, path) != NULL)
292 if (do_umount(path))
293 continue;
294 bb_perror_msg("%s", path);
295 result++;
296 } while (--argc > 0 && ++argv);
297 return result;
298} 142}