diff options
Diffstat (limited to 'busybox/util-linux/mount.c')
-rw-r--r-- | busybox/util-linux/mount.c | 497 |
1 files changed, 497 insertions, 0 deletions
diff --git a/busybox/util-linux/mount.c b/busybox/util-linux/mount.c new file mode 100644 index 000000000..b059d7094 --- /dev/null +++ b/busybox/util-linux/mount.c | |||
@@ -0,0 +1,497 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * Mini mount implementation for busybox | ||
4 | * | ||
5 | * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>. | ||
6 | * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> | ||
7 | * | ||
8 | * 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 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * 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 | * | ||
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 | */ | ||
46 | |||
47 | #include <limits.h> | ||
48 | #include <stdlib.h> | ||
49 | #include <unistd.h> | ||
50 | #include <errno.h> | ||
51 | #include <string.h> | ||
52 | #include <stdio.h> | ||
53 | #include <mntent.h> | ||
54 | #include <ctype.h> | ||
55 | #include "busybox.h" | ||
56 | |||
57 | #ifdef CONFIG_NFSMOUNT | ||
58 | #if 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." | ||
60 | #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 | |||
82 | #if defined CONFIG_FEATURE_MOUNT_LOOP | ||
83 | #include <fcntl.h> | ||
84 | #include <sys/ioctl.h> | ||
85 | static int use_loop = FALSE; | ||
86 | #endif | ||
87 | |||
88 | extern int mount(__const char *__special_file, __const char *__dir, | ||
89 | __const char *__fstype, unsigned long int __rwflag, | ||
90 | __const void *__data); | ||
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 | |||
96 | struct mount_options { | ||
97 | const char *name; | ||
98 | unsigned long and; | ||
99 | unsigned long or; | ||
100 | }; | ||
101 | |||
102 | static const struct mount_options mount_options[] = { | ||
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) | ||
205 | { | ||
206 | while (options) { | ||
207 | int gotone = FALSE; | ||
208 | char *comma = strchr(options, ','); | ||
209 | const struct mount_options *f = mount_options; | ||
210 | |||
211 | if (comma) { | ||
212 | *comma = '\0'; | ||
213 | } | ||
214 | |||
215 | while (f->name != 0) { | ||
216 | if (strcasecmp(f->name, options) == 0) { | ||
217 | |||
218 | *flags &= f->and; | ||
219 | *flags |= f->or; | ||
220 | gotone = TRUE; | ||
221 | break; | ||
222 | } | ||
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 | } | ||
230 | #endif | ||
231 | if (!gotone) { | ||
232 | if (**strflags) { | ||
233 | /* have previous parsed options */ | ||
234 | paste_str(strflags, ","); | ||
235 | } | ||
236 | paste_str(strflags, options); | ||
237 | } | ||
238 | if (comma) { | ||
239 | *comma = ','; | ||
240 | options = ++comma; | ||
241 | } else { | ||
242 | break; | ||
243 | } | ||
244 | } | ||
245 | } | ||
246 | |||
247 | static int mount_one(char *blockDevice, char *directory, char *filesystemType, | ||
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 | |||
297 | while (fgets(buf, sizeof(buf), f) != NULL) { | ||
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 | { | ||
337 | FILE *mountTable = setmntent(bb_path_mtab_file, "r"); | ||
338 | |||
339 | if (mountTable) { | ||
340 | struct mntent *m; | ||
341 | |||
342 | while ((m = getmntent(mountTable)) != 0) { | ||
343 | char *blockDevice = m->mnt_fsname; | ||
344 | |||
345 | if (strcmp(blockDevice, "rootfs") == 0) { | ||
346 | continue; | ||
347 | } else if (strcmp(blockDevice, "/dev/root") == 0) { | ||
348 | blockDevice = find_real_root_device_name(); | ||
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 | } | ||
364 | exit(EXIT_SUCCESS); | ||
365 | } | ||
366 | |||
367 | extern int mount_main(int argc, char **argv) | ||
368 | { | ||
369 | struct stat statbuf; | ||
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) { | ||
388 | case 'o': | ||
389 | parse_mount_options(optarg, &flags, &string_flags); | ||
390 | break; | ||
391 | case 'r': | ||
392 | flags |= MS_RDONLY; | ||
393 | break; | ||
394 | case 't': | ||
395 | filesystemType = optarg; | ||
396 | got_filesystemType = 1; | ||
397 | break; | ||
398 | case 'w': | ||
399 | flags &= ~MS_RDONLY; | ||
400 | break; | ||
401 | case 'a': | ||
402 | all = TRUE; | ||
403 | break; | ||
404 | case 'f': | ||
405 | fakeIt = TRUE; | ||
406 | break; | ||
407 | case 'n': | ||
408 | #ifdef CONFIG_FEATURE_MTAB_SUPPORT | ||
409 | useMtab = FALSE; | ||
410 | #endif | ||
411 | break; | ||
412 | case 'v': | ||
413 | break; /* ignore -v */ | ||
414 | } | ||
415 | } | ||
416 | |||
417 | if (!all && (optind == argc)) { | ||
418 | show_mounts(got_filesystemType ? filesystemType : NULL); | ||
419 | } | ||
420 | |||
421 | if (optind < argc) { | ||
422 | /* if device is a filename get its real path */ | ||
423 | if (stat(argv[optind], &statbuf) == 0) { | ||
424 | char *tmp = bb_simplify_path(argv[optind]); | ||
425 | |||
426 | safe_strncpy(device, tmp, PATH_MAX); | ||
427 | } else { | ||
428 | safe_strncpy(device, argv[optind], PATH_MAX); | ||
429 | } | ||
430 | } | ||
431 | |||
432 | if (optind + 1 < argc) | ||
433 | directory = bb_simplify_path(argv[optind + 1]); | ||
434 | |||
435 | if (all || optind + 1 == argc) { | ||
436 | f = setmntent("/etc/fstab", "r"); | ||
437 | |||
438 | if (f == NULL) | ||
439 | bb_perror_msg_and_die("\nCannot read /etc/fstab"); | ||
440 | |||
441 | while ((m = getmntent(f)) != NULL) { | ||
442 | if (!all && (optind + 1 == argc) | ||
443 | && ((strcmp(device, m->mnt_fsname) != 0) | ||
444 | && (strcmp(device, m->mnt_dir) != 0))) { | ||
445 | continue; | ||
446 | } | ||
447 | |||
448 | if (all && ( /* If we're mounting 'all' */ | ||
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 | { | ||
452 | continue; | ||
453 | } | ||
454 | |||
455 | if (all || flags == 0) { /* Allow single mount to override fstab flags */ | ||
456 | flags = 0; | ||
457 | string_flags[0] = 0; | ||
458 | parse_mount_options(m->mnt_opts, &flags, &string_flags); | ||
459 | } | ||
460 | |||
461 | strcpy(device, m->mnt_fsname); | ||
462 | strcpy(directory, m->mnt_dir); | ||
463 | filesystemType = bb_xstrdup(m->mnt_type); | ||
464 | singlemount: | ||
465 | extra_opts = string_flags; | ||
466 | rc = EXIT_SUCCESS; | ||
467 | #ifdef CONFIG_NFSMOUNT | ||
468 | if (strchr(device, ':') != NULL) { | ||
469 | filesystemType = "nfs"; | ||
470 | if (nfsmount | ||
471 | (device, directory, &flags, &extra_opts, &string_flags, | ||
472 | 1)) { | ||
473 | bb_perror_msg("nfsmount failed"); | ||
474 | rc = EXIT_FAILURE; | ||
475 | } | ||
476 | } | ||
477 | #endif | ||
478 | if (!mount_one | ||
479 | (device, directory, filesystemType, flags, string_flags, | ||
480 | useMtab, fakeIt, extra_opts, TRUE, all)) { | ||
481 | rc = EXIT_FAILURE; | ||
482 | } | ||
483 | if (!all) { | ||
484 | break; | ||
485 | } | ||
486 | } | ||
487 | if (f) { | ||
488 | endmntent(f); | ||
489 | } | ||
490 | if (!all && f && m == NULL) { | ||
491 | fprintf(stderr, "Can't find %s in /etc/fstab\n", device); | ||
492 | } | ||
493 | return rc; | ||
494 | } | ||
495 | |||
496 | goto singlemount; | ||
497 | } | ||