1 /* vi: set sw=4 ts=4: */
3 * Mini umount implementation for busybox
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 * Copyright (C) 2005 by Rob Landley <rob@landley.net>
8 * Licensed under GPL version 2, see file LICENSE in this tarball for details.
14 #if defined(__dietlibc__)
15 /* 16.12.2006, Sampo Kellomaki (sampo@iki.fi)
16 * dietlibc-0.30 does not have implementation of getmntent_r() */
17 static struct mntent
*getmntent_r(FILE* stream
, struct mntent
* result
,
18 char* buffer UNUSED_PARAM
, int bufsize UNUSED_PARAM
)
20 struct mntent
* ment
= getmntent(stream
);
21 return memcpy(result
, ment
, sizeof(*ment
));
25 /* ignored: -v -d -t -i */
26 #define OPTION_STRING "fldnra" "vdt:i"
27 #define OPT_FORCE (1 << 0)
28 #define OPT_LAZY (1 << 1)
29 #define OPT_FREELOOP (1 << 2)
30 #define OPT_NO_MTAB (1 << 3)
31 #define OPT_REMOUNT (1 << 4)
32 #define OPT_ALL (ENABLE_FEATURE_UMOUNT_ALL ? (1 << 5) : 0)
34 // These constants from linux/fs.h must match OPT_FORCE and OPT_LAZY,
35 // otherwise "doForce" trick below won't work!
36 //#define MNT_FORCE 0x00000001 /* Attempt to forcibly umount */
37 //#define MNT_DETACH 0x00000002 /* Just detach from the tree */
39 int umount_main(int argc
, char **argv
) MAIN_EXTERNALLY_VISIBLE
;
40 int umount_main(int argc UNUSED_PARAM
, char **argv
)
43 char *const path
= xmalloc(PATH_MAX
+ 2); /* to save stack */
47 int status
= EXIT_SUCCESS
;
52 struct mtab_list
*next
;
55 opt
= getopt32(argv
, OPTION_STRING
, &fstype
);
58 doForce
= MAX((opt
& OPT_FORCE
), (opt
& OPT_LAZY
));
60 /* Get a list of mount points from mtab. We read them all in now mostly
61 * for umount -a (so we don't have to worry about the list changing while
62 * we iterate over it, or about getting stuck in a loop on the same failing
63 * entry. Notice that this also naturally reverses the list so that -a
64 * umounts the most recent entries first. */
67 // If we're umounting all, then m points to the start of the list and
68 // the argument list should be empty (which will match all).
69 fp
= setmntent(bb_path_mtab_file
, "r");
72 bb_error_msg_and_die("can't open '%s'", bb_path_mtab_file
);
74 while (getmntent_r(fp
, &me
, path
, PATH_MAX
)) {
75 /* Match fstype if passed */
76 if (!match_fstype(&me
, fstype
))
78 m
= xzalloc(sizeof(*m
));
80 m
->device
= xstrdup(me
.mnt_fsname
);
81 m
->dir
= xstrdup(me
.mnt_dir
);
87 // If we're not umounting all, we need at least one argument.
88 if (!(opt
& OPT_ALL
) && !fstype
) {
94 // Loop through everything we're supposed to umount, and do so.
99 // Do we already know what to umount this time through the loop?
101 safe_strncpy(path
, m
->dir
, PATH_MAX
);
102 // For umount -a, end of mtab means time to exit.
103 else if (opt
& OPT_ALL
)
105 // Use command line argument (and look it up in mtab list)
110 realpath(zapit
, path
);
111 for (m
= mtl
; m
; m
= m
->next
)
112 if (!strcmp(path
, m
->dir
) || !strcmp(path
, m
->device
))
115 // If we couldn't find this sucker in /etc/mtab, punt by passing our
116 // command line argument straight to the umount syscall. Otherwise,
117 // umount the directory even if we were given the block device.
118 if (m
) zapit
= m
->dir
;
120 // Let's ask the thing nicely to unmount.
121 curstat
= umount(zapit
);
123 // Force the unmount, if necessary.
124 if (curstat
&& doForce
)
125 curstat
= umount2(zapit
, doForce
);
127 // If still can't umount, maybe remount read-only?
129 if ((opt
& OPT_REMOUNT
) && errno
== EBUSY
&& m
) {
130 // Note! Even if we succeed here, later we should not
131 // free loop device or erase mtab entry!
132 const char *msg
= "%s busy - remounted read-only";
133 curstat
= mount(m
->device
, zapit
, NULL
, MS_REMOUNT
|MS_RDONLY
, NULL
);
135 msg
= "can't remount %s read-only";
136 status
= EXIT_FAILURE
;
138 bb_error_msg(msg
, m
->device
);
140 status
= EXIT_FAILURE
;
141 bb_perror_msg("can't %sumount %s", (doForce
? "forcibly " : ""), zapit
);
144 // De-allocate the loop device. This ioctl should be ignored on
145 // any non-loop block devices.
146 if (ENABLE_FEATURE_MOUNT_LOOP
&& (opt
& OPT_FREELOOP
) && m
)
148 if (ENABLE_FEATURE_MTAB_SUPPORT
&& !(opt
& OPT_NO_MTAB
) && m
)
152 // Find next matching mtab entry for -a or umount /dev
153 // Note this means that "umount /dev/blah" will unmount all instances
154 // of /dev/blah, not just the most recent.
155 if (m
) while ((m
= m
->next
) != NULL
)
156 if ((opt
& OPT_ALL
) || !strcmp(path
, m
->device
))
160 // Free mtab list if necessary
161 if (ENABLE_FEATURE_CLEAN_UP
) {