Major rewrite of mount, umount, losetup. Untangled lots of code, shrunk

things down a bit, fixed a number of funky corner cases, added support for
several new features (things like mount --move, mount --bind, lazy unounts,
automatic detection of loop mounts, and so on).  Probably broke several
other things, but it's fixable.  (Bang on it, tell me what doesn't work for
you...)

Note: you no longer need to say "-o loop".  It does that for you when
necessary.

Still need to add "user mount" support, which involves making mount suid.  Not
too hard to do under the new infrastructure, just haven't done it yet...

The previous code had the following notes, that belong in the version
control comments:

- * 3/21/1999   Charles P. Wright <cpwright@cpwright.com>
- *             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 <andersen@codepoet.org>.
- *              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 support is back - andersee
- *
- * 2000-01-12   Ben Collins <bcollins@debian.org>, Borrowed utils-linux's
- *              mount to add loop support.
- *
- * 2000-04-30  Dave Cinege <dcinege@psychosis.com>
- *             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.
- *
This commit is contained in:
Rob Landley
2005-08-10 20:35:54 +00:00
parent 0b62158475
commit 6a6798b8e4
12 changed files with 555 additions and 934 deletions

View File

@@ -4,6 +4,7 @@
*
* Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
* Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
* Copyright (C) 2005 by Rob Landley <rob@landley.net>
*
* 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
@@ -19,29 +20,6 @@
* 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 <cpwright@cpwright.com>
* 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 <andersen@codepoet.org>.
* 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 support is back - andersee
*
* 2000-01-12 Ben Collins <bcollins@debian.org>, Borrowed utils-linux's
* mount to add loop support.
*
* 2000-04-30 Dave Cinege <dcinege@psychosis.com>
* 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.
*
*/
#include <limits.h>
@@ -52,351 +30,131 @@
#include <stdio.h>
#include <mntent.h>
#include <ctype.h>
#include <sys/mount.h>
#include <fcntl.h> // for CONFIG_FEATURE_MOUNT_LOOP
#include <sys/ioctl.h> // for CONFIG_FEATURE_MOUNT_LOOP
#include "busybox.h"
#ifdef CONFIG_NFSMOUNT
#if defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__)
/* This is just a warning of a common mistake. Possibly this should be a
* uclibc faq entry rather than in busybox... */
#if ENABLE_NFSMOUNT && defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__)
#error "You need to build uClibc with UCLIBC_HAS_RPC for busybox mount with NFS support to compile."
#endif
// 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
enum {
MS_MGC_VAL = 0xc0ed0000, /* Magic number indicatng "new" flags */
MS_RDONLY = 1, /* Mount read-only */
MS_NOSUID = 2, /* Ignore suid and sgid bits */
MS_NODEV = 4, /* Disallow access to device special files */
MS_NOEXEC = 8, /* Disallow program execution */
MS_SYNCHRONOUS = 16, /* Writes are synced at once */
MS_REMOUNT = 32, /* Alter flags of a mounted FS */
MS_MANDLOCK = 64, /* Allow mandatory locks on an FS */
S_QUOTA = 128, /* Quota initialized for file/directory/symlink */
S_APPEND = 256, /* Append-only file */
S_IMMUTABLE = 512, /* Immutable file */
MS_NOATIME = 1024, /* Do not update access times. */
MS_NODIRATIME = 2048, /* Do not update directory access times */
MS_BIND = 4096, /* Use the new linux 2.4.x "mount --bind" feature */
MS_MOVE = 8192, /* Use the new linux 2.4.x "mount --move" feature */
};
/* Consume standard mount options (from -o options or --options).
* Set appropriate flags and collect unrecognized ones as a comma separated
* string to pass to kernel */
#if defined CONFIG_FEATURE_MOUNT_LOOP
#include <fcntl.h>
#include <sys/ioctl.h>
static int use_loop = FALSE;
#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 int sysfs(int option, unsigned int fs_index, char *buf);
struct mount_options {
struct {
const char *name;
unsigned long and;
unsigned long or;
long flags;
} static const mount_options[] = {
{"loop", 0},
{"defaults", 0},
{"noauto", 0},
{"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},
{"remount", MS_REMOUNT},
{"atime", MS_NOATIME},
{"noatime", MS_NOATIME},
{"diratime", MS_NODIRATIME},
{"nodiratime", MS_NODIRATIME},
{"bind", MS_BIND},
{"move", MS_MOVE}
};
static const struct mount_options mount_options[] = {
{"async", ~MS_SYNCHRONOUS, 0},
{"atime", ~0, ~MS_NOATIME},
{"defaults", ~0, 0},
{"noauto", ~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},
{"bind", ~0, MS_BIND},
{"move", ~0, MS_MOVE},
{0, 0, 0}
};
static int
do_mount(char *specialfile, char *dir, char *filesystemtype, long flags,
void *string_flags, int useMtab, int fakeIt, char *mtab_opts,
int mount_all)
{
int status = 0;
#if defined CONFIG_FEATURE_MOUNT_LOOP
char *lofile = NULL;
#endif
if (!fakeIt) {
#if defined CONFIG_FEATURE_MOUNT_LOOP
if (use_loop == TRUE) {
int loro = flags & MS_RDONLY;
lofile = specialfile;
specialfile = find_unused_loop_device();
if (specialfile == NULL) {
bb_error_msg_and_die("Could not find a spare loop device");
}
if (set_loop(specialfile, lofile, 0, &loro)) {
bb_error_msg_and_die("Could not setup loop device");
}
if (!(flags & MS_RDONLY) && loro) { /* loop is ro, but wanted rw */
bb_error_msg("WARNING: loop device is read-only");
flags |= MS_RDONLY;
}
}
#endif
status = mount(specialfile, dir, filesystemtype, flags, string_flags);
if (status < 0 && errno == EROFS) {
bb_error_msg("%s is write-protected, mounting read-only",
specialfile);
status = mount(specialfile, dir, filesystemtype, flags |=
MS_RDONLY, string_flags);
}
/* Don't whine about already mounted filesystems when mounting all. */
if (status < 0 && errno == EBUSY && mount_all) {
return TRUE;
}
}
/* If the mount was sucessful, do anything needed, then return TRUE */
if (status == 0 || fakeIt == TRUE) {
#if defined CONFIG_FEATURE_MTAB_SUPPORT
if (useMtab) {
erase_mtab(specialfile); /* Clean any stale entries */
write_mtab(specialfile, dir, filesystemtype, flags, mtab_opts);
}
#endif
return (TRUE);
}
/* Bummer. mount failed. Clean up */
#if defined CONFIG_FEATURE_MOUNT_LOOP
if (lofile != NULL) {
del_loop(specialfile);
}
#endif
if (errno == EPERM) {
bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
}
return (FALSE);
}
static void paste_str(char **s1, const char *s2)
{
*s1 = xrealloc(*s1, strlen(*s1) + strlen(s2) + 1);
strcat(*s1, s2);
}
/* Seperate standard mount options from the nonstandard string options */
/* Uses the mount_options list above */
static void parse_mount_options(char *options, int *flags, char **strflags)
{
while (options) {
int gotone = FALSE;
// Loop through options
for(;;) {
int i;
char *comma = strchr(options, ',');
const struct mount_options *f = mount_options;
if (comma) {
*comma = '\0';
}
if(comma) *comma = 0;
while (f->name != 0) {
if (strcasecmp(f->name, options) == 0) {
*flags &= f->and;
*flags |= f->or;
gotone = TRUE;
// 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;
}
f++;
}
#if defined CONFIG_FEATURE_MOUNT_LOOP
if (!strcasecmp("loop", options)) { /* loop device support */
use_loop = TRUE;
gotone = TRUE;
// Unrecognized mount option?
if(i == sizeof(mount_options)) {
// Add it to strflags, to pass on to kernel
i = *strflags ? strlen(*strflags) : 0;
*strflags = xrealloc(*strflags, i+strlen(options)+2);
// Comma separated if it's not the first one
if(i) (*strflags)[i] = ',';
strcpy((*strflags)+i, options);
}
#endif
if (!gotone) {
if (**strflags) {
/* have previous parsed options */
paste_str(strflags, ",");
}
paste_str(strflags, options);
}
if (comma) {
// Advance to next option, or finish
if(comma) {
*comma = ',';
options = ++comma;
} else {
break;
}
} else break;
}
}
static int mount_one(char *blockDevice, char *directory, char *filesystemType,
unsigned long flags, char *string_flags, int useMtab,
int fakeIt, char *mtab_opts, int whineOnErrors,
int mount_all)
{
int status = 0;
if (strcmp(filesystemType, "auto") == 0) {
char buf[255];
FILE *f;
int read_proc = 0;
f = fopen("/etc/filesystems", "r");
if (f) {
while (fgets(buf, sizeof(buf), f)) {
if (*buf == '*') {
read_proc = 1;
} else if (*buf == '#') {
continue;
} else {
filesystemType = buf;
/* Add NULL termination to each line */
while (*filesystemType && !isspace(*filesystemType)) {
filesystemType++;
}
*filesystemType = '\0';
filesystemType = buf;
if (bb_strlen(filesystemType)) {
status = do_mount(blockDevice, directory, filesystemType,
flags | MS_MGC_VAL, string_flags,
useMtab, fakeIt, mtab_opts, mount_all);
if (status) {
break;
}
}
}
}
fclose(f);
} else {
read_proc = 1;
}
if (read_proc && !status) {
f = bb_xfopen("/proc/filesystems", "r");
while (fgets(buf, sizeof(buf), f) != NULL) {
filesystemType = buf;
if (*filesystemType == '\t') { /* Not a nodev filesystem */
/* Add NULL termination to each line */
while (*filesystemType && *filesystemType != '\n') {
filesystemType++;
}
*filesystemType = '\0';
filesystemType = buf;
filesystemType++; /* hop past tab */
status = do_mount(blockDevice, directory, filesystemType,
flags | MS_MGC_VAL, string_flags, useMtab,
fakeIt, mtab_opts, mount_all);
if (status) {
break;
}
}
}
fclose(f);
}
} else {
status = do_mount(blockDevice, directory, filesystemType,
flags | MS_MGC_VAL, string_flags, useMtab, fakeIt,
mtab_opts, mount_all);
}
if (!status) {
if (whineOnErrors) {
bb_perror_msg("Mounting %s on %s failed", blockDevice, directory);
}
return (FALSE);
}
return (TRUE);
}
static void show_mounts(char *onlytype)
{
FILE *mountTable = setmntent(bb_path_mtab_file, "r");
if (mountTable) {
struct mntent *m;
while ((m = getmntent(mountTable)) != 0) {
char *blockDevice = m->mnt_fsname;
if (strcmp(blockDevice, "rootfs") == 0) {
continue;
} else if (strcmp(blockDevice, "/dev/root") == 0) {
blockDevice = find_real_root_device_name();
}
if (!onlytype || (strcmp(m->mnt_type, onlytype) == 0)) {
printf("%s on %s type %s (%s)\n", blockDevice, m->mnt_dir,
m->mnt_type, m->mnt_opts);
}
#ifdef CONFIG_FEATURE_CLEAN_UP
if (blockDevice != m->mnt_fsname) {
free(blockDevice);
}
#endif
}
endmntent(mountTable);
} else {
bb_perror_msg_and_die(bb_path_mtab_file);
}
exit(EXIT_SUCCESS);
}
/* This does the work */
extern int mount_main(int argc, char **argv)
{
char *string_flags = 0, *fsType = 0, *blockDevice = 0, *directory = 0,
*loopFile = 0, *buf = 0,
*files[] = {"/etc/filesystems", "/proc/filesystems", 0};
int i, opt, all = FALSE, fakeIt = FALSE, allowWrite = FALSE,
rc = EXIT_FAILURE, useMtab = ENABLE_FEATURE_MTAB_SUPPORT;
int flags=0xc0ed0000; // Needed for linux 2.2, ignored by 2.4 and 2.6.
FILE *file = 0,*f = 0;
char path[PATH_MAX*2];
struct mntent m;
struct stat statbuf;
char *string_flags = bb_xstrdup("");
char *extra_opts;
int flags = 0;
char *filesystemType = "auto";
int got_filesystemType = 0;
char *device = xmalloc(PATH_MAX);
char *directory = xmalloc(PATH_MAX);
struct mntent *m = NULL;
int all = FALSE;
int fakeIt = FALSE;
int useMtab = TRUE;
int rc = EXIT_FAILURE;
FILE *f = 0;
int opt;
/* Parse options */
while ((opt = getopt(argc, argv, "o:rt:wafnv")) > 0) {
/* 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] == '-')
parse_mount_options(argv[i]+2, &flags, &string_flags);
else argv[opt++] = argv[i];
}
argc = opt;
// Parse remaining options
while((opt = getopt(argc, argv, "o:t:rwafnv")) > 0) {
switch (opt) {
case 'o':
parse_mount_options(optarg, &flags, &string_flags);
break;
case 't':
fsType = optarg;
break;
case 'r':
flags |= MS_RDONLY;
break;
case 't':
filesystemType = optarg;
got_filesystemType = 1;
break;
case 'w':
flags &= ~MS_RDONLY;
allowWrite=TRUE;
break;
case 'a':
all = TRUE;
@@ -405,93 +163,238 @@ extern int mount_main(int argc, char **argv)
fakeIt = TRUE;
break;
case 'n':
#ifdef CONFIG_FEATURE_MTAB_SUPPORT
useMtab = FALSE;
#endif
break;
case 'v':
break; /* ignore -v */
break; // ignore -v
default:
bb_show_usage();
}
}
if (!all && (optind == argc)) {
show_mounts(got_filesystemType ? filesystemType : NULL);
// If we have no arguments, show currently mounted filesystems
if(!all && (optind == argc)) {
FILE *mountTable = setmntent(bb_path_mtab_file, "r");
if(!mountTable) bb_perror_msg_and_die(bb_path_mtab_file);
while (getmntent_r(mountTable,&m,path,sizeof(path))) {
blockDevice = m.mnt_fsname;
// Clean up display a little bit regarding root devie
if(!strcmp(blockDevice, "rootfs")) continue;
if(!strcmp(blockDevice, "/dev/root"))
blockDevice = find_block_device("/");
if(!fsType || !strcmp(m.mnt_type, fsType))
printf("%s on %s type %s (%s)\n", blockDevice, m.mnt_dir,
m.mnt_type, m.mnt_opts);
if(ENABLE_FEATURE_CLEAN_UP && blockDevice != m.mnt_fsname)
free(blockDevice);
}
endmntent(mountTable);
return EXIT_SUCCESS;
}
if (optind < argc) {
/* if device is a filename get its real path */
if (stat(argv[optind], &statbuf) == 0) {
char *tmp = bb_simplify_path(argv[optind]);
/* The next argument is what to mount. if there's an argument after that
* it's where to mount it. If we're not mounting all, and we have both
* of these arguments, jump straight to the actual mount. */
safe_strncpy(device, tmp, PATH_MAX);
statbuf.st_mode=0;
if(optind < argc)
blockDevice = !stat(argv[optind], &statbuf) ?
bb_simplify_path(argv[optind]) :
(ENABLE_FEATURE_CLEAN_UP ? strdup(argv[optind]) : argv[optind]);
if(optind+1 < argc) directory = bb_simplify_path(argv[optind+1]);
// If we don't have to loop through fstab, skip ahead a bit.
if(!all && optind+1!=argc) goto singlemount;
// Loop through /etc/fstab entries to look up this entry.
if(!(file=setmntent("/etc/fstab","r")))
bb_perror_msg_and_die("\nCannot read /etc/fstab");
for(;;) {
// Get next fstab entry
if(!getmntent_r(file,&m,path,sizeof(path))) {
if(!all)
bb_perror_msg("Can't find %s in /etc/fstab\n", blockDevice);
break;
}
// If we're mounting all and all doesn't mount this one, skip it.
if(all) {
if(strstr(m.mnt_opts,"noauto") || strstr(m.mnt_type,"swap"))
continue;
flags=0;
/* If we're mounting 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 */
} else if(strcmp(blockDevice,m.mnt_fsname) &&
strcmp(argv[optind],m.mnt_fsname) &&
strcmp(blockDevice,m.mnt_dir) &&
strcmp(argv[optind],m.mnt_dir)) continue;
/* Parse flags from /etc/fstab (unless this is a single mount
* overriding fstab -- note the "all" test above zeroed the flags,
* to prevent flags from previous entries affecting this one, so
* the only way we could get here with nonzero flags is a single
* mount). */
if(!flags) {
if(ENABLE_FEATURE_CLEAN_UP) free(string_flags);
string_flags=NULL;
parse_mount_options(m.mnt_opts, &flags, &string_flags);
}
/* Fill out remaining fields with info from mtab */
if(ENABLE_FEATURE_CLEAN_UP) {
free(blockDevice);
blockDevice=strdup(m.mnt_fsname);
free(directory);
directory=strdup(m.mnt_type);
} else {
safe_strncpy(device, argv[optind], PATH_MAX);
blockDevice=m.mnt_fsname;
directory=m.mnt_dir;
}
}
fsType=m.mnt_type;
if (optind + 1 < argc)
directory = bb_simplify_path(argv[optind + 1]);
/* Ok, we're ready to actually mount a specific source on a specific
* directory now. */
if (all || optind + 1 == argc) {
f = setmntent("/etc/fstab", "r");
singlemount:
if (f == NULL)
bb_perror_msg_and_die("\nCannot read /etc/fstab");
// If they said -w, override fstab
while ((m = getmntent(f)) != NULL) {
if (!all && (optind + 1 == argc)
&& ((strcmp(device, m->mnt_fsname) != 0)
&& (strcmp(device, m->mnt_dir) != 0))) {
continue;
if(allowWrite) flags&=~MS_RDONLY;
// Might this be an NFS filesystem?
if(ENABLE_NFSMOUNT && (!fsType || !strcmp(fsType,"nfs")) &&
strchr(blockDevice, ':') != NULL)
{
if(nfsmount(blockDevice, directory, &flags, &string_flags, 1))
bb_perror_msg("nfsmount failed");
else {
rc=EXIT_SUCCESS;
fsType="nfs";
}
} else {
// Do we need to allocate a loopback device?
if (all && ( /* 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, then mount it */
if(ENABLE_FEATURE_MOUNT_LOOP && !fakeIt && S_ISREG(statbuf.st_mode))
{
continue;
}
if (all || flags == 0) { /* Allow single mount to override fstab flags */
flags = 0;
string_flags[0] = 0;
parse_mount_options(m->mnt_opts, &flags, &string_flags);
}
strcpy(device, m->mnt_fsname);
strcpy(directory, m->mnt_dir);
filesystemType = bb_xstrdup(m->mnt_type);
singlemount:
extra_opts = string_flags;
rc = EXIT_SUCCESS;
#ifdef CONFIG_NFSMOUNT
if (strchr(device, ':') != NULL) {
filesystemType = "nfs";
if (nfsmount
(device, directory, &flags, &extra_opts, &string_flags,
1)) {
bb_perror_msg("nfsmount failed");
rc = EXIT_FAILURE;
loopFile = blockDevice;
blockDevice = 0;
switch(set_loop(&blockDevice, loopFile, 0)) {
case 0:
case 1:
break;
default:
bb_error_msg_and_die(
errno == EPERM || errno == EACCES ?
bb_msg_perm_denied_are_you_root :
"Couldn't setup loop device");
break;
}
}
#endif
if (!mount_one
(device, directory, filesystemType, flags, string_flags,
useMtab, fakeIt, extra_opts, TRUE, all)) {
rc = EXIT_FAILURE;
/* If we know the fstype (or don't need to), jump straight
* to the actual mount. */
if(fsType || (flags & (MS_REMOUNT | MS_BIND | MS_MOVE)))
goto mount_it_now;
}
// Loop through filesystem types until mount succeeds or we run out
for(i = 0; files[i] && rc; i++) {
f = fopen(files[i], "r");
if(!f) continue;
// Get next block device backed filesystem
for(buf = 0; (buf = fsType = bb_get_chomped_line_from_file(f));
free(buf))
{
// Skip funky entries in /proc
if(!strncmp(buf,"nodev",5) && isspace(buf[5])) continue;
while(isspace(*fsType)) fsType++;
if(*buf=='#' || *buf=='*') continue;
if(!*fsType) continue;
mount_it_now:
// Okay, try to mount
if (!fakeIt) {
for(;;) {
rc = mount(blockDevice, directory, fsType, flags, string_flags);
if(!rc || (flags&MS_RDONLY) || (errno!=EACCES && errno!=EROFS))
break;
bb_error_msg("%s is write-protected, mounting read-only", blockDevice);
flags|=MS_RDONLY;
}
}
if(!rc) break;
}
if (!all) {
break;
if(f) fclose(f);
if(!f || !rc) break;
}
/* If the mount was sucessful, and we're maintaining an old-style
* mtab file by hand, add new entry to it now. */
if((!rc || fakeIt) && useMtab) {
FILE *mountTable = setmntent(bb_path_mtab_file, "a+");
if(!mountTable) bb_perror_msg(bb_path_mtab_file);
else {
// Remove trailing / (if any) from directory we mounted on
int length=strlen(directory);
if(length>1 && directory[length-1] == '/')
directory[length-1]=0;
// Fill out structure (should be ok to re-use existing one).
m.mnt_fsname=blockDevice;
m.mnt_dir=directory;
m.mnt_type=fsType ? : "--bind";
m.mnt_opts=string_flags ? :
((flags & MS_RDONLY) ? "ro" : "rw");
m.mnt_freq = 0;
m.mnt_passno = 0;
// Write and close
addmntent(mountTable, &m);
endmntent(mountTable);
}
} else {
// Mount failed. Clean up
if(loopFile) {
del_loop(blockDevice);
if(ENABLE_FEATURE_CLEAN_UP) free(loopFile);
}
// Don't whine about already mounted fs when mounting all.
if(rc<0 && errno == EBUSY && all) rc=0;
else if (errno == EPERM)
bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
}
if (f) {
endmntent(f);
// We couldn't free this earlier becase fsType could be in buf.
if(ENABLE_FEATURE_CLEAN_UP) {
free(buf);
free(blockDevice);
free(directory);
}
if (!all && f && m == NULL) {
fprintf(stderr, "Can't find %s in /etc/fstab\n", device);
}
return rc;
if(!all) break;
}
goto singlemount;
if(file) endmntent(file);
if(rc) bb_perror_msg("Mounting %s on %s failed", blockDevice, directory);
return rc ? : EXIT_FAILURE;
}