diff options
Diffstat (limited to 'util-linux/mount.c')
-rw-r--r-- | util-linux/mount.c | 681 |
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 | |||
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 | } |