mdmfs.c revision 163952
147398Sdfr/* 247398Sdfr * Copyright (c) 2001 Dima Dorfman. 347398Sdfr * All rights reserved. 447398Sdfr * 547398Sdfr * Redistribution and use in source and binary forms, with or without 647398Sdfr * modification, are permitted provided that the following conditions 747398Sdfr * are met: 847398Sdfr * 1. Redistributions of source code must retain the above copyright 947398Sdfr * notice, this list of conditions and the following disclaimer. 1047398Sdfr * 2. Redistributions in binary form must reproduce the above copyright 1147398Sdfr * notice, this list of conditions and the following disclaimer in the 1247398Sdfr * documentation and/or other materials provided with the distribution. 1347398Sdfr * 1447398Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1547398Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1647398Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1747398Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1847398Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1947398Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2047398Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2147398Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2247398Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2347398Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2447398Sdfr * SUCH DAMAGE. 2547398Sdfr */ 2650477Speter 2747398Sdfr/* 2847398Sdfr * mdmfs (md/MFS) is a wrapper around mdconfig(8), 2947398Sdfr * newfs(8), and mount(8) that mimics the command line option set of 3047398Sdfr * the deprecated mount_mfs(8). 3147398Sdfr */ 3247398Sdfr 3347398Sdfr#include <sys/cdefs.h> 3447398Sdfr__FBSDID("$FreeBSD: head/sbin/mdmfs/mdmfs.c 163952 2006-11-03 12:02:24Z ru $"); 3547398Sdfr 3647398Sdfr#include <sys/param.h> 3747398Sdfr#include <sys/mdioctl.h> 3847398Sdfr#include <sys/stat.h> 3947398Sdfr#include <sys/wait.h> 4047398Sdfr 4147398Sdfr#include <assert.h> 4247398Sdfr#include <err.h> 4347398Sdfr#include <fcntl.h> 4447398Sdfr#include <grp.h> 4547398Sdfr#include <paths.h> 4647398Sdfr#include <pwd.h> 4747398Sdfr#include <stdarg.h> 4847398Sdfr#include <stdio.h> 4947398Sdfr#include <stdlib.h> 5047398Sdfr#include <string.h> 5147398Sdfr#include <unistd.h> 5247398Sdfr 5347398Sdfrtypedef enum { false, true } bool; 5447398Sdfr 5547398Sdfrstruct mtpt_info { 5647398Sdfr uid_t mi_uid; 5747398Sdfr bool mi_have_uid; 5847398Sdfr gid_t mi_gid; 5947398Sdfr bool mi_have_gid; 6047398Sdfr mode_t mi_mode; 6147398Sdfr bool mi_have_mode; 6247398Sdfr}; 6347398Sdfr 6447398Sdfrstatic bool debug; /* Emit debugging information? */ 6547398Sdfrstatic bool loudsubs; /* Suppress output from helper programs? */ 6647398Sdfrstatic bool norun; /* Actually run the helper programs? */ 6747398Sdfrstatic int unit; /* The unit we're working with. */ 6847398Sdfrstatic const char *mdname; /* Name of memory disk device (e.g., "md"). */ 6947398Sdfrstatic size_t mdnamelen; /* Length of mdname. */ 7047398Sdfrstatic const char *path_mdconfig =_PATH_MDCONFIG; 7147398Sdfr 7247398Sdfrstatic void argappend(char **, const char *, ...) __printflike(2, 3); 7347398Sdfrstatic void debugprintf(const char *, ...) __printflike(1, 2); 7447398Sdfrstatic void do_mdconfig_attach(const char *, const enum md_types); 7547398Sdfrstatic void do_mdconfig_attach_au(const char *, const enum md_types); 7647398Sdfrstatic void do_mdconfig_detach(void); 7747398Sdfrstatic void do_mount(const char *, const char *); 7847398Sdfrstatic void do_mtptsetup(const char *, struct mtpt_info *); 7962987Sjhbstatic void do_newfs(const char *); 8062987Sjhbstatic void extract_ugid(const char *, struct mtpt_info *); 8169774Sphkstatic int run(int *, const char *, ...) __printflike(2, 3); 8247398Sdfrstatic void usage(void); 8347398Sdfr 8453094Sdfrint 8547398Sdfrmain(int argc, char **argv) 8647398Sdfr{ 8747398Sdfr struct mtpt_info mi; /* Mountpoint info. */ 8847398Sdfr char *mdconfig_arg, *newfs_arg, /* Args to helper programs. */ 8947398Sdfr *mount_arg; 9047398Sdfr enum md_types mdtype; /* The type of our memory disk. */ 9147398Sdfr bool have_mdtype; 9247398Sdfr bool detach, softdep, autounit, newfs; 9347398Sdfr char *mtpoint, *unitstr; 9447398Sdfr char *p; 9588376Stmm int ch; 9653094Sdfr void *set; 9747398Sdfr unsigned long ul; 9847398Sdfr 9947398Sdfr /* Misc. initialization. */ 10047398Sdfr (void)memset(&mi, '\0', sizeof(mi)); 10147398Sdfr detach = true; 10247398Sdfr softdep = true; 10347398Sdfr autounit = false; 10447398Sdfr newfs = true; 10550769Sdfr have_mdtype = false; 10647398Sdfr mdtype = MD_SWAP; 10747398Sdfr mdname = MD_NAME; 10847398Sdfr mdnamelen = strlen(mdname); 10947398Sdfr /* 11047398Sdfr * Can't set these to NULL. They may be passed to the 11147398Sdfr * respective programs without modification. I.e., we may not 11250769Sdfr * receive any command-line options which will caused them to 11350769Sdfr * be modified. 11450769Sdfr */ 11550769Sdfr mdconfig_arg = strdup(""); 11650769Sdfr newfs_arg = strdup(""); 11750769Sdfr mount_arg = strdup(""); 11850769Sdfr 11950769Sdfr /* If we were started as mount_mfs or mfs, imply -C. */ 12050769Sdfr if (strcmp(getprogname(), "mount_mfs") == 0 || 12150769Sdfr strcmp(getprogname(), "mfs") == 0) { 12250769Sdfr /* Make compatibility assumptions. */ 12350769Sdfr mi.mi_mode = 01777; 12450769Sdfr mi.mi_have_mode = true; 12550769Sdfr } 12650769Sdfr 12750769Sdfr while ((ch = getopt(argc, argv, 12852174Sdfr "a:b:Cc:Dd:E:e:F:f:hi:LlMm:Nn:O:o:Pp:Ss:t:Uv:w:X")) != -1) 12950769Sdfr switch (ch) { 13050769Sdfr case 'a': 13150769Sdfr argappend(&newfs_arg, "-a %s", optarg); 13250769Sdfr break; 13350769Sdfr case 'b': 13450769Sdfr argappend(&newfs_arg, "-b %s", optarg); 13550769Sdfr break; 13683051Syokota case 'C': 13783051Syokota /* Ignored for compatibility. */ 13883051Syokota break; 13983051Syokota case 'c': 14083051Syokota argappend(&newfs_arg, "-c %s", optarg); 14183051Syokota break; 14283051Syokota case 'D': 14383051Syokota detach = false; 14483051Syokota break; 14583051Syokota case 'd': 14683051Syokota argappend(&newfs_arg, "-d %s", optarg); 14783051Syokota break; 14850769Sdfr case 'E': 14950769Sdfr path_mdconfig = optarg; 15050769Sdfr break; 15150769Sdfr case 'e': 15250769Sdfr argappend(&newfs_arg, "-e %s", optarg); 15352174Sdfr break; 15450769Sdfr case 'F': 15550769Sdfr if (have_mdtype) 15650769Sdfr usage(); 15757132Smsmith mdtype = MD_VNODE; 15850769Sdfr have_mdtype = true; 15950769Sdfr argappend(&mdconfig_arg, "-f %s", optarg); 16050769Sdfr break; 16150769Sdfr case 'f': 16250769Sdfr argappend(&newfs_arg, "-f %s", optarg); 16350769Sdfr break; 16450769Sdfr case 'h': 16550769Sdfr usage(); 16650769Sdfr break; 16750769Sdfr case 'i': 16850769Sdfr argappend(&newfs_arg, "-i %s", optarg); 16950769Sdfr break; 17050769Sdfr case 'L': 17150769Sdfr loudsubs = true; 17250769Sdfr break; 17350769Sdfr case 'l': 17450769Sdfr argappend(&newfs_arg, "-l"); 17550769Sdfr break; 17650769Sdfr case 'M': 17750769Sdfr if (have_mdtype) 17850769Sdfr usage(); 17950769Sdfr mdtype = MD_MALLOC; 18050769Sdfr have_mdtype = true; 18150769Sdfr break; 18250769Sdfr case 'm': 18350769Sdfr argappend(&newfs_arg, "-m %s", optarg); 18450769Sdfr break; 18550769Sdfr case 'N': 18650769Sdfr norun = true; 18750769Sdfr break; 18850769Sdfr case 'n': 18950769Sdfr argappend(&newfs_arg, "-n %s", optarg); 19050769Sdfr break; 19150769Sdfr case 'O': 19250769Sdfr argappend(&newfs_arg, "-o %s", optarg); 19350769Sdfr break; 19450769Sdfr case 'o': 19550769Sdfr argappend(&mount_arg, "-o %s", optarg); 19650769Sdfr break; 19750769Sdfr case 'P': 19850769Sdfr newfs = false; 19950769Sdfr break; 20050769Sdfr case 'p': 20150769Sdfr if ((set = setmode(optarg)) == NULL) 20250769Sdfr usage(); 20352174Sdfr mi.mi_mode = getmode(set, S_IRWXU | S_IRWXG | S_IRWXO); 20450769Sdfr mi.mi_have_mode = true; 20550769Sdfr free(set); 20650769Sdfr break; 20750769Sdfr case 'S': 20850769Sdfr softdep = false; 20950769Sdfr break; 21050769Sdfr case 's': 21183051Syokota argappend(&mdconfig_arg, "-s %s", optarg); 21283051Syokota break; 21383051Syokota case 'U': 21483051Syokota softdep = true; 21583051Syokota break; 21683051Syokota case 'v': 21783051Syokota argappend(&newfs_arg, "-O %s", optarg); 21883051Syokota break; 21983051Syokota case 'w': 22083051Syokota extract_ugid(optarg, &mi); 22183051Syokota break; 22283051Syokota case 'X': 22350769Sdfr debug = true; 22450769Sdfr break; 22550769Sdfr default: 22650769Sdfr usage(); 22750769Sdfr } 22852174Sdfr argc -= optind; 22950769Sdfr argv += optind; 23050769Sdfr if (argc < 2) 23150769Sdfr usage(); 23257132Smsmith 23350769Sdfr /* Derive 'unit' (global). */ 23450769Sdfr unitstr = argv[0]; 23550769Sdfr if (strncmp(unitstr, "/dev/", 5) == 0) 23650769Sdfr unitstr += 5; 23750769Sdfr if (strncmp(unitstr, mdname, mdnamelen) == 0) 23850769Sdfr unitstr += mdnamelen; 23950769Sdfr if (*unitstr == '\0') { 24050769Sdfr autounit = true; 24150769Sdfr unit = -1; 24250769Sdfr } else { 24350769Sdfr ul = strtoul(unitstr, &p, 10); 24450769Sdfr if (ul == ULONG_MAX || *p != '\0') 24550769Sdfr errx(1, "bad device unit: %s", unitstr); 24650769Sdfr unit = ul; 24750769Sdfr } 24850769Sdfr 24950769Sdfr mtpoint = argv[1]; 25050769Sdfr if (!have_mdtype) 25150769Sdfr mdtype = MD_SWAP; 25250769Sdfr if (softdep) 25350769Sdfr argappend(&newfs_arg, "-U"); 25450769Sdfr if (mdtype != MD_VNODE && !newfs) 25550769Sdfr errx(1, "-P requires a vnode-backed disk"); 25650769Sdfr 25750769Sdfr /* Do the work. */ 25850769Sdfr if (detach && !autounit) 25950769Sdfr do_mdconfig_detach(); 26050769Sdfr if (autounit) 26150769Sdfr do_mdconfig_attach_au(mdconfig_arg, mdtype); 26250769Sdfr else 26350769Sdfr do_mdconfig_attach(mdconfig_arg, mdtype); 26450769Sdfr if (newfs) 26550769Sdfr do_newfs(newfs_arg); 26650769Sdfr do_mount(mount_arg, mtpoint); 26750769Sdfr do_mtptsetup(mtpoint, &mi); 26850769Sdfr 26950769Sdfr return (0); 27050769Sdfr} 27150769Sdfr 27250769Sdfr/* 27350769Sdfr * Append the expansion of 'fmt' to the buffer pointed to by '*dstp'; 27450769Sdfr * reallocate as required. 27550769Sdfr */ 27650769Sdfrstatic void 27750769Sdfrargappend(char **dstp, const char *fmt, ...) 27850769Sdfr{ 27950769Sdfr char *old, *new; 28050769Sdfr va_list ap; 28150769Sdfr 28250769Sdfr old = *dstp; 28350769Sdfr assert(old != NULL); 28450769Sdfr 28550769Sdfr va_start(ap, fmt); 28650769Sdfr if (vasprintf(&new, fmt,ap) == -1) 28750769Sdfr errx(1, "vasprintf"); 28850769Sdfr va_end(ap); 28950769Sdfr 29050769Sdfr *dstp = new; 29150769Sdfr if (asprintf(&new, "%s %s", old, new) == -1) 29250769Sdfr errx(1, "asprintf"); 29350769Sdfr free(*dstp); 29450769Sdfr free(old); 29550769Sdfr 29650769Sdfr *dstp = new; 29750769Sdfr} 29850769Sdfr 29950769Sdfr/* 30050769Sdfr * If run-time debugging is enabled, print the expansion of 'fmt'. 30152174Sdfr * Otherwise, do nothing. 30250769Sdfr */ 30350769Sdfrstatic void 30450769Sdfrdebugprintf(const char *fmt, ...) 30550769Sdfr{ 30650769Sdfr va_list ap; 30750769Sdfr 30850769Sdfr if (!debug) 30950769Sdfr return; 31083051Syokota fprintf(stderr, "DEBUG: "); 31183051Syokota va_start(ap, fmt); 31283051Syokota vfprintf(stderr, fmt, ap); 31383051Syokota va_end(ap); 31483051Syokota fprintf(stderr, "\n"); 31583051Syokota fflush(stderr); 31683051Syokota} 31750769Sdfr 31850769Sdfr/* 31950769Sdfr * Attach a memory disk with a known unit. 32052174Sdfr */ 32150769Sdfrstatic void 32250769Sdfrdo_mdconfig_attach(const char *args, const enum md_types mdtype) 32350769Sdfr{ 32457132Smsmith int rv; 32550769Sdfr const char *ta; /* Type arg. */ 32650769Sdfr 32750769Sdfr switch (mdtype) { 32850769Sdfr case MD_SWAP: 32950769Sdfr ta = "-t swap"; 33050769Sdfr break; 33150769Sdfr case MD_VNODE: 33250769Sdfr ta = "-t vnode"; 33350769Sdfr break; 33450769Sdfr case MD_MALLOC: 33550769Sdfr ta = "-t malloc"; 33650769Sdfr break; 33750769Sdfr default: 33850769Sdfr abort(); 33950769Sdfr } 34050769Sdfr rv = run(NULL, "%s -a %s%s -u %s%d", path_mdconfig, ta, args, 34150769Sdfr mdname, unit); 34250769Sdfr if (rv) 34350769Sdfr errx(1, "mdconfig (attach) exited with error code %d", rv); 34450769Sdfr} 34550769Sdfr 34650769Sdfr/* 34750769Sdfr * Attach a memory disk with an unknown unit; use autounit. 34850769Sdfr */ 34950769Sdfrstatic void 35050769Sdfrdo_mdconfig_attach_au(const char *args, const enum md_types mdtype) 35150769Sdfr{ 35250769Sdfr const char *ta; /* Type arg. */ 35350769Sdfr char *linep, *linebuf; /* Line pointer, line buffer. */ 35450769Sdfr int fd; /* Standard output of mdconfig invocation. */ 35550769Sdfr FILE *sfd; 35650769Sdfr int rv; 35750769Sdfr char *p; 35850769Sdfr size_t linelen; 35950769Sdfr unsigned long ul; 36050769Sdfr 36150769Sdfr switch (mdtype) { 36250769Sdfr case MD_SWAP: 36350769Sdfr ta = "-t swap"; 36450769Sdfr break; 36550769Sdfr case MD_VNODE: 36650769Sdfr ta = "-t vnode"; 36752174Sdfr break; 36850769Sdfr case MD_MALLOC: 36950769Sdfr ta = "-t malloc"; 37050769Sdfr break; 37150769Sdfr default: 37250769Sdfr abort(); 37350769Sdfr } 37450769Sdfr rv = run(&fd, "%s -a %s%s", path_mdconfig, ta, args); 37550769Sdfr if (rv) 37683051Syokota errx(1, "mdconfig (attach) exited with error code %d", rv); 37783051Syokota 37883051Syokota /* Receive the unit number. */ 37983051Syokota if (norun) { /* Since we didn't run, we can't read. Fake it. */ 38083051Syokota unit = 0; 38183051Syokota return; 38283051Syokota } 38350769Sdfr sfd = fdopen(fd, "r"); 38450769Sdfr if (sfd == NULL) 38550769Sdfr err(1, "fdopen"); 38652174Sdfr linep = fgetln(sfd, &linelen); 38750769Sdfr if (linep == NULL && linelen < mdnamelen + 1) 38850769Sdfr errx(1, "unexpected output from mdconfig (attach)"); 38950769Sdfr /* If the output format changes, we want to know about it. */ 39057132Smsmith assert(strncmp(linep, mdname, mdnamelen) == 0); 39150769Sdfr linebuf = malloc(linelen - mdnamelen + 1); 39250769Sdfr assert(linebuf != NULL); 39350769Sdfr /* Can't use strlcpy because linep is not NULL-terminated. */ 39450769Sdfr strncpy(linebuf, linep + mdnamelen, linelen); 39550769Sdfr linebuf[linelen] = '\0'; 39650769Sdfr ul = strtoul(linebuf, &p, 10); 39750769Sdfr if (ul == ULONG_MAX || *p != '\n') 39850769Sdfr errx(1, "unexpected output from mdconfig (attach)"); 39950769Sdfr unit = ul; 40050769Sdfr 40150769Sdfr fclose(sfd); 40250769Sdfr close(fd); 40350769Sdfr} 40450769Sdfr 40550769Sdfr/* 40650769Sdfr * Detach a memory disk. 40750769Sdfr */ 40850769Sdfrstatic void 40950769Sdfrdo_mdconfig_detach(void) 41050769Sdfr{ 41150769Sdfr int rv; 41250769Sdfr 41350769Sdfr rv = run(NULL, "%s -d -u %s%d", path_mdconfig, mdname, unit); 41450769Sdfr if (rv && debug) /* This is allowed to fail. */ 41550769Sdfr warnx("mdconfig (detach) exited with error code %d (ignored)", 41650769Sdfr rv); 41750769Sdfr} 41850769Sdfr 41950769Sdfr/* 42050769Sdfr * Mount the configured memory disk. 42150769Sdfr */ 42250769Sdfrstatic void 42350769Sdfrdo_mount(const char *args, const char *mtpoint) 42450769Sdfr{ 42581401Sjulian int rv; 42691206Salfred 42791206Salfred rv = run(NULL, "%s%s /dev/%s%d %s", _PATH_MOUNT, args, 42891206Salfred mdname, unit, mtpoint); 42981401Sjulian if (rv) 43081401Sjulian errx(1, "mount exited with error code %d", rv); 43181401Sjulian} 43250769Sdfr 43391202Salfred/* 43481401Sjulian * Various configuration of the mountpoint. Mostly, enact 'mip'. 43550769Sdfr */ 43691202Salfredstatic void 43781401Sjuliando_mtptsetup(const char *mtpoint, struct mtpt_info *mip) 43850769Sdfr{ 43991202Salfred 44081401Sjulian if (mip->mi_have_mode) { 44150769Sdfr debugprintf("changing mode of %s to %o.", mtpoint, 44291202Salfred mip->mi_mode); 44381401Sjulian if (!norun) 44450769Sdfr if (chmod(mtpoint, mip->mi_mode) == -1) 44550769Sdfr err(1, "chmod: %s", mtpoint); 44650769Sdfr } 44750769Sdfr /* 44850769Sdfr * We have to do these separately because the user may have 44950769Sdfr * only specified one of them. 45091202Salfred */ 45150769Sdfr if (mip->mi_have_uid) { 45250769Sdfr debugprintf("changing owner (user) or %s to %u.", mtpoint, 45381401Sjulian mip->mi_uid); 45481401Sjulian if (!norun) 45550769Sdfr if (chown(mtpoint, mip->mi_uid, -1) == -1) 45650769Sdfr err(1, "chown %s to %u (user)", mtpoint, 45750769Sdfr mip->mi_uid); 45850769Sdfr } 45950769Sdfr if (mip->mi_have_gid) { 46050769Sdfr debugprintf("changing owner (group) or %s to %u.", mtpoint, 46150769Sdfr mip->mi_gid); 46262987Sjhb if (!norun) 46391202Salfred if (chown(mtpoint, -1, mip->mi_gid) == -1) 46462987Sjhb err(1, "chown %s to %u (group)", mtpoint, 46562987Sjhb mip->mi_gid); 46681401Sjulian } 46750769Sdfr} 46881401Sjulian 46950769Sdfr/* 47050769Sdfr * Put a file system on the memory disk. 47181401Sjulian */ 47250769Sdfrstatic void 47350769Sdfrdo_newfs(const char *args) 47450769Sdfr{ 47550769Sdfr int rv; 47683051Syokota 47783051Syokota rv = run(NULL, "%s%s /dev/%s%d", _PATH_NEWFS, args, mdname, unit); 47883051Syokota if (rv) 47983051Syokota errx(1, "newfs exited with error code %d", rv); 48083051Syokota} 48183051Syokota 48283051Syokota/* 48383051Syokota * 'str' should be a user and group name similar to the last argument 48483051Syokota * to chown(1); i.e., a user, followed by a colon, followed by a 48583051Syokota * group. The user and group in 'str' may be either a [ug]id or a 48683051Syokota * name. Upon return, the uid and gid fields in 'mip' will contain 48783051Syokota * the uid and gid of the user and group name in 'str', respectively. 48883051Syokota * 48983051Syokota * In other words, this derives a user and group id from a string 49083051Syokota * formatted like the last argument to chown(1). 49183051Syokota * 49283051Syokota * Notice: At this point we don't support only a username or only a 49383051Syokota * group name. do_mtptsetup already does, so when this feature is 49483051Syokota * desired, this is the only routine that needs to be changed. 49583051Syokota */ 49683051Syokotastatic void 49783051Syokotaextract_ugid(const char *str, struct mtpt_info *mip) 49883051Syokota{ 49983051Syokota char *ug; /* Writable 'str'. */ 50083051Syokota char *user, *group; /* Result of extracton. */ 50183051Syokota struct passwd *pw; 50283051Syokota struct group *gr; 50383051Syokota char *p; 50483051Syokota uid_t *uid; 50583051Syokota gid_t *gid; 50683051Syokota 50783051Syokota uid = &mip->mi_uid; 50883051Syokota gid = &mip->mi_gid; 50983051Syokota mip->mi_have_uid = mip->mi_have_gid = false; 51083051Syokota 51183051Syokota /* Extract the user and group from 'str'. Format above. */ 51283051Syokota ug = strdup(str); 51383051Syokota assert(ug != NULL); 51483051Syokota group = ug; 51583051Syokota user = strsep(&group, ":"); 51683051Syokota if (user == NULL || group == NULL || *user == '\0' || *group == '\0') 51783051Syokota usage(); 51883051Syokota 51983051Syokota /* Derive uid. */ 52083051Syokota *uid = strtoul(user, &p, 10); 52183051Syokota if (*uid == (uid_t)ULONG_MAX) 52283051Syokota usage(); 52383051Syokota if (*p != '\0') { 52483051Syokota pw = getpwnam(user); 52550769Sdfr if (pw == NULL) 52650769Sdfr errx(1, "invalid user: %s", user); 52750769Sdfr *uid = pw->pw_uid; 52850769Sdfr } 52950769Sdfr mip->mi_have_uid = true; 53050769Sdfr 53181401Sjulian /* Derive gid. */ 53250769Sdfr *gid = strtoul(group, &p, 10); 53350769Sdfr if (*gid == (gid_t)ULONG_MAX) 53453094Sdfr usage(); 53553094Sdfr if (*p != '\0') { 53653094Sdfr gr = getgrnam(group); 53753094Sdfr if (gr == NULL) 53853094Sdfr errx(1, "invalid group: %s", group); 53950769Sdfr *gid = gr->gr_gid; 54050769Sdfr } 54150769Sdfr mip->mi_have_gid = true; 54250769Sdfr 54351905Sdfr free(ug); 54451905Sdfr} 54551905Sdfr 54653094Sdfr/* 54753094Sdfr * Run a process with command name and arguments pointed to by the 54881401Sjulian * formatted string 'cmdline'. Since system(3) is not used, the first 54981401Sjulian * space-delimited token of 'cmdline' must be the full pathname of the 55081401Sjulian * program to run. The return value is the return code of the process 55181401Sjulian * spawned. If 'ofd' is non-NULL, it is set to the standard output of 55281401Sjulian * the program spawned (i.e., you can read from ofd and get the output 55381401Sjulian * of the program). 55481401Sjulian */ 55551905Sdfrstatic int 55651905Sdfrrun(int *ofd, const char *cmdline, ...) 55751905Sdfr{ 55851905Sdfr char **argv, **argvp; /* Result of splitting 'cmd'. */ 55981401Sjulian int argc; 56051905Sdfr char *cmd; /* Expansion of 'cmdline'. */ 56181401Sjulian int pid, status; /* Child info. */ 56251905Sdfr int pfd[2]; /* Pipe to the child. */ 56351905Sdfr int nfd; /* Null (/dev/null) file descriptor. */ 56481401Sjulian bool dup2dn; /* Dup /dev/null to stdout? */ 56581401Sjulian va_list ap; 56651905Sdfr char *p; 56751905Sdfr int rv, i; 56850769Sdfr 56950769Sdfr dup2dn = true; 57053094Sdfr va_start(ap, cmdline); 57153094Sdfr rv = vasprintf(&cmd, cmdline, ap); 57250769Sdfr if (rv == -1) 57350769Sdfr err(1, "vasprintf"); 57450769Sdfr va_end(ap); 57550769Sdfr 57650769Sdfr /* Split up 'cmd' into 'argv' for use with execve. */ 57750769Sdfr for (argc = 1, p = cmd; (p = strchr(p, ' ')) != NULL; p++) 57850769Sdfr argc++; /* 'argc' generation loop. */ 57950769Sdfr argv = (char **)malloc(sizeof(*argv) * (argc + 1)); 58050769Sdfr assert(argv != NULL); 58150769Sdfr for (p = cmd, argvp = argv; (*argvp = strsep(&p, " ")) != NULL;) 58250769Sdfr if (**argv != '\0') 58351905Sdfr if (++argvp >= &argv[argc]) { 58450769Sdfr *argvp = NULL; 58553094Sdfr break; 58653094Sdfr } 58750769Sdfr assert(*argv); 58850769Sdfr 58950769Sdfr /* Make sure the above loop works as expected. */ 59050769Sdfr if (debug) { 59150769Sdfr /* 59250769Sdfr * We can't, but should, use debugprintf here. First, 59350769Sdfr * it appends a trailing newline to the output, and 59450769Sdfr * second it prepends "DEBUG: " to the output. The 59552174Sdfr * former is a problem for this would-be first call, 59650769Sdfr * and the latter for the would-be call inside the 59750769Sdfr * loop. 59850769Sdfr */ 59950769Sdfr (void)fprintf(stderr, "DEBUG: running:"); 60050769Sdfr /* Should be equivilent to 'cmd' (before strsep, of course). */ 60150769Sdfr for (i = 0; argv[i] != NULL; i++) 60250769Sdfr (void)fprintf(stderr, " %s", argv[i]); 60350769Sdfr (void)fprintf(stderr, "\n"); 60452174Sdfr } 60550769Sdfr 60650769Sdfr /* Create a pipe if necessary and fork the helper program. */ 60752174Sdfr if (ofd != NULL) { 60850769Sdfr if (pipe(&pfd[0]) == -1) 60950769Sdfr err(1, "pipe"); 61062059Sdfr *ofd = pfd[0]; 61150769Sdfr dup2dn = false; 61250769Sdfr } 61350769Sdfr pid = fork(); 61450769Sdfr switch (pid) { 61550769Sdfr case 0: 61650769Sdfr /* XXX can we call err() in here? */ 61753094Sdfr if (norun) 61853094Sdfr _exit(0); 61950769Sdfr if (ofd != NULL) 62050769Sdfr if (dup2(pfd[1], STDOUT_FILENO) < 0) 62150769Sdfr err(1, "dup2"); 62247398Sdfr if (!loudsubs) { 62347398Sdfr nfd = open(_PATH_DEVNULL, O_RDWR); 62447398Sdfr if (nfd == -1) 62547578Sdfr err(1, "open: %s", _PATH_DEVNULL); 62647398Sdfr if (dup2(nfd, STDIN_FILENO) < 0) 62754073Smdodd err(1, "dup2"); 62847398Sdfr if (dup2dn) 62947398Sdfr if (dup2(nfd, STDOUT_FILENO) < 0) 630104179Sphk err(1, "dup2"); 631104179Sphk if (dup2(nfd, STDERR_FILENO) < 0) 632104179Sphk err(1, "dup2"); 633104179Sphk } 63469781Sdwmalone 63547398Sdfr (void)execv(argv[0], argv); 63647398Sdfr warn("exec: %s", argv[0]); 63747398Sdfr _exit(-1); 63847398Sdfr case -1: 63950769Sdfr err(1, "fork"); 64047398Sdfr } 641104179Sphk 64254073Smdodd free(cmd); 643104179Sphk free(argv); 64447398Sdfr while (waitpid(pid, &status, 0) != pid) 64547398Sdfr ; 64662059Sdfr return (WEXITSTATUS(status)); 64762059Sdfr} 64847398Sdfr 64947398Sdfrstatic void 65047398Sdfrusage(void) 65149195Smdodd{ 65247398Sdfr 65351052Sdfr fprintf(stderr, 65449195Smdodd"usage: %s [-DLlMNPSUX] [-a maxcontig] [-b block-size] [-c cylinders]\n" 65547398Sdfr"\t[-d rotdelay] [-E path-mdconfig] [-e maxbpg] [-F file] [-f frag-size]\n" 65688376Stmm"\t[-i bytes] [-m percent-free] [-n rotational-positions] [-O optimization]\n" 65788376Stmm"\t[-o mount-options] [-p permissions] [-s size] [-v version]\n" 65888376Stmm"\t[-w user:group] md-device mount-point\n", getprogname()); 65988376Stmm exit(1); 66051052Sdfr} 66151052Sdfr