summaryrefslogtreecommitdiff
path: root/util-linux/mount.c
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 /util-linux/mount.c
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. - *
Diffstat (limited to 'util-linux/mount.c')
-rw-r--r--util-linux/mount.c681
1 files changed, 292 insertions, 389 deletions
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}