1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1980, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/param.h> 33 #include <sys/disk.h> 34 #include <sys/disklabel.h> 35 #include <sys/mdioctl.h> 36 #include <sys/stat.h> 37 #include <sys/sysctl.h> 38 #include <sys/wait.h> 39 #include <vm/vm_param.h> 40 #include <vm/swap_pager.h> 41 42 #include <err.h> 43 #include <errno.h> 44 #include <fcntl.h> 45 #include <fnmatch.h> 46 #include <fstab.h> 47 #include <libgen.h> 48 #include <libutil.h> 49 #include <limits.h> 50 #include <paths.h> 51 #include <stdarg.h> 52 #include <stdio.h> 53 #include <stdlib.h> 54 #include <string.h> 55 #include <unistd.h> 56 57 #define DOT_ELI ".eli" 58 59 static void usage(void) __dead2; 60 static const char *swap_on_off(const char *, int, char *); 61 static const char *swap_on_off_geli(const char *, char *, int); 62 static const char *swap_on_off_md(const char *, char *, int); 63 static const char *swap_on_off_sfile(const char *, int); 64 static void swaplist(int, int, int); 65 static int run_cmd(int *, const char *, ...) __printflike(2, 3); 66 67 static enum { SWAPON, SWAPOFF, SWAPCTL } orig_prog, which_prog = SWAPCTL; 68 69 static int Eflag, fflag, qflag; 70 71 int 72 main(int argc, char **argv) 73 { 74 struct fstab *fsp; 75 const char *swfile; 76 char *ptr; 77 int ret, ch, doall; 78 int sflag, lflag, late, hflag; 79 const char *etc_fstab; 80 81 sflag = lflag = late = hflag = 0; 82 if ((ptr = strrchr(argv[0], '/')) == NULL) 83 ptr = argv[0]; 84 if (strstr(ptr, "swapon") != NULL) 85 which_prog = SWAPON; 86 else if (strstr(ptr, "swapoff") != NULL) 87 which_prog = SWAPOFF; 88 orig_prog = which_prog; 89 90 doall = 0; 91 etc_fstab = NULL; 92 while ((ch = getopt(argc, argv, "AadEfghklLmqsUF:")) != -1) { 93 switch(ch) { 94 case 'A': 95 if (which_prog == SWAPCTL) { 96 doall = 1; 97 which_prog = SWAPON; 98 } else 99 usage(); 100 break; 101 case 'a': 102 if (which_prog == SWAPON || which_prog == SWAPOFF) 103 doall = 1; 104 else 105 which_prog = SWAPON; 106 break; 107 case 'd': 108 if (which_prog == SWAPCTL) 109 which_prog = SWAPOFF; 110 else 111 usage(); 112 break; 113 case 'E': 114 if (which_prog == SWAPON) 115 Eflag = 2; 116 else 117 usage(); 118 break; 119 case 'f': 120 if (which_prog == SWAPOFF) 121 fflag = 1; 122 else 123 usage(); 124 break; 125 case 'g': 126 hflag = 'G'; 127 break; 128 case 'h': 129 hflag = 'H'; 130 break; 131 case 'k': 132 hflag = 'K'; 133 break; 134 case 'l': 135 lflag = 1; 136 break; 137 case 'L': 138 late = 1; 139 break; 140 case 'm': 141 hflag = 'M'; 142 break; 143 case 'q': 144 if (which_prog == SWAPON || which_prog == SWAPOFF) 145 qflag = 1; 146 break; 147 case 's': 148 sflag = 1; 149 break; 150 case 'U': 151 if (which_prog == SWAPCTL) { 152 doall = 1; 153 which_prog = SWAPOFF; 154 } else 155 usage(); 156 break; 157 case 'F': 158 etc_fstab = optarg; 159 break; 160 case '?': 161 default: 162 usage(); 163 } 164 } 165 argv += optind; 166 167 ret = 0; 168 swfile = NULL; 169 if (etc_fstab != NULL) 170 setfstab(etc_fstab); 171 if (which_prog == SWAPON || which_prog == SWAPOFF) { 172 if (doall) { 173 while ((fsp = getfsent()) != NULL) { 174 if (strcmp(fsp->fs_type, FSTAB_SW) != 0) 175 continue; 176 if (strstr(fsp->fs_mntops, "noauto") != NULL) 177 continue; 178 if (which_prog != SWAPOFF && 179 strstr(fsp->fs_mntops, "late") && 180 late == 0) 181 continue; 182 if (which_prog == SWAPOFF && 183 strstr(fsp->fs_mntops, "late") == NULL && 184 late != 0) 185 continue; 186 Eflag |= (strstr(fsp->fs_mntops, "trimonce") != NULL); 187 swfile = swap_on_off(fsp->fs_spec, 1, 188 fsp->fs_mntops); 189 Eflag &= ~1; 190 if (swfile == NULL) { 191 ret = 1; 192 continue; 193 } 194 if (qflag == 0) { 195 printf("%s: %sing %s as swap device\n", 196 getprogname(), 197 (which_prog == SWAPOFF) ? 198 "remov" : "add", swfile); 199 } 200 } 201 } else if (*argv == NULL) 202 usage(); 203 for (; *argv; ++argv) { 204 swfile = swap_on_off(*argv, 0, NULL); 205 if (swfile == NULL) { 206 ret = 1; 207 continue; 208 } 209 if (orig_prog == SWAPCTL) { 210 printf("%s: %sing %s as swap device\n", 211 getprogname(), 212 (which_prog == SWAPOFF) ? "remov" : "add", 213 swfile); 214 } 215 } 216 } else { 217 if (lflag || sflag) 218 swaplist(lflag, sflag, hflag); 219 else 220 usage(); 221 } 222 exit(ret); 223 } 224 225 static const char * 226 swap_on_off(const char *name, int doingall, char *mntops) 227 { 228 char *base, *basebuf; 229 230 /* Swap on vnode-backed md(4) device. */ 231 if (mntops != NULL && 232 (fnmatch(_PATH_DEV MD_NAME "[0-9]*", name, 0) == 0 || 233 fnmatch(MD_NAME "[0-9]*", name, 0) == 0 || 234 strncmp(_PATH_DEV MD_NAME, name, 235 sizeof(_PATH_DEV MD_NAME)) == 0 || 236 strncmp(MD_NAME, name, sizeof(MD_NAME)) == 0 || 237 strncmp(_PATH_DEV MD_NAME DOT_ELI, name, 238 sizeof(_PATH_DEV MD_NAME DOT_ELI)) == 0 || 239 strncmp(MD_NAME DOT_ELI, name, sizeof(MD_NAME DOT_ELI)) == 0)) 240 return (swap_on_off_md(name, mntops, doingall)); 241 242 basebuf = strdup(name); 243 base = basename(basebuf); 244 245 /* Swap on encrypted device by GEOM_ELI. */ 246 if (fnmatch("*" DOT_ELI, base, 0) == 0) { 247 free(basebuf); 248 return (swap_on_off_geli(name, mntops, doingall)); 249 } 250 251 /* Swap on special file. */ 252 free(basebuf); 253 return (swap_on_off_sfile(name, doingall)); 254 } 255 256 /* Strip off .bde or .eli suffix from swap device name */ 257 static char * 258 swap_basename(const char *name) 259 { 260 char *dname, *p; 261 262 dname = strdup(name); 263 p = strrchr(dname, '.'); 264 /* assert(p != NULL); */ 265 *p = '\0'; 266 267 return (dname); 268 } 269 270 /* Build geli(8) arguments from mntops */ 271 static char * 272 swap_on_geli_args(const char *mntops) 273 { 274 const char *aalgo, *ealgo, *keylen_str, *sectorsize_str; 275 const char *aflag, *eflag, *lflag, *Tflag, *sflag; 276 char *p, *args, *token, *string, *ops; 277 int pagesize; 278 size_t pagesize_len; 279 u_long ul; 280 281 /* Use built-in defaults for geli(8). */ 282 aalgo = ealgo = keylen_str = ""; 283 aflag = eflag = lflag = Tflag = ""; 284 285 /* We will always specify sectorsize. */ 286 sflag = " -s "; 287 sectorsize_str = NULL; 288 289 if (mntops != NULL) { 290 string = ops = strdup(mntops); 291 292 while ((token = strsep(&string, ",")) != NULL) { 293 if ((p = strstr(token, "aalgo=")) == token) { 294 aalgo = p + sizeof("aalgo=") - 1; 295 aflag = " -a "; 296 } else if ((p = strstr(token, "ealgo=")) == token) { 297 ealgo = p + sizeof("ealgo=") - 1; 298 eflag = " -e "; 299 } else if ((p = strstr(token, "keylen=")) == token) { 300 keylen_str = p + sizeof("keylen=") - 1; 301 errno = 0; 302 ul = strtoul(keylen_str, &p, 10); 303 if (errno == 0) { 304 if (*p != '\0' || ul > INT_MAX) 305 errno = EINVAL; 306 } 307 if (errno) { 308 warn("Invalid keylen: %s", keylen_str); 309 free(ops); 310 return (NULL); 311 } 312 lflag = " -l "; 313 } else if ((p = strstr(token, "sectorsize=")) == token) { 314 sectorsize_str = p + sizeof("sectorsize=") - 1; 315 errno = 0; 316 ul = strtoul(sectorsize_str, &p, 10); 317 if (errno == 0) { 318 if (*p != '\0' || ul > INT_MAX) 319 errno = EINVAL; 320 } 321 if (errno) { 322 warn("Invalid sectorsize: %s", 323 sectorsize_str); 324 free(ops); 325 return (NULL); 326 } 327 } else if (strcmp(token, "notrim") == 0) { 328 if (Eflag) { 329 warn("Options \"notrim\" and " 330 "\"trimonce\" conflict"); 331 free(ops); 332 return (NULL); 333 } 334 Tflag = " -T "; 335 } else if ((p = strstr(token, "file=")) == token) { 336 /* ignore known option */ 337 } else if (strcmp(token, "late") == 0) { 338 /* ignore known option */ 339 } else if (strcmp(token, "noauto") == 0) { 340 /* ignore known option */ 341 } else if (strcmp(token, "sw") == 0) { 342 /* ignore known option */ 343 } else if (strcmp(token, "trimonce") == 0) { 344 /* ignore known option */ 345 } else { 346 warnx("Invalid option: %s", token); 347 free(ops); 348 return (NULL); 349 } 350 } 351 } else 352 ops = NULL; 353 354 /* 355 * If we do not have a sector size at this point, fill in 356 * pagesize as sector size. 357 */ 358 if (sectorsize_str == NULL) { 359 /* Use pagesize as default sectorsize. */ 360 pagesize = getpagesize(); 361 pagesize_len = snprintf(NULL, 0, "%d", pagesize) + 1; 362 p = alloca(pagesize_len); 363 snprintf(p, pagesize_len, "%d", pagesize); 364 sectorsize_str = p; 365 } 366 367 (void)asprintf(&args, "%s%s%s%s%s%s%s%s%s -d", 368 aflag, aalgo, eflag, ealgo, lflag, keylen_str, Tflag, 369 sflag, sectorsize_str); 370 371 free(ops); 372 return (args); 373 } 374 375 static const char * 376 swap_on_off_geli(const char *name, char *mntops, int doingall) 377 { 378 struct stat sb; 379 char *dname, *args; 380 int error; 381 382 error = stat(name, &sb); 383 384 if (which_prog == SWAPON) do { 385 /* Skip if the .eli device already exists. */ 386 if (error == 0) 387 break; 388 389 args = swap_on_geli_args(mntops); 390 if (args == NULL) 391 return (NULL); 392 393 dname = swap_basename(name); 394 if (dname == NULL) { 395 free(args); 396 return (NULL); 397 } 398 399 error = run_cmd(NULL, "%s onetime%s %s", _PATH_GELI, args, 400 dname); 401 402 free(dname); 403 free(args); 404 405 if (error) { 406 /* error occurred during creation. */ 407 if (qflag == 0) 408 warnx("%s: Invalid parameters", name); 409 return (NULL); 410 } 411 } while (0); 412 413 return (swap_on_off_sfile(name, doingall)); 414 } 415 416 static const char * 417 swap_on_off_md(const char *name, char *mntops, int doingall) 418 { 419 FILE *sfd; 420 int fd, mdunit, error; 421 const char *ret; 422 static char mdpath[PATH_MAX], linebuf[PATH_MAX]; 423 char *p, *vnodefile; 424 size_t linelen; 425 u_long ul; 426 const char *suffix; 427 char *devbuf, *dname; 428 int name_len; 429 430 fd = -1; 431 sfd = NULL; 432 devbuf = strdup(name); 433 name_len = strlen(name) - strlen(DOT_ELI); 434 if (name_len > 0 && strcmp(suffix = &name[name_len], DOT_ELI) == 0) { 435 suffix++; 436 devbuf[name_len] = '\0'; 437 } else 438 suffix = NULL; 439 /* dname will be name without /dev/ prefix and .eli suffix */ 440 dname = basename(devbuf); 441 if (strlen(dname) == (sizeof(MD_NAME) - 1)) 442 mdunit = -1; 443 else { 444 errno = 0; 445 ul = strtoul(dname + 2, &p, 10); 446 if (errno == 0) { 447 if (*p != '\0' || ul > INT_MAX) 448 errno = EINVAL; 449 } 450 if (errno) { 451 warn("Bad device unit: %s", dname); 452 free(devbuf); 453 return (NULL); 454 } 455 mdunit = (int)ul; 456 } 457 free(devbuf); 458 459 vnodefile = NULL; 460 if ((p = strstr(mntops, "file=")) != NULL) { 461 vnodefile = strdup(p + sizeof("file=") - 1); 462 p = strchr(vnodefile, ','); 463 if (p != NULL) 464 *p = '\0'; 465 } 466 if (vnodefile == NULL) { 467 warnx("file option not found for %s", name); 468 return (NULL); 469 } 470 471 if (which_prog == SWAPON) { 472 if (mdunit == -1) { 473 error = run_cmd(&fd, "%s -l -n -f %s", 474 _PATH_MDCONFIG, vnodefile); 475 if (error == 0) { 476 /* md device found. Ignore it. */ 477 close(fd); 478 if (!qflag) 479 warnx("%s: Device already in use", 480 vnodefile); 481 free(vnodefile); 482 return (NULL); 483 } 484 error = run_cmd(&fd, "%s -a -t vnode -n -f %s", 485 _PATH_MDCONFIG, vnodefile); 486 if (error) { 487 warnx("mdconfig (attach) error: file=%s", 488 vnodefile); 489 free(vnodefile); 490 return (NULL); 491 } 492 sfd = fdopen(fd, "r"); 493 if (sfd == NULL) { 494 warn("mdconfig (attach) fdopen error"); 495 ret = NULL; 496 goto err; 497 } 498 p = fgetln(sfd, &linelen); 499 if (p == NULL || 500 (linelen < 2 || linelen > sizeof(linebuf))) { 501 warn("mdconfig (attach) unexpected output"); 502 ret = NULL; 503 goto err; 504 } 505 strlcpy(linebuf, p, linelen); 506 errno = 0; 507 ul = strtoul(linebuf, &p, 10); 508 if (errno == 0) { 509 if (*p != '\0' || ul > INT_MAX) 510 errno = EINVAL; 511 } 512 if (errno) { 513 warn("mdconfig (attach) unexpected output: %s", 514 linebuf); 515 ret = NULL; 516 goto err; 517 } 518 mdunit = (int)ul; 519 } else { 520 error = run_cmd(&fd, "%s -l -n -f %s -u %d", 521 _PATH_MDCONFIG, vnodefile, mdunit); 522 if (error == 0) { 523 /* md device found. Ignore it. */ 524 close(fd); 525 if (qflag == 0) 526 warnx("md%d on %s: Device already " 527 "in use", mdunit, vnodefile); 528 free(vnodefile); 529 return (NULL); 530 } 531 error = run_cmd(NULL, "%s -a -t vnode -u %d -f %s", 532 _PATH_MDCONFIG, mdunit, vnodefile); 533 if (error) { 534 warnx("mdconfig (attach) error: " 535 "md%d on file=%s", mdunit, vnodefile); 536 free(vnodefile); 537 return (NULL); 538 } 539 } 540 } else /* SWAPOFF */ { 541 if (mdunit == -1) { 542 error = run_cmd(&fd, "%s -l -n -f %s", 543 _PATH_MDCONFIG, vnodefile); 544 if (error) { 545 /* md device not found. Ignore it. */ 546 close(fd); 547 if (!qflag) 548 warnx("md on %s: Device not found", 549 vnodefile); 550 free(vnodefile); 551 return (NULL); 552 } 553 sfd = fdopen(fd, "r"); 554 if (sfd == NULL) { 555 warn("mdconfig (list) fdopen error"); 556 ret = NULL; 557 goto err; 558 } 559 p = fgetln(sfd, &linelen); 560 if (p == NULL || 561 (linelen < 2 || linelen > sizeof(linebuf))) { 562 warn("mdconfig (list) unexpected output"); 563 ret = NULL; 564 goto err; 565 } 566 strlcpy(linebuf, p, linelen); 567 p = strchr(linebuf, ' '); 568 if (p != NULL) 569 *p = '\0'; 570 errno = 0; 571 ul = strtoul(linebuf, &p, 10); 572 if (errno == 0) { 573 if (*p != '\0' || ul > INT_MAX) 574 errno = EINVAL; 575 } 576 if (errno) { 577 warn("mdconfig (list) unexpected output: %s", 578 linebuf); 579 ret = NULL; 580 goto err; 581 } 582 mdunit = (int)ul; 583 } else { 584 error = run_cmd(&fd, "%s -l -n -f %s -u %d", 585 _PATH_MDCONFIG, vnodefile, mdunit); 586 if (error) { 587 /* md device not found. Ignore it. */ 588 close(fd); 589 if (!qflag) 590 warnx("md%d on %s: Device not found", 591 mdunit, vnodefile); 592 free(vnodefile); 593 return (NULL); 594 } 595 } 596 } 597 598 if (suffix != NULL && strcmp("eli", suffix) == 0) { 599 /* Swap on encrypted device by GEOM_ELI. */ 600 snprintf(mdpath, sizeof(mdpath), "%s%s%d" DOT_ELI, _PATH_DEV, 601 MD_NAME, mdunit); 602 mdpath[sizeof(mdpath) - 1] = '\0'; 603 ret = swap_on_off_geli(mdpath, mntops, doingall); 604 } else { 605 snprintf(mdpath, sizeof(mdpath), "%s%s%d", _PATH_DEV, 606 MD_NAME, mdunit); 607 mdpath[sizeof(mdpath) - 1] = '\0'; 608 ret = swap_on_off_sfile(mdpath, doingall); 609 } 610 611 if (which_prog == SWAPOFF) { 612 if (ret != NULL) { 613 error = run_cmd(NULL, "%s -d -u %d", 614 _PATH_MDCONFIG, mdunit); 615 if (error) 616 warn("mdconfig (detach) detach failed: %s%s%d", 617 _PATH_DEV, MD_NAME, mdunit); 618 } 619 } 620 err: 621 if (sfd != NULL) 622 fclose(sfd); 623 if (fd != -1) 624 close(fd); 625 free(vnodefile); 626 return (ret); 627 } 628 629 static int 630 run_cmd(int *ofd, const char *cmdline, ...) 631 { 632 va_list ap; 633 char **argv, **argvp, *cmd, *p; 634 int argc, pid, status, rv; 635 int pfd[2], nfd, dup2dn; 636 637 va_start(ap, cmdline); 638 rv = vasprintf(&cmd, cmdline, ap); 639 if (rv == -1) { 640 warn("%s", __func__); 641 va_end(ap); 642 return (rv); 643 } 644 va_end(ap); 645 646 for (argc = 1, p = cmd; (p = strchr(p, ' ')) != NULL; p++) 647 argc++; 648 argv = (char **)malloc(sizeof(*argv) * (argc + 1)); 649 for (p = cmd, argvp = argv; (*argvp = strsep(&p, " ")) != NULL;) 650 if (**argvp != '\0' && (++argvp > &argv[argc])) { 651 *argvp = NULL; 652 break; 653 } 654 /* The argv array ends up NULL-terminated here. */ 655 #if 0 656 { 657 int i; 658 659 fprintf(stderr, "DEBUG: running:"); 660 /* Should be equivalent to 'cmd' (before strsep, of course). */ 661 for (i = 0; argv[i] != NULL; i++) 662 fprintf(stderr, " %s", argv[i]); 663 fprintf(stderr, "\n"); 664 } 665 #endif 666 dup2dn = 1; 667 if (ofd != NULL) { 668 if (pipe(&pfd[0]) == -1) { 669 warn("%s: pipe", __func__); 670 return (-1); 671 } 672 *ofd = pfd[0]; 673 dup2dn = 0; 674 } 675 pid = fork(); 676 switch (pid) { 677 case 0: 678 /* Child process. */ 679 if (ofd != NULL) 680 if (dup2(pfd[1], STDOUT_FILENO) < 0) 681 err(1, "dup2 in %s", __func__); 682 nfd = open(_PATH_DEVNULL, O_RDWR); 683 if (nfd == -1) 684 err(1, "%s: open %s", __func__, _PATH_DEVNULL); 685 if (dup2(nfd, STDIN_FILENO) < 0) 686 err(1, "%s: dup2", __func__); 687 if (dup2dn && dup2(nfd, STDOUT_FILENO) < 0) 688 err(1, "%s: dup2", __func__); 689 if (dup2(nfd, STDERR_FILENO) < 0) 690 err(1, "%s: dup2", __func__); 691 execv(argv[0], argv); 692 warn("exec: %s", argv[0]); 693 _exit(-1); 694 case -1: 695 err(1, "%s: fork", __func__); 696 } 697 free(cmd); 698 free(argv); 699 while (waitpid(pid, &status, 0) != pid) 700 ; 701 return (WEXITSTATUS(status)); 702 } 703 704 static int 705 swapon_trim(const char *name) 706 { 707 struct stat sb; 708 off_t ioarg[2], sz; 709 int error, fd; 710 711 /* Open a descriptor to create a consumer of the device. */ 712 fd = open(name, O_WRONLY); 713 if (fd < 0) 714 errx(1, "Cannot open %s", name); 715 /* Find the device size. */ 716 if (fstat(fd, &sb) < 0) 717 errx(1, "Cannot stat %s", name); 718 if (S_ISREG(sb.st_mode)) 719 sz = sb.st_size; 720 else if (S_ISCHR(sb.st_mode)) { 721 if (ioctl(fd, DIOCGMEDIASIZE, &sz) != 0) 722 err(1, "ioctl(DIOCGMEDIASIZE)"); 723 } else 724 errx(1, "%s has an invalid file type", name); 725 /* Trim the device. */ 726 ioarg[0] = BBSIZE; 727 ioarg[1] = sz - BBSIZE; 728 if (ioctl(fd, DIOCGDELETE, ioarg) != 0) 729 warn("ioctl(DIOCGDELETE)"); 730 731 /* Start using the device for swapping, creating a second consumer. */ 732 error = swapon(name); 733 734 /* 735 * Do not close the device until the swap pager has attempted to create 736 * another consumer. For GELI devices created with the 'detach -l' 737 * option, removing the last consumer causes the device to be detached 738 * - that is, to disappear. This ordering ensures that the device will 739 * not be detached until swapoff is called. 740 */ 741 close(fd); 742 return (error); 743 } 744 745 static const char * 746 swap_on_off_sfile(const char *name, int doingall) 747 { 748 int error; 749 750 if (which_prog == SWAPON) 751 error = Eflag ? swapon_trim(name) : swapon(name); 752 else /* SWAPOFF */ 753 error = swapoff(name, fflag ? SWAPOFF_FORCE : 0); 754 755 if (error == -1) { 756 switch (errno) { 757 case EBUSY: 758 if (doingall == 0) 759 warnx("%s: Device already in use", name); 760 break; 761 case EINVAL: 762 if (which_prog == SWAPON) 763 warnx("%s: NSWAPDEV limit reached", name); 764 else if (doingall == 0) 765 warn("%s", name); 766 break; 767 default: 768 warn("%s", name); 769 break; 770 } 771 return (NULL); 772 } 773 return (name); 774 } 775 776 static void 777 usage(void) 778 { 779 780 fprintf(stderr, "usage: %s ", getprogname()); 781 switch(orig_prog) { 782 case SWAPON: 783 fprintf(stderr, "[-F fstab] -aLq | [-E] file ...\n"); 784 break; 785 case SWAPOFF: 786 fprintf(stderr, "[-F fstab] -afLq | file ...\n"); 787 break; 788 case SWAPCTL: 789 fprintf(stderr, "[-AghklmsU] [-a file ... | -d file ...]\n"); 790 break; 791 } 792 exit(1); 793 } 794 795 static void 796 sizetobuf(char *buf, size_t bufsize, int hflag, long long val, int hlen, 797 long blocksize) 798 { 799 char tmp[16]; 800 801 if (hflag == 'H') { 802 humanize_number(tmp, 5, (int64_t)val, "", HN_AUTOSCALE, 803 HN_B | HN_NOSPACE | HN_DECIMAL); 804 snprintf(buf, bufsize, "%*s", hlen, tmp); 805 } else 806 snprintf(buf, bufsize, "%*lld", hlen, val / blocksize); 807 } 808 809 static void 810 swaplist(int lflag, int sflag, int hflag) 811 { 812 size_t mibsize, size; 813 struct xswdev xsw; 814 int hlen, mib[16], n, pagesize; 815 long blocksize; 816 long long total = 0; 817 long long used = 0; 818 long long tmp_total; 819 long long tmp_used; 820 char buf[32]; 821 822 pagesize = getpagesize(); 823 switch(hflag) { 824 case 'G': 825 blocksize = 1024 * 1024 * 1024; 826 strlcpy(buf, "1GB-blocks", sizeof(buf)); 827 hlen = 10; 828 break; 829 case 'H': 830 blocksize = -1; 831 strlcpy(buf, "Bytes", sizeof(buf)); 832 hlen = 10; 833 break; 834 case 'K': 835 blocksize = 1024; 836 strlcpy(buf, "1kB-blocks", sizeof(buf)); 837 hlen = 10; 838 break; 839 case 'M': 840 blocksize = 1024 * 1024; 841 strlcpy(buf, "1MB-blocks", sizeof(buf)); 842 hlen = 10; 843 break; 844 default: 845 getbsize(&hlen, &blocksize); 846 snprintf(buf, sizeof(buf), "%ld-blocks", blocksize); 847 break; 848 } 849 850 mibsize = nitems(mib); 851 if (sysctlnametomib("vm.swap_info", mib, &mibsize) == -1) 852 err(1, "sysctlnametomib()"); 853 854 if (lflag) { 855 printf("%-13s %*s %*s\n", 856 "Device:", 857 hlen, buf, 858 hlen, "Used:"); 859 } 860 861 for (n = 0; ; ++n) { 862 mib[mibsize] = n; 863 size = sizeof xsw; 864 if (sysctl(mib, mibsize + 1, &xsw, &size, NULL, 0) == -1) 865 break; 866 if (xsw.xsw_version != XSWDEV_VERSION) 867 errx(1, "xswdev version mismatch"); 868 869 tmp_total = (long long)xsw.xsw_nblks * pagesize; 870 tmp_used = (long long)xsw.xsw_used * pagesize; 871 total += tmp_total; 872 used += tmp_used; 873 if (lflag) { 874 sizetobuf(buf, sizeof(buf), hflag, tmp_total, hlen, 875 blocksize); 876 printf("/dev/%-8s %s ", devname(xsw.xsw_dev, S_IFCHR), 877 buf); 878 sizetobuf(buf, sizeof(buf), hflag, tmp_used, hlen, 879 blocksize); 880 printf("%s\n", buf); 881 } 882 } 883 if (errno != ENOENT) 884 err(1, "sysctl()"); 885 886 if (sflag) { 887 sizetobuf(buf, sizeof(buf), hflag, total, hlen, blocksize); 888 printf("Total: %s ", buf); 889 sizetobuf(buf, sizeof(buf), hflag, used, hlen, blocksize); 890 printf("%s\n", buf); 891 } 892 } 893 894