diff options
-rw-r--r-- | coreutils/df.c | 2 | ||||
-rw-r--r-- | include/libbb.h | 11 | ||||
-rw-r--r-- | libbb/find_mount_point.c | 2 | ||||
-rw-r--r-- | libbb/find_root_device.c | 70 | ||||
-rw-r--r-- | libbb/loop.c | 163 | ||||
-rw-r--r-- | libbb/mtab.c | 45 | ||||
-rw-r--r-- | miscutils/eject.c | 8 | ||||
-rw-r--r-- | util-linux/Config.in | 59 | ||||
-rw-r--r-- | util-linux/losetup.c | 48 | ||||
-rw-r--r-- | util-linux/mount.c | 681 | ||||
-rw-r--r-- | util-linux/nfsmount.c | 6 | ||||
-rw-r--r-- | util-linux/umount.c | 370 |
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 | ||
133 | extern int get_console_fd(void); | 133 | extern int get_console_fd(void); |
134 | extern struct mntent *find_mount_point(const char *name, const char *table); | 134 | extern struct mntent *find_mount_point(const char *name, const char *table); |
135 | extern void write_mtab(char* blockDevice, char* directory, | ||
136 | char* filesystemType, long flags, char* string_flags); | ||
137 | extern void erase_mtab(const char * name); | 135 | extern void erase_mtab(const char * name); |
138 | extern long *find_pid_by_name( const char* pidName); | 136 | extern long *find_pid_by_name( const char* pidName); |
139 | extern char *find_real_root_device_name(void); | 137 | extern char *find_block_device(char *path); |
140 | extern char *bb_get_line_from_file(FILE *file); | 138 | extern char *bb_get_line_from_file(FILE *file); |
141 | extern char *bb_get_chomped_line_from_file(FILE *file); | 139 | extern char *bb_get_chomped_line_from_file(FILE *file); |
142 | extern char *bb_get_chunk_from_file(FILE *file); | 140 | extern char *bb_get_chunk_from_file(FILE *file); |
@@ -242,16 +240,14 @@ extern char *bb_askpass(int timeout, const char * prompt); | |||
242 | extern int device_open(const char *device, int mode); | 240 | extern int device_open(const char *device, int mode); |
243 | 241 | ||
244 | extern int del_loop(const char *device); | 242 | extern int del_loop(const char *device); |
245 | extern int set_loop(const char *device, const char *file, int offset, int *loopro); | 243 | extern int set_loop(char **device, const char *file, int offset); |
246 | extern char *find_unused_loop_device (void); | ||
247 | |||
248 | 244 | ||
249 | #if (__GLIBC__ < 2) | 245 | #if (__GLIBC__ < 2) |
250 | extern int vdprintf(int d, const char *format, va_list ap); | 246 | extern int vdprintf(int d, const char *format, va_list ap); |
251 | #endif | 247 | #endif |
252 | 248 | ||
253 | int nfsmount(const char *spec, const char *node, int *flags, | 249 | int 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 | 28 | extern char *find_block_device(char *path) | |
29 | |||
30 | extern 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 | } |
84 | Local Variables: | ||
85 | c-file-style: "linux" | ||
86 | c-basic-offset: 4 | ||
87 | tab-width: 4 | ||
88 | End: | ||
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) | 36 | typedef 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 |
54 | struct loop_info { | 50 | typedef 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 | ||
69 | extern int del_loop(const char *device) | 66 | extern 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 | ||
86 | extern 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 | 83 | extern 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 | |||
129 | extern 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 |
31 | static const int MS_RDONLY = 1; /* Mount read-only. */ | ||
32 | 31 | ||
32 | #ifdef CONFIG_FEATURE_MTAB_SUPPORT | ||
33 | void erase_mtab(const char *name) | 33 | void 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 | |
76 | void 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 | ||
326 | config 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 | |||
334 | comment "Common options for mount/umount" | 326 | comment "Common options for mount/umount" |
335 | depends on CONFIG_MOUNT || CONFIG_UMOUNT | 327 | depends on CONFIG_MOUNT || CONFIG_UMOUNT |
336 | 328 | ||
337 | config CONFIG_FEATURE_MOUNT_LOOP | 329 | config 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".) | |
352 | config 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 | ||
360 | config CONFIG_FEATURE_MTAB_SUPPORT | 345 | config 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 | ||
375 | config CONFIG_READPROFILE | 364 | config 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 @@ | |||
27 | int | 27 | int |
28 | losetup_main (int argc, char **argv) | 28 | losetup_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 | |||
63 | enum { | ||
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 |
85 | static int use_loop = FALSE; | 47 | #endif |
48 | #ifndef MS_MOVE | ||
49 | #define MS_MOVE 8192 | ||
86 | #endif | 50 | #endif |
87 | 51 | ||
88 | extern 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 */ |
91 | extern int umount(__const char *__special_file); | ||
92 | extern int umount2(__const char *__special_file, int __flags); | ||
93 | |||
94 | extern int sysfs(int option, unsigned int fs_index, char *buf); | ||
95 | 55 | ||
96 | struct mount_options { | 56 | struct { |
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 | ||
102 | static 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 | |||
125 | static int | ||
126 | do_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 | |||
197 | static 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 */ | ||
204 | static void parse_mount_options(char *options, int *flags, char **strflags) | 83 | static 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 | ||
247 | static 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) { | 120 | extern 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 | |||
335 | static 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 | ||
367 | extern 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 | |||
273 | singlemount: | ||
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; | ||
333 | mount_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 | ||
305 | int nfsmount(const char *spec, const char *node, int *flags, | 305 | int 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 | 23 | extern int umount_main(int argc, char **argv) |
32 | * prototype is missing... */ | ||
33 | #if (__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 1) | ||
34 | extern char *realpath(const char *path, char *resolved_path); | ||
35 | #endif | ||
36 | |||
37 | static const int MNT_FORCE = 1; | ||
38 | static const int MS_MGC_VAL = 0xc0ed0000; /* Magic number indicatng "new" flags */ | ||
39 | static const int MS_REMOUNT = 32; /* Alter flags of a mounted FS. */ | ||
40 | static const int MS_RDONLY = 1; /* Mount read-only. */ | ||
41 | |||
42 | extern int mount (__const char *__special_file, __const char *__dir, | ||
43 | __const char *__fstype, unsigned long int __rwflag, | ||
44 | __const void *__data); | ||
45 | extern int umount (__const char *__special_file); | ||
46 | extern int umount2 (__const char *__special_file, int __flags); | ||
47 | |||
48 | struct _mtab_entry_t { | ||
49 | char *device; | ||
50 | char *mountpt; | ||
51 | struct _mtab_entry_t *next; | ||
52 | }; | ||
53 | |||
54 | static struct _mtab_entry_t *mtab_cache = NULL; | ||
55 | |||
56 | |||
57 | |||
58 | #if defined CONFIG_FEATURE_MOUNT_FORCE | ||
59 | static int doForce = FALSE; | ||
60 | #endif | ||
61 | #if defined CONFIG_FEATURE_MOUNT_LOOP | ||
62 | static int freeLoop = TRUE; | ||
63 | #endif | ||
64 | #if defined CONFIG_FEATURE_MTAB_SUPPORT | ||
65 | static int useMtab = TRUE; | ||
66 | #endif | ||
67 | static int umountAll = FALSE; | ||
68 | static 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 | */ | ||
79 | static 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; | |
102 | static 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 | |||
129 | static 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; | |
140 | static 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 | ||
154 | static 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 | |||
169 | static 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 | ||
211 | static 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 | ||
239 | extern 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 | } |