swapon.c revision 252332
1121474Sume/*
262614Sitojun * Copyright (c) 1980, 1993
355163Sshin *	The Regents of the University of California.  All rights reserved.
455163Sshin *
555163Sshin * Redistribution and use in source and binary forms, with or without
655163Sshin * modification, are permitted provided that the following conditions
755163Sshin * are met:
855163Sshin * 1. Redistributions of source code must retain the above copyright
955163Sshin *    notice, this list of conditions and the following disclaimer.
1055163Sshin * 2. Redistributions in binary form must reproduce the above copyright
1155163Sshin *    notice, this list of conditions and the following disclaimer in the
1255163Sshin *    documentation and/or other materials provided with the distribution.
1355163Sshin * 4. Neither the name of the University nor the names of its contributors
1455163Sshin *    may be used to endorse or promote products derived from this software
1555163Sshin *    without specific prior written permission.
1655163Sshin *
1755163Sshin * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1855163Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1955163Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2055163Sshin * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2155163Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2255163Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2355163Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2455163Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2555163Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2655163Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2755163Sshin * SUCH DAMAGE.
2855163Sshin */
2955163Sshin
3055163Sshin#if 0
3155163Sshin#ifndef lint
3255163Sshinstatic const char copyright[] =
3355163Sshin"@(#) Copyright (c) 1980, 1993\n\
3455163Sshin	The Regents of the University of California.  All rights reserved.\n";
3555163Sshin#endif /* not lint */
3655163Sshin
3755163Sshin#ifndef lint
3855163Sshinstatic char sccsid[] = "@(#)swapon.c	8.1 (Berkeley) 6/5/93";
3955163Sshin#endif /* not lint */
4061877Sume#endif
41105940Sume#include <sys/cdefs.h>
42105940Sume__FBSDID("$FreeBSD: head/sbin/swapon/swapon.c 252332 2013-06-28 05:09:01Z hrs $");
4356627Sshin
4456627Sshin#include <sys/param.h>
4556627Sshin#include <sys/types.h>
4656627Sshin#include <sys/mdioctl.h>
4756627Sshin#include <sys/stat.h>
4861877Sume#include <sys/sysctl.h>
4961877Sume#include <sys/wait.h>
5061877Sume#include <vm/vm_param.h>
5161877Sume
52105940Sume#include <err.h>
53105940Sume#include <errno.h>
5461877Sume#include <fcntl.h>
5561877Sume#include <fnmatch.h>
5661877Sume#include <fstab.h>
5761877Sume#include <libgen.h>
58105940Sume#include <libutil.h>
59105940Sume#include <limits.h>
60105940Sume#include <paths.h>
61105940Sume#include <stdarg.h>
6255163Sshin#include <stdio.h>
6355163Sshin#include <stdlib.h>
6492986Sobrien#include <string.h>
6592986Sobrien#include <unistd.h>
6692986Sobrien
6771579Sdeischenstatic void usage(void);
6855163Sshinstatic const char *swap_on_off(char *, int, char *);
6955163Sshinstatic const char *swap_on_off_gbde(char *, int);
7055163Sshinstatic const char *swap_on_off_geli(char *, char *, int);
7155163Sshinstatic const char *swap_on_off_md(char *, char *, int);
7255163Sshinstatic const char *swap_on_off_sfile(char *, int);
73121747Sumestatic void swaplist(int, int, int);
74121747Sumestatic int run_cmd(int *, const char *, ...) __printflike(2, 3);
75121747Sume
76121747Sumestatic enum { SWAPON, SWAPOFF, SWAPCTL } orig_prog, which_prog = SWAPCTL;
77129901Sume
78121747Sumestatic int qflag;
79121747Sume
8055163Sshinint
8155163Sshinmain(int argc, char **argv)
82121474Sume{
83121474Sume	struct fstab *fsp;
84121474Sume	const char *swfile;
8555163Sshin	char *ptr;
8655163Sshin	int ret;
8755163Sshin	int ch, doall;
8855163Sshin	int sflag = 0, lflag = 0, late = 0, hflag = 0;
8955163Sshin	const char *etc_fstab;
9055163Sshin
9155163Sshin	if ((ptr = strrchr(argv[0], '/')) == NULL)
9255163Sshin		ptr = argv[0];
9361877Sume	if (strstr(ptr, "swapon"))
94102237Spirzyk		which_prog = SWAPON;
95102237Spirzyk	else if (strstr(ptr, "swapoff"))
96102237Spirzyk		which_prog = SWAPOFF;
9778012Sume	orig_prog = which_prog;
9878012Sume
9978012Sume	doall = 0;
10055163Sshin	etc_fstab = NULL;
10165532Snectar	while ((ch = getopt(argc, argv, "AadghklLmqsUF:")) != -1) {
10265532Snectar		switch(ch) {
10371579Sdeischen		case 'A':
104111618Snectar			if (which_prog == SWAPCTL) {
105158115Sume				doall = 1;
106158115Sume				which_prog = SWAPON;
107158115Sume			} else {
10865532Snectar				usage();
10955163Sshin			}
11055163Sshin			break;
11155163Sshin		case 'a':
11255163Sshin			if (which_prog == SWAPON || which_prog == SWAPOFF)
113105940Sume				doall = 1;
114105940Sume			else
115105940Sume				which_prog = SWAPON;
116105940Sume			break;
11755163Sshin		case 'd':
11855163Sshin			if (which_prog == SWAPCTL)
119105940Sume				which_prog = SWAPOFF;
120105940Sume			else
12155163Sshin				usage();
12255163Sshin			break;
12355163Sshin		case 'g':
12455163Sshin			hflag = 'G';
12555163Sshin			break;
12655163Sshin		case 'h':
127105940Sume			hflag = 'H';
12855163Sshin			break;
129121747Sume		case 'k':
130121747Sume			hflag = 'K';
131121747Sume			break;
132121747Sume		case 'l':
133121747Sume			lflag = 1;
134121747Sume			break;
135121747Sume		case 'L':
136121747Sume			late = 1;
13755163Sshin			break;
13855163Sshin		case 'm':
13955163Sshin			hflag = 'M';
140146244Sume			break;
14155163Sshin		case 'q':
14255163Sshin			if (which_prog == SWAPON || which_prog == SWAPOFF)
14373665Sobrien				qflag = 1;
14455163Sshin			break;
14555163Sshin		case 's':
14655163Sshin			sflag = 1;
14755163Sshin			break;
14855163Sshin		case 'U':
14955163Sshin			if (which_prog == SWAPCTL) {
15055163Sshin				doall = 1;
15155163Sshin				which_prog = SWAPOFF;
15255163Sshin			} else {
15355163Sshin				usage();
15455163Sshin			}
15555163Sshin			break;
15655163Sshin		case 'F':
15755163Sshin			etc_fstab = optarg;
15855163Sshin			break;
15955163Sshin		case '?':
16055163Sshin		default:
16155163Sshin			usage();
16255163Sshin		}
16355163Sshin	}
16461877Sume	argv += optind;
16555163Sshin
16655163Sshin	ret = 0;
16755163Sshin	swfile = NULL;
16855163Sshin	if (etc_fstab != NULL)
169105940Sume		setfstab(etc_fstab);
170105940Sume	if (which_prog == SWAPON || which_prog == SWAPOFF) {
171105940Sume		if (doall) {
17255163Sshin			while ((fsp = getfsent()) != NULL) {
17355163Sshin				if (strcmp(fsp->fs_type, FSTAB_SW))
17455163Sshin					continue;
17561877Sume				if (strstr(fsp->fs_mntops, "noauto"))
176121474Sume					continue;
17761877Sume				if (which_prog != SWAPOFF &&
17861877Sume				    strstr(fsp->fs_mntops, "late") &&
179121474Sume				    !late)
180121474Sume					continue;
181121474Sume				swfile = swap_on_off(fsp->fs_spec, 1,
18261877Sume				    fsp->fs_mntops);
183121474Sume				if (swfile == NULL) {
184121474Sume					ret = 1;
185121474Sume					continue;
186121474Sume				}
187121474Sume				if (!qflag) {
188121474Sume					printf("%s: %sing %s as swap device\n",
18961877Sume					    getprogname(),
19055163Sshin					    (which_prog == SWAPOFF) ?
19155163Sshin					    "remov" : "add", swfile);
19255163Sshin				}
193105940Sume			}
19455163Sshin		}
195105940Sume		else if (!*argv)
19655163Sshin			usage();
19755163Sshin		for (; *argv; ++argv) {
198121747Sume			swfile = swap_on_off(*argv, 0, NULL);
199121747Sume			if (swfile == NULL) {
200121747Sume				ret = 1;
201121747Sume				continue;
202121747Sume			}
203121747Sume			if (orig_prog == SWAPCTL) {
204121747Sume				printf("%s: %sing %s as swap device\n",
205121747Sume				    getprogname(),
206121747Sume				    (which_prog == SWAPOFF) ? "remov" : "add",
207121747Sume				    swfile);
208121747Sume			}
209121747Sume		}
210121747Sume	} else {
211121747Sume		if (lflag || sflag)
212121747Sume			swaplist(lflag, sflag, hflag);
213121747Sume		else
214121747Sume			usage();
21565532Snectar	}
21665532Snectar	exit(ret);
21765532Snectar}
21865532Snectar
21965532Snectarstatic const char *
22065532Snectarswap_on_off(char *name, int doingall, char *mntops)
22161877Sume{
22261877Sume	char base[PATH_MAX];
22361877Sume
22462614Sitojun	/* Swap on vnode-backed md(4) device. */
22561877Sume	if (mntops != NULL &&
22661877Sume	    (fnmatch(_PATH_DEV MD_NAME "[0-9]*", name, 0) != FNM_NOMATCH ||
22761877Sume	     fnmatch(MD_NAME "[0-9]*", name, 0) != FNM_NOMATCH ||
22861877Sume	     strncmp(_PATH_DEV MD_NAME, name,
22961877Sume		sizeof(_PATH_DEV) + sizeof(MD_NAME)) == 0 ||
230121426Sume	     strncmp(MD_NAME, name, sizeof(MD_NAME)) == 0))
231121426Sume		return (swap_on_off_md(name, mntops, doingall));
232121426Sume
233121426Sume	/* Swap on encrypted device by GEOM_BDE. */
234121426Sume	basename_r(name, base);
235121426Sume	if (fnmatch("*.bde", base, 0) != FNM_NOMATCH)
236121426Sume		return (swap_on_off_gbde(name, doingall));
237140908Sume
23892941Sobrien	/* Swap on encrypted device by GEOM_ELI. */
23992941Sobrien	if (fnmatch("*.eli", base, 0) != FNM_NOMATCH)
24092941Sobrien		return (swap_on_off_geli(name, mntops, doingall));
241140906Sume
24292941Sobrien	/* Swap on special file. */
24392941Sobrien	return (swap_on_off_sfile(name, doingall));
24492941Sobrien}
24592941Sobrien
24692941Sobrienstatic const char *
24792941Sobrienswap_on_off_gbde(char *name, int doingall)
24892905Sobrien{
24992905Sobrien	const char *ret;
25092905Sobrien	char pass[64 * 2 + 1], bpass[64];
251121474Sume	char *dname, *p;
252129901Sume	int i, fd, error;
253121747Sume
25461877Sume	dname = strdup(name);
255105943Sume	p = strrchr(dname, '.');
25661877Sume	if (p == NULL) {
257121747Sume		warnx("%s: Malformed device name", name);
25855163Sshin		return (NULL);
259121426Sume	}
260121426Sume	*p = '\0';
261121426Sume
262121747Sume	fd = -1;
263121747Sume	switch (which_prog) {
264121747Sume	case SWAPON:
265121747Sume		arc4random_buf(bpass, sizeof(bpass));
266121747Sume		for (i = 0; i < (int)sizeof(bpass); i++)
267129901Sume			sprintf(&pass[2 * i], "%02x", bpass[i]);
268121747Sume		pass[sizeof(pass) - 1] = '\0';
26992941Sobrien
270156960Sume		error = run_cmd(&fd, "%s init %s -P %s", _PATH_GBDE,
271121426Sume		    dname, pass);
272156960Sume		if (error) {
273121426Sume			/* bde device found.  Ignore it. */
274105943Sume			close(fd);
275144634Sume			if (!qflag)
276144634Sume				warnx("%s: Device already in use", name);
277144634Sume			return (NULL);
278144634Sume		}
27992905Sobrien		close(fd);
28061877Sume		error = run_cmd(&fd, "%s attach %s -p %s", _PATH_GBDE,
28192905Sobrien		    dname, pass);
28292905Sobrien		if (error) {
28361877Sume			close(fd);
284158115Sume			warnx("gbde (attach) error: %s", name);
285158115Sume			return (NULL);
286158115Sume		}
287158115Sume		break;
288158115Sume	case SWAPOFF:
28961877Sume		break;
290156960Sume	default:
291156960Sume		return (NULL);
29292941Sobrien		break;
293156960Sume	}
29461877Sume	if (fd != -1)
29555163Sshin		close(fd);
29655163Sshin	ret = swap_on_off_sfile(name, doingall);
297105940Sume
29855163Sshin	fd = -1;
29955163Sshin	switch (which_prog) {
30055163Sshin	case SWAPOFF:
30155163Sshin		error = run_cmd(&fd, "%s detach %s", _PATH_GBDE, dname);
30255163Sshin		if (error) {
30355163Sshin			/* bde device not found.  Ignore it. */
30455163Sshin			if (!qflag)
30561877Sume				warnx("%s: Device not found", dname);
30655163Sshin			return (NULL);
307105940Sume		}
30855163Sshin		break;
30955163Sshin	default:
31055163Sshin		return (NULL);
31155163Sshin		break;
31255163Sshin	}
31361877Sume
31455163Sshin	if (fd != -1)
315105940Sume		close(fd);
31655163Sshin	return (ret);
31755163Sshin}
31855163Sshin
31955163Sshinstatic const char *
32055163Sshinswap_on_off_geli(char *name, char *mntops, int doingall)
32161877Sume{
32255163Sshin	const char *ops, *aalgo, *ealgo, *keylen_str, *sectorsize_str;
323105940Sume	char *dname, *p;
32455163Sshin	char args[4096];
32555163Sshin	struct stat sb;
32655163Sshin	int fd, error, keylen, sectorsize;
32755163Sshin	u_long ul;
32861877Sume
32961877Sume	dname = strdup(name);
33055163Sshin	p = strrchr(dname, '.');
331105940Sume	if (p == NULL) {
33261877Sume		warnx("%s: Malformed device name", name);
333105940Sume		return (NULL);
33461877Sume	}
33555163Sshin	*p = '\0';
33655163Sshin
337157119Sume	ops = strdup(mntops);
33855163Sshin
33955163Sshin	/* Default parameters for geli(8). */
34055163Sshin	aalgo = "hmac/sha256";
34155163Sshin	ealgo = "aes";
34255163Sshin	keylen = 256;
34355163Sshin	sectorsize = 4096;
34455163Sshin
34555163Sshin	if ((p = strstr(ops, "aalgo=")) != NULL) {
34655163Sshin		aalgo = p + sizeof("aalgo=") - 1;
34761877Sume		p = strchr(aalgo, ',');
34861877Sume		if (p != NULL)
34955163Sshin			*p = '\0';
35055163Sshin	}
35155163Sshin	if ((p = strstr(ops, "ealgo=")) != NULL) {
352157119Sume		ealgo = p + sizeof("ealgo=") - 1;
35355163Sshin		p = strchr(ealgo, ',');
35462836Sitojun		if (p != NULL)
355140908Sume			*p = '\0';
35662836Sitojun	}
35762836Sitojun	if ((p = strstr(ops, "keylen=")) != NULL) {
358140908Sume		keylen_str = p + sizeof("keylen=") - 1;
35962836Sitojun		p = strchr(keylen_str, ',');
360105943Sume		if (p != NULL)
361140908Sume			*p = '\0';
362140908Sume		errno = 0;
363140908Sume		ul = strtoul(keylen_str, &p, 10);
36462836Sitojun		if (errno == 0) {
365140908Sume			if (*p != '\0' || ul > INT_MAX)
36655163Sshin				errno = EINVAL;
36755163Sshin		}
36855163Sshin		if (errno) {
369157119Sume			warn("Invalid keylen: %s", keylen_str);
370157119Sume			return (NULL);
37155163Sshin		}
37255163Sshin		keylen = (int)ul;
37355163Sshin	}
37455163Sshin	if ((p = strstr(ops, "sectorsize=")) != NULL) {
375121474Sume		sectorsize_str = p + sizeof("sectorsize=") - 1;
376121474Sume		p = strchr(sectorsize_str, ',');
37755163Sshin		if (p != NULL)
37855163Sshin			*p = '\0';
379121747Sume		errno = 0;
38055163Sshin		ul = strtoul(sectorsize_str, &p, 10);
38161877Sume		if (errno == 0) {
38255163Sshin			if (*p != '\0' || ul > INT_MAX)
38355163Sshin				errno = EINVAL;
38455163Sshin		}
38555163Sshin		if (errno) {
38655163Sshin			warn("Invalid sectorsize: %s", sectorsize_str);
38755163Sshin			return (NULL);
38855163Sshin		}
38955163Sshin		sectorsize = (int)ul;
39055163Sshin	}
39155163Sshin	snprintf(args, sizeof(args), "-a %s -e %s -l %d -s %d -d",
39255163Sshin	    aalgo, ealgo, keylen, sectorsize);
39355163Sshin	args[sizeof(args) - 1] = '\0';
39455163Sshin	free((void *)ops);
39555163Sshin
39655163Sshin	fd = -1;
39755163Sshin	switch (which_prog) {
39855163Sshin	case SWAPON:
39955163Sshin		error = run_cmd(&fd, "%s onetime %s %s", _PATH_GELI, args,
40055163Sshin		    dname);
40155163Sshin		if (error) {
40255163Sshin			/* eli device found.  Ignore it. */
40355163Sshin			close(fd);
40455163Sshin			if (!qflag)
40555163Sshin				warnx("%s: Device already in use "
40655163Sshin				    "or invalid parameters", name);
40755163Sshin			return (NULL);
40855163Sshin		}
40955163Sshin		break;
41055163Sshin	case SWAPOFF:
41155163Sshin		if (stat(name, &sb) == -1 && errno == ENOENT) {
41255163Sshin			if (!qflag)
41355163Sshin				warnx("%s: Device not found", name);
41455163Sshin			return (NULL);
41555163Sshin		}
41655163Sshin		break;
41755163Sshin	default:
41855163Sshin		return (NULL);
41961877Sume		break;
420121474Sume	}
42161877Sume	if (fd != -1)
422121474Sume		close(fd);
42355163Sshin
424121474Sume	return (swap_on_off_sfile(name, doingall));
42555163Sshin}
426121474Sume
427121474Sumestatic const char *
428121474Sumeswap_on_off_md(char *name, char *mntops, int doingall)
429121474Sume{
43055163Sshin	FILE *sfd;
43155163Sshin	int fd, mdunit, error;
43255163Sshin	const char *ret;
43355163Sshin	char mdpath[PATH_MAX], linebuf[PATH_MAX];
43461877Sume	char *p, *vnodefile;
43561877Sume	size_t linelen;
436105940Sume	u_long ul;
43761877Sume
43861877Sume	fd = -1;
43961877Sume	sfd = NULL;
44061877Sume	if (strlen(name) == (sizeof(MD_NAME) - 1))
44161877Sume		mdunit = -1;
44261877Sume	else {
44361877Sume		errno = 0;
44461877Sume		ul = strtoul(name + 2, &p, 10);
44561877Sume		if (errno == 0) {
44661877Sume			if (*p != '\0' || ul > INT_MAX)
44761877Sume				errno = EINVAL;
44861877Sume		}
44961877Sume		if (errno) {
45061877Sume			warn("Bad device unit: %s", name);
45161877Sume			return (NULL);
45261877Sume		}
45361877Sume		mdunit = (int)ul;
45455163Sshin	}
45555163Sshin
45661877Sume	vnodefile = NULL;
45761877Sume	if ((p = strstr(mntops, "file=")) != NULL) {
45861877Sume		vnodefile = strdup(p + sizeof("file=") - 1);
45955163Sshin		p = strchr(vnodefile, ',');
46055163Sshin		if (p != NULL)
46161877Sume			*p = '\0';
462121474Sume	}
46355163Sshin	if (vnodefile == NULL) {
46455163Sshin		warnx("file option not found for %s", name);
46561877Sume		return (NULL);
46655163Sshin	}
46761877Sume
46861877Sume	switch (which_prog) {
46955163Sshin	case SWAPON:
47055163Sshin		if (mdunit == -1) {
47155163Sshin			error = run_cmd(&fd, "%s -l -n -f %s",
47255163Sshin			    _PATH_MDCONFIG, vnodefile);
47361877Sume			if (error == 0) {
47455163Sshin				/* md device found.  Ignore it. */
47555163Sshin				close(fd);
47655163Sshin				if (!qflag)
47761877Sume					warnx("%s: Device already in use",
47861877Sume					    vnodefile);
47955163Sshin				return (NULL);
48055163Sshin			}
48161877Sume			error = run_cmd(&fd, "%s -a -t vnode -n -f %s",
48261877Sume			    _PATH_MDCONFIG, vnodefile);
483121474Sume			if (error) {
484121474Sume				warnx("mdconfig (attach) error: file=%s",
48555163Sshin				    vnodefile);
48655163Sshin				return (NULL);
487121474Sume			}
488121474Sume			sfd = fdopen(fd, "r");
48955163Sshin			if (sfd == NULL) {
49061877Sume				warn("mdconfig (attach) fdopen error");
491121474Sume				ret = NULL;
492121474Sume				goto err;
493121474Sume			}
494121474Sume			p = fgetln(sfd, &linelen);
495121474Sume			if (p == NULL &&
496121474Sume			    (linelen < 2 || linelen > sizeof(linebuf))) {
497121474Sume				warn("mdconfig (attach) unexpected output");
49855163Sshin				ret = NULL;
499121474Sume				goto err;
500121474Sume			}
501121474Sume			strncpy(linebuf, p, linelen);
502121474Sume			linebuf[linelen - 1] = '\0';
503121474Sume			errno = 0;
50455163Sshin			ul = strtoul(linebuf, &p, 10);
505121474Sume			if (errno == 0) {
506121474Sume				if (*p != '\0' || ul > INT_MAX)
507121474Sume					errno = EINVAL;
508140906Sume			}
509140906Sume			if (errno) {
51055163Sshin				warn("mdconfig (attach) unexpected output: %s",
511121474Sume				    linebuf);
512121474Sume				ret = NULL;
513121474Sume				goto err;
514121474Sume			}
515121474Sume			mdunit = (int)ul;
51655163Sshin		} else {
51755163Sshin			error = run_cmd(&fd, "%s -l -n -f %s -u %d",
518121474Sume			    _PATH_MDCONFIG, vnodefile, mdunit);
519121474Sume			if (error == 0) {
520121474Sume				/* md device found.  Ignore it. */
521121474Sume				close(fd);
522121474Sume				if (!qflag)
523121747Sume					warnx("md%d on %s: Device already "
524121747Sume					    "in use", mdunit, vnodefile);
525121474Sume				return (NULL);
526121747Sume			}
527121474Sume			error = run_cmd(NULL, "%s -a -t vnode -u %d -f %s",
528121425Sume			    _PATH_MDCONFIG, mdunit, vnodefile);
529121425Sume			if (error) {
53055163Sshin				warnx("mdconfig (attach) error: "
53190053Sroam				    "md%d on file=%s", mdunit, vnodefile);
53255163Sshin				return (NULL);
533121474Sume			}
534121474Sume		}
535121474Sume		break;
53661877Sume	case SWAPOFF:
53761877Sume		if (mdunit == -1) {
538121474Sume			error = run_cmd(&fd, "%s -l -n -f %s",
539121474Sume			    _PATH_MDCONFIG, vnodefile);
54061877Sume			if (error) {
54161877Sume				/* md device not found.  Ignore it. */
54261877Sume				close(fd);
54355163Sshin				if (!qflag)
544121474Sume					warnx("md on %s: Device not found",
545121474Sume					    vnodefile);
54661877Sume				return (NULL);
54755163Sshin			}
548121474Sume			sfd = fdopen(fd, "r");
549121474Sume			if (sfd == NULL) {
55061877Sume				warn("mdconfig (list) fdopen error");
551121474Sume				ret = NULL;
552121474Sume				goto err;
553121474Sume			}
55461877Sume			p = fgetln(sfd, &linelen);
555121474Sume			if (p == NULL &&
55655163Sshin			    (linelen < 2 || linelen > sizeof(linebuf) - 1)) {
55761877Sume				warn("mdconfig (list) unexpected output");
55861877Sume				ret = NULL;
55961877Sume				goto err;
56061877Sume			}
56161877Sume			strncpy(linebuf, p, linelen);
562121474Sume			linebuf[linelen - 1] = '\0';
563121474Sume			p = strchr(linebuf, ' ');
56461877Sume			if (p != NULL)
56561877Sume				*p = '\0';
56661877Sume			errno = 0;
56755163Sshin			ul = strtoul(linebuf, &p, 10);
56855163Sshin			if (errno == 0) {
569121747Sume				if (*p != '\0' || ul > INT_MAX)
57061877Sume					errno = EINVAL;
57161877Sume			}
57261877Sume			if (errno) {
573121747Sume				warn("mdconfig (list) unexpected output: %s",
574121747Sume				    linebuf);
575121747Sume				ret = NULL;
576121747Sume				goto err;
577121747Sume			}
578121747Sume			mdunit = (int)ul;
57961877Sume		} else {
58061877Sume			error = run_cmd(&fd, "%s -l -n -f %s -u %d",
581121747Sume			    _PATH_MDCONFIG, vnodefile, mdunit);
582121747Sume			if (error) {
583121747Sume				/* md device not found.  Ignore it. */
584121747Sume				close(fd);
585121747Sume				if (!qflag)
586121747Sume					warnx("md%d on %s: Device not found",
587121747Sume					    mdunit, vnodefile);
588121747Sume				return (NULL);
589121747Sume			}
590121747Sume		}
59161877Sume		break;
592121474Sume	default:
59361877Sume		return (NULL);
59461877Sume	}
59555163Sshin	snprintf(mdpath, sizeof(mdpath), "%s%s%d", _PATH_DEV,
596121747Sume	    MD_NAME, mdunit);
597121747Sume	mdpath[sizeof(mdpath) - 1] = '\0';
598121474Sume	ret = swap_on_off_sfile(mdpath, doingall);
599121474Sume
600121474Sume	switch (which_prog) {
60155163Sshin	case SWAPOFF:
60255163Sshin		if (ret != NULL) {
60355163Sshin			error = run_cmd(NULL, "%s -d -u %d",
604121747Sume			    _PATH_MDCONFIG, mdunit);
605157119Sume			if (error)
606121747Sume				warn("mdconfig (detach) detach failed: %s%s%d",
607121747Sume				    _PATH_DEV, MD_NAME, mdunit);
608121747Sume		}
609121747Sume		break;
610121747Sume	default:
611121747Sume		break;
612121747Sume	}
613121747Sumeerr:
614121747Sume	if (sfd != NULL)
615121747Sume		fclose(sfd);
616121747Sume	if (fd != -1)
617121747Sume		close(fd);
618121747Sume	return (ret);
619121747Sume}
620121747Sume
621121747Sumestatic int
622121747Sumerun_cmd(int *ofd, const char *cmdline, ...)
623121747Sume{
624121747Sume	va_list ap;
625121747Sume	char **argv, **argvp, *cmd, *p;
626121747Sume	int argc, pid, status, rv;
627121747Sume	int pfd[2], nfd, dup2dn;
628121747Sume
629121747Sume	va_start(ap, cmdline);
630121747Sume	rv = vasprintf(&cmd, cmdline, ap);
631121747Sume	if (rv == -1) {
632121747Sume		warn("%s", __func__);
633121747Sume		return (rv);
634121747Sume	}
635121747Sume	va_end(ap);
636121747Sume
637121747Sume	for (argc = 1, p = cmd; (p = strchr(p, ' ')) != NULL; p++)
638121747Sume		argc++;
639121747Sume	argv = (char **)malloc(sizeof(*argv) * (argc + 1));
640129901Sume	for (p = cmd, argvp = argv; (*argvp = strsep(&p, " ")) != NULL;)
641121747Sume		if (**argvp != '\0' && (++argvp > &argv[argc])) {
642121747Sume			*argvp = NULL;
643121747Sume			break;
644121747Sume		}
645121747Sume	/* The argv array ends up NULL-terminated here. */
646121747Sume#if 0
647121747Sume	{
648121747Sume		int i;
649121747Sume
650121747Sume		fprintf(stderr, "DEBUG: running:");
651121747Sume		/* Should be equivalent to 'cmd' (before strsep, of course). */
652121747Sume		for (i = 0; argv[i] != NULL; i++)
653121747Sume			fprintf(stderr, " %s", argv[i]);
654121747Sume		fprintf(stderr, "\n");
655121747Sume	}
656121747Sume#endif
657121747Sume	dup2dn = 1;
658121747Sume	if (ofd != NULL) {
659121747Sume		if (pipe(&pfd[0]) == -1) {
660157119Sume			warn("%s: pipe", __func__);
661121747Sume			return (-1);
662121747Sume		}
663121747Sume		*ofd = pfd[0];
664121747Sume		dup2dn = 0;
665121747Sume	}
666121747Sume	pid = fork();
667121747Sume	switch (pid) {
668121747Sume	case 0:
669121747Sume		/* Child process. */
670121747Sume		if (ofd != NULL)
671121747Sume			if (dup2(pfd[1], STDOUT_FILENO) < 0)
672121747Sume				err(1, "dup2 in %s", __func__);
673121747Sume		nfd = open(_PATH_DEVNULL, O_RDWR);
674121747Sume		if (nfd == -1)
675121747Sume			err(1, "%s: open %s", __func__, _PATH_DEVNULL);
676121747Sume		if (dup2(nfd, STDIN_FILENO) < 0)
677121747Sume			err(1, "%s: dup2", __func__);
678121747Sume		if (dup2dn && dup2(nfd, STDOUT_FILENO) < 0)
679121747Sume			err(1, "%s: dup2", __func__);
680121747Sume		if (dup2(nfd, STDERR_FILENO) < 0)
681121747Sume			err(1, "%s: dup2", __func__);
682121747Sume		execv(argv[0], argv);
683121747Sume		warn("exec: %s", argv[0]);
684121747Sume		_exit(-1);
685121747Sume	case -1:
686121747Sume		err(1, "%s: fork", __func__);
687121747Sume	}
688121747Sume	free(cmd);
689121747Sume	free(argv);
690121747Sume	while (waitpid(pid, &status, 0) != pid)
691121747Sume		;
692121747Sume	return (WEXITSTATUS(status));
693121747Sume}
694121747Sume
695121747Sumestatic const char *
696121747Sumeswap_on_off_sfile(char *name, int doingall)
697157119Sume{
698121747Sume	int error;
699121747Sume
700121747Sume	switch (which_prog) {
701121747Sume	case SWAPON:
702121747Sume		error = swapon(name);
703121747Sume		break;
704121747Sume	case SWAPOFF:
705121747Sume		error = swapoff(name);
706121747Sume		break;
707121747Sume	default:
708121747Sume		error = 0;
709157119Sume		break;
710121747Sume	}
711121747Sume	if (error == -1) {
712121747Sume		switch (errno) {
713121747Sume		case EBUSY:
714121747Sume			if (!doingall)
715121747Sume				warnx("%s: Device already in use", name);
716121747Sume			break;
717121747Sume		case EINVAL:
718121747Sume			if (which_prog == SWAPON)
719121747Sume				warnx("%s: NSWAPDEV limit reached", name);
720121747Sume			else if (!doingall)
721121747Sume				warn("%s", name);
722121747Sume			break;
723121747Sume		default:
724121747Sume			warn("%s", name);
725121747Sume			break;
726121747Sume		}
727121747Sume		return (NULL);
728121747Sume	}
729121747Sume	return (name);
730121747Sume}
731121747Sume
732121747Sumestatic void
733121747Sumeusage(void)
734121747Sume{
735121747Sume	fprintf(stderr, "usage: %s ", getprogname());
736121747Sume	switch(orig_prog) {
737121747Sume	case SWAPON:
738121747Sume	case SWAPOFF:
739121747Sume	    fprintf(stderr, "[-F fstab] -aLq | file ...\n");
740121747Sume	    break;
741121747Sume	case SWAPCTL:
742121747Sume	    fprintf(stderr, "[-AghklmsU] [-a file ... | -d file ...]\n");
743121747Sume	    break;
744121747Sume	}
745121747Sume	exit(1);
746121747Sume}
747121747Sume
748121747Sumestatic void
749121747Sumesizetobuf(char *buf, size_t bufsize, int hflag, long long val, int hlen,
750121747Sume    long blocksize)
751121747Sume{
752121747Sume
753121747Sume	if (hflag == 'H') {
754121747Sume		char tmp[16];
755121747Sume
756121747Sume		humanize_number(tmp, 5, (int64_t)val, "", HN_AUTOSCALE,
757121747Sume		    HN_B | HN_NOSPACE | HN_DECIMAL);
758121747Sume		snprintf(buf, bufsize, "%*s", hlen, tmp);
759121747Sume	} else {
760121747Sume		snprintf(buf, bufsize, "%*lld", hlen, val / blocksize);
761121747Sume	}
762121747Sume}
763121747Sume
764121747Sumestatic void
765121747Sumeswaplist(int lflag, int sflag, int hflag)
766121747Sume{
767121747Sume	size_t mibsize, size;
768121747Sume	struct xswdev xsw;
769121747Sume	int hlen, mib[16], n, pagesize;
770121747Sume	long blocksize;
771121747Sume	long long total = 0;
772121747Sume	long long used = 0;
773121747Sume	long long tmp_total;
774121747Sume	long long tmp_used;
775129901Sume	char buf[32];
776157119Sume
777129901Sume	pagesize = getpagesize();
778129901Sume	switch(hflag) {
779129901Sume	case 'G':
780145786Sume	    blocksize = 1024 * 1024 * 1024;
781145786Sume	    strlcpy(buf, "1GB-blocks", sizeof(buf));
782129901Sume	    hlen = 10;
783129901Sume	    break;
784129901Sume	case 'H':
785129901Sume	    blocksize = -1;
786129901Sume	    strlcpy(buf, "Bytes", sizeof(buf));
787129901Sume	    hlen = 10;
788129901Sume	    break;
789129901Sume	case 'K':
790129901Sume	    blocksize = 1024;
791129901Sume	    strlcpy(buf, "1kB-blocks", sizeof(buf));
792129901Sume	    hlen = 10;
793129901Sume	    break;
794129901Sume	case 'M':
795129901Sume	    blocksize = 1024 * 1024;
796129901Sume	    strlcpy(buf, "1MB-blocks", sizeof(buf));
797129901Sume	    hlen = 10;
798129901Sume	    break;
799129901Sume	default:
800129901Sume	    getbsize(&hlen, &blocksize);
801129901Sume	    snprintf(buf, sizeof(buf), "%ld-blocks", blocksize);
802129901Sume	    break;
803129901Sume	}
804129901Sume
805129901Sume	mibsize = sizeof mib / sizeof mib[0];
806129901Sume	if (sysctlnametomib("vm.swap_info", mib, &mibsize) == -1)
807129901Sume		err(1, "sysctlnametomib()");
808129901Sume
809129901Sume	if (lflag) {
810129901Sume		printf("%-13s %*s %*s\n",
811129901Sume		    "Device:",
812129901Sume		    hlen, buf,
813129901Sume		    hlen, "Used:");
814129901Sume	}
815129901Sume
816129901Sume	for (n = 0; ; ++n) {
817129901Sume		mib[mibsize] = n;
818129901Sume		size = sizeof xsw;
819129901Sume		if (sysctl(mib, mibsize + 1, &xsw, &size, NULL, 0) == -1)
820129901Sume			break;
821129901Sume		if (xsw.xsw_version != XSWDEV_VERSION)
822129901Sume			errx(1, "xswdev version mismatch");
823129901Sume
824129901Sume		tmp_total = (long long)xsw.xsw_nblks * pagesize;
825129901Sume		tmp_used  = (long long)xsw.xsw_used * pagesize;
826129901Sume		total += tmp_total;
827129901Sume		used  += tmp_used;
828129901Sume		if (lflag) {
829129901Sume			sizetobuf(buf, sizeof(buf), hflag, tmp_total, hlen,
830129901Sume			    blocksize);
831129901Sume			printf("/dev/%-8s %s ", devname(xsw.xsw_dev, S_IFCHR),
832129901Sume			    buf);
833129901Sume			sizetobuf(buf, sizeof(buf), hflag, tmp_used, hlen,
834129901Sume			    blocksize);
835129901Sume			printf("%s\n", buf);
836129901Sume		}
837129901Sume	}
838129901Sume	if (errno != ENOENT)
839129901Sume		err(1, "sysctl()");
840129901Sume
841121747Sume	if (sflag) {
842157119Sume		sizetobuf(buf, sizeof(buf), hflag, total, hlen, blocksize);
843129901Sume		printf("Total:        %s ", buf);
844129901Sume		sizetobuf(buf, sizeof(buf), hflag, used, hlen, blocksize);
845129901Sume		printf("%s\n", buf);
846129901Sume	}
847129901Sume}
848129901Sume
849129901Sume