mdmfs.c revision 78569
155714Skris/* 255714Skris * Copyright (c) 2001 Dima Dorfman <dd@FreeBSD.org> 355714Skris * All rights reserved. 455714Skris * 555714Skris * Redistribution and use in source and binary forms, with or without 655714Skris * modification, are permitted provided that the following conditions 755714Skris * are met: 8280304Sjkim * 1. Redistributions of source code must retain the above copyright 955714Skris * notice, this list of conditions and the following disclaimer. 1055714Skris * 2. Redistributions in binary form must reproduce the above copyright 1155714Skris * notice, this list of conditions and the following disclaimer in the 1255714Skris * documentation and/or other materials provided with the distribution. 1355714Skris * 1455714Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15280304Sjkim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1655714Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1755714Skris * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1855714Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1955714Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2055714Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2155714Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22280304Sjkim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2355714Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2455714Skris * SUCH DAMAGE. 2555714Skris */ 2655714Skris 2755714Skris/* 2855714Skris * mdmfs (md/MFS) is a wrapper around mdconfig(8), disklabel(8), 2955714Skris * newfs(8), and mount(8) that mimics the command line option set of 3055714Skris * the deprecated mount_mfs(8). 3155714Skris */ 3255714Skris 3355714Skris#ifndef lint 3455714Skrisstatic const char rcsid[] = 3555714Skris "$FreeBSD: head/sbin/mdmfs/mdmfs.c 78569 2001-06-21 22:34:50Z mjacob $"; 3655714Skris#endif /* not lint */ 37280304Sjkim 3855714Skris#include <sys/param.h> 3955714Skris#include <sys/mdioctl.h> 40280304Sjkim#include <sys/stat.h> 4155714Skris#include <sys/wait.h> 4255714Skris 4355714Skris#include <assert.h> 4455714Skris#include <err.h> 4555714Skris#include <fcntl.h> 4655714Skris#include <grp.h> 4755714Skris#include <paths.h> 4855714Skris#include <pwd.h> 4955714Skris#include <stdarg.h> 5055714Skris#include <stdio.h> 5155714Skris#include <stdlib.h> 52280304Sjkim#include <string.h> 5355714Skris#include <unistd.h> 5455714Skris 5555714Skris#include "pathnames.h" 5655714Skris 5755714Skristypedef enum { false, true } bool; 5889840Skris 59238405Sjkimstruct mtpt_info { 6089840Skris uid_t mi_uid; 6189840Skris bool mi_have_uid; 6289840Skris gid_t mi_gid; 6389840Skris bool mi_have_gid; 6489840Skris mode_t mi_mode; 6589840Skris bool mi_have_mode; 66280304Sjkim}; 6789840Skris 6889840Skrisstatic bool debug; /* Emit debugging information? */ 6989840Skrisstatic bool loudsubs; /* Suppress output from helper programs? */ 7089840Skrisstatic bool norun; /* Actually run the helper programs? */ 7189840Skrisstatic int unit; /* The unit we're working with. */ 7289840Skrisstatic const char *mdname; /* Name of memory disk device (e.g., "md"). */ 7389840Skrisstatic size_t mdnamelen; /* Length of mdname. */ 7489840Skris 7589840Skrisstatic void argappend(char **, const char *, ...); 7689840Skrisstatic void debugprintf(const char *, ...); 7789840Skrisstatic void do_disklabel(void); 7889840Skrisstatic void do_mdconfig_attach(const char *, const enum md_types); 7989840Skrisstatic void do_mdconfig_attach_au(const char *, const enum md_types); 8089840Skrisstatic void do_mdconfig_detach(void); 8189840Skrisstatic void do_mount(const char *, const char *); 8289840Skrisstatic void do_mtptsetup(const char *, struct mtpt_info *); 8389840Skrisstatic void do_newfs(const char *); 8489840Skrisstatic void extract_ugid(const char *, struct mtpt_info *); 8589840Skrisstatic int run(int *, const char *, ...); 8689840Skrisstatic void usage(void); 8789840Skris 8889840Skrisint 8989840Skrismain(int ac, char **av) 9089840Skris{ 9189840Skris struct mtpt_info mi; /* Mountpoint info. */ 9289840Skris char *mdconfig_arg, *newfs_arg, /* Args to helper programs. */ 9389840Skris *mount_arg; 9489840Skris enum md_types mdtype; /* The type of our memory disk. */ 9589840Skris bool have_mdtype; 9689840Skris bool detach, softdep, autounit; 9789840Skris char *mtpoint, *unitstr; 9889840Skris char ch, *p; 9989840Skris 10089840Skris /* Misc. initialization. */ 10189840Skris (void)memset(&mi, '\0', sizeof(mi)); 10289840Skris detach = true; 10389840Skris softdep = true; 10489840Skris autounit = false; 10589840Skris have_mdtype = false; 10689840Skris mdname = MD_NAME; 10789840Skris mdnamelen = strlen(mdname); 10889840Skris /* 10989840Skris * Can't set these to NULL. They may be passed to the 11089840Skris * respective programs without modification. I.e., we may not 11155714Skris * receive any command-line options which will caused them to 11255714Skris * be modified. 113110007Smarkm */ 11455714Skris mdconfig_arg = strdup(""); 11555714Skris newfs_arg = strdup(""); 11655714Skris mount_arg = strdup(""); 11755714Skris 118238405Sjkim while ((ch = getopt(ac, av, 119280304Sjkim "a:b:c:Dd:e:F:f:hi:LMm:Nn:O:o:p:Ss:t:w:X")) != -1) 120238405Sjkim switch (ch) { 12155714Skris case 'a': 122238405Sjkim argappend(&newfs_arg, "-a %s", optarg); 12355714Skris break; 124238405Sjkim case 'b': 125280304Sjkim argappend(&newfs_arg, "-b %s", optarg); 126110007Smarkm break; 127280304Sjkim case 'c': 128280304Sjkim argappend(&newfs_arg, "-c %s", optarg); 12955949Skris break; 130273149Sjkim case 'D': 131280304Sjkim detach = false; 132280304Sjkim break; 133273149Sjkim case 'd': 134280304Sjkim argappend(&newfs_arg, "-d %s", optarg); 135280304Sjkim break; 136280304Sjkim case 'e': 137280304Sjkim argappend(&newfs_arg, "-e %s", optarg); 138280304Sjkim break; 139280304Sjkim case 'F': 140280304Sjkim if (have_mdtype) 141280304Sjkim usage(); 142280304Sjkim mdtype = MD_VNODE; 14355714Skris have_mdtype = true; 144160817Ssimon argappend(&mdconfig_arg, "-f %s", optarg); 145280304Sjkim break; 146280304Sjkim case 'f': 14755714Skris argappend(&newfs_arg, "-f %s", optarg); 14855714Skris break; 149280304Sjkim case 'h': 150280304Sjkim usage(); 151280304Sjkim break; 152280304Sjkim case 'i': 153280304Sjkim argappend(&newfs_arg, "-i %s", optarg); 154280304Sjkim break; 15555714Skris case 'L': 156280304Sjkim loudsubs = true; 157280304Sjkim break; 158280304Sjkim case 'M': 15955714Skris if (have_mdtype) 160280304Sjkim usage(); 161280304Sjkim mdtype = MD_MALLOC; 162280304Sjkim have_mdtype = true; 163280304Sjkim break; 16455714Skris case 'm': 165280304Sjkim argappend(&newfs_arg, "-m %s", optarg); 166280304Sjkim break; 167280304Sjkim case 'N': 16855714Skris norun = true; 169280304Sjkim break; 170280304Sjkim case 'n': 17155714Skris argappend(&newfs_arg, "-n %s", optarg); 172280304Sjkim break; 173280304Sjkim case 'O': 174280304Sjkim argappend(&newfs_arg, "-o %s", optarg); 175280304Sjkim break; 176280304Sjkim case 'o': 17755714Skris argappend(&mount_arg, "-o %s", optarg); 178280304Sjkim break; 179280304Sjkim case 'p': 180280304Sjkim if (*optarg >= '0' && *optarg <= '7') 18155714Skris mi.mi_mode = strtol(optarg, NULL, 8); 182280304Sjkim if ((mi.mi_mode & ~07777) != 0) 183280304Sjkim usage(); 18455714Skris mi.mi_have_mode = true; 185280304Sjkim break; 186280304Sjkim case 'S': 187280304Sjkim softdep = false; 188280304Sjkim break; 189280304Sjkim case 's': 190280304Sjkim argappend(&mdconfig_arg, "-s %s", optarg); 191280304Sjkim break; 192280304Sjkim case 'w': 193280304Sjkim extract_ugid(optarg, &mi); 194280304Sjkim break; 195280304Sjkim case 'X': 196280304Sjkim debug = true; 19755714Skris break; 198280304Sjkim default: 19955714Skris usage(); 200280304Sjkim } 201280304Sjkim ac -= optind; 202280304Sjkim av += optind; 203280304Sjkim if (ac < 2) 20455714Skris usage(); 205280304Sjkim 206280304Sjkim /* Derive 'unit' (global). */ 20755714Skris unitstr = av[0]; 208280304Sjkim if (strncmp(unitstr, "/dev/", 5) == 0) 209280304Sjkim unitstr += 5; 210280304Sjkim if (strncmp(unitstr, mdname, mdnamelen) == 0) 211280304Sjkim unitstr += mdnamelen; 212280304Sjkim if (*unitstr == '\0') { 213280304Sjkim autounit = true; 21455714Skris unit = -1; 215280304Sjkim } else { 216280304Sjkim unit = strtoul(unitstr, &p, 10); 217280304Sjkim if ((unsigned)unit == ULONG_MAX || *p != '\0') 218280304Sjkim errx(1, "bad device unit: %s", unitstr); 219280304Sjkim } 220280304Sjkim 22155714Skris mtpoint = av[1]; 222280304Sjkim if (!have_mdtype) 223280304Sjkim mdtype = MD_SWAP; 224280304Sjkim if (softdep) 225280304Sjkim argappend(&newfs_arg, "-U"); 226280304Sjkim 227280304Sjkim /* Do the work. */ 228280304Sjkim if (detach && !autounit) 229280304Sjkim do_mdconfig_detach(); 230280304Sjkim if (autounit) 231280304Sjkim do_mdconfig_attach_au(mdconfig_arg, mdtype); 232280304Sjkim else 233280304Sjkim do_mdconfig_attach(mdconfig_arg, mdtype); 234280304Sjkim do_disklabel(); 23555714Skris do_newfs(newfs_arg); 23655714Skris do_mount(mount_arg, mtpoint); 237280304Sjkim do_mtptsetup(mtpoint, &mi); 238280304Sjkim 239280304Sjkim return (0); 240280304Sjkim} 241280304Sjkim 242280304Sjkim/* 243280304Sjkim * Append the expansion of 'fmt' to the buffer pointed to by '*dstp'; 244280304Sjkim * reallocate as required. 245280304Sjkim */ 246280304Sjkimstatic void 247280304Sjkimargappend(char **dstp, const char *fmt, ...) 248280304Sjkim{ 249280304Sjkim char *old, *new; 250280304Sjkim va_list ap; 251280304Sjkim 252280304Sjkim old = *dstp; 253280304Sjkim assert(old != NULL); 254280304Sjkim 255280304Sjkim va_start(ap, fmt); 256280304Sjkim if (vasprintf(&new, fmt,ap) == -1) 257280304Sjkim errx(1, "vasprintf"); 258280304Sjkim va_end(ap); 259280304Sjkim 26055714Skris *dstp = new; 261280304Sjkim if (asprintf(&new, "%s %s", old, new) == -1) 262280304Sjkim errx(1, "asprintf"); 263280304Sjkim free(*dstp); 26459194Skris free(old); 265280304Sjkim 266280304Sjkim *dstp = new; 26755714Skris} 268280304Sjkim 269280304Sjkim/* 270280304Sjkim * If run-time debugging is enabled, print the expansion of 'fmt'. 27155714Skris * Otherwise, do nothing. 272280304Sjkim */ 27355714Skrisstatic void 274280304Sjkimdebugprintf(const char *fmt, ...) 27555714Skris{ 276280304Sjkim va_list ap; 277280304Sjkim 278280304Sjkim if (!debug) 279280304Sjkim return; 280280304Sjkim fprintf(stderr, "DEBUG: "); 281280304Sjkim va_start(ap, fmt); 282280304Sjkim vfprintf(stderr, fmt, ap); 283280304Sjkim va_end(ap); 284280304Sjkim fprintf(stderr, "\n"); 285280304Sjkim fflush(stderr); 286280304Sjkim} 287280304Sjkim 288280304Sjkim/* 289280304Sjkim * Label the memory disk. 290280304Sjkim */ 291280304Sjkimstatic void 292280304Sjkimdo_disklabel(void) 293280304Sjkim{ 294280304Sjkim int rv; 295280304Sjkim 296280304Sjkim rv = run(NULL, "%s -r -w %s%d auto", PATH_DISKLABEL, mdname, unit); 297280304Sjkim if (rv) 298280304Sjkim errx(1, "disklabel exited with error code %d", rv); 299280304Sjkim} 300280304Sjkim 301280304Sjkim/* 302280304Sjkim * Attach a memory disk with a known unit. 303280304Sjkim */ 304280304Sjkimstatic void 305280304Sjkimdo_mdconfig_attach(const char *args, const enum md_types mdtype) 306280304Sjkim{ 307280304Sjkim int rv; 308280304Sjkim const char *ta; /* Type arg. */ 309280304Sjkim 310280304Sjkim switch (mdtype) { 311280304Sjkim case MD_SWAP: 312280304Sjkim ta = "-t swap"; 313280304Sjkim break; 314280304Sjkim case MD_VNODE: 315280304Sjkim ta = "-t vnode"; 316280304Sjkim break; 317280304Sjkim case MD_MALLOC: 318280304Sjkim ta = "-t malloc"; 319280304Sjkim break; 320280304Sjkim default: 321280304Sjkim abort(); 322280304Sjkim } 323280304Sjkim rv = run(NULL, "%s -a %s%s -u %s%d", PATH_MDCONFIG, ta, args, 324280304Sjkim mdname, unit); 32555714Skris if (rv) 326280304Sjkim errx(1, "mdconfig (attach) exited with error code %d", rv); 327280304Sjkim} 328280304Sjkim 329280304Sjkim/* 330280304Sjkim * Attach a memory disk with an unknown unit; use autounit. 331280304Sjkim */ 332280304Sjkimstatic void 333280304Sjkimdo_mdconfig_attach_au(const char *args, const enum md_types mdtype) 334280304Sjkim{ 335280304Sjkim const char *ta; /* Type arg. */ 33655714Skris char *linep, *linebuf; /* Line pointer, line buffer. */ 337280304Sjkim int fd; /* Standard output of mdconfig invocation. */ 338280304Sjkim FILE *sfd; 339280304Sjkim int rv; 340280304Sjkim char *p; 341280304Sjkim size_t linelen; 342280304Sjkim 343280304Sjkim switch (mdtype) { 344280304Sjkim case MD_SWAP: 345280304Sjkim ta = "-t swap"; 346280304Sjkim break; 347280304Sjkim case MD_VNODE: 348280304Sjkim ta = "-t vnode"; 349280304Sjkim break; 350280304Sjkim case MD_MALLOC: 351280304Sjkim ta = "-t malloc"; 352280304Sjkim break; 353280304Sjkim default: 354280304Sjkim abort(); 355280304Sjkim } 356280304Sjkim rv = run(&fd, "%s -a %s%s", PATH_MDCONFIG, ta, args); 357280304Sjkim if (rv) 358280304Sjkim errx(1, "mdconfig (attach) exited with error code %d", rv); 359280304Sjkim 360280304Sjkim /* Receive the unit number. */ 361280304Sjkim if (norun) { /* Since we didn't run, we can't read. Fake it. */ 362280304Sjkim unit = -1; 363280304Sjkim return; 364280304Sjkim } 365280304Sjkim sfd = fdopen(fd, "r"); 366280304Sjkim if (sfd == NULL) 367280304Sjkim err(1, "fdopen"); 368280304Sjkim linep = fgetln(sfd, &linelen); 369280304Sjkim if (linep == NULL && linelen < mdnamelen + 1) 370280304Sjkim errx(1, "unexpected output from mdconfig (attach)"); 371280304Sjkim /* If the output format changes, we want to know about it. */ 372280304Sjkim assert(strncmp(linep, mdname, mdnamelen) == 0); 373280304Sjkim linebuf = malloc(linelen - mdnamelen + 1); 374280304Sjkim assert(linebuf != NULL); 375280304Sjkim /* Can't use strlcpy because linep is not NULL-terminated. */ 376280304Sjkim strncpy(linebuf, linep + mdnamelen, linelen); 377280304Sjkim linebuf[linelen] = '\0'; 378280304Sjkim unit = strtoul(linebuf, &p, 10); 379280304Sjkim if ((unsigned)unit == ULONG_MAX || *p != '\n') 380280304Sjkim errx(1, "unexpected output from mdconfig (attach)"); 381280304Sjkim 382280304Sjkim fclose(sfd); 383280304Sjkim close(fd); 384280304Sjkim} 385280304Sjkim 386280304Sjkim/* 387280304Sjkim * Detach a memory disk. 388280304Sjkim */ 389280304Sjkimstatic void 390280304Sjkimdo_mdconfig_detach(void) 391280304Sjkim{ 392280304Sjkim int rv; 393280304Sjkim 394280304Sjkim rv = run(NULL, "%s -d -u %s%d", PATH_MDCONFIG, mdname, unit); 395280304Sjkim if (rv && debug) /* This is allowed to fail. */ 396280304Sjkim warnx("mdconfig (detach) exited with error code %d (ignored)", 397280304Sjkim rv); 398280304Sjkim} 399280304Sjkim 400280304Sjkim/* 401273149Sjkim * Mount the configured memory disk. 402280304Sjkim */ 403280304Sjkimstatic void 404280304Sjkimdo_mount(const char *args, const char *mtpoint) 405194206Ssimon{ 406280304Sjkim int rv; 407280304Sjkim 408280304Sjkim rv = run(NULL, "%s%s /dev/%s%dc %s", PATH_MOUNT, args, 409280304Sjkim mdname, unit, mtpoint); 410280304Sjkim if (rv) 411194206Ssimon errx(1, "mount exited with error code %d", rv); 412194206Ssimon} 413280304Sjkim 414280304Sjkim/* 415280304Sjkim * Various configuration of the mountpoint. Mostly, enact 'mip'. 416280304Sjkim */ 417280304Sjkimstatic void 41859194Skrisdo_mtptsetup(const char *mtpoint, struct mtpt_info *mip) 419280304Sjkim{ 420280304Sjkim 421280304Sjkim if (mip->mi_have_mode) { 422280304Sjkim debugprintf("changing mode of %s to %o.", mtpoint, 42359194Skris mip->mi_mode); 424280304Sjkim if (!norun) 425280304Sjkim if (chmod(mtpoint, mip->mi_mode) == -1) 426280304Sjkim err(1, "chmod: %s", mtpoint); 427280304Sjkim } 428280304Sjkim /* 429280304Sjkim * We have to do these separately because the user may have 430280304Sjkim * only specified one of them. 431280304Sjkim */ 432280304Sjkim if (mip->mi_have_uid) { 433280304Sjkim debugprintf("changing owner (user) or %s to %u.", mtpoint, 434280304Sjkim mip->mi_uid); 435280304Sjkim if (!norun) 436280304Sjkim if (chown(mtpoint, mip->mi_uid, -1) == -1) 437280304Sjkim err(1, "chown %s to %u (user)", mtpoint, 438280304Sjkim mip->mi_uid); 439280304Sjkim } 440280304Sjkim if (mip->mi_have_gid) { 441280304Sjkim debugprintf("changing owner (group) or %s to %u.", mtpoint, 442280304Sjkim mip->mi_gid); 443280304Sjkim if (!norun) 444280304Sjkim if (chown(mtpoint, -1, mip->mi_gid) == -1) 445280304Sjkim err(1, "chown %s to %u (group)", mtpoint, 446280304Sjkim mip->mi_gid); 44755714Skris } 448280304Sjkim} 449280304Sjkim 450280304Sjkim/* 451280304Sjkim * Put a filesystem on the memory disk. 452280304Sjkim */ 453280304Sjkimstatic void 454280304Sjkimdo_newfs(const char *args) 45555714Skris{ 456280304Sjkim int rv; 45755714Skris 458280304Sjkim rv = run(NULL, "%s%s /dev/%s%dc", PATH_NEWFS, args, mdname, unit); 459280304Sjkim if (rv) 460280304Sjkim errx(1, "newfs exited with error code %d", rv); 461280304Sjkim} 46255714Skris 463280304Sjkim/* 464280304Sjkim * 'str' should be a user and group name similar to the last argument 465280304Sjkim * to chown(1); i.e., a user, followed by a colon, followed by a 466280304Sjkim * group. The user and group in 'str' may be either a [ug]id or a 467280304Sjkim * name. Upon return, the uid and gid fields in 'mip' will contain 468280304Sjkim * the uid and gid of the user and group name in 'str', respectively. 469280304Sjkim * 470280304Sjkim * In other words, this derives a user and group id from a string 471280304Sjkim * formatted like the last argument to chown(1). 472280304Sjkim */ 473280304Sjkimstatic void 474280304Sjkimextract_ugid(const char *str, struct mtpt_info *mip) 475280304Sjkim{ 476280304Sjkim char *ug; /* Writable 'str'. */ 477280304Sjkim char *user, *group; /* Result of extracton. */ 478280304Sjkim size_t strl; /* Length of 'str' incl. NULL. */ 479280304Sjkim struct passwd *pw; 480280304Sjkim struct group *gr; 481110007Smarkm char *p; 482280304Sjkim uid_t *uid; 483280304Sjkim gid_t *gid; 484280304Sjkim size_t rv; 485280304Sjkim 486280304Sjkim uid = &mip->mi_uid; 48755714Skris gid = &mip->mi_gid; 488280304Sjkim mip->mi_have_uid = mip->mi_have_gid = false; 489280304Sjkim 490280304Sjkim /* Extract the user and group from 'str'. Format above. */ 49155714Skris strl = strlen(str) + 1; 492280304Sjkim ug = malloc(strl); 493280304Sjkim assert(ug != NULL); 494280304Sjkim rv = strlcpy(ug, str, strl); 495280304Sjkim if (rv >= strl) 496280304Sjkim errx(1, "-w word too long (%ld >= %ld)", (long)rv, (long)strl); 497280304Sjkim group = ug; 49855714Skris user = strsep(&group, ":"); 499280304Sjkim if (user == NULL || group == NULL || *user == '\0' || *group == '\0') 500280304Sjkim usage(); 50155714Skris 502280304Sjkim /* Derive uid. */ 503280304Sjkim *uid = strtoul(user, &p, 10); 504280304Sjkim if ((unsigned)*uid == ULONG_MAX) 505280304Sjkim usage(); 506280304Sjkim if (*p != '\0') { 507280304Sjkim pw = getpwnam(user); 508280304Sjkim if (pw == NULL) 509280304Sjkim errx(1, "invalid user: %s", user); 510280304Sjkim *uid = pw->pw_uid; 511280304Sjkim mip->mi_have_uid = true; 512280304Sjkim } 513280304Sjkim 514280304Sjkim /* Derive gid. */ 515280304Sjkim *gid = strtoul(group, &p, 10); 516280304Sjkim if ((unsigned)*gid == ULONG_MAX) 517280304Sjkim usage(); 518280304Sjkim if (*p != '\0') { 519238405Sjkim gr = getgrnam(group); 520280304Sjkim if (gr == NULL) 521280304Sjkim errx(1, "invalid group: %s", group); 522280304Sjkim *gid = gr->gr_gid; 523280304Sjkim mip->mi_have_gid = true; 524280304Sjkim } 525238405Sjkim 526238405Sjkim free(ug); 527280304Sjkim /* 528280304Sjkim * At this point we don't support only a username or only a 52955714Skris * group name. do_mtptsetup already does, so when this 530280304Sjkim * feature is desired, this is the only routine that needs to 531280304Sjkim * be changed. 532280304Sjkim */ 533280304Sjkim assert(mip->mi_have_uid); 534280304Sjkim assert(mip->mi_have_gid); 53555714Skris} 536280304Sjkim 537280304Sjkim/* 53859194Skris * Run a process with command name and arguments pointed to by the 539280304Sjkim * formatted string 'cmdline'. Since system(3) is not used, the first 540110007Smarkm * space-delimited token of 'cmdline' must be the full pathname of the 541280304Sjkim * program to run. The return value is the return code of the process 542280304Sjkim * spawned. If 'ofd' is non-NULL, it is set to the standard output of 54355949Skris * the program spawned (i.e., you can read from ofd and get the output 544280304Sjkim * of the program). 545280304Sjkim */ 546280304Sjkimstatic int 547280304Sjkimrun(int *ofd, const char *cmdline, ...) 548280304Sjkim{ 54955714Skris char **av, **avp; /* Result of splitting 'cmd'. */ 550280304Sjkim int ac; 551280304Sjkim char *cmd; /* Expansion of 'cmdline'. */ 552280304Sjkim int pid, status; /* Child info. */ 553280304Sjkim int pfd[2]; /* Pipe to the child. */ 554280304Sjkim int nfd; /* Null (/dev/null) file descriptor. */ 55555714Skris bool dup2dn; /* Dup /dev/null to stdout? */ 556280304Sjkim va_list ap; 557280304Sjkim char *p; 55855714Skris int rv, i; 559280304Sjkim 560280304Sjkim dup2dn = true; 561280304Sjkim va_start(ap, cmdline); 562280304Sjkim rv = vasprintf(&cmd, cmdline, ap); 56355714Skris if (rv == -1) 564280304Sjkim err(1, "vasprintf"); 565280304Sjkim va_end(ap); 566280304Sjkim 567280304Sjkim /* Split up 'cmd' into 'av' for use with execve. */ 568280304Sjkim for (ac = 1, p = cmd; (p = strchr(p, ' ')) != NULL; p++) 569280304Sjkim ac++; /* 'ac' generation loop. */ 570280304Sjkim av = (char **)malloc(sizeof(*av) * (ac + 1)); 571280304Sjkim assert(av != NULL); 572280304Sjkim for (p = cmd, avp = av; (*avp = strsep(&p, " ")) != NULL;) 57355714Skris if (**av != '\0') 574280304Sjkim if (++avp >= &av[ac]) { 575280304Sjkim *avp = NULL; 576280304Sjkim break; 577280304Sjkim } 578280304Sjkim assert(*av); 579280304Sjkim 580280304Sjkim /* Make sure the above loop works as expected. */ 581280304Sjkim if (debug) { 582280304Sjkim /* 583280304Sjkim * We can't, but should, use debugprintf here. First, 58455714Skris * it appends a trailing newline to the output, and 585280304Sjkim * second it prepends "DEBUG: " to the output. The 586280304Sjkim * former is a problem for this would-be first call, 58755949Skris * and the latter for the would-be call inside the 588280304Sjkim * loop. 58955714Skris */ 590280304Sjkim (void)fprintf(stderr, "DEBUG: running:"); 591280304Sjkim /* Should be equivilent to 'cmd' (before strsep, of course). */ 592280304Sjkim for (i = 0; av[i] != NULL; i++) 593280304Sjkim (void)fprintf(stderr, " %s", av[i]); 594280304Sjkim (void)fprintf(stderr, "\n"); 595280304Sjkim } 596280304Sjkim 597280304Sjkim /* Create a pipe if necessary and fork the helper program. */ 598280304Sjkim if (ofd != NULL) { 599280304Sjkim if (pipe(&pfd[0]) == -1) 600280304Sjkim err(1, "pipe"); 60155714Skris *ofd = pfd[0]; 602280304Sjkim dup2dn = false; 603280304Sjkim } 60455714Skris pid = fork(); 605280304Sjkim switch (pid) { 606280304Sjkim case 0: 60755714Skris /* XXX can we call err() in here? */ 608280304Sjkim if (norun) 609280304Sjkim _exit(0); 610280304Sjkim if (ofd != NULL) 611280304Sjkim if (dup2(pfd[1], STDOUT_FILENO) < 0) 612280304Sjkim err(1, "dup2"); 613280304Sjkim if (!loudsubs) { 614280304Sjkim nfd = open(_PATH_DEVNULL, O_RDWR); 615280304Sjkim if (nfd == -1) 616280304Sjkim err(1, "open: %s", _PATH_DEVNULL); 617238405Sjkim if (dup2(nfd, STDIN_FILENO) < 0) 618280304Sjkim err(1, "dup2"); 619280304Sjkim if (dup2dn) 620280304Sjkim if (dup2(nfd, STDOUT_FILENO) < 0) 621280304Sjkim err(1, "dup2"); 622280304Sjkim if (dup2(nfd, STDERR_FILENO) < 0) 623280304Sjkim err(1, "dup2"); 624280304Sjkim } 625280304Sjkim 626280304Sjkim (void)execv(av[0], av); 627280304Sjkim warn("exec: %s", av[0]); 628280304Sjkim _exit(-1); 62959194Skris case -1: 630280304Sjkim err(1, "fork"); 631280304Sjkim } 63255714Skris 633280304Sjkim free(cmd); 634280304Sjkim free(av); 635280304Sjkim while (waitpid(pid, &status, 0) != pid) 636280304Sjkim ; 637280304Sjkim return (WEXITSTATUS(status)); 638280304Sjkim} 639280304Sjkim 640280304Sjkimstatic void 641280304Sjkimusage(void) 642280304Sjkim{ 643280304Sjkim 644280304Sjkim fprintf(stderr, 645280304Sjkim"usage: %s [-DLMNSX] [-a maxcontig] [-b block-size] [-c cylinders]\n" 646280304Sjkim"\t[-d rotdelay] [-e maxbpg] [-F file] [-f frag-size] [-i bytes]\n" 647280304Sjkim"\t[-m percent-free] [-n rotational-positions] [-O optimization]\n" 648"\t[-o mount-options] [-p permissions] [-s size] [-w user:group]\n" 649"\tmd-device mount-point\n", getprogname()); 650 exit(1); 651} 652