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