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
main(int argc,char ** argv)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 *
swap_on_off(const char * name,int doingall,char * mntops)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 *
swap_basename(const char * name)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 *
swap_on_geli_args(const char * mntops)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 *
swap_on_off_geli(const char * name,char * mntops,int doingall)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 *
swap_on_off_md(const char * name,char * mntops,int doingall)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
run_cmd(int * ofd,const char * cmdline,...)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
swapon_trim(const char * name)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 *
swap_on_off_sfile(const char * name,int doingall)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
usage(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
sizetobuf(char * buf,size_t bufsize,int hflag,long long val,int hlen,long blocksize)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
swaplist(int lflag,int sflag,int hflag)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