diff options
-rw-r--r-- | sbin/mdmfs/Makefile | 7 | ||||
-rw-r--r-- | sbin/mdmfs/mdmfs.8 | 262 | ||||
-rw-r--r-- | sbin/mdmfs/mdmfs.c | 651 | ||||
-rw-r--r-- | sbin/mdmfs/pathnames.h | 10 |
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 */ |