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 /util-linux | |
| 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.
Diffstat (limited to 'util-linux')
| -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 | } | ||
