mdmfs.c revision 141611
178447Sdd/* 280607Sdd * Copyright (c) 2001 Dima Dorfman. 378447Sdd * All rights reserved. 478447Sdd * 578447Sdd * Redistribution and use in source and binary forms, with or without 678447Sdd * modification, are permitted provided that the following conditions 778447Sdd * are met: 878447Sdd * 1. Redistributions of source code must retain the above copyright 978447Sdd * notice, this list of conditions and the following disclaimer. 1078447Sdd * 2. Redistributions in binary form must reproduce the above copyright 1178447Sdd * notice, this list of conditions and the following disclaimer in the 1278447Sdd * documentation and/or other materials provided with the distribution. 1378447Sdd * 1478447Sdd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1578447Sdd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1678447Sdd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1778447Sdd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1878447Sdd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1978447Sdd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2078447Sdd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2178447Sdd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2278447Sdd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2378447Sdd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2478447Sdd * SUCH DAMAGE. 2578447Sdd */ 2678447Sdd 2778447Sdd/* 28103798Sphk * mdmfs (md/MFS) is a wrapper around mdconfig(8), 2978447Sdd * newfs(8), and mount(8) that mimics the command line option set of 3078447Sdd * the deprecated mount_mfs(8). 3178447Sdd */ 3278447Sdd 33114589Sobrien#include <sys/cdefs.h> 34114589Sobrien__FBSDID("$FreeBSD: head/sbin/mdmfs/mdmfs.c 141611 2005-02-10 09:19:34Z ru $"); 3578447Sdd 3678447Sdd#include <sys/param.h> 3778447Sdd#include <sys/mdioctl.h> 3878447Sdd#include <sys/stat.h> 3978447Sdd#include <sys/wait.h> 4078447Sdd 4178447Sdd#include <assert.h> 4278447Sdd#include <err.h> 4378447Sdd#include <fcntl.h> 4478447Sdd#include <grp.h> 4578447Sdd#include <paths.h> 4678447Sdd#include <pwd.h> 4778447Sdd#include <stdarg.h> 4878447Sdd#include <stdio.h> 4978447Sdd#include <stdlib.h> 5078447Sdd#include <string.h> 5178447Sdd#include <unistd.h> 5278447Sdd 5378447Sddtypedef enum { false, true } bool; 5478447Sdd 5578447Sddstruct mtpt_info { 5678447Sdd uid_t mi_uid; 5778447Sdd bool mi_have_uid; 5878447Sdd gid_t mi_gid; 5978447Sdd bool mi_have_gid; 6078447Sdd mode_t mi_mode; 6178447Sdd bool mi_have_mode; 6278447Sdd}; 6378447Sdd 6481742Sddstatic bool compat; /* Full compatibility with mount_mfs? */ 6578447Sddstatic bool debug; /* Emit debugging information? */ 6678447Sddstatic bool loudsubs; /* Suppress output from helper programs? */ 6778447Sddstatic bool norun; /* Actually run the helper programs? */ 6878447Sddstatic int unit; /* The unit we're working with. */ 6978447Sddstatic const char *mdname; /* Name of memory disk device (e.g., "md"). */ 7078447Sddstatic size_t mdnamelen; /* Length of mdname. */ 7178447Sdd 7279052Skrisstatic void argappend(char **, const char *, ...) __printflike(2, 3); 7379052Skrisstatic void debugprintf(const char *, ...) __printflike(1, 2); 7478447Sddstatic void do_mdconfig_attach(const char *, const enum md_types); 7578447Sddstatic void do_mdconfig_attach_au(const char *, const enum md_types); 7678447Sddstatic void do_mdconfig_detach(void); 7778447Sddstatic void do_mount(const char *, const char *); 7878447Sddstatic void do_mtptsetup(const char *, struct mtpt_info *); 7978447Sddstatic void do_newfs(const char *); 8078447Sddstatic void extract_ugid(const char *, struct mtpt_info *); 8179052Skrisstatic int run(int *, const char *, ...) __printflike(2, 3); 8278447Sddstatic void usage(void); 8378447Sdd 8478447Sddint 8581628Sobrienmain(int argc, char **argv) 8678447Sdd{ 8778447Sdd struct mtpt_info mi; /* Mountpoint info. */ 8878447Sdd char *mdconfig_arg, *newfs_arg, /* Args to helper programs. */ 8978447Sdd *mount_arg; 9078447Sdd enum md_types mdtype; /* The type of our memory disk. */ 9178447Sdd bool have_mdtype; 9278447Sdd bool detach, softdep, autounit; 9378447Sdd char *mtpoint, *unitstr; 94124830Sgrehan char *p; 95124830Sgrehan int ch; 96118500Syar void *set; 97141082Sssouhlal unsigned long ul; 9878447Sdd 9978447Sdd /* Misc. initialization. */ 10078447Sdd (void)memset(&mi, '\0', sizeof(mi)); 10178447Sdd detach = true; 10278447Sdd softdep = true; 10378447Sdd autounit = false; 10478447Sdd have_mdtype = false; 105140815Sssouhlal mdtype = MD_SWAP; 10678447Sdd mdname = MD_NAME; 10778447Sdd mdnamelen = strlen(mdname); 10878447Sdd /* 10978447Sdd * Can't set these to NULL. They may be passed to the 11078447Sdd * respective programs without modification. I.e., we may not 11178447Sdd * receive any command-line options which will caused them to 11278447Sdd * be modified. 11378447Sdd */ 11478447Sdd mdconfig_arg = strdup(""); 11578447Sdd newfs_arg = strdup(""); 11678447Sdd mount_arg = strdup(""); 11778447Sdd 11884167Siedowse /* If we were started as mount_mfs or mfs, imply -C. */ 11984167Siedowse if (strcmp(getprogname(), "mount_mfs") == 0 || 12084167Siedowse strcmp(getprogname(), "mfs") == 0) 12181742Sdd compat = true; 12281742Sdd 12381628Sobrien while ((ch = getopt(argc, argv, 124126255Srwatson "a:b:Cc:Dd:e:F:f:hi:LlMm:Nn:O:o:p:Ss:t:Uv:w:X")) != -1) 12578447Sdd switch (ch) { 12678447Sdd case 'a': 12778447Sdd argappend(&newfs_arg, "-a %s", optarg); 12878447Sdd break; 12978447Sdd case 'b': 13078447Sdd argappend(&newfs_arg, "-b %s", optarg); 13178447Sdd break; 13281742Sdd case 'C': 13381742Sdd if (compat) 13481742Sdd usage(); 13581742Sdd compat = true; 13681742Sdd break; 13778447Sdd case 'c': 13878447Sdd argappend(&newfs_arg, "-c %s", optarg); 13978447Sdd break; 14078447Sdd case 'D': 14181742Sdd if (compat) 14281742Sdd usage(); 14378447Sdd detach = false; 14478447Sdd break; 14578447Sdd case 'd': 14678447Sdd argappend(&newfs_arg, "-d %s", optarg); 14778447Sdd break; 14878447Sdd case 'e': 14978447Sdd argappend(&newfs_arg, "-e %s", optarg); 15078447Sdd break; 15178447Sdd case 'F': 15278447Sdd if (have_mdtype) 15378447Sdd usage(); 15478447Sdd mdtype = MD_VNODE; 15578447Sdd have_mdtype = true; 15678447Sdd argappend(&mdconfig_arg, "-f %s", optarg); 15778447Sdd break; 15878447Sdd case 'f': 15978447Sdd argappend(&newfs_arg, "-f %s", optarg); 16078447Sdd break; 16178447Sdd case 'h': 16278447Sdd usage(); 16378447Sdd break; 16478447Sdd case 'i': 16578447Sdd argappend(&newfs_arg, "-i %s", optarg); 16678447Sdd break; 16778447Sdd case 'L': 16881742Sdd if (compat) 16981742Sdd usage(); 17078447Sdd loudsubs = true; 17178447Sdd break; 172126255Srwatson case 'l': 173126255Srwatson argappend(&newfs_arg, "-l"); 174126255Srwatson break; 17578447Sdd case 'M': 17678447Sdd if (have_mdtype) 17778447Sdd usage(); 17878447Sdd mdtype = MD_MALLOC; 17978447Sdd have_mdtype = true; 18078447Sdd break; 18178447Sdd case 'm': 18278447Sdd argappend(&newfs_arg, "-m %s", optarg); 18378447Sdd break; 18478447Sdd case 'N': 18581742Sdd if (compat) 18681742Sdd usage(); 18778447Sdd norun = true; 18878447Sdd break; 18978447Sdd case 'n': 19078447Sdd argappend(&newfs_arg, "-n %s", optarg); 19178447Sdd break; 19278447Sdd case 'O': 19378447Sdd argappend(&newfs_arg, "-o %s", optarg); 19478447Sdd break; 19578447Sdd case 'o': 19678447Sdd argappend(&mount_arg, "-o %s", optarg); 19778447Sdd break; 19878447Sdd case 'p': 19981742Sdd if (compat) 20081742Sdd usage(); 201118500Syar if ((set = setmode(optarg)) == NULL) 20278447Sdd usage(); 203118500Syar mi.mi_mode = getmode(set, S_IRWXU | S_IRWXG | S_IRWXO); 20478447Sdd mi.mi_have_mode = true; 205118500Syar free(set); 20678447Sdd break; 20778447Sdd case 'S': 20881742Sdd if (compat) 20981742Sdd usage(); 21078447Sdd softdep = false; 21178447Sdd break; 21278447Sdd case 's': 21378447Sdd argappend(&mdconfig_arg, "-s %s", optarg); 21478447Sdd break; 21581742Sdd case 'U': 21681742Sdd softdep = true; 21781742Sdd break; 218107475Srwatson case 'v': 219107475Srwatson argappend(&newfs_arg, "-O %s", optarg); 220107475Srwatson break; 22178447Sdd case 'w': 22281742Sdd if (compat) 22381742Sdd usage(); 22478447Sdd extract_ugid(optarg, &mi); 22578447Sdd break; 22678447Sdd case 'X': 22781742Sdd if (compat) 22881742Sdd usage(); 22978447Sdd debug = true; 23078447Sdd break; 23178447Sdd default: 23278447Sdd usage(); 23378447Sdd } 23481628Sobrien argc -= optind; 23581628Sobrien argv += optind; 23681628Sobrien if (argc < 2) 23778447Sdd usage(); 23878447Sdd 23981742Sdd /* Make compatibility assumptions. */ 24081742Sdd if (compat) { 24181742Sdd mi.mi_mode = 01777; 24281742Sdd mi.mi_have_mode = true; 24381742Sdd } 24481742Sdd 24578447Sdd /* Derive 'unit' (global). */ 24681628Sobrien unitstr = argv[0]; 24778447Sdd if (strncmp(unitstr, "/dev/", 5) == 0) 24878447Sdd unitstr += 5; 24978447Sdd if (strncmp(unitstr, mdname, mdnamelen) == 0) 25078447Sdd unitstr += mdnamelen; 25178447Sdd if (*unitstr == '\0') { 25278447Sdd autounit = true; 25378447Sdd unit = -1; 25478447Sdd } else { 255141082Sssouhlal ul = strtoul(unitstr, &p, 10); 256141082Sssouhlal if (ul == ULONG_MAX || *p != '\0') 25778447Sdd errx(1, "bad device unit: %s", unitstr); 258141082Sssouhlal unit = ul; 25978447Sdd } 26078447Sdd 26181628Sobrien mtpoint = argv[1]; 26278447Sdd if (!have_mdtype) 26378447Sdd mdtype = MD_SWAP; 26478447Sdd if (softdep) 26578447Sdd argappend(&newfs_arg, "-U"); 26678447Sdd 26778447Sdd /* Do the work. */ 26878447Sdd if (detach && !autounit) 26978447Sdd do_mdconfig_detach(); 27078447Sdd if (autounit) 27178447Sdd do_mdconfig_attach_au(mdconfig_arg, mdtype); 27278447Sdd else 27378447Sdd do_mdconfig_attach(mdconfig_arg, mdtype); 27478447Sdd do_newfs(newfs_arg); 27578447Sdd do_mount(mount_arg, mtpoint); 27678447Sdd do_mtptsetup(mtpoint, &mi); 27778447Sdd 27878447Sdd return (0); 27978447Sdd} 28078447Sdd 28178447Sdd/* 28278447Sdd * Append the expansion of 'fmt' to the buffer pointed to by '*dstp'; 28378447Sdd * reallocate as required. 28478447Sdd */ 28578447Sddstatic void 28678447Sddargappend(char **dstp, const char *fmt, ...) 28778447Sdd{ 28878447Sdd char *old, *new; 28978447Sdd va_list ap; 29078447Sdd 29178447Sdd old = *dstp; 29278447Sdd assert(old != NULL); 29378447Sdd 29478447Sdd va_start(ap, fmt); 29578447Sdd if (vasprintf(&new, fmt,ap) == -1) 29678447Sdd errx(1, "vasprintf"); 29778447Sdd va_end(ap); 29878447Sdd 29978447Sdd *dstp = new; 30078447Sdd if (asprintf(&new, "%s %s", old, new) == -1) 30178447Sdd errx(1, "asprintf"); 30278447Sdd free(*dstp); 30378447Sdd free(old); 30478447Sdd 30578447Sdd *dstp = new; 30678447Sdd} 30778447Sdd 30878447Sdd/* 30978447Sdd * If run-time debugging is enabled, print the expansion of 'fmt'. 31078447Sdd * Otherwise, do nothing. 31178447Sdd */ 31278447Sddstatic void 31378447Sdddebugprintf(const char *fmt, ...) 31478447Sdd{ 31578447Sdd va_list ap; 31678447Sdd 31778447Sdd if (!debug) 31878447Sdd return; 31978447Sdd fprintf(stderr, "DEBUG: "); 32078447Sdd va_start(ap, fmt); 32178447Sdd vfprintf(stderr, fmt, ap); 32278447Sdd va_end(ap); 32378447Sdd fprintf(stderr, "\n"); 32478447Sdd fflush(stderr); 32578447Sdd} 32678447Sdd 32778447Sdd/* 32878447Sdd * Attach a memory disk with a known unit. 32978447Sdd */ 33078447Sddstatic void 33178447Sdddo_mdconfig_attach(const char *args, const enum md_types mdtype) 33278447Sdd{ 33378447Sdd int rv; 33478447Sdd const char *ta; /* Type arg. */ 33578447Sdd 33678447Sdd switch (mdtype) { 33778447Sdd case MD_SWAP: 33878447Sdd ta = "-t swap"; 33978447Sdd break; 34078447Sdd case MD_VNODE: 34178447Sdd ta = "-t vnode"; 34278447Sdd break; 34378447Sdd case MD_MALLOC: 34478447Sdd ta = "-t malloc"; 34578447Sdd break; 34678447Sdd default: 34778447Sdd abort(); 34878447Sdd } 349117033Sgordon rv = run(NULL, "%s -a %s%s -u %s%d", _PATH_MDCONFIG, ta, args, 35078447Sdd mdname, unit); 35178447Sdd if (rv) 35278447Sdd errx(1, "mdconfig (attach) exited with error code %d", rv); 35378447Sdd} 35478447Sdd 35578447Sdd/* 35678447Sdd * Attach a memory disk with an unknown unit; use autounit. 35778447Sdd */ 35878447Sddstatic void 35978447Sdddo_mdconfig_attach_au(const char *args, const enum md_types mdtype) 36078447Sdd{ 36178447Sdd const char *ta; /* Type arg. */ 36278447Sdd char *linep, *linebuf; /* Line pointer, line buffer. */ 36378447Sdd int fd; /* Standard output of mdconfig invocation. */ 36478447Sdd FILE *sfd; 36578447Sdd int rv; 36678447Sdd char *p; 36778447Sdd size_t linelen; 368141082Sssouhlal unsigned long ul; 36978447Sdd 37078447Sdd switch (mdtype) { 37178447Sdd case MD_SWAP: 37278447Sdd ta = "-t swap"; 37378447Sdd break; 37478447Sdd case MD_VNODE: 37578447Sdd ta = "-t vnode"; 37678447Sdd break; 37778447Sdd case MD_MALLOC: 37878447Sdd ta = "-t malloc"; 37978447Sdd break; 38078447Sdd default: 38178447Sdd abort(); 38278447Sdd } 383117033Sgordon rv = run(&fd, "%s -a %s%s", _PATH_MDCONFIG, ta, args); 38478447Sdd if (rv) 38578447Sdd errx(1, "mdconfig (attach) exited with error code %d", rv); 38678447Sdd 38778447Sdd /* Receive the unit number. */ 38878447Sdd if (norun) { /* Since we didn't run, we can't read. Fake it. */ 38978447Sdd unit = -1; 39078447Sdd return; 39178447Sdd } 39278447Sdd sfd = fdopen(fd, "r"); 39378447Sdd if (sfd == NULL) 39478447Sdd err(1, "fdopen"); 39578447Sdd linep = fgetln(sfd, &linelen); 39678447Sdd if (linep == NULL && linelen < mdnamelen + 1) 39778447Sdd errx(1, "unexpected output from mdconfig (attach)"); 39878447Sdd /* If the output format changes, we want to know about it. */ 39978447Sdd assert(strncmp(linep, mdname, mdnamelen) == 0); 40078447Sdd linebuf = malloc(linelen - mdnamelen + 1); 40178447Sdd assert(linebuf != NULL); 40278447Sdd /* Can't use strlcpy because linep is not NULL-terminated. */ 40378447Sdd strncpy(linebuf, linep + mdnamelen, linelen); 40478447Sdd linebuf[linelen] = '\0'; 405141082Sssouhlal ul = strtoul(linebuf, &p, 10); 406141082Sssouhlal if (ul == ULONG_MAX || *p != '\n') 40778447Sdd errx(1, "unexpected output from mdconfig (attach)"); 408141082Sssouhlal unit = ul; 40978447Sdd 41078447Sdd fclose(sfd); 41178447Sdd close(fd); 41278447Sdd} 41378447Sdd 41478447Sdd/* 41578447Sdd * Detach a memory disk. 41678447Sdd */ 41778447Sddstatic void 41878447Sdddo_mdconfig_detach(void) 41978447Sdd{ 42078447Sdd int rv; 42178447Sdd 422117033Sgordon rv = run(NULL, "%s -d -u %s%d", _PATH_MDCONFIG, mdname, unit); 42378447Sdd if (rv && debug) /* This is allowed to fail. */ 42478447Sdd warnx("mdconfig (detach) exited with error code %d (ignored)", 42578447Sdd rv); 42678447Sdd} 42778447Sdd 42878447Sdd/* 42978447Sdd * Mount the configured memory disk. 43078447Sdd */ 43178447Sddstatic void 43278447Sdddo_mount(const char *args, const char *mtpoint) 43378447Sdd{ 43478447Sdd int rv; 43578447Sdd 436117033Sgordon rv = run(NULL, "%s%s /dev/%s%d %s", _PATH_MOUNT, args, 43778447Sdd mdname, unit, mtpoint); 43878447Sdd if (rv) 43978447Sdd errx(1, "mount exited with error code %d", rv); 44078447Sdd} 44178447Sdd 44278447Sdd/* 44378447Sdd * Various configuration of the mountpoint. Mostly, enact 'mip'. 44478447Sdd */ 44578447Sddstatic void 44678447Sdddo_mtptsetup(const char *mtpoint, struct mtpt_info *mip) 44778447Sdd{ 44878447Sdd 44978447Sdd if (mip->mi_have_mode) { 45078447Sdd debugprintf("changing mode of %s to %o.", mtpoint, 45178447Sdd mip->mi_mode); 45278447Sdd if (!norun) 45378447Sdd if (chmod(mtpoint, mip->mi_mode) == -1) 45478447Sdd err(1, "chmod: %s", mtpoint); 45578447Sdd } 45678447Sdd /* 45778447Sdd * We have to do these separately because the user may have 45878447Sdd * only specified one of them. 45978447Sdd */ 46078447Sdd if (mip->mi_have_uid) { 46178447Sdd debugprintf("changing owner (user) or %s to %u.", mtpoint, 46278447Sdd mip->mi_uid); 46378447Sdd if (!norun) 46478447Sdd if (chown(mtpoint, mip->mi_uid, -1) == -1) 46578447Sdd err(1, "chown %s to %u (user)", mtpoint, 46678447Sdd mip->mi_uid); 46778447Sdd } 46878447Sdd if (mip->mi_have_gid) { 46978447Sdd debugprintf("changing owner (group) or %s to %u.", mtpoint, 47078447Sdd mip->mi_gid); 47178447Sdd if (!norun) 47278447Sdd if (chown(mtpoint, -1, mip->mi_gid) == -1) 47378447Sdd err(1, "chown %s to %u (group)", mtpoint, 47478447Sdd mip->mi_gid); 47578447Sdd } 47678447Sdd} 47778447Sdd 47878447Sdd/* 479102231Strhodes * Put a file system on the memory disk. 48078447Sdd */ 48178447Sddstatic void 48278447Sdddo_newfs(const char *args) 48378447Sdd{ 48478447Sdd int rv; 48578447Sdd 486117033Sgordon rv = run(NULL, "%s%s /dev/%s%d", _PATH_NEWFS, args, mdname, unit); 48778447Sdd if (rv) 48878447Sdd errx(1, "newfs exited with error code %d", rv); 48978447Sdd} 49078447Sdd 49178447Sdd/* 49278447Sdd * 'str' should be a user and group name similar to the last argument 49378447Sdd * to chown(1); i.e., a user, followed by a colon, followed by a 49478447Sdd * group. The user and group in 'str' may be either a [ug]id or a 49578447Sdd * name. Upon return, the uid and gid fields in 'mip' will contain 49678447Sdd * the uid and gid of the user and group name in 'str', respectively. 49778447Sdd * 49878447Sdd * In other words, this derives a user and group id from a string 49978447Sdd * formatted like the last argument to chown(1). 50078447Sdd */ 50178447Sddstatic void 50278447Sddextract_ugid(const char *str, struct mtpt_info *mip) 50378447Sdd{ 50478447Sdd char *ug; /* Writable 'str'. */ 50578447Sdd char *user, *group; /* Result of extracton. */ 50678447Sdd struct passwd *pw; 50778447Sdd struct group *gr; 50878447Sdd char *p; 50978447Sdd uid_t *uid; 51078447Sdd gid_t *gid; 51178447Sdd 51278447Sdd uid = &mip->mi_uid; 51378447Sdd gid = &mip->mi_gid; 51478447Sdd mip->mi_have_uid = mip->mi_have_gid = false; 51578447Sdd 51678447Sdd /* Extract the user and group from 'str'. Format above. */ 51778711Sdd ug = strdup(str); 51878447Sdd assert(ug != NULL); 51978447Sdd group = ug; 52078447Sdd user = strsep(&group, ":"); 52178447Sdd if (user == NULL || group == NULL || *user == '\0' || *group == '\0') 52278447Sdd usage(); 52378447Sdd 52478447Sdd /* Derive uid. */ 52578447Sdd *uid = strtoul(user, &p, 10); 526117430Skan if (*uid == (uid_t)ULONG_MAX) 52778447Sdd usage(); 52878447Sdd if (*p != '\0') { 52978447Sdd pw = getpwnam(user); 53078447Sdd if (pw == NULL) 53178447Sdd errx(1, "invalid user: %s", user); 53278447Sdd *uid = pw->pw_uid; 53378447Sdd mip->mi_have_uid = true; 53478447Sdd } 53578447Sdd 53678447Sdd /* Derive gid. */ 53778447Sdd *gid = strtoul(group, &p, 10); 538117430Skan if (*gid == (gid_t)ULONG_MAX) 53978447Sdd usage(); 54078447Sdd if (*p != '\0') { 54178447Sdd gr = getgrnam(group); 54278447Sdd if (gr == NULL) 54378447Sdd errx(1, "invalid group: %s", group); 54478447Sdd *gid = gr->gr_gid; 54578447Sdd mip->mi_have_gid = true; 54678447Sdd } 54778447Sdd 54878447Sdd free(ug); 54978447Sdd /* 55078447Sdd * At this point we don't support only a username or only a 55178447Sdd * group name. do_mtptsetup already does, so when this 55278447Sdd * feature is desired, this is the only routine that needs to 55378447Sdd * be changed. 55478447Sdd */ 55578447Sdd assert(mip->mi_have_uid); 55678447Sdd assert(mip->mi_have_gid); 55778447Sdd} 55878447Sdd 55978447Sdd/* 56078447Sdd * Run a process with command name and arguments pointed to by the 56178447Sdd * formatted string 'cmdline'. Since system(3) is not used, the first 56278447Sdd * space-delimited token of 'cmdline' must be the full pathname of the 56378447Sdd * program to run. The return value is the return code of the process 56478447Sdd * spawned. If 'ofd' is non-NULL, it is set to the standard output of 56578447Sdd * the program spawned (i.e., you can read from ofd and get the output 56678447Sdd * of the program). 56778447Sdd */ 56878447Sddstatic int 56978447Sddrun(int *ofd, const char *cmdline, ...) 57078447Sdd{ 57181628Sobrien char **argv, **argvp; /* Result of splitting 'cmd'. */ 57281628Sobrien int argc; 57378447Sdd char *cmd; /* Expansion of 'cmdline'. */ 57478447Sdd int pid, status; /* Child info. */ 57578447Sdd int pfd[2]; /* Pipe to the child. */ 57678447Sdd int nfd; /* Null (/dev/null) file descriptor. */ 57778447Sdd bool dup2dn; /* Dup /dev/null to stdout? */ 57878447Sdd va_list ap; 57978447Sdd char *p; 58078447Sdd int rv, i; 58178447Sdd 58278447Sdd dup2dn = true; 58378447Sdd va_start(ap, cmdline); 58478447Sdd rv = vasprintf(&cmd, cmdline, ap); 58578447Sdd if (rv == -1) 58678447Sdd err(1, "vasprintf"); 58778447Sdd va_end(ap); 58878447Sdd 58981628Sobrien /* Split up 'cmd' into 'argv' for use with execve. */ 59081628Sobrien for (argc = 1, p = cmd; (p = strchr(p, ' ')) != NULL; p++) 59181628Sobrien argc++; /* 'argc' generation loop. */ 59281628Sobrien argv = (char **)malloc(sizeof(*argv) * (argc + 1)); 59381628Sobrien assert(argv != NULL); 59481628Sobrien for (p = cmd, argvp = argv; (*argvp = strsep(&p, " ")) != NULL;) 59581628Sobrien if (**argv != '\0') 59681628Sobrien if (++argvp >= &argv[argc]) { 59781628Sobrien *argvp = NULL; 59878447Sdd break; 59978447Sdd } 60081628Sobrien assert(*argv); 60178447Sdd 60278447Sdd /* Make sure the above loop works as expected. */ 60378447Sdd if (debug) { 60478447Sdd /* 60578447Sdd * We can't, but should, use debugprintf here. First, 60678447Sdd * it appends a trailing newline to the output, and 60778447Sdd * second it prepends "DEBUG: " to the output. The 60878447Sdd * former is a problem for this would-be first call, 60978447Sdd * and the latter for the would-be call inside the 61078447Sdd * loop. 61178447Sdd */ 61278447Sdd (void)fprintf(stderr, "DEBUG: running:"); 61378447Sdd /* Should be equivilent to 'cmd' (before strsep, of course). */ 61481628Sobrien for (i = 0; argv[i] != NULL; i++) 61581628Sobrien (void)fprintf(stderr, " %s", argv[i]); 61678447Sdd (void)fprintf(stderr, "\n"); 61778447Sdd } 61878447Sdd 61978447Sdd /* Create a pipe if necessary and fork the helper program. */ 62078447Sdd if (ofd != NULL) { 62178447Sdd if (pipe(&pfd[0]) == -1) 62278447Sdd err(1, "pipe"); 62378447Sdd *ofd = pfd[0]; 62478447Sdd dup2dn = false; 62578447Sdd } 62678447Sdd pid = fork(); 62778447Sdd switch (pid) { 62878447Sdd case 0: 62978447Sdd /* XXX can we call err() in here? */ 63078447Sdd if (norun) 63178447Sdd _exit(0); 63278447Sdd if (ofd != NULL) 63378447Sdd if (dup2(pfd[1], STDOUT_FILENO) < 0) 63478447Sdd err(1, "dup2"); 63578447Sdd if (!loudsubs) { 63678447Sdd nfd = open(_PATH_DEVNULL, O_RDWR); 63778447Sdd if (nfd == -1) 63878447Sdd err(1, "open: %s", _PATH_DEVNULL); 63978447Sdd if (dup2(nfd, STDIN_FILENO) < 0) 64078447Sdd err(1, "dup2"); 64178447Sdd if (dup2dn) 64278447Sdd if (dup2(nfd, STDOUT_FILENO) < 0) 64378447Sdd err(1, "dup2"); 64478447Sdd if (dup2(nfd, STDERR_FILENO) < 0) 64578447Sdd err(1, "dup2"); 64678447Sdd } 64778447Sdd 64881628Sobrien (void)execv(argv[0], argv); 64981628Sobrien warn("exec: %s", argv[0]); 65078447Sdd _exit(-1); 65178447Sdd case -1: 65278447Sdd err(1, "fork"); 65378447Sdd } 65478447Sdd 65578447Sdd free(cmd); 65681628Sobrien free(argv); 65778447Sdd while (waitpid(pid, &status, 0) != pid) 65878447Sdd ; 65978447Sdd return (WEXITSTATUS(status)); 66078447Sdd} 66178447Sdd 66278447Sddstatic void 66378447Sddusage(void) 66478447Sdd{ 66581742Sdd const char *name; 66678447Sdd 66781742Sdd if (compat) 66881742Sdd name = getprogname(); 66981742Sdd else 67081742Sdd name = "mdmfs"; 67181742Sdd if (!compat) 67281742Sdd fprintf(stderr, 673141611Sru"usage: %s [-DLlMNSUX] [-a maxcontig] [-b block-size] [-c cylinders]\n" 67481742Sdd"\t[-d rotdelay] [-e maxbpg] [-F file] [-f frag-size] [-i bytes]\n" 67581742Sdd"\t[-m percent-free] [-n rotational-positions] [-O optimization]\n" 676141611Sru"\t[-o mount-options] [-p permissions] [-s size] [-v version]\n" 677141611Sru"\t[-w user:group] md-device mount-point\n", name); 67878447Sdd fprintf(stderr, 679129322Sru"usage: %s -C [-lNU] [-a maxcontig] [-b block-size] [-c cylinders]\n" 68078447Sdd"\t[-d rotdelay] [-e maxbpg] [-F file] [-f frag-size] [-i bytes]\n" 68178447Sdd"\t[-m percent-free] [-n rotational-positions] [-O optimization]\n" 682141611Sru"\t[-o mount-options] [-s size] [-v version] md-device mount-point\n", name); 68378447Sdd exit(1); 68478447Sdd} 685