source: MondoRescue/branches/3.3/mindi-busybox/util-linux/umount.c@ 3625

Last change on this file since 3625 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

File size: 6.6 KB
Line 
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 * Copyright (C) 2005 by Rob Landley <rob@landley.net>
7 *
8 * Licensed under GPLv2, see file LICENSE in this source tree.
9 */
10
11//usage:#define umount_trivial_usage
12//usage: "[OPTIONS] FILESYSTEM|DIRECTORY"
13//usage:#define umount_full_usage "\n\n"
14//usage: "Unmount file systems\n"
15//usage: IF_FEATURE_UMOUNT_ALL(
16//usage: "\n -a Unmount all file systems" IF_FEATURE_MTAB_SUPPORT(" in /etc/mtab")
17//usage: )
18//usage: IF_FEATURE_MTAB_SUPPORT(
19//usage: "\n -n Don't erase /etc/mtab entries"
20//usage: )
21//usage: "\n -r Try to remount devices as read-only if mount is busy"
22//usage: "\n -l Lazy umount (detach filesystem)"
23//usage: "\n -f Force umount (i.e., unreachable NFS server)"
24//usage: IF_FEATURE_MOUNT_LOOP(
25//usage: "\n -D Don't free loop device even if it has been used"
26//usage: )
27//usage:
28//usage:#define umount_example_usage
29//usage: "$ umount /dev/hdc1\n"
30
31#include <mntent.h>
32#include <sys/mount.h>
33#ifndef MNT_DETACH
34# define MNT_DETACH 0x00000002
35#endif
36#include "libbb.h"
37#include "common_bufsiz.h"
38
39#if defined(__dietlibc__)
40// TODO: This does not belong here.
41/* 16.12.2006, Sampo Kellomaki (sampo@iki.fi)
42 * dietlibc-0.30 does not have implementation of getmntent_r() */
43static struct mntent *getmntent_r(FILE* stream, struct mntent* result,
44 char* buffer UNUSED_PARAM, int bufsize UNUSED_PARAM)
45{
46 struct mntent* ment = getmntent(stream);
47 return memcpy(result, ment, sizeof(*ment));
48}
49#endif
50
51/* Ignored: -v -t -i
52 * bbox always acts as if -d is present.
53 * -D can be used to suppress it (bbox extension).
54 * Rationale:
55 * (1) util-linux's umount does it if "loop=..." is seen in /etc/mtab:
56 * thus, on many systems, bare umount _does_ drop loop devices.
57 * (2) many users request this feature.
58 */
59#define OPTION_STRING "fldDnra" "vt:i"
60#define OPT_FORCE (1 << 0) // Same as MNT_FORCE
61#define OPT_LAZY (1 << 1) // Same as MNT_DETACH
62//#define OPT_FREE_LOOP (1 << 2) // -d is assumed always present
63#define OPT_DONT_FREE_LOOP (1 << 3)
64#define OPT_NO_MTAB (1 << 4)
65#define OPT_REMOUNT (1 << 5)
66#define OPT_ALL (ENABLE_FEATURE_UMOUNT_ALL ? (1 << 6) : 0)
67
68int umount_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
69int umount_main(int argc UNUSED_PARAM, char **argv)
70{
71 int doForce;
72 struct mntent me;
73 FILE *fp;
74 char *fstype = NULL;
75 int status = EXIT_SUCCESS;
76 unsigned opt;
77 struct mtab_list {
78 char *dir;
79 char *device;
80 struct mtab_list *next;
81 } *mtl, *m;
82
83 opt = getopt32(argv, OPTION_STRING, &fstype);
84 //argc -= optind;
85 argv += optind;
86
87 // MNT_FORCE and MNT_DETACH (from linux/fs.h) must match
88 // OPT_FORCE and OPT_LAZY.
89 BUILD_BUG_ON(OPT_FORCE != MNT_FORCE || OPT_LAZY != MNT_DETACH);
90 doForce = opt & (OPT_FORCE|OPT_LAZY);
91
92 /* Get a list of mount points from mtab. We read them all in now mostly
93 * for umount -a (so we don't have to worry about the list changing while
94 * we iterate over it, or about getting stuck in a loop on the same failing
95 * entry. Notice that this also naturally reverses the list so that -a
96 * umounts the most recent entries first. */
97 m = mtl = NULL;
98
99 // If we're umounting all, then m points to the start of the list and
100 // the argument list should be empty (which will match all).
101 fp = setmntent(bb_path_mtab_file, "r");
102 if (!fp) {
103 if (opt & OPT_ALL)
104 bb_error_msg_and_die("can't open '%s'", bb_path_mtab_file);
105 } else {
106 setup_common_bufsiz();
107 while (getmntent_r(fp, &me, bb_common_bufsiz1, COMMON_BUFSIZE)) {
108 /* Match fstype if passed */
109 if (!match_fstype(&me, fstype))
110 continue;
111 m = xzalloc(sizeof(*m));
112 m->next = mtl;
113 m->device = xstrdup(me.mnt_fsname);
114 m->dir = xstrdup(me.mnt_dir);
115 mtl = m;
116 }
117 endmntent(fp);
118 }
119
120 // If we're not umounting all, we need at least one argument.
121 if (!(opt & OPT_ALL) && !fstype) {
122 if (!argv[0])
123 bb_show_usage();
124 m = NULL;
125 }
126
127 // Loop through everything we're supposed to umount, and do so.
128 for (;;) {
129 int curstat;
130 char *zapit = *argv;
131 char *path;
132
133 // Do we already know what to umount this time through the loop?
134 if (m)
135 path = xstrdup(m->dir);
136 // For umount -a, end of mtab means time to exit.
137 else if (opt & OPT_ALL)
138 break;
139 // Use command line argument (and look it up in mtab list)
140 else {
141 if (!zapit)
142 break;
143 argv++;
144 path = xmalloc_realpath(zapit);
145 if (path) {
146 for (m = mtl; m; m = m->next)
147 if (strcmp(path, m->dir) == 0 || strcmp(path, m->device) == 0)
148 break;
149 }
150 }
151 // If we couldn't find this sucker in /etc/mtab, punt by passing our
152 // command line argument straight to the umount syscall. Otherwise,
153 // umount the directory even if we were given the block device.
154 if (m) zapit = m->dir;
155
156// umount from util-linux 2.22.2 does not do this:
157// umount -f uses umount2(MNT_FORCE) immediately,
158// not trying umount() first.
159// (Strangely, umount -fl ignores -f: it is equivalent to umount -l.
160// We do pass both flags in this case)
161#if 0
162 // Let's ask the thing nicely to unmount.
163 curstat = umount(zapit);
164
165 // Unmount with force and/or lazy flags, if necessary.
166 if (curstat && doForce)
167#endif
168 curstat = umount2(zapit, doForce);
169
170 // If still can't umount, maybe remount read-only?
171 if (curstat) {
172 if ((opt & OPT_REMOUNT) && errno == EBUSY && m) {
173 // Note! Even if we succeed here, later we should not
174 // free loop device or erase mtab entry!
175 const char *msg = "%s busy - remounted read-only";
176 curstat = mount(m->device, zapit, NULL, MS_REMOUNT|MS_RDONLY, NULL);
177 if (curstat) {
178 msg = "can't remount %s read-only";
179 status = EXIT_FAILURE;
180 }
181 bb_error_msg(msg, m->device);
182 } else {
183 status = EXIT_FAILURE;
184 bb_perror_msg("can't unmount %s", zapit);
185 }
186 } else {
187 // De-allocate the loop device. This ioctl should be ignored on
188 // any non-loop block devices.
189 if (ENABLE_FEATURE_MOUNT_LOOP && !(opt & OPT_DONT_FREE_LOOP) && m)
190 del_loop(m->device);
191 if (ENABLE_FEATURE_MTAB_SUPPORT && !(opt & OPT_NO_MTAB) && m)
192 erase_mtab(m->dir);
193 }
194
195 // Find next matching mtab entry for -a or umount /dev
196 // Note this means that "umount /dev/blah" will unmount all instances
197 // of /dev/blah, not just the most recent.
198 if (m) {
199 while ((m = m->next) != NULL)
200 // NB: if m is non-NULL, path is non-NULL as well
201 if ((opt & OPT_ALL) || strcmp(path, m->device) == 0)
202 break;
203 }
204 free(path);
205 }
206
207 // Free mtab list if necessary
208 if (ENABLE_FEATURE_CLEAN_UP) {
209 while (mtl) {
210 m = mtl->next;
211 free(mtl->device);
212 free(mtl->dir);
213 free(mtl);
214 mtl = m;
215 }
216 }
217
218 return status;
219}
Note: See TracBrowser for help on using the repository browser.