aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2006-09-15 15:12:00 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2006-09-15 15:12:00 +0000
commit30a64cdc95eaa435c00a9aeccdc1b8f9da727875 (patch)
tree1f8fd2a5aa7b863be39d32d371d0f34fbb470b01
parent215c61d3c2830113479ce008d9c1d7e3978ad9c1 (diff)
downloadbusybox-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.c740
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
89static int nfsmount(struct mntent *mp, int vfsflags, char *filteropts); 99
90 100
91/* Append mount options to string */ 101/* Append mount options to string */
92static void append_mount_options(char **oldopts, char *newopts) 102static 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
278static 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
411report_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
425int 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
607clean_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. */
1264int 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
1271static 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
1404report_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
1418int 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
1600clean_up:
1601
1602 if (ENABLE_FEATURE_CLEAN_UP) {
1603 free(storage_path);
1604 free(cmdopts);
1605 }
1606
1607 return rc;
1608}