xref: /freebsd/sbin/mdmfs/mdmfs.c (revision 541ce3c1)
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 
64f7acb7e4SDima Dorfman static	bool compat;		/* Full compatibility with mount_mfs? */
654d7de91fSDima Dorfman static	bool debug;		/* Emit debugging information? */
664d7de91fSDima Dorfman static	bool loudsubs;		/* Suppress output from helper programs? */
674d7de91fSDima Dorfman static	bool norun;		/* Actually run the helper programs? */
684d7de91fSDima Dorfman static	int unit;      		/* The unit we're working with. */
694d7de91fSDima Dorfman static	const char *mdname;	/* Name of memory disk device (e.g., "md"). */
704d7de91fSDima Dorfman static	size_t mdnamelen;	/* Length of mdname. */
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;
924d7de91fSDima Dorfman 	bool detach, softdep, autounit;
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;
1044d7de91fSDima Dorfman 	have_mdtype = false;
1056449237fSSuleiman Souhlal 	mdtype = MD_SWAP;
1064d7de91fSDima Dorfman 	mdname = MD_NAME;
1074d7de91fSDima Dorfman 	mdnamelen = strlen(mdname);
1084d7de91fSDima Dorfman 	/*
1094d7de91fSDima Dorfman 	 * Can't set these to NULL.  They may be passed to the
1104d7de91fSDima Dorfman 	 * respective programs without modification.  I.e., we may not
1114d7de91fSDima Dorfman 	 * receive any command-line options which will caused them to
1124d7de91fSDima Dorfman 	 * be modified.
1134d7de91fSDima Dorfman 	 */
1144d7de91fSDima Dorfman 	mdconfig_arg = strdup("");
1154d7de91fSDima Dorfman 	newfs_arg = strdup("");
1164d7de91fSDima Dorfman 	mount_arg = strdup("");
1174d7de91fSDima Dorfman 
1182dc4ac06SIan Dowse 	/* If we were started as mount_mfs or mfs, imply -C. */
1192dc4ac06SIan Dowse 	if (strcmp(getprogname(), "mount_mfs") == 0 ||
1202dc4ac06SIan Dowse 	    strcmp(getprogname(), "mfs") == 0)
121f7acb7e4SDima Dorfman 		compat = true;
122f7acb7e4SDima Dorfman 
12394ddc5afSDavid E. O'Brien 	while ((ch = getopt(argc, argv,
1241d3170aaSRobert Watson 	    "a:b:Cc:Dd:e:F:f:hi:LlMm:Nn:O:o:p:Ss:t:Uv:w:X")) != -1)
1254d7de91fSDima Dorfman 		switch (ch) {
1264d7de91fSDima Dorfman 		case 'a':
1274d7de91fSDima Dorfman 			argappend(&newfs_arg, "-a %s", optarg);
1284d7de91fSDima Dorfman 			break;
1294d7de91fSDima Dorfman 		case 'b':
1304d7de91fSDima Dorfman 			argappend(&newfs_arg, "-b %s", optarg);
1314d7de91fSDima Dorfman 			break;
132f7acb7e4SDima Dorfman 		case 'C':
133f7acb7e4SDima Dorfman 			if (compat)
134f7acb7e4SDima Dorfman 				usage();
135f7acb7e4SDima Dorfman 			compat = true;
136f7acb7e4SDima Dorfman 			break;
1374d7de91fSDima Dorfman 		case 'c':
1384d7de91fSDima Dorfman 			argappend(&newfs_arg, "-c %s", optarg);
1394d7de91fSDima Dorfman 			break;
1404d7de91fSDima Dorfman 		case 'D':
141f7acb7e4SDima Dorfman 			if (compat)
142f7acb7e4SDima Dorfman 				usage();
1434d7de91fSDima Dorfman 			detach = false;
1444d7de91fSDima Dorfman 			break;
1454d7de91fSDima Dorfman 		case 'd':
1464d7de91fSDima Dorfman 			argappend(&newfs_arg, "-d %s", optarg);
1474d7de91fSDima Dorfman 			break;
1484d7de91fSDima Dorfman 		case 'e':
1494d7de91fSDima Dorfman 			argappend(&newfs_arg, "-e %s", optarg);
1504d7de91fSDima Dorfman 			break;
1514d7de91fSDima Dorfman 		case 'F':
1524d7de91fSDima Dorfman 			if (have_mdtype)
1534d7de91fSDima Dorfman 				usage();
1544d7de91fSDima Dorfman 			mdtype = MD_VNODE;
1554d7de91fSDima Dorfman 			have_mdtype = true;
1564d7de91fSDima Dorfman 			argappend(&mdconfig_arg, "-f %s", optarg);
1574d7de91fSDima Dorfman 			break;
1584d7de91fSDima Dorfman 		case 'f':
1594d7de91fSDima Dorfman 			argappend(&newfs_arg, "-f %s", optarg);
1604d7de91fSDima Dorfman 			break;
1614d7de91fSDima Dorfman 		case 'h':
1624d7de91fSDima Dorfman 			usage();
1634d7de91fSDima Dorfman 			break;
1644d7de91fSDima Dorfman 		case 'i':
1654d7de91fSDima Dorfman 			argappend(&newfs_arg, "-i %s", optarg);
1664d7de91fSDima Dorfman 			break;
1674d7de91fSDima Dorfman 		case 'L':
168f7acb7e4SDima Dorfman 			if (compat)
169f7acb7e4SDima Dorfman 				usage();
1704d7de91fSDima Dorfman 			loudsubs = true;
1714d7de91fSDima Dorfman 			break;
1721d3170aaSRobert Watson 		case 'l':
1731d3170aaSRobert Watson 			argappend(&newfs_arg, "-l");
1741d3170aaSRobert Watson 			break;
1754d7de91fSDima Dorfman 		case 'M':
1764d7de91fSDima Dorfman 			if (have_mdtype)
1774d7de91fSDima Dorfman 				usage();
1784d7de91fSDima Dorfman 			mdtype = MD_MALLOC;
1794d7de91fSDima Dorfman 			have_mdtype = true;
1804d7de91fSDima Dorfman 			break;
1814d7de91fSDima Dorfman 		case 'm':
1824d7de91fSDima Dorfman 			argappend(&newfs_arg, "-m %s", optarg);
1834d7de91fSDima Dorfman 			break;
1844d7de91fSDima Dorfman 		case 'N':
185f7acb7e4SDima Dorfman 			if (compat)
186f7acb7e4SDima Dorfman 				usage();
1874d7de91fSDima Dorfman 			norun = true;
1884d7de91fSDima Dorfman 			break;
1894d7de91fSDima Dorfman 		case 'n':
1904d7de91fSDima Dorfman 			argappend(&newfs_arg, "-n %s", optarg);
1914d7de91fSDima Dorfman 			break;
1924d7de91fSDima Dorfman 		case 'O':
1934d7de91fSDima Dorfman 			argappend(&newfs_arg, "-o %s", optarg);
1944d7de91fSDima Dorfman 			break;
1954d7de91fSDima Dorfman 		case 'o':
1964d7de91fSDima Dorfman 			argappend(&mount_arg, "-o %s", optarg);
1974d7de91fSDima Dorfman 			break;
1984d7de91fSDima Dorfman 		case 'p':
199f7acb7e4SDima Dorfman 			if (compat)
200f7acb7e4SDima Dorfman 				usage();
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':
208f7acb7e4SDima Dorfman 			if (compat)
209f7acb7e4SDima Dorfman 				usage();
2104d7de91fSDima Dorfman 			softdep = false;
2114d7de91fSDima Dorfman 			break;
2124d7de91fSDima Dorfman 		case 's':
2134d7de91fSDima Dorfman 			argappend(&mdconfig_arg, "-s %s", optarg);
2144d7de91fSDima Dorfman 			break;
215f7acb7e4SDima Dorfman 		case 'U':
216f7acb7e4SDima Dorfman 			softdep = true;
217f7acb7e4SDima Dorfman 			break;
218622448faSRobert Watson 		case 'v':
219622448faSRobert Watson 			argappend(&newfs_arg, "-O %s", optarg);
220622448faSRobert Watson 			break;
2214d7de91fSDima Dorfman 		case 'w':
222f7acb7e4SDima Dorfman 			if (compat)
223f7acb7e4SDima Dorfman 				usage();
2244d7de91fSDima Dorfman 			extract_ugid(optarg, &mi);
2254d7de91fSDima Dorfman 			break;
2264d7de91fSDima Dorfman 		case 'X':
227f7acb7e4SDima Dorfman 			if (compat)
228f7acb7e4SDima Dorfman 				usage();
2294d7de91fSDima Dorfman 			debug = true;
2304d7de91fSDima Dorfman 			break;
2314d7de91fSDima Dorfman 		default:
2324d7de91fSDima Dorfman 			usage();
2334d7de91fSDima Dorfman 		}
23494ddc5afSDavid E. O'Brien 	argc -= optind;
23594ddc5afSDavid E. O'Brien 	argv += optind;
23694ddc5afSDavid E. O'Brien 	if (argc < 2)
2374d7de91fSDima Dorfman 		usage();
2384d7de91fSDima Dorfman 
239f7acb7e4SDima Dorfman 	/* Make compatibility assumptions. */
240f7acb7e4SDima Dorfman 	if (compat) {
241f7acb7e4SDima Dorfman 		mi.mi_mode = 01777;
242f7acb7e4SDima Dorfman 		mi.mi_have_mode = true;
243f7acb7e4SDima Dorfman 	}
244f7acb7e4SDima Dorfman 
2454d7de91fSDima Dorfman 	/* Derive 'unit' (global). */
24694ddc5afSDavid E. O'Brien 	unitstr = argv[0];
2474d7de91fSDima Dorfman 	if (strncmp(unitstr, "/dev/", 5) == 0)
2484d7de91fSDima Dorfman 		unitstr += 5;
2494d7de91fSDima Dorfman 	if (strncmp(unitstr, mdname, mdnamelen) == 0)
2504d7de91fSDima Dorfman 		unitstr += mdnamelen;
2514d7de91fSDima Dorfman 	if (*unitstr == '\0') {
2524d7de91fSDima Dorfman 		autounit = true;
2534d7de91fSDima Dorfman 		unit = -1;
2544d7de91fSDima Dorfman 	} else {
25547376189SSuleiman Souhlal 		ul = strtoul(unitstr, &p, 10);
25647376189SSuleiman Souhlal 		if (ul == ULONG_MAX || *p != '\0')
2574d7de91fSDima Dorfman 			errx(1, "bad device unit: %s", unitstr);
25847376189SSuleiman Souhlal 		unit = ul;
2594d7de91fSDima Dorfman 	}
2604d7de91fSDima Dorfman 
26194ddc5afSDavid E. O'Brien 	mtpoint = argv[1];
2624d7de91fSDima Dorfman 	if (!have_mdtype)
2634d7de91fSDima Dorfman 		mdtype = MD_SWAP;
2644d7de91fSDima Dorfman 	if (softdep)
2654d7de91fSDima Dorfman 		argappend(&newfs_arg, "-U");
2664d7de91fSDima Dorfman 
2674d7de91fSDima Dorfman 	/* Do the work. */
2684d7de91fSDima Dorfman 	if (detach && !autounit)
2694d7de91fSDima Dorfman 		do_mdconfig_detach();
2704d7de91fSDima Dorfman 	if (autounit)
2714d7de91fSDima Dorfman 		do_mdconfig_attach_au(mdconfig_arg, mdtype);
2724d7de91fSDima Dorfman 	else
2734d7de91fSDima Dorfman 		do_mdconfig_attach(mdconfig_arg, mdtype);
2744d7de91fSDima Dorfman 	do_newfs(newfs_arg);
2754d7de91fSDima Dorfman 	do_mount(mount_arg, mtpoint);
2764d7de91fSDima Dorfman 	do_mtptsetup(mtpoint, &mi);
2774d7de91fSDima Dorfman 
2784d7de91fSDima Dorfman 	return (0);
2794d7de91fSDima Dorfman }
2804d7de91fSDima Dorfman 
2814d7de91fSDima Dorfman /*
2824d7de91fSDima Dorfman  * Append the expansion of 'fmt' to the buffer pointed to by '*dstp';
2834d7de91fSDima Dorfman  * reallocate as required.
2844d7de91fSDima Dorfman  */
2854d7de91fSDima Dorfman static void
2864d7de91fSDima Dorfman argappend(char **dstp, const char *fmt, ...)
2874d7de91fSDima Dorfman {
2884d7de91fSDima Dorfman 	char *old, *new;
2894d7de91fSDima Dorfman 	va_list ap;
2904d7de91fSDima Dorfman 
2914d7de91fSDima Dorfman 	old = *dstp;
2924d7de91fSDima Dorfman 	assert(old != NULL);
2934d7de91fSDima Dorfman 
2944d7de91fSDima Dorfman 	va_start(ap, fmt);
2954d7de91fSDima Dorfman 	if (vasprintf(&new, fmt,ap) == -1)
2964d7de91fSDima Dorfman 		errx(1, "vasprintf");
2974d7de91fSDima Dorfman 	va_end(ap);
2984d7de91fSDima Dorfman 
2994d7de91fSDima Dorfman 	*dstp = new;
3004d7de91fSDima Dorfman 	if (asprintf(&new, "%s %s", old, new) == -1)
3014d7de91fSDima Dorfman 		errx(1, "asprintf");
3024d7de91fSDima Dorfman 	free(*dstp);
3034d7de91fSDima Dorfman 	free(old);
3044d7de91fSDima Dorfman 
3054d7de91fSDima Dorfman 	*dstp = new;
3064d7de91fSDima Dorfman }
3074d7de91fSDima Dorfman 
3084d7de91fSDima Dorfman /*
3094d7de91fSDima Dorfman  * If run-time debugging is enabled, print the expansion of 'fmt'.
3104d7de91fSDima Dorfman  * Otherwise, do nothing.
3114d7de91fSDima Dorfman  */
3124d7de91fSDima Dorfman static void
3134d7de91fSDima Dorfman debugprintf(const char *fmt, ...)
3144d7de91fSDima Dorfman {
3154d7de91fSDima Dorfman 	va_list ap;
3164d7de91fSDima Dorfman 
3174d7de91fSDima Dorfman 	if (!debug)
3184d7de91fSDima Dorfman 		return;
3194d7de91fSDima Dorfman 	fprintf(stderr, "DEBUG: ");
3204d7de91fSDima Dorfman 	va_start(ap, fmt);
3214d7de91fSDima Dorfman 	vfprintf(stderr, fmt, ap);
3224d7de91fSDima Dorfman 	va_end(ap);
3234d7de91fSDima Dorfman 	fprintf(stderr, "\n");
3244d7de91fSDima Dorfman 	fflush(stderr);
3254d7de91fSDima Dorfman }
3264d7de91fSDima Dorfman 
3274d7de91fSDima Dorfman /*
3284d7de91fSDima Dorfman  * Attach a memory disk with a known unit.
3294d7de91fSDima Dorfman  */
3304d7de91fSDima Dorfman static void
3314d7de91fSDima Dorfman do_mdconfig_attach(const char *args, const enum md_types mdtype)
3324d7de91fSDima Dorfman {
3334d7de91fSDima Dorfman 	int rv;
3344d7de91fSDima Dorfman 	const char *ta;		/* Type arg. */
3354d7de91fSDima Dorfman 
3364d7de91fSDima Dorfman 	switch (mdtype) {
3374d7de91fSDima Dorfman 	case MD_SWAP:
3384d7de91fSDima Dorfman 		ta = "-t swap";
3394d7de91fSDima Dorfman 		break;
3404d7de91fSDima Dorfman 	case MD_VNODE:
3414d7de91fSDima Dorfman 		ta = "-t vnode";
3424d7de91fSDima Dorfman 		break;
3434d7de91fSDima Dorfman 	case MD_MALLOC:
3444d7de91fSDima Dorfman 		ta = "-t malloc";
3454d7de91fSDima Dorfman 		break;
3464d7de91fSDima Dorfman 	default:
3474d7de91fSDima Dorfman 		abort();
3484d7de91fSDima Dorfman 	}
3491386defaSGordon Tetlow 	rv = run(NULL, "%s -a %s%s -u %s%d", _PATH_MDCONFIG, ta, args,
3504d7de91fSDima Dorfman 	    mdname, unit);
3514d7de91fSDima Dorfman 	if (rv)
3524d7de91fSDima Dorfman 		errx(1, "mdconfig (attach) exited with error code %d", rv);
3534d7de91fSDima Dorfman }
3544d7de91fSDima Dorfman 
3554d7de91fSDima Dorfman /*
3564d7de91fSDima Dorfman  * Attach a memory disk with an unknown unit; use autounit.
3574d7de91fSDima Dorfman  */
3584d7de91fSDima Dorfman static void
3594d7de91fSDima Dorfman do_mdconfig_attach_au(const char *args, const enum md_types mdtype)
3604d7de91fSDima Dorfman {
3614d7de91fSDima Dorfman 	const char *ta;		/* Type arg. */
3624d7de91fSDima Dorfman 	char *linep, *linebuf; 	/* Line pointer, line buffer. */
3634d7de91fSDima Dorfman 	int fd;			/* Standard output of mdconfig invocation. */
3644d7de91fSDima Dorfman 	FILE *sfd;
3654d7de91fSDima Dorfman 	int rv;
3664d7de91fSDima Dorfman 	char *p;
3674d7de91fSDima Dorfman 	size_t linelen;
36847376189SSuleiman Souhlal 	unsigned long ul;
3694d7de91fSDima Dorfman 
3704d7de91fSDima Dorfman 	switch (mdtype) {
3714d7de91fSDima Dorfman 	case MD_SWAP:
3724d7de91fSDima Dorfman 		ta = "-t swap";
3734d7de91fSDima Dorfman 		break;
3744d7de91fSDima Dorfman 	case MD_VNODE:
3754d7de91fSDima Dorfman 		ta = "-t vnode";
3764d7de91fSDima Dorfman 		break;
3774d7de91fSDima Dorfman 	case MD_MALLOC:
3784d7de91fSDima Dorfman 		ta = "-t malloc";
3794d7de91fSDima Dorfman 		break;
3804d7de91fSDima Dorfman 	default:
3814d7de91fSDima Dorfman 		abort();
3824d7de91fSDima Dorfman 	}
3831386defaSGordon Tetlow 	rv = run(&fd, "%s -a %s%s", _PATH_MDCONFIG, ta, args);
3844d7de91fSDima Dorfman 	if (rv)
3854d7de91fSDima Dorfman 		errx(1, "mdconfig (attach) exited with error code %d", rv);
3864d7de91fSDima Dorfman 
3874d7de91fSDima Dorfman 	/* Receive the unit number. */
3884d7de91fSDima Dorfman 	if (norun) {	/* Since we didn't run, we can't read.  Fake it. */
389541ce3c1SDima Dorfman 		unit = 0;
3904d7de91fSDima Dorfman 		return;
3914d7de91fSDima Dorfman 	}
3924d7de91fSDima Dorfman 	sfd = fdopen(fd, "r");
3934d7de91fSDima Dorfman 	if (sfd == NULL)
3944d7de91fSDima Dorfman 		err(1, "fdopen");
3954d7de91fSDima Dorfman 	linep = fgetln(sfd, &linelen);
3964d7de91fSDima Dorfman 	if (linep == NULL && linelen < mdnamelen + 1)
3974d7de91fSDima Dorfman 		errx(1, "unexpected output from mdconfig (attach)");
3984d7de91fSDima Dorfman 	/* If the output format changes, we want to know about it. */
3994d7de91fSDima Dorfman 	assert(strncmp(linep, mdname, mdnamelen) == 0);
4004d7de91fSDima Dorfman 	linebuf = malloc(linelen - mdnamelen + 1);
4014d7de91fSDima Dorfman 	assert(linebuf != NULL);
4024d7de91fSDima Dorfman 	/* Can't use strlcpy because linep is not NULL-terminated. */
4034d7de91fSDima Dorfman 	strncpy(linebuf, linep + mdnamelen, linelen);
4044d7de91fSDima Dorfman 	linebuf[linelen] = '\0';
40547376189SSuleiman Souhlal 	ul = strtoul(linebuf, &p, 10);
40647376189SSuleiman Souhlal 	if (ul == ULONG_MAX || *p != '\n')
4074d7de91fSDima Dorfman 		errx(1, "unexpected output from mdconfig (attach)");
40847376189SSuleiman Souhlal 	unit = ul;
4094d7de91fSDima Dorfman 
4104d7de91fSDima Dorfman 	fclose(sfd);
4114d7de91fSDima Dorfman 	close(fd);
4124d7de91fSDima Dorfman }
4134d7de91fSDima Dorfman 
4144d7de91fSDima Dorfman /*
4154d7de91fSDima Dorfman  * Detach a memory disk.
4164d7de91fSDima Dorfman  */
4174d7de91fSDima Dorfman static void
4184d7de91fSDima Dorfman do_mdconfig_detach(void)
4194d7de91fSDima Dorfman {
4204d7de91fSDima Dorfman 	int rv;
4214d7de91fSDima Dorfman 
4221386defaSGordon Tetlow 	rv = run(NULL, "%s -d -u %s%d", _PATH_MDCONFIG, mdname, unit);
4234d7de91fSDima Dorfman 	if (rv && debug)	/* This is allowed to fail. */
4244d7de91fSDima Dorfman 		warnx("mdconfig (detach) exited with error code %d (ignored)",
4254d7de91fSDima Dorfman 		      rv);
4264d7de91fSDima Dorfman }
4274d7de91fSDima Dorfman 
4284d7de91fSDima Dorfman /*
4294d7de91fSDima Dorfman  * Mount the configured memory disk.
4304d7de91fSDima Dorfman  */
4314d7de91fSDima Dorfman static void
4324d7de91fSDima Dorfman do_mount(const char *args, const char *mtpoint)
4334d7de91fSDima Dorfman {
4344d7de91fSDima Dorfman 	int rv;
4354d7de91fSDima Dorfman 
4361386defaSGordon Tetlow 	rv = run(NULL, "%s%s /dev/%s%d %s", _PATH_MOUNT, args,
4374d7de91fSDima Dorfman 	    mdname, unit, mtpoint);
4384d7de91fSDima Dorfman 	if (rv)
4394d7de91fSDima Dorfman 		errx(1, "mount exited with error code %d", rv);
4404d7de91fSDima Dorfman }
4414d7de91fSDima Dorfman 
4424d7de91fSDima Dorfman /*
4434d7de91fSDima Dorfman  * Various configuration of the mountpoint.  Mostly, enact 'mip'.
4444d7de91fSDima Dorfman  */
4454d7de91fSDima Dorfman static void
4464d7de91fSDima Dorfman do_mtptsetup(const char *mtpoint, struct mtpt_info *mip)
4474d7de91fSDima Dorfman {
4484d7de91fSDima Dorfman 
4494d7de91fSDima Dorfman 	if (mip->mi_have_mode) {
4504d7de91fSDima Dorfman 		debugprintf("changing mode of %s to %o.", mtpoint,
4514d7de91fSDima Dorfman 		    mip->mi_mode);
4524d7de91fSDima Dorfman 		if (!norun)
4534d7de91fSDima Dorfman 			if (chmod(mtpoint, mip->mi_mode) == -1)
4544d7de91fSDima Dorfman 				err(1, "chmod: %s", mtpoint);
4554d7de91fSDima Dorfman 	}
4564d7de91fSDima Dorfman 	/*
4574d7de91fSDima Dorfman 	 * We have to do these separately because the user may have
4584d7de91fSDima Dorfman 	 * only specified one of them.
4594d7de91fSDima Dorfman 	 */
4604d7de91fSDima Dorfman 	if (mip->mi_have_uid) {
4614d7de91fSDima Dorfman 		debugprintf("changing owner (user) or %s to %u.", mtpoint,
4624d7de91fSDima Dorfman 		    mip->mi_uid);
4634d7de91fSDima Dorfman 		if (!norun)
4644d7de91fSDima Dorfman 			if (chown(mtpoint, mip->mi_uid, -1) == -1)
4654d7de91fSDima Dorfman 				err(1, "chown %s to %u (user)", mtpoint,
4664d7de91fSDima Dorfman 				    mip->mi_uid);
4674d7de91fSDima Dorfman 	}
4684d7de91fSDima Dorfman 	if (mip->mi_have_gid) {
4694d7de91fSDima Dorfman 		debugprintf("changing owner (group) or %s to %u.", mtpoint,
4704d7de91fSDima Dorfman 		    mip->mi_gid);
4714d7de91fSDima Dorfman 		if (!norun)
4724d7de91fSDima Dorfman 			if (chown(mtpoint, -1, mip->mi_gid) == -1)
4734d7de91fSDima Dorfman 				err(1, "chown %s to %u (group)", mtpoint,
4744d7de91fSDima Dorfman 				    mip->mi_gid);
4754d7de91fSDima Dorfman 	}
4764d7de91fSDima Dorfman }
4774d7de91fSDima Dorfman 
4784d7de91fSDima Dorfman /*
4794d7de91fSDima Dorfman  * Put a file system on the memory disk.
4804d7de91fSDima Dorfman  */
4814d7de91fSDima Dorfman static void
4824d7de91fSDima Dorfman do_newfs(const char *args)
4834d7de91fSDima Dorfman {
4844d7de91fSDima Dorfman 	int rv;
4854d7de91fSDima Dorfman 
4861386defaSGordon Tetlow 	rv = run(NULL, "%s%s /dev/%s%d", _PATH_NEWFS, args, mdname, unit);
4874d7de91fSDima Dorfman 	if (rv)
4884d7de91fSDima Dorfman 		errx(1, "newfs exited with error code %d", rv);
4894d7de91fSDima Dorfman }
4904d7de91fSDima Dorfman 
4914d7de91fSDima Dorfman /*
4924d7de91fSDima Dorfman  * 'str' should be a user and group name similar to the last argument
4934d7de91fSDima Dorfman  * to chown(1); i.e., a user, followed by a colon, followed by a
4944d7de91fSDima Dorfman  * group.  The user and group in 'str' may be either a [ug]id or a
4954d7de91fSDima Dorfman  * name.  Upon return, the uid and gid fields in 'mip' will contain
4964d7de91fSDima Dorfman  * the uid and gid of the user and group name in 'str', respectively.
4974d7de91fSDima Dorfman  *
4984d7de91fSDima Dorfman  * In other words, this derives a user and group id from a string
4994d7de91fSDima Dorfman  * formatted like the last argument to chown(1).
500de90a634SRalf S. Engelschall  *
501de90a634SRalf S. Engelschall  * Notice: At this point we don't support only a username or only a
502de90a634SRalf S. Engelschall  * group name. do_mtptsetup already does, so when this feature is
503de90a634SRalf S. Engelschall  * desired, this is the only routine that needs to be changed.
5044d7de91fSDima Dorfman  */
5054d7de91fSDima Dorfman static void
5064d7de91fSDima Dorfman extract_ugid(const char *str, struct mtpt_info *mip)
5074d7de91fSDima Dorfman {
5084d7de91fSDima Dorfman 	char *ug;			/* Writable 'str'. */
5094d7de91fSDima Dorfman 	char *user, *group;		/* Result of extracton. */
5104d7de91fSDima Dorfman 	struct passwd *pw;
5114d7de91fSDima Dorfman 	struct group *gr;
5124d7de91fSDima Dorfman 	char *p;
5134d7de91fSDima Dorfman 	uid_t *uid;
5144d7de91fSDima Dorfman 	gid_t *gid;
5154d7de91fSDima Dorfman 
5164d7de91fSDima Dorfman 	uid = &mip->mi_uid;
5174d7de91fSDima Dorfman 	gid = &mip->mi_gid;
5184d7de91fSDima Dorfman 	mip->mi_have_uid = mip->mi_have_gid = false;
5194d7de91fSDima Dorfman 
5204d7de91fSDima Dorfman 	/* Extract the user and group from 'str'.  Format above. */
5218d3c1246SDima Dorfman 	ug = strdup(str);
5224d7de91fSDima Dorfman 	assert(ug != NULL);
5234d7de91fSDima Dorfman 	group = ug;
5244d7de91fSDima Dorfman 	user = strsep(&group, ":");
5254d7de91fSDima Dorfman 	if (user == NULL || group == NULL || *user == '\0' || *group == '\0')
5264d7de91fSDima Dorfman 		usage();
5274d7de91fSDima Dorfman 
5284d7de91fSDima Dorfman 	/* Derive uid. */
5294d7de91fSDima Dorfman 	*uid = strtoul(user, &p, 10);
5308a50130bSAlexander Kabaev 	if (*uid == (uid_t)ULONG_MAX)
5314d7de91fSDima Dorfman 		usage();
5324d7de91fSDima Dorfman 	if (*p != '\0') {
5334d7de91fSDima Dorfman 		pw = getpwnam(user);
5344d7de91fSDima Dorfman 		if (pw == NULL)
5354d7de91fSDima Dorfman 			errx(1, "invalid user: %s", user);
5364d7de91fSDima Dorfman 		*uid = pw->pw_uid;
5374d7de91fSDima Dorfman 	}
538de90a634SRalf S. Engelschall 	mip->mi_have_uid = true;
5394d7de91fSDima Dorfman 
5404d7de91fSDima Dorfman 	/* Derive gid. */
5414d7de91fSDima Dorfman 	*gid = strtoul(group, &p, 10);
5428a50130bSAlexander Kabaev 	if (*gid == (gid_t)ULONG_MAX)
5434d7de91fSDima Dorfman 		usage();
5444d7de91fSDima Dorfman 	if (*p != '\0') {
5454d7de91fSDima Dorfman 		gr = getgrnam(group);
5464d7de91fSDima Dorfman 		if (gr == NULL)
5474d7de91fSDima Dorfman 			errx(1, "invalid group: %s", group);
5484d7de91fSDima Dorfman 		*gid = gr->gr_gid;
5494d7de91fSDima Dorfman 	}
550de90a634SRalf S. Engelschall 	mip->mi_have_gid = true;
5514d7de91fSDima Dorfman 
5524d7de91fSDima Dorfman 	free(ug);
5534d7de91fSDima Dorfman }
5544d7de91fSDima Dorfman 
5554d7de91fSDima Dorfman /*
5564d7de91fSDima Dorfman  * Run a process with command name and arguments pointed to by the
5574d7de91fSDima Dorfman  * formatted string 'cmdline'.  Since system(3) is not used, the first
5584d7de91fSDima Dorfman  * space-delimited token of 'cmdline' must be the full pathname of the
5594d7de91fSDima Dorfman  * program to run.  The return value is the return code of the process
5604d7de91fSDima Dorfman  * spawned.  If 'ofd' is non-NULL, it is set to the standard output of
5614d7de91fSDima Dorfman  * the program spawned (i.e., you can read from ofd and get the output
5624d7de91fSDima Dorfman  * of the program).
5634d7de91fSDima Dorfman  */
5644d7de91fSDima Dorfman static int
5654d7de91fSDima Dorfman run(int *ofd, const char *cmdline, ...)
5664d7de91fSDima Dorfman {
56794ddc5afSDavid E. O'Brien 	char **argv, **argvp;		/* Result of splitting 'cmd'. */
56894ddc5afSDavid E. O'Brien 	int argc;
5694d7de91fSDima Dorfman 	char *cmd;			/* Expansion of 'cmdline'. */
5704d7de91fSDima Dorfman 	int pid, status;		/* Child info. */
5714d7de91fSDima Dorfman 	int pfd[2];			/* Pipe to the child. */
5724d7de91fSDima Dorfman 	int nfd;			/* Null (/dev/null) file descriptor. */
5734d7de91fSDima Dorfman 	bool dup2dn;			/* Dup /dev/null to stdout? */
5744d7de91fSDima Dorfman 	va_list ap;
5754d7de91fSDima Dorfman 	char *p;
5764d7de91fSDima Dorfman 	int rv, i;
5774d7de91fSDima Dorfman 
5784d7de91fSDima Dorfman 	dup2dn = true;
5794d7de91fSDima Dorfman 	va_start(ap, cmdline);
5804d7de91fSDima Dorfman 	rv = vasprintf(&cmd, cmdline, ap);
5814d7de91fSDima Dorfman 	if (rv == -1)
5824d7de91fSDima Dorfman 		err(1, "vasprintf");
5834d7de91fSDima Dorfman 	va_end(ap);
5844d7de91fSDima Dorfman 
58594ddc5afSDavid E. O'Brien 	/* Split up 'cmd' into 'argv' for use with execve. */
58694ddc5afSDavid E. O'Brien 	for (argc = 1, p = cmd; (p = strchr(p, ' ')) != NULL; p++)
58794ddc5afSDavid E. O'Brien 		argc++;		/* 'argc' generation loop. */
58894ddc5afSDavid E. O'Brien 	argv = (char **)malloc(sizeof(*argv) * (argc + 1));
58994ddc5afSDavid E. O'Brien 	assert(argv != NULL);
59094ddc5afSDavid E. O'Brien 	for (p = cmd, argvp = argv; (*argvp = strsep(&p, " ")) != NULL;)
59194ddc5afSDavid E. O'Brien 		if (**argv != '\0')
59294ddc5afSDavid E. O'Brien 			if (++argvp >= &argv[argc]) {
59394ddc5afSDavid E. O'Brien 				*argvp = NULL;
5944d7de91fSDima Dorfman 				break;
5954d7de91fSDima Dorfman 			}
59694ddc5afSDavid E. O'Brien 	assert(*argv);
5974d7de91fSDima Dorfman 
5984d7de91fSDima Dorfman 	/* Make sure the above loop works as expected. */
5994d7de91fSDima Dorfman 	if (debug) {
6004d7de91fSDima Dorfman 		/*
6014d7de91fSDima Dorfman 		 * We can't, but should, use debugprintf here.  First,
6024d7de91fSDima Dorfman 		 * it appends a trailing newline to the output, and
6034d7de91fSDima Dorfman 		 * second it prepends "DEBUG: " to the output.  The
6044d7de91fSDima Dorfman 		 * former is a problem for this would-be first call,
6054d7de91fSDima Dorfman 		 * and the latter for the would-be call inside the
6064d7de91fSDima Dorfman 		 * loop.
6074d7de91fSDima Dorfman 		 */
6084d7de91fSDima Dorfman 		(void)fprintf(stderr, "DEBUG: running:");
6094d7de91fSDima Dorfman 		/* Should be equivilent to 'cmd' (before strsep, of course). */
61094ddc5afSDavid E. O'Brien 		for (i = 0; argv[i] != NULL; i++)
61194ddc5afSDavid E. O'Brien 			(void)fprintf(stderr, " %s", argv[i]);
6124d7de91fSDima Dorfman 		(void)fprintf(stderr, "\n");
6134d7de91fSDima Dorfman 	}
6144d7de91fSDima Dorfman 
6154d7de91fSDima Dorfman 	/* Create a pipe if necessary and fork the helper program. */
6164d7de91fSDima Dorfman 	if (ofd != NULL) {
6174d7de91fSDima Dorfman 		if (pipe(&pfd[0]) == -1)
6184d7de91fSDima Dorfman 			err(1, "pipe");
6194d7de91fSDima Dorfman 		*ofd = pfd[0];
6204d7de91fSDima Dorfman 		dup2dn = false;
6214d7de91fSDima Dorfman 	}
6224d7de91fSDima Dorfman 	pid = fork();
6234d7de91fSDima Dorfman 	switch (pid) {
6244d7de91fSDima Dorfman 	case 0:
6254d7de91fSDima Dorfman 		/* XXX can we call err() in here? */
6264d7de91fSDima Dorfman 		if (norun)
6274d7de91fSDima Dorfman 			_exit(0);
6284d7de91fSDima Dorfman 		if (ofd != NULL)
6294d7de91fSDima Dorfman 			if (dup2(pfd[1], STDOUT_FILENO) < 0)
6304d7de91fSDima Dorfman 				err(1, "dup2");
6314d7de91fSDima Dorfman 		if (!loudsubs) {
6324d7de91fSDima Dorfman 			nfd = open(_PATH_DEVNULL, O_RDWR);
6334d7de91fSDima Dorfman 			if (nfd == -1)
6344d7de91fSDima Dorfman 				err(1, "open: %s", _PATH_DEVNULL);
6354d7de91fSDima Dorfman 			if (dup2(nfd, STDIN_FILENO) < 0)
6364d7de91fSDima Dorfman 				err(1, "dup2");
6374d7de91fSDima Dorfman 			if (dup2dn)
6384d7de91fSDima Dorfman 				if (dup2(nfd, STDOUT_FILENO) < 0)
6394d7de91fSDima Dorfman 				   err(1, "dup2");
6404d7de91fSDima Dorfman 			if (dup2(nfd, STDERR_FILENO) < 0)
6414d7de91fSDima Dorfman 				err(1, "dup2");
6424d7de91fSDima Dorfman 		}
6434d7de91fSDima Dorfman 
64494ddc5afSDavid E. O'Brien 		(void)execv(argv[0], argv);
64594ddc5afSDavid E. O'Brien 		warn("exec: %s", argv[0]);
6464d7de91fSDima Dorfman 		_exit(-1);
6474d7de91fSDima Dorfman 	case -1:
6484d7de91fSDima Dorfman 		err(1, "fork");
6494d7de91fSDima Dorfman 	}
6504d7de91fSDima Dorfman 
6514d7de91fSDima Dorfman 	free(cmd);
65294ddc5afSDavid E. O'Brien 	free(argv);
6534d7de91fSDima Dorfman 	while (waitpid(pid, &status, 0) != pid)
6544d7de91fSDima Dorfman 		;
6554d7de91fSDima Dorfman 	return (WEXITSTATUS(status));
6564d7de91fSDima Dorfman }
6574d7de91fSDima Dorfman 
6584d7de91fSDima Dorfman static void
6594d7de91fSDima Dorfman usage(void)
6604d7de91fSDima Dorfman {
661f7acb7e4SDima Dorfman 	const char *name;
6624d7de91fSDima Dorfman 
663f7acb7e4SDima Dorfman 	if (compat)
664f7acb7e4SDima Dorfman 		name = getprogname();
665f7acb7e4SDima Dorfman 	else
666f7acb7e4SDima Dorfman 		name = "mdmfs";
667f7acb7e4SDima Dorfman 	if (!compat)
6684d7de91fSDima Dorfman 		fprintf(stderr,
6698d646af5SRuslan Ermilov "usage: %s [-DLlMNSUX] [-a maxcontig] [-b block-size] [-c cylinders]\n"
6704d7de91fSDima Dorfman "\t[-d rotdelay] [-e maxbpg] [-F file] [-f frag-size] [-i bytes]\n"
6714d7de91fSDima Dorfman "\t[-m percent-free] [-n rotational-positions] [-O optimization]\n"
6728d646af5SRuslan Ermilov "\t[-o mount-options] [-p permissions] [-s size] [-v version]\n"
6738d646af5SRuslan Ermilov "\t[-w user:group] md-device mount-point\n", name);
674f7acb7e4SDima Dorfman 	fprintf(stderr,
6752921afedSRuslan Ermilov "usage: %s -C [-lNU] [-a maxcontig] [-b block-size] [-c cylinders]\n"
676f7acb7e4SDima Dorfman "\t[-d rotdelay] [-e maxbpg] [-F file] [-f frag-size] [-i bytes]\n"
677f7acb7e4SDima Dorfman "\t[-m percent-free] [-n rotational-positions] [-O optimization]\n"
6788d646af5SRuslan Ermilov "\t[-o mount-options] [-s size] [-v version] md-device mount-point\n", name);
6794d7de91fSDima Dorfman 	exit(1);
6804d7de91fSDima Dorfman }
681