X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=util-linux%2Fmount.c;h=f665a08758e2377809a04ba726448bba79c777f2;hb=6ced427a6debb71967a8b9cebc12e31c08de0f6a;hp=88e45fc726f5cbb2273ed54dfce9889748817071;hpb=6f65a3a7e88a87bdd0f921884cd05ae593659dda;p=oweals%2Fbusybox.git diff --git a/util-linux/mount.c b/util-linux/mount.c index 88e45fc72..f665a0875 100644 --- a/util-linux/mount.c +++ b/util-linux/mount.c @@ -3,512 +3,544 @@ * Mini mount implementation for busybox * * Copyright (C) 1995, 1996 by Bruce Perens . + * Copyright (C) 1999-2004 by Erik Andersen + * Copyright (C) 2005-2006 by Rob Landley * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * 3/21/1999 Charles P. Wright - * searches through fstab when -a is passed - * will try mounting stuff with all fses when passed -t auto - * - * 1999-04-17 Dave Cinege...Rewrote -t auto. Fixed ro mtab. - * - * 1999-10-07 Erik Andersen , . - * Rewrite of a lot of code. Removed mtab usage (I plan on - * putting it back as a compile-time option some time), - * major adjustments to option parsing, and some serious - * dieting all around. - * - * 1999-11-06 mtab suppport is back - andersee - * - * 2000-01-12 Ben Collins , Borrowed utils-linux's - * mount to add loop support. - * - * 2000-04-30 Dave Cinege - * Rewrote fstab while loop and lower mount section. Can now do - * single mounts from fstab. Can override fstab options for single - * mount. Common mount_one call for single mounts and 'all'. Fixed - * mtab updating and stale entries. Removed 'remount' default. - * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ -#include "busybox.h" -#include -#include -#include -#include -#include -#include -#include -#if defined BB_FEATURE_USE_DEVPS_PATCH -#include /* For Erik's nifty devmtab device driver */ -#endif +/* todo: + * bb_getopt_ulflags(); + */ +/* Design notes: There is no spec for mount. Remind me to write one. -#define MS_MGC_VAL 0xc0ed0000 /* Magic number indicatng "new" flags */ -#define MS_RDONLY 1 /* Mount read-only */ -#define MS_NOSUID 2 /* Ignore suid and sgid bits */ -#define MS_NODEV 4 /* Disallow access to device special files */ -#define MS_NOEXEC 8 /* Disallow program execution */ -#define MS_SYNCHRONOUS 16 /* Writes are synced at once */ -#define MS_REMOUNT 32 /* Alter flags of a mounted FS */ -#define MS_MANDLOCK 64 /* Allow mandatory locks on an FS */ -#define S_QUOTA 128 /* Quota initialized for file/directory/symlink */ -#define S_APPEND 256 /* Append-only file */ -#define S_IMMUTABLE 512 /* Immutable file */ -#define MS_NOATIME 1024 /* Do not update access times. */ -#define MS_NODIRATIME 2048 /* Do not update directory access times */ + mount_main() calls singlemount() which calls mount_it_now(). + mount_main() can loop through /etc/fstab for mount -a + singlemount() can loop through /etc/filesystems for fstype detection. + mount_it_now() does the actual mount. +*/ +#include "busybox.h" +#include -#if defined BB_FEATURE_MOUNT_LOOP -#include -#include -static int use_loop = FALSE; +// These two aren't always defined in old headers +#ifndef MS_BIND +#define MS_BIND 4096 +#endif +#ifndef MS_MOVE +#define MS_MOVE 8192 +#endif +#ifndef MS_SILENT +#define MS_SILENT 32768 #endif -extern int mount (__const char *__special_file, __const char *__dir, - __const char *__fstype, unsigned long int __rwflag, - __const void *__data); -extern int umount (__const char *__special_file); -extern int umount2 (__const char *__special_file, int __flags); - - -extern const char mtab_file[]; /* Defined in utility.c */ +// Not real flags, but we want to be able to check for this. +#define MOUNT_NOAUTO (1<<29) +#define MOUNT_SWAP (1<<30) +/* Standard mount options (from -o options or --options), with corresponding + * flags */ -struct mount_options { +struct { const char *name; - unsigned long and; - unsigned long or; + long flags; +} static const mount_options[] = { + // NOP flags. + + {"loop", 0}, + {"defaults", 0}, + {"quiet", 0}, + + // vfs flags + + {"ro", MS_RDONLY}, + {"rw", ~MS_RDONLY}, + {"nosuid", MS_NOSUID}, + {"suid", ~MS_NOSUID}, + {"dev", ~MS_NODEV}, + {"nodev", MS_NODEV}, + {"exec", ~MS_NOEXEC}, + {"noexec", MS_NOEXEC}, + {"sync", MS_SYNCHRONOUS}, + {"async", ~MS_SYNCHRONOUS}, + {"atime", ~MS_NOATIME}, + {"noatime", MS_NOATIME}, + {"diratime", ~MS_NODIRATIME}, + {"nodiratime", MS_NODIRATIME}, + {"loud", ~MS_SILENT}, + + // action flags + + {"remount", MS_REMOUNT}, + {"bind", MS_BIND}, + {"move", MS_MOVE}, + {"noauto",MOUNT_NOAUTO}, + {"swap",MOUNT_SWAP} }; -static const struct mount_options mount_options[] = { - {"async", ~MS_SYNCHRONOUS, 0}, - {"atime", ~0, ~MS_NOATIME}, - {"defaults", ~0, 0}, - {"dev", ~MS_NODEV, 0}, - {"diratime", ~0, ~MS_NODIRATIME}, - {"exec", ~MS_NOEXEC, 0}, - {"noatime", ~0, MS_NOATIME}, - {"nodev", ~0, MS_NODEV}, - {"nodiratime", ~0, MS_NODIRATIME}, - {"noexec", ~0, MS_NOEXEC}, - {"nosuid", ~0, MS_NOSUID}, - {"remount", ~0, MS_REMOUNT}, - {"ro", ~0, MS_RDONLY}, - {"rw", ~MS_RDONLY, 0}, - {"suid", ~MS_NOSUID, 0}, - {"sync", ~0, MS_SYNCHRONOUS}, - {0, 0, 0} -}; +/* Append mount options to string */ +static void append_mount_options(char **oldopts, char *newopts) +{ + if(*oldopts && **oldopts) { + char *temp=xasprintf("%s,%s",*oldopts,newopts); + free(*oldopts); + *oldopts=temp; + } else { + if (ENABLE_FEATURE_CLEAN_UP) free(*oldopts); + *oldopts = xstrdup(newopts); + } +} -static int -do_mount(char *specialfile, char *dir, char *filesystemtype, - long flags, void *string_flags, int useMtab, int fakeIt, - char *mtab_opts) +/* Use the mount_options list to parse options into flags. + * Return list of unrecognized options in *strflags if strflags!=NULL */ +static int parse_mount_options(char *options, char **unrecognized) { - int status = 0; -#if defined BB_FEATURE_MOUNT_LOOP - char *lofile = NULL; -#endif + int flags = MS_SILENT; - if (fakeIt == FALSE) - { -#if defined BB_FEATURE_MOUNT_LOOP - if (use_loop==TRUE) { - int loro = flags & MS_RDONLY; - char *lofile = specialfile; - - specialfile = find_unused_loop_device(); - if (specialfile == NULL) { - error_msg_and_die("Could not find a spare loop device\n"); - } - if (set_loop(specialfile, lofile, 0, &loro)) { - error_msg_and_die("Could not setup loop device\n"); - } - if (!(flags & MS_RDONLY) && loro) { /* loop is ro, but wanted rw */ - error_msg("WARNING: loop device is read-only\n"); - flags &= ~MS_RDONLY; + // Loop through options + for (;;) { + int i; + char *comma = strchr(options, ','); + + if (comma) *comma = 0; + + // Find this option in mount_options + for (i = 0; i < (sizeof(mount_options) / sizeof(*mount_options)); i++) { + if (!strcasecmp(mount_options[i].name, options)) { + long fl = mount_options[i].flags; + if(fl < 0) flags &= fl; + else flags |= fl; + break; } } -#endif - status = mount(specialfile, dir, filesystemtype, flags, string_flags); - if (errno == EROFS) { - error_msg("%s is write-protected, mounting read-only\n", specialfile); - status = mount(specialfile, dir, filesystemtype, flags |= MS_RDONLY, string_flags); + // If unrecognized not NULL, append unrecognized mount options */ + if (unrecognized + && i == (sizeof(mount_options) / sizeof(*mount_options))) + { + // Add it to strflags, to pass on to kernel + i = *unrecognized ? strlen(*unrecognized) : 0; + *unrecognized = xrealloc(*unrecognized, i+strlen(options)+2); + + // Comma separated if it's not the first one + if (i) (*unrecognized)[i++] = ','; + strcpy((*unrecognized)+i, options); } + + // Advance to next option, or finish + if(comma) { + *comma = ','; + options = ++comma; + } else break; } + return flags; +} + +// Return a list of all block device backed filesystems + +static llist_t *get_block_backed_filesystems(void) +{ + char *fs, *buf, + *filesystems[] = {"/etc/filesystems", "/proc/filesystems", 0}; + llist_t *list = 0; + int i; + FILE *f; - /* If the mount was sucessful, do anything needed, then return TRUE */ - if (status == 0 || fakeIt==TRUE) { + for(i = 0; filesystems[i]; i++) { + if(!(f = fopen(filesystems[i], "r"))) continue; -#if defined BB_MTAB - if (useMtab == TRUE) { - erase_mtab(specialfile); // Clean any stale entries - write_mtab(specialfile, dir, filesystemtype, flags, mtab_opts); + for(fs = buf = 0; (fs = buf = bb_get_chomped_line_from_file(f)); + free(buf)) + { + if(!strncmp(buf,"nodev",5) && isspace(buf[5])) continue; + + while(isspace(*fs)) fs++; + if(*fs=='#' || *fs=='*') continue; + if(!*fs) continue; + + llist_add_to_end(&list,xstrdup(fs)); } -#endif - return (TRUE); + if (ENABLE_FEATURE_CLEAN_UP) fclose(f); } - /* Bummer. mount failed. Clean up */ -#if defined BB_FEATURE_MOUNT_LOOP - if (lofile != NULL) { - del_loop(specialfile); - } -#endif + return list; +} - if (errno == EPERM) { - error_msg_and_die("permission denied. Are you root?\n"); - } +llist_t *fslist = 0; - return (FALSE); +#if ENABLE_FEATURE_CLEAN_UP +static void delete_block_backed_filesystems(void) +{ + llist_free(fslist, free); } +#else +void delete_block_backed_filesystems(void); +#endif +#if ENABLE_FEATURE_MTAB_SUPPORT +static int useMtab; +static int fakeIt; +#else +#define useMtab 0 +#define fakeIt 0 +#endif +// Perform actual mount of specific filesystem at specific location. -/* Seperate standard mount options from the nonstandard string options */ -static void -parse_mount_options(char *options, int *flags, char *strflags) +static int mount_it_now(struct mntent *mp, int vfsflags, char *filteropts) { - while (options) { - int gotone = FALSE; - char *comma = strchr(options, ','); - const struct mount_options *f = mount_options; - - if (comma) - *comma = '\0'; + int rc; - while (f->name != 0) { - if (strcasecmp(f->name, options) == 0) { + if (fakeIt) { return 0; } - *flags &= f->and; - *flags |= f->or; - gotone = TRUE; - break; - } - f++; - } -#if defined BB_FEATURE_MOUNT_LOOP - if (gotone == FALSE && !strcasecmp("loop", options)) { /* loop device support */ - use_loop = TRUE; - gotone = TRUE; - } -#endif - if (*strflags && strflags != '\0' && gotone == FALSE) { - char *temp = strflags; + // Mount, with fallback to read-only if necessary. - temp += strlen(strflags); - *temp++ = ','; - *temp++ = '\0'; - } - if (gotone == FALSE) - strcat(strflags, options); - if (comma) { - *comma = ','; - options = ++comma; - } else { + for(;;) { + rc = mount(mp->mnt_fsname, mp->mnt_dir, mp->mnt_type, + vfsflags, filteropts); + if(!rc || (vfsflags&MS_RDONLY) || (errno!=EACCES && errno!=EROFS)) break; - } + bb_error_msg("%s is write-protected, mounting read-only", + mp->mnt_fsname); + vfsflags |= MS_RDONLY; + } + + // Abort entirely if permission denied. + + if (rc && errno == EPERM) + bb_error_msg_and_die(bb_msg_perm_denied_are_you_root); + + /* If the mount was successful, and we're maintaining an old-style + * mtab file by hand, add the new entry to it now. */ + + if(ENABLE_FEATURE_MTAB_SUPPORT && useMtab && !rc) { + FILE *mountTable = setmntent(bb_path_mtab_file, "a+"); + int i; + + if(!mountTable) + bb_error_msg("No %s\n",bb_path_mtab_file); + + // Add vfs string flags + + for(i=0; mount_options[i].flags != MS_REMOUNT; i++) + if (mount_options[i].flags > 0) + append_mount_options(&(mp->mnt_opts), +// Shut up about the darn const. It's not important. I don't care. + (char *)mount_options[i].name); + + // Remove trailing / (if any) from directory we mounted on + + i = strlen(mp->mnt_dir); + if(i>1 && mp->mnt_dir[i-1] == '/') mp->mnt_dir[i-1] = 0; + + // Write and close. + + if(!mp->mnt_type || !*mp->mnt_type) mp->mnt_type="--bind"; + addmntent(mountTable, mp); + endmntent(mountTable); + if (ENABLE_FEATURE_CLEAN_UP) + if(strcmp(mp->mnt_type,"--bind")) mp->mnt_type = 0; } + + return rc; } -int -mount_one(char *blockDevice, char *directory, char *filesystemType, - unsigned long flags, char *string_flags, int useMtab, int fakeIt, - char *mtab_opts, int whineOnErrors) + +// Mount one directory. Handles NFS, loopback, autobind, and filesystem type +// detection. Returns 0 for success, nonzero for failure. + +static int singlemount(struct mntent *mp, int ignore_busy) { - int status = 0; + int rc = -1, vfsflags; + char *loopFile = 0, *filteropts = 0; + llist_t *fl = 0; + struct stat st; -#if defined BB_FEATURE_USE_PROCFS - char buf[255]; - if (strcmp(filesystemType, "auto") == 0) { - FILE *f = fopen("/proc/filesystems", "r"); + vfsflags = parse_mount_options(mp->mnt_opts, &filteropts); - if (f == NULL) - return (FALSE); + // Treat fstype "auto" as unspecified. - while (fgets(buf, sizeof(buf), f) != NULL) { - filesystemType = buf; - if (*filesystemType == '\t') { // Not a nodev filesystem + if (mp->mnt_type && !strcmp(mp->mnt_type,"auto")) mp->mnt_type = 0; - // Add NULL termination to each line - while (*filesystemType && *filesystemType != '\n') - filesystemType++; - *filesystemType = '\0'; + // Might this be an NFS filesystem? - filesystemType = buf; - filesystemType++; // hop past tab + if (ENABLE_FEATURE_MOUNT_NFS && + (!mp->mnt_type || !strcmp(mp->mnt_type,"nfs")) && + strchr(mp->mnt_fsname, ':') != NULL) + { + if (nfsmount(mp->mnt_fsname, mp->mnt_dir, &vfsflags, &filteropts, 1)) { + bb_perror_msg("nfsmount failed"); + goto report_error; + } else { + // Strangely enough, nfsmount() doesn't actually mount() anything. + mp->mnt_type = "nfs"; + rc = mount_it_now(mp, vfsflags, filteropts); + if (ENABLE_FEATURE_CLEAN_UP) free(filteropts); + + goto report_error; + } + } - status = do_mount(blockDevice, directory, filesystemType, - flags | MS_MGC_VAL, string_flags, - useMtab, fakeIt, mtab_opts); - if (status == TRUE) + // Look at the file. (Not found isn't a failure for remount, or for + // a synthetic filesystem like proc or sysfs.) + + if (lstat(mp->mnt_fsname, &st)); + else if (!(vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))) { + // Do we need to allocate a loopback device for it? + + if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) { + loopFile = bb_simplify_path(mp->mnt_fsname); + mp->mnt_fsname = 0; + switch(set_loop(&(mp->mnt_fsname), loopFile, 0)) { + case 0: + case 1: break; + default: + bb_error_msg( errno == EPERM || errno == EACCES + ? bb_msg_perm_denied_are_you_root + : "Couldn't setup loop device"); + return errno; } + + // Autodetect bind mounts + + } else if (S_ISDIR(st.st_mode) && !mp->mnt_type) vfsflags |= MS_BIND; + } + + /* If we know the fstype (or don't need to), jump straight + * to the actual mount. */ + + if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))) + rc = mount_it_now(mp, vfsflags, filteropts); + + // Loop through filesystem types until mount succeeds or we run out + + else { + + /* Initialize list of block backed filesystems. This has to be + * done here so that during "mount -a", mounts after /proc shows up + * can autodetect. */ + + if (!fslist) { + fslist = get_block_backed_filesystems(); + if (ENABLE_FEATURE_CLEAN_UP && fslist) + atexit(delete_block_backed_filesystems); } - fclose(f); - } else -#endif -#if defined BB_FEATURE_USE_DEVPS_PATCH - if (strcmp(filesystemType, "auto") == 0) { - int fd, i, numfilesystems; - char device[] = "/dev/mtab"; - struct k_fstype *fslist; - - /* open device */ - fd = open(device, O_RDONLY); - if (fd < 0) - perror_msg_and_die("open failed for `%s'", device); - - /* How many filesystems? We need to know to allocate enough space */ - numfilesystems = ioctl (fd, DEVMTAB_COUNT_FILESYSTEMS); - if (numfilesystems<0) - perror_msg_and_die("\nDEVMTAB_COUNT_FILESYSTEMS"); - fslist = (struct k_fstype *) xcalloc ( numfilesystems, sizeof(struct k_fstype)); - - /* Grab the list of available filesystems */ - status = ioctl (fd, DEVMTAB_GET_FILESYSTEMS, fslist); - if (status<0) - perror_msg_and_die("\nDEVMTAB_GET_FILESYSTEMS"); - - /* Walk the list trying to mount filesystems - * that do not claim to be nodev filesystems */ - for( i = 0 ; i < numfilesystems ; i++) { - if (fslist[i].mnt_nodev) - continue; - status = do_mount(blockDevice, directory, fslist[i].mnt_type, - flags | MS_MGC_VAL, string_flags, - useMtab, fakeIt, mtab_opts); - if (status == TRUE) - break; + + for (fl = fslist; fl; fl = fl->link) { + mp->mnt_type = fl->data; + + if (!(rc = mount_it_now(mp,vfsflags, filteropts))) break; + + mp->mnt_type = 0; } - free( fslist); - close(fd); - } else -#endif - { - status = do_mount(blockDevice, directory, filesystemType, - flags | MS_MGC_VAL, string_flags, useMtab, - fakeIt, mtab_opts); } - if (status == FALSE) { - if (whineOnErrors == TRUE) { - perror_msg("Mounting %s on %s failed", blockDevice, directory); + if (ENABLE_FEATURE_CLEAN_UP) free(filteropts); + + // If mount failed, clean up loop file (if any). + + if (ENABLE_FEATURE_MOUNT_LOOP && rc && loopFile) { + del_loop(mp->mnt_fsname); + if (ENABLE_FEATURE_CLEAN_UP) { + free(loopFile); + free(mp->mnt_fsname); } - return (FALSE); } - return (TRUE); +report_error: + if (rc && errno == EBUSY && ignore_busy) rc = 0; + if (rc < 0) + bb_perror_msg("Mounting %s on %s failed", mp->mnt_fsname, mp->mnt_dir); + + return rc; } -extern int mount_main(int argc, char **argv) +// Parse options, if necessary parse fstab/mtab, and call singlemount for +// each directory to be mounted. + +int mount_main(int argc, char **argv) { - char string_flags_buf[1024] = ""; - char *string_flags = string_flags_buf; - char *extra_opts = string_flags_buf; - int flags = 0; - char *filesystemType = "auto"; - char *device = NULL; - char *directory = NULL; - int all = FALSE; - int fakeIt = FALSE; - int useMtab = TRUE; - int i; - int rc = EXIT_FAILURE; - int fstabmount = FALSE; - -#if defined BB_FEATURE_USE_DEVPS_PATCH - if (argc == 1) { - int fd, i, numfilesystems; - char device[] = "/dev/mtab"; - struct k_mntent *mntentlist; - - /* open device */ - fd = open(device, O_RDONLY); - if (fd < 0) - perror_msg_and_die("open failed for `%s'", device); - - /* How many mounted filesystems? We need to know to - * allocate enough space for later... */ - numfilesystems = ioctl (fd, DEVMTAB_COUNT_MOUNTS); - if (numfilesystems<0) - perror_msg_and_die( "\nDEVMTAB_COUNT_MOUNTS"); - mntentlist = (struct k_mntent *) xcalloc ( numfilesystems, sizeof(struct k_mntent)); - - /* Grab the list of mounted filesystems */ - if (ioctl (fd, DEVMTAB_GET_MOUNTS, mntentlist)<0) - perror_msg_and_die( "\nDEVMTAB_GET_MOUNTS"); - - for( i = 0 ; i < numfilesystems ; i++) { - printf( "%s %s %s %s %d %d\n", mntentlist[i].mnt_fsname, - mntentlist[i].mnt_dir, mntentlist[i].mnt_type, - mntentlist[i].mnt_opts, mntentlist[i].mnt_freq, - mntentlist[i].mnt_passno); - } -#ifdef BB_FEATURE_CLEAN_UP - /* Don't bother to close files or free memory. Exit - * does that automagically, so we can save a few bytes */ - free( mntentlist); - close(fd); -#endif - return EXIT_SUCCESS; + char *cmdopts = xstrdup(""), *fstabname, *fstype=0, *storage_path=0; + FILE *fstab; + int i, opt, all = FALSE, rc = 0; + struct mntent mtpair[2], *mtcur = mtpair; + + /* parse long options, like --bind and --move. Note that -o option + * and --option are synonymous. Yes, this means --remount,rw works. */ + + for (i = opt = 0; i < argc; i++) { + if (argv[i][0] == '-' && argv[i][1] == '-') { + append_mount_options(&cmdopts,argv[i]+2); + } else argv[opt++] = argv[i]; } -#else - if (argc == 1) { - FILE *mountTable = setmntent(mtab_file, "r"); - - if (mountTable) { - struct mntent *m; - - while ((m = getmntent(mountTable)) != 0) { - char *blockDevice = m->mnt_fsname; - if (strcmp(blockDevice, "/dev/root") == 0) { - find_real_root_device_name( blockDevice); - } - printf("%s on %s type %s (%s)\n", blockDevice, m->mnt_dir, - m->mnt_type, m->mnt_opts); - } - endmntent(mountTable); - } else { - perror_msg_and_die("%s", mtab_file); + argc = opt; + + // Parse remaining options + + while ((opt = getopt(argc, argv, "o:t:rwavnf")) > 0) { + switch (opt) { + case 'o': + append_mount_options(&cmdopts, optarg); + break; + case 't': + fstype = optarg; + break; + case 'r': + append_mount_options(&cmdopts, "ro"); + break; + case 'w': + append_mount_options(&cmdopts, "rw"); + break; + case 'a': + all = TRUE; + break; + case 'n': + USE_FEATURE_MTAB_SUPPORT(useMtab = FALSE;) + break; + case 'f': + USE_FEATURE_MTAB_SUPPORT(fakeIt = FALSE;) + break; + case 'v': + break; // ignore -v + default: + bb_show_usage(); } - return EXIT_SUCCESS; } -#endif - /* Parse options */ - i = --argc; - argv++; - while (i > 0 && **argv) { - if (**argv == '-') { - char *opt = *argv; - - while (i > 0 && *++opt) - switch (*opt) { - case 'o': - if (--i == 0) { - goto goodbye; - } - parse_mount_options(*(++argv), &flags, string_flags); - break; - case 'r': - flags |= MS_RDONLY; - break; - case 't': - if (--i == 0) { - goto goodbye; - } - filesystemType = *(++argv); - break; - case 'w': - flags &= ~MS_RDONLY; - break; - case 'a': - all = TRUE; - break; - case 'f': - fakeIt = TRUE; - break; -#ifdef BB_MTAB - case 'n': - useMtab = FALSE; - break; -#endif - case 'v': - break; /* ignore -v */ - case 'h': - case '-': - goto goodbye; - } - } else { - if (device == NULL) - device = *argv; - else if (directory == NULL) - directory = *argv; - else { - goto goodbye; + // Three or more non-option arguments? Die with a usage message. + + if (optind-argc>2) bb_show_usage(); + + // If we have no arguments, show currently mounted filesystems + + if (optind == argc) { + if (!all) { + FILE *mountTable = setmntent(bb_path_mtab_file, "r"); + + if(!mountTable) bb_error_msg_and_die("No %s",bb_path_mtab_file); + + while (getmntent_r(mountTable,mtpair,bb_common_bufsiz1, + sizeof(bb_common_bufsiz1))) + { + // Don't show rootfs. + if (!strcmp(mtpair->mnt_fsname, "rootfs")) continue; + + if (!fstype || !strcmp(mtpair->mnt_type, fstype)) + printf("%s on %s type %s (%s)\n", mtpair->mnt_fsname, + mtpair->mnt_dir, mtpair->mnt_type, + mtpair->mnt_opts); } + if (ENABLE_FEATURE_CLEAN_UP) endmntent(mountTable); + return EXIT_SUCCESS; } - i--; - argv++; } - if (all == TRUE || directory == NULL) { - struct mntent *m; - FILE *f = setmntent("/etc/fstab", "r"); - fstabmount = TRUE; + // When we have two arguments, the second is the directory and we can + // skip looking at fstab entirely. We can always abspath() the directory + // argument when we get it. + + if (optind+2 == argc) { + mtpair->mnt_fsname = argv[optind]; + mtpair->mnt_dir = argv[optind+1]; + mtpair->mnt_type = fstype; + mtpair->mnt_opts = cmdopts; + rc = singlemount(mtpair, 0); + goto clean_up; + } - if (f == NULL) - perror_msg_and_die( "\nCannot read /etc/fstab"); + // If we have at least one argument, it's the storage location - while ((m = getmntent(f)) != NULL) { - if (all == FALSE && directory == NULL && ( - (strcmp(device, m->mnt_fsname) != 0) && - (strcmp(device, m->mnt_dir) != 0) ) ) { - continue; - } - - if (all == TRUE && ( // If we're mounting 'all' - (strstr(m->mnt_opts, "noauto")) || // and the file system isn't noauto, - (strstr(m->mnt_type, "swap")) || // and isn't swap or nfs, then mount it - (strstr(m->mnt_type, "nfs")) ) ) { - continue; - } - - if (all == TRUE || flags == 0) { // Allow single mount to override fstab flags - flags = 0; - *string_flags = '\0'; - parse_mount_options(m->mnt_opts, &flags, string_flags); + if (optind < argc) storage_path = bb_simplify_path(argv[optind]); + + // Open either fstab or mtab + + if (parse_mount_options(cmdopts,0) & MS_REMOUNT) + fstabname = (char *)bb_path_mtab_file; // Again with the evil const. + else fstabname="/etc/fstab"; + + if (!(fstab=setmntent(fstabname,"r"))) + bb_perror_msg_and_die("Cannot read %s",fstabname); + + // Loop through entries until we find what we're looking for. + + memset(mtpair,0,sizeof(mtpair)); + for (;;) { + struct mntent *mtnext = mtpair + (mtcur==mtpair ? 1 : 0); + + // Get next fstab entry + + if (!getmntent_r(fstab, mtcur, bb_common_bufsiz1 + + (mtcur==mtpair ? sizeof(bb_common_bufsiz1)/2 : 0), + sizeof(bb_common_bufsiz1)/2)) + { + // Were we looking for something specific? + + if (optind != argc) { + + // If we didn't find anything, complain. + + if (!mtnext->mnt_fsname) + bb_error_msg_and_die("Can't find %s in %s", + argv[optind], fstabname); + + // Mount the last thing we found. + + mtcur = mtnext; + mtcur->mnt_opts = xstrdup(mtcur->mnt_opts); + append_mount_options(&(mtcur->mnt_opts),cmdopts); + rc = singlemount(mtcur, 0); + free(mtcur->mnt_opts); } - - device = strdup(m->mnt_fsname); - directory = strdup(m->mnt_dir); - filesystemType = strdup(m->mnt_type); -singlemount: - rc = EXIT_SUCCESS; -#ifdef BB_NFSMOUNT - if (strchr(device, ':') != NULL) - filesystemType = "nfs"; - if (strcmp(filesystemType, "nfs") == 0) { - rc = nfsmount (device, directory, &flags, - &extra_opts, &string_flags, 1); - if ( rc != 0) { - perror_msg_and_die("nfsmount failed"); - rc = EXIT_FAILURE; - } + goto clean_up; + } + + /* If we're trying to mount something specific and this isn't it, + * skip it. Note we must match both the exact text in fstab (ala + * "proc") or a full path from root */ + + if (optind != argc) { + + // Is this what we're looking for? + + if(strcmp(argv[optind],mtcur->mnt_fsname) && + strcmp(storage_path,mtcur->mnt_fsname) && + strcmp(argv[optind],mtcur->mnt_dir) && + strcmp(storage_path,mtcur->mnt_dir)) continue; + + // Remember this entry. Something later may have overmounted + // it, and we want the _last_ match. + + mtcur = mtnext; + + // If we're mounting all. + + } else { + + // Do we need to match a filesystem type? + if (fstype && strcmp(mtcur->mnt_type,fstype)) continue; + + // Skip noauto and swap anyway. + + if (parse_mount_options(mtcur->mnt_opts,0) + & (MOUNT_NOAUTO | MOUNT_SWAP)) continue; + + // Mount this thing. + + if (singlemount(mtcur, 1)) { + /* Count number of failed mounts */ + rc++; } -#endif - if (!mount_one(device, directory, filesystemType, flags, - string_flags, useMtab, fakeIt, extra_opts, TRUE)) - rc = EXIT_FAILURE; - - if (all == FALSE) - break; } - if (fstabmount == TRUE) - endmntent(f); - - if (all == FALSE && fstabmount == TRUE && directory == NULL) - fprintf(stderr, "Can't find %s in /etc/fstab\n", device); - - exit(rc); } - - goto singlemount; - -goodbye: - usage(mount_usage); + if (ENABLE_FEATURE_CLEAN_UP) endmntent(fstab); + +clean_up: + + if (ENABLE_FEATURE_CLEAN_UP) { + free(storage_path); + free(cmdopts); + } + + return rc; }