aboutsummaryrefslogtreecommitdiff
path: root/util-linux/umount.c
diff options
context:
space:
mode:
authorlandley <landley@69ca8d6d-28ef-0310-b511-8ec308f3f277>2005-08-10 20:35:54 +0000
committerlandley <landley@69ca8d6d-28ef-0310-b511-8ec308f3f277>2005-08-10 20:35:54 +0000
commit5c30637d244bd5b2915599286da3bbd7f2721ee7 (patch)
tree9179ec8c6dc4e402cdc4a86cf6af119745de2f40 /util-linux/umount.c
parent3832c8463134a14ed87f6a267327412a91ee45b9 (diff)
downloadbusybox-w32-5c30637d244bd5b2915599286da3bbd7f2721ee7.tar.gz
busybox-w32-5c30637d244bd5b2915599286da3bbd7f2721ee7.tar.bz2
busybox-w32-5c30637d244bd5b2915599286da3bbd7f2721ee7.zip
Major rewrite of mount, umount, losetup. Untangled lots of code, shrunk
things down a bit, fixed a number of funky corner cases, added support for several new features (things like mount --move, mount --bind, lazy unounts, automatic detection of loop mounts, and so on). Probably broke several other things, but it's fixable. (Bang on it, tell me what doesn't work for you...) Note: you no longer need to say "-o loop". It does that for you when necessary. Still need to add "user mount" support, which involves making mount suid. Not too hard to do under the new infrastructure, just haven't done it yet... The previous code had the following notes, that belong in the version control comments: - * 3/21/1999 Charles P. Wright <cpwright@cpwright.com> - * searches through fstab when -a is passed - * will try mounting stuff with all fses when passed -t auto - * - * 1999-04-17 Dave Cinege...Rewrote -t auto. Fixed ro mtab. - * - * 1999-10-07 Erik Andersen <andersen@codepoet.org>. - * Rewrite of a lot of code. Removed mtab usage (I plan on - * putting it back as a compile-time option some time), - * major adjustments to option parsing, and some serious - * dieting all around. - * - * 1999-11-06 mtab support is back - andersee - * - * 2000-01-12 Ben Collins <bcollins@debian.org>, Borrowed utils-linux's - * mount to add loop support. - * - * 2000-04-30 Dave Cinege <dcinege@psychosis.com> - * Rewrote fstab while loop and lower mount section. Can now do - * single mounts from fstab. Can override fstab options for single - * mount. Common mount_one call for single mounts and 'all'. Fixed - * mtab updating and stale entries. Removed 'remount' default. - * git-svn-id: svn://busybox.net/trunk/busybox@11099 69ca8d6d-28ef-0310-b511-8ec308f3f277
Diffstat (limited to '')
-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}