aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Landley <rob@landley.net>2005-08-10 20:35:54 +0000
committerRob Landley <rob@landley.net>2005-08-10 20:35:54 +0000
commit6a6798b8e47c71888945ec5cb55c703db19b956c (patch)
tree9179ec8c6dc4e402cdc4a86cf6af119745de2f40
parent0b62158475ecbfce16fb857042ec7f402d7594ec (diff)
downloadbusybox-w32-6a6798b8e47c71888945ec5cb55c703db19b956c.tar.gz
busybox-w32-6a6798b8e47c71888945ec5cb55c703db19b956c.tar.bz2
busybox-w32-6a6798b8e47c71888945ec5cb55c703db19b956c.zip
Major rewrite of mount, umount, losetup. Untangled lots of code, shrunk
things down a bit, fixed a number of funky corner cases, added support for several new features (things like mount --move, mount --bind, lazy unounts, automatic detection of loop mounts, and so on). Probably broke several other things, but it's fixable. (Bang on it, tell me what doesn't work for you...) Note: you no longer need to say "-o loop". It does that for you when necessary. Still need to add "user mount" support, which involves making mount suid. Not too hard to do under the new infrastructure, just haven't done it yet... The previous code had the following notes, that belong in the version control comments: - * 3/21/1999 Charles P. Wright <cpwright@cpwright.com> - * searches through fstab when -a is passed - * will try mounting stuff with all fses when passed -t auto - * - * 1999-04-17 Dave Cinege...Rewrote -t auto. Fixed ro mtab. - * - * 1999-10-07 Erik Andersen <andersen@codepoet.org>. - * Rewrite of a lot of code. Removed mtab usage (I plan on - * putting it back as a compile-time option some time), - * major adjustments to option parsing, and some serious - * dieting all around. - * - * 1999-11-06 mtab support is back - andersee - * - * 2000-01-12 Ben Collins <bcollins@debian.org>, Borrowed utils-linux's - * mount to add loop support. - * - * 2000-04-30 Dave Cinege <dcinege@psychosis.com> - * Rewrote fstab while loop and lower mount section. Can now do - * single mounts from fstab. Can override fstab options for single - * mount. Common mount_one call for single mounts and 'all'. Fixed - * mtab updating and stale entries. Removed 'remount' default. - *
-rw-r--r--coreutils/df.c2
-rw-r--r--include/libbb.h11
-rw-r--r--libbb/find_mount_point.c2
-rw-r--r--libbb/find_root_device.c70
-rw-r--r--libbb/loop.c163
-rw-r--r--libbb/mtab.c45
-rw-r--r--miscutils/eject.c8
-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
12 files changed, 543 insertions, 922 deletions
diff --git a/coreutils/df.c b/coreutils/df.c
index ba2e7ccc9..9233fbbf1 100644
--- a/coreutils/df.c
+++ b/coreutils/df.c
@@ -130,7 +130,7 @@ extern int df_main(int argc, char **argv)
130 } else if (strcmp(device, "/dev/root") == 0) { 130 } else if (strcmp(device, "/dev/root") == 0) {
131 /* Adjusts device to be the real root device, 131 /* Adjusts device to be the real root device,
132 * or leaves device alone if it can't find it */ 132 * or leaves device alone if it can't find it */
133 if ((device = find_real_root_device_name()) == NULL) { 133 if ((device = find_block_device("/")) == NULL) {
134 goto SET_ERROR; 134 goto SET_ERROR;
135 } 135 }
136 } 136 }
diff --git a/include/libbb.h b/include/libbb.h
index d12860ca9..14670f026 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -132,11 +132,9 @@ extern int get_kernel_revision(void);
132 132
133extern int get_console_fd(void); 133extern int get_console_fd(void);
134extern struct mntent *find_mount_point(const char *name, const char *table); 134extern struct mntent *find_mount_point(const char *name, const char *table);
135extern void write_mtab(char* blockDevice, char* directory,
136 char* filesystemType, long flags, char* string_flags);
137extern void erase_mtab(const char * name); 135extern void erase_mtab(const char * name);
138extern long *find_pid_by_name( const char* pidName); 136extern long *find_pid_by_name( const char* pidName);
139extern char *find_real_root_device_name(void); 137extern char *find_block_device(char *path);
140extern char *bb_get_line_from_file(FILE *file); 138extern char *bb_get_line_from_file(FILE *file);
141extern char *bb_get_chomped_line_from_file(FILE *file); 139extern char *bb_get_chomped_line_from_file(FILE *file);
142extern char *bb_get_chunk_from_file(FILE *file); 140extern char *bb_get_chunk_from_file(FILE *file);
@@ -242,16 +240,14 @@ extern char *bb_askpass(int timeout, const char * prompt);
242extern int device_open(const char *device, int mode); 240extern int device_open(const char *device, int mode);
243 241
244extern int del_loop(const char *device); 242extern int del_loop(const char *device);
245extern int set_loop(const char *device, const char *file, int offset, int *loopro); 243extern int set_loop(char **device, const char *file, int offset);
246extern char *find_unused_loop_device (void);
247
248 244
249#if (__GLIBC__ < 2) 245#if (__GLIBC__ < 2)
250extern int vdprintf(int d, const char *format, va_list ap); 246extern int vdprintf(int d, const char *format, va_list ap);
251#endif 247#endif
252 248
253int nfsmount(const char *spec, const char *node, int *flags, 249int nfsmount(const char *spec, const char *node, int *flags,
254 char **extra_opts, char **mount_opts, int running_bg); 250 char **mount_opts, int running_bg);
255 251
256/* Include our own copy of struct sysinfo to avoid binary compatability 252/* Include our own copy of struct sysinfo to avoid binary compatability
257 * problems with Linux 2.4, which changed things. Grumble, grumble. */ 253 * problems with Linux 2.4, which changed things. Grumble, grumble. */
@@ -452,6 +448,7 @@ typedef struct {
452 int ppid; 448 int ppid;
453#ifdef FEATURE_CPU_USAGE_PERCENTAGE 449#ifdef FEATURE_CPU_USAGE_PERCENTAGE
454 unsigned pcpu; 450 unsigned pcpu;
451 unsigned pscpu;
455 unsigned long stime, utime; 452 unsigned long stime, utime;
456#endif 453#endif
457 char *cmd; 454 char *cmd;
diff --git a/libbb/find_mount_point.c b/libbb/find_mount_point.c
index 83824de9e..eec738aea 100644
--- a/libbb/find_mount_point.c
+++ b/libbb/find_mount_point.c
@@ -48,7 +48,7 @@ extern struct mntent *find_mount_point(const char *name, const char *table)
48 mountDevice = s.st_dev; 48 mountDevice = s.st_dev;
49 49
50 50
51 if ((mountTable = setmntent(table, "r")) == 0) 51 if ((mountTable = setmntent(table ? : bb_path_mtab_file, "r")) == 0)
52 return 0; 52 return 0;
53 53
54 while ((mountEntry = getmntent(mountTable)) != 0) { 54 while ((mountEntry = getmntent(mountTable)) != 0) {
diff --git a/libbb/find_root_device.c b/libbb/find_root_device.c
index 2600ce5e0..7ff65bb57 100644
--- a/libbb/find_root_device.c
+++ b/libbb/find_root_device.c
@@ -25,65 +25,25 @@
25#include <stdlib.h> 25#include <stdlib.h>
26#include "libbb.h" 26#include "libbb.h"
27 27
28 28extern char *find_block_device(char *path)
29
30extern char *find_real_root_device_name(void)
31{ 29{
32 DIR *dir; 30 DIR *dir;
33 struct dirent *entry; 31 struct dirent *entry;
34 struct stat statBuf, rootStat; 32 struct stat st;
35 char *fileName = NULL;
36 dev_t dev; 33 dev_t dev;
37 34 char *retpath=NULL;
38 if (stat("/", &rootStat) != 0) 35
39 bb_perror_msg("could not stat '/'"); 36 if(stat(path, &st) || !(dir = opendir("/dev"))) return NULL;
40 else { 37 dev = (st.st_mode & S_IFMT) == S_IFBLK ? st.st_rdev : st.st_dev;
41 /* This check is here in case they pass in /dev name */ 38 while((entry = readdir(dir)) != NULL) {
42 if ((rootStat.st_mode & S_IFMT) == S_IFBLK) 39 char devpath[PATH_MAX];
43 dev = rootStat.st_rdev; 40 sprintf(devpath,"/dev/%s", entry->d_name);
44 else 41 if(!stat(devpath, &st) && S_ISBLK(st.st_mode) && st.st_rdev == dev) {
45 dev = rootStat.st_dev; 42 retpath = bb_xstrdup(devpath);
46 43 break;
47 dir = opendir("/dev");
48 if (!dir)
49 bb_perror_msg("could not open '/dev'");
50 else {
51 while((entry = readdir(dir)) != NULL) {
52 const char *myname = entry->d_name;
53 /* Must skip ".." since that is "/", and so we
54 * would get a false positive on ".." */
55 if (myname[0] == '.' && myname[1] == '.' && !myname[2])
56 continue;
57#ifdef CONFIG_FEATURE_DEVFS
58 /* if there is a link named /dev/root skip that too */
59 if (strcmp(myname, "root")==0)
60 continue;
61#endif
62 fileName = concat_path_file("/dev", myname);
63
64 /* Some char devices have the same dev_t as block
65 * devices, so make sure this is a block device */
66 if (stat(fileName, &statBuf) == 0 &&
67 S_ISBLK(statBuf.st_mode)!=0 &&
68 statBuf.st_rdev == dev)
69 break;
70 free(fileName);
71 fileName=NULL;
72 }
73 closedir(dir);
74 } 44 }
75 } 45 }
76 if(fileName==NULL) 46 closedir(dir);
77 fileName = bb_xstrdup("/dev/root");
78 return fileName;
79}
80
81 47
82/* END CODE */ 48 return retpath;
83/* 49}
84Local Variables:
85c-file-style: "linux"
86c-basic-offset: 4
87tab-width: 4
88End:
89*/
diff --git a/libbb/loop.c b/libbb/loop.c
index c4c3da4b1..25f66fcea 100644
--- a/libbb/loop.c
+++ b/libbb/loop.c
@@ -19,10 +19,8 @@
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */ 20 */
21 21
22
22#include <features.h> 23#include <features.h>
23#if defined (__GLIBC__) && !defined(__UCLIBC__)
24#include <linux/posix_types.h>
25#endif
26#include <stdio.h> 24#include <stdio.h>
27#include <errno.h> 25#include <errno.h>
28#include <fcntl.h> 26#include <fcntl.h>
@@ -30,127 +28,108 @@
30#include <unistd.h> 28#include <unistd.h>
31#include <sys/ioctl.h> 29#include <sys/ioctl.h>
32#include "libbb.h" 30#include "libbb.h"
33#ifdef CONFIG_FEATURE_MOUNT_LOOP
34 31
35/* Grumble... The 2.6.x kernel breaks asm/posix_types.h 32/* For 2.6, use the cleaned up header to get the 64 bit API. */
36 * so we get to try and cope as best we can... */
37#include <linux/version.h> 33#include <linux/version.h>
38
39#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) 34#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
40#define __bb_kernel_dev_t __kernel_old_dev_t 35#include <linux/loop.h>
41#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) 36typedef struct loop_info64 bb_loop_info;
42#define __bb_kernel_dev_t __kernel_dev_t 37#define BB_LOOP_SET_STATUS LOOP_SET_STATUS64
43#else 38#define BB_LOOP_GET_STATUS LOOP_GET_STATUS64
44#define __bb_kernel_dev_t unsigned short
45#endif
46 39
47/* Stuff stolen from linux/loop.h */ 40/* For 2.4 and earlier, use the 32 bit API (and don't trust the headers) */
41#else
42/* Stuff stolen from linux/loop.h for 2.4 and earlier kernels*/
43#include <linux/posix_types.h>
48#define LO_NAME_SIZE 64 44#define LO_NAME_SIZE 64
49#define LO_KEY_SIZE 32 45#define LO_KEY_SIZE 32
50#define LOOP_SET_FD 0x4C00 46#define LOOP_SET_FD 0x4C00
51#define LOOP_CLR_FD 0x4C01 47#define LOOP_CLR_FD 0x4C01
52#define LOOP_SET_STATUS 0x4C02 48#define BB_LOOP_SET_STATUS 0x4C02
53#define LOOP_GET_STATUS 0x4C03 49#define BB_LOOP_GET_STATUS 0x4C03
54struct loop_info { 50typedef struct {
55 int lo_number; 51 int lo_number;
56 __bb_kernel_dev_t lo_device; 52 __kernel_dev_t lo_device;
57 unsigned long lo_inode; 53 unsigned long lo_inode;
58 __bb_kernel_dev_t lo_rdevice; 54 __kernel_dev_t lo_rdevice;
59 int lo_offset; 55 int lo_offset;
60 int lo_encrypt_type; 56 int lo_encrypt_type;
61 int lo_encrypt_key_size; 57 int lo_encrypt_key_size;
62 int lo_flags; 58 int lo_flags;
63 char lo_name[LO_NAME_SIZE]; 59 char lo_file_name[LO_NAME_SIZE];
64 unsigned char lo_encrypt_key[LO_KEY_SIZE]; 60 unsigned char lo_encrypt_key[LO_KEY_SIZE];
65 unsigned long lo_init[2]; 61 unsigned long lo_init[2];
66 char reserved[4]; 62 char reserved[4];
67}; 63} bb_loop_info;
64#endif
68 65
69extern int del_loop(const char *device) 66extern int del_loop(const char *device)
70{ 67{
71 int fd; 68 int fd,rc=0;
72 69
73 if ((fd = open(device, O_RDONLY)) < 0) { 70 if ((fd = open(device, O_RDONLY)) < 0) rc=1;
74 bb_perror_msg("%s", device); 71 else {
75 return (FALSE); 72 if (ioctl(fd, LOOP_CLR_FD, 0) < 0) rc=1;
76 }
77 if (ioctl(fd, LOOP_CLR_FD, 0) < 0) {
78 close(fd); 73 close(fd);
79 bb_perror_msg("ioctl: LOOP_CLR_FD");
80 return (FALSE);
81 } 74 }
82 close(fd); 75 return rc;
83 return (TRUE);
84} 76}
85 77
86extern int set_loop(const char *device, const char *file, int offset, 78// Returns 0 if mounted RW, 1 if mounted read-only, <0 for error.
87 int *loopro) 79// *device is loop device to use, or if *device==NULL finds a loop device to
88{ 80// mount it on and sets *device to a strdup of that loop device name. This
89 struct loop_info loopinfo; 81// search will re-use an existing loop device already bound to that
90 int fd, ffd, mode; 82// file/offset if it finds one.
91 83extern int set_loop(char **device, const char *file, int offset)
92 mode = *loopro ? O_RDONLY : O_RDWR;
93 if ((ffd = open(file, mode)) < 0 && !*loopro
94 && (errno != EROFS || (ffd = open(file, mode = O_RDONLY)) < 0)) {
95 bb_perror_msg("%s", file);
96 return 1;
97 }
98 if ((fd = open(device, mode)) < 0) {
99 close(ffd);
100 bb_perror_msg("%s", device);
101 return 1;
102 }
103 *loopro = (mode == O_RDONLY);
104
105 memset(&loopinfo, 0, sizeof(loopinfo));
106 safe_strncpy(loopinfo.lo_name, file, LO_NAME_SIZE);
107
108 loopinfo.lo_offset = offset;
109
110 loopinfo.lo_encrypt_key_size = 0;
111 if (ioctl(fd, LOOP_SET_FD, ffd) < 0) {
112 bb_perror_msg("ioctl: LOOP_SET_FD");
113 close(fd);
114 close(ffd);
115 return 1;
116 }
117 if (ioctl(fd, LOOP_SET_STATUS, &loopinfo) < 0) {
118 (void) ioctl(fd, LOOP_CLR_FD, 0);
119 bb_perror_msg("ioctl: LOOP_SET_STATUS");
120 close(fd);
121 close(ffd);
122 return 1;
123 }
124 close(fd);
125 close(ffd);
126 return 0;
127}
128
129extern char *find_unused_loop_device(void)
130{ 84{
131 char dev[20]; 85 char dev[20];
132 int i, fd; 86 bb_loop_info loopinfo;
133 struct stat statbuf; 87 struct stat statbuf;
134 struct loop_info loopinfo; 88 int i, dfd, ffd, mode, rc=1;
135 89
136 for (i = 0; i <= CONFIG_FEATURE_MOUNT_LOOP_MAX; i++) { 90 // Open the file. Barf if this doesn't work.
137 sprintf(dev, LOOP_FORMAT, i); 91 if((ffd = open(file, mode=O_RDWR))<0)
138 if (stat(dev, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)) { 92 if(errno!=EROFS || (ffd=open(file,mode=O_RDONLY))<0)
139 if ((fd = open(dev, O_RDONLY)) >= 0) { 93 return errno;
140 if (ioctl(fd, LOOP_GET_STATUS, &loopinfo) != 0) { 94
141 if (errno == ENXIO) { /* probably free */ 95 // Find a loop device
142 close(fd); 96 for(i=0;rc;i++) {
143 return strdup(dev); 97 sprintf(dev, LOOP_FORMAT, i++);
144 } 98 // Ran out of block devices, return failure.
145 } 99 if(stat(*device ? : dev, &statbuf) || !S_ISBLK(statbuf.st_mode)) {
146 close(fd); 100 rc=ENOENT;
147 } 101 break;
148 } 102 }
103 // Open the sucker and check its loopiness.
104 if((dfd=open(dev, mode))<0 && errno==EROFS)
105 dfd=open(dev,mode=O_RDONLY);
106 if(dfd<0) continue;
107
108 rc=ioctl(dfd, BB_LOOP_GET_STATUS, &loopinfo);
109 // If device free, claim it.
110 if(rc && errno==ENXIO) {
111 memset(&loopinfo, 0, sizeof(loopinfo));
112 safe_strncpy(loopinfo.lo_file_name, file, LO_NAME_SIZE);
113 loopinfo.lo_offset = offset;
114 // Associate free loop device with file
115 if(!ioctl(dfd, LOOP_SET_FD, ffd) &&
116 !ioctl(dfd, BB_LOOP_SET_STATUS, &loopinfo)) rc=0;
117 else ioctl(dfd, LOOP_CLR_FD, 0);
118 // If this block device already set up right, re-use it.
119 // (Yes this is racy, but associating two loop devices with the same
120 // file isn't pretty either. In general, mounting the same file twice
121 // without using losetup manually is problematic.)
122 } else if(strcmp(file,loopinfo.lo_file_name)
123 || offset!=loopinfo.lo_offset) rc=1;
124 close(dfd);
125 if(*device) break;
149 } 126 }
150 return NULL; 127 close(ffd);
128 if(!rc) {
129 if(!*device) *device=strdup(dev);
130 return mode==O_RDONLY ? 1 : 0;
131 } else return rc;
151} 132}
152#endif
153
154 133
155/* END CODE */ 134/* END CODE */
156/* 135/*
diff --git a/libbb/mtab.c b/libbb/mtab.c
index b1f74c476..fa4958c26 100644
--- a/libbb/mtab.c
+++ b/libbb/mtab.c
@@ -28,8 +28,8 @@
28#include "libbb.h" 28#include "libbb.h"
29 29
30#define MTAB_MAX_ENTRIES 40 30#define MTAB_MAX_ENTRIES 40
31static const int MS_RDONLY = 1; /* Mount read-only. */
32 31
32#ifdef CONFIG_FEATURE_MTAB_SUPPORT
33void erase_mtab(const char *name) 33void erase_mtab(const char *name)
34{ 34{
35 struct mntent entries[MTAB_MAX_ENTRIES]; 35 struct mntent entries[MTAB_MAX_ENTRIES];
@@ -72,45 +72,4 @@ void erase_mtab(const char *name)
72 } else if (errno != EROFS) 72 } else if (errno != EROFS)
73 bb_perror_msg(bb_path_mtab_file); 73 bb_perror_msg(bb_path_mtab_file);
74} 74}
75 75#endif
76void write_mtab(char *blockDevice, char *directory,
77 char *filesystemType, long flags, char *string_flags)
78{
79 FILE *mountTable = setmntent(bb_path_mtab_file, "a+");
80 struct mntent m;
81
82 if (mountTable == 0) {
83 bb_perror_msg(bb_path_mtab_file);
84 return;
85 }
86 if (mountTable) {
87 int length = strlen(directory);
88
89 if (length > 1 && directory[length - 1] == '/')
90 directory[length - 1] = '\0';
91
92 if (filesystemType == 0) {
93 struct mntent *p = find_mount_point(blockDevice, "/proc/mounts");
94
95 if (p && p->mnt_type)
96 filesystemType = p->mnt_type;
97 }
98 m.mnt_fsname = blockDevice;
99 m.mnt_dir = directory;
100 m.mnt_type = filesystemType ? filesystemType : "default";
101
102 if (*string_flags) {
103 m.mnt_opts = string_flags;
104 } else {
105 if ((flags | MS_RDONLY) == flags)
106 m.mnt_opts = "ro";
107 else
108 m.mnt_opts = "rw";
109 }
110
111 m.mnt_freq = 0;
112 m.mnt_passno = 0;
113 addmntent(mountTable, &m);
114 endmntent(mountTable);
115 }
116}
diff --git a/miscutils/eject.c b/miscutils/eject.c
index 8864687e4..3f1d6ab44 100644
--- a/miscutils/eject.c
+++ b/miscutils/eject.c
@@ -48,13 +48,9 @@ extern int eject_main(int argc, char **argv)
48 if((m = find_mount_point(device, bb_path_mtab_file))) { 48 if((m = find_mount_point(device, bb_path_mtab_file))) {
49 if(umount(m->mnt_dir)) 49 if(umount(m->mnt_dir))
50 bb_error_msg_and_die("Can't umount"); 50 bb_error_msg_and_die("Can't umount");
51#ifdef CONFIG_FEATURE_MTAB_SUPPORT 51 else if(ENABLE_FEATURE_MTAB_SUPPORT) erase_mtab(m->mnt_fsname);
52 else
53 erase_mtab(m->mnt_fsname);
54#endif
55 } 52 }
56 if (ioctl(bb_xopen( device, 53 if (ioctl(bb_xopen( device, (O_RDONLY | O_NONBLOCK)),
57 (O_RDONLY | O_NONBLOCK)),
58 ( flags ? CDROMCLOSETRAY : CDROMEJECT))) 54 ( flags ? CDROMCLOSETRAY : CDROMEJECT)))
59 { 55 {
60 bb_perror_msg_and_die(device); 56 bb_perror_msg_and_die(device);
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}