diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2006-09-15 15:12:00 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2006-09-15 15:12:00 +0000 |
commit | 30a64cdc95eaa435c00a9aeccdc1b8f9da727875 (patch) | |
tree | 1f8fd2a5aa7b863be39d32d371d0f34fbb470b01 | |
parent | 215c61d3c2830113479ce008d9c1d7e3978ad9c1 (diff) | |
download | busybox-w32-30a64cdc95eaa435c00a9aeccdc1b8f9da727875.tar.gz busybox-w32-30a64cdc95eaa435c00a9aeccdc1b8f9da727875.tar.bz2 busybox-w32-30a64cdc95eaa435c00a9aeccdc1b8f9da727875.zip |
mount: reorder things, fix NFS-less mount.
-rw-r--r-- | util-linux/mount.c | 740 |
1 files changed, 360 insertions, 380 deletions
diff --git a/util-linux/mount.c b/util-linux/mount.c index 4660b27ef..5219842ef 100644 --- a/util-linux/mount.c +++ b/util-linux/mount.c | |||
@@ -25,6 +25,16 @@ | |||
25 | #include "busybox.h" | 25 | #include "busybox.h" |
26 | #include <mntent.h> | 26 | #include <mntent.h> |
27 | 27 | ||
28 | /* Needed for nfs support only... */ | ||
29 | #include <syslog.h> | ||
30 | #include <sys/utsname.h> | ||
31 | #undef TRUE | ||
32 | #undef FALSE | ||
33 | #include <rpc/rpc.h> | ||
34 | #include <rpc/pmap_prot.h> | ||
35 | #include <rpc/pmap_clnt.h> | ||
36 | |||
37 | |||
28 | // Not real flags, but we want to be able to check for this. | 38 | // Not real flags, but we want to be able to check for this. |
29 | #define MOUNT_NOAUTO (1<<29) | 39 | #define MOUNT_NOAUTO (1<<29) |
30 | #define MOUNT_SWAP (1<<30) | 40 | #define MOUNT_SWAP (1<<30) |
@@ -86,7 +96,7 @@ struct { | |||
86 | {"remount", MS_REMOUNT}, // action flag | 96 | {"remount", MS_REMOUNT}, // action flag |
87 | }; | 97 | }; |
88 | 98 | ||
89 | static int nfsmount(struct mntent *mp, int vfsflags, char *filteropts); | 99 | |
90 | 100 | ||
91 | /* Append mount options to string */ | 101 | /* Append mount options to string */ |
92 | static void append_mount_options(char **oldopts, char *newopts) | 102 | static void append_mount_options(char **oldopts, char *newopts) |
@@ -272,349 +282,6 @@ static int mount_it_now(struct mntent *mp, int vfsflags, char *filteropts) | |||
272 | return rc; | 282 | return rc; |
273 | } | 283 | } |
274 | 284 | ||
275 | // Mount one directory. Handles CIFS, NFS, loopback, autobind, and filesystem | ||
276 | // type detection. Returns 0 for success, nonzero for failure. | ||
277 | |||
278 | static int singlemount(struct mntent *mp, int ignore_busy) | ||
279 | { | ||
280 | int rc = -1, vfsflags; | ||
281 | char *loopFile = 0, *filteropts = 0; | ||
282 | llist_t *fl = 0; | ||
283 | struct stat st; | ||
284 | |||
285 | vfsflags = parse_mount_options(mp->mnt_opts, &filteropts); | ||
286 | |||
287 | // Treat fstype "auto" as unspecified. | ||
288 | |||
289 | if (mp->mnt_type && !strcmp(mp->mnt_type,"auto")) mp->mnt_type = 0; | ||
290 | |||
291 | // Might this be an CIFS filesystem? | ||
292 | |||
293 | if(ENABLE_FEATURE_MOUNT_CIFS && | ||
294 | (!mp->mnt_type || !strcmp(mp->mnt_type,"cifs")) && | ||
295 | (mp->mnt_fsname[0]==mp->mnt_fsname[1] && (mp->mnt_fsname[0]=='/' || mp->mnt_fsname[0]=='\\'))) | ||
296 | { | ||
297 | struct hostent *he; | ||
298 | char ip[32], *s; | ||
299 | |||
300 | rc = 1; | ||
301 | // Replace '/' with '\' and verify that unc points to "//server/share". | ||
302 | |||
303 | for (s = mp->mnt_fsname; *s; ++s) | ||
304 | if (*s == '/') *s = '\\'; | ||
305 | |||
306 | // get server IP | ||
307 | |||
308 | s = strrchr(mp->mnt_fsname, '\\'); | ||
309 | if (s == mp->mnt_fsname+1) goto report_error; | ||
310 | *s = 0; | ||
311 | he = gethostbyname(mp->mnt_fsname+2); | ||
312 | *s = '\\'; | ||
313 | if (!he) goto report_error; | ||
314 | |||
315 | // Insert ip=... option into string flags. (NOTE: Add IPv6 support.) | ||
316 | |||
317 | sprintf(ip, "ip=%d.%d.%d.%d", he->h_addr[0], he->h_addr[1], | ||
318 | he->h_addr[2], he->h_addr[3]); | ||
319 | parse_mount_options(ip, &filteropts); | ||
320 | |||
321 | // compose new unc '\\server-ip\share' | ||
322 | |||
323 | s = xasprintf("\\\\%s%s",ip+3,strchr(mp->mnt_fsname+2,'\\')); | ||
324 | if (ENABLE_FEATURE_CLEAN_UP) free(mp->mnt_fsname); | ||
325 | mp->mnt_fsname = s; | ||
326 | |||
327 | // lock is required | ||
328 | vfsflags |= MS_MANDLOCK; | ||
329 | |||
330 | mp->mnt_type = "cifs"; | ||
331 | rc = mount_it_now(mp, vfsflags, filteropts); | ||
332 | goto report_error; | ||
333 | } | ||
334 | |||
335 | // Might this be an NFS filesystem? | ||
336 | |||
337 | if (ENABLE_FEATURE_MOUNT_NFS && | ||
338 | (!mp->mnt_type || !strcmp(mp->mnt_type,"nfs")) && | ||
339 | strchr(mp->mnt_fsname, ':') != NULL) | ||
340 | { | ||
341 | rc = nfsmount(mp, vfsflags, filteropts); | ||
342 | goto report_error; | ||
343 | } | ||
344 | |||
345 | // Look at the file. (Not found isn't a failure for remount, or for | ||
346 | // a synthetic filesystem like proc or sysfs.) | ||
347 | |||
348 | if (!lstat(mp->mnt_fsname, &st) && !(vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))) | ||
349 | { | ||
350 | // Do we need to allocate a loopback device for it? | ||
351 | |||
352 | if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) { | ||
353 | loopFile = bb_simplify_path(mp->mnt_fsname); | ||
354 | mp->mnt_fsname = 0; | ||
355 | switch(set_loop(&(mp->mnt_fsname), loopFile, 0)) { | ||
356 | case 0: | ||
357 | case 1: | ||
358 | break; | ||
359 | default: | ||
360 | bb_error_msg( errno == EPERM || errno == EACCES | ||
361 | ? bb_msg_perm_denied_are_you_root | ||
362 | : "cannot setup loop device"); | ||
363 | return errno; | ||
364 | } | ||
365 | |||
366 | // Autodetect bind mounts | ||
367 | |||
368 | } else if (S_ISDIR(st.st_mode) && !mp->mnt_type) | ||
369 | vfsflags |= MS_BIND; | ||
370 | } | ||
371 | |||
372 | /* If we know the fstype (or don't need to), jump straight | ||
373 | * to the actual mount. */ | ||
374 | |||
375 | if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))) | ||
376 | rc = mount_it_now(mp, vfsflags, filteropts); | ||
377 | |||
378 | // Loop through filesystem types until mount succeeds or we run out | ||
379 | |||
380 | else { | ||
381 | |||
382 | /* Initialize list of block backed filesystems. This has to be | ||
383 | * done here so that during "mount -a", mounts after /proc shows up | ||
384 | * can autodetect. */ | ||
385 | |||
386 | if (!fslist) { | ||
387 | fslist = get_block_backed_filesystems(); | ||
388 | if (ENABLE_FEATURE_CLEAN_UP && fslist) | ||
389 | atexit(delete_block_backed_filesystems); | ||
390 | } | ||
391 | |||
392 | for (fl = fslist; fl; fl = fl->link) { | ||
393 | mp->mnt_type = fl->data; | ||
394 | |||
395 | if (!(rc = mount_it_now(mp,vfsflags, filteropts))) break; | ||
396 | |||
397 | mp->mnt_type = 0; | ||
398 | } | ||
399 | } | ||
400 | |||
401 | // If mount failed, clean up loop file (if any). | ||
402 | |||
403 | if (ENABLE_FEATURE_MOUNT_LOOP && rc && loopFile) { | ||
404 | del_loop(mp->mnt_fsname); | ||
405 | if (ENABLE_FEATURE_CLEAN_UP) { | ||
406 | free(loopFile); | ||
407 | free(mp->mnt_fsname); | ||
408 | } | ||
409 | } | ||
410 | |||
411 | report_error: | ||
412 | if (ENABLE_FEATURE_CLEAN_UP) free(filteropts); | ||
413 | |||
414 | if (rc && errno == EBUSY && ignore_busy) rc = 0; | ||
415 | if (rc < 0) | ||
416 | /* perror here sometimes says "mounting ... on ... failed: Success" */ | ||
417 | bb_error_msg("mounting %s on %s failed", mp->mnt_fsname, mp->mnt_dir); | ||
418 | |||
419 | return rc; | ||
420 | } | ||
421 | |||
422 | // Parse options, if necessary parse fstab/mtab, and call singlemount for | ||
423 | // each directory to be mounted. | ||
424 | |||
425 | int mount_main(int argc, char **argv) | ||
426 | { | ||
427 | char *cmdopts = xstrdup(""), *fstabname, *fstype=0, *storage_path=0; | ||
428 | FILE *fstab; | ||
429 | int i, opt, all = FALSE, rc = 0; | ||
430 | struct mntent mtpair[2], *mtcur = mtpair; | ||
431 | |||
432 | /* parse long options, like --bind and --move. Note that -o option | ||
433 | * and --option are synonymous. Yes, this means --remount,rw works. */ | ||
434 | |||
435 | for (i = opt = 0; i < argc; i++) { | ||
436 | if (argv[i][0] == '-' && argv[i][1] == '-') { | ||
437 | append_mount_options(&cmdopts,argv[i]+2); | ||
438 | } else argv[opt++] = argv[i]; | ||
439 | } | ||
440 | argc = opt; | ||
441 | |||
442 | // Parse remaining options | ||
443 | |||
444 | while ((opt = getopt(argc, argv, "o:t:rwavnf")) > 0) { | ||
445 | switch (opt) { | ||
446 | case 'o': | ||
447 | append_mount_options(&cmdopts, optarg); | ||
448 | break; | ||
449 | case 't': | ||
450 | fstype = optarg; | ||
451 | break; | ||
452 | case 'r': | ||
453 | append_mount_options(&cmdopts, "ro"); | ||
454 | break; | ||
455 | case 'w': | ||
456 | append_mount_options(&cmdopts, "rw"); | ||
457 | break; | ||
458 | case 'a': | ||
459 | all = TRUE; | ||
460 | break; | ||
461 | case 'n': | ||
462 | USE_FEATURE_MTAB_SUPPORT(useMtab = FALSE;) | ||
463 | break; | ||
464 | case 'f': | ||
465 | USE_FEATURE_MTAB_SUPPORT(fakeIt = FALSE;) | ||
466 | break; | ||
467 | case 'v': | ||
468 | break; // ignore -v | ||
469 | default: | ||
470 | bb_show_usage(); | ||
471 | } | ||
472 | } | ||
473 | |||
474 | // Three or more non-option arguments? Die with a usage message. | ||
475 | |||
476 | if (optind-argc>2) bb_show_usage(); | ||
477 | |||
478 | // If we have no arguments, show currently mounted filesystems | ||
479 | |||
480 | if (optind == argc) { | ||
481 | if (!all) { | ||
482 | FILE *mountTable = setmntent(bb_path_mtab_file, "r"); | ||
483 | |||
484 | if(!mountTable) bb_error_msg_and_die("no %s",bb_path_mtab_file); | ||
485 | |||
486 | while (getmntent_r(mountTable,mtpair,bb_common_bufsiz1, | ||
487 | sizeof(bb_common_bufsiz1))) | ||
488 | { | ||
489 | // Don't show rootfs. | ||
490 | if (!strcmp(mtpair->mnt_fsname, "rootfs")) continue; | ||
491 | |||
492 | if (!fstype || !strcmp(mtpair->mnt_type, fstype)) | ||
493 | printf("%s on %s type %s (%s)\n", mtpair->mnt_fsname, | ||
494 | mtpair->mnt_dir, mtpair->mnt_type, | ||
495 | mtpair->mnt_opts); | ||
496 | } | ||
497 | if (ENABLE_FEATURE_CLEAN_UP) endmntent(mountTable); | ||
498 | return EXIT_SUCCESS; | ||
499 | } | ||
500 | } else storage_path = bb_simplify_path(argv[optind]); | ||
501 | |||
502 | // When we have two arguments, the second is the directory and we can | ||
503 | // skip looking at fstab entirely. We can always abspath() the directory | ||
504 | // argument when we get it. | ||
505 | |||
506 | if (optind+2 == argc) { | ||
507 | mtpair->mnt_fsname = argv[optind]; | ||
508 | mtpair->mnt_dir = argv[optind+1]; | ||
509 | mtpair->mnt_type = fstype; | ||
510 | mtpair->mnt_opts = cmdopts; | ||
511 | rc = singlemount(mtpair, 0); | ||
512 | goto clean_up; | ||
513 | } | ||
514 | |||
515 | // If we have a shared subtree flag, don't worry about fstab or mtab. | ||
516 | i = parse_mount_options(cmdopts,0); | ||
517 | if (ENABLE_FEATURE_MOUNT_FLAGS && | ||
518 | (i & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE ))) | ||
519 | { | ||
520 | rc = mount("", argv[optind], "", i, ""); | ||
521 | if (rc) bb_perror_msg_and_die("%s", argv[optind]); | ||
522 | goto clean_up; | ||
523 | } | ||
524 | |||
525 | // Open either fstab or mtab | ||
526 | |||
527 | if (parse_mount_options(cmdopts,0) & MS_REMOUNT) | ||
528 | fstabname = bb_path_mtab_file; | ||
529 | else fstabname="/etc/fstab"; | ||
530 | |||
531 | if (!(fstab=setmntent(fstabname,"r"))) | ||
532 | bb_perror_msg_and_die("cannot read %s",fstabname); | ||
533 | |||
534 | // Loop through entries until we find what we're looking for. | ||
535 | |||
536 | memset(mtpair,0,sizeof(mtpair)); | ||
537 | for (;;) { | ||
538 | struct mntent *mtnext = mtpair + (mtcur==mtpair ? 1 : 0); | ||
539 | |||
540 | // Get next fstab entry | ||
541 | |||
542 | if (!getmntent_r(fstab, mtcur, bb_common_bufsiz1 | ||
543 | + (mtcur==mtpair ? sizeof(bb_common_bufsiz1)/2 : 0), | ||
544 | sizeof(bb_common_bufsiz1)/2)) | ||
545 | { | ||
546 | // Were we looking for something specific? | ||
547 | |||
548 | if (optind != argc) { | ||
549 | |||
550 | // If we didn't find anything, complain. | ||
551 | |||
552 | if (!mtnext->mnt_fsname) | ||
553 | bb_error_msg_and_die("can't find %s in %s", | ||
554 | argv[optind], fstabname); | ||
555 | |||
556 | // Mount the last thing we found. | ||
557 | |||
558 | mtcur = mtnext; | ||
559 | mtcur->mnt_opts = xstrdup(mtcur->mnt_opts); | ||
560 | append_mount_options(&(mtcur->mnt_opts),cmdopts); | ||
561 | rc = singlemount(mtcur, 0); | ||
562 | free(mtcur->mnt_opts); | ||
563 | } | ||
564 | goto clean_up; | ||
565 | } | ||
566 | |||
567 | /* If we're trying to mount something specific and this isn't it, | ||
568 | * skip it. Note we must match both the exact text in fstab (ala | ||
569 | * "proc") or a full path from root */ | ||
570 | |||
571 | if (optind != argc) { | ||
572 | |||
573 | // Is this what we're looking for? | ||
574 | |||
575 | if(strcmp(argv[optind],mtcur->mnt_fsname) && | ||
576 | strcmp(storage_path,mtcur->mnt_fsname) && | ||
577 | strcmp(argv[optind],mtcur->mnt_dir) && | ||
578 | strcmp(storage_path,mtcur->mnt_dir)) continue; | ||
579 | |||
580 | // Remember this entry. Something later may have overmounted | ||
581 | // it, and we want the _last_ match. | ||
582 | |||
583 | mtcur = mtnext; | ||
584 | |||
585 | // If we're mounting all. | ||
586 | |||
587 | } else { | ||
588 | |||
589 | // Do we need to match a filesystem type? | ||
590 | if (fstype && strcmp(mtcur->mnt_type,fstype)) continue; | ||
591 | |||
592 | // Skip noauto and swap anyway. | ||
593 | |||
594 | if (parse_mount_options(mtcur->mnt_opts,0) | ||
595 | & (MOUNT_NOAUTO | MOUNT_SWAP)) continue; | ||
596 | |||
597 | // Mount this thing. | ||
598 | |||
599 | if (singlemount(mtcur, 1)) { | ||
600 | /* Count number of failed mounts */ | ||
601 | rc++; | ||
602 | } | ||
603 | } | ||
604 | } | ||
605 | if (ENABLE_FEATURE_CLEAN_UP) endmntent(fstab); | ||
606 | |||
607 | clean_up: | ||
608 | |||
609 | if (ENABLE_FEATURE_CLEAN_UP) { | ||
610 | free(storage_path); | ||
611 | free(cmdopts); | ||
612 | } | ||
613 | |||
614 | return rc; | ||
615 | } | ||
616 | |||
617 | |||
618 | #if ENABLE_FEATURE_MOUNT_NFS | 285 | #if ENABLE_FEATURE_MOUNT_NFS |
619 | 286 | ||
620 | /* | 287 | /* |
@@ -639,17 +306,9 @@ clean_up: | |||
639 | * plus NFSv3 stuff. | 306 | * plus NFSv3 stuff. |
640 | */ | 307 | */ |
641 | 308 | ||
642 | #include <syslog.h> | ||
643 | #include <sys/utsname.h> | ||
644 | #undef TRUE | ||
645 | #undef FALSE | ||
646 | #include <rpc/rpc.h> | ||
647 | #include <rpc/pmap_prot.h> | ||
648 | #include <rpc/pmap_clnt.h> | ||
649 | |||
650 | /* This is just a warning of a common mistake. Possibly this should be a | 309 | /* This is just a warning of a common mistake. Possibly this should be a |
651 | * uclibc faq entry rather than in busybox... */ | 310 | * uclibc faq entry rather than in busybox... */ |
652 | #if ENABLE_FEATURE_MOUNT_NFS && defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__) | 311 | #if defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__) |
653 | #error "You need to build uClibc with UCLIBC_HAS_RPC for NFS support." | 312 | #error "You need to build uClibc with UCLIBC_HAS_RPC for NFS support." |
654 | #endif | 313 | #endif |
655 | 314 | ||
@@ -1314,25 +973,6 @@ static int nfsmount(struct mntent *mp, int vfsflags, char *filteropts) | |||
1314 | if (!data.timeo) | 973 | if (!data.timeo) |
1315 | data.timeo = tcp ? 70 : 7; | 974 | data.timeo = tcp ? 70 : 7; |
1316 | 975 | ||
1317 | #ifdef NFS_MOUNT_DEBUG | ||
1318 | printf("rsize = %d, wsize = %d, timeo = %d, retrans = %d\n", | ||
1319 | data.rsize, data.wsize, data.timeo, data.retrans); | ||
1320 | printf("acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)\n", | ||
1321 | data.acregmin, data.acregmax, data.acdirmin, data.acdirmax); | ||
1322 | printf("port = %d, bg = %d, retry = %d, flags = %.8x\n", | ||
1323 | port, bg, retry, data.flags); | ||
1324 | printf("mountprog = %d, mountvers = %d, nfsprog = %d, nfsvers = %d\n", | ||
1325 | mountprog, mountvers, nfsprog, nfsvers); | ||
1326 | printf("soft = %d, intr = %d, posix = %d, nocto = %d, noac = %d\n", | ||
1327 | (data.flags & NFS_MOUNT_SOFT) != 0, | ||
1328 | (data.flags & NFS_MOUNT_INTR) != 0, | ||
1329 | (data.flags & NFS_MOUNT_POSIX) != 0, | ||
1330 | (data.flags & NFS_MOUNT_NOCTO) != 0, | ||
1331 | (data.flags & NFS_MOUNT_NOAC) != 0); | ||
1332 | printf("tcp = %d\n", | ||
1333 | (data.flags & NFS_MOUNT_TCP) != 0); | ||
1334 | #endif | ||
1335 | |||
1336 | data.version = nfs_mount_version; | 976 | data.version = nfs_mount_version; |
1337 | 977 | ||
1338 | if (vfsflags & MS_REMOUNT) | 978 | if (vfsflags & MS_REMOUNT) |
@@ -1559,14 +1199,7 @@ prepare_kernel_data: | |||
1559 | tcp ? IPPROTO_TCP : IPPROTO_UDP); | 1199 | tcp ? IPPROTO_TCP : IPPROTO_UDP); |
1560 | if (port == 0) | 1200 | if (port == 0) |
1561 | port = NFS_PORT; | 1201 | port = NFS_PORT; |
1562 | #ifdef NFS_MOUNT_DEBUG | ||
1563 | else | ||
1564 | printf("used portmapper to find NFS port\n"); | ||
1565 | #endif | ||
1566 | } | 1202 | } |
1567 | #ifdef NFS_MOUNT_DEBUG | ||
1568 | printf("using port %d for nfs daemon\n", port); | ||
1569 | #endif | ||
1570 | server_addr.sin_port = htons(port); | 1203 | server_addr.sin_port = htons(port); |
1571 | 1204 | ||
1572 | /* prepare data structure for kernel */ | 1205 | /* prepare data structure for kernel */ |
@@ -1625,4 +1258,351 @@ ret: | |||
1625 | return retval; | 1258 | return retval; |
1626 | } | 1259 | } |
1627 | 1260 | ||
1628 | #endif /* ENABLE_FEATURE_MOUNT_NFS */ | 1261 | #else /* !ENABLE_FEATURE_MOUNT_NFS */ |
1262 | |||
1263 | /* Never called. Call should be optimized out. */ | ||
1264 | int nfsmount(struct mntent *mp, int vfsflags, char *filteropts); | ||
1265 | |||
1266 | #endif /* !ENABLE_FEATURE_MOUNT_NFS */ | ||
1267 | |||
1268 | // Mount one directory. Handles CIFS, NFS, loopback, autobind, and filesystem | ||
1269 | // type detection. Returns 0 for success, nonzero for failure. | ||
1270 | |||
1271 | static int singlemount(struct mntent *mp, int ignore_busy) | ||
1272 | { | ||
1273 | int rc = -1, vfsflags; | ||
1274 | char *loopFile = 0, *filteropts = 0; | ||
1275 | llist_t *fl = 0; | ||
1276 | struct stat st; | ||
1277 | |||
1278 | vfsflags = parse_mount_options(mp->mnt_opts, &filteropts); | ||
1279 | |||
1280 | // Treat fstype "auto" as unspecified. | ||
1281 | |||
1282 | if (mp->mnt_type && !strcmp(mp->mnt_type,"auto")) mp->mnt_type = 0; | ||
1283 | |||
1284 | // Might this be an CIFS filesystem? | ||
1285 | |||
1286 | if(ENABLE_FEATURE_MOUNT_CIFS && | ||
1287 | (!mp->mnt_type || !strcmp(mp->mnt_type,"cifs")) && | ||
1288 | (mp->mnt_fsname[0]==mp->mnt_fsname[1] && (mp->mnt_fsname[0]=='/' || mp->mnt_fsname[0]=='\\'))) | ||
1289 | { | ||
1290 | struct hostent *he; | ||
1291 | char ip[32], *s; | ||
1292 | |||
1293 | rc = 1; | ||
1294 | // Replace '/' with '\' and verify that unc points to "//server/share". | ||
1295 | |||
1296 | for (s = mp->mnt_fsname; *s; ++s) | ||
1297 | if (*s == '/') *s = '\\'; | ||
1298 | |||
1299 | // get server IP | ||
1300 | |||
1301 | s = strrchr(mp->mnt_fsname, '\\'); | ||
1302 | if (s == mp->mnt_fsname+1) goto report_error; | ||
1303 | *s = 0; | ||
1304 | he = gethostbyname(mp->mnt_fsname+2); | ||
1305 | *s = '\\'; | ||
1306 | if (!he) goto report_error; | ||
1307 | |||
1308 | // Insert ip=... option into string flags. (NOTE: Add IPv6 support.) | ||
1309 | |||
1310 | sprintf(ip, "ip=%d.%d.%d.%d", he->h_addr[0], he->h_addr[1], | ||
1311 | he->h_addr[2], he->h_addr[3]); | ||
1312 | parse_mount_options(ip, &filteropts); | ||
1313 | |||
1314 | // compose new unc '\\server-ip\share' | ||
1315 | |||
1316 | s = xasprintf("\\\\%s%s",ip+3,strchr(mp->mnt_fsname+2,'\\')); | ||
1317 | if (ENABLE_FEATURE_CLEAN_UP) free(mp->mnt_fsname); | ||
1318 | mp->mnt_fsname = s; | ||
1319 | |||
1320 | // lock is required | ||
1321 | vfsflags |= MS_MANDLOCK; | ||
1322 | |||
1323 | mp->mnt_type = "cifs"; | ||
1324 | rc = mount_it_now(mp, vfsflags, filteropts); | ||
1325 | goto report_error; | ||
1326 | } | ||
1327 | |||
1328 | // Might this be an NFS filesystem? | ||
1329 | |||
1330 | if (ENABLE_FEATURE_MOUNT_NFS && | ||
1331 | (!mp->mnt_type || !strcmp(mp->mnt_type,"nfs")) && | ||
1332 | strchr(mp->mnt_fsname, ':') != NULL) | ||
1333 | { | ||
1334 | rc = nfsmount(mp, vfsflags, filteropts); | ||
1335 | goto report_error; | ||
1336 | } | ||
1337 | |||
1338 | // Look at the file. (Not found isn't a failure for remount, or for | ||
1339 | // a synthetic filesystem like proc or sysfs.) | ||
1340 | |||
1341 | if (!lstat(mp->mnt_fsname, &st) && !(vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))) | ||
1342 | { | ||
1343 | // Do we need to allocate a loopback device for it? | ||
1344 | |||
1345 | if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) { | ||
1346 | loopFile = bb_simplify_path(mp->mnt_fsname); | ||
1347 | mp->mnt_fsname = 0; | ||
1348 | switch(set_loop(&(mp->mnt_fsname), loopFile, 0)) { | ||
1349 | case 0: | ||
1350 | case 1: | ||
1351 | break; | ||
1352 | default: | ||
1353 | bb_error_msg( errno == EPERM || errno == EACCES | ||
1354 | ? bb_msg_perm_denied_are_you_root | ||
1355 | : "cannot setup loop device"); | ||
1356 | return errno; | ||
1357 | } | ||
1358 | |||
1359 | // Autodetect bind mounts | ||
1360 | |||
1361 | } else if (S_ISDIR(st.st_mode) && !mp->mnt_type) | ||
1362 | vfsflags |= MS_BIND; | ||
1363 | } | ||
1364 | |||
1365 | /* If we know the fstype (or don't need to), jump straight | ||
1366 | * to the actual mount. */ | ||
1367 | |||
1368 | if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))) | ||
1369 | rc = mount_it_now(mp, vfsflags, filteropts); | ||
1370 | |||
1371 | // Loop through filesystem types until mount succeeds or we run out | ||
1372 | |||
1373 | else { | ||
1374 | |||
1375 | /* Initialize list of block backed filesystems. This has to be | ||
1376 | * done here so that during "mount -a", mounts after /proc shows up | ||
1377 | * can autodetect. */ | ||
1378 | |||
1379 | if (!fslist) { | ||
1380 | fslist = get_block_backed_filesystems(); | ||
1381 | if (ENABLE_FEATURE_CLEAN_UP && fslist) | ||
1382 | atexit(delete_block_backed_filesystems); | ||
1383 | } | ||
1384 | |||
1385 | for (fl = fslist; fl; fl = fl->link) { | ||
1386 | mp->mnt_type = fl->data; | ||
1387 | |||
1388 | if (!(rc = mount_it_now(mp,vfsflags, filteropts))) break; | ||
1389 | |||
1390 | mp->mnt_type = 0; | ||
1391 | } | ||
1392 | } | ||
1393 | |||
1394 | // If mount failed, clean up loop file (if any). | ||
1395 | |||
1396 | if (ENABLE_FEATURE_MOUNT_LOOP && rc && loopFile) { | ||
1397 | del_loop(mp->mnt_fsname); | ||
1398 | if (ENABLE_FEATURE_CLEAN_UP) { | ||
1399 | free(loopFile); | ||
1400 | free(mp->mnt_fsname); | ||
1401 | } | ||
1402 | } | ||
1403 | |||
1404 | report_error: | ||
1405 | if (ENABLE_FEATURE_CLEAN_UP) free(filteropts); | ||
1406 | |||
1407 | if (rc && errno == EBUSY && ignore_busy) rc = 0; | ||
1408 | if (rc < 0) | ||
1409 | /* perror here sometimes says "mounting ... on ... failed: Success" */ | ||
1410 | bb_error_msg("mounting %s on %s failed", mp->mnt_fsname, mp->mnt_dir); | ||
1411 | |||
1412 | return rc; | ||
1413 | } | ||
1414 | |||
1415 | // Parse options, if necessary parse fstab/mtab, and call singlemount for | ||
1416 | // each directory to be mounted. | ||
1417 | |||
1418 | int mount_main(int argc, char **argv) | ||
1419 | { | ||
1420 | char *cmdopts = xstrdup(""), *fstabname, *fstype=0, *storage_path=0; | ||
1421 | FILE *fstab; | ||
1422 | int i, opt, all = FALSE, rc = 0; | ||
1423 | struct mntent mtpair[2], *mtcur = mtpair; | ||
1424 | |||
1425 | /* parse long options, like --bind and --move. Note that -o option | ||
1426 | * and --option are synonymous. Yes, this means --remount,rw works. */ | ||
1427 | |||
1428 | for (i = opt = 0; i < argc; i++) { | ||
1429 | if (argv[i][0] == '-' && argv[i][1] == '-') { | ||
1430 | append_mount_options(&cmdopts,argv[i]+2); | ||
1431 | } else argv[opt++] = argv[i]; | ||
1432 | } | ||
1433 | argc = opt; | ||
1434 | |||
1435 | // Parse remaining options | ||
1436 | |||
1437 | while ((opt = getopt(argc, argv, "o:t:rwavnf")) > 0) { | ||
1438 | switch (opt) { | ||
1439 | case 'o': | ||
1440 | append_mount_options(&cmdopts, optarg); | ||
1441 | break; | ||
1442 | case 't': | ||
1443 | fstype = optarg; | ||
1444 | break; | ||
1445 | case 'r': | ||
1446 | append_mount_options(&cmdopts, "ro"); | ||
1447 | break; | ||
1448 | case 'w': | ||
1449 | append_mount_options(&cmdopts, "rw"); | ||
1450 | break; | ||
1451 | case 'a': | ||
1452 | all = TRUE; | ||
1453 | break; | ||
1454 | case 'n': | ||
1455 | USE_FEATURE_MTAB_SUPPORT(useMtab = FALSE;) | ||
1456 | break; | ||
1457 | case 'f': | ||
1458 | USE_FEATURE_MTAB_SUPPORT(fakeIt = FALSE;) | ||
1459 | break; | ||
1460 | case 'v': | ||
1461 | break; // ignore -v | ||
1462 | default: | ||
1463 | bb_show_usage(); | ||
1464 | } | ||
1465 | } | ||
1466 | |||
1467 | // Three or more non-option arguments? Die with a usage message. | ||
1468 | |||
1469 | if (optind-argc>2) bb_show_usage(); | ||
1470 | |||
1471 | // If we have no arguments, show currently mounted filesystems | ||
1472 | |||
1473 | if (optind == argc) { | ||
1474 | if (!all) { | ||
1475 | FILE *mountTable = setmntent(bb_path_mtab_file, "r"); | ||
1476 | |||
1477 | if(!mountTable) bb_error_msg_and_die("no %s",bb_path_mtab_file); | ||
1478 | |||
1479 | while (getmntent_r(mountTable,mtpair,bb_common_bufsiz1, | ||
1480 | sizeof(bb_common_bufsiz1))) | ||
1481 | { | ||
1482 | // Don't show rootfs. | ||
1483 | if (!strcmp(mtpair->mnt_fsname, "rootfs")) continue; | ||
1484 | |||
1485 | if (!fstype || !strcmp(mtpair->mnt_type, fstype)) | ||
1486 | printf("%s on %s type %s (%s)\n", mtpair->mnt_fsname, | ||
1487 | mtpair->mnt_dir, mtpair->mnt_type, | ||
1488 | mtpair->mnt_opts); | ||
1489 | } | ||
1490 | if (ENABLE_FEATURE_CLEAN_UP) endmntent(mountTable); | ||
1491 | return EXIT_SUCCESS; | ||
1492 | } | ||
1493 | } else storage_path = bb_simplify_path(argv[optind]); | ||
1494 | |||
1495 | // When we have two arguments, the second is the directory and we can | ||
1496 | // skip looking at fstab entirely. We can always abspath() the directory | ||
1497 | // argument when we get it. | ||
1498 | |||
1499 | if (optind+2 == argc) { | ||
1500 | mtpair->mnt_fsname = argv[optind]; | ||
1501 | mtpair->mnt_dir = argv[optind+1]; | ||
1502 | mtpair->mnt_type = fstype; | ||
1503 | mtpair->mnt_opts = cmdopts; | ||
1504 | rc = singlemount(mtpair, 0); | ||
1505 | goto clean_up; | ||
1506 | } | ||
1507 | |||
1508 | // If we have a shared subtree flag, don't worry about fstab or mtab. | ||
1509 | i = parse_mount_options(cmdopts,0); | ||
1510 | if (ENABLE_FEATURE_MOUNT_FLAGS && | ||
1511 | (i & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE ))) | ||
1512 | { | ||
1513 | rc = mount("", argv[optind], "", i, ""); | ||
1514 | if (rc) bb_perror_msg_and_die("%s", argv[optind]); | ||
1515 | goto clean_up; | ||
1516 | } | ||
1517 | |||
1518 | // Open either fstab or mtab | ||
1519 | |||
1520 | if (parse_mount_options(cmdopts,0) & MS_REMOUNT) | ||
1521 | fstabname = bb_path_mtab_file; | ||
1522 | else fstabname="/etc/fstab"; | ||
1523 | |||
1524 | if (!(fstab=setmntent(fstabname,"r"))) | ||
1525 | bb_perror_msg_and_die("cannot read %s",fstabname); | ||
1526 | |||
1527 | // Loop through entries until we find what we're looking for. | ||
1528 | |||
1529 | memset(mtpair,0,sizeof(mtpair)); | ||
1530 | for (;;) { | ||
1531 | struct mntent *mtnext = mtpair + (mtcur==mtpair ? 1 : 0); | ||
1532 | |||
1533 | // Get next fstab entry | ||
1534 | |||
1535 | if (!getmntent_r(fstab, mtcur, bb_common_bufsiz1 | ||
1536 | + (mtcur==mtpair ? sizeof(bb_common_bufsiz1)/2 : 0), | ||
1537 | sizeof(bb_common_bufsiz1)/2)) | ||
1538 | { | ||
1539 | // Were we looking for something specific? | ||
1540 | |||
1541 | if (optind != argc) { | ||
1542 | |||
1543 | // If we didn't find anything, complain. | ||
1544 | |||
1545 | if (!mtnext->mnt_fsname) | ||
1546 | bb_error_msg_and_die("can't find %s in %s", | ||
1547 | argv[optind], fstabname); | ||
1548 | |||
1549 | // Mount the last thing we found. | ||
1550 | |||
1551 | mtcur = mtnext; | ||
1552 | mtcur->mnt_opts = xstrdup(mtcur->mnt_opts); | ||
1553 | append_mount_options(&(mtcur->mnt_opts),cmdopts); | ||
1554 | rc = singlemount(mtcur, 0); | ||
1555 | free(mtcur->mnt_opts); | ||
1556 | } | ||
1557 | goto clean_up; | ||
1558 | } | ||
1559 | |||
1560 | /* If we're trying to mount something specific and this isn't it, | ||
1561 | * skip it. Note we must match both the exact text in fstab (ala | ||
1562 | * "proc") or a full path from root */ | ||
1563 | |||
1564 | if (optind != argc) { | ||
1565 | |||
1566 | // Is this what we're looking for? | ||
1567 | |||
1568 | if(strcmp(argv[optind],mtcur->mnt_fsname) && | ||
1569 | strcmp(storage_path,mtcur->mnt_fsname) && | ||
1570 | strcmp(argv[optind],mtcur->mnt_dir) && | ||
1571 | strcmp(storage_path,mtcur->mnt_dir)) continue; | ||
1572 | |||
1573 | // Remember this entry. Something later may have overmounted | ||
1574 | // it, and we want the _last_ match. | ||
1575 | |||
1576 | mtcur = mtnext; | ||
1577 | |||
1578 | // If we're mounting all. | ||
1579 | |||
1580 | } else { | ||
1581 | |||
1582 | // Do we need to match a filesystem type? | ||
1583 | if (fstype && strcmp(mtcur->mnt_type,fstype)) continue; | ||
1584 | |||
1585 | // Skip noauto and swap anyway. | ||
1586 | |||
1587 | if (parse_mount_options(mtcur->mnt_opts,0) | ||
1588 | & (MOUNT_NOAUTO | MOUNT_SWAP)) continue; | ||
1589 | |||
1590 | // Mount this thing. | ||
1591 | |||
1592 | if (singlemount(mtcur, 1)) { | ||
1593 | /* Count number of failed mounts */ | ||
1594 | rc++; | ||
1595 | } | ||
1596 | } | ||
1597 | } | ||
1598 | if (ENABLE_FEATURE_CLEAN_UP) endmntent(fstab); | ||
1599 | |||
1600 | clean_up: | ||
1601 | |||
1602 | if (ENABLE_FEATURE_CLEAN_UP) { | ||
1603 | free(storage_path); | ||
1604 | free(cmdopts); | ||
1605 | } | ||
1606 | |||
1607 | return rc; | ||
1608 | } | ||