1255267Shrs/*- 21558Srgrimes * Copyright (c) 1980, 1993 31558Srgrimes * The Regents of the University of California. All rights reserved. 41558Srgrimes * 51558Srgrimes * Redistribution and use in source and binary forms, with or without 61558Srgrimes * modification, are permitted provided that the following conditions 71558Srgrimes * are met: 81558Srgrimes * 1. Redistributions of source code must retain the above copyright 91558Srgrimes * notice, this list of conditions and the following disclaimer. 101558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111558Srgrimes * notice, this list of conditions and the following disclaimer in the 121558Srgrimes * documentation and/or other materials provided with the distribution. 131558Srgrimes * 4. Neither the name of the University nor the names of its contributors 141558Srgrimes * may be used to endorse or promote products derived from this software 151558Srgrimes * without specific prior written permission. 161558Srgrimes * 171558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271558Srgrimes * SUCH DAMAGE. 281558Srgrimes */ 291558Srgrimes 30114589Sobrien#if 0 311558Srgrimes#ifndef lint 3238039Scharnierstatic const char copyright[] = 331558Srgrimes"@(#) Copyright (c) 1980, 1993\n\ 341558Srgrimes The Regents of the University of California. All rights reserved.\n"; 351558Srgrimes#endif /* not lint */ 361558Srgrimes 371558Srgrimes#ifndef lint 381558Srgrimesstatic char sccsid[] = "@(#)swapon.c 8.1 (Berkeley) 6/5/93"; 39114589Sobrien#endif /* not lint */ 4038039Scharnier#endif 41114589Sobrien#include <sys/cdefs.h> 42114589Sobrien__FBSDID("$FreeBSD: stable/11/sbin/swapon/swapon.c 360893 2020-05-11 07:21:59Z delphij $"); 431558Srgrimes 44252310Shrs#include <sys/param.h> 45252310Shrs#include <sys/types.h> 46252310Shrs#include <sys/mdioctl.h> 47108375Sdillon#include <sys/stat.h> 48108375Sdillon#include <sys/sysctl.h> 49252310Shrs#include <sys/wait.h> 50138129Sdas#include <vm/vm_param.h> 51108375Sdillon 5238039Scharnier#include <err.h> 5338039Scharnier#include <errno.h> 54252310Shrs#include <fcntl.h> 55252310Shrs#include <fnmatch.h> 561558Srgrimes#include <fstab.h> 57252310Shrs#include <libgen.h> 58252310Shrs#include <libutil.h> 59252310Shrs#include <limits.h> 60252310Shrs#include <paths.h> 61252310Shrs#include <stdarg.h> 621558Srgrimes#include <stdio.h> 6378732Sdd#include <stdlib.h> 6438039Scharnier#include <string.h> 656661Sphk#include <unistd.h> 661558Srgrimes 67108375Sdillonstatic void usage(void); 68252388Sdelphijstatic const char *swap_on_off(const char *, int, char *); 69252388Sdelphijstatic const char *swap_on_off_gbde(const char *, int); 70252388Sdelphijstatic const char *swap_on_off_geli(const char *, char *, int); 71252388Sdelphijstatic const char *swap_on_off_md(const char *, char *, int); 72252388Sdelphijstatic const char *swap_on_off_sfile(const char *, int); 73108375Sdillonstatic void swaplist(int, int, int); 74252310Shrsstatic int run_cmd(int *, const char *, ...) __printflike(2, 3); 756661Sphk 76227081Sedstatic enum { SWAPON, SWAPOFF, SWAPCTL } orig_prog, which_prog = SWAPCTL; 77108375Sdillon 78252310Shrsstatic int qflag; 79252310Shrs 806661Sphkint 816661Sphkmain(int argc, char **argv) 821558Srgrimes{ 8392806Sobrien struct fstab *fsp; 84252310Shrs const char *swfile; 85108375Sdillon char *ptr; 86255267Shrs int ret, ch, doall; 87255267Shrs int sflag, lflag, late, hflag; 88226712Ssobomax const char *etc_fstab; 891558Srgrimes 90255267Shrs sflag = lflag = late = hflag = 0; 91108375Sdillon if ((ptr = strrchr(argv[0], '/')) == NULL) 92108375Sdillon ptr = argv[0]; 93255267Shrs if (strstr(ptr, "swapon") != NULL) 94108375Sdillon which_prog = SWAPON; 95255267Shrs else if (strstr(ptr, "swapoff") != NULL) 96108375Sdillon which_prog = SWAPOFF; 97108375Sdillon orig_prog = which_prog; 98108375Sdillon 991558Srgrimes doall = 0; 100226712Ssobomax etc_fstab = NULL; 101252310Shrs while ((ch = getopt(argc, argv, "AadghklLmqsUF:")) != -1) { 102108375Sdillon switch(ch) { 103108375Sdillon case 'A': 104108375Sdillon if (which_prog == SWAPCTL) { 105108375Sdillon doall = 1; 106108375Sdillon which_prog = SWAPON; 107255267Shrs } else 108108375Sdillon usage(); 109108375Sdillon break; 1101558Srgrimes case 'a': 111108375Sdillon if (which_prog == SWAPON || which_prog == SWAPOFF) 112108375Sdillon doall = 1; 113108375Sdillon else 114108375Sdillon which_prog = SWAPON; 1151558Srgrimes break; 116108375Sdillon case 'd': 117108375Sdillon if (which_prog == SWAPCTL) 118108375Sdillon which_prog = SWAPOFF; 119108375Sdillon else 120108375Sdillon usage(); 121108375Sdillon break; 122179154Spjd case 'g': 123179154Spjd hflag = 'G'; 124108375Sdillon break; 125179154Spjd case 'h': 126179154Spjd hflag = 'H'; 127179154Spjd break; 128179154Spjd case 'k': 129179154Spjd hflag = 'K'; 130179154Spjd break; 131108375Sdillon case 'l': 132108375Sdillon lflag = 1; 133108375Sdillon break; 134252310Shrs case 'L': 135252310Shrs late = 1; 136252310Shrs break; 137179154Spjd case 'm': 138108375Sdillon hflag = 'M'; 139108375Sdillon break; 140179966Smtm case 'q': 141179966Smtm if (which_prog == SWAPON || which_prog == SWAPOFF) 142179966Smtm qflag = 1; 143179966Smtm break; 144179154Spjd case 's': 145179154Spjd sflag = 1; 146108375Sdillon break; 147108375Sdillon case 'U': 148108375Sdillon if (which_prog == SWAPCTL) { 149108375Sdillon doall = 1; 150108375Sdillon which_prog = SWAPOFF; 151255267Shrs } else 152108375Sdillon usage(); 153108375Sdillon break; 154226712Ssobomax case 'F': 155226712Ssobomax etc_fstab = optarg; 156226712Ssobomax break; 1571558Srgrimes case '?': 1581558Srgrimes default: 159108375Sdillon usage(); 1601558Srgrimes } 161108375Sdillon } 1621558Srgrimes argv += optind; 1631558Srgrimes 164226742Sed ret = 0; 165252310Shrs swfile = NULL; 166226712Ssobomax if (etc_fstab != NULL) 167226712Ssobomax setfstab(etc_fstab); 168108375Sdillon if (which_prog == SWAPON || which_prog == SWAPOFF) { 169108375Sdillon if (doall) { 170108375Sdillon while ((fsp = getfsent()) != NULL) { 171255265Shrs if (strcmp(fsp->fs_type, FSTAB_SW) != 0) 172108375Sdillon continue; 173255265Shrs if (strstr(fsp->fs_mntops, "noauto") != NULL) 174108375Sdillon continue; 175252310Shrs if (which_prog != SWAPOFF && 176272885Shrs strstr(fsp->fs_mntops, "late") && 177255265Shrs late == 0) 178252310Shrs continue; 179308865Sjilles if (which_prog == SWAPOFF && 180308865Sjilles strstr(fsp->fs_mntops, "late") == NULL && 181308865Sjilles late != 0) 182308865Sjilles continue; 183252310Shrs swfile = swap_on_off(fsp->fs_spec, 1, 184252310Shrs fsp->fs_mntops); 185252310Shrs if (swfile == NULL) { 186226742Sed ret = 1; 187252310Shrs continue; 188108375Sdillon } 189255267Shrs if (qflag == 0) { 190252310Shrs printf("%s: %sing %s as swap device\n", 191252310Shrs getprogname(), 192252310Shrs (which_prog == SWAPOFF) ? 193252310Shrs "remov" : "add", swfile); 194252310Shrs } 195108375Sdillon } 196255267Shrs } else if (*argv == NULL) 197108375Sdillon usage(); 198108375Sdillon for (; *argv; ++argv) { 199252310Shrs swfile = swap_on_off(*argv, 0, NULL); 200252310Shrs if (swfile == NULL) { 201226742Sed ret = 1; 202252310Shrs continue; 203252310Shrs } 204252310Shrs if (orig_prog == SWAPCTL) { 205107913Sdillon printf("%s: %sing %s as swap device\n", 206252310Shrs getprogname(), 207252310Shrs (which_prog == SWAPOFF) ? "remov" : "add", 208252310Shrs swfile); 209108375Sdillon } 2101558Srgrimes } 211108375Sdillon } else { 212108375Sdillon if (lflag || sflag) 213108375Sdillon swaplist(lflag, sflag, hflag); 214108375Sdillon else 215108375Sdillon usage(); 216108375Sdillon } 217226742Sed exit(ret); 2181558Srgrimes} 2191558Srgrimes 220252310Shrsstatic const char * 221252388Sdelphijswap_on_off(const char *name, int doingall, char *mntops) 222252310Shrs{ 223301024Sed char *base, *basebuf; 224252310Shrs 225252310Shrs /* Swap on vnode-backed md(4) device. */ 226252310Shrs if (mntops != NULL && 227252388Sdelphij (fnmatch(_PATH_DEV MD_NAME "[0-9]*", name, 0) == 0 || 228252388Sdelphij fnmatch(MD_NAME "[0-9]*", name, 0) == 0 || 229252310Shrs strncmp(_PATH_DEV MD_NAME, name, 230252310Shrs sizeof(_PATH_DEV) + sizeof(MD_NAME)) == 0 || 231252310Shrs strncmp(MD_NAME, name, sizeof(MD_NAME)) == 0)) 232252310Shrs return (swap_on_off_md(name, mntops, doingall)); 233252310Shrs 234301024Sed basebuf = strdup(name); 235301024Sed base = basename(basebuf); 236252388Sdelphij 237252310Shrs /* Swap on encrypted device by GEOM_BDE. */ 238301024Sed if (fnmatch("*.bde", base, 0) == 0) { 239301024Sed free(basebuf); 240252310Shrs return (swap_on_off_gbde(name, doingall)); 241301024Sed } 242252310Shrs 243252310Shrs /* Swap on encrypted device by GEOM_ELI. */ 244301024Sed if (fnmatch("*.eli", base, 0) == 0) { 245301024Sed free(basebuf); 246252310Shrs return (swap_on_off_geli(name, mntops, doingall)); 247301024Sed } 248252310Shrs 249252310Shrs /* Swap on special file. */ 250301024Sed free(basebuf); 251252310Shrs return (swap_on_off_sfile(name, doingall)); 252252310Shrs} 253252310Shrs 254252388Sdelphij/* Strip off .bde or .eli suffix from swap device name */ 255252388Sdelphijstatic char * 256252388Sdelphijswap_basename(const char *name) 257252310Shrs{ 258252332Shrs char *dname, *p; 259252310Shrs 260252332Shrs dname = strdup(name); 261252332Shrs p = strrchr(dname, '.'); 262252388Sdelphij /* assert(p != NULL); */ 263252310Shrs *p = '\0'; 264252310Shrs 265252388Sdelphij return (dname); 266252388Sdelphij} 267252388Sdelphij 268252388Sdelphijstatic const char * 269252388Sdelphijswap_on_off_gbde(const char *name, int doingall) 270252388Sdelphij{ 271252388Sdelphij const char *ret; 272259677Sjilles char pass[64 * 2 + 1]; 273259677Sjilles unsigned char bpass[64]; 274252388Sdelphij char *dname; 275252388Sdelphij int i, error; 276252388Sdelphij 277252388Sdelphij dname = swap_basename(name); 278252388Sdelphij if (dname == NULL) 279252388Sdelphij return (NULL); 280252388Sdelphij 281252388Sdelphij if (which_prog == SWAPON) { 282252310Shrs arc4random_buf(bpass, sizeof(bpass)); 283252310Shrs for (i = 0; i < (int)sizeof(bpass); i++) 284252310Shrs sprintf(&pass[2 * i], "%02x", bpass[i]); 285252310Shrs pass[sizeof(pass) - 1] = '\0'; 286252310Shrs 287252388Sdelphij error = run_cmd(NULL, "%s init %s -P %s", _PATH_GBDE, 288252332Shrs dname, pass); 289252310Shrs if (error) { 290252310Shrs /* bde device found. Ignore it. */ 291252388Sdelphij free(dname); 292255267Shrs if (qflag == 0) 293252310Shrs warnx("%s: Device already in use", name); 294252310Shrs return (NULL); 295252310Shrs } 296252388Sdelphij error = run_cmd(NULL, "%s attach %s -p %s", _PATH_GBDE, 297252332Shrs dname, pass); 298252388Sdelphij free(dname); 299252310Shrs if (error) { 300252310Shrs warnx("gbde (attach) error: %s", name); 301252310Shrs return (NULL); 302252310Shrs } 303252310Shrs } 304252388Sdelphij 305252310Shrs ret = swap_on_off_sfile(name, doingall); 306252310Shrs 307252388Sdelphij if (which_prog == SWAPOFF) { 308252388Sdelphij error = run_cmd(NULL, "%s detach %s", _PATH_GBDE, dname); 309252388Sdelphij free(dname); 310252310Shrs if (error) { 311252310Shrs /* bde device not found. Ignore it. */ 312255267Shrs if (qflag == 0) 313252388Sdelphij warnx("%s: Device not found", name); 314252310Shrs return (NULL); 315252310Shrs } 316252310Shrs } 317252310Shrs 318252310Shrs return (ret); 319252310Shrs} 320252310Shrs 321252480Sdelphij/* Build geli(8) arguments from mntops */ 322252388Sdelphijstatic char * 323252388Sdelphijswap_on_geli_args(const char *mntops) 324252310Shrs{ 325252388Sdelphij const char *aalgo, *ealgo, *keylen_str, *sectorsize_str; 326286445Spjd const char *aflag, *eflag, *lflag, *Tflag, *sflag; 327255267Shrs char *p, *args, *token, *string, *ops; 328295121Sngie int pagesize; 329252388Sdelphij size_t pagesize_len; 330252310Shrs u_long ul; 331252310Shrs 332255267Shrs /* Use built-in defaults for geli(8). */ 333252388Sdelphij aalgo = ealgo = keylen_str = ""; 334286445Spjd aflag = eflag = lflag = Tflag = ""; 335252310Shrs 336255267Shrs /* We will always specify sectorsize. */ 337252388Sdelphij sflag = " -s "; 338252388Sdelphij sectorsize_str = NULL; 339252310Shrs 340252388Sdelphij if (mntops != NULL) { 341252388Sdelphij string = ops = strdup(mntops); 342252310Shrs 343252388Sdelphij while ((token = strsep(&string, ",")) != NULL) { 344252388Sdelphij if ((p = strstr(token, "aalgo=")) == token) { 345252388Sdelphij aalgo = p + sizeof("aalgo=") - 1; 346252388Sdelphij aflag = " -a "; 347252388Sdelphij } else if ((p = strstr(token, "ealgo=")) == token) { 348252388Sdelphij ealgo = p + sizeof("ealgo=") - 1; 349252388Sdelphij eflag = " -e "; 350252388Sdelphij } else if ((p = strstr(token, "keylen=")) == token) { 351252388Sdelphij keylen_str = p + sizeof("keylen=") - 1; 352252388Sdelphij errno = 0; 353252388Sdelphij ul = strtoul(keylen_str, &p, 10); 354252388Sdelphij if (errno == 0) { 355252388Sdelphij if (*p != '\0' || ul > INT_MAX) 356252388Sdelphij errno = EINVAL; 357252388Sdelphij } 358252388Sdelphij if (errno) { 359252388Sdelphij warn("Invalid keylen: %s", keylen_str); 360252388Sdelphij free(ops); 361252388Sdelphij return (NULL); 362252388Sdelphij } 363252388Sdelphij lflag = " -l "; 364252388Sdelphij } else if ((p = strstr(token, "sectorsize=")) == token) { 365252388Sdelphij sectorsize_str = p + sizeof("sectorsize=") - 1; 366252388Sdelphij errno = 0; 367252388Sdelphij ul = strtoul(sectorsize_str, &p, 10); 368252388Sdelphij if (errno == 0) { 369252388Sdelphij if (*p != '\0' || ul > INT_MAX) 370252388Sdelphij errno = EINVAL; 371252388Sdelphij } 372252388Sdelphij if (errno) { 373255267Shrs warn("Invalid sectorsize: %s", 374255267Shrs sectorsize_str); 375252388Sdelphij free(ops); 376252388Sdelphij return (NULL); 377252388Sdelphij } 378316096Samdmi3 } else if (strcmp(token, "notrim") == 0) { 379286445Spjd Tflag = " -T "; 380316096Samdmi3 } else if (strcmp(token, "late") == 0) { 381316096Samdmi3 /* ignore known option */ 382316096Samdmi3 } else if (strcmp(token, "noauto") == 0) { 383316096Samdmi3 /* ignore known option */ 384252388Sdelphij } else if (strcmp(token, "sw") != 0) { 385252388Sdelphij warnx("Invalid option: %s", token); 386252388Sdelphij free(ops); 387252388Sdelphij return (NULL); 388252388Sdelphij } 389252310Shrs } 390252388Sdelphij } else 391252388Sdelphij ops = NULL; 392252388Sdelphij 393252388Sdelphij /* 394252388Sdelphij * If we do not have a sector size at this point, fill in 395252388Sdelphij * pagesize as sector size. 396252388Sdelphij */ 397252388Sdelphij if (sectorsize_str == NULL) { 398255267Shrs /* Use pagesize as default sectorsize. */ 399252388Sdelphij pagesize = getpagesize(); 400252388Sdelphij pagesize_len = snprintf(NULL, 0, "%d", pagesize) + 1; 401252388Sdelphij p = alloca(pagesize_len); 402252388Sdelphij snprintf(p, pagesize_len, "%d", pagesize); 403252388Sdelphij sectorsize_str = p; 404252310Shrs } 405252388Sdelphij 406295121Sngie (void)asprintf(&args, "%s%s%s%s%s%s%s%s%s -d", 407286445Spjd aflag, aalgo, eflag, ealgo, lflag, keylen_str, Tflag, 408252388Sdelphij sflag, sectorsize_str); 409252388Sdelphij 410252388Sdelphij free(ops); 411252388Sdelphij return (args); 412252388Sdelphij} 413252388Sdelphij 414252388Sdelphijstatic const char * 415252388Sdelphijswap_on_off_geli(const char *name, char *mntops, int doingall) 416252388Sdelphij{ 417252388Sdelphij struct stat sb; 418255267Shrs char *dname, *args; 419252388Sdelphij int error; 420252388Sdelphij 421252388Sdelphij error = stat(name, &sb); 422252388Sdelphij 423252388Sdelphij if (which_prog == SWAPON) do { 424255267Shrs /* Skip if the .eli device already exists. */ 425252388Sdelphij if (error == 0) 426252388Sdelphij break; 427252388Sdelphij 428252388Sdelphij args = swap_on_geli_args(mntops); 429252388Sdelphij if (args == NULL) 430252310Shrs return (NULL); 431252388Sdelphij 432252388Sdelphij dname = swap_basename(name); 433252388Sdelphij if (dname == NULL) { 434252388Sdelphij free(args); 435252388Sdelphij return (NULL); 436252310Shrs } 437252310Shrs 438252388Sdelphij error = run_cmd(NULL, "%s onetime%s %s", _PATH_GELI, args, 439252332Shrs dname); 440252388Sdelphij 441252388Sdelphij free(dname); 442252388Sdelphij free(args); 443252388Sdelphij 444252310Shrs if (error) { 445298858Spfg /* error occurred during creation. */ 446255267Shrs if (qflag == 0) 447252388Sdelphij warnx("%s: Invalid parameters", name); 448252310Shrs return (NULL); 449252310Shrs } 450252388Sdelphij } while (0); 451252310Shrs 452252310Shrs return (swap_on_off_sfile(name, doingall)); 453252310Shrs} 454252310Shrs 455252310Shrsstatic const char * 456252388Sdelphijswap_on_off_md(const char *name, char *mntops, int doingall) 457252310Shrs{ 458252310Shrs FILE *sfd; 459252310Shrs int fd, mdunit, error; 460252310Shrs const char *ret; 461253834Sdelphij static char mdpath[PATH_MAX], linebuf[PATH_MAX]; 462252310Shrs char *p, *vnodefile; 463252310Shrs size_t linelen; 464252310Shrs u_long ul; 465252310Shrs 466252310Shrs fd = -1; 467252310Shrs sfd = NULL; 468252310Shrs if (strlen(name) == (sizeof(MD_NAME) - 1)) 469252310Shrs mdunit = -1; 470252310Shrs else { 471252310Shrs errno = 0; 472252310Shrs ul = strtoul(name + 2, &p, 10); 473252310Shrs if (errno == 0) { 474252310Shrs if (*p != '\0' || ul > INT_MAX) 475252310Shrs errno = EINVAL; 476252310Shrs } 477252310Shrs if (errno) { 478252310Shrs warn("Bad device unit: %s", name); 479252310Shrs return (NULL); 480252310Shrs } 481252310Shrs mdunit = (int)ul; 482252310Shrs } 483252310Shrs 484252310Shrs vnodefile = NULL; 485252310Shrs if ((p = strstr(mntops, "file=")) != NULL) { 486252310Shrs vnodefile = strdup(p + sizeof("file=") - 1); 487252310Shrs p = strchr(vnodefile, ','); 488252310Shrs if (p != NULL) 489252310Shrs *p = '\0'; 490252310Shrs } 491252310Shrs if (vnodefile == NULL) { 492252310Shrs warnx("file option not found for %s", name); 493252310Shrs return (NULL); 494252310Shrs } 495252310Shrs 496252388Sdelphij if (which_prog == SWAPON) { 497252310Shrs if (mdunit == -1) { 498252310Shrs error = run_cmd(&fd, "%s -l -n -f %s", 499252310Shrs _PATH_MDCONFIG, vnodefile); 500252310Shrs if (error == 0) { 501252310Shrs /* md device found. Ignore it. */ 502252310Shrs close(fd); 503252310Shrs if (!qflag) 504252310Shrs warnx("%s: Device already in use", 505252310Shrs vnodefile); 506252514Sdelphij free(vnodefile); 507252310Shrs return (NULL); 508252310Shrs } 509252310Shrs error = run_cmd(&fd, "%s -a -t vnode -n -f %s", 510252310Shrs _PATH_MDCONFIG, vnodefile); 511252310Shrs if (error) { 512252310Shrs warnx("mdconfig (attach) error: file=%s", 513252310Shrs vnodefile); 514252514Sdelphij free(vnodefile); 515252310Shrs return (NULL); 516252310Shrs } 517252310Shrs sfd = fdopen(fd, "r"); 518252310Shrs if (sfd == NULL) { 519252310Shrs warn("mdconfig (attach) fdopen error"); 520252310Shrs ret = NULL; 521252310Shrs goto err; 522252310Shrs } 523252310Shrs p = fgetln(sfd, &linelen); 524357133Struckman if (p == NULL || 525252310Shrs (linelen < 2 || linelen > sizeof(linebuf))) { 526252310Shrs warn("mdconfig (attach) unexpected output"); 527252310Shrs ret = NULL; 528252310Shrs goto err; 529252310Shrs } 530360893Sdelphij strlcpy(linebuf, p, linelen); 531252310Shrs errno = 0; 532252310Shrs ul = strtoul(linebuf, &p, 10); 533252310Shrs if (errno == 0) { 534252310Shrs if (*p != '\0' || ul > INT_MAX) 535252310Shrs errno = EINVAL; 536252310Shrs } 537252310Shrs if (errno) { 538252310Shrs warn("mdconfig (attach) unexpected output: %s", 539252310Shrs linebuf); 540252310Shrs ret = NULL; 541252310Shrs goto err; 542252310Shrs } 543252310Shrs mdunit = (int)ul; 544252310Shrs } else { 545252310Shrs error = run_cmd(&fd, "%s -l -n -f %s -u %d", 546252310Shrs _PATH_MDCONFIG, vnodefile, mdunit); 547252310Shrs if (error == 0) { 548252310Shrs /* md device found. Ignore it. */ 549252310Shrs close(fd); 550255267Shrs if (qflag == 0) 551252310Shrs warnx("md%d on %s: Device already " 552252310Shrs "in use", mdunit, vnodefile); 553252514Sdelphij free(vnodefile); 554252310Shrs return (NULL); 555252310Shrs } 556252310Shrs error = run_cmd(NULL, "%s -a -t vnode -u %d -f %s", 557252310Shrs _PATH_MDCONFIG, mdunit, vnodefile); 558252310Shrs if (error) { 559252310Shrs warnx("mdconfig (attach) error: " 560252310Shrs "md%d on file=%s", mdunit, vnodefile); 561252514Sdelphij free(vnodefile); 562252310Shrs return (NULL); 563252310Shrs } 564252310Shrs } 565252388Sdelphij } else /* SWAPOFF */ { 566252310Shrs if (mdunit == -1) { 567252310Shrs error = run_cmd(&fd, "%s -l -n -f %s", 568252310Shrs _PATH_MDCONFIG, vnodefile); 569252310Shrs if (error) { 570252310Shrs /* md device not found. Ignore it. */ 571252310Shrs close(fd); 572252310Shrs if (!qflag) 573252310Shrs warnx("md on %s: Device not found", 574252310Shrs vnodefile); 575252514Sdelphij free(vnodefile); 576252310Shrs return (NULL); 577252310Shrs } 578252310Shrs sfd = fdopen(fd, "r"); 579252310Shrs if (sfd == NULL) { 580252310Shrs warn("mdconfig (list) fdopen error"); 581252310Shrs ret = NULL; 582252310Shrs goto err; 583252310Shrs } 584252310Shrs p = fgetln(sfd, &linelen); 585360893Sdelphij if (p == NULL || 586360893Sdelphij (linelen < 2 || linelen > sizeof(linebuf))) { 587252310Shrs warn("mdconfig (list) unexpected output"); 588252310Shrs ret = NULL; 589252310Shrs goto err; 590252310Shrs } 591360893Sdelphij strlcpy(linebuf, p, linelen); 592252310Shrs p = strchr(linebuf, ' '); 593252310Shrs if (p != NULL) 594252310Shrs *p = '\0'; 595252310Shrs errno = 0; 596252310Shrs ul = strtoul(linebuf, &p, 10); 597252310Shrs if (errno == 0) { 598252310Shrs if (*p != '\0' || ul > INT_MAX) 599252310Shrs errno = EINVAL; 600252310Shrs } 601252310Shrs if (errno) { 602252310Shrs warn("mdconfig (list) unexpected output: %s", 603252310Shrs linebuf); 604252310Shrs ret = NULL; 605252310Shrs goto err; 606252310Shrs } 607252310Shrs mdunit = (int)ul; 608252310Shrs } else { 609252310Shrs error = run_cmd(&fd, "%s -l -n -f %s -u %d", 610252310Shrs _PATH_MDCONFIG, vnodefile, mdunit); 611252310Shrs if (error) { 612252310Shrs /* md device not found. Ignore it. */ 613252310Shrs close(fd); 614252310Shrs if (!qflag) 615252310Shrs warnx("md%d on %s: Device not found", 616252310Shrs mdunit, vnodefile); 617252514Sdelphij free(vnodefile); 618252310Shrs return (NULL); 619252310Shrs } 620252310Shrs } 621252310Shrs } 622252310Shrs snprintf(mdpath, sizeof(mdpath), "%s%s%d", _PATH_DEV, 623252310Shrs MD_NAME, mdunit); 624252310Shrs mdpath[sizeof(mdpath) - 1] = '\0'; 625252310Shrs ret = swap_on_off_sfile(mdpath, doingall); 626252310Shrs 627252388Sdelphij if (which_prog == SWAPOFF) { 628252310Shrs if (ret != NULL) { 629252310Shrs error = run_cmd(NULL, "%s -d -u %d", 630252310Shrs _PATH_MDCONFIG, mdunit); 631252310Shrs if (error) 632252310Shrs warn("mdconfig (detach) detach failed: %s%s%d", 633252310Shrs _PATH_DEV, MD_NAME, mdunit); 634252310Shrs } 635252310Shrs } 636252310Shrserr: 637252310Shrs if (sfd != NULL) 638252310Shrs fclose(sfd); 639252310Shrs if (fd != -1) 640252310Shrs close(fd); 641252514Sdelphij free(vnodefile); 642252310Shrs return (ret); 643252310Shrs} 644252310Shrs 645108375Sdillonstatic int 646252310Shrsrun_cmd(int *ofd, const char *cmdline, ...) 6471558Srgrimes{ 648252310Shrs va_list ap; 649252310Shrs char **argv, **argvp, *cmd, *p; 650252310Shrs int argc, pid, status, rv; 651252310Shrs int pfd[2], nfd, dup2dn; 652252310Shrs 653252310Shrs va_start(ap, cmdline); 654252310Shrs rv = vasprintf(&cmd, cmdline, ap); 655252310Shrs if (rv == -1) { 656252310Shrs warn("%s", __func__); 657292005Sngie va_end(ap); 658252310Shrs return (rv); 659252310Shrs } 660252310Shrs va_end(ap); 661252310Shrs 662252310Shrs for (argc = 1, p = cmd; (p = strchr(p, ' ')) != NULL; p++) 663252310Shrs argc++; 664252310Shrs argv = (char **)malloc(sizeof(*argv) * (argc + 1)); 665252310Shrs for (p = cmd, argvp = argv; (*argvp = strsep(&p, " ")) != NULL;) 666252310Shrs if (**argvp != '\0' && (++argvp > &argv[argc])) { 667252310Shrs *argvp = NULL; 668252310Shrs break; 669252310Shrs } 670252310Shrs /* The argv array ends up NULL-terminated here. */ 671252310Shrs#if 0 672252310Shrs { 673252310Shrs int i; 674252310Shrs 675252310Shrs fprintf(stderr, "DEBUG: running:"); 676252310Shrs /* Should be equivalent to 'cmd' (before strsep, of course). */ 677252310Shrs for (i = 0; argv[i] != NULL; i++) 678252310Shrs fprintf(stderr, " %s", argv[i]); 679252310Shrs fprintf(stderr, "\n"); 680252310Shrs } 681252310Shrs#endif 682252310Shrs dup2dn = 1; 683252310Shrs if (ofd != NULL) { 684252310Shrs if (pipe(&pfd[0]) == -1) { 685252310Shrs warn("%s: pipe", __func__); 686252310Shrs return (-1); 687252310Shrs } 688252310Shrs *ofd = pfd[0]; 689252310Shrs dup2dn = 0; 690252310Shrs } 691252310Shrs pid = fork(); 692252310Shrs switch (pid) { 693252310Shrs case 0: 694252310Shrs /* Child process. */ 695252310Shrs if (ofd != NULL) 696252310Shrs if (dup2(pfd[1], STDOUT_FILENO) < 0) 697252310Shrs err(1, "dup2 in %s", __func__); 698252310Shrs nfd = open(_PATH_DEVNULL, O_RDWR); 699252310Shrs if (nfd == -1) 700252310Shrs err(1, "%s: open %s", __func__, _PATH_DEVNULL); 701252310Shrs if (dup2(nfd, STDIN_FILENO) < 0) 702252310Shrs err(1, "%s: dup2", __func__); 703252310Shrs if (dup2dn && dup2(nfd, STDOUT_FILENO) < 0) 704252310Shrs err(1, "%s: dup2", __func__); 705252310Shrs if (dup2(nfd, STDERR_FILENO) < 0) 706252310Shrs err(1, "%s: dup2", __func__); 707252310Shrs execv(argv[0], argv); 708252310Shrs warn("exec: %s", argv[0]); 709252310Shrs _exit(-1); 710252310Shrs case -1: 711252310Shrs err(1, "%s: fork", __func__); 712252310Shrs } 713252310Shrs free(cmd); 714252310Shrs free(argv); 715252310Shrs while (waitpid(pid, &status, 0) != pid) 716252310Shrs ; 717252310Shrs return (WEXITSTATUS(status)); 718252310Shrs} 719252310Shrs 720252310Shrsstatic const char * 721252388Sdelphijswap_on_off_sfile(const char *name, int doingall) 722252310Shrs{ 723252310Shrs int error; 724252310Shrs 725252388Sdelphij if (which_prog == SWAPON) 726252310Shrs error = swapon(name); 727252388Sdelphij else /* SWAPOFF */ 728252310Shrs error = swapoff(name); 729252388Sdelphij 730252310Shrs if (error == -1) { 7311558Srgrimes switch (errno) { 7321558Srgrimes case EBUSY: 733255267Shrs if (doingall == 0) 734252310Shrs warnx("%s: Device already in use", name); 7351558Srgrimes break; 736111424Sdas case EINVAL: 737111424Sdas if (which_prog == SWAPON) 738111424Sdas warnx("%s: NSWAPDEV limit reached", name); 739255267Shrs else if (doingall == 0) 740111424Sdas warn("%s", name); 741111424Sdas break; 7421558Srgrimes default: 74326740Scharnier warn("%s", name); 7441558Srgrimes break; 7451558Srgrimes } 746252310Shrs return (NULL); 7471558Srgrimes } 748252310Shrs return (name); 7491558Srgrimes} 7501558Srgrimes 75126740Scharnierstatic void 752108375Sdillonusage(void) 7531558Srgrimes{ 754255267Shrs 755108375Sdillon fprintf(stderr, "usage: %s ", getprogname()); 756108375Sdillon switch(orig_prog) { 757141611Sru case SWAPON: 758108375Sdillon case SWAPOFF: 759252310Shrs fprintf(stderr, "[-F fstab] -aLq | file ...\n"); 760108375Sdillon break; 761108375Sdillon case SWAPCTL: 762179154Spjd fprintf(stderr, "[-AghklmsU] [-a file ... | -d file ...]\n"); 763108375Sdillon break; 764108375Sdillon } 7651558Srgrimes exit(1); 7661558Srgrimes} 767107913Sdillon 768108375Sdillonstatic void 769179154Spjdsizetobuf(char *buf, size_t bufsize, int hflag, long long val, int hlen, 770179154Spjd long blocksize) 771179154Spjd{ 772255267Shrs char tmp[16]; 773179154Spjd 774179154Spjd if (hflag == 'H') { 775179154Spjd humanize_number(tmp, 5, (int64_t)val, "", HN_AUTOSCALE, 776179154Spjd HN_B | HN_NOSPACE | HN_DECIMAL); 777179154Spjd snprintf(buf, bufsize, "%*s", hlen, tmp); 778255267Shrs } else 779179154Spjd snprintf(buf, bufsize, "%*lld", hlen, val / blocksize); 780179154Spjd} 781179154Spjd 782179154Spjdstatic void 783108375Sdillonswaplist(int lflag, int sflag, int hflag) 784107913Sdillon{ 785108375Sdillon size_t mibsize, size; 786108375Sdillon struct xswdev xsw; 787108425Smike int hlen, mib[16], n, pagesize; 788108375Sdillon long blocksize; 789108375Sdillon long long total = 0; 790108375Sdillon long long used = 0; 791108375Sdillon long long tmp_total; 792108375Sdillon long long tmp_used; 793179154Spjd char buf[32]; 794108375Sdillon 795108375Sdillon pagesize = getpagesize(); 796108375Sdillon switch(hflag) { 797179154Spjd case 'G': 798255267Shrs blocksize = 1024 * 1024 * 1024; 799255267Shrs strlcpy(buf, "1GB-blocks", sizeof(buf)); 800255267Shrs hlen = 10; 801255267Shrs break; 802179154Spjd case 'H': 803255267Shrs blocksize = -1; 804255267Shrs strlcpy(buf, "Bytes", sizeof(buf)); 805255267Shrs hlen = 10; 806255267Shrs break; 807108375Sdillon case 'K': 808255267Shrs blocksize = 1024; 809255267Shrs strlcpy(buf, "1kB-blocks", sizeof(buf)); 810255267Shrs hlen = 10; 811255267Shrs break; 812108375Sdillon case 'M': 813255267Shrs blocksize = 1024 * 1024; 814255267Shrs strlcpy(buf, "1MB-blocks", sizeof(buf)); 815255267Shrs hlen = 10; 816255267Shrs break; 817108375Sdillon default: 818255267Shrs getbsize(&hlen, &blocksize); 819255267Shrs snprintf(buf, sizeof(buf), "%ld-blocks", blocksize); 820255267Shrs break; 821108375Sdillon } 822108375Sdillon 823255267Shrs mibsize = nitems(mib); 824108375Sdillon if (sysctlnametomib("vm.swap_info", mib, &mibsize) == -1) 825108375Sdillon err(1, "sysctlnametomib()"); 826108375Sdillon 827108375Sdillon if (lflag) { 828108375Sdillon printf("%-13s %*s %*s\n", 829108375Sdillon "Device:", 830108375Sdillon hlen, buf, 831108375Sdillon hlen, "Used:"); 832108375Sdillon } 833108375Sdillon 834108375Sdillon for (n = 0; ; ++n) { 835108375Sdillon mib[mibsize] = n; 836108375Sdillon size = sizeof xsw; 837126643Smarkm if (sysctl(mib, mibsize + 1, &xsw, &size, NULL, 0) == -1) 838108375Sdillon break; 839108375Sdillon if (xsw.xsw_version != XSWDEV_VERSION) 840108375Sdillon errx(1, "xswdev version mismatch"); 841108375Sdillon 842179154Spjd tmp_total = (long long)xsw.xsw_nblks * pagesize; 843179154Spjd tmp_used = (long long)xsw.xsw_used * pagesize; 844108375Sdillon total += tmp_total; 845108375Sdillon used += tmp_used; 846108375Sdillon if (lflag) { 847179154Spjd sizetobuf(buf, sizeof(buf), hflag, tmp_total, hlen, 848179154Spjd blocksize); 849179154Spjd printf("/dev/%-8s %s ", devname(xsw.xsw_dev, S_IFCHR), 850179154Spjd buf); 851179154Spjd sizetobuf(buf, sizeof(buf), hflag, tmp_used, hlen, 852179154Spjd blocksize); 853179154Spjd printf("%s\n", buf); 854108375Sdillon } 855108375Sdillon } 856108375Sdillon if (errno != ENOENT) 857108375Sdillon err(1, "sysctl()"); 858108375Sdillon 859108375Sdillon if (sflag) { 860179154Spjd sizetobuf(buf, sizeof(buf), hflag, total, hlen, blocksize); 861179154Spjd printf("Total: %s ", buf); 862179154Spjd sizetobuf(buf, sizeof(buf), hflag, used, hlen, blocksize); 863179154Spjd printf("%s\n", buf); 864108375Sdillon } 865108375Sdillon} 866107913Sdillon 867