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