summaryrefslogtreecommitdiffstats
path: root/sbin
diff options
context:
space:
mode:
authordd <dd@FreeBSD.org>2001-06-18 23:46:58 +0000
committerdd <dd@FreeBSD.org>2001-06-18 23:46:58 +0000
commit2a395fdfb3953a05ad2c981452ebd271fe8e242a (patch)
tree596c2b198da237b7a0241932d1266757eea191a9 /sbin
parentb037431a26b5531b4ac75d931acbbac396af3227 (diff)
downloadFreeBSD-src-2a395fdfb3953a05ad2c981452ebd271fe8e242a.zip
FreeBSD-src-2a395fdfb3953a05ad2c981452ebd271fe8e242a.tar.gz
Introduce mdmfs(8), a wrapper around mdconfig(8), disklabel(8),
newfs(8), and mount(8) that mimics the command line option set of the deprecated mount_mfs(8). Approved by: jkh, phk, -hackers
Diffstat (limited to 'sbin')
-rw-r--r--sbin/mdmfs/Makefile7
-rw-r--r--sbin/mdmfs/mdmfs.8262
-rw-r--r--sbin/mdmfs/mdmfs.c651
-rw-r--r--sbin/mdmfs/pathnames.h10
4 files changed, 930 insertions, 0 deletions
diff --git a/sbin/mdmfs/Makefile b/sbin/mdmfs/Makefile
new file mode 100644
index 0000000..afa13e8
--- /dev/null
+++ b/sbin/mdmfs/Makefile
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+PROG= mdmfs
+MAN= mdmfs.8
+WARNS?= 2
+
+.include <bsd.prog.mk>
diff --git a/sbin/mdmfs/mdmfs.8 b/sbin/mdmfs/mdmfs.8
new file mode 100644
index 0000000..f5b6694
--- /dev/null
+++ b/sbin/mdmfs/mdmfs.8
@@ -0,0 +1,262 @@
+.\"
+.\" Copyright (c) 2001 Dima Dorfman <dd@FreeBSD.org>
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd May 26, 2001
+.Dt MDMFS 8
+.Os
+.Sh NAME
+.Nm mdmfs
+.Nd configure and mount an in-memory filesystem using the
+.Xr md 4
+driver
+.Sh SYNOPSIS
+.Nm
+.Op Fl DLMNSX
+.Op Fl a Ar maxcontig
+.Op Fl b Ar block-size
+.Op Fl c Ar cylinders
+.Op Fl d Ar rotdelay
+.Op Fl e Ar maxbpg
+.Op Fl F Ar file
+.Op Fl f Ar frag-size
+.Op Fl i Ar bytes
+.Op Fl m Ar percent-free
+.Op Fl n Ar rotational-positions
+.Op Fl O Ar optimization
+.Op Fl o Ar mount-options
+.Op Fl p Ar permissions
+.Op Fl s Ar size
+.Op Fl w Ar user Ns | Ns Ar group
+.Ar md-device
+.Ar mount-point
+.Sh DESCRIPTION
+The
+.Nm
+program is designed to be a work-alike and look-alike of the deprecated
+.Xr mount_mfs 8 .
+The end result is essentially the same,
+but is accomplished in a completely different way.
+.Nm
+configures an
+.Xr md 4
+disk using
+.Xr mdconfig 8 ,
+labels it using
+.Xr disklabel 8 ,
+puts a UFS filesystem on it using
+.Xr newfs 8 ,
+and mounts it using
+.Xr mount 8 .
+All the command line options are passed to the appropriate program
+at the appropriate stage in order to achieve the desired effect.
+.Pp
+By default,
+.Nm
+creates a swap-based
+.Pq Dv MD_SWAP
+disk with soft-updates enabled
+and mounts it on
+.Ar mount-point .
+It uses the
+.Xr md 4
+device specified by
+.Ar md-device .
+If
+.Ar md-device
+is
+.Ql md
+(no unit number),
+it will use
+.Xr md 4 Ns 's
+auto-unit feature to automatically select an unused device.
+Unless otherwise specified with one of the options below,
+it uses the default arguments to all the helper programs.
+.Pp
+The following options are available.
+Where possible,
+the option letter matches the one used by
+.Xr mount_mfs 8
+for the same thing.
+.Bl -tag -width Ds
+.It Fl a Ar maxcontig
+Specify the maximum number of contiguous blocks that will be laid
+out before forcing a rotational delay
+(see the
+.Fl d
+option).
+.It Fl b Ar block-size
+The block size of the filesystem, in bytes.
+.It Fl c Ar cylinders
+The number of cylinders per cylinder group in the filesystem.
+.It Fl D
+If not using auto-unit,
+don't run
+.Xr mdconfig 8
+to try to detach the unit before attaching it.
+.It Fl d Ar rotdelay
+Specify the mininum time in milliseconds required to initiate another
+disk transfer on the same cylinder.
+Modern disks with read/write-behind achieve higher performance without
+this feature,
+so it is best to leave it at 0 milliseconds.
+.It Fl e Ar maxbpg
+Indicate the maximum number of blocks any single file can allocate
+out of a cylinder group before it is forced to begin allocating
+blocks from another cylinder group.
+.It Fl F Ar file
+Create a vnode-backed
+.Pq Dv MD_VNODE
+memory disk backed by
+.Ar file .
+.It Fl f Ar frag-size
+The fragment size of the filesystem in bytes.
+.It Fl i Ar bytes
+Number of bytes per inode.
+.It Fl L
+Show the output of the helper programs.
+By default,
+it is sent to
+.Pa /dev/null .
+.It Fl M
+Create a
+.Xr malloc 9
+backed disk
+.Pq Dv MD_MALLOC
+instead of a swap-backed disk.
+.It Fl m Ar percent-free
+The percentage of space reserved for the superuser.
+.It Fl N
+Don't actually run the helper programs.
+This is most useful in conjunction with
+.Fl X .
+.It Fl n Ar rotational-positions
+The default number of rotational positions to distinguish.
+.It Fl O Ar optimization
+Select the optimization preference;
+valid choices are
+.Ar space
+and
+.Ar time ,
+which will optimize for minimum space fragmentation and
+minimum time spent allocating blocks,
+respectively.
+.It Fl o Ar mount-options
+Specify the mount options with which to mount the filesystem.
+See
+.Xr mount 8
+for more information.
+.It Fl p Ar permissions
+Set the file (directory) permissions of the mount point
+.Ar mount-point
+to
+.Ar permissions .
+.It Fl S
+Don't enable soft-updates on the filesystem.
+.It Fl s Ar size
+Specify the size of the disk to create.
+This only makes sense if
+.Fl F
+is
+.Em not
+specified.
+That is,
+this will work for the default swap-backed
+.Pq Dv MD_SWAP
+disks,
+and the optional
+.Pq Fl M
+.Xr malloc 9
+backed disks
+.Pq Dv MD_MALLOC .
+.It Fl w Ar user Ns | Ns Ar group
+Set the owner user and group to
+.Ar user
+and
+.Ar group ,
+respectively.
+The arguments have the same semantics as with
+.Xr chown 8 ,
+but specifying just a user or just a group is not supported.
+.El
+.Pp
+The
+.Fl F
+and
+.Fl s
+options are passed to
+.Xr mdconfig 8
+as
+.Fl f
+and
+.Fl s ,
+respectively.
+The
+.Fl a ,
+.Fl b ,
+.Fl c ,
+.Fl d ,
+.Fl e ,
+.Fl f ,
+.Fl i ,
+.FL m
+and
+.Fl n
+options are passed to
+.Xr newfs 8
+with the same letter;
+the
+.Fl O
+option is passed to
+.Xr newfs 8
+as
+.Fl o .
+The
+.Fl o
+option is passed to
+.Xr mount 8
+with the same letter.
+See the programs that the options are passed to for more information
+on their semantics.
+.Sh EXAMPLES
+Create and mount a 32 megabyte swap-backed filesystem on
+.Pa /tmp :
+.Pp
+.Dl mdmfs -s 32m md /tmp
+.Pp
+Create and mount a 16 megabyte malloc-backed filesystem on
+.Pa /tmp
+using the
+.Pa /dev/md1
+device;
+furthermore,
+don't use soft-updates it and mount it
+.Cm async :
+.Pp
+.Dl mdmfs -M -S -o async -s 16m md1 /tmp
+.Sh AUTHOR
+.An Dima Dorfman
+.Aq dd@FreeBSD.org
diff --git a/sbin/mdmfs/mdmfs.c b/sbin/mdmfs/mdmfs.c
new file mode 100644
index 0000000..2debcea
--- /dev/null
+++ b/sbin/mdmfs/mdmfs.c
@@ -0,0 +1,651 @@
+/*
+ * Copyright (c) 2001 Dima Dorfman <dd@FreeBSD.org>
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+/*
+ * mdmfs (md/MFS) is a wrapper around mdconfig(8), disklabel(8),
+ * newfs(8), and mount(8) that mimics the command line option set of
+ * the deprecated mount_mfs(8).
+ */
+
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/mdioctl.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include <assert.h>
+#include <err.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <paths.h>
+#include <pwd.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "pathnames.h"
+
+typedef enum { false, true } bool;
+
+struct mtpt_info {
+ uid_t mi_uid;
+ bool mi_have_uid;
+ gid_t mi_gid;
+ bool mi_have_gid;
+ mode_t mi_mode;
+ bool mi_have_mode;
+};
+
+static bool debug; /* Emit debugging information? */
+static bool loudsubs; /* Suppress output from helper programs? */
+static bool norun; /* Actually run the helper programs? */
+static int unit; /* The unit we're working with. */
+static const char *mdname; /* Name of memory disk device (e.g., "md"). */
+static size_t mdnamelen; /* Length of mdname. */
+
+static void argappend(char **, const char *, ...);
+static void debugprintf(const char *, ...);
+static void do_disklabel(void);
+static void do_mdconfig_attach(const char *, const enum md_types);
+static void do_mdconfig_attach_au(const char *, const enum md_types);
+static void do_mdconfig_detach(void);
+static void do_mount(const char *, const char *);
+static void do_mtptsetup(const char *, struct mtpt_info *);
+static void do_newfs(const char *);
+static void extract_ugid(const char *, struct mtpt_info *);
+static int run(int *, const char *, ...);
+static void usage(void);
+
+int
+main(int ac, char **av)
+{
+ struct mtpt_info mi; /* Mountpoint info. */
+ char *mdconfig_arg, *newfs_arg, /* Args to helper programs. */
+ *mount_arg;
+ enum md_types mdtype; /* The type of our memory disk. */
+ bool have_mdtype;
+ bool detach, softdep, autounit;
+ char *mtpoint, *unitstr;
+ char ch, *p;
+
+ /* Misc. initialization. */
+ (void)memset(&mi, '\0', sizeof(mi));
+ detach = true;
+ softdep = true;
+ autounit = false;
+ have_mdtype = false;
+ mdname = MD_NAME;
+ mdnamelen = strlen(mdname);
+ /*
+ * Can't set these to NULL. They may be passed to the
+ * respective programs without modification. I.e., we may not
+ * receive any command-line options which will caused them to
+ * be modified.
+ */
+ mdconfig_arg = strdup("");
+ newfs_arg = strdup("");
+ mount_arg = strdup("");
+
+ while ((ch = getopt(ac, av,
+ "a:b:c:Dd:e:F:f:hi:LMm:Nn:O:o:p:Ss:t:w:X")) != -1)
+ switch (ch) {
+ case 'a':
+ argappend(&newfs_arg, "-a %s", optarg);
+ break;
+ case 'b':
+ argappend(&newfs_arg, "-b %s", optarg);
+ break;
+ case 'c':
+ argappend(&newfs_arg, "-c %s", optarg);
+ break;
+ case 'D':
+ detach = false;
+ break;
+ case 'd':
+ argappend(&newfs_arg, "-d %s", optarg);
+ break;
+ case 'e':
+ argappend(&newfs_arg, "-e %s", optarg);
+ break;
+ case 'F':
+ if (have_mdtype)
+ usage();
+ mdtype = MD_VNODE;
+ have_mdtype = true;
+ argappend(&mdconfig_arg, "-f %s", optarg);
+ break;
+ case 'f':
+ argappend(&newfs_arg, "-f %s", optarg);
+ break;
+ case 'h':
+ usage();
+ break;
+ case 'i':
+ argappend(&newfs_arg, "-i %s", optarg);
+ break;
+ case 'L':
+ loudsubs = true;
+ break;
+ case 'M':
+ if (have_mdtype)
+ usage();
+ mdtype = MD_MALLOC;
+ have_mdtype = true;
+ break;
+ case 'm':
+ argappend(&newfs_arg, "-m %s", optarg);
+ break;
+ case 'N':
+ norun = true;
+ break;
+ case 'n':
+ argappend(&newfs_arg, "-n %s", optarg);
+ break;
+ case 'O':
+ argappend(&newfs_arg, "-o %s", optarg);
+ break;
+ case 'o':
+ argappend(&mount_arg, "-o %s", optarg);
+ break;
+ case 'p':
+ if (*optarg >= '0' && *optarg <= '7')
+ mi.mi_mode = strtol(optarg, NULL, 8);
+ if ((mi.mi_mode & ~07777) != 0)
+ usage();
+ mi.mi_have_mode = true;
+ break;
+ case 'S':
+ softdep = false;
+ break;
+ case 's':
+ argappend(&mdconfig_arg, "-s %s", optarg);
+ break;
+ case 'w':
+ extract_ugid(optarg, &mi);
+ break;
+ case 'X':
+ debug = true;
+ break;
+ default:
+ usage();
+ }
+ ac -= optind;
+ av += optind;
+ if (ac < 2)
+ usage();
+
+ /* Derive 'unit' (global). */
+ unitstr = av[0];
+ if (strncmp(unitstr, "/dev/", 5) == 0)
+ unitstr += 5;
+ if (strncmp(unitstr, mdname, mdnamelen) == 0)
+ unitstr += mdnamelen;
+ if (*unitstr == '\0') {
+ autounit = true;
+ unit = -1;
+ } else {
+ unit = strtoul(unitstr, &p, 10);
+ if ((unsigned)unit == ULONG_MAX || *p != '\0')
+ errx(1, "bad device unit: %s", unitstr);
+ }
+
+ mtpoint = av[1];
+ if (!have_mdtype)
+ mdtype = MD_SWAP;
+ if (softdep)
+ argappend(&newfs_arg, "-U");
+
+ /* Do the work. */
+ if (detach && !autounit)
+ do_mdconfig_detach();
+ if (autounit)
+ do_mdconfig_attach_au(mdconfig_arg, mdtype);
+ else
+ do_mdconfig_attach(mdconfig_arg, mdtype);
+ do_disklabel();
+ do_newfs(newfs_arg);
+ do_mount(mount_arg, mtpoint);
+ do_mtptsetup(mtpoint, &mi);
+
+ return (0);
+}
+
+/*
+ * Append the expansion of 'fmt' to the buffer pointed to by '*dstp';
+ * reallocate as required.
+ */
+static void
+argappend(char **dstp, const char *fmt, ...)
+{
+ char *old, *new;
+ va_list ap;
+
+ old = *dstp;
+ assert(old != NULL);
+
+ va_start(ap, fmt);
+ if (vasprintf(&new, fmt,ap) == -1)
+ errx(1, "vasprintf");
+ va_end(ap);
+
+ *dstp = new;
+ if (asprintf(&new, "%s %s", old, new) == -1)
+ errx(1, "asprintf");
+ free(*dstp);
+ free(old);
+
+ *dstp = new;
+}
+
+/*
+ * If run-time debugging is enabled, print the expansion of 'fmt'.
+ * Otherwise, do nothing.
+ */
+static void
+debugprintf(const char *fmt, ...)
+{
+ va_list ap;
+
+ if (!debug)
+ return;
+ fprintf(stderr, "DEBUG: ");
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+ fflush(stderr);
+}
+
+/*
+ * Label the memory disk.
+ */
+static void
+do_disklabel(void)
+{
+ int rv;
+
+ rv = run(NULL, "%s -r -w %s%d auto", PATH_DISKLABEL, mdname, unit);
+ if (rv)
+ errx(1, "disklabel exited with error code %d", rv);
+}
+
+/*
+ * Attach a memory disk with a known unit.
+ */
+static void
+do_mdconfig_attach(const char *args, const enum md_types mdtype)
+{
+ int rv;
+ const char *ta; /* Type arg. */
+
+ switch (mdtype) {
+ case MD_SWAP:
+ ta = "-t swap";
+ break;
+ case MD_VNODE:
+ ta = "-t vnode";
+ break;
+ case MD_MALLOC:
+ ta = "-t malloc";
+ break;
+ default:
+ abort();
+ }
+ rv = run(NULL, "%s -a %s%s -u %s%d", PATH_MDCONFIG, ta, args,
+ mdname, unit);
+ if (rv)
+ errx(1, "mdconfig (attach) exited with error code %d", rv);
+}
+
+/*
+ * Attach a memory disk with an unknown unit; use autounit.
+ */
+static void
+do_mdconfig_attach_au(const char *args, const enum md_types mdtype)
+{
+ const char *ta; /* Type arg. */
+ char *linep, *linebuf; /* Line pointer, line buffer. */
+ int fd; /* Standard output of mdconfig invocation. */
+ FILE *sfd;
+ int rv;
+ char *p;
+ size_t linelen;
+
+ switch (mdtype) {
+ case MD_SWAP:
+ ta = "-t swap";
+ break;
+ case MD_VNODE:
+ ta = "-t vnode";
+ break;
+ case MD_MALLOC:
+ ta = "-t malloc";
+ break;
+ default:
+ abort();
+ }
+ rv = run(&fd, "%s -a %s%s", PATH_MDCONFIG, ta, args);
+ if (rv)
+ errx(1, "mdconfig (attach) exited with error code %d", rv);
+
+ /* Receive the unit number. */
+ if (norun) { /* Since we didn't run, we can't read. Fake it. */
+ unit = -1;
+ return;
+ }
+ sfd = fdopen(fd, "r");
+ if (sfd == NULL)
+ err(1, "fdopen");
+ linep = fgetln(sfd, &linelen);
+ if (linep == NULL && linelen < mdnamelen + 1)
+ errx(1, "unexpected output from mdconfig (attach)");
+ /* If the output format changes, we want to know about it. */
+ assert(strncmp(linep, mdname, mdnamelen) == 0);
+ linebuf = malloc(linelen - mdnamelen + 1);
+ assert(linebuf != NULL);
+ /* Can't use strlcpy because linep is not NULL-terminated. */
+ strncpy(linebuf, linep + mdnamelen, linelen);
+ linebuf[linelen] = '\0';
+ unit = strtoul(linebuf, &p, 10);
+ if ((unsigned)unit == ULONG_MAX || *p != '\n')
+ errx(1, "unexpected output from mdconfig (attach)");
+
+ fclose(sfd);
+ close(fd);
+}
+
+/*
+ * Detach a memory disk.
+ */
+static void
+do_mdconfig_detach(void)
+{
+ int rv;
+
+ rv = run(NULL, "%s -d -u %s%d", PATH_MDCONFIG, mdname, unit);
+ if (rv && debug) /* This is allowed to fail. */
+ warnx("mdconfig (detach) exited with error code %d (ignored)",
+ rv);
+}
+
+/*
+ * Mount the configured memory disk.
+ */
+static void
+do_mount(const char *args, const char *mtpoint)
+{
+ int rv;
+
+ rv = run(NULL, "%s%s /dev/%s%dc %s", PATH_MOUNT, args,
+ mdname, unit, mtpoint);
+ if (rv)
+ errx(1, "mount exited with error code %d", rv);
+}
+
+/*
+ * Various configuration of the mountpoint. Mostly, enact 'mip'.
+ */
+static void
+do_mtptsetup(const char *mtpoint, struct mtpt_info *mip)
+{
+
+ if (mip->mi_have_mode) {
+ debugprintf("changing mode of %s to %o.", mtpoint,
+ mip->mi_mode);
+ if (!norun)
+ if (chmod(mtpoint, mip->mi_mode) == -1)
+ err(1, "chmod: %s", mtpoint);
+ }
+ /*
+ * We have to do these separately because the user may have
+ * only specified one of them.
+ */
+ if (mip->mi_have_uid) {
+ debugprintf("changing owner (user) or %s to %u.", mtpoint,
+ mip->mi_uid);
+ if (!norun)
+ if (chown(mtpoint, mip->mi_uid, -1) == -1)
+ err(1, "chown %s to %u (user)", mtpoint,
+ mip->mi_uid);
+ }
+ if (mip->mi_have_gid) {
+ debugprintf("changing owner (group) or %s to %u.", mtpoint,
+ mip->mi_gid);
+ if (!norun)
+ if (chown(mtpoint, -1, mip->mi_gid) == -1)
+ err(1, "chown %s to %u (group)", mtpoint,
+ mip->mi_gid);
+ }
+}
+
+/*
+ * Put a filesystem on the memory disk.
+ */
+static void
+do_newfs(const char *args)
+{
+ int rv;
+
+ rv = run(NULL, "%s%s /dev/%s%dc", PATH_NEWFS, args, mdname, unit);
+ if (rv)
+ errx(1, "newfs exited with error code %d", rv);
+}
+
+/*
+ * 'str' should be a user and group name similar to the last argument
+ * to chown(1); i.e., a user, followed by a colon, followed by a
+ * group. The user and group in 'str' may be either a [ug]id or a
+ * name. Upon return, the uid and gid fields in 'mip' will contain
+ * the uid and gid of the user and group name in 'str', respectively.
+ *
+ * In other words, this derives a user and group id from a string
+ * formatted like the last argument to chown(1).
+ */
+static void
+extract_ugid(const char *str, struct mtpt_info *mip)
+{
+ char *ug; /* Writable 'str'. */
+ char *user, *group; /* Result of extracton. */
+ size_t strl; /* Length of 'str' incl. NULL. */
+ struct passwd *pw;
+ struct group *gr;
+ char *p;
+ uid_t *uid;
+ gid_t *gid;
+ size_t rv;
+
+ uid = &mip->mi_uid;
+ gid = &mip->mi_gid;
+ mip->mi_have_uid = mip->mi_have_gid = false;
+
+ /* Extract the user and group from 'str'. Format above. */
+ strl = strlen(str) + 1;
+ ug = malloc(strl);
+ assert(ug != NULL);
+ rv = strlcpy(ug, str, strl);
+ if (rv >= strl)
+ errx(1, "-w word too long (%d >= %d)", rv, strl);
+ group = ug;
+ user = strsep(&group, ":");
+ if (user == NULL || group == NULL || *user == '\0' || *group == '\0')
+ usage();
+
+ /* Derive uid. */
+ *uid = strtoul(user, &p, 10);
+ if ((unsigned)*uid == ULONG_MAX)
+ usage();
+ if (*p != '\0') {
+ pw = getpwnam(user);
+ if (pw == NULL)
+ errx(1, "invalid user: %s", user);
+ *uid = pw->pw_uid;
+ mip->mi_have_uid = true;
+ }
+
+ /* Derive gid. */
+ *gid = strtoul(group, &p, 10);
+ if ((unsigned)*gid == ULONG_MAX)
+ usage();
+ if (*p != '\0') {
+ gr = getgrnam(group);
+ if (gr == NULL)
+ errx(1, "invalid group: %s", group);
+ *gid = gr->gr_gid;
+ mip->mi_have_gid = true;
+ }
+
+ free(ug);
+ /*
+ * At this point we don't support only a username or only a
+ * group name. do_mtptsetup already does, so when this
+ * feature is desired, this is the only routine that needs to
+ * be changed.
+ */
+ assert(mip->mi_have_uid);
+ assert(mip->mi_have_gid);
+}
+
+/*
+ * Run a process with command name and arguments pointed to by the
+ * formatted string 'cmdline'. Since system(3) is not used, the first
+ * space-delimited token of 'cmdline' must be the full pathname of the
+ * program to run. The return value is the return code of the process
+ * spawned. If 'ofd' is non-NULL, it is set to the standard output of
+ * the program spawned (i.e., you can read from ofd and get the output
+ * of the program).
+ */
+static int
+run(int *ofd, const char *cmdline, ...)
+{
+ char **av, **avp; /* Result of splitting 'cmd'. */
+ int ac;
+ char *cmd; /* Expansion of 'cmdline'. */
+ int pid, status; /* Child info. */
+ int pfd[2]; /* Pipe to the child. */
+ int nfd; /* Null (/dev/null) file descriptor. */
+ bool dup2dn; /* Dup /dev/null to stdout? */
+ va_list ap;
+ char *p;
+ int rv, i;
+
+ dup2dn = true;
+ va_start(ap, cmdline);
+ rv = vasprintf(&cmd, cmdline, ap);
+ if (rv == -1)
+ err(1, "vasprintf");
+ va_end(ap);
+
+ /* Split up 'cmd' into 'av' for use with execve. */
+ for (ac = 1, p = cmd; (p = strchr(p, ' ')) != NULL; p++)
+ ac++; /* 'ac' generation loop. */
+ av = (char **)malloc(sizeof(*av) * (ac + 1));
+ assert(av != NULL);
+ for (p = cmd, avp = av; (*avp = strsep(&p, " ")) != NULL;)
+ if (**av != '\0')
+ if (++avp >= &av[ac]) {
+ *avp = NULL;
+ break;
+ }
+ assert(*av);
+
+ /* Make sure the above loop works as expected. */
+ if (debug) {
+ /*
+ * We can't, but should, use debugprintf here. First,
+ * it appends a trailing newline to the output, and
+ * second it prepends "DEBUG: " to the output. The
+ * former is a problem for this would-be first call,
+ * and the latter for the would-be call inside the
+ * loop.
+ */
+ (void)fprintf(stderr, "DEBUG: running:");
+ /* Should be equivilent to 'cmd' (before strsep, of course). */
+ for (i = 0; av[i] != NULL; i++)
+ (void)fprintf(stderr, " %s", av[i]);
+ (void)fprintf(stderr, "\n");
+ }
+
+ /* Create a pipe if necessary and fork the helper program. */
+ if (ofd != NULL) {
+ if (pipe(&pfd[0]) == -1)
+ err(1, "pipe");
+ *ofd = pfd[0];
+ dup2dn = false;
+ }
+ pid = fork();
+ switch (pid) {
+ case 0:
+ /* XXX can we call err() in here? */
+ if (norun)
+ _exit(0);
+ if (ofd != NULL)
+ if (dup2(pfd[1], STDOUT_FILENO) < 0)
+ err(1, "dup2");
+ if (!loudsubs) {
+ nfd = open(_PATH_DEVNULL, O_RDWR);
+ if (nfd == -1)
+ err(1, "open: %s", _PATH_DEVNULL);
+ if (dup2(nfd, STDIN_FILENO) < 0)
+ err(1, "dup2");
+ if (dup2dn)
+ if (dup2(nfd, STDOUT_FILENO) < 0)
+ err(1, "dup2");
+ if (dup2(nfd, STDERR_FILENO) < 0)
+ err(1, "dup2");
+ }
+
+ (void)execv(av[0], av);
+ warn("exec: %s", av[0]);
+ _exit(-1);
+ case -1:
+ err(1, "fork");
+ }
+
+ free(cmd);
+ free(av);
+ while (waitpid(pid, &status, 0) != pid)
+ ;
+ return (WEXITSTATUS(status));
+}
+
+static void
+usage(void)
+{
+
+ fprintf(stderr,
+"usage: %s [-DLMNSX] [-a maxcontig] [-b block-size] [-c cylinders]\n"
+"\t[-d rotdelay] [-e maxbpg] [-F file] [-f frag-size] [-i bytes]\n"
+"\t[-m percent-free] [-n rotational-positions] [-O optimization]\n"
+"\t[-o mount-options] [-p permissions] [-s size] [-w user:group]\n"
+"\tmd-device mount-point\n", getprogname());
+ exit(1);
+}
diff --git a/sbin/mdmfs/pathnames.h b/sbin/mdmfs/pathnames.h
new file mode 100644
index 0000000..d072cf2
--- /dev/null
+++ b/sbin/mdmfs/pathnames.h
@@ -0,0 +1,10 @@
+/* $FreeBSD$ */
+#ifndef MDMFS_PATHNAMES_H
+#define MDMFS_PATHNAMES_H
+
+#define PATH_MDCONFIG "/sbin/mdconfig"
+#define PATH_DISKLABEL "/sbin/disklabel"
+#define PATH_NEWFS "/sbin/newfs"
+#define PATH_MOUNT "/sbin/mount"
+
+#endif /* !MDMFS_PATHNAMES_H */
OpenPOWER on IntegriCloud