1 /* vi: set sw=4 ts=4: */
3 * Mini umount implementation for busybox
6 * Copyright (C) 1999,2000 by Lineo, inc.
7 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 #define MS_MGC_VAL 0xc0ed0000 /* Magic number indicatng "new" flags */
33 #define MS_REMOUNT 32 /* Alter flags of a mounted FS. */
34 #define MS_RDONLY 1 /* Mount read-only. */
36 extern int mount (__const char *__special_file, __const char *__dir,
37 __const char *__fstype, unsigned long int __rwflag,
38 __const void *__data);
39 extern int umount (__const char *__special_file);
40 extern int umount2 (__const char *__special_file, int __flags);
44 static const char umount_usage[] =
45 "umount [flags] filesystem|directory\n"
46 #ifndef BB_FEATURE_TRIVIAL_HELP
47 "Unmount file systems\n"
48 "\nFlags:\n" "\t-a:\tUnmount all file systems"
50 " in /etc/mtab\n\t-n:\tDon't erase /etc/mtab entries\n"
54 "\t-r:\tTry to remount devices as read-only if mount is busy\n"
55 #if defined BB_FEATURE_MOUNT_FORCE
56 "\t-f:\tForce filesystem umount (i.e. unreachable NFS server)\n"
58 #if defined BB_FEATURE_MOUNT_LOOP
59 "\t-l:\tDo not free loop device (if a loop device has been used)\n"
64 struct _mtab_entry_t {
67 struct _mtab_entry_t *next;
70 static struct _mtab_entry_t *mtab_cache = NULL;
74 #if defined BB_FEATURE_MOUNT_FORCE
75 static int doForce = FALSE;
77 #if defined BB_FEATURE_MOUNT_LOOP
78 static int freeLoop = TRUE;
80 static int useMtab = TRUE;
81 static int umountAll = FALSE;
82 static int doRemount = FALSE;
83 extern const char mtab_file[]; /* Defined in utility.c */
87 /* These functions are here because the getmntent functions do not appear
88 * to be re-entrant, which leads to all sorts of problems when we try to
89 * use them recursively - randolph
91 * TODO: Perhaps switch to using Glibc's getmntent_r
96 struct _mtab_entry_t *entry = NULL;
100 if (mtab_cache != NULL)
103 if ((fp = setmntent(mtab_file, "r")) == NULL) {
104 fprintf(stderr, "Cannot open %s\n", mtab_file);
107 while ((e = getmntent(fp))) {
108 entry = xmalloc(sizeof(struct _mtab_entry_t));
109 entry->device = strdup(e->mnt_fsname);
110 entry->mountpt = strdup(e->mnt_dir);
111 entry->next = mtab_cache;
117 char *mtab_getinfo(const char *match, const char which)
119 struct _mtab_entry_t *cur = mtab_cache;
122 if (strcmp(cur->mountpt, match) == 0 ||
123 strcmp(cur->device, match) == 0) {
124 if (which == MTAB_GETMOUNTPT) {
128 if (strcmp(cur->device, "/dev/root") == 0) {
129 /* Adjusts device to be the real root device,
130 * or leaves device alone if it can't find it */
131 find_real_root_device_name( cur->device);
132 return ( cur->device);
143 char *mtab_first(void **iter)
145 struct _mtab_entry_t *mtab_iter;
149 mtab_iter = mtab_cache;
150 *iter = (void *) mtab_iter;
151 return mtab_next(iter);
154 char *mtab_next(void **iter)
158 if (iter == NULL || *iter == NULL)
160 mp = ((struct _mtab_entry_t *) (*iter))->mountpt;
161 *iter = (void *) ((struct _mtab_entry_t *) (*iter))->next;
165 /* Don't bother to clean up, since exit() does that
166 * automagically, so we can save a few bytes */
170 struct _mtab_entry_t *this, *next;
185 static int do_umount(const char *name, int useMtab)
188 char *blockDevice = mtab_getinfo(name, MTAB_GETDEVICE);
190 if (blockDevice && strcmp(blockDevice, name) == 0)
191 name = mtab_getinfo(blockDevice, MTAB_GETMOUNTPT);
193 status = umount(name);
195 #if defined BB_FEATURE_MOUNT_LOOP
196 if (freeLoop == TRUE && blockDevice != NULL && !strncmp("/dev/loop", blockDevice, 9))
197 /* this was a loop device, delete it */
198 del_loop(blockDevice);
200 #if defined BB_FEATURE_MOUNT_FORCE
201 if (status != 0 && doForce == TRUE) {
202 status = umount2(blockDevice, MNT_FORCE);
204 fatalError("umount: forced umount of %s failed!\n", blockDevice);
208 if (status != 0 && doRemount == TRUE && errno == EBUSY) {
209 status = mount(blockDevice, name, NULL,
210 MS_MGC_VAL | MS_REMOUNT | MS_RDONLY, NULL);
212 fprintf(stderr, "umount: %s busy - remounted read-only\n",
215 fprintf(stderr, "umount: Cannot remount %s read-only\n",
229 static int umount_all(int useMtab)
235 for (mountpt = mtab_first(&iter); mountpt; mountpt = mtab_next(&iter)) {
236 /* Never umount /proc on a umount -a */
237 if (strstr(mountpt, "proc")!= NULL)
239 status = do_umount(mountpt, useMtab);
241 /* Don't bother retrying the umount on busy devices */
242 if (errno == EBUSY) {
246 status = do_umount(mountpt, useMtab);
248 printf("Couldn't umount %s on %s: %s\n",
249 mountpt, mtab_getinfo(mountpt, MTAB_GETDEVICE),
257 extern int umount_main(int argc, char **argv)
263 /* Parse any options */
264 while (--argc > 0 && **(++argv) == '-') {
270 #if defined BB_FEATURE_MOUNT_LOOP
280 #ifdef BB_FEATURE_MOUNT_FORCE
289 break; /* ignore -v */
296 if (umountAll == TRUE) {
297 exit(umount_all(useMtab));
299 if (do_umount(*argv, useMtab) == 0)