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