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