summaryrefslogtreecommitdiffstats
path: root/sbin/mount/mount.c
diff options
context:
space:
mode:
Diffstat (limited to 'sbin/mount/mount.c')
-rw-r--r--sbin/mount/mount.c512
1 files changed, 512 insertions, 0 deletions
diff --git a/sbin/mount/mount.c b/sbin/mount/mount.c
new file mode 100644
index 0000000..f0ff782
--- /dev/null
+++ b/sbin/mount/mount.c
@@ -0,0 +1,512 @@
+/*
+ * Copyright (c) 1980, 1989, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1980, 1989, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)mount.c 8.19 (Berkeley) 4/19/94";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <sys/wait.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fstab.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "pathnames.h"
+
+int debug, verbose, skipvfs;
+
+int badvfsname __P((const char *, const char **));
+int badvfstype __P((int, const char **));
+char *catopt __P((char *, const char *));
+struct statfs
+ *getmntpt __P((const char *));
+const char
+ **makevfslist __P((char *));
+void mangle __P((char *, int *, const char **));
+int mountfs __P((const char *, const char *, const char *,
+ int, const char *, const char *));
+void prmount __P((const char *, const char *, int));
+void usage __P((void));
+
+/* From mount_ufs.c. */
+int mount_ufs __P((int, char * const *));
+
+/* Map from mount otions to printable formats. */
+static struct opt {
+ int o_opt;
+ const char *o_name;
+} optnames[] = {
+ { MNT_ASYNC, "asynchronous" },
+ { MNT_EXPORTED, "NFS exported" },
+ { MNT_LOCAL, "local" },
+ { MNT_NODEV, "nodev" },
+ { MNT_NOEXEC, "noexec" },
+ { MNT_NOSUID, "nosuid" },
+ { MNT_QUOTA, "with quotas" },
+ { MNT_RDONLY, "read-only" },
+ { MNT_SYNCHRONOUS, "synchronous" },
+ { MNT_UNION, "union" },
+ { MNT_USER, "user mount" },
+ { NULL }
+};
+
+int
+main(argc, argv)
+ int argc;
+ char * const argv[];
+{
+ const char *mntonname, **vfslist, *vfstype;
+ struct fstab *fs;
+ struct statfs *mntbuf;
+ FILE *mountdfp;
+ pid_t pid;
+ int all, ch, i, init_flags, mntsize, rval;
+ char *options;
+
+ all = init_flags = 0;
+ options = NULL;
+ vfslist = NULL;
+ vfstype = "ufs";
+ while ((ch = getopt(argc, argv, "adfo:rwt:uv")) != EOF)
+ switch (ch) {
+ case 'a':
+ all = 1;
+ break;
+ case 'd':
+ debug = 1;
+ break;
+ case 'f':
+ init_flags |= MNT_FORCE;
+ break;
+ case 'o':
+ if (*optarg)
+ options = catopt(options, optarg);
+ break;
+ case 'r':
+ init_flags |= MNT_RDONLY;
+ break;
+ case 't':
+ if (vfslist != NULL)
+ errx(1, "only one -t option may be specified.");
+ vfslist = makevfslist(optarg);
+ vfstype = optarg;
+ break;
+ case 'u':
+ init_flags |= MNT_UPDATE;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case 'w':
+ init_flags &= ~MNT_RDONLY;
+ break;
+ case '?':
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+ argc -= optind;
+ argv += optind;
+
+#define BADTYPE(type) \
+ (strcmp(type, FSTAB_RO) && \
+ strcmp(type, FSTAB_RW) && strcmp(type, FSTAB_RQ))
+
+ rval = 0;
+ switch (argc) {
+ case 0:
+ if (all)
+ while ((fs = getfsent()) != NULL) {
+ if (BADTYPE(fs->fs_type))
+ continue;
+ if (badvfsname(fs->fs_vfstype, vfslist))
+ continue;
+ if (mountfs(fs->fs_vfstype, fs->fs_spec,
+ fs->fs_file, init_flags, options,
+ fs->fs_mntops))
+ rval = 1;
+ }
+ else {
+ if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0)
+ err(1, "getmntinfo");
+ for (i = 0; i < mntsize; i++) {
+ if (badvfstype(mntbuf[i].f_type, vfslist))
+ continue;
+ prmount(mntbuf[i].f_mntfromname,
+ mntbuf[i].f_mntonname, mntbuf[i].f_flags);
+ }
+ }
+ exit(rval);
+ case 1:
+ if (vfslist != NULL)
+ usage();
+
+ if (init_flags & MNT_UPDATE) {
+ if ((mntbuf = getmntpt(*argv)) == NULL)
+ errx(1,
+ "unknown special file or file system %s.",
+ *argv);
+ if ((fs = getfsfile(mntbuf->f_mntonname)) == NULL)
+ errx(1, "can't find fstab entry for %s.",
+ *argv);
+ /* If it's an update, ignore the fstab file options. */
+ fs->fs_mntops = NULL;
+ mntonname = mntbuf->f_mntonname;
+ } else {
+ if ((fs = getfsfile(*argv)) == NULL &&
+ (fs = getfsspec(*argv)) == NULL)
+ errx(1,
+ "%s: unknown special file or file system.",
+ *argv);
+ if (BADTYPE(fs->fs_type))
+ errx(1, "%s has unknown file system type.",
+ *argv);
+ mntonname = fs->fs_file;
+ }
+ rval = mountfs(fs->fs_vfstype, fs->fs_spec,
+ mntonname, init_flags, options, fs->fs_mntops);
+ break;
+ case 2:
+ /*
+ * If -t flag has not been specified, and spec contains either
+ * a ':' or a '@' then assume that an NFS filesystem is being
+ * specified ala Sun.
+ */
+ if (vfslist == NULL && strpbrk(argv[0], ":@") != NULL)
+ vfstype = "nfs";
+ rval = mountfs(vfstype,
+ argv[0], argv[1], init_flags, options, NULL);
+ break;
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+
+ /*
+ * If the mount was successfully, and done by root, tell mountd the
+ * good news. Pid checks are probably unnecessary, but don't hurt.
+ */
+ if (rval == 0 && getuid() == 0 &&
+ (mountdfp = fopen(_PATH_MOUNTDPID, "r")) != NULL) {
+ if (fscanf(mountdfp, "%ld", &pid) == 1 &&
+ pid > 0 && kill(pid, SIGHUP) == -1 && errno != ESRCH)
+ err(1, "signal mountd");
+ (void)fclose(mountdfp);
+ }
+
+ exit(rval);
+}
+
+int
+mountfs(vfstype, spec, name, flags, options, mntopts)
+ const char *vfstype, *spec, *name, *options, *mntopts;
+ int flags;
+{
+ /* List of directories containing mount_xxx subcommands. */
+ static const char *edirs[] = {
+ _PATH_SBIN,
+ _PATH_USRSBIN,
+ NULL
+ };
+ const char *argv[100], **edir;
+ struct statfs sf;
+ pid_t pid;
+ int argc, i, status;
+ char *optbuf, execname[MAXPATHLEN + 1], mntpath[MAXPATHLEN];
+
+ if (realpath(name, mntpath) == NULL) {
+ warn("%s", mntpath);
+ return (1);
+ }
+
+ name = mntpath;
+
+ if (options == NULL) {
+ if (mntopts == NULL || *mntopts == '\0')
+ options = "rw";
+ else
+ options = mntopts;
+ mntopts = "";
+ }
+ optbuf = catopt(strdup(mntopts), options);
+
+ if (strcmp(name, "/") == 0)
+ flags |= MNT_UPDATE;
+ if (flags & MNT_FORCE)
+ optbuf = catopt(optbuf, "force");
+ if (flags & MNT_RDONLY)
+ optbuf = catopt(optbuf, "ro");
+ /*
+ * XXX
+ * The mount_mfs (newfs) command uses -o to select the
+ * optimisation mode. We don't pass the default "-o rw"
+ * for that reason.
+ */
+ if (flags & MNT_UPDATE)
+ optbuf = catopt(optbuf, "update");
+
+ argc = 0;
+ argv[argc++] = vfstype;
+ mangle(optbuf, &argc, argv);
+ argv[argc++] = spec;
+ argv[argc++] = name;
+ argv[argc] = NULL;
+
+ if (debug) {
+ (void)printf("exec: mount_%s", vfstype);
+ for (i = 1; i < argc; i++)
+ (void)printf(" %s", argv[i]);
+ (void)printf("\n");
+ return (0);
+ }
+
+ switch (pid = vfork()) {
+ case -1: /* Error. */
+ warn("vfork");
+ free(optbuf);
+ return (1);
+ case 0: /* Child. */
+ if (strcmp(vfstype, "ufs") == 0)
+ exit(mount_ufs(argc, (char * const *) argv));
+
+ /* Go find an executable. */
+ edir = edirs;
+ do {
+ (void)snprintf(execname,
+ sizeof(execname), "%s/mount_%s", *edir, vfstype);
+ execv(execname, (char * const *)argv);
+ if (errno != ENOENT)
+ warn("exec %s for %s", execname, name);
+ } while (*++edir != NULL);
+
+ if (errno == ENOENT)
+ warn("exec %s for %s", execname, name);
+ exit(1);
+ /* NOTREACHED */
+ default: /* Parent. */
+ free(optbuf);
+
+ if (waitpid(pid, &status, 0) < 0) {
+ warn("waitpid");
+ return (1);
+ }
+
+ if (WIFEXITED(status)) {
+ if (WEXITSTATUS(status) != 0)
+ return (WEXITSTATUS(status));
+ } else if (WIFSIGNALED(status)) {
+ warnx("%s: %s", name, sys_siglist[WTERMSIG(status)]);
+ return (1);
+ }
+
+ if (verbose) {
+ if (statfs(name, &sf) < 0) {
+ warn("%s", name);
+ return (1);
+ }
+ prmount(sf.f_mntfromname, sf.f_mntonname, sf.f_flags);
+ }
+ break;
+ }
+
+ return (0);
+}
+
+void
+prmount(spec, name, flags)
+ const char *spec, *name;
+ int flags;
+{
+ struct opt *o;
+ int f;
+
+ (void)printf("%s on %s", spec, name);
+
+ flags &= MNT_VISFLAGMASK;
+ for (f = 0, o = optnames; flags && o->o_opt; o++)
+ if (flags & o->o_opt) {
+ (void)printf("%s%s", !f++ ? " (" : ", ", o->o_name);
+ flags &= ~o->o_opt;
+ }
+ (void)printf(f ? ")\n" : "\n");
+}
+
+struct statfs *
+getmntpt(name)
+ const char *name;
+{
+ struct statfs *mntbuf;
+ int i, mntsize;
+
+ mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
+ for (i = 0; i < mntsize; i++)
+ if (strcmp(mntbuf[i].f_mntfromname, name) == 0 ||
+ strcmp(mntbuf[i].f_mntonname, name) == 0)
+ return (&mntbuf[i]);
+ return (NULL);
+}
+
+int
+badvfsname(vfsname, vfslist)
+ const char *vfsname;
+ const char **vfslist;
+{
+
+ if (vfslist == NULL)
+ return (0);
+ while (*vfslist != NULL) {
+ if (strcmp(vfsname, *vfslist) == 0)
+ return (skipvfs);
+ ++vfslist;
+ }
+ return (!skipvfs);
+}
+
+int
+badvfstype(vfstype, vfslist)
+ int vfstype;
+ const char **vfslist;
+{
+static const char *vfsnames[] = INITMOUNTNAMES;
+
+ if ((vfstype < 0) || (vfstype > MOUNT_MAXTYPE))
+ return (0);
+
+ return (badvfsname(vfsnames[vfstype], vfslist));
+}
+
+const char **
+makevfslist(fslist)
+ char *fslist;
+{
+ const char **av;
+ int i;
+ char *nextcp;
+
+ if (fslist == NULL)
+ return (NULL);
+ if (fslist[0] == 'n' && fslist[1] == 'o') {
+ fslist += 2;
+ skipvfs = 1;
+ }
+ for (i = 0, nextcp = fslist; *nextcp; nextcp++)
+ if (*nextcp == ',')
+ i++;
+ if ((av = malloc((size_t)(i + 2) * sizeof(char *))) == NULL) {
+ warn(NULL);
+ return (NULL);
+ }
+ nextcp = fslist;
+ i = 0;
+ av[i++] = nextcp;
+ while ((nextcp = strchr(nextcp, ',')) != NULL) {
+ *nextcp++ = '\0';
+ av[i++] = nextcp;
+ }
+ av[i++] = NULL;
+ return (av);
+}
+
+char *
+catopt(s0, s1)
+ char *s0;
+ const char *s1;
+{
+ size_t i;
+ char *cp;
+
+ if (s0 && *s0) {
+ i = strlen(s0) + strlen(s1) + 1 + 1;
+ if ((cp = malloc(i)) == NULL)
+ err(1, NULL);
+ (void)snprintf(cp, i, "%s,%s", s0, s1);
+ } else
+ cp = strdup(s1);
+
+ if (s0)
+ free(s0);
+ return (cp);
+}
+
+void
+mangle(options, argcp, argv)
+ char *options;
+ int *argcp;
+ const char **argv;
+{
+ char *p, *s;
+ int argc;
+
+ argc = *argcp;
+ for (s = options; (p = strsep(&s, ",")) != NULL;)
+ if (*p != '\0')
+ if (*p == '-') {
+ argv[argc++] = p;
+ p = strchr(p, '=');
+ if (p) {
+ *p = '\0';
+ argv[argc++] = p+1;
+ }
+ } else if (strcmp(p, "rw") != 0) {
+ argv[argc++] = "-o";
+ argv[argc++] = p;
+ }
+
+ *argcp = argc;
+}
+
+void
+usage()
+{
+
+ (void)fprintf(stderr,
+ "usage: mount %s %s\n mount %s\n mount %s\n",
+ "[-dfruvw] [-o options] [-t ufs | external_type]",
+ "special node",
+ "[-adfruvw] [-t ufs | external_type]",
+ "[-dfruvw] special | node");
+ exit(1);
+}
OpenPOWER on IntegriCloud