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$"); 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 && 176273188Shrs strstr(fsp->fs_mntops, "late") && 177255265Shrs late == 0) 178252310Shrs continue; 179252310Shrs swfile = swap_on_off(fsp->fs_spec, 1, 180252310Shrs fsp->fs_mntops); 181252310Shrs if (swfile == NULL) { 182226742Sed ret = 1; 183252310Shrs continue; 184108375Sdillon } 185255267Shrs if (qflag == 0) { 186252310Shrs printf("%s: %sing %s as swap device\n", 187252310Shrs getprogname(), 188252310Shrs (which_prog == SWAPOFF) ? 189252310Shrs "remov" : "add", swfile); 190252310Shrs } 191108375Sdillon } 192255267Shrs } else if (*argv == NULL) 193108375Sdillon usage(); 194108375Sdillon for (; *argv; ++argv) { 195252310Shrs swfile = swap_on_off(*argv, 0, NULL); 196252310Shrs if (swfile == NULL) { 197226742Sed ret = 1; 198252310Shrs continue; 199252310Shrs } 200252310Shrs if (orig_prog == SWAPCTL) { 201107913Sdillon printf("%s: %sing %s as swap device\n", 202252310Shrs getprogname(), 203252310Shrs (which_prog == SWAPOFF) ? "remov" : "add", 204252310Shrs swfile); 205108375Sdillon } 2061558Srgrimes } 207108375Sdillon } else { 208108375Sdillon if (lflag || sflag) 209108375Sdillon swaplist(lflag, sflag, hflag); 210108375Sdillon else 211108375Sdillon usage(); 212108375Sdillon } 213226742Sed exit(ret); 2141558Srgrimes} 2151558Srgrimes 216252310Shrsstatic const char * 217252388Sdelphijswap_on_off(const char *name, int doingall, char *mntops) 218252310Shrs{ 219252310Shrs char base[PATH_MAX]; 220252310Shrs 221252310Shrs /* Swap on vnode-backed md(4) device. */ 222252310Shrs if (mntops != NULL && 223252388Sdelphij (fnmatch(_PATH_DEV MD_NAME "[0-9]*", name, 0) == 0 || 224252388Sdelphij fnmatch(MD_NAME "[0-9]*", name, 0) == 0 || 225252310Shrs strncmp(_PATH_DEV MD_NAME, name, 226252310Shrs sizeof(_PATH_DEV) + sizeof(MD_NAME)) == 0 || 227252310Shrs strncmp(MD_NAME, name, sizeof(MD_NAME)) == 0)) 228252310Shrs return (swap_on_off_md(name, mntops, doingall)); 229252310Shrs 230252388Sdelphij basename_r(name, base); 231252388Sdelphij 232252310Shrs /* Swap on encrypted device by GEOM_BDE. */ 233252388Sdelphij if (fnmatch("*.bde", base, 0) == 0) 234252310Shrs return (swap_on_off_gbde(name, doingall)); 235252310Shrs 236252310Shrs /* Swap on encrypted device by GEOM_ELI. */ 237252388Sdelphij if (fnmatch("*.eli", base, 0) == 0) 238252310Shrs return (swap_on_off_geli(name, mntops, doingall)); 239252310Shrs 240252310Shrs /* Swap on special file. */ 241252310Shrs return (swap_on_off_sfile(name, doingall)); 242252310Shrs} 243252310Shrs 244252388Sdelphij/* Strip off .bde or .eli suffix from swap device name */ 245252388Sdelphijstatic char * 246252388Sdelphijswap_basename(const char *name) 247252310Shrs{ 248252332Shrs char *dname, *p; 249252310Shrs 250252332Shrs dname = strdup(name); 251252332Shrs p = strrchr(dname, '.'); 252252388Sdelphij /* assert(p != NULL); */ 253252310Shrs *p = '\0'; 254252310Shrs 255252388Sdelphij return (dname); 256252388Sdelphij} 257252388Sdelphij 258252388Sdelphijstatic const char * 259252388Sdelphijswap_on_off_gbde(const char *name, int doingall) 260252388Sdelphij{ 261252388Sdelphij const char *ret; 262259820Sjilles char pass[64 * 2 + 1]; 263259820Sjilles unsigned char bpass[64]; 264252388Sdelphij char *dname; 265252388Sdelphij int i, error; 266252388Sdelphij 267252388Sdelphij dname = swap_basename(name); 268252388Sdelphij if (dname == NULL) 269252388Sdelphij return (NULL); 270252388Sdelphij 271252388Sdelphij if (which_prog == SWAPON) { 272252310Shrs arc4random_buf(bpass, sizeof(bpass)); 273252310Shrs for (i = 0; i < (int)sizeof(bpass); i++) 274252310Shrs sprintf(&pass[2 * i], "%02x", bpass[i]); 275252310Shrs pass[sizeof(pass) - 1] = '\0'; 276252310Shrs 277252388Sdelphij error = run_cmd(NULL, "%s init %s -P %s", _PATH_GBDE, 278252332Shrs dname, pass); 279252310Shrs if (error) { 280252310Shrs /* bde device found. Ignore it. */ 281252388Sdelphij free(dname); 282255267Shrs if (qflag == 0) 283252310Shrs warnx("%s: Device already in use", name); 284252310Shrs return (NULL); 285252310Shrs } 286252388Sdelphij error = run_cmd(NULL, "%s attach %s -p %s", _PATH_GBDE, 287252332Shrs dname, pass); 288252388Sdelphij free(dname); 289252310Shrs if (error) { 290252310Shrs warnx("gbde (attach) error: %s", name); 291252310Shrs return (NULL); 292252310Shrs } 293252310Shrs } 294252388Sdelphij 295252310Shrs ret = swap_on_off_sfile(name, doingall); 296252310Shrs 297252388Sdelphij if (which_prog == SWAPOFF) { 298252388Sdelphij error = run_cmd(NULL, "%s detach %s", _PATH_GBDE, dname); 299252388Sdelphij free(dname); 300252310Shrs if (error) { 301252310Shrs /* bde device not found. Ignore it. */ 302255267Shrs if (qflag == 0) 303252388Sdelphij warnx("%s: Device not found", name); 304252310Shrs return (NULL); 305252310Shrs } 306252310Shrs } 307252310Shrs 308252310Shrs return (ret); 309252310Shrs} 310252310Shrs 311252480Sdelphij/* Build geli(8) arguments from mntops */ 312252388Sdelphijstatic char * 313252388Sdelphijswap_on_geli_args(const char *mntops) 314252310Shrs{ 315252388Sdelphij const char *aalgo, *ealgo, *keylen_str, *sectorsize_str; 316252388Sdelphij const char *aflag, *eflag, *lflag, *sflag; 317255267Shrs char *p, *args, *token, *string, *ops; 318252388Sdelphij int argsize, pagesize; 319252388Sdelphij size_t pagesize_len; 320252310Shrs u_long ul; 321252310Shrs 322255267Shrs /* Use built-in defaults for geli(8). */ 323252388Sdelphij aalgo = ealgo = keylen_str = ""; 324252388Sdelphij aflag = eflag = lflag = ""; 325252310Shrs 326255267Shrs /* We will always specify sectorsize. */ 327252388Sdelphij sflag = " -s "; 328252388Sdelphij sectorsize_str = NULL; 329252310Shrs 330252388Sdelphij if (mntops != NULL) { 331252388Sdelphij string = ops = strdup(mntops); 332252310Shrs 333252388Sdelphij while ((token = strsep(&string, ",")) != NULL) { 334252388Sdelphij if ((p = strstr(token, "aalgo=")) == token) { 335252388Sdelphij aalgo = p + sizeof("aalgo=") - 1; 336252388Sdelphij aflag = " -a "; 337252388Sdelphij } else if ((p = strstr(token, "ealgo=")) == token) { 338252388Sdelphij ealgo = p + sizeof("ealgo=") - 1; 339252388Sdelphij eflag = " -e "; 340252388Sdelphij } else if ((p = strstr(token, "keylen=")) == token) { 341252388Sdelphij keylen_str = p + sizeof("keylen=") - 1; 342252388Sdelphij errno = 0; 343252388Sdelphij ul = strtoul(keylen_str, &p, 10); 344252388Sdelphij if (errno == 0) { 345252388Sdelphij if (*p != '\0' || ul > INT_MAX) 346252388Sdelphij errno = EINVAL; 347252388Sdelphij } 348252388Sdelphij if (errno) { 349252388Sdelphij warn("Invalid keylen: %s", keylen_str); 350252388Sdelphij free(ops); 351252388Sdelphij return (NULL); 352252388Sdelphij } 353252388Sdelphij lflag = " -l "; 354252388Sdelphij } else if ((p = strstr(token, "sectorsize=")) == token) { 355252388Sdelphij sectorsize_str = p + sizeof("sectorsize=") - 1; 356252388Sdelphij errno = 0; 357252388Sdelphij ul = strtoul(sectorsize_str, &p, 10); 358252388Sdelphij if (errno == 0) { 359252388Sdelphij if (*p != '\0' || ul > INT_MAX) 360252388Sdelphij errno = EINVAL; 361252388Sdelphij } 362252388Sdelphij if (errno) { 363255267Shrs warn("Invalid sectorsize: %s", 364255267Shrs sectorsize_str); 365252388Sdelphij free(ops); 366252388Sdelphij return (NULL); 367252388Sdelphij } 368252388Sdelphij } else if (strcmp(token, "sw") != 0) { 369252388Sdelphij warnx("Invalid option: %s", token); 370252388Sdelphij free(ops); 371252388Sdelphij return (NULL); 372252388Sdelphij } 373252310Shrs } 374252388Sdelphij } else 375252388Sdelphij ops = NULL; 376252388Sdelphij 377252388Sdelphij /* 378252388Sdelphij * If we do not have a sector size at this point, fill in 379252388Sdelphij * pagesize as sector size. 380252388Sdelphij */ 381252388Sdelphij if (sectorsize_str == NULL) { 382255267Shrs /* Use pagesize as default sectorsize. */ 383252388Sdelphij pagesize = getpagesize(); 384252388Sdelphij pagesize_len = snprintf(NULL, 0, "%d", pagesize) + 1; 385252388Sdelphij p = alloca(pagesize_len); 386252388Sdelphij snprintf(p, pagesize_len, "%d", pagesize); 387252388Sdelphij sectorsize_str = p; 388252310Shrs } 389252388Sdelphij 390252388Sdelphij argsize = asprintf(&args, "%s%s%s%s%s%s%s%s -d", 391252388Sdelphij aflag, aalgo, eflag, ealgo, lflag, keylen_str, 392252388Sdelphij sflag, sectorsize_str); 393252388Sdelphij 394252388Sdelphij free(ops); 395252388Sdelphij return (args); 396252388Sdelphij} 397252388Sdelphij 398252388Sdelphijstatic const char * 399252388Sdelphijswap_on_off_geli(const char *name, char *mntops, int doingall) 400252388Sdelphij{ 401252388Sdelphij struct stat sb; 402255267Shrs char *dname, *args; 403252388Sdelphij int error; 404252388Sdelphij 405252388Sdelphij error = stat(name, &sb); 406252388Sdelphij 407252388Sdelphij if (which_prog == SWAPON) do { 408255267Shrs /* Skip if the .eli device already exists. */ 409252388Sdelphij if (error == 0) 410252388Sdelphij break; 411252388Sdelphij 412252388Sdelphij args = swap_on_geli_args(mntops); 413252388Sdelphij if (args == NULL) 414252310Shrs return (NULL); 415252388Sdelphij 416252388Sdelphij dname = swap_basename(name); 417252388Sdelphij if (dname == NULL) { 418252388Sdelphij free(args); 419252388Sdelphij return (NULL); 420252310Shrs } 421252310Shrs 422252388Sdelphij error = run_cmd(NULL, "%s onetime%s %s", _PATH_GELI, args, 423252332Shrs dname); 424252388Sdelphij 425252388Sdelphij free(dname); 426252388Sdelphij free(args); 427252388Sdelphij 428252310Shrs if (error) { 429255267Shrs /* error occured during creation. */ 430255267Shrs if (qflag == 0) 431252388Sdelphij warnx("%s: Invalid parameters", name); 432252310Shrs return (NULL); 433252310Shrs } 434252388Sdelphij } while (0); 435252310Shrs 436252310Shrs return (swap_on_off_sfile(name, doingall)); 437252310Shrs} 438252310Shrs 439252310Shrsstatic const char * 440252388Sdelphijswap_on_off_md(const char *name, char *mntops, int doingall) 441252310Shrs{ 442252310Shrs FILE *sfd; 443252310Shrs int fd, mdunit, error; 444252310Shrs const char *ret; 445253834Sdelphij static char mdpath[PATH_MAX], linebuf[PATH_MAX]; 446252310Shrs char *p, *vnodefile; 447252310Shrs size_t linelen; 448252310Shrs u_long ul; 449252310Shrs 450252310Shrs fd = -1; 451252310Shrs sfd = NULL; 452252310Shrs if (strlen(name) == (sizeof(MD_NAME) - 1)) 453252310Shrs mdunit = -1; 454252310Shrs else { 455252310Shrs errno = 0; 456252310Shrs ul = strtoul(name + 2, &p, 10); 457252310Shrs if (errno == 0) { 458252310Shrs if (*p != '\0' || ul > INT_MAX) 459252310Shrs errno = EINVAL; 460252310Shrs } 461252310Shrs if (errno) { 462252310Shrs warn("Bad device unit: %s", name); 463252310Shrs return (NULL); 464252310Shrs } 465252310Shrs mdunit = (int)ul; 466252310Shrs } 467252310Shrs 468252310Shrs vnodefile = NULL; 469252310Shrs if ((p = strstr(mntops, "file=")) != NULL) { 470252310Shrs vnodefile = strdup(p + sizeof("file=") - 1); 471252310Shrs p = strchr(vnodefile, ','); 472252310Shrs if (p != NULL) 473252310Shrs *p = '\0'; 474252310Shrs } 475252310Shrs if (vnodefile == NULL) { 476252310Shrs warnx("file option not found for %s", name); 477252310Shrs return (NULL); 478252310Shrs } 479252310Shrs 480252388Sdelphij if (which_prog == SWAPON) { 481252310Shrs if (mdunit == -1) { 482252310Shrs error = run_cmd(&fd, "%s -l -n -f %s", 483252310Shrs _PATH_MDCONFIG, vnodefile); 484252310Shrs if (error == 0) { 485252310Shrs /* md device found. Ignore it. */ 486252310Shrs close(fd); 487252310Shrs if (!qflag) 488252310Shrs warnx("%s: Device already in use", 489252310Shrs vnodefile); 490252514Sdelphij free(vnodefile); 491252310Shrs return (NULL); 492252310Shrs } 493252310Shrs error = run_cmd(&fd, "%s -a -t vnode -n -f %s", 494252310Shrs _PATH_MDCONFIG, vnodefile); 495252310Shrs if (error) { 496252310Shrs warnx("mdconfig (attach) error: file=%s", 497252310Shrs vnodefile); 498252514Sdelphij free(vnodefile); 499252310Shrs return (NULL); 500252310Shrs } 501252310Shrs sfd = fdopen(fd, "r"); 502252310Shrs if (sfd == NULL) { 503252310Shrs warn("mdconfig (attach) fdopen error"); 504252310Shrs ret = NULL; 505252310Shrs goto err; 506252310Shrs } 507252310Shrs p = fgetln(sfd, &linelen); 508252310Shrs if (p == NULL && 509252310Shrs (linelen < 2 || linelen > sizeof(linebuf))) { 510252310Shrs warn("mdconfig (attach) unexpected output"); 511252310Shrs ret = NULL; 512252310Shrs goto err; 513252310Shrs } 514252310Shrs strncpy(linebuf, p, linelen); 515252310Shrs linebuf[linelen - 1] = '\0'; 516252310Shrs errno = 0; 517252310Shrs ul = strtoul(linebuf, &p, 10); 518252310Shrs if (errno == 0) { 519252310Shrs if (*p != '\0' || ul > INT_MAX) 520252310Shrs errno = EINVAL; 521252310Shrs } 522252310Shrs if (errno) { 523252310Shrs warn("mdconfig (attach) unexpected output: %s", 524252310Shrs linebuf); 525252310Shrs ret = NULL; 526252310Shrs goto err; 527252310Shrs } 528252310Shrs mdunit = (int)ul; 529252310Shrs } else { 530252310Shrs error = run_cmd(&fd, "%s -l -n -f %s -u %d", 531252310Shrs _PATH_MDCONFIG, vnodefile, mdunit); 532252310Shrs if (error == 0) { 533252310Shrs /* md device found. Ignore it. */ 534252310Shrs close(fd); 535255267Shrs if (qflag == 0) 536252310Shrs warnx("md%d on %s: Device already " 537252310Shrs "in use", mdunit, vnodefile); 538252514Sdelphij free(vnodefile); 539252310Shrs return (NULL); 540252310Shrs } 541252310Shrs error = run_cmd(NULL, "%s -a -t vnode -u %d -f %s", 542252310Shrs _PATH_MDCONFIG, mdunit, vnodefile); 543252310Shrs if (error) { 544252310Shrs warnx("mdconfig (attach) error: " 545252310Shrs "md%d on file=%s", mdunit, vnodefile); 546252514Sdelphij free(vnodefile); 547252310Shrs return (NULL); 548252310Shrs } 549252310Shrs } 550252388Sdelphij } else /* SWAPOFF */ { 551252310Shrs if (mdunit == -1) { 552252310Shrs error = run_cmd(&fd, "%s -l -n -f %s", 553252310Shrs _PATH_MDCONFIG, vnodefile); 554252310Shrs if (error) { 555252310Shrs /* md device not found. Ignore it. */ 556252310Shrs close(fd); 557252310Shrs if (!qflag) 558252310Shrs warnx("md on %s: Device not found", 559252310Shrs vnodefile); 560252514Sdelphij free(vnodefile); 561252310Shrs return (NULL); 562252310Shrs } 563252310Shrs sfd = fdopen(fd, "r"); 564252310Shrs if (sfd == NULL) { 565252310Shrs warn("mdconfig (list) fdopen error"); 566252310Shrs ret = NULL; 567252310Shrs goto err; 568252310Shrs } 569252310Shrs p = fgetln(sfd, &linelen); 570252310Shrs if (p == NULL && 571252310Shrs (linelen < 2 || linelen > sizeof(linebuf) - 1)) { 572252310Shrs warn("mdconfig (list) unexpected output"); 573252310Shrs ret = NULL; 574252310Shrs goto err; 575252310Shrs } 576252310Shrs strncpy(linebuf, p, linelen); 577252310Shrs linebuf[linelen - 1] = '\0'; 578252310Shrs p = strchr(linebuf, ' '); 579252310Shrs if (p != NULL) 580252310Shrs *p = '\0'; 581252310Shrs errno = 0; 582252310Shrs ul = strtoul(linebuf, &p, 10); 583252310Shrs if (errno == 0) { 584252310Shrs if (*p != '\0' || ul > INT_MAX) 585252310Shrs errno = EINVAL; 586252310Shrs } 587252310Shrs if (errno) { 588252310Shrs warn("mdconfig (list) unexpected output: %s", 589252310Shrs linebuf); 590252310Shrs ret = NULL; 591252310Shrs goto err; 592252310Shrs } 593252310Shrs mdunit = (int)ul; 594252310Shrs } else { 595252310Shrs error = run_cmd(&fd, "%s -l -n -f %s -u %d", 596252310Shrs _PATH_MDCONFIG, vnodefile, mdunit); 597252310Shrs if (error) { 598252310Shrs /* md device not found. Ignore it. */ 599252310Shrs close(fd); 600252310Shrs if (!qflag) 601252310Shrs warnx("md%d on %s: Device not found", 602252310Shrs mdunit, vnodefile); 603252514Sdelphij free(vnodefile); 604252310Shrs return (NULL); 605252310Shrs } 606252310Shrs } 607252310Shrs } 608252310Shrs snprintf(mdpath, sizeof(mdpath), "%s%s%d", _PATH_DEV, 609252310Shrs MD_NAME, mdunit); 610252310Shrs mdpath[sizeof(mdpath) - 1] = '\0'; 611252310Shrs ret = swap_on_off_sfile(mdpath, doingall); 612252310Shrs 613252388Sdelphij if (which_prog == SWAPOFF) { 614252310Shrs if (ret != NULL) { 615252310Shrs error = run_cmd(NULL, "%s -d -u %d", 616252310Shrs _PATH_MDCONFIG, mdunit); 617252310Shrs if (error) 618252310Shrs warn("mdconfig (detach) detach failed: %s%s%d", 619252310Shrs _PATH_DEV, MD_NAME, mdunit); 620252310Shrs } 621252310Shrs } 622252310Shrserr: 623252310Shrs if (sfd != NULL) 624252310Shrs fclose(sfd); 625252310Shrs if (fd != -1) 626252310Shrs close(fd); 627252514Sdelphij free(vnodefile); 628252310Shrs return (ret); 629252310Shrs} 630252310Shrs 631108375Sdillonstatic int 632252310Shrsrun_cmd(int *ofd, const char *cmdline, ...) 6331558Srgrimes{ 634252310Shrs va_list ap; 635252310Shrs char **argv, **argvp, *cmd, *p; 636252310Shrs int argc, pid, status, rv; 637252310Shrs int pfd[2], nfd, dup2dn; 638252310Shrs 639252310Shrs va_start(ap, cmdline); 640252310Shrs rv = vasprintf(&cmd, cmdline, ap); 641252310Shrs if (rv == -1) { 642252310Shrs warn("%s", __func__); 643252310Shrs return (rv); 644252310Shrs } 645252310Shrs va_end(ap); 646252310Shrs 647252310Shrs for (argc = 1, p = cmd; (p = strchr(p, ' ')) != NULL; p++) 648252310Shrs argc++; 649252310Shrs argv = (char **)malloc(sizeof(*argv) * (argc + 1)); 650252310Shrs for (p = cmd, argvp = argv; (*argvp = strsep(&p, " ")) != NULL;) 651252310Shrs if (**argvp != '\0' && (++argvp > &argv[argc])) { 652252310Shrs *argvp = NULL; 653252310Shrs break; 654252310Shrs } 655252310Shrs /* The argv array ends up NULL-terminated here. */ 656252310Shrs#if 0 657252310Shrs { 658252310Shrs int i; 659252310Shrs 660252310Shrs fprintf(stderr, "DEBUG: running:"); 661252310Shrs /* Should be equivalent to 'cmd' (before strsep, of course). */ 662252310Shrs for (i = 0; argv[i] != NULL; i++) 663252310Shrs fprintf(stderr, " %s", argv[i]); 664252310Shrs fprintf(stderr, "\n"); 665252310Shrs } 666252310Shrs#endif 667252310Shrs dup2dn = 1; 668252310Shrs if (ofd != NULL) { 669252310Shrs if (pipe(&pfd[0]) == -1) { 670252310Shrs warn("%s: pipe", __func__); 671252310Shrs return (-1); 672252310Shrs } 673252310Shrs *ofd = pfd[0]; 674252310Shrs dup2dn = 0; 675252310Shrs } 676252310Shrs pid = fork(); 677252310Shrs switch (pid) { 678252310Shrs case 0: 679252310Shrs /* Child process. */ 680252310Shrs if (ofd != NULL) 681252310Shrs if (dup2(pfd[1], STDOUT_FILENO) < 0) 682252310Shrs err(1, "dup2 in %s", __func__); 683252310Shrs nfd = open(_PATH_DEVNULL, O_RDWR); 684252310Shrs if (nfd == -1) 685252310Shrs err(1, "%s: open %s", __func__, _PATH_DEVNULL); 686252310Shrs if (dup2(nfd, STDIN_FILENO) < 0) 687252310Shrs err(1, "%s: dup2", __func__); 688252310Shrs if (dup2dn && dup2(nfd, STDOUT_FILENO) < 0) 689252310Shrs err(1, "%s: dup2", __func__); 690252310Shrs if (dup2(nfd, STDERR_FILENO) < 0) 691252310Shrs err(1, "%s: dup2", __func__); 692252310Shrs execv(argv[0], argv); 693252310Shrs warn("exec: %s", argv[0]); 694252310Shrs _exit(-1); 695252310Shrs case -1: 696252310Shrs err(1, "%s: fork", __func__); 697252310Shrs } 698252310Shrs free(cmd); 699252310Shrs free(argv); 700252310Shrs while (waitpid(pid, &status, 0) != pid) 701252310Shrs ; 702252310Shrs return (WEXITSTATUS(status)); 703252310Shrs} 704252310Shrs 705252310Shrsstatic const char * 706252388Sdelphijswap_on_off_sfile(const char *name, int doingall) 707252310Shrs{ 708252310Shrs int error; 709252310Shrs 710252388Sdelphij if (which_prog == SWAPON) 711252310Shrs error = swapon(name); 712252388Sdelphij else /* SWAPOFF */ 713252310Shrs error = swapoff(name); 714252388Sdelphij 715252310Shrs if (error == -1) { 7161558Srgrimes switch (errno) { 7171558Srgrimes case EBUSY: 718255267Shrs if (doingall == 0) 719252310Shrs warnx("%s: Device already in use", name); 7201558Srgrimes break; 721111424Sdas case EINVAL: 722111424Sdas if (which_prog == SWAPON) 723111424Sdas warnx("%s: NSWAPDEV limit reached", name); 724255267Shrs else if (doingall == 0) 725111424Sdas warn("%s", name); 726111424Sdas break; 7271558Srgrimes default: 72826740Scharnier warn("%s", name); 7291558Srgrimes break; 7301558Srgrimes } 731252310Shrs return (NULL); 7321558Srgrimes } 733252310Shrs return (name); 7341558Srgrimes} 7351558Srgrimes 73626740Scharnierstatic void 737108375Sdillonusage(void) 7381558Srgrimes{ 739255267Shrs 740108375Sdillon fprintf(stderr, "usage: %s ", getprogname()); 741108375Sdillon switch(orig_prog) { 742141611Sru case SWAPON: 743108375Sdillon case SWAPOFF: 744252310Shrs fprintf(stderr, "[-F fstab] -aLq | file ...\n"); 745108375Sdillon break; 746108375Sdillon case SWAPCTL: 747179154Spjd fprintf(stderr, "[-AghklmsU] [-a file ... | -d file ...]\n"); 748108375Sdillon break; 749108375Sdillon } 7501558Srgrimes exit(1); 7511558Srgrimes} 752107913Sdillon 753108375Sdillonstatic void 754179154Spjdsizetobuf(char *buf, size_t bufsize, int hflag, long long val, int hlen, 755179154Spjd long blocksize) 756179154Spjd{ 757255267Shrs char tmp[16]; 758179154Spjd 759179154Spjd if (hflag == 'H') { 760179154Spjd humanize_number(tmp, 5, (int64_t)val, "", HN_AUTOSCALE, 761179154Spjd HN_B | HN_NOSPACE | HN_DECIMAL); 762179154Spjd snprintf(buf, bufsize, "%*s", hlen, tmp); 763255267Shrs } else 764179154Spjd snprintf(buf, bufsize, "%*lld", hlen, val / blocksize); 765179154Spjd} 766179154Spjd 767179154Spjdstatic void 768108375Sdillonswaplist(int lflag, int sflag, int hflag) 769107913Sdillon{ 770108375Sdillon size_t mibsize, size; 771108375Sdillon struct xswdev xsw; 772108425Smike int hlen, mib[16], n, pagesize; 773108375Sdillon long blocksize; 774108375Sdillon long long total = 0; 775108375Sdillon long long used = 0; 776108375Sdillon long long tmp_total; 777108375Sdillon long long tmp_used; 778179154Spjd char buf[32]; 779108375Sdillon 780108375Sdillon pagesize = getpagesize(); 781108375Sdillon switch(hflag) { 782179154Spjd case 'G': 783255267Shrs blocksize = 1024 * 1024 * 1024; 784255267Shrs strlcpy(buf, "1GB-blocks", sizeof(buf)); 785255267Shrs hlen = 10; 786255267Shrs break; 787179154Spjd case 'H': 788255267Shrs blocksize = -1; 789255267Shrs strlcpy(buf, "Bytes", sizeof(buf)); 790255267Shrs hlen = 10; 791255267Shrs break; 792108375Sdillon case 'K': 793255267Shrs blocksize = 1024; 794255267Shrs strlcpy(buf, "1kB-blocks", sizeof(buf)); 795255267Shrs hlen = 10; 796255267Shrs break; 797108375Sdillon case 'M': 798255267Shrs blocksize = 1024 * 1024; 799255267Shrs strlcpy(buf, "1MB-blocks", sizeof(buf)); 800255267Shrs hlen = 10; 801255267Shrs break; 802108375Sdillon default: 803255267Shrs getbsize(&hlen, &blocksize); 804255267Shrs snprintf(buf, sizeof(buf), "%ld-blocks", blocksize); 805255267Shrs break; 806108375Sdillon } 807108375Sdillon 808255267Shrs mibsize = nitems(mib); 809108375Sdillon if (sysctlnametomib("vm.swap_info", mib, &mibsize) == -1) 810108375Sdillon err(1, "sysctlnametomib()"); 811108375Sdillon 812108375Sdillon if (lflag) { 813108375Sdillon printf("%-13s %*s %*s\n", 814108375Sdillon "Device:", 815108375Sdillon hlen, buf, 816108375Sdillon hlen, "Used:"); 817108375Sdillon } 818108375Sdillon 819108375Sdillon for (n = 0; ; ++n) { 820108375Sdillon mib[mibsize] = n; 821108375Sdillon size = sizeof xsw; 822126643Smarkm if (sysctl(mib, mibsize + 1, &xsw, &size, NULL, 0) == -1) 823108375Sdillon break; 824108375Sdillon if (xsw.xsw_version != XSWDEV_VERSION) 825108375Sdillon errx(1, "xswdev version mismatch"); 826108375Sdillon 827179154Spjd tmp_total = (long long)xsw.xsw_nblks * pagesize; 828179154Spjd tmp_used = (long long)xsw.xsw_used * pagesize; 829108375Sdillon total += tmp_total; 830108375Sdillon used += tmp_used; 831108375Sdillon if (lflag) { 832179154Spjd sizetobuf(buf, sizeof(buf), hflag, tmp_total, hlen, 833179154Spjd blocksize); 834179154Spjd printf("/dev/%-8s %s ", devname(xsw.xsw_dev, S_IFCHR), 835179154Spjd buf); 836179154Spjd sizetobuf(buf, sizeof(buf), hflag, tmp_used, hlen, 837179154Spjd blocksize); 838179154Spjd printf("%s\n", buf); 839108375Sdillon } 840108375Sdillon } 841108375Sdillon if (errno != ENOENT) 842108375Sdillon err(1, "sysctl()"); 843108375Sdillon 844108375Sdillon if (sflag) { 845179154Spjd sizetobuf(buf, sizeof(buf), hflag, total, hlen, blocksize); 846179154Spjd printf("Total: %s ", buf); 847179154Spjd sizetobuf(buf, sizeof(buf), hflag, used, hlen, blocksize); 848179154Spjd printf("%s\n", buf); 849108375Sdillon } 850108375Sdillon} 851107913Sdillon 852