14d7de91fSDima Dorfman /* 2d69f5deeSDima Dorfman * Copyright (c) 2001 Dima Dorfman. 34d7de91fSDima Dorfman * All rights reserved. 44d7de91fSDima Dorfman * 54d7de91fSDima Dorfman * Redistribution and use in source and binary forms, with or without 64d7de91fSDima Dorfman * modification, are permitted provided that the following conditions 74d7de91fSDima Dorfman * are met: 84d7de91fSDima Dorfman * 1. Redistributions of source code must retain the above copyright 94d7de91fSDima Dorfman * notice, this list of conditions and the following disclaimer. 104d7de91fSDima Dorfman * 2. Redistributions in binary form must reproduce the above copyright 114d7de91fSDima Dorfman * notice, this list of conditions and the following disclaimer in the 124d7de91fSDima Dorfman * documentation and/or other materials provided with the distribution. 134d7de91fSDima Dorfman * 144d7de91fSDima Dorfman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 154d7de91fSDima Dorfman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 164d7de91fSDima Dorfman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 174d7de91fSDima Dorfman * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 184d7de91fSDima Dorfman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 194d7de91fSDima Dorfman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 204d7de91fSDima Dorfman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 214d7de91fSDima Dorfman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 224d7de91fSDima Dorfman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 234d7de91fSDima Dorfman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 244d7de91fSDima Dorfman * SUCH DAMAGE. 254d7de91fSDima Dorfman */ 264d7de91fSDima Dorfman 274d7de91fSDima Dorfman /* 28b7e368f7SPoul-Henning Kamp * mdmfs (md/MFS) is a wrapper around mdconfig(8), 294d7de91fSDima Dorfman * newfs(8), and mount(8) that mimics the command line option set of 304d7de91fSDima Dorfman * the deprecated mount_mfs(8). 314d7de91fSDima Dorfman */ 324d7de91fSDima Dorfman 33c69284caSDavid E. O'Brien #include <sys/cdefs.h> 34c69284caSDavid E. O'Brien __FBSDID("$FreeBSD$"); 354d7de91fSDima Dorfman 364d7de91fSDima Dorfman #include <sys/param.h> 374d7de91fSDima Dorfman #include <sys/mdioctl.h> 384d7de91fSDima Dorfman #include <sys/stat.h> 394d7de91fSDima Dorfman #include <sys/wait.h> 404d7de91fSDima Dorfman 414d7de91fSDima Dorfman #include <assert.h> 424d7de91fSDima Dorfman #include <err.h> 434d7de91fSDima Dorfman #include <fcntl.h> 444d7de91fSDima Dorfman #include <grp.h> 454d7de91fSDima Dorfman #include <paths.h> 464d7de91fSDima Dorfman #include <pwd.h> 474d7de91fSDima Dorfman #include <stdarg.h> 484d7de91fSDima Dorfman #include <stdio.h> 494d7de91fSDima Dorfman #include <stdlib.h> 504d7de91fSDima Dorfman #include <string.h> 514d7de91fSDima Dorfman #include <unistd.h> 524d7de91fSDima Dorfman 534d7de91fSDima Dorfman typedef enum { false, true } bool; 544d7de91fSDima Dorfman 554d7de91fSDima Dorfman struct mtpt_info { 564d7de91fSDima Dorfman uid_t mi_uid; 574d7de91fSDima Dorfman bool mi_have_uid; 584d7de91fSDima Dorfman gid_t mi_gid; 594d7de91fSDima Dorfman bool mi_have_gid; 604d7de91fSDima Dorfman mode_t mi_mode; 614d7de91fSDima Dorfman bool mi_have_mode; 624d7de91fSDima Dorfman }; 634d7de91fSDima Dorfman 644d7de91fSDima Dorfman static bool debug; /* Emit debugging information? */ 654d7de91fSDima Dorfman static bool loudsubs; /* Suppress output from helper programs? */ 664d7de91fSDima Dorfman static bool norun; /* Actually run the helper programs? */ 674d7de91fSDima Dorfman static int unit; /* The unit we're working with. */ 684d7de91fSDima Dorfman static const char *mdname; /* Name of memory disk device (e.g., "md"). */ 694d7de91fSDima Dorfman static size_t mdnamelen; /* Length of mdname. */ 7063f8ddbeSMaxim Sobolev static const char *path_mdconfig =_PATH_MDCONFIG; 714d7de91fSDima Dorfman 72bc56b93aSKris Kennaway static void argappend(char **, const char *, ...) __printflike(2, 3); 73bc56b93aSKris Kennaway static void debugprintf(const char *, ...) __printflike(1, 2); 744d7de91fSDima Dorfman static void do_mdconfig_attach(const char *, const enum md_types); 754d7de91fSDima Dorfman static void do_mdconfig_attach_au(const char *, const enum md_types); 764d7de91fSDima Dorfman static void do_mdconfig_detach(void); 774d7de91fSDima Dorfman static void do_mount(const char *, const char *); 784d7de91fSDima Dorfman static void do_mtptsetup(const char *, struct mtpt_info *); 794d7de91fSDima Dorfman static void do_newfs(const char *); 804d7de91fSDima Dorfman static void extract_ugid(const char *, struct mtpt_info *); 81bc56b93aSKris Kennaway static int run(int *, const char *, ...) __printflike(2, 3); 824d7de91fSDima Dorfman static void usage(void); 834d7de91fSDima Dorfman 844d7de91fSDima Dorfman int 8594ddc5afSDavid E. O'Brien main(int argc, char **argv) 864d7de91fSDima Dorfman { 874d7de91fSDima Dorfman struct mtpt_info mi; /* Mountpoint info. */ 884d7de91fSDima Dorfman char *mdconfig_arg, *newfs_arg, /* Args to helper programs. */ 894d7de91fSDima Dorfman *mount_arg; 904d7de91fSDima Dorfman enum md_types mdtype; /* The type of our memory disk. */ 914d7de91fSDima Dorfman bool have_mdtype; 9205b2fd30SDima Dorfman bool detach, softdep, autounit, newfs; 934d7de91fSDima Dorfman char *mtpoint, *unitstr; 945cfe0423SPeter Grehan char *p; 955cfe0423SPeter Grehan int ch; 96ce03e3a7SYaroslav Tykhiy void *set; 9747376189SSuleiman Souhlal unsigned long ul; 984d7de91fSDima Dorfman 994d7de91fSDima Dorfman /* Misc. initialization. */ 1004d7de91fSDima Dorfman (void)memset(&mi, '\0', sizeof(mi)); 1014d7de91fSDima Dorfman detach = true; 1024d7de91fSDima Dorfman softdep = true; 1034d7de91fSDima Dorfman autounit = false; 10405b2fd30SDima Dorfman newfs = true; 1054d7de91fSDima Dorfman have_mdtype = false; 1066449237fSSuleiman Souhlal mdtype = MD_SWAP; 1074d7de91fSDima Dorfman mdname = MD_NAME; 1084d7de91fSDima Dorfman mdnamelen = strlen(mdname); 1094d7de91fSDima Dorfman /* 1104d7de91fSDima Dorfman * Can't set these to NULL. They may be passed to the 1114d7de91fSDima Dorfman * respective programs without modification. I.e., we may not 1124d7de91fSDima Dorfman * receive any command-line options which will caused them to 1134d7de91fSDima Dorfman * be modified. 1144d7de91fSDima Dorfman */ 1154d7de91fSDima Dorfman mdconfig_arg = strdup(""); 1164d7de91fSDima Dorfman newfs_arg = strdup(""); 1174d7de91fSDima Dorfman mount_arg = strdup(""); 1184d7de91fSDima Dorfman 1192dc4ac06SIan Dowse /* If we were started as mount_mfs or mfs, imply -C. */ 1202dc4ac06SIan Dowse if (strcmp(getprogname(), "mount_mfs") == 0 || 121957d7c8fSRuslan Ermilov strcmp(getprogname(), "mfs") == 0) { 122957d7c8fSRuslan Ermilov /* Make compatibility assumptions. */ 123957d7c8fSRuslan Ermilov mi.mi_mode = 01777; 124957d7c8fSRuslan Ermilov mi.mi_have_mode = true; 125957d7c8fSRuslan Ermilov } 126f7acb7e4SDima Dorfman 12794ddc5afSDavid E. O'Brien while ((ch = getopt(argc, argv, 12863f8ddbeSMaxim Sobolev "a:b:Cc:Dd:E:e:F:f:hi:LlMm:Nn:O:o:Pp:Ss:t:Uv:w:X")) != -1) 1294d7de91fSDima Dorfman switch (ch) { 1304d7de91fSDima Dorfman case 'a': 1314d7de91fSDima Dorfman argappend(&newfs_arg, "-a %s", optarg); 1324d7de91fSDima Dorfman break; 1334d7de91fSDima Dorfman case 'b': 1344d7de91fSDima Dorfman argappend(&newfs_arg, "-b %s", optarg); 1354d7de91fSDima Dorfman break; 136f7acb7e4SDima Dorfman case 'C': 137957d7c8fSRuslan Ermilov /* Ignored for compatibility. */ 138f7acb7e4SDima Dorfman break; 1394d7de91fSDima Dorfman case 'c': 1404d7de91fSDima Dorfman argappend(&newfs_arg, "-c %s", optarg); 1414d7de91fSDima Dorfman break; 1424d7de91fSDima Dorfman case 'D': 1434d7de91fSDima Dorfman detach = false; 1444d7de91fSDima Dorfman break; 1454d7de91fSDima Dorfman case 'd': 1464d7de91fSDima Dorfman argappend(&newfs_arg, "-d %s", optarg); 1474d7de91fSDima Dorfman break; 14863f8ddbeSMaxim Sobolev case 'E': 14963f8ddbeSMaxim Sobolev path_mdconfig = optarg; 15063f8ddbeSMaxim Sobolev break; 1514d7de91fSDima Dorfman case 'e': 1524d7de91fSDima Dorfman argappend(&newfs_arg, "-e %s", optarg); 1534d7de91fSDima Dorfman break; 1544d7de91fSDima Dorfman case 'F': 1554d7de91fSDima Dorfman if (have_mdtype) 1564d7de91fSDima Dorfman usage(); 1574d7de91fSDima Dorfman mdtype = MD_VNODE; 1584d7de91fSDima Dorfman have_mdtype = true; 1594d7de91fSDima Dorfman argappend(&mdconfig_arg, "-f %s", optarg); 1604d7de91fSDima Dorfman break; 1614d7de91fSDima Dorfman case 'f': 1624d7de91fSDima Dorfman argappend(&newfs_arg, "-f %s", optarg); 1634d7de91fSDima Dorfman break; 1644d7de91fSDima Dorfman case 'h': 1654d7de91fSDima Dorfman usage(); 1664d7de91fSDima Dorfman break; 1674d7de91fSDima Dorfman case 'i': 1684d7de91fSDima Dorfman argappend(&newfs_arg, "-i %s", optarg); 1694d7de91fSDima Dorfman break; 1704d7de91fSDima Dorfman case 'L': 1714d7de91fSDima Dorfman loudsubs = true; 1724d7de91fSDima Dorfman break; 1731d3170aaSRobert Watson case 'l': 1741d3170aaSRobert Watson argappend(&newfs_arg, "-l"); 1751d3170aaSRobert Watson break; 1764d7de91fSDima Dorfman case 'M': 1774d7de91fSDima Dorfman if (have_mdtype) 1784d7de91fSDima Dorfman usage(); 1794d7de91fSDima Dorfman mdtype = MD_MALLOC; 1804d7de91fSDima Dorfman have_mdtype = true; 1814d7de91fSDima Dorfman break; 1824d7de91fSDima Dorfman case 'm': 1834d7de91fSDima Dorfman argappend(&newfs_arg, "-m %s", optarg); 1844d7de91fSDima Dorfman break; 1854d7de91fSDima Dorfman case 'N': 1864d7de91fSDima Dorfman norun = true; 1874d7de91fSDima Dorfman break; 1884d7de91fSDima Dorfman case 'n': 1894d7de91fSDima Dorfman argappend(&newfs_arg, "-n %s", optarg); 1904d7de91fSDima Dorfman break; 1914d7de91fSDima Dorfman case 'O': 1924d7de91fSDima Dorfman argappend(&newfs_arg, "-o %s", optarg); 1934d7de91fSDima Dorfman break; 1944d7de91fSDima Dorfman case 'o': 1954d7de91fSDima Dorfman argappend(&mount_arg, "-o %s", optarg); 1964d7de91fSDima Dorfman break; 19705b2fd30SDima Dorfman case 'P': 19805b2fd30SDima Dorfman newfs = false; 19905b2fd30SDima Dorfman break; 2004d7de91fSDima Dorfman case 'p': 201ce03e3a7SYaroslav Tykhiy if ((set = setmode(optarg)) == NULL) 2024d7de91fSDima Dorfman usage(); 203ce03e3a7SYaroslav Tykhiy mi.mi_mode = getmode(set, S_IRWXU | S_IRWXG | S_IRWXO); 2044d7de91fSDima Dorfman mi.mi_have_mode = true; 205ce03e3a7SYaroslav Tykhiy free(set); 2064d7de91fSDima Dorfman break; 2074d7de91fSDima Dorfman case 'S': 2084d7de91fSDima Dorfman softdep = false; 2094d7de91fSDima Dorfman break; 2104d7de91fSDima Dorfman case 's': 2114d7de91fSDima Dorfman argappend(&mdconfig_arg, "-s %s", optarg); 2124d7de91fSDima Dorfman break; 213f7acb7e4SDima Dorfman case 'U': 214f7acb7e4SDima Dorfman softdep = true; 215f7acb7e4SDima Dorfman break; 216622448faSRobert Watson case 'v': 217622448faSRobert Watson argappend(&newfs_arg, "-O %s", optarg); 218622448faSRobert Watson break; 2194d7de91fSDima Dorfman case 'w': 2204d7de91fSDima Dorfman extract_ugid(optarg, &mi); 2214d7de91fSDima Dorfman break; 2224d7de91fSDima Dorfman case 'X': 2234d7de91fSDima Dorfman debug = true; 2244d7de91fSDima Dorfman break; 2254d7de91fSDima Dorfman default: 2264d7de91fSDima Dorfman usage(); 2274d7de91fSDima Dorfman } 22894ddc5afSDavid E. O'Brien argc -= optind; 22994ddc5afSDavid E. O'Brien argv += optind; 23094ddc5afSDavid E. O'Brien if (argc < 2) 2314d7de91fSDima Dorfman usage(); 2324d7de91fSDima Dorfman 2334d7de91fSDima Dorfman /* Derive 'unit' (global). */ 23494ddc5afSDavid E. O'Brien unitstr = argv[0]; 2354d7de91fSDima Dorfman if (strncmp(unitstr, "/dev/", 5) == 0) 2364d7de91fSDima Dorfman unitstr += 5; 2374d7de91fSDima Dorfman if (strncmp(unitstr, mdname, mdnamelen) == 0) 2384d7de91fSDima Dorfman unitstr += mdnamelen; 2394d7de91fSDima Dorfman if (*unitstr == '\0') { 2404d7de91fSDima Dorfman autounit = true; 2414d7de91fSDima Dorfman unit = -1; 2424d7de91fSDima Dorfman } else { 24347376189SSuleiman Souhlal ul = strtoul(unitstr, &p, 10); 24447376189SSuleiman Souhlal if (ul == ULONG_MAX || *p != '\0') 2454d7de91fSDima Dorfman errx(1, "bad device unit: %s", unitstr); 24647376189SSuleiman Souhlal unit = ul; 2474d7de91fSDima Dorfman } 2484d7de91fSDima Dorfman 24994ddc5afSDavid E. O'Brien mtpoint = argv[1]; 2504d7de91fSDima Dorfman if (!have_mdtype) 2514d7de91fSDima Dorfman mdtype = MD_SWAP; 2524d7de91fSDima Dorfman if (softdep) 2534d7de91fSDima Dorfman argappend(&newfs_arg, "-U"); 25405b2fd30SDima Dorfman if (mdtype != MD_VNODE && !newfs) 25505b2fd30SDima Dorfman errx(1, "-P requires a vnode-backed disk"); 2564d7de91fSDima Dorfman 2574d7de91fSDima Dorfman /* Do the work. */ 2584d7de91fSDima Dorfman if (detach && !autounit) 2594d7de91fSDima Dorfman do_mdconfig_detach(); 2604d7de91fSDima Dorfman if (autounit) 2614d7de91fSDima Dorfman do_mdconfig_attach_au(mdconfig_arg, mdtype); 2624d7de91fSDima Dorfman else 2634d7de91fSDima Dorfman do_mdconfig_attach(mdconfig_arg, mdtype); 26405b2fd30SDima Dorfman if (newfs) 2654d7de91fSDima Dorfman do_newfs(newfs_arg); 2664d7de91fSDima Dorfman do_mount(mount_arg, mtpoint); 2674d7de91fSDima Dorfman do_mtptsetup(mtpoint, &mi); 2684d7de91fSDima Dorfman 2694d7de91fSDima Dorfman return (0); 2704d7de91fSDima Dorfman } 2714d7de91fSDima Dorfman 2724d7de91fSDima Dorfman /* 2734d7de91fSDima Dorfman * Append the expansion of 'fmt' to the buffer pointed to by '*dstp'; 2744d7de91fSDima Dorfman * reallocate as required. 2754d7de91fSDima Dorfman */ 2764d7de91fSDima Dorfman static void 2774d7de91fSDima Dorfman argappend(char **dstp, const char *fmt, ...) 2784d7de91fSDima Dorfman { 2794d7de91fSDima Dorfman char *old, *new; 2804d7de91fSDima Dorfman va_list ap; 2814d7de91fSDima Dorfman 2824d7de91fSDima Dorfman old = *dstp; 2834d7de91fSDima Dorfman assert(old != NULL); 2844d7de91fSDima Dorfman 2854d7de91fSDima Dorfman va_start(ap, fmt); 2864d7de91fSDima Dorfman if (vasprintf(&new, fmt,ap) == -1) 2874d7de91fSDima Dorfman errx(1, "vasprintf"); 2884d7de91fSDima Dorfman va_end(ap); 2894d7de91fSDima Dorfman 2904d7de91fSDima Dorfman *dstp = new; 2914d7de91fSDima Dorfman if (asprintf(&new, "%s %s", old, new) == -1) 2924d7de91fSDima Dorfman errx(1, "asprintf"); 2934d7de91fSDima Dorfman free(*dstp); 2944d7de91fSDima Dorfman free(old); 2954d7de91fSDima Dorfman 2964d7de91fSDima Dorfman *dstp = new; 2974d7de91fSDima Dorfman } 2984d7de91fSDima Dorfman 2994d7de91fSDima Dorfman /* 3004d7de91fSDima Dorfman * If run-time debugging is enabled, print the expansion of 'fmt'. 3014d7de91fSDima Dorfman * Otherwise, do nothing. 3024d7de91fSDima Dorfman */ 3034d7de91fSDima Dorfman static void 3044d7de91fSDima Dorfman debugprintf(const char *fmt, ...) 3054d7de91fSDima Dorfman { 3064d7de91fSDima Dorfman va_list ap; 3074d7de91fSDima Dorfman 3084d7de91fSDima Dorfman if (!debug) 3094d7de91fSDima Dorfman return; 3104d7de91fSDima Dorfman fprintf(stderr, "DEBUG: "); 3114d7de91fSDima Dorfman va_start(ap, fmt); 3124d7de91fSDima Dorfman vfprintf(stderr, fmt, ap); 3134d7de91fSDima Dorfman va_end(ap); 3144d7de91fSDima Dorfman fprintf(stderr, "\n"); 3154d7de91fSDima Dorfman fflush(stderr); 3164d7de91fSDima Dorfman } 3174d7de91fSDima Dorfman 3184d7de91fSDima Dorfman /* 3194d7de91fSDima Dorfman * Attach a memory disk with a known unit. 3204d7de91fSDima Dorfman */ 3214d7de91fSDima Dorfman static void 3224d7de91fSDima Dorfman do_mdconfig_attach(const char *args, const enum md_types mdtype) 3234d7de91fSDima Dorfman { 3244d7de91fSDima Dorfman int rv; 3254d7de91fSDima Dorfman const char *ta; /* Type arg. */ 3264d7de91fSDima Dorfman 3274d7de91fSDima Dorfman switch (mdtype) { 3284d7de91fSDima Dorfman case MD_SWAP: 3294d7de91fSDima Dorfman ta = "-t swap"; 3304d7de91fSDima Dorfman break; 3314d7de91fSDima Dorfman case MD_VNODE: 3324d7de91fSDima Dorfman ta = "-t vnode"; 3334d7de91fSDima Dorfman break; 3344d7de91fSDima Dorfman case MD_MALLOC: 3354d7de91fSDima Dorfman ta = "-t malloc"; 3364d7de91fSDima Dorfman break; 3374d7de91fSDima Dorfman default: 3384d7de91fSDima Dorfman abort(); 3394d7de91fSDima Dorfman } 34063f8ddbeSMaxim Sobolev rv = run(NULL, "%s -a %s%s -u %s%d", path_mdconfig, ta, args, 3414d7de91fSDima Dorfman mdname, unit); 3424d7de91fSDima Dorfman if (rv) 3434d7de91fSDima Dorfman errx(1, "mdconfig (attach) exited with error code %d", rv); 3444d7de91fSDima Dorfman } 3454d7de91fSDima Dorfman 3464d7de91fSDima Dorfman /* 3474d7de91fSDima Dorfman * Attach a memory disk with an unknown unit; use autounit. 3484d7de91fSDima Dorfman */ 3494d7de91fSDima Dorfman static void 3504d7de91fSDima Dorfman do_mdconfig_attach_au(const char *args, const enum md_types mdtype) 3514d7de91fSDima Dorfman { 3524d7de91fSDima Dorfman const char *ta; /* Type arg. */ 3534d7de91fSDima Dorfman char *linep, *linebuf; /* Line pointer, line buffer. */ 3544d7de91fSDima Dorfman int fd; /* Standard output of mdconfig invocation. */ 3554d7de91fSDima Dorfman FILE *sfd; 3564d7de91fSDima Dorfman int rv; 3574d7de91fSDima Dorfman char *p; 3584d7de91fSDima Dorfman size_t linelen; 35947376189SSuleiman Souhlal unsigned long ul; 3604d7de91fSDima Dorfman 3614d7de91fSDima Dorfman switch (mdtype) { 3624d7de91fSDima Dorfman case MD_SWAP: 3634d7de91fSDima Dorfman ta = "-t swap"; 3644d7de91fSDima Dorfman break; 3654d7de91fSDima Dorfman case MD_VNODE: 3664d7de91fSDima Dorfman ta = "-t vnode"; 3674d7de91fSDima Dorfman break; 3684d7de91fSDima Dorfman case MD_MALLOC: 3694d7de91fSDima Dorfman ta = "-t malloc"; 3704d7de91fSDima Dorfman break; 3714d7de91fSDima Dorfman default: 3724d7de91fSDima Dorfman abort(); 3734d7de91fSDima Dorfman } 37463f8ddbeSMaxim Sobolev rv = run(&fd, "%s -a %s%s", path_mdconfig, ta, args); 3754d7de91fSDima Dorfman if (rv) 3764d7de91fSDima Dorfman errx(1, "mdconfig (attach) exited with error code %d", rv); 3774d7de91fSDima Dorfman 3784d7de91fSDima Dorfman /* Receive the unit number. */ 3794d7de91fSDima Dorfman if (norun) { /* Since we didn't run, we can't read. Fake it. */ 380541ce3c1SDima Dorfman unit = 0; 3814d7de91fSDima Dorfman return; 3824d7de91fSDima Dorfman } 3834d7de91fSDima Dorfman sfd = fdopen(fd, "r"); 3844d7de91fSDima Dorfman if (sfd == NULL) 3854d7de91fSDima Dorfman err(1, "fdopen"); 3864d7de91fSDima Dorfman linep = fgetln(sfd, &linelen); 3874d7de91fSDima Dorfman if (linep == NULL && linelen < mdnamelen + 1) 3884d7de91fSDima Dorfman errx(1, "unexpected output from mdconfig (attach)"); 3894d7de91fSDima Dorfman /* If the output format changes, we want to know about it. */ 3904d7de91fSDima Dorfman assert(strncmp(linep, mdname, mdnamelen) == 0); 3914d7de91fSDima Dorfman linebuf = malloc(linelen - mdnamelen + 1); 3924d7de91fSDima Dorfman assert(linebuf != NULL); 3934d7de91fSDima Dorfman /* Can't use strlcpy because linep is not NULL-terminated. */ 3944d7de91fSDima Dorfman strncpy(linebuf, linep + mdnamelen, linelen); 3954d7de91fSDima Dorfman linebuf[linelen] = '\0'; 39647376189SSuleiman Souhlal ul = strtoul(linebuf, &p, 10); 39747376189SSuleiman Souhlal if (ul == ULONG_MAX || *p != '\n') 3984d7de91fSDima Dorfman errx(1, "unexpected output from mdconfig (attach)"); 39947376189SSuleiman Souhlal unit = ul; 4004d7de91fSDima Dorfman 4014d7de91fSDima Dorfman fclose(sfd); 4024d7de91fSDima Dorfman close(fd); 4034d7de91fSDima Dorfman } 4044d7de91fSDima Dorfman 4054d7de91fSDima Dorfman /* 4064d7de91fSDima Dorfman * Detach a memory disk. 4074d7de91fSDima Dorfman */ 4084d7de91fSDima Dorfman static void 4094d7de91fSDima Dorfman do_mdconfig_detach(void) 4104d7de91fSDima Dorfman { 4114d7de91fSDima Dorfman int rv; 4124d7de91fSDima Dorfman 41363f8ddbeSMaxim Sobolev rv = run(NULL, "%s -d -u %s%d", path_mdconfig, mdname, unit); 4144d7de91fSDima Dorfman if (rv && debug) /* This is allowed to fail. */ 4154d7de91fSDima Dorfman warnx("mdconfig (detach) exited with error code %d (ignored)", 4164d7de91fSDima Dorfman rv); 4174d7de91fSDima Dorfman } 4184d7de91fSDima Dorfman 4194d7de91fSDima Dorfman /* 4204d7de91fSDima Dorfman * Mount the configured memory disk. 4214d7de91fSDima Dorfman */ 4224d7de91fSDima Dorfman static void 4234d7de91fSDima Dorfman do_mount(const char *args, const char *mtpoint) 4244d7de91fSDima Dorfman { 4254d7de91fSDima Dorfman int rv; 4264d7de91fSDima Dorfman 4271386defaSGordon Tetlow rv = run(NULL, "%s%s /dev/%s%d %s", _PATH_MOUNT, args, 4284d7de91fSDima Dorfman mdname, unit, mtpoint); 4294d7de91fSDima Dorfman if (rv) 4304d7de91fSDima Dorfman errx(1, "mount exited with error code %d", rv); 4314d7de91fSDima Dorfman } 4324d7de91fSDima Dorfman 4334d7de91fSDima Dorfman /* 4344d7de91fSDima Dorfman * Various configuration of the mountpoint. Mostly, enact 'mip'. 4354d7de91fSDima Dorfman */ 4364d7de91fSDima Dorfman static void 4374d7de91fSDima Dorfman do_mtptsetup(const char *mtpoint, struct mtpt_info *mip) 4384d7de91fSDima Dorfman { 4394d7de91fSDima Dorfman 4404d7de91fSDima Dorfman if (mip->mi_have_mode) { 4414d7de91fSDima Dorfman debugprintf("changing mode of %s to %o.", mtpoint, 4424d7de91fSDima Dorfman mip->mi_mode); 4434d7de91fSDima Dorfman if (!norun) 4444d7de91fSDima Dorfman if (chmod(mtpoint, mip->mi_mode) == -1) 4454d7de91fSDima Dorfman err(1, "chmod: %s", mtpoint); 4464d7de91fSDima Dorfman } 4474d7de91fSDima Dorfman /* 4484d7de91fSDima Dorfman * We have to do these separately because the user may have 4494d7de91fSDima Dorfman * only specified one of them. 4504d7de91fSDima Dorfman */ 4514d7de91fSDima Dorfman if (mip->mi_have_uid) { 4524d7de91fSDima Dorfman debugprintf("changing owner (user) or %s to %u.", mtpoint, 4534d7de91fSDima Dorfman mip->mi_uid); 4544d7de91fSDima Dorfman if (!norun) 4554d7de91fSDima Dorfman if (chown(mtpoint, mip->mi_uid, -1) == -1) 4564d7de91fSDima Dorfman err(1, "chown %s to %u (user)", mtpoint, 4574d7de91fSDima Dorfman mip->mi_uid); 4584d7de91fSDima Dorfman } 4594d7de91fSDima Dorfman if (mip->mi_have_gid) { 4604d7de91fSDima Dorfman debugprintf("changing owner (group) or %s to %u.", mtpoint, 4614d7de91fSDima Dorfman mip->mi_gid); 4624d7de91fSDima Dorfman if (!norun) 4634d7de91fSDima Dorfman if (chown(mtpoint, -1, mip->mi_gid) == -1) 4644d7de91fSDima Dorfman err(1, "chown %s to %u (group)", mtpoint, 4654d7de91fSDima Dorfman mip->mi_gid); 4664d7de91fSDima Dorfman } 4674d7de91fSDima Dorfman } 4684d7de91fSDima Dorfman 4694d7de91fSDima Dorfman /* 4704d7de91fSDima Dorfman * Put a file system on the memory disk. 4714d7de91fSDima Dorfman */ 4724d7de91fSDima Dorfman static void 4734d7de91fSDima Dorfman do_newfs(const char *args) 4744d7de91fSDima Dorfman { 4754d7de91fSDima Dorfman int rv; 4764d7de91fSDima Dorfman 4771386defaSGordon Tetlow rv = run(NULL, "%s%s /dev/%s%d", _PATH_NEWFS, args, mdname, unit); 4784d7de91fSDima Dorfman if (rv) 4794d7de91fSDima Dorfman errx(1, "newfs exited with error code %d", rv); 4804d7de91fSDima Dorfman } 4814d7de91fSDima Dorfman 4824d7de91fSDima Dorfman /* 4834d7de91fSDima Dorfman * 'str' should be a user and group name similar to the last argument 4844d7de91fSDima Dorfman * to chown(1); i.e., a user, followed by a colon, followed by a 4854d7de91fSDima Dorfman * group. The user and group in 'str' may be either a [ug]id or a 4864d7de91fSDima Dorfman * name. Upon return, the uid and gid fields in 'mip' will contain 4874d7de91fSDima Dorfman * the uid and gid of the user and group name in 'str', respectively. 4884d7de91fSDima Dorfman * 4894d7de91fSDima Dorfman * In other words, this derives a user and group id from a string 4904d7de91fSDima Dorfman * formatted like the last argument to chown(1). 491de90a634SRalf S. Engelschall * 492de90a634SRalf S. Engelschall * Notice: At this point we don't support only a username or only a 493de90a634SRalf S. Engelschall * group name. do_mtptsetup already does, so when this feature is 494de90a634SRalf S. Engelschall * desired, this is the only routine that needs to be changed. 4954d7de91fSDima Dorfman */ 4964d7de91fSDima Dorfman static void 4974d7de91fSDima Dorfman extract_ugid(const char *str, struct mtpt_info *mip) 4984d7de91fSDima Dorfman { 4994d7de91fSDima Dorfman char *ug; /* Writable 'str'. */ 5004d7de91fSDima Dorfman char *user, *group; /* Result of extracton. */ 5014d7de91fSDima Dorfman struct passwd *pw; 5024d7de91fSDima Dorfman struct group *gr; 5034d7de91fSDima Dorfman char *p; 5044d7de91fSDima Dorfman uid_t *uid; 5054d7de91fSDima Dorfman gid_t *gid; 5064d7de91fSDima Dorfman 5074d7de91fSDima Dorfman uid = &mip->mi_uid; 5084d7de91fSDima Dorfman gid = &mip->mi_gid; 5094d7de91fSDima Dorfman mip->mi_have_uid = mip->mi_have_gid = false; 5104d7de91fSDima Dorfman 5114d7de91fSDima Dorfman /* Extract the user and group from 'str'. Format above. */ 5128d3c1246SDima Dorfman ug = strdup(str); 5134d7de91fSDima Dorfman assert(ug != NULL); 5144d7de91fSDima Dorfman group = ug; 5154d7de91fSDima Dorfman user = strsep(&group, ":"); 5164d7de91fSDima Dorfman if (user == NULL || group == NULL || *user == '\0' || *group == '\0') 5174d7de91fSDima Dorfman usage(); 5184d7de91fSDima Dorfman 5194d7de91fSDima Dorfman /* Derive uid. */ 5204d7de91fSDima Dorfman *uid = strtoul(user, &p, 10); 5218a50130bSAlexander Kabaev if (*uid == (uid_t)ULONG_MAX) 5224d7de91fSDima Dorfman usage(); 5234d7de91fSDima Dorfman if (*p != '\0') { 5244d7de91fSDima Dorfman pw = getpwnam(user); 5254d7de91fSDima Dorfman if (pw == NULL) 5264d7de91fSDima Dorfman errx(1, "invalid user: %s", user); 5274d7de91fSDima Dorfman *uid = pw->pw_uid; 5284d7de91fSDima Dorfman } 529de90a634SRalf S. Engelschall mip->mi_have_uid = true; 5304d7de91fSDima Dorfman 5314d7de91fSDima Dorfman /* Derive gid. */ 5324d7de91fSDima Dorfman *gid = strtoul(group, &p, 10); 5338a50130bSAlexander Kabaev if (*gid == (gid_t)ULONG_MAX) 5344d7de91fSDima Dorfman usage(); 5354d7de91fSDima Dorfman if (*p != '\0') { 5364d7de91fSDima Dorfman gr = getgrnam(group); 5374d7de91fSDima Dorfman if (gr == NULL) 5384d7de91fSDima Dorfman errx(1, "invalid group: %s", group); 5394d7de91fSDima Dorfman *gid = gr->gr_gid; 5404d7de91fSDima Dorfman } 541de90a634SRalf S. Engelschall mip->mi_have_gid = true; 5424d7de91fSDima Dorfman 5434d7de91fSDima Dorfman free(ug); 5444d7de91fSDima Dorfman } 5454d7de91fSDima Dorfman 5464d7de91fSDima Dorfman /* 5474d7de91fSDima Dorfman * Run a process with command name and arguments pointed to by the 5484d7de91fSDima Dorfman * formatted string 'cmdline'. Since system(3) is not used, the first 5494d7de91fSDima Dorfman * space-delimited token of 'cmdline' must be the full pathname of the 5504d7de91fSDima Dorfman * program to run. The return value is the return code of the process 5514d7de91fSDima Dorfman * spawned. If 'ofd' is non-NULL, it is set to the standard output of 5524d7de91fSDima Dorfman * the program spawned (i.e., you can read from ofd and get the output 5534d7de91fSDima Dorfman * of the program). 5544d7de91fSDima Dorfman */ 5554d7de91fSDima Dorfman static int 5564d7de91fSDima Dorfman run(int *ofd, const char *cmdline, ...) 5574d7de91fSDima Dorfman { 55894ddc5afSDavid E. O'Brien char **argv, **argvp; /* Result of splitting 'cmd'. */ 55994ddc5afSDavid E. O'Brien int argc; 5604d7de91fSDima Dorfman char *cmd; /* Expansion of 'cmdline'. */ 5614d7de91fSDima Dorfman int pid, status; /* Child info. */ 5624d7de91fSDima Dorfman int pfd[2]; /* Pipe to the child. */ 5634d7de91fSDima Dorfman int nfd; /* Null (/dev/null) file descriptor. */ 5644d7de91fSDima Dorfman bool dup2dn; /* Dup /dev/null to stdout? */ 5654d7de91fSDima Dorfman va_list ap; 5664d7de91fSDima Dorfman char *p; 5674d7de91fSDima Dorfman int rv, i; 5684d7de91fSDima Dorfman 5694d7de91fSDima Dorfman dup2dn = true; 5704d7de91fSDima Dorfman va_start(ap, cmdline); 5714d7de91fSDima Dorfman rv = vasprintf(&cmd, cmdline, ap); 5724d7de91fSDima Dorfman if (rv == -1) 5734d7de91fSDima Dorfman err(1, "vasprintf"); 5744d7de91fSDima Dorfman va_end(ap); 5754d7de91fSDima Dorfman 57694ddc5afSDavid E. O'Brien /* Split up 'cmd' into 'argv' for use with execve. */ 57794ddc5afSDavid E. O'Brien for (argc = 1, p = cmd; (p = strchr(p, ' ')) != NULL; p++) 57894ddc5afSDavid E. O'Brien argc++; /* 'argc' generation loop. */ 57994ddc5afSDavid E. O'Brien argv = (char **)malloc(sizeof(*argv) * (argc + 1)); 58094ddc5afSDavid E. O'Brien assert(argv != NULL); 58194ddc5afSDavid E. O'Brien for (p = cmd, argvp = argv; (*argvp = strsep(&p, " ")) != NULL;) 58294ddc5afSDavid E. O'Brien if (**argv != '\0') 58394ddc5afSDavid E. O'Brien if (++argvp >= &argv[argc]) { 58494ddc5afSDavid E. O'Brien *argvp = NULL; 5854d7de91fSDima Dorfman break; 5864d7de91fSDima Dorfman } 58794ddc5afSDavid E. O'Brien assert(*argv); 5884d7de91fSDima Dorfman 5894d7de91fSDima Dorfman /* Make sure the above loop works as expected. */ 5904d7de91fSDima Dorfman if (debug) { 5914d7de91fSDima Dorfman /* 5924d7de91fSDima Dorfman * We can't, but should, use debugprintf here. First, 5934d7de91fSDima Dorfman * it appends a trailing newline to the output, and 5944d7de91fSDima Dorfman * second it prepends "DEBUG: " to the output. The 5954d7de91fSDima Dorfman * former is a problem for this would-be first call, 5964d7de91fSDima Dorfman * and the latter for the would-be call inside the 5974d7de91fSDima Dorfman * loop. 5984d7de91fSDima Dorfman */ 5994d7de91fSDima Dorfman (void)fprintf(stderr, "DEBUG: running:"); 6004d7de91fSDima Dorfman /* Should be equivilent to 'cmd' (before strsep, of course). */ 60194ddc5afSDavid E. O'Brien for (i = 0; argv[i] != NULL; i++) 60294ddc5afSDavid E. O'Brien (void)fprintf(stderr, " %s", argv[i]); 6034d7de91fSDima Dorfman (void)fprintf(stderr, "\n"); 6044d7de91fSDima Dorfman } 6054d7de91fSDima Dorfman 6064d7de91fSDima Dorfman /* Create a pipe if necessary and fork the helper program. */ 6074d7de91fSDima Dorfman if (ofd != NULL) { 6084d7de91fSDima Dorfman if (pipe(&pfd[0]) == -1) 6094d7de91fSDima Dorfman err(1, "pipe"); 6104d7de91fSDima Dorfman *ofd = pfd[0]; 6114d7de91fSDima Dorfman dup2dn = false; 6124d7de91fSDima Dorfman } 6134d7de91fSDima Dorfman pid = fork(); 6144d7de91fSDima Dorfman switch (pid) { 6154d7de91fSDima Dorfman case 0: 6164d7de91fSDima Dorfman /* XXX can we call err() in here? */ 6174d7de91fSDima Dorfman if (norun) 6184d7de91fSDima Dorfman _exit(0); 6194d7de91fSDima Dorfman if (ofd != NULL) 6204d7de91fSDima Dorfman if (dup2(pfd[1], STDOUT_FILENO) < 0) 6214d7de91fSDima Dorfman err(1, "dup2"); 6224d7de91fSDima Dorfman if (!loudsubs) { 6234d7de91fSDima Dorfman nfd = open(_PATH_DEVNULL, O_RDWR); 6244d7de91fSDima Dorfman if (nfd == -1) 6254d7de91fSDima Dorfman err(1, "open: %s", _PATH_DEVNULL); 6264d7de91fSDima Dorfman if (dup2(nfd, STDIN_FILENO) < 0) 6274d7de91fSDima Dorfman err(1, "dup2"); 6284d7de91fSDima Dorfman if (dup2dn) 6294d7de91fSDima Dorfman if (dup2(nfd, STDOUT_FILENO) < 0) 6304d7de91fSDima Dorfman err(1, "dup2"); 6314d7de91fSDima Dorfman if (dup2(nfd, STDERR_FILENO) < 0) 6324d7de91fSDima Dorfman err(1, "dup2"); 6334d7de91fSDima Dorfman } 6344d7de91fSDima Dorfman 63594ddc5afSDavid E. O'Brien (void)execv(argv[0], argv); 63694ddc5afSDavid E. O'Brien warn("exec: %s", argv[0]); 6374d7de91fSDima Dorfman _exit(-1); 6384d7de91fSDima Dorfman case -1: 6394d7de91fSDima Dorfman err(1, "fork"); 6404d7de91fSDima Dorfman } 6414d7de91fSDima Dorfman 6424d7de91fSDima Dorfman free(cmd); 64394ddc5afSDavid E. O'Brien free(argv); 6444d7de91fSDima Dorfman while (waitpid(pid, &status, 0) != pid) 6454d7de91fSDima Dorfman ; 6464d7de91fSDima Dorfman return (WEXITSTATUS(status)); 6474d7de91fSDima Dorfman } 6484d7de91fSDima Dorfman 6494d7de91fSDima Dorfman static void 6504d7de91fSDima Dorfman usage(void) 6514d7de91fSDima Dorfman { 6524d7de91fSDima Dorfman 6534d7de91fSDima Dorfman fprintf(stderr, 65405b2fd30SDima Dorfman "usage: %s [-DLlMNPSUX] [-a maxcontig] [-b block-size] [-c cylinders]\n" 65563f8ddbeSMaxim Sobolev "\t[-d rotdelay] [-E path-mdconfig] [-e maxbpg] [-F file] [-f frag-size]\n" 65663f8ddbeSMaxim Sobolev "\t[-i bytes] [-m percent-free] [-n rotational-positions] [-O optimization]\n" 6578d646af5SRuslan Ermilov "\t[-o mount-options] [-p permissions] [-s size] [-v version]\n" 658957d7c8fSRuslan Ermilov "\t[-w user:group] md-device mount-point\n", getprogname()); 6594d7de91fSDima Dorfman exit(1); 6604d7de91fSDima Dorfman } 661