aboutsummaryrefslogtreecommitdiff
path: root/busybox/util-linux/umount.c
diff options
context:
space:
mode:
Diffstat (limited to 'busybox/util-linux/umount.c')
-rw-r--r--busybox/util-linux/umount.c298
1 files changed, 298 insertions, 0 deletions
diff --git a/busybox/util-linux/umount.c b/busybox/util-linux/umount.c
new file mode 100644
index 000000000..21c2e6e4d
--- /dev/null
+++ b/busybox/util-linux/umount.c
@@ -0,0 +1,298 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini umount implementation for busybox
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
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 *
21 */
22
23#include <limits.h>
24#include <stdio.h>
25#include <mntent.h>
26#include <errno.h>
27#include <string.h>
28#include <stdlib.h>
29#include "busybox.h"
30
31/* Teach libc5 about realpath -- it includes it but the
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{
81 struct _mtab_entry_t *entry = NULL;
82 struct mntent *e;
83 FILE *fp;
84
85 if (mtab_cache != NULL)
86 return;
87
88 if ((fp = setmntent(bb_path_mtab_file, "r")) == NULL) {
89 bb_error_msg("Cannot open %s", bb_path_mtab_file);
90 return;
91 }
92 while ((e = getmntent(fp))) {
93 entry = xmalloc(sizeof(struct _mtab_entry_t));
94 entry->device = strdup(e->mnt_fsname);
95 entry->mountpt = strdup(e->mnt_dir);
96 entry->next = mtab_cache;
97 mtab_cache = entry;
98 }
99 endmntent(fp);
100}
101
102static char *mtab_getinfo(const char *match, const char which)
103{
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 }
124 cur = cur->next;
125 }
126 return NULL;
127}
128
129static char *mtab_next(void **iter)
130{
131 char *mp;
132
133 if (iter == NULL || *iter == NULL)
134 return NULL;
135 mp = ((struct _mtab_entry_t *) (*iter))->mountpt;
136 *iter = (void *) ((struct _mtab_entry_t *) (*iter))->next;
137 return mp;
138}
139
140static char *mtab_first(void **iter)
141{
142 struct _mtab_entry_t *mtab_iter;
143
144 if (!iter)
145 return NULL;
146 mtab_iter = mtab_cache;
147 *iter = (void *) mtab_iter;
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 }
166}
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
179#if defined CONFIG_FEATURE_MOUNT_LOOP
180 if (freeLoop && blockDevice != NULL && !strncmp("/dev/loop", blockDevice, 9))
181 /* this was a loop device, delete it */
182 del_loop(blockDevice);
183#endif
184#if defined CONFIG_FEATURE_MOUNT_FORCE
185 if (status != 0 && doForce) {
186 status = umount2(blockDevice, MNT_FORCE);
187 if (status != 0) {
188 bb_error_msg_and_die("forced umount of %s failed!", blockDevice);
189 }
190 }
191#endif
192 if (status != 0 && doRemount && errno == EBUSY) {
193 status = mount(blockDevice, name, NULL,
194 MS_MGC_VAL | MS_REMOUNT | MS_RDONLY, NULL);
195 if (status == 0) {
196 bb_error_msg("%s busy - remounted read-only", blockDevice);
197 } else {
198 bb_error_msg("Cannot remount %s read-only", blockDevice);
199 }
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
211static int umount_all(void)
212{
213 int status = TRUE;
214 char *mountpt;
215 void *iter;
216
217 for (mountpt = mtab_first(&iter); mountpt; mountpt = mtab_next(&iter)) {
218 /* Never umount /proc on a umount -a */
219 if (strstr(mountpt, "proc")!= NULL)
220 continue;
221 if (!do_umount(mountpt)) {
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 }
235 }
236 return (status);
237}
238
239extern int umount_main(int argc, char **argv)
240{
241 char path[PATH_MAX], result = 0;
242
243 if (argc < 2) {
244 bb_show_usage();
245 }
246#ifdef CONFIG_FEATURE_CLEAN_UP
247 atexit(mtab_free);
248#endif
249
250 /* Parse any options */
251 while (--argc > 0 && **(++argv) == '-') {
252 while (*++(*argv))
253 switch (**argv) {
254 case 'a':
255 umountAll = TRUE;
256 break;
257#if defined CONFIG_FEATURE_MOUNT_LOOP
258 case 'l':
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 }
281
282 mtab_read();
283 if (umountAll) {
284 if (umount_all())
285 return EXIT_SUCCESS;
286 else
287 return EXIT_FAILURE;
288 }
289
290 do {
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}