*/
#include <mntent.h>
-#include "libbb.h"
#include <syslog.h>
+#include "libbb.h"
+
+#if ENABLE_FEATURE_MOUNT_LABEL
+#include "volume_id.h"
+#endif
-/* Needed for nfs support only... */
+/* Needed for nfs support only */
#include <sys/utsname.h>
#undef TRUE
#undef FALSE
#if defined(__dietlibc__)
/* 16.12.2006, Sampo Kellomaki (sampo@iki.fi)
* dietlibc-0.30 does not have implementation of getmntent_r() */
-static struct mntent *getmntent_r(FILE* stream, struct mntent* result, char* buffer, int bufsize)
+static struct mntent *getmntent_r(FILE* stream, struct mntent* result,
+ char* buffer ATTRIBUTE_UNUSED, int bufsize ATTRIBUTE_UNUSED)
{
struct mntent* ment = getmntent(stream);
- memcpy(result, ment, sizeof(struct mntent));
- return result;
+ return memcpy(result, ment, sizeof(*ment));
}
#endif
// Not real flags, but we want to be able to check for this.
enum {
- MOUNT_USERS = (1<<28)*ENABLE_DESKTOP,
- MOUNT_NOAUTO = (1<<29),
- MOUNT_SWAP = (1<<30),
+ MOUNT_USERS = (1 << 28) * ENABLE_DESKTOP,
+ MOUNT_NOAUTO = (1 << 29),
+ MOUNT_SWAP = (1 << 30),
};
unsigned verbose;
#endif
llist_t *fslist;
- char getmntent_buf[sizeof(bb_common_bufsiz1) - 8*3];
+ char getmntent_buf[1];
};
+enum { GETMNTENT_BUFSIZE = COMMON_BUFSIZE - offsetof(struct globals, getmntent_buf) };
#define G (*(struct globals*)&bb_common_bufsiz1)
#define nfs_mount_version (G.nfs_mount_version)
#if ENABLE_FEATURE_MOUNT_VERBOSE
errno = 0;
rc = mount(source, target, filesystemtype, mountflags, data);
if (verbose >= 2)
- bb_perror_msg("would do mount('%s','%s','%s',0x%08lx,'%s'):%d"
- + (sizeof("would do ")-1),
+ bb_perror_msg("mount('%s','%s','%s',0x%08lx,'%s'):%d",
source, target, filesystemtype,
mountflags, (char*)data, rc);
return rc;
#define verbose_mount(...) mount(__VA_ARGS__)
#endif
+static int resolve_mount_spec(char **fsname)
+{
+ char *tmp = NULL;
+
+#if ENABLE_FEATURE_MOUNT_LABEL
+ if (!strncmp(*fsname, "UUID=", 5))
+ tmp = get_devname_from_uuid(*fsname + 5);
+ else if (!strncmp(*fsname, "LABEL=", 6))
+ tmp = get_devname_from_label(*fsname + 6);
+#endif
+
+ if (tmp) {
+ *fsname = tmp;
+ return 1;
+ }
+ return 0;
+}
+
/* Append mount options to string */
static void append_mount_options(char **oldopts, const char *newopts)
{
// Loop through options
for (;;) {
- int i;
+ unsigned i;
char *comma = strchr(options, ',');
const char *option_str = mount_option_str;
if (comma) *comma = '\0';
+/* FIXME: use hasmntopt() */
// Find this option in mount_options
for (i = 0; i < ARRAY_SIZE(mount_options); i++) {
if (!strcasecmp(option_str, options)) {
f = fopen(filesystems[i], "r");
if (!f) continue;
- while ((buf = xmalloc_getline(f)) != 0) {
+ while ((buf = xmalloc_fgetline(f)) != NULL) {
if (!strncmp(buf, "nodev", 5) && isspace(buf[5]))
continue;
fs = skip_whitespace(buf);
vfsflags, filteropts);
// If mount failed, try
- // helper program <mnt_type>
+ // helper program mount.<mnt_type>
if (ENABLE_FEATURE_MOUNT_HELPERS && rc) {
char *args[6];
int errno_save = errno;
- args[0] = mp->mnt_type;
+ args[0] = xasprintf("mount.%s", mp->mnt_type);
rc = 1;
if (filteropts) {
args[rc++] = (char *)"-o";
args[rc++] = mp->mnt_dir;
args[rc] = NULL;
rc = wait4pid(spawn(args));
+ free(args[0]);
if (!rc)
break;
errno = errno_save;
* Wed Oct 1 23:55:28 1997: Dick Streefland <dick_streefland@tasking.com>
* Implemented the "bg", "fg" and "retry" mount options for NFS.
*
- * 1999-02-22 Arkadiusz MiΒΆkiewicz <misiek@misiek.eu.org>
+ * 1999-02-22 Arkadiusz Mickiewicz <misiek@misiek.eu.org>
* - added Native Language Support
*
* Modified by Olaf Kirch and Trond Myklebust for new NFS code,
#endif
// TODO
-static inline int we_saw_this_host_before(const char *hostname)
+static inline int we_saw_this_host_before(const char *hostname ATTRIBUTE_UNUSED)
{
return 0;
}
bb_herror_msg("%s", hostname);
goto fail;
}
- if (hp->h_length > sizeof(struct in_addr)) {
+ if ((size_t)hp->h_length > sizeof(struct in_addr)) {
bb_error_msg("got bad hp->h_length");
hp->h_length = sizeof(struct in_addr);
}
if (filteropts) for (opt = strtok(filteropts, ","); opt; opt = strtok(NULL, ",")) {
char *opteq = strchr(opt, '=');
if (opteq) {
+ int val, idx;
static const char options[] ALIGN1 =
/* 0 */ "rsize\0"
/* 1 */ "wsize\0"
/* 18 */ "proto\0"
/* 19 */ "namlen\0"
/* 20 */ "addr\0";
- int val = xatoi_u(opteq + 1);
- *opteq = '\0';
- switch (index_in_strings(options, opt)) {
+
+ *opteq++ = '\0';
+ idx = index_in_strings(options, opt);
+ switch (idx) {
+ case 12: // "mounthost"
+ mounthost = xstrndup(opteq,
+ strcspn(opteq, " \t\n\r,"));
+ continue;
+ case 18: // "proto"
+ if (!strncmp(opteq, "tcp", 3))
+ tcp = 1;
+ else if (!strncmp(opteq, "udp", 3))
+ tcp = 0;
+ else
+ bb_error_msg("warning: unrecognized proto= option");
+ continue;
+ case 20: // "addr" - ignore
+ continue;
+ }
+
+ val = xatoi_u(opteq);
+ switch (idx) {
case 0: // "rsize"
data.rsize = val;
- break;
+ continue;
case 1: // "wsize"
data.wsize = val;
- break;
+ continue;
case 2: // "timeo"
data.timeo = val;
- break;
+ continue;
case 3: // "retrans"
data.retrans = val;
- break;
+ continue;
case 4: // "acregmin"
data.acregmin = val;
- break;
+ continue;
case 5: // "acregmax"
data.acregmax = val;
- break;
+ continue;
case 6: // "acdirmin"
data.acdirmin = val;
- break;
+ continue;
case 7: // "acdirmax"
data.acdirmax = val;
- break;
+ continue;
case 8: // "actimeo"
data.acregmin = val;
data.acregmax = val;
data.acdirmin = val;
data.acdirmax = val;
- break;
+ continue;
case 9: // "retry"
retry = val;
- break;
+ continue;
case 10: // "port"
port = val;
- break;
+ continue;
case 11: // "mountport"
mountport = val;
- break;
- case 12: // "mounthost"
- mounthost = xstrndup(opteq+1,
- strcspn(opteq+1," \t\n\r,"));
- break;
+ continue;
case 13: // "mountprog"
mountprog = val;
- break;
+ continue;
case 14: // "mountvers"
mountvers = val;
- break;
+ continue;
case 15: // "nfsprog"
nfsprog = val;
- break;
+ continue;
case 16: // "nfsvers"
case 17: // "vers"
nfsvers = val;
- break;
- case 18: // "proto"
- if (!strncmp(opteq+1, "tcp", 3))
- tcp = 1;
- else if (!strncmp(opteq+1, "udp", 3))
- tcp = 0;
- else
- bb_error_msg("warning: unrecognized proto= option");
- break;
+ continue;
case 19: // "namlen"
- if (nfs_mount_version >= 2)
+ //if (nfs_mount_version >= 2)
data.namlen = val;
- else
- bb_error_msg("warning: option namlen is not supported\n");
- break;
- case 20: // "addr" - ignore
- break;
+ //else
+ // bb_error_msg("warning: option namlen is not supported\n");
+ continue;
default:
bb_error_msg("unknown nfs mount parameter: %s=%d", opt, val);
goto fail;
}
}
- else {
+ else { /* not of the form opt=val */
static const char options[] ALIGN1 =
"bg\0"
"fg\0"
if (hp == NULL) {
bb_herror_msg("%s", mounthost);
goto fail;
- } else {
- if (hp->h_length > sizeof(struct in_addr)) {
- bb_error_msg("got bad hp->h_length?");
- hp->h_length = sizeof(struct in_addr);
- }
- mount_server_addr.sin_family = AF_INET;
- memcpy(&mount_server_addr.sin_addr,
- hp->h_addr, hp->h_length);
}
+ if ((size_t)hp->h_length > sizeof(struct in_addr)) {
+ bb_error_msg("got bad hp->h_length");
+ hp->h_length = sizeof(struct in_addr);
+ }
+ mount_server_addr.sin_family = AF_INET;
+ memcpy(&mount_server_addr.sin_addr,
+ hp->h_addr, hp->h_length);
}
}
// Treat fstype "auto" as unspecified.
- if (mp->mnt_type && strcmp(mp->mnt_type,"auto") == 0)
- mp->mnt_type = 0;
+ if (mp->mnt_type && strcmp(mp->mnt_type, "auto") == 0)
+ mp->mnt_type = NULL;
// Might this be a virtual filesystem?
) {
char *s, *p, *args[35];
int n = 0;
+// FIXME: does it allow execution of arbitrary commands?!
+// What args[0] can end up with?
for (s = p = mp->mnt_fsname; *s && n < 35-3; ++s) {
if (s[0] == '#' && s[1] != '#') {
*s = '\0';
// Might this be an CIFS filesystem?
if (ENABLE_FEATURE_MOUNT_CIFS
- && (!mp->mnt_type || strcmp(mp->mnt_type,"cifs") == 0)
- && (mp->mnt_fsname[0]=='/' || mp->mnt_fsname[0]=='\\')
- && mp->mnt_fsname[0]==mp->mnt_fsname[1]
+ && (!mp->mnt_type || strcmp(mp->mnt_type, "cifs") == 0)
+ && (mp->mnt_fsname[0] == '/' || mp->mnt_fsname[0] == '\\')
+ && mp->mnt_fsname[0] == mp->mnt_fsname[1]
) {
len_and_sockaddr *lsa;
char *ip, *dotted;
static const char must_be_root[] ALIGN1 = "you must be root";
int mount_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
-int mount_main(int argc, char **argv)
+int mount_main(int argc ATTRIBUTE_UNUSED, char **argv)
{
- enum { OPT_ALL = 0x10 };
-
- char *cmdopts = xstrdup(""), *fstype=0, *storage_path=0;
+ char *cmdopts = xstrdup("");
+ char *fstype = NULL;
+ char *storage_path;
char *opt_o;
const char *fstabname;
FILE *fstab;
struct mntent mtpair[2], *mtcur = mtpair;
SKIP_DESKTOP(const int nonroot = 0;)
- USE_DESKTOP( int nonroot = ) sanitize_env_if_suid();
+ USE_DESKTOP(int nonroot = ) sanitize_env_if_suid();
// Parse long options, like --bind and --move. Note that -o option
// and --option are synonymous. Yes, this means --remount,rw works.
-
- for (i = j = 0; i < argc; i++) {
- if (argv[i][0] == '-' && argv[i][1] == '-') {
- append_mount_options(&cmdopts, argv[i]+2);
- } else argv[j++] = argv[i];
+ for (i = j = 1; argv[i]; i++) {
+ if (argv[i][0] == '-' && argv[i][1] == '-')
+ append_mount_options(&cmdopts, argv[i] + 2);
+ else
+ argv[j++] = argv[i];
}
- argv[j] = 0;
- argc = j;
+ argv[j] = NULL;
// Parse remaining options
-
-#if ENABLE_FEATURE_MOUNT_VERBOSE
- opt_complementary = "vv"; // -v is a counter
-#endif
+ // Max 2 params; -v is a counter
+ opt_complementary = "?2" USE_FEATURE_MOUNT_VERBOSE(":vv");
opt = getopt32(argv, OPTION_STR, &opt_o, &fstype
USE_FEATURE_MOUNT_VERBOSE(, &verbose));
if (opt & OPT_o) append_mount_options(&cmdopts, opt_o); // -o
if (opt & OPT_r) append_mount_options(&cmdopts, "ro"); // -r
if (opt & OPT_w) append_mount_options(&cmdopts, "rw"); // -w
argv += optind;
- argc -= optind;
-
- // Three or more non-option arguments? Die with a usage message.
-
- if (argc > 2) bb_show_usage();
// If we have no arguments, show currently mounted filesystems
-
- if (!argc) {
- if (!(opt & OPT_ALL)) {
+ if (!argv[0]) {
+ if (!(opt & OPT_a)) {
FILE *mountTable = setmntent(bb_path_mtab_file, "r");
- if (!mountTable) bb_error_msg_and_die("no %s", bb_path_mtab_file);
+ if (!mountTable)
+ bb_error_msg_and_die("no %s", bb_path_mtab_file);
while (getmntent_r(mountTable, &mtpair[0], getmntent_buf,
- sizeof(getmntent_buf)))
+ GETMNTENT_BUFSIZE))
{
// Don't show rootfs. FIXME: why??
// util-linux 2.12a happily shows rootfs...
mtpair->mnt_dir, mtpair->mnt_type,
mtpair->mnt_opts);
}
- if (ENABLE_FEATURE_CLEAN_UP) endmntent(mountTable);
+ if (ENABLE_FEATURE_CLEAN_UP)
+ endmntent(mountTable);
return EXIT_SUCCESS;
}
- } else storage_path = bb_simplify_path(argv[0]);
-
- // 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 (argc == 2) {
- if (nonroot)
- bb_error_msg_and_die(must_be_root);
- mtpair->mnt_fsname = argv[0];
- mtpair->mnt_dir = argv[1];
- mtpair->mnt_type = fstype;
- mtpair->mnt_opts = cmdopts;
- rc = singlemount(mtpair, 0);
- goto clean_up;
+ storage_path = NULL;
+ } else {
+ // 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 (argv[1]) {
+ if (nonroot)
+ bb_error_msg_and_die(must_be_root);
+ mtpair->mnt_fsname = argv[0];
+ mtpair->mnt_dir = argv[1];
+ mtpair->mnt_type = fstype;
+ mtpair->mnt_opts = cmdopts;
+ if (ENABLE_FEATURE_MOUNT_LABEL) {
+ resolve_mount_spec(&mtpair->mnt_fsname);
+ }
+ rc = singlemount(mtpair, 0);
+ return rc;
+ }
+ storage_path = bb_simplify_path(argv[0]); // malloced
}
+ // Past this point, we are handling either "mount -a [opts]"
+ // or "mount [opts] single_param"
+
i = parse_mount_options(cmdopts, 0); // FIXME: should be "long", not "int"
if (nonroot && (i & ~MS_SILENT)) // Non-root users cannot specify flags
bb_error_msg_and_die(must_be_root);
// If we have a shared subtree flag, don't worry about fstab or mtab.
-
if (ENABLE_FEATURE_MOUNT_FLAGS
&& (i & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
) {
- rc = verbose_mount("", argv[0], "", i, "");
- if (rc) bb_simple_perror_msg_and_die(argv[0]);
- goto clean_up;
+ rc = verbose_mount(/*source:*/ "", /*target:*/ argv[0],
+ /*type:*/ "", /*flags:*/ i, /*data:*/ "");
+ if (rc)
+ bb_simple_perror_msg_and_die(argv[0]);
+ return rc;
}
// Open either fstab or mtab
-
fstabname = "/etc/fstab";
if (i & MS_REMOUNT) {
+ // WARNING. I am not sure this matches util-linux's
+ // behavior. It's possible util-linux does not
+ // take -o opts from mtab (takes only mount source).
fstabname = bb_path_mtab_file;
}
fstab = setmntent(fstabname, "r");
if (!fstab)
bb_perror_msg_and_die("cannot read %s", fstabname);
- // Loop through entries until we find what we're looking for.
-
+ // Loop through entries until we find what we're looking for
memset(mtpair, 0, sizeof(mtpair));
for (;;) {
- struct mntent *mtnext = (mtcur==mtpair ? mtpair+1 : mtpair);
+ struct mntent *mtother = (mtcur==mtpair ? mtpair+1 : mtpair);
// Get next fstab entry
-
if (!getmntent_r(fstab, mtcur, getmntent_buf
- + (mtcur==mtpair ? sizeof(getmntent_buf)/2 : 0),
- sizeof(getmntent_buf)/2))
- {
- // Were we looking for something specific?
-
- if (argc) {
-
- // If we didn't find anything, complain.
-
- if (!mtnext->mnt_fsname)
- bb_error_msg_and_die("can't find %s in %s",
- argv[0], fstabname);
-
- mtcur = mtnext;
- if (nonroot) {
- // fstab must have "users" or "user"
- if (!(parse_mount_options(mtcur->mnt_opts, 0) & MOUNT_USERS))
- bb_error_msg_and_die(must_be_root);
- }
-
- // Mount the last thing we found.
-
- mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
- append_mount_options(&(mtcur->mnt_opts), cmdopts);
- rc = singlemount(mtcur, 0);
- free(mtcur->mnt_opts);
- }
- goto clean_up;
+ + (mtcur==mtpair ? GETMNTENT_BUFSIZE/2 : 0),
+ GETMNTENT_BUFSIZE/2)
+ ) { // End of fstab/mtab is reached
+ mtcur = mtother; // the thing we found last time
+ break;
}
- /* 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 (argc) {
+ // If we're trying to mount something specific and this isn't it,
+ // skip it. Note we must match the exact text in fstab (ala
+ // "proc") or a full path from root
+ if (argv[0]) {
// Is this what we're looking for?
-
if (strcmp(argv[0], mtcur->mnt_fsname) &&
strcmp(storage_path, mtcur->mnt_fsname) &&
strcmp(argv[0], 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.
+ // Remember this entry. Something later may have
+ // overmounted it, and we want the _last_ match.
+ mtcur = mtother;
+ // If we're mounting all
} else {
// Do we need to match a filesystem type?
- if (fstype && match_fstype(mtcur, fstype)) continue;
+ if (fstype && match_fstype(mtcur, fstype))
+ continue;
// Skip noauto and swap anyway.
-
- if (parse_mount_options(mtcur->mnt_opts, 0)
- & (MOUNT_NOAUTO | MOUNT_SWAP)) continue;
+ if (parse_mount_options(mtcur->mnt_opts, 0) & (MOUNT_NOAUTO | MOUNT_SWAP))
+ continue;
// No, mount -a won't mount anything,
- // even user mounts, for mere humans.
-
+ // even user mounts, for mere humans
if (nonroot)
bb_error_msg_and_die(must_be_root);
- // Mount this thing.
+ // Mount this thing
+ if (ENABLE_FEATURE_MOUNT_LABEL)
+ resolve_mount_spec(&mtpair->mnt_fsname);
// NFS mounts want this to be xrealloc-able
mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
if (singlemount(mtcur, 1)) {
- /* Count number of failed mounts */
+ // Count number of failed mounts
rc++;
}
free(mtcur->mnt_opts);
}
}
- if (ENABLE_FEATURE_CLEAN_UP) endmntent(fstab);
- clean_up:
+ // End of fstab/mtab is reached.
+ // Were we looking for something specific?
+ if (argv[0]) {
+ // If we didn't find anything, complain
+ if (!mtcur->mnt_fsname)
+ bb_error_msg_and_die("can't find %s in %s",
+ argv[0], fstabname);
+ if (nonroot) {
+ // fstab must have "users" or "user"
+ if (!(parse_mount_options(mtcur->mnt_opts, 0) & MOUNT_USERS))
+ bb_error_msg_and_die(must_be_root);
+ }
+ // Mount the last thing we found
+ mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
+ append_mount_options(&(mtcur->mnt_opts), cmdopts);
+ if (ENABLE_FEATURE_MOUNT_LABEL) {
+ resolve_mount_spec(&mtpair->mnt_fsname);
+ }
+ rc = singlemount(mtcur, 0);
+ if (ENABLE_FEATURE_CLEAN_UP)
+ free(mtcur->mnt_opts);
+ }
+
+ if (ENABLE_FEATURE_CLEAN_UP)
+ endmntent(fstab);
if (ENABLE_FEATURE_CLEAN_UP) {
free(storage_path);
free(cmdopts);
}
-
return rc;
}