aboutsummaryrefslogtreecommitdiff
path: root/util-linux
diff options
context:
space:
mode:
Diffstat (limited to 'util-linux')
-rw-r--r--util-linux/Config.in59
-rw-r--r--util-linux/losetup.c48
-rw-r--r--util-linux/mount.c681
-rw-r--r--util-linux/nfsmount.c6
-rw-r--r--util-linux/umount.c370
5 files changed, 447 insertions, 717 deletions
diff --git a/util-linux/Config.in b/util-linux/Config.in
index 7007915ba..7fde01971 100644
--- a/util-linux/Config.in
+++ b/util-linux/Config.in
@@ -323,54 +323,43 @@ config CONFIG_UMOUNT
323 the tool to use. If you enabled the 'mount' utility, you almost certainly 323 the tool to use. If you enabled the 'mount' utility, you almost certainly
324 also want to enable 'umount'. 324 also want to enable 'umount'.
325 325
326config CONFIG_FEATURE_MOUNT_FORCE
327 bool " Support forced filesystem unmounting"
328 default n
329 depends on CONFIG_UMOUNT
330 help
331 This allows you to _force_ a filesystem to be umounted. This is generally
332 only useful when you want to get rid of an unreachable NFS system.
333
334comment "Common options for mount/umount" 326comment "Common options for mount/umount"
335 depends on CONFIG_MOUNT || CONFIG_UMOUNT 327 depends on CONFIG_MOUNT || CONFIG_UMOUNT
336 328
337config CONFIG_FEATURE_MOUNT_LOOP 329config CONFIG_FEATURE_MOUNT_LOOP
338 bool " Support for loop devices" 330 bool " Support loopback mounts"
339 default n 331 default n
340 depends on CONFIG_MOUNT || CONFIG_UMOUNT 332 depends on CONFIG_MOUNT || CONFIG_UMOUNT
341 help 333 help
342 Enabling this feature allows automatic loopback mounts, meaning you can mount 334 Enabling this feature allows automatic mounting of files (containing
343 filesystems contained in normal files as well as in block devices. The mount 335 filesystem images) via the linux kernel's loopback devices. The mount
344 and umount commands will detect you are trying to mount a file instead of a 336 command will detect you are trying to mount a file instead of a block
345 block device, and transparently associate it with a loopback device (and free 337 device, and transparently associate the file with a loopback device.
346 the loopback device on unmount) for you. 338 The umount command will also free that loopback device.
347 339
348 You can still use the 'losetup' utility and mount the loopback device yourself 340 You can still use the 'losetup' utility (to manually associate files
349 if you need to do something advanced, such as specify an offset or cryptographic 341 with loop devices) if you need to do something advanced, such as
350 options to the loopback device. 342 specify an offset or cryptographic options to the loopback device.
351 343 (If you don't want umount to free the loop device, use "umount -D".)
352config CONFIG_FEATURE_MOUNT_LOOP_MAX
353 int " max number of loop devices"
354 default 7
355 depends on CONFIG_FEATURE_MOUNT_LOOP
356 help
357 This option sets the highest numbered loop device to be used
358 automatically by the '-o loop' feature of mount.
359 344
360config CONFIG_FEATURE_MTAB_SUPPORT 345config CONFIG_FEATURE_MTAB_SUPPORT
361 bool " Support for a /etc/mtab file (instead of symlink to /proc/mounts)" 346 bool " Support for the old /etc/mtab file"
362 default n 347 default n
363 depends on CONFIG_MOUNT || CONFIG_UMOUNT 348 depends on CONFIG_MOUNT || CONFIG_UMOUNT
364 help 349 help
365 If your root filesystem is writable and you wish to have the 'mount' 350 Historically, Unix systems kept track of the currently mounted
366 utility create an mtab file listing the filesystems which have been 351 partitions in the file "/etc/mtab". These days, the kernel exports
367 mounted then you should enable this option. Most people that use 352 the list of currently mounted partitions in "/proc/mounts", rendering
368 BusyBox have a read-only root filesystem, so they will leave this 353 the old mtab file obsolete. (In modern systems, /etc/mtab should be
369 option disabled and BusyBox will use the /proc/mounts file. 354 a symlink to /proc/mounts.)
370 355
371 Note that even non-embedded developers probably want to have /etc/mtab 356 The only reason to have mount maintain an /etc/mtab file itself is if
372 be a symlink to /proc/mounts, since otherwise mtab can get out of sync 357 your stripped-down embedded system does not have a /proc directory.
373 with the real kernel mount state in numerous ways. 358 If you must use this, keep in mind it's inherently brittle (for
359 example a mount under chroot won't update it), can't handle modern
360 features like separate per-process filesystem namespaces, requires
361 that your /etc directory be writeable, tends to get easily confused
362 by --bind or --move mounts, and so on. (In brief: avoid.)
374 363
375config CONFIG_READPROFILE 364config CONFIG_READPROFILE
376 bool "readprofile" 365 bool "readprofile"
diff --git a/util-linux/losetup.c b/util-linux/losetup.c
index c94456522..11bd66ebf 100644
--- a/util-linux/losetup.c
+++ b/util-linux/losetup.c
@@ -27,33 +27,27 @@
27int 27int
28losetup_main (int argc, char **argv) 28losetup_main (int argc, char **argv)
29{ 29{
30 int delete = 0;
31 int offset = 0; 30 int offset = 0;
32 int opt;
33 31
34 while ((opt = getopt (argc, argv, "do:")) != -1) 32 /* This will need a "while(getopt()!=-1)" loop when we can have more than
35 switch (opt) 33 one option, but for now we can't. */
36 { 34 switch(getopt(argc,argv, "do:")) {
37 case 'd': 35 case 'd':
38 delete = 1; 36 /* detach takes exactly one argument */
39 break; 37 if(optind+1==argc)
40 38 return del_loop(argv[optind]) ? EXIT_SUCCESS : EXIT_FAILURE;
41 case 'o': 39 break;
42 offset = bb_xparse_number (optarg, NULL); 40
43 break; 41 case 'o':
44 42 offset = bb_xparse_number (optarg, NULL);
45 default: 43 /* Fall through to do the losetup */
46 bb_show_usage(); 44 case -1:
47 } 45 /* losetup takes two argument:, loop_device and file */
48 46 if(optind+2==argc)
49 if ((delete && (offset || optind + 1 != argc)) 47 return set_loop(&argv[optind], argv[optind + 1], offset)<0
50 || (!delete && optind + 2 != argc)) 48 ? EXIT_FAILURE : EXIT_SUCCESS;
51 bb_show_usage(); 49 break;
52 50 }
53 opt = 0; 51 bb_show_usage();
54 if (delete) 52 return EXIT_FAILURE;
55 return del_loop (argv[optind]) ? EXIT_SUCCESS : EXIT_FAILURE;
56 else
57 return set_loop (argv[optind], argv[optind + 1], offset, &opt)
58 ? EXIT_FAILURE : EXIT_SUCCESS;
59} 53}
diff --git a/util-linux/mount.c b/util-linux/mount.c
index b059d7094..924d79d69 100644
--- a/util-linux/mount.c
+++ b/util-linux/mount.c
@@ -4,6 +4,7 @@
4 * 4 *
5 * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>. 5 * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
6 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> 6 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
7 * Copyright (C) 2005 by Rob Landley <rob@landley.net>
7 * 8 *
8 * This program is free software; you can redistribute it and/or modify 9 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by 10 * it under the terms of the GNU General Public License as published by
@@ -19,29 +20,6 @@
19 * along with this program; if not, write to the Free Software 20 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * 22 *
22 * 3/21/1999 Charles P. Wright <cpwright@cpwright.com>
23 * searches through fstab when -a is passed
24 * will try mounting stuff with all fses when passed -t auto
25 *
26 * 1999-04-17 Dave Cinege...Rewrote -t auto. Fixed ro mtab.
27 *
28 * 1999-10-07 Erik Andersen <andersen@codepoet.org>.
29 * Rewrite of a lot of code. Removed mtab usage (I plan on
30 * putting it back as a compile-time option some time),
31 * major adjustments to option parsing, and some serious
32 * dieting all around.
33 *
34 * 1999-11-06 mtab support is back - andersee
35 *
36 * 2000-01-12 Ben Collins <bcollins@debian.org>, Borrowed utils-linux's
37 * mount to add loop support.
38 *
39 * 2000-04-30 Dave Cinege <dcinege@psychosis.com>
40 * Rewrote fstab while loop and lower mount section. Can now do
41 * single mounts from fstab. Can override fstab options for single
42 * mount. Common mount_one call for single mounts and 'all'. Fixed
43 * mtab updating and stale entries. Removed 'remount' default.
44 *
45 */ 23 */
46 24
47#include <limits.h> 25#include <limits.h>
@@ -52,351 +30,131 @@
52#include <stdio.h> 30#include <stdio.h>
53#include <mntent.h> 31#include <mntent.h>
54#include <ctype.h> 32#include <ctype.h>
33#include <sys/mount.h>
34#include <fcntl.h> // for CONFIG_FEATURE_MOUNT_LOOP
35#include <sys/ioctl.h> // for CONFIG_FEATURE_MOUNT_LOOP
55#include "busybox.h" 36#include "busybox.h"
56 37
57#ifdef CONFIG_NFSMOUNT 38/* This is just a warning of a common mistake. Possibly this should be a
58#if defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__) 39 * uclibc faq entry rather than in busybox... */
40#if ENABLE_NFSMOUNT && defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__)
59#error "You need to build uClibc with UCLIBC_HAS_RPC for busybox mount with NFS support to compile." 41#error "You need to build uClibc with UCLIBC_HAS_RPC for busybox mount with NFS support to compile."
60#endif 42#endif
61#endif
62
63enum {
64 MS_MGC_VAL = 0xc0ed0000, /* Magic number indicatng "new" flags */
65 MS_RDONLY = 1, /* Mount read-only */
66 MS_NOSUID = 2, /* Ignore suid and sgid bits */
67 MS_NODEV = 4, /* Disallow access to device special files */
68 MS_NOEXEC = 8, /* Disallow program execution */
69 MS_SYNCHRONOUS = 16, /* Writes are synced at once */
70 MS_REMOUNT = 32, /* Alter flags of a mounted FS */
71 MS_MANDLOCK = 64, /* Allow mandatory locks on an FS */
72 S_QUOTA = 128, /* Quota initialized for file/directory/symlink */
73 S_APPEND = 256, /* Append-only file */
74 S_IMMUTABLE = 512, /* Immutable file */
75 MS_NOATIME = 1024, /* Do not update access times. */
76 MS_NODIRATIME = 2048, /* Do not update directory access times */
77 MS_BIND = 4096, /* Use the new linux 2.4.x "mount --bind" feature */
78 MS_MOVE = 8192, /* Use the new linux 2.4.x "mount --move" feature */
79};
80
81 43
82#if defined CONFIG_FEATURE_MOUNT_LOOP 44// These two aren't always defined in old headers
83#include <fcntl.h> 45#ifndef MS_BIND
84#include <sys/ioctl.h> 46#define MS_BIND 4096
85static int use_loop = FALSE; 47#endif
48#ifndef MS_MOVE
49#define MS_MOVE 8192
86#endif 50#endif
87 51
88extern int mount(__const char *__special_file, __const char *__dir, 52/* Consume standard mount options (from -o options or --options).
89 __const char *__fstype, unsigned long int __rwflag, 53 * Set appropriate flags and collect unrecognized ones as a comma separated
90 __const void *__data); 54 * string to pass to kernel */
91extern int umount(__const char *__special_file);
92extern int umount2(__const char *__special_file, int __flags);
93
94extern int sysfs(int option, unsigned int fs_index, char *buf);
95 55
96struct mount_options { 56struct {
97 const char *name; 57 const char *name;
98 unsigned long and; 58 long flags;
99 unsigned long or; 59} static const mount_options[] = {
60 {"loop", 0},
61 {"defaults", 0},
62 {"noauto", 0},
63 {"ro", MS_RDONLY},
64 {"rw", ~MS_RDONLY},
65 {"nosuid", MS_NOSUID},
66 {"suid", ~MS_NOSUID},
67 {"dev", ~MS_NODEV},
68 {"nodev", MS_NODEV},
69 {"exec", ~MS_NOEXEC},
70 {"noexec", MS_NOEXEC},
71 {"sync", MS_SYNCHRONOUS},
72 {"async", ~MS_SYNCHRONOUS},
73 {"remount", MS_REMOUNT},
74 {"atime", MS_NOATIME},
75 {"noatime", MS_NOATIME},
76 {"diratime", MS_NODIRATIME},
77 {"nodiratime", MS_NODIRATIME},
78 {"bind", MS_BIND},
79 {"move", MS_MOVE}
100}; 80};
101 81
102static const struct mount_options mount_options[] = { 82/* Uses the mount_options list above */
103 {"async", ~MS_SYNCHRONOUS, 0},
104 {"atime", ~0, ~MS_NOATIME},
105 {"defaults", ~0, 0},
106 {"noauto", ~0, 0},
107 {"dev", ~MS_NODEV, 0},
108 {"diratime", ~0, ~MS_NODIRATIME},
109 {"exec", ~MS_NOEXEC, 0},
110 {"noatime", ~0, MS_NOATIME},
111 {"nodev", ~0, MS_NODEV},
112 {"nodiratime", ~0, MS_NODIRATIME},
113 {"noexec", ~0, MS_NOEXEC},
114 {"nosuid", ~0, MS_NOSUID},
115 {"remount", ~0, MS_REMOUNT},
116 {"ro", ~0, MS_RDONLY},
117 {"rw", ~MS_RDONLY, 0},
118 {"suid", ~MS_NOSUID, 0},
119 {"sync", ~0, MS_SYNCHRONOUS},
120 {"bind", ~0, MS_BIND},
121 {"move", ~0, MS_MOVE},
122 {0, 0, 0}
123};
124
125static int
126do_mount(char *specialfile, char *dir, char *filesystemtype, long flags,
127 void *string_flags, int useMtab, int fakeIt, char *mtab_opts,
128 int mount_all)
129{
130 int status = 0;
131
132#if defined CONFIG_FEATURE_MOUNT_LOOP
133 char *lofile = NULL;
134#endif
135
136 if (!fakeIt) {
137#if defined CONFIG_FEATURE_MOUNT_LOOP
138 if (use_loop == TRUE) {
139 int loro = flags & MS_RDONLY;
140
141 lofile = specialfile;
142
143 specialfile = find_unused_loop_device();
144 if (specialfile == NULL) {
145 bb_error_msg_and_die("Could not find a spare loop device");
146 }
147 if (set_loop(specialfile, lofile, 0, &loro)) {
148 bb_error_msg_and_die("Could not setup loop device");
149 }
150 if (!(flags & MS_RDONLY) && loro) { /* loop is ro, but wanted rw */
151 bb_error_msg("WARNING: loop device is read-only");
152 flags |= MS_RDONLY;
153 }
154 }
155#endif
156 status = mount(specialfile, dir, filesystemtype, flags, string_flags);
157 if (status < 0 && errno == EROFS) {
158 bb_error_msg("%s is write-protected, mounting read-only",
159 specialfile);
160 status = mount(specialfile, dir, filesystemtype, flags |=
161 MS_RDONLY, string_flags);
162 }
163 /* Don't whine about already mounted filesystems when mounting all. */
164 if (status < 0 && errno == EBUSY && mount_all) {
165 return TRUE;
166 }
167 }
168
169
170 /* If the mount was sucessful, do anything needed, then return TRUE */
171 if (status == 0 || fakeIt == TRUE) {
172
173#if defined CONFIG_FEATURE_MTAB_SUPPORT
174 if (useMtab) {
175 erase_mtab(specialfile); /* Clean any stale entries */
176 write_mtab(specialfile, dir, filesystemtype, flags, mtab_opts);
177 }
178#endif
179 return (TRUE);
180 }
181
182 /* Bummer. mount failed. Clean up */
183#if defined CONFIG_FEATURE_MOUNT_LOOP
184 if (lofile != NULL) {
185 del_loop(specialfile);
186 }
187#endif
188
189 if (errno == EPERM) {
190 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
191 }
192
193 return (FALSE);
194}
195
196
197static void paste_str(char **s1, const char *s2)
198{
199 *s1 = xrealloc(*s1, strlen(*s1) + strlen(s2) + 1);
200 strcat(*s1, s2);
201}
202
203/* Seperate standard mount options from the nonstandard string options */
204static void parse_mount_options(char *options, int *flags, char **strflags) 83static void parse_mount_options(char *options, int *flags, char **strflags)
205{ 84{
206 while (options) { 85 // Loop through options
207 int gotone = FALSE; 86 for(;;) {
87 int i;
208 char *comma = strchr(options, ','); 88 char *comma = strchr(options, ',');
209 const struct mount_options *f = mount_options;
210 89
211 if (comma) { 90 if(comma) *comma = 0;
212 *comma = '\0';
213 }
214
215 while (f->name != 0) {
216 if (strcasecmp(f->name, options) == 0) {
217 91
218 *flags &= f->and; 92 // Find this option in mount_options
219 *flags |= f->or; 93 for(i = 0; i < (sizeof(mount_options) / sizeof(*mount_options)); i++) {
220 gotone = TRUE; 94 if(!strcasecmp(mount_options[i].name, options)) {
95 long fl = mount_options[i].flags;
96 if(fl < 0) *flags &= fl;
97 else *flags |= fl;
221 break; 98 break;
222 } 99 }
223 f++;
224 }
225#if defined CONFIG_FEATURE_MOUNT_LOOP
226 if (!strcasecmp("loop", options)) { /* loop device support */
227 use_loop = TRUE;
228 gotone = TRUE;
229 } 100 }
230#endif 101 // Unrecognized mount option?
231 if (!gotone) { 102 if(i == sizeof(mount_options)) {
232 if (**strflags) { 103 // Add it to strflags, to pass on to kernel
233 /* have previous parsed options */ 104 i = *strflags ? strlen(*strflags) : 0;
234 paste_str(strflags, ","); 105 *strflags = xrealloc(*strflags, i+strlen(options)+2);
235 } 106 // Comma separated if it's not the first one
236 paste_str(strflags, options); 107 if(i) (*strflags)[i] = ',';
108 strcpy((*strflags)+i, options);
237 } 109 }
238 if (comma) { 110 // Advance to next option, or finish
111 if(comma) {
239 *comma = ','; 112 *comma = ',';
240 options = ++comma; 113 options = ++comma;
241 } else { 114 } else break;
242 break;
243 }
244 } 115 }
245} 116}
246 117
247static int mount_one(char *blockDevice, char *directory, char *filesystemType, 118/* This does the work */
248 unsigned long flags, char *string_flags, int useMtab,
249 int fakeIt, char *mtab_opts, int whineOnErrors,
250 int mount_all)
251{
252 int status = 0;
253 if (strcmp(filesystemType, "auto") == 0) {
254 char buf[255];
255 FILE *f;
256 int read_proc = 0;
257
258 f = fopen("/etc/filesystems", "r");
259
260 if (f) {
261 while (fgets(buf, sizeof(buf), f)) {
262 if (*buf == '*') {
263 read_proc = 1;
264 } else if (*buf == '#') {
265 continue;
266 } else {
267 filesystemType = buf;
268
269 /* Add NULL termination to each line */
270 while (*filesystemType && !isspace(*filesystemType)) {
271 filesystemType++;
272 }
273 *filesystemType = '\0';
274
275 filesystemType = buf;
276
277 if (bb_strlen(filesystemType)) {
278 status = do_mount(blockDevice, directory, filesystemType,
279 flags | MS_MGC_VAL, string_flags,
280 useMtab, fakeIt, mtab_opts, mount_all);
281 if (status) {
282 break;
283 }
284 }
285
286 }
287 }
288 fclose(f);
289 } else {
290 read_proc = 1;
291 }
292
293 if (read_proc && !status) {
294
295 f = bb_xfopen("/proc/filesystems", "r");
296 119
297 while (fgets(buf, sizeof(buf), f) != NULL) { 120extern int mount_main(int argc, char **argv)
298 filesystemType = buf;
299 if (*filesystemType == '\t') { /* Not a nodev filesystem */
300
301 /* Add NULL termination to each line */
302 while (*filesystemType && *filesystemType != '\n') {
303 filesystemType++;
304 }
305 *filesystemType = '\0';
306
307 filesystemType = buf;
308 filesystemType++; /* hop past tab */
309
310 status = do_mount(blockDevice, directory, filesystemType,
311 flags | MS_MGC_VAL, string_flags, useMtab,
312 fakeIt, mtab_opts, mount_all);
313 if (status) {
314 break;
315 }
316 }
317 }
318 fclose(f);
319 }
320 } else {
321 status = do_mount(blockDevice, directory, filesystemType,
322 flags | MS_MGC_VAL, string_flags, useMtab, fakeIt,
323 mtab_opts, mount_all);
324 }
325
326 if (!status) {
327 if (whineOnErrors) {
328 bb_perror_msg("Mounting %s on %s failed", blockDevice, directory);
329 }
330 return (FALSE);
331 }
332 return (TRUE);
333}
334
335static void show_mounts(char *onlytype)
336{ 121{
337 FILE *mountTable = setmntent(bb_path_mtab_file, "r"); 122 char *string_flags = 0, *fsType = 0, *blockDevice = 0, *directory = 0,
338 123 *loopFile = 0, *buf = 0,
339 if (mountTable) { 124 *files[] = {"/etc/filesystems", "/proc/filesystems", 0};
340 struct mntent *m; 125 int i, opt, all = FALSE, fakeIt = FALSE, allowWrite = FALSE,
126 rc = EXIT_FAILURE, useMtab = ENABLE_FEATURE_MTAB_SUPPORT;
127 int flags=0xc0ed0000; // Needed for linux 2.2, ignored by 2.4 and 2.6.
128 FILE *file = 0,*f = 0;
129 char path[PATH_MAX*2];
130 struct mntent m;
131 struct stat statbuf;
341 132
342 while ((m = getmntent(mountTable)) != 0) { 133 /* parse long options, like --bind and --move. Note that -o option
343 char *blockDevice = m->mnt_fsname; 134 * and --option are synonymous. Yes, this means --remount,rw works. */
344 135
345 if (strcmp(blockDevice, "rootfs") == 0) { 136 for(i = opt = 0; i < argc; i++) {
346 continue; 137 if(argv[i][0] == '-' && argv[i][1] == '-')
347 } else if (strcmp(blockDevice, "/dev/root") == 0) { 138 parse_mount_options(argv[i]+2, &flags, &string_flags);
348 blockDevice = find_real_root_device_name(); 139 else argv[opt++] = argv[i];
349 }
350 if (!onlytype || (strcmp(m->mnt_type, onlytype) == 0)) {
351 printf("%s on %s type %s (%s)\n", blockDevice, m->mnt_dir,
352 m->mnt_type, m->mnt_opts);
353 }
354#ifdef CONFIG_FEATURE_CLEAN_UP
355 if (blockDevice != m->mnt_fsname) {
356 free(blockDevice);
357 }
358#endif
359 }
360 endmntent(mountTable);
361 } else {
362 bb_perror_msg_and_die(bb_path_mtab_file);
363 } 140 }
364 exit(EXIT_SUCCESS); 141 argc = opt;
365}
366 142
367extern int mount_main(int argc, char **argv) 143 // Parse remaining options
368{ 144
369 struct stat statbuf; 145 while((opt = getopt(argc, argv, "o:t:rwafnv")) > 0) {
370 char *string_flags = bb_xstrdup("");
371 char *extra_opts;
372 int flags = 0;
373 char *filesystemType = "auto";
374 int got_filesystemType = 0;
375 char *device = xmalloc(PATH_MAX);
376 char *directory = xmalloc(PATH_MAX);
377 struct mntent *m = NULL;
378 int all = FALSE;
379 int fakeIt = FALSE;
380 int useMtab = TRUE;
381 int rc = EXIT_FAILURE;
382 FILE *f = 0;
383 int opt;
384
385 /* Parse options */
386 while ((opt = getopt(argc, argv, "o:rt:wafnv")) > 0) {
387 switch (opt) { 146 switch (opt) {
388 case 'o': 147 case 'o':
389 parse_mount_options(optarg, &flags, &string_flags); 148 parse_mount_options(optarg, &flags, &string_flags);
390 break; 149 break;
150 case 't':
151 fsType = optarg;
152 break;
391 case 'r': 153 case 'r':
392 flags |= MS_RDONLY; 154 flags |= MS_RDONLY;
393 break; 155 break;
394 case 't':
395 filesystemType = optarg;
396 got_filesystemType = 1;
397 break;
398 case 'w': 156 case 'w':
399 flags &= ~MS_RDONLY; 157 allowWrite=TRUE;
400 break; 158 break;
401 case 'a': 159 case 'a':
402 all = TRUE; 160 all = TRUE;
@@ -405,93 +163,238 @@ extern int mount_main(int argc, char **argv)
405 fakeIt = TRUE; 163 fakeIt = TRUE;
406 break; 164 break;
407 case 'n': 165 case 'n':
408#ifdef CONFIG_FEATURE_MTAB_SUPPORT
409 useMtab = FALSE; 166 useMtab = FALSE;
410#endif
411 break; 167 break;
412 case 'v': 168 case 'v':
413 break; /* ignore -v */ 169 break; // ignore -v
170 default:
171 bb_show_usage();
414 } 172 }
415 } 173 }
416 174
417 if (!all && (optind == argc)) { 175 // If we have no arguments, show currently mounted filesystems
418 show_mounts(got_filesystemType ? filesystemType : NULL);
419 }
420 176
421 if (optind < argc) { 177 if(!all && (optind == argc)) {
422 /* if device is a filename get its real path */ 178 FILE *mountTable = setmntent(bb_path_mtab_file, "r");
423 if (stat(argv[optind], &statbuf) == 0) {
424 char *tmp = bb_simplify_path(argv[optind]);
425 179
426 safe_strncpy(device, tmp, PATH_MAX); 180 if(!mountTable) bb_perror_msg_and_die(bb_path_mtab_file);
427 } else { 181
428 safe_strncpy(device, argv[optind], PATH_MAX); 182 while (getmntent_r(mountTable,&m,path,sizeof(path))) {
183 blockDevice = m.mnt_fsname;
184
185 // Clean up display a little bit regarding root devie
186 if(!strcmp(blockDevice, "rootfs")) continue;
187 if(!strcmp(blockDevice, "/dev/root"))
188 blockDevice = find_block_device("/");
189
190 if(!fsType || !strcmp(m.mnt_type, fsType))
191 printf("%s on %s type %s (%s)\n", blockDevice, m.mnt_dir,
192 m.mnt_type, m.mnt_opts);
193 if(ENABLE_FEATURE_CLEAN_UP && blockDevice != m.mnt_fsname)
194 free(blockDevice);
429 } 195 }
196 endmntent(mountTable);
197 return EXIT_SUCCESS;
430 } 198 }
431 199
432 if (optind + 1 < argc) 200 /* The next argument is what to mount. if there's an argument after that
433 directory = bb_simplify_path(argv[optind + 1]); 201 * it's where to mount it. If we're not mounting all, and we have both
202 * of these arguments, jump straight to the actual mount. */
203
204 statbuf.st_mode=0;
205 if(optind < argc)
206 blockDevice = !stat(argv[optind], &statbuf) ?
207 bb_simplify_path(argv[optind]) :
208 (ENABLE_FEATURE_CLEAN_UP ? strdup(argv[optind]) : argv[optind]);
209 if(optind+1 < argc) directory = bb_simplify_path(argv[optind+1]);
210
211 // If we don't have to loop through fstab, skip ahead a bit.
212
213 if(!all && optind+1!=argc) goto singlemount;
214
215 // Loop through /etc/fstab entries to look up this entry.
434 216
435 if (all || optind + 1 == argc) { 217 if(!(file=setmntent("/etc/fstab","r")))
436 f = setmntent("/etc/fstab", "r"); 218 bb_perror_msg_and_die("\nCannot read /etc/fstab");
219 for(;;) {
437 220
438 if (f == NULL) 221 // Get next fstab entry
439 bb_perror_msg_and_die("\nCannot read /etc/fstab");
440 222
441 while ((m = getmntent(f)) != NULL) { 223 if(!getmntent_r(file,&m,path,sizeof(path))) {
442 if (!all && (optind + 1 == argc) 224 if(!all)
443 && ((strcmp(device, m->mnt_fsname) != 0) 225 bb_perror_msg("Can't find %s in /etc/fstab\n", blockDevice);
444 && (strcmp(device, m->mnt_dir) != 0))) { 226 break;
227 }
228
229 // If we're mounting all and all doesn't mount this one, skip it.
230
231 if(all) {
232 if(strstr(m.mnt_opts,"noauto") || strstr(m.mnt_type,"swap"))
445 continue; 233 continue;
234 flags=0;
235
236 /* If we're mounting something specific and this isn't it, skip it.
237 * Note we must match both the exact text in fstab (ala "proc") or
238 * a full path from root */
239
240 } else if(strcmp(blockDevice,m.mnt_fsname) &&
241 strcmp(argv[optind],m.mnt_fsname) &&
242 strcmp(blockDevice,m.mnt_dir) &&
243 strcmp(argv[optind],m.mnt_dir)) continue;
244
245 /* Parse flags from /etc/fstab (unless this is a single mount
246 * overriding fstab -- note the "all" test above zeroed the flags,
247 * to prevent flags from previous entries affecting this one, so
248 * the only way we could get here with nonzero flags is a single
249 * mount). */
250
251 if(!flags) {
252 if(ENABLE_FEATURE_CLEAN_UP) free(string_flags);
253 string_flags=NULL;
254 parse_mount_options(m.mnt_opts, &flags, &string_flags);
255 }
256
257 /* Fill out remaining fields with info from mtab */
258
259 if(ENABLE_FEATURE_CLEAN_UP) {
260 free(blockDevice);
261 blockDevice=strdup(m.mnt_fsname);
262 free(directory);
263 directory=strdup(m.mnt_type);
264 } else {
265 blockDevice=m.mnt_fsname;
266 directory=m.mnt_dir;
267 }
268 fsType=m.mnt_type;
269
270 /* Ok, we're ready to actually mount a specific source on a specific
271 * directory now. */
272
273singlemount:
274
275 // If they said -w, override fstab
276
277 if(allowWrite) flags&=~MS_RDONLY;
278
279 // Might this be an NFS filesystem?
280
281 if(ENABLE_NFSMOUNT && (!fsType || !strcmp(fsType,"nfs")) &&
282 strchr(blockDevice, ':') != NULL)
283 {
284 if(nfsmount(blockDevice, directory, &flags, &string_flags, 1))
285 bb_perror_msg("nfsmount failed");
286 else {
287 rc=EXIT_SUCCESS;
288 fsType="nfs";
446 } 289 }
290 } else {
291
292 // Do we need to allocate a loopback device?
447 293
448 if (all && ( /* If we're mounting 'all' */ 294 if(ENABLE_FEATURE_MOUNT_LOOP && !fakeIt && S_ISREG(statbuf.st_mode))
449 (strstr(m->mnt_opts, "noauto")) || /* and the file system isn't noauto, */
450 (strstr(m->mnt_type, "swap")))) /* and isn't swap, then mount it */
451 { 295 {
452 continue; 296 loopFile = blockDevice;
297 blockDevice = 0;
298 switch(set_loop(&blockDevice, loopFile, 0)) {
299 case 0:
300 case 1:
301 break;
302 default:
303 bb_error_msg_and_die(
304 errno == EPERM || errno == EACCES ?
305 bb_msg_perm_denied_are_you_root :
306 "Couldn't setup loop device");
307 break;
308 }
453 } 309 }
454 310
455 if (all || flags == 0) { /* Allow single mount to override fstab flags */ 311 /* If we know the fstype (or don't need to), jump straight
456 flags = 0; 312 * to the actual mount. */
457 string_flags[0] = 0;
458 parse_mount_options(m->mnt_opts, &flags, &string_flags);
459 }
460 313
461 strcpy(device, m->mnt_fsname); 314 if(fsType || (flags & (MS_REMOUNT | MS_BIND | MS_MOVE)))
462 strcpy(directory, m->mnt_dir); 315 goto mount_it_now;
463 filesystemType = bb_xstrdup(m->mnt_type); 316 }
464 singlemount: 317
465 extra_opts = string_flags; 318 // Loop through filesystem types until mount succeeds or we run out
466 rc = EXIT_SUCCESS; 319
467#ifdef CONFIG_NFSMOUNT 320 for(i = 0; files[i] && rc; i++) {
468 if (strchr(device, ':') != NULL) { 321 f = fopen(files[i], "r");
469 filesystemType = "nfs"; 322 if(!f) continue;
470 if (nfsmount 323 // Get next block device backed filesystem
471 (device, directory, &flags, &extra_opts, &string_flags, 324 for(buf = 0; (buf = fsType = bb_get_chomped_line_from_file(f));
472 1)) { 325 free(buf))
473 bb_perror_msg("nfsmount failed"); 326 {
474 rc = EXIT_FAILURE; 327 // Skip funky entries in /proc
328 if(!strncmp(buf,"nodev",5) && isspace(buf[5])) continue;
329
330 while(isspace(*fsType)) fsType++;
331 if(*buf=='#' || *buf=='*') continue;
332 if(!*fsType) continue;
333mount_it_now:
334 // Okay, try to mount
335
336 if (!fakeIt) {
337 for(;;) {
338 rc = mount(blockDevice, directory, fsType, flags, string_flags);
339 if(!rc || (flags&MS_RDONLY) || (errno!=EACCES && errno!=EROFS))
340 break;
341 bb_error_msg("%s is write-protected, mounting read-only", blockDevice);
342 flags|=MS_RDONLY;
343 }
475 } 344 }
345 if(!rc) break;
476 } 346 }
477#endif 347 if(f) fclose(f);
478 if (!mount_one 348 if(!f || !rc) break;
479 (device, directory, filesystemType, flags, string_flags, 349 }
480 useMtab, fakeIt, extra_opts, TRUE, all)) { 350
481 rc = EXIT_FAILURE; 351 /* If the mount was sucessful, and we're maintaining an old-style
352 * mtab file by hand, add new entry to it now. */
353 if((!rc || fakeIt) && useMtab) {
354 FILE *mountTable = setmntent(bb_path_mtab_file, "a+");
355
356 if(!mountTable) bb_perror_msg(bb_path_mtab_file);
357 else {
358 // Remove trailing / (if any) from directory we mounted on
359 int length=strlen(directory);
360 if(length>1 && directory[length-1] == '/')
361 directory[length-1]=0;
362
363 // Fill out structure (should be ok to re-use existing one).
364 m.mnt_fsname=blockDevice;
365 m.mnt_dir=directory;
366 m.mnt_type=fsType ? : "--bind";
367 m.mnt_opts=string_flags ? :
368 ((flags & MS_RDONLY) ? "ro" : "rw");
369 m.mnt_freq = 0;
370 m.mnt_passno = 0;
371
372 // Write and close
373 addmntent(mountTable, &m);
374 endmntent(mountTable);
482 } 375 }
483 if (!all) { 376 } else {
484 break; 377 // Mount failed. Clean up
378 if(loopFile) {
379 del_loop(blockDevice);
380 if(ENABLE_FEATURE_CLEAN_UP) free(loopFile);
485 } 381 }
382 // Don't whine about already mounted fs when mounting all.
383 if(rc<0 && errno == EBUSY && all) rc=0;
384 else if (errno == EPERM)
385 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
486 } 386 }
487 if (f) { 387 // We couldn't free this earlier becase fsType could be in buf.
488 endmntent(f); 388 if(ENABLE_FEATURE_CLEAN_UP) {
389 free(buf);
390 free(blockDevice);
391 free(directory);
489 } 392 }
490 if (!all && f && m == NULL) { 393 if(!all) break;
491 fprintf(stderr, "Can't find %s in /etc/fstab\n", device);
492 }
493 return rc;
494 } 394 }
495 395
496 goto singlemount; 396 if(file) endmntent(file);
397 if(rc) bb_perror_msg("Mounting %s on %s failed", blockDevice, directory);
398
399 return rc ? : EXIT_FAILURE;
497} 400}
diff --git a/util-linux/nfsmount.c b/util-linux/nfsmount.c
index 0ebab80f6..11ca3268e 100644
--- a/util-linux/nfsmount.c
+++ b/util-linux/nfsmount.c
@@ -303,7 +303,7 @@ return &p;
303} 303}
304 304
305int nfsmount(const char *spec, const char *node, int *flags, 305int nfsmount(const char *spec, const char *node, int *flags,
306 char **extra_opts, char **mount_opts, int running_bg) 306 char **mount_opts, int running_bg)
307{ 307{
308 static char *prev_bg_host; 308 static char *prev_bg_host;
309 char hostdir[1024]; 309 char hostdir[1024];
@@ -399,7 +399,7 @@ int nfsmount(const char *spec, const char *node, int *flags,
399 /* add IP address to mtab options for use when unmounting */ 399 /* add IP address to mtab options for use when unmounting */
400 400
401 s = inet_ntoa(server_addr.sin_addr); 401 s = inet_ntoa(server_addr.sin_addr);
402 old_opts = *extra_opts; 402 old_opts = *mount_opts;
403 if (!old_opts) 403 if (!old_opts)
404 old_opts = ""; 404 old_opts = "";
405 if (strlen(old_opts) + strlen(s) + 10 >= sizeof(new_opts)) { 405 if (strlen(old_opts) + strlen(s) + 10 >= sizeof(new_opts)) {
@@ -408,7 +408,7 @@ int nfsmount(const char *spec, const char *node, int *flags,
408 } 408 }
409 sprintf(new_opts, "%s%saddr=%s", 409 sprintf(new_opts, "%s%saddr=%s",
410 old_opts, *old_opts ? "," : "", s); 410 old_opts, *old_opts ? "," : "", s);
411 *extra_opts = bb_xstrdup(new_opts); 411 *mount_opts = bb_xstrdup(new_opts);
412 412
413 /* Set default options. 413 /* Set default options.
414 * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to 414 * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to
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}