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/10/sbin/swapon/swapon.c 316097 2017-03-28 10:43:20Z amdmi3 $"); 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 && 176272960Shrs strstr(fsp->fs_mntops, "late") && 177255265Shrs late == 0) 178252310Shrs continue; 179308886Sjilles if (which_prog == SWAPOFF && 180308886Sjilles strstr(fsp->fs_mntops, "late") == NULL && 181308886Sjilles late != 0) 182308886Sjilles 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{ 223252310Shrs char base[PATH_MAX]; 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 234252388Sdelphij basename_r(name, base); 235252388Sdelphij 236252310Shrs /* Swap on encrypted device by GEOM_BDE. */ 237252388Sdelphij if (fnmatch("*.bde", base, 0) == 0) 238252310Shrs return (swap_on_off_gbde(name, doingall)); 239252310Shrs 240252310Shrs /* Swap on encrypted device by GEOM_ELI. */ 241252388Sdelphij if (fnmatch("*.eli", base, 0) == 0) 242252310Shrs return (swap_on_off_geli(name, mntops, doingall)); 243252310Shrs 244252310Shrs /* Swap on special file. */ 245252310Shrs return (swap_on_off_sfile(name, doingall)); 246252310Shrs} 247252310Shrs 248252388Sdelphij/* Strip off .bde or .eli suffix from swap device name */ 249252388Sdelphijstatic char * 250252388Sdelphijswap_basename(const char *name) 251252310Shrs{ 252252332Shrs char *dname, *p; 253252310Shrs 254252332Shrs dname = strdup(name); 255252332Shrs p = strrchr(dname, '.'); 256252388Sdelphij /* assert(p != NULL); */ 257252310Shrs *p = '\0'; 258252310Shrs 259252388Sdelphij return (dname); 260252388Sdelphij} 261252388Sdelphij 262252388Sdelphijstatic const char * 263252388Sdelphijswap_on_off_gbde(const char *name, int doingall) 264252388Sdelphij{ 265252388Sdelphij const char *ret; 266259820Sjilles char pass[64 * 2 + 1]; 267259820Sjilles unsigned char bpass[64]; 268252388Sdelphij char *dname; 269252388Sdelphij int i, error; 270252388Sdelphij 271252388Sdelphij dname = swap_basename(name); 272252388Sdelphij if (dname == NULL) 273252388Sdelphij return (NULL); 274252388Sdelphij 275252388Sdelphij if (which_prog == SWAPON) { 276252310Shrs arc4random_buf(bpass, sizeof(bpass)); 277252310Shrs for (i = 0; i < (int)sizeof(bpass); i++) 278252310Shrs sprintf(&pass[2 * i], "%02x", bpass[i]); 279252310Shrs pass[sizeof(pass) - 1] = '\0'; 280252310Shrs 281252388Sdelphij error = run_cmd(NULL, "%s init %s -P %s", _PATH_GBDE, 282252332Shrs dname, pass); 283252310Shrs if (error) { 284252310Shrs /* bde device found. Ignore it. */ 285252388Sdelphij free(dname); 286255267Shrs if (qflag == 0) 287252310Shrs warnx("%s: Device already in use", name); 288252310Shrs return (NULL); 289252310Shrs } 290252388Sdelphij error = run_cmd(NULL, "%s attach %s -p %s", _PATH_GBDE, 291252332Shrs dname, pass); 292252388Sdelphij free(dname); 293252310Shrs if (error) { 294252310Shrs warnx("gbde (attach) error: %s", name); 295252310Shrs return (NULL); 296252310Shrs } 297252310Shrs } 298252388Sdelphij 299252310Shrs ret = swap_on_off_sfile(name, doingall); 300252310Shrs 301252388Sdelphij if (which_prog == SWAPOFF) { 302252388Sdelphij error = run_cmd(NULL, "%s detach %s", _PATH_GBDE, dname); 303252388Sdelphij free(dname); 304252310Shrs if (error) { 305252310Shrs /* bde device not found. Ignore it. */ 306255267Shrs if (qflag == 0) 307252388Sdelphij warnx("%s: Device not found", name); 308252310Shrs return (NULL); 309252310Shrs } 310252310Shrs } 311252310Shrs 312252310Shrs return (ret); 313252310Shrs} 314252310Shrs 315252480Sdelphij/* Build geli(8) arguments from mntops */ 316252388Sdelphijstatic char * 317252388Sdelphijswap_on_geli_args(const char *mntops) 318252310Shrs{ 319252388Sdelphij const char *aalgo, *ealgo, *keylen_str, *sectorsize_str; 320252388Sdelphij const char *aflag, *eflag, *lflag, *sflag; 321255267Shrs char *p, *args, *token, *string, *ops; 322296742Sngie int pagesize; 323252388Sdelphij size_t pagesize_len; 324252310Shrs u_long ul; 325252310Shrs 326255267Shrs /* Use built-in defaults for geli(8). */ 327252388Sdelphij aalgo = ealgo = keylen_str = ""; 328252388Sdelphij aflag = eflag = lflag = ""; 329252310Shrs 330255267Shrs /* 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) { 367255267Shrs warn("Invalid sectorsize: %s", 368255267Shrs sectorsize_str); 369252388Sdelphij free(ops); 370252388Sdelphij return (NULL); 371252388Sdelphij } 372316097Samdmi3 } else if (strcmp(token, "late") == 0) { 373316097Samdmi3 /* ignore known option */ 374316097Samdmi3 } else if (strcmp(token, "noauto") == 0) { 375316097Samdmi3 /* ignore known option */ 376252388Sdelphij } else if (strcmp(token, "sw") != 0) { 377252388Sdelphij warnx("Invalid option: %s", token); 378252388Sdelphij free(ops); 379252388Sdelphij return (NULL); 380252388Sdelphij } 381252310Shrs } 382252388Sdelphij } else 383252388Sdelphij ops = NULL; 384252388Sdelphij 385252388Sdelphij /* 386252388Sdelphij * If we do not have a sector size at this point, fill in 387252388Sdelphij * pagesize as sector size. 388252388Sdelphij */ 389252388Sdelphij if (sectorsize_str == NULL) { 390255267Shrs /* Use pagesize as default sectorsize. */ 391252388Sdelphij pagesize = getpagesize(); 392252388Sdelphij pagesize_len = snprintf(NULL, 0, "%d", pagesize) + 1; 393252388Sdelphij p = alloca(pagesize_len); 394252388Sdelphij snprintf(p, pagesize_len, "%d", pagesize); 395252388Sdelphij sectorsize_str = p; 396252310Shrs } 397252388Sdelphij 398296742Sngie (void)asprintf(&args, "%s%s%s%s%s%s%s%s -d", 399252388Sdelphij aflag, aalgo, eflag, ealgo, lflag, keylen_str, 400252388Sdelphij sflag, sectorsize_str); 401252388Sdelphij 402252388Sdelphij free(ops); 403252388Sdelphij return (args); 404252388Sdelphij} 405252388Sdelphij 406252388Sdelphijstatic const char * 407252388Sdelphijswap_on_off_geli(const char *name, char *mntops, int doingall) 408252388Sdelphij{ 409252388Sdelphij struct stat sb; 410255267Shrs char *dname, *args; 411252388Sdelphij int error; 412252388Sdelphij 413252388Sdelphij error = stat(name, &sb); 414252388Sdelphij 415252388Sdelphij if (which_prog == SWAPON) do { 416255267Shrs /* Skip if the .eli device already exists. */ 417252388Sdelphij if (error == 0) 418252388Sdelphij break; 419252388Sdelphij 420252388Sdelphij args = swap_on_geli_args(mntops); 421252388Sdelphij if (args == NULL) 422252310Shrs return (NULL); 423252388Sdelphij 424252388Sdelphij dname = swap_basename(name); 425252388Sdelphij if (dname == NULL) { 426252388Sdelphij free(args); 427252388Sdelphij return (NULL); 428252310Shrs } 429252310Shrs 430252388Sdelphij error = run_cmd(NULL, "%s onetime%s %s", _PATH_GELI, args, 431252332Shrs dname); 432252388Sdelphij 433252388Sdelphij free(dname); 434252388Sdelphij free(args); 435252388Sdelphij 436252310Shrs if (error) { 437255267Shrs /* error occured during creation. */ 438255267Shrs if (qflag == 0) 439252388Sdelphij warnx("%s: Invalid parameters", name); 440252310Shrs return (NULL); 441252310Shrs } 442252388Sdelphij } while (0); 443252310Shrs 444252310Shrs return (swap_on_off_sfile(name, doingall)); 445252310Shrs} 446252310Shrs 447252310Shrsstatic const char * 448252388Sdelphijswap_on_off_md(const char *name, char *mntops, int doingall) 449252310Shrs{ 450252310Shrs FILE *sfd; 451252310Shrs int fd, mdunit, error; 452252310Shrs const char *ret; 453253834Sdelphij static char mdpath[PATH_MAX], linebuf[PATH_MAX]; 454252310Shrs char *p, *vnodefile; 455252310Shrs size_t linelen; 456252310Shrs u_long ul; 457252310Shrs 458252310Shrs fd = -1; 459252310Shrs sfd = NULL; 460252310Shrs if (strlen(name) == (sizeof(MD_NAME) - 1)) 461252310Shrs mdunit = -1; 462252310Shrs else { 463252310Shrs errno = 0; 464252310Shrs ul = strtoul(name + 2, &p, 10); 465252310Shrs if (errno == 0) { 466252310Shrs if (*p != '\0' || ul > INT_MAX) 467252310Shrs errno = EINVAL; 468252310Shrs } 469252310Shrs if (errno) { 470252310Shrs warn("Bad device unit: %s", name); 471252310Shrs return (NULL); 472252310Shrs } 473252310Shrs mdunit = (int)ul; 474252310Shrs } 475252310Shrs 476252310Shrs vnodefile = NULL; 477252310Shrs if ((p = strstr(mntops, "file=")) != NULL) { 478252310Shrs vnodefile = strdup(p + sizeof("file=") - 1); 479252310Shrs p = strchr(vnodefile, ','); 480252310Shrs if (p != NULL) 481252310Shrs *p = '\0'; 482252310Shrs } 483252310Shrs if (vnodefile == NULL) { 484252310Shrs warnx("file option not found for %s", name); 485252310Shrs return (NULL); 486252310Shrs } 487252310Shrs 488252388Sdelphij if (which_prog == SWAPON) { 489252310Shrs if (mdunit == -1) { 490252310Shrs error = run_cmd(&fd, "%s -l -n -f %s", 491252310Shrs _PATH_MDCONFIG, vnodefile); 492252310Shrs if (error == 0) { 493252310Shrs /* md device found. Ignore it. */ 494252310Shrs close(fd); 495252310Shrs if (!qflag) 496252310Shrs warnx("%s: Device already in use", 497252310Shrs vnodefile); 498252514Sdelphij free(vnodefile); 499252310Shrs return (NULL); 500252310Shrs } 501252310Shrs error = run_cmd(&fd, "%s -a -t vnode -n -f %s", 502252310Shrs _PATH_MDCONFIG, vnodefile); 503252310Shrs if (error) { 504252310Shrs warnx("mdconfig (attach) error: file=%s", 505252310Shrs vnodefile); 506252514Sdelphij free(vnodefile); 507252310Shrs return (NULL); 508252310Shrs } 509252310Shrs sfd = fdopen(fd, "r"); 510252310Shrs if (sfd == NULL) { 511252310Shrs warn("mdconfig (attach) fdopen error"); 512252310Shrs ret = NULL; 513252310Shrs goto err; 514252310Shrs } 515252310Shrs p = fgetln(sfd, &linelen); 516252310Shrs if (p == NULL && 517252310Shrs (linelen < 2 || linelen > sizeof(linebuf))) { 518252310Shrs warn("mdconfig (attach) unexpected output"); 519252310Shrs ret = NULL; 520252310Shrs goto err; 521252310Shrs } 522252310Shrs strncpy(linebuf, p, linelen); 523252310Shrs linebuf[linelen - 1] = '\0'; 524252310Shrs errno = 0; 525252310Shrs ul = strtoul(linebuf, &p, 10); 526252310Shrs if (errno == 0) { 527252310Shrs if (*p != '\0' || ul > INT_MAX) 528252310Shrs errno = EINVAL; 529252310Shrs } 530252310Shrs if (errno) { 531252310Shrs warn("mdconfig (attach) unexpected output: %s", 532252310Shrs linebuf); 533252310Shrs ret = NULL; 534252310Shrs goto err; 535252310Shrs } 536252310Shrs mdunit = (int)ul; 537252310Shrs } else { 538252310Shrs error = run_cmd(&fd, "%s -l -n -f %s -u %d", 539252310Shrs _PATH_MDCONFIG, vnodefile, mdunit); 540252310Shrs if (error == 0) { 541252310Shrs /* md device found. Ignore it. */ 542252310Shrs close(fd); 543255267Shrs if (qflag == 0) 544252310Shrs warnx("md%d on %s: Device already " 545252310Shrs "in use", mdunit, vnodefile); 546252514Sdelphij free(vnodefile); 547252310Shrs return (NULL); 548252310Shrs } 549252310Shrs error = run_cmd(NULL, "%s -a -t vnode -u %d -f %s", 550252310Shrs _PATH_MDCONFIG, mdunit, vnodefile); 551252310Shrs if (error) { 552252310Shrs warnx("mdconfig (attach) error: " 553252310Shrs "md%d on file=%s", mdunit, vnodefile); 554252514Sdelphij free(vnodefile); 555252310Shrs return (NULL); 556252310Shrs } 557252310Shrs } 558252388Sdelphij } else /* SWAPOFF */ { 559252310Shrs if (mdunit == -1) { 560252310Shrs error = run_cmd(&fd, "%s -l -n -f %s", 561252310Shrs _PATH_MDCONFIG, vnodefile); 562252310Shrs if (error) { 563252310Shrs /* md device not found. Ignore it. */ 564252310Shrs close(fd); 565252310Shrs if (!qflag) 566252310Shrs warnx("md on %s: Device not found", 567252310Shrs vnodefile); 568252514Sdelphij free(vnodefile); 569252310Shrs return (NULL); 570252310Shrs } 571252310Shrs sfd = fdopen(fd, "r"); 572252310Shrs if (sfd == NULL) { 573252310Shrs warn("mdconfig (list) fdopen error"); 574252310Shrs ret = NULL; 575252310Shrs goto err; 576252310Shrs } 577252310Shrs p = fgetln(sfd, &linelen); 578252310Shrs if (p == NULL && 579252310Shrs (linelen < 2 || linelen > sizeof(linebuf) - 1)) { 580252310Shrs warn("mdconfig (list) unexpected output"); 581252310Shrs ret = NULL; 582252310Shrs goto err; 583252310Shrs } 584252310Shrs strncpy(linebuf, p, linelen); 585252310Shrs linebuf[linelen - 1] = '\0'; 586252310Shrs p = strchr(linebuf, ' '); 587252310Shrs if (p != NULL) 588252310Shrs *p = '\0'; 589252310Shrs errno = 0; 590252310Shrs ul = strtoul(linebuf, &p, 10); 591252310Shrs if (errno == 0) { 592252310Shrs if (*p != '\0' || ul > INT_MAX) 593252310Shrs errno = EINVAL; 594252310Shrs } 595252310Shrs if (errno) { 596252310Shrs warn("mdconfig (list) unexpected output: %s", 597252310Shrs linebuf); 598252310Shrs ret = NULL; 599252310Shrs goto err; 600252310Shrs } 601252310Shrs mdunit = (int)ul; 602252310Shrs } else { 603252310Shrs error = run_cmd(&fd, "%s -l -n -f %s -u %d", 604252310Shrs _PATH_MDCONFIG, vnodefile, mdunit); 605252310Shrs if (error) { 606252310Shrs /* md device not found. Ignore it. */ 607252310Shrs close(fd); 608252310Shrs if (!qflag) 609252310Shrs warnx("md%d on %s: Device not found", 610252310Shrs mdunit, vnodefile); 611252514Sdelphij free(vnodefile); 612252310Shrs return (NULL); 613252310Shrs } 614252310Shrs } 615252310Shrs } 616252310Shrs snprintf(mdpath, sizeof(mdpath), "%s%s%d", _PATH_DEV, 617252310Shrs MD_NAME, mdunit); 618252310Shrs mdpath[sizeof(mdpath) - 1] = '\0'; 619252310Shrs ret = swap_on_off_sfile(mdpath, doingall); 620252310Shrs 621252388Sdelphij if (which_prog == SWAPOFF) { 622252310Shrs if (ret != NULL) { 623252310Shrs error = run_cmd(NULL, "%s -d -u %d", 624252310Shrs _PATH_MDCONFIG, mdunit); 625252310Shrs if (error) 626252310Shrs warn("mdconfig (detach) detach failed: %s%s%d", 627252310Shrs _PATH_DEV, MD_NAME, mdunit); 628252310Shrs } 629252310Shrs } 630252310Shrserr: 631252310Shrs if (sfd != NULL) 632252310Shrs fclose(sfd); 633252310Shrs if (fd != -1) 634252310Shrs close(fd); 635252514Sdelphij free(vnodefile); 636252310Shrs return (ret); 637252310Shrs} 638252310Shrs 639108375Sdillonstatic int 640252310Shrsrun_cmd(int *ofd, const char *cmdline, ...) 6411558Srgrimes{ 642252310Shrs va_list ap; 643252310Shrs char **argv, **argvp, *cmd, *p; 644252310Shrs int argc, pid, status, rv; 645252310Shrs int pfd[2], nfd, dup2dn; 646252310Shrs 647252310Shrs va_start(ap, cmdline); 648252310Shrs rv = vasprintf(&cmd, cmdline, ap); 649252310Shrs if (rv == -1) { 650252310Shrs warn("%s", __func__); 651292311Sngie va_end(ap); 652252310Shrs return (rv); 653252310Shrs } 654252310Shrs va_end(ap); 655252310Shrs 656252310Shrs for (argc = 1, p = cmd; (p = strchr(p, ' ')) != NULL; p++) 657252310Shrs argc++; 658252310Shrs argv = (char **)malloc(sizeof(*argv) * (argc + 1)); 659252310Shrs for (p = cmd, argvp = argv; (*argvp = strsep(&p, " ")) != NULL;) 660252310Shrs if (**argvp != '\0' && (++argvp > &argv[argc])) { 661252310Shrs *argvp = NULL; 662252310Shrs break; 663252310Shrs } 664252310Shrs /* The argv array ends up NULL-terminated here. */ 665252310Shrs#if 0 666252310Shrs { 667252310Shrs int i; 668252310Shrs 669252310Shrs fprintf(stderr, "DEBUG: running:"); 670252310Shrs /* Should be equivalent to 'cmd' (before strsep, of course). */ 671252310Shrs for (i = 0; argv[i] != NULL; i++) 672252310Shrs fprintf(stderr, " %s", argv[i]); 673252310Shrs fprintf(stderr, "\n"); 674252310Shrs } 675252310Shrs#endif 676252310Shrs dup2dn = 1; 677252310Shrs if (ofd != NULL) { 678252310Shrs if (pipe(&pfd[0]) == -1) { 679252310Shrs warn("%s: pipe", __func__); 680252310Shrs return (-1); 681252310Shrs } 682252310Shrs *ofd = pfd[0]; 683252310Shrs dup2dn = 0; 684252310Shrs } 685252310Shrs pid = fork(); 686252310Shrs switch (pid) { 687252310Shrs case 0: 688252310Shrs /* Child process. */ 689252310Shrs if (ofd != NULL) 690252310Shrs if (dup2(pfd[1], STDOUT_FILENO) < 0) 691252310Shrs err(1, "dup2 in %s", __func__); 692252310Shrs nfd = open(_PATH_DEVNULL, O_RDWR); 693252310Shrs if (nfd == -1) 694252310Shrs err(1, "%s: open %s", __func__, _PATH_DEVNULL); 695252310Shrs if (dup2(nfd, STDIN_FILENO) < 0) 696252310Shrs err(1, "%s: dup2", __func__); 697252310Shrs if (dup2dn && dup2(nfd, STDOUT_FILENO) < 0) 698252310Shrs err(1, "%s: dup2", __func__); 699252310Shrs if (dup2(nfd, STDERR_FILENO) < 0) 700252310Shrs err(1, "%s: dup2", __func__); 701252310Shrs execv(argv[0], argv); 702252310Shrs warn("exec: %s", argv[0]); 703252310Shrs _exit(-1); 704252310Shrs case -1: 705252310Shrs err(1, "%s: fork", __func__); 706252310Shrs } 707252310Shrs free(cmd); 708252310Shrs free(argv); 709252310Shrs while (waitpid(pid, &status, 0) != pid) 710252310Shrs ; 711252310Shrs return (WEXITSTATUS(status)); 712252310Shrs} 713252310Shrs 714252310Shrsstatic const char * 715252388Sdelphijswap_on_off_sfile(const char *name, int doingall) 716252310Shrs{ 717252310Shrs int error; 718252310Shrs 719252388Sdelphij if (which_prog == SWAPON) 720252310Shrs error = swapon(name); 721252388Sdelphij else /* SWAPOFF */ 722252310Shrs error = swapoff(name); 723252388Sdelphij 724252310Shrs if (error == -1) { 7251558Srgrimes switch (errno) { 7261558Srgrimes case EBUSY: 727255267Shrs if (doingall == 0) 728252310Shrs warnx("%s: Device already in use", name); 7291558Srgrimes break; 730111424Sdas case EINVAL: 731111424Sdas if (which_prog == SWAPON) 732111424Sdas warnx("%s: NSWAPDEV limit reached", name); 733255267Shrs else if (doingall == 0) 734111424Sdas warn("%s", name); 735111424Sdas break; 7361558Srgrimes default: 73726740Scharnier warn("%s", name); 7381558Srgrimes break; 7391558Srgrimes } 740252310Shrs return (NULL); 7411558Srgrimes } 742252310Shrs return (name); 7431558Srgrimes} 7441558Srgrimes 74526740Scharnierstatic void 746108375Sdillonusage(void) 7471558Srgrimes{ 748255267Shrs 749108375Sdillon fprintf(stderr, "usage: %s ", getprogname()); 750108375Sdillon switch(orig_prog) { 751141611Sru case SWAPON: 752108375Sdillon case SWAPOFF: 753252310Shrs fprintf(stderr, "[-F fstab] -aLq | file ...\n"); 754108375Sdillon break; 755108375Sdillon case SWAPCTL: 756179154Spjd fprintf(stderr, "[-AghklmsU] [-a file ... | -d file ...]\n"); 757108375Sdillon break; 758108375Sdillon } 7591558Srgrimes exit(1); 7601558Srgrimes} 761107913Sdillon 762108375Sdillonstatic void 763179154Spjdsizetobuf(char *buf, size_t bufsize, int hflag, long long val, int hlen, 764179154Spjd long blocksize) 765179154Spjd{ 766255267Shrs char tmp[16]; 767179154Spjd 768179154Spjd if (hflag == 'H') { 769179154Spjd humanize_number(tmp, 5, (int64_t)val, "", HN_AUTOSCALE, 770179154Spjd HN_B | HN_NOSPACE | HN_DECIMAL); 771179154Spjd snprintf(buf, bufsize, "%*s", hlen, tmp); 772255267Shrs } else 773179154Spjd snprintf(buf, bufsize, "%*lld", hlen, val / blocksize); 774179154Spjd} 775179154Spjd 776179154Spjdstatic void 777108375Sdillonswaplist(int lflag, int sflag, int hflag) 778107913Sdillon{ 779108375Sdillon size_t mibsize, size; 780108375Sdillon struct xswdev xsw; 781108425Smike int hlen, mib[16], n, pagesize; 782108375Sdillon long blocksize; 783108375Sdillon long long total = 0; 784108375Sdillon long long used = 0; 785108375Sdillon long long tmp_total; 786108375Sdillon long long tmp_used; 787179154Spjd char buf[32]; 788108375Sdillon 789108375Sdillon pagesize = getpagesize(); 790108375Sdillon switch(hflag) { 791179154Spjd case 'G': 792255267Shrs blocksize = 1024 * 1024 * 1024; 793255267Shrs strlcpy(buf, "1GB-blocks", sizeof(buf)); 794255267Shrs hlen = 10; 795255267Shrs break; 796179154Spjd case 'H': 797255267Shrs blocksize = -1; 798255267Shrs strlcpy(buf, "Bytes", sizeof(buf)); 799255267Shrs hlen = 10; 800255267Shrs break; 801108375Sdillon case 'K': 802255267Shrs blocksize = 1024; 803255267Shrs strlcpy(buf, "1kB-blocks", sizeof(buf)); 804255267Shrs hlen = 10; 805255267Shrs break; 806108375Sdillon case 'M': 807255267Shrs blocksize = 1024 * 1024; 808255267Shrs strlcpy(buf, "1MB-blocks", sizeof(buf)); 809255267Shrs hlen = 10; 810255267Shrs break; 811108375Sdillon default: 812255267Shrs getbsize(&hlen, &blocksize); 813255267Shrs snprintf(buf, sizeof(buf), "%ld-blocks", blocksize); 814255267Shrs break; 815108375Sdillon } 816108375Sdillon 817255267Shrs mibsize = nitems(mib); 818108375Sdillon if (sysctlnametomib("vm.swap_info", mib, &mibsize) == -1) 819108375Sdillon err(1, "sysctlnametomib()"); 820108375Sdillon 821108375Sdillon if (lflag) { 822108375Sdillon printf("%-13s %*s %*s\n", 823108375Sdillon "Device:", 824108375Sdillon hlen, buf, 825108375Sdillon hlen, "Used:"); 826108375Sdillon } 827108375Sdillon 828108375Sdillon for (n = 0; ; ++n) { 829108375Sdillon mib[mibsize] = n; 830108375Sdillon size = sizeof xsw; 831126643Smarkm if (sysctl(mib, mibsize + 1, &xsw, &size, NULL, 0) == -1) 832108375Sdillon break; 833108375Sdillon if (xsw.xsw_version != XSWDEV_VERSION) 834108375Sdillon errx(1, "xswdev version mismatch"); 835108375Sdillon 836179154Spjd tmp_total = (long long)xsw.xsw_nblks * pagesize; 837179154Spjd tmp_used = (long long)xsw.xsw_used * pagesize; 838108375Sdillon total += tmp_total; 839108375Sdillon used += tmp_used; 840108375Sdillon if (lflag) { 841179154Spjd sizetobuf(buf, sizeof(buf), hflag, tmp_total, hlen, 842179154Spjd blocksize); 843179154Spjd printf("/dev/%-8s %s ", devname(xsw.xsw_dev, S_IFCHR), 844179154Spjd buf); 845179154Spjd sizetobuf(buf, sizeof(buf), hflag, tmp_used, hlen, 846179154Spjd blocksize); 847179154Spjd printf("%s\n", buf); 848108375Sdillon } 849108375Sdillon } 850108375Sdillon if (errno != ENOENT) 851108375Sdillon err(1, "sysctl()"); 852108375Sdillon 853108375Sdillon if (sflag) { 854179154Spjd sizetobuf(buf, sizeof(buf), hflag, total, hlen, blocksize); 855179154Spjd printf("Total: %s ", buf); 856179154Spjd sizetobuf(buf, sizeof(buf), hflag, used, hlen, blocksize); 857179154Spjd printf("%s\n", buf); 858108375Sdillon } 859108375Sdillon} 860107913Sdillon 861