swapon.c revision 253834
11558Srgrimes/* 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: head/sbin/swapon/swapon.c 253834 2013-07-31 07:09:35Z 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; 86226742Sed int ret; 871558Srgrimes int ch, doall; 88252310Shrs int sflag = 0, lflag = 0, late = 0, hflag = 0; 89226712Ssobomax const char *etc_fstab; 901558Srgrimes 91108375Sdillon if ((ptr = strrchr(argv[0], '/')) == NULL) 92108375Sdillon ptr = argv[0]; 93108375Sdillon if (strstr(ptr, "swapon")) 94108375Sdillon which_prog = SWAPON; 95108375Sdillon else if (strstr(ptr, "swapoff")) 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; 107108375Sdillon } else { 108108375Sdillon usage(); 109108375Sdillon } 110108375Sdillon break; 1111558Srgrimes case 'a': 112108375Sdillon if (which_prog == SWAPON || which_prog == SWAPOFF) 113108375Sdillon doall = 1; 114108375Sdillon else 115108375Sdillon which_prog = SWAPON; 1161558Srgrimes break; 117108375Sdillon case 'd': 118108375Sdillon if (which_prog == SWAPCTL) 119108375Sdillon which_prog = SWAPOFF; 120108375Sdillon else 121108375Sdillon usage(); 122108375Sdillon break; 123179154Spjd case 'g': 124179154Spjd hflag = 'G'; 125108375Sdillon break; 126179154Spjd case 'h': 127179154Spjd hflag = 'H'; 128179154Spjd break; 129179154Spjd case 'k': 130179154Spjd hflag = 'K'; 131179154Spjd break; 132108375Sdillon case 'l': 133108375Sdillon lflag = 1; 134108375Sdillon break; 135252310Shrs case 'L': 136252310Shrs late = 1; 137252310Shrs break; 138179154Spjd case 'm': 139108375Sdillon hflag = 'M'; 140108375Sdillon break; 141179966Smtm case 'q': 142179966Smtm if (which_prog == SWAPON || which_prog == SWAPOFF) 143179966Smtm qflag = 1; 144179966Smtm break; 145179154Spjd case 's': 146179154Spjd sflag = 1; 147108375Sdillon break; 148108375Sdillon case 'U': 149108375Sdillon if (which_prog == SWAPCTL) { 150108375Sdillon doall = 1; 151108375Sdillon which_prog = SWAPOFF; 152108375Sdillon } else { 153108375Sdillon usage(); 154108375Sdillon } 155108375Sdillon break; 156226712Ssobomax case 'F': 157226712Ssobomax etc_fstab = optarg; 158226712Ssobomax break; 1591558Srgrimes case '?': 1601558Srgrimes default: 161108375Sdillon usage(); 1621558Srgrimes } 163108375Sdillon } 1641558Srgrimes argv += optind; 1651558Srgrimes 166226742Sed ret = 0; 167252310Shrs swfile = NULL; 168226712Ssobomax if (etc_fstab != NULL) 169226712Ssobomax setfstab(etc_fstab); 170108375Sdillon if (which_prog == SWAPON || which_prog == SWAPOFF) { 171108375Sdillon if (doall) { 172108375Sdillon while ((fsp = getfsent()) != NULL) { 173108375Sdillon if (strcmp(fsp->fs_type, FSTAB_SW)) 174108375Sdillon continue; 175108375Sdillon if (strstr(fsp->fs_mntops, "noauto")) 176108375Sdillon continue; 177252310Shrs if (which_prog != SWAPOFF && 178252310Shrs strstr(fsp->fs_mntops, "late") && 179252310Shrs !late) 180252310Shrs continue; 181252310Shrs swfile = swap_on_off(fsp->fs_spec, 1, 182252310Shrs fsp->fs_mntops); 183252310Shrs if (swfile == NULL) { 184226742Sed ret = 1; 185252310Shrs continue; 186108375Sdillon } 187252310Shrs if (!qflag) { 188252310Shrs printf("%s: %sing %s as swap device\n", 189252310Shrs getprogname(), 190252310Shrs (which_prog == SWAPOFF) ? 191252310Shrs "remov" : "add", swfile); 192252310Shrs } 193108375Sdillon } 194108375Sdillon } 195108375Sdillon else if (!*argv) 196108375Sdillon usage(); 197108375Sdillon for (; *argv; ++argv) { 198252310Shrs swfile = swap_on_off(*argv, 0, NULL); 199252310Shrs if (swfile == NULL) { 200226742Sed ret = 1; 201252310Shrs continue; 202252310Shrs } 203252310Shrs if (orig_prog == SWAPCTL) { 204107913Sdillon printf("%s: %sing %s as swap device\n", 205252310Shrs getprogname(), 206252310Shrs (which_prog == SWAPOFF) ? "remov" : "add", 207252310Shrs swfile); 208108375Sdillon } 2091558Srgrimes } 210108375Sdillon } else { 211108375Sdillon if (lflag || sflag) 212108375Sdillon swaplist(lflag, sflag, hflag); 213108375Sdillon else 214108375Sdillon usage(); 215108375Sdillon } 216226742Sed exit(ret); 2171558Srgrimes} 2181558Srgrimes 219252310Shrsstatic const char * 220252388Sdelphijswap_on_off(const char *name, int doingall, char *mntops) 221252310Shrs{ 222252310Shrs char base[PATH_MAX]; 223252310Shrs 224252310Shrs /* Swap on vnode-backed md(4) device. */ 225252310Shrs if (mntops != NULL && 226252388Sdelphij (fnmatch(_PATH_DEV MD_NAME "[0-9]*", name, 0) == 0 || 227252388Sdelphij fnmatch(MD_NAME "[0-9]*", name, 0) == 0 || 228252310Shrs strncmp(_PATH_DEV MD_NAME, name, 229252310Shrs sizeof(_PATH_DEV) + sizeof(MD_NAME)) == 0 || 230252310Shrs strncmp(MD_NAME, name, sizeof(MD_NAME)) == 0)) 231252310Shrs return (swap_on_off_md(name, mntops, doingall)); 232252310Shrs 233252388Sdelphij basename_r(name, base); 234252388Sdelphij 235252310Shrs /* Swap on encrypted device by GEOM_BDE. */ 236252388Sdelphij if (fnmatch("*.bde", base, 0) == 0) 237252310Shrs return (swap_on_off_gbde(name, doingall)); 238252310Shrs 239252310Shrs /* Swap on encrypted device by GEOM_ELI. */ 240252388Sdelphij if (fnmatch("*.eli", base, 0) == 0) 241252310Shrs return (swap_on_off_geli(name, mntops, doingall)); 242252310Shrs 243252310Shrs /* Swap on special file. */ 244252310Shrs return (swap_on_off_sfile(name, doingall)); 245252310Shrs} 246252310Shrs 247252388Sdelphij/* Strip off .bde or .eli suffix from swap device name */ 248252388Sdelphijstatic char * 249252388Sdelphijswap_basename(const char *name) 250252310Shrs{ 251252332Shrs char *dname, *p; 252252310Shrs 253252332Shrs dname = strdup(name); 254252332Shrs p = strrchr(dname, '.'); 255252388Sdelphij /* assert(p != NULL); */ 256252310Shrs *p = '\0'; 257252310Shrs 258252388Sdelphij return (dname); 259252388Sdelphij} 260252388Sdelphij 261252388Sdelphijstatic const char * 262252388Sdelphijswap_on_off_gbde(const char *name, int doingall) 263252388Sdelphij{ 264252388Sdelphij const char *ret; 265252388Sdelphij char pass[64 * 2 + 1], bpass[64]; 266252388Sdelphij char *dname; 267252388Sdelphij int i, error; 268252388Sdelphij 269252388Sdelphij dname = swap_basename(name); 270252388Sdelphij if (dname == NULL) 271252388Sdelphij return (NULL); 272252388Sdelphij 273252388Sdelphij if (which_prog == SWAPON) { 274252310Shrs arc4random_buf(bpass, sizeof(bpass)); 275252310Shrs for (i = 0; i < (int)sizeof(bpass); i++) 276252310Shrs sprintf(&pass[2 * i], "%02x", bpass[i]); 277252310Shrs pass[sizeof(pass) - 1] = '\0'; 278252310Shrs 279252388Sdelphij error = run_cmd(NULL, "%s init %s -P %s", _PATH_GBDE, 280252332Shrs dname, pass); 281252310Shrs if (error) { 282252310Shrs /* bde device found. Ignore it. */ 283252388Sdelphij free(dname); 284252310Shrs if (!qflag) 285252310Shrs warnx("%s: Device already in use", name); 286252310Shrs return (NULL); 287252310Shrs } 288252388Sdelphij error = run_cmd(NULL, "%s attach %s -p %s", _PATH_GBDE, 289252332Shrs dname, pass); 290252388Sdelphij free(dname); 291252310Shrs if (error) { 292252310Shrs warnx("gbde (attach) error: %s", name); 293252310Shrs return (NULL); 294252310Shrs } 295252310Shrs } 296252388Sdelphij 297252310Shrs ret = swap_on_off_sfile(name, doingall); 298252310Shrs 299252388Sdelphij if (which_prog == SWAPOFF) { 300252388Sdelphij error = run_cmd(NULL, "%s detach %s", _PATH_GBDE, dname); 301252388Sdelphij free(dname); 302252310Shrs if (error) { 303252310Shrs /* bde device not found. Ignore it. */ 304252310Shrs if (!qflag) 305252388Sdelphij warnx("%s: Device not found", name); 306252310Shrs return (NULL); 307252310Shrs } 308252310Shrs } 309252310Shrs 310252310Shrs return (ret); 311252310Shrs} 312252310Shrs 313252480Sdelphij/* Build geli(8) arguments from mntops */ 314252388Sdelphijstatic char * 315252388Sdelphijswap_on_geli_args(const char *mntops) 316252310Shrs{ 317252388Sdelphij const char *aalgo, *ealgo, *keylen_str, *sectorsize_str; 318252388Sdelphij const char *aflag, *eflag, *lflag, *sflag; 319252388Sdelphij char *p; 320252388Sdelphij char *args; 321252388Sdelphij char *token, *string, *ops; 322252388Sdelphij int argsize, pagesize; 323252388Sdelphij size_t pagesize_len; 324252310Shrs u_long ul; 325252310Shrs 326252388Sdelphij /* Use built-in defaults for geli(8) */ 327252388Sdelphij aalgo = ealgo = keylen_str = ""; 328252388Sdelphij aflag = eflag = lflag = ""; 329252310Shrs 330252388Sdelphij /* We will always specify sectorsize */ 331252388Sdelphij sflag = " -s "; 332252388Sdelphij sectorsize_str = NULL; 333252310Shrs 334252388Sdelphij if (mntops != NULL) { 335252388Sdelphij string = ops = strdup(mntops); 336252310Shrs 337252388Sdelphij while ((token = strsep(&string, ",")) != NULL) { 338252388Sdelphij if ((p = strstr(token, "aalgo=")) == token) { 339252388Sdelphij aalgo = p + sizeof("aalgo=") - 1; 340252388Sdelphij aflag = " -a "; 341252388Sdelphij } else if ((p = strstr(token, "ealgo=")) == token) { 342252388Sdelphij ealgo = p + sizeof("ealgo=") - 1; 343252388Sdelphij eflag = " -e "; 344252388Sdelphij } else if ((p = strstr(token, "keylen=")) == token) { 345252388Sdelphij keylen_str = p + sizeof("keylen=") - 1; 346252388Sdelphij errno = 0; 347252388Sdelphij ul = strtoul(keylen_str, &p, 10); 348252388Sdelphij if (errno == 0) { 349252388Sdelphij if (*p != '\0' || ul > INT_MAX) 350252388Sdelphij errno = EINVAL; 351252388Sdelphij } 352252388Sdelphij if (errno) { 353252388Sdelphij warn("Invalid keylen: %s", keylen_str); 354252388Sdelphij free(ops); 355252388Sdelphij return (NULL); 356252388Sdelphij } 357252388Sdelphij lflag = " -l "; 358252388Sdelphij } else if ((p = strstr(token, "sectorsize=")) == token) { 359252388Sdelphij sectorsize_str = p + sizeof("sectorsize=") - 1; 360252388Sdelphij errno = 0; 361252388Sdelphij ul = strtoul(sectorsize_str, &p, 10); 362252388Sdelphij if (errno == 0) { 363252388Sdelphij if (*p != '\0' || ul > INT_MAX) 364252388Sdelphij errno = EINVAL; 365252388Sdelphij } 366252388Sdelphij if (errno) { 367252388Sdelphij warn("Invalid sectorsize: %s", sectorsize_str); 368252388Sdelphij free(ops); 369252388Sdelphij return (NULL); 370252388Sdelphij } 371252388Sdelphij } else if (strcmp(token, "sw") != 0) { 372252388Sdelphij warnx("Invalid option: %s", token); 373252388Sdelphij free(ops); 374252388Sdelphij return (NULL); 375252388Sdelphij } 376252310Shrs } 377252388Sdelphij } else 378252388Sdelphij ops = NULL; 379252388Sdelphij 380252388Sdelphij /* 381252388Sdelphij * If we do not have a sector size at this point, fill in 382252388Sdelphij * pagesize as sector size. 383252388Sdelphij */ 384252388Sdelphij if (sectorsize_str == NULL) { 385252388Sdelphij /* Use pagesize as default sectorsize */ 386252388Sdelphij pagesize = getpagesize(); 387252388Sdelphij pagesize_len = snprintf(NULL, 0, "%d", pagesize) + 1; 388252388Sdelphij p = alloca(pagesize_len); 389252388Sdelphij snprintf(p, pagesize_len, "%d", pagesize); 390252388Sdelphij sectorsize_str = p; 391252310Shrs } 392252388Sdelphij 393252388Sdelphij argsize = asprintf(&args, "%s%s%s%s%s%s%s%s -d", 394252388Sdelphij aflag, aalgo, eflag, ealgo, lflag, keylen_str, 395252388Sdelphij sflag, sectorsize_str); 396252388Sdelphij 397252388Sdelphij free(ops); 398252388Sdelphij return (args); 399252388Sdelphij} 400252388Sdelphij 401252388Sdelphijstatic const char * 402252388Sdelphijswap_on_off_geli(const char *name, char *mntops, int doingall) 403252388Sdelphij{ 404252388Sdelphij char *dname; 405252388Sdelphij char *args; 406252388Sdelphij struct stat sb; 407252388Sdelphij int error; 408252388Sdelphij 409252388Sdelphij error = stat(name, &sb); 410252388Sdelphij 411252388Sdelphij if (which_prog == SWAPON) do { 412252388Sdelphij /* Skip if the .eli device already exists */ 413252388Sdelphij if (error == 0) 414252388Sdelphij break; 415252388Sdelphij 416252388Sdelphij args = swap_on_geli_args(mntops); 417252388Sdelphij if (args == NULL) 418252310Shrs return (NULL); 419252388Sdelphij 420252388Sdelphij dname = swap_basename(name); 421252388Sdelphij if (dname == NULL) { 422252388Sdelphij free(args); 423252388Sdelphij return (NULL); 424252310Shrs } 425252310Shrs 426252388Sdelphij error = run_cmd(NULL, "%s onetime%s %s", _PATH_GELI, args, 427252332Shrs dname); 428252388Sdelphij 429252388Sdelphij free(dname); 430252388Sdelphij free(args); 431252388Sdelphij 432252310Shrs if (error) { 433252388Sdelphij /* error occured during creation */ 434252310Shrs if (!qflag) 435252388Sdelphij warnx("%s: Invalid parameters", name); 436252310Shrs return (NULL); 437252310Shrs } 438252388Sdelphij } while (0); 439252310Shrs 440252310Shrs return (swap_on_off_sfile(name, doingall)); 441252310Shrs} 442252310Shrs 443252310Shrsstatic const char * 444252388Sdelphijswap_on_off_md(const char *name, char *mntops, int doingall) 445252310Shrs{ 446252310Shrs FILE *sfd; 447252310Shrs int fd, mdunit, error; 448252310Shrs const char *ret; 449253834Sdelphij static char mdpath[PATH_MAX], linebuf[PATH_MAX]; 450252310Shrs char *p, *vnodefile; 451252310Shrs size_t linelen; 452252310Shrs u_long ul; 453252310Shrs 454252310Shrs fd = -1; 455252310Shrs sfd = NULL; 456252310Shrs if (strlen(name) == (sizeof(MD_NAME) - 1)) 457252310Shrs mdunit = -1; 458252310Shrs else { 459252310Shrs errno = 0; 460252310Shrs ul = strtoul(name + 2, &p, 10); 461252310Shrs if (errno == 0) { 462252310Shrs if (*p != '\0' || ul > INT_MAX) 463252310Shrs errno = EINVAL; 464252310Shrs } 465252310Shrs if (errno) { 466252310Shrs warn("Bad device unit: %s", name); 467252310Shrs return (NULL); 468252310Shrs } 469252310Shrs mdunit = (int)ul; 470252310Shrs } 471252310Shrs 472252310Shrs vnodefile = NULL; 473252310Shrs if ((p = strstr(mntops, "file=")) != NULL) { 474252310Shrs vnodefile = strdup(p + sizeof("file=") - 1); 475252310Shrs p = strchr(vnodefile, ','); 476252310Shrs if (p != NULL) 477252310Shrs *p = '\0'; 478252310Shrs } 479252310Shrs if (vnodefile == NULL) { 480252310Shrs warnx("file option not found for %s", name); 481252310Shrs return (NULL); 482252310Shrs } 483252310Shrs 484252388Sdelphij if (which_prog == SWAPON) { 485252310Shrs if (mdunit == -1) { 486252310Shrs error = run_cmd(&fd, "%s -l -n -f %s", 487252310Shrs _PATH_MDCONFIG, vnodefile); 488252310Shrs if (error == 0) { 489252310Shrs /* md device found. Ignore it. */ 490252310Shrs close(fd); 491252310Shrs if (!qflag) 492252310Shrs warnx("%s: Device already in use", 493252310Shrs vnodefile); 494252514Sdelphij free(vnodefile); 495252310Shrs return (NULL); 496252310Shrs } 497252310Shrs error = run_cmd(&fd, "%s -a -t vnode -n -f %s", 498252310Shrs _PATH_MDCONFIG, vnodefile); 499252310Shrs if (error) { 500252310Shrs warnx("mdconfig (attach) error: file=%s", 501252310Shrs vnodefile); 502252514Sdelphij free(vnodefile); 503252310Shrs return (NULL); 504252310Shrs } 505252310Shrs sfd = fdopen(fd, "r"); 506252310Shrs if (sfd == NULL) { 507252310Shrs warn("mdconfig (attach) fdopen error"); 508252310Shrs ret = NULL; 509252310Shrs goto err; 510252310Shrs } 511252310Shrs p = fgetln(sfd, &linelen); 512252310Shrs if (p == NULL && 513252310Shrs (linelen < 2 || linelen > sizeof(linebuf))) { 514252310Shrs warn("mdconfig (attach) unexpected output"); 515252310Shrs ret = NULL; 516252310Shrs goto err; 517252310Shrs } 518252310Shrs strncpy(linebuf, p, linelen); 519252310Shrs linebuf[linelen - 1] = '\0'; 520252310Shrs errno = 0; 521252310Shrs ul = strtoul(linebuf, &p, 10); 522252310Shrs if (errno == 0) { 523252310Shrs if (*p != '\0' || ul > INT_MAX) 524252310Shrs errno = EINVAL; 525252310Shrs } 526252310Shrs if (errno) { 527252310Shrs warn("mdconfig (attach) unexpected output: %s", 528252310Shrs linebuf); 529252310Shrs ret = NULL; 530252310Shrs goto err; 531252310Shrs } 532252310Shrs mdunit = (int)ul; 533252310Shrs } else { 534252310Shrs error = run_cmd(&fd, "%s -l -n -f %s -u %d", 535252310Shrs _PATH_MDCONFIG, vnodefile, mdunit); 536252310Shrs if (error == 0) { 537252310Shrs /* md device found. Ignore it. */ 538252310Shrs close(fd); 539252310Shrs if (!qflag) 540252310Shrs warnx("md%d on %s: Device already " 541252310Shrs "in use", mdunit, vnodefile); 542252514Sdelphij free(vnodefile); 543252310Shrs return (NULL); 544252310Shrs } 545252310Shrs error = run_cmd(NULL, "%s -a -t vnode -u %d -f %s", 546252310Shrs _PATH_MDCONFIG, mdunit, vnodefile); 547252310Shrs if (error) { 548252310Shrs warnx("mdconfig (attach) error: " 549252310Shrs "md%d on file=%s", mdunit, vnodefile); 550252514Sdelphij free(vnodefile); 551252310Shrs return (NULL); 552252310Shrs } 553252310Shrs } 554252388Sdelphij } else /* SWAPOFF */ { 555252310Shrs if (mdunit == -1) { 556252310Shrs error = run_cmd(&fd, "%s -l -n -f %s", 557252310Shrs _PATH_MDCONFIG, vnodefile); 558252310Shrs if (error) { 559252310Shrs /* md device not found. Ignore it. */ 560252310Shrs close(fd); 561252310Shrs if (!qflag) 562252310Shrs warnx("md on %s: Device not found", 563252310Shrs vnodefile); 564252514Sdelphij free(vnodefile); 565252310Shrs return (NULL); 566252310Shrs } 567252310Shrs sfd = fdopen(fd, "r"); 568252310Shrs if (sfd == NULL) { 569252310Shrs warn("mdconfig (list) fdopen error"); 570252310Shrs ret = NULL; 571252310Shrs goto err; 572252310Shrs } 573252310Shrs p = fgetln(sfd, &linelen); 574252310Shrs if (p == NULL && 575252310Shrs (linelen < 2 || linelen > sizeof(linebuf) - 1)) { 576252310Shrs warn("mdconfig (list) unexpected output"); 577252310Shrs ret = NULL; 578252310Shrs goto err; 579252310Shrs } 580252310Shrs strncpy(linebuf, p, linelen); 581252310Shrs linebuf[linelen - 1] = '\0'; 582252310Shrs p = strchr(linebuf, ' '); 583252310Shrs if (p != NULL) 584252310Shrs *p = '\0'; 585252310Shrs errno = 0; 586252310Shrs ul = strtoul(linebuf, &p, 10); 587252310Shrs if (errno == 0) { 588252310Shrs if (*p != '\0' || ul > INT_MAX) 589252310Shrs errno = EINVAL; 590252310Shrs } 591252310Shrs if (errno) { 592252310Shrs warn("mdconfig (list) unexpected output: %s", 593252310Shrs linebuf); 594252310Shrs ret = NULL; 595252310Shrs goto err; 596252310Shrs } 597252310Shrs mdunit = (int)ul; 598252310Shrs } else { 599252310Shrs error = run_cmd(&fd, "%s -l -n -f %s -u %d", 600252310Shrs _PATH_MDCONFIG, vnodefile, mdunit); 601252310Shrs if (error) { 602252310Shrs /* md device not found. Ignore it. */ 603252310Shrs close(fd); 604252310Shrs if (!qflag) 605252310Shrs warnx("md%d on %s: Device not found", 606252310Shrs mdunit, vnodefile); 607252514Sdelphij free(vnodefile); 608252310Shrs return (NULL); 609252310Shrs } 610252310Shrs } 611252310Shrs } 612252310Shrs snprintf(mdpath, sizeof(mdpath), "%s%s%d", _PATH_DEV, 613252310Shrs MD_NAME, mdunit); 614252310Shrs mdpath[sizeof(mdpath) - 1] = '\0'; 615252310Shrs ret = swap_on_off_sfile(mdpath, doingall); 616252310Shrs 617252388Sdelphij if (which_prog == SWAPOFF) { 618252310Shrs if (ret != NULL) { 619252310Shrs error = run_cmd(NULL, "%s -d -u %d", 620252310Shrs _PATH_MDCONFIG, mdunit); 621252310Shrs if (error) 622252310Shrs warn("mdconfig (detach) detach failed: %s%s%d", 623252310Shrs _PATH_DEV, MD_NAME, mdunit); 624252310Shrs } 625252310Shrs } 626252310Shrserr: 627252310Shrs if (sfd != NULL) 628252310Shrs fclose(sfd); 629252310Shrs if (fd != -1) 630252310Shrs close(fd); 631252514Sdelphij free(vnodefile); 632252310Shrs return (ret); 633252310Shrs} 634252310Shrs 635108375Sdillonstatic int 636252310Shrsrun_cmd(int *ofd, const char *cmdline, ...) 6371558Srgrimes{ 638252310Shrs va_list ap; 639252310Shrs char **argv, **argvp, *cmd, *p; 640252310Shrs int argc, pid, status, rv; 641252310Shrs int pfd[2], nfd, dup2dn; 642252310Shrs 643252310Shrs va_start(ap, cmdline); 644252310Shrs rv = vasprintf(&cmd, cmdline, ap); 645252310Shrs if (rv == -1) { 646252310Shrs warn("%s", __func__); 647252310Shrs return (rv); 648252310Shrs } 649252310Shrs va_end(ap); 650252310Shrs 651252310Shrs for (argc = 1, p = cmd; (p = strchr(p, ' ')) != NULL; p++) 652252310Shrs argc++; 653252310Shrs argv = (char **)malloc(sizeof(*argv) * (argc + 1)); 654252310Shrs for (p = cmd, argvp = argv; (*argvp = strsep(&p, " ")) != NULL;) 655252310Shrs if (**argvp != '\0' && (++argvp > &argv[argc])) { 656252310Shrs *argvp = NULL; 657252310Shrs break; 658252310Shrs } 659252310Shrs /* The argv array ends up NULL-terminated here. */ 660252310Shrs#if 0 661252310Shrs { 662252310Shrs int i; 663252310Shrs 664252310Shrs fprintf(stderr, "DEBUG: running:"); 665252310Shrs /* Should be equivalent to 'cmd' (before strsep, of course). */ 666252310Shrs for (i = 0; argv[i] != NULL; i++) 667252310Shrs fprintf(stderr, " %s", argv[i]); 668252310Shrs fprintf(stderr, "\n"); 669252310Shrs } 670252310Shrs#endif 671252310Shrs dup2dn = 1; 672252310Shrs if (ofd != NULL) { 673252310Shrs if (pipe(&pfd[0]) == -1) { 674252310Shrs warn("%s: pipe", __func__); 675252310Shrs return (-1); 676252310Shrs } 677252310Shrs *ofd = pfd[0]; 678252310Shrs dup2dn = 0; 679252310Shrs } 680252310Shrs pid = fork(); 681252310Shrs switch (pid) { 682252310Shrs case 0: 683252310Shrs /* Child process. */ 684252310Shrs if (ofd != NULL) 685252310Shrs if (dup2(pfd[1], STDOUT_FILENO) < 0) 686252310Shrs err(1, "dup2 in %s", __func__); 687252310Shrs nfd = open(_PATH_DEVNULL, O_RDWR); 688252310Shrs if (nfd == -1) 689252310Shrs err(1, "%s: open %s", __func__, _PATH_DEVNULL); 690252310Shrs if (dup2(nfd, STDIN_FILENO) < 0) 691252310Shrs err(1, "%s: dup2", __func__); 692252310Shrs if (dup2dn && dup2(nfd, STDOUT_FILENO) < 0) 693252310Shrs err(1, "%s: dup2", __func__); 694252310Shrs if (dup2(nfd, STDERR_FILENO) < 0) 695252310Shrs err(1, "%s: dup2", __func__); 696252310Shrs execv(argv[0], argv); 697252310Shrs warn("exec: %s", argv[0]); 698252310Shrs _exit(-1); 699252310Shrs case -1: 700252310Shrs err(1, "%s: fork", __func__); 701252310Shrs } 702252310Shrs free(cmd); 703252310Shrs free(argv); 704252310Shrs while (waitpid(pid, &status, 0) != pid) 705252310Shrs ; 706252310Shrs return (WEXITSTATUS(status)); 707252310Shrs} 708252310Shrs 709252310Shrsstatic const char * 710252388Sdelphijswap_on_off_sfile(const char *name, int doingall) 711252310Shrs{ 712252310Shrs int error; 713252310Shrs 714252388Sdelphij if (which_prog == SWAPON) 715252310Shrs error = swapon(name); 716252388Sdelphij else /* SWAPOFF */ 717252310Shrs error = swapoff(name); 718252388Sdelphij 719252310Shrs if (error == -1) { 7201558Srgrimes switch (errno) { 7211558Srgrimes case EBUSY: 722111424Sdas if (!doingall) 723252310Shrs warnx("%s: Device already in use", name); 7241558Srgrimes break; 725111424Sdas case EINVAL: 726111424Sdas if (which_prog == SWAPON) 727111424Sdas warnx("%s: NSWAPDEV limit reached", name); 728111424Sdas else if (!doingall) 729111424Sdas warn("%s", name); 730111424Sdas break; 7311558Srgrimes default: 73226740Scharnier warn("%s", name); 7331558Srgrimes break; 7341558Srgrimes } 735252310Shrs return (NULL); 7361558Srgrimes } 737252310Shrs return (name); 7381558Srgrimes} 7391558Srgrimes 74026740Scharnierstatic void 741108375Sdillonusage(void) 7421558Srgrimes{ 743108375Sdillon fprintf(stderr, "usage: %s ", getprogname()); 744108375Sdillon switch(orig_prog) { 745141611Sru case SWAPON: 746108375Sdillon case SWAPOFF: 747252310Shrs fprintf(stderr, "[-F fstab] -aLq | file ...\n"); 748108375Sdillon break; 749108375Sdillon case SWAPCTL: 750179154Spjd fprintf(stderr, "[-AghklmsU] [-a file ... | -d file ...]\n"); 751108375Sdillon break; 752108375Sdillon } 7531558Srgrimes exit(1); 7541558Srgrimes} 755107913Sdillon 756108375Sdillonstatic void 757179154Spjdsizetobuf(char *buf, size_t bufsize, int hflag, long long val, int hlen, 758179154Spjd long blocksize) 759179154Spjd{ 760179154Spjd 761179154Spjd if (hflag == 'H') { 762179154Spjd char tmp[16]; 763179154Spjd 764179154Spjd humanize_number(tmp, 5, (int64_t)val, "", HN_AUTOSCALE, 765179154Spjd HN_B | HN_NOSPACE | HN_DECIMAL); 766179154Spjd snprintf(buf, bufsize, "%*s", hlen, tmp); 767179154Spjd } else { 768179154Spjd snprintf(buf, bufsize, "%*lld", hlen, val / blocksize); 769179154Spjd } 770179154Spjd} 771179154Spjd 772179154Spjdstatic void 773108375Sdillonswaplist(int lflag, int sflag, int hflag) 774107913Sdillon{ 775108375Sdillon size_t mibsize, size; 776108375Sdillon struct xswdev xsw; 777108425Smike int hlen, mib[16], n, pagesize; 778108375Sdillon long blocksize; 779108375Sdillon long long total = 0; 780108375Sdillon long long used = 0; 781108375Sdillon long long tmp_total; 782108375Sdillon long long tmp_used; 783179154Spjd char buf[32]; 784108375Sdillon 785108375Sdillon pagesize = getpagesize(); 786108375Sdillon switch(hflag) { 787179154Spjd case 'G': 788179154Spjd blocksize = 1024 * 1024 * 1024; 789179154Spjd strlcpy(buf, "1GB-blocks", sizeof(buf)); 790179154Spjd hlen = 10; 791179154Spjd break; 792179154Spjd case 'H': 793179154Spjd blocksize = -1; 794179154Spjd strlcpy(buf, "Bytes", sizeof(buf)); 795179154Spjd hlen = 10; 796179154Spjd break; 797108375Sdillon case 'K': 798108375Sdillon blocksize = 1024; 799179154Spjd strlcpy(buf, "1kB-blocks", sizeof(buf)); 800108375Sdillon hlen = 10; 801108375Sdillon break; 802108375Sdillon case 'M': 803108375Sdillon blocksize = 1024 * 1024; 804179154Spjd strlcpy(buf, "1MB-blocks", sizeof(buf)); 805108375Sdillon hlen = 10; 806108375Sdillon break; 807108375Sdillon default: 808108459Smike getbsize(&hlen, &blocksize); 809179154Spjd snprintf(buf, sizeof(buf), "%ld-blocks", blocksize); 810108375Sdillon break; 811108375Sdillon } 812108375Sdillon 813108375Sdillon mibsize = sizeof mib / sizeof mib[0]; 814108375Sdillon if (sysctlnametomib("vm.swap_info", mib, &mibsize) == -1) 815108375Sdillon err(1, "sysctlnametomib()"); 816108375Sdillon 817108375Sdillon if (lflag) { 818108375Sdillon printf("%-13s %*s %*s\n", 819108375Sdillon "Device:", 820108375Sdillon hlen, buf, 821108375Sdillon hlen, "Used:"); 822108375Sdillon } 823108375Sdillon 824108375Sdillon for (n = 0; ; ++n) { 825108375Sdillon mib[mibsize] = n; 826108375Sdillon size = sizeof xsw; 827126643Smarkm if (sysctl(mib, mibsize + 1, &xsw, &size, NULL, 0) == -1) 828108375Sdillon break; 829108375Sdillon if (xsw.xsw_version != XSWDEV_VERSION) 830108375Sdillon errx(1, "xswdev version mismatch"); 831108375Sdillon 832179154Spjd tmp_total = (long long)xsw.xsw_nblks * pagesize; 833179154Spjd tmp_used = (long long)xsw.xsw_used * pagesize; 834108375Sdillon total += tmp_total; 835108375Sdillon used += tmp_used; 836108375Sdillon if (lflag) { 837179154Spjd sizetobuf(buf, sizeof(buf), hflag, tmp_total, hlen, 838179154Spjd blocksize); 839179154Spjd printf("/dev/%-8s %s ", devname(xsw.xsw_dev, S_IFCHR), 840179154Spjd buf); 841179154Spjd sizetobuf(buf, sizeof(buf), hflag, tmp_used, hlen, 842179154Spjd blocksize); 843179154Spjd printf("%s\n", buf); 844108375Sdillon } 845108375Sdillon } 846108375Sdillon if (errno != ENOENT) 847108375Sdillon err(1, "sysctl()"); 848108375Sdillon 849108375Sdillon if (sflag) { 850179154Spjd sizetobuf(buf, sizeof(buf), hflag, total, hlen, blocksize); 851179154Spjd printf("Total: %s ", buf); 852179154Spjd sizetobuf(buf, sizeof(buf), hflag, used, hlen, blocksize); 853179154Spjd printf("%s\n", buf); 854108375Sdillon } 855108375Sdillon} 856107913Sdillon 857