1 /*        $NetBSD: swapctl.c,v 1.43 2023/03/01 15:18:18 kre Exp $     */
2 
3 /*
4  * Copyright (c) 1996, 1997, 1999, 2015 Matthew R. Green
5  * 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  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 /*
30  * swapctl command:
31  *        -A                  add all devices listed as `sw' in /etc/fstab (also
32  *                            (sets the dump device, if listed in fstab)
33  *        -D [<dev>|none]     set dumpdev to <dev> or disable dumps
34  *        -z                  show dumpdev
35  *        -U                  remove all devices listed as `sw' in /etc/fstab.
36  *        -t [blk|noblk|auto]
37  *                            if -A or -U , add (remove) either all block device
38  *                            or all non-block devices, or all swap partitions
39  *        -q                  check if any swap or dump devices are defined in
40  *                            /etc/fstab
41  *        -a <dev>  add this device
42  *        -d <dev>  remove this swap device
43  *        -f                  with -A -t auto, use the first swap as dump device
44  *        -g                  use gigabytes
45  *        -h                  use humanize_number(3) for listing
46  *        -l                  list swap devices
47  *        -m                  use megabytes
48  *        -n                  print actions, but do not add/remove swap or
49  *                            with -A/-U
50  *        -o                  with -A -t auto only configure the first swap as dump,
51  *                            (similar to -f), but do not add any further swap devs
52  *        -s                  short listing of swap devices
53  *        -k                  use kilobytes
54  *        -p <pri>  use this priority
55  *        -c                  change priority
56  *
57  * or, if invoked as "swapon" (compatibility mode):
58  *
59  *        -a                  all devices listed as `sw' in /etc/fstab
60  *        -t                  same as -t above (feature not present in old
61  *                            swapon(8) command)
62  *        <dev>               add this device
63  */
64 #include <sys/cdefs.h>
65 
66 #ifndef lint
67 __RCSID("$NetBSD: swapctl.c,v 1.43 2023/03/01 15:18:18 kre Exp $");
68 #endif
69 
70 
71 #include <sys/param.h>
72 #include <sys/ioctl.h>
73 #include <sys/stat.h>
74 #include <sys/swap.h>
75 #include <sys/sysctl.h>
76 #include <sys/disk.h>
77 #include <sys/disklabel.h>
78 
79 #include <unistd.h>
80 #include <err.h>
81 #include <errno.h>
82 #include <stdio.h>
83 #include <stdlib.h>
84 #include <string.h>
85 #include <fstab.h>
86 #include <fcntl.h>
87 #include <util.h>
88 #include <paths.h>
89 
90 #include "swapctl.h"
91 
92 static int          command;
93 
94 /*
95  * Commands for swapctl(8).  These are mutually exclusive.
96  */
97 #define   CMD_A               0x01      /* process /etc/fstab for adding */
98 #define   CMD_D               0x02      /* set dumpdev */
99 #define   CMD_U               0x04      /* process /etc/fstab for removing */
100 #define   CMD_a               0x08      /* add a swap file/device */
101 #define   CMD_c               0x10      /* change priority of a swap file/device */
102 #define   CMD_d               0x20      /* delete a swap file/device */
103 #define   CMD_l               0x40      /* list swap files/devices */
104 #define   CMD_s               0x80      /* summary of swap files/devices */
105 #define   CMD_z               0x100     /* show dump device */
106 #define   CMD_q               0x200     /* check for dump/swap in /etc/fstab */
107 
108 #define   SET_COMMAND(cmd) \
109 do { \
110           if (command) \
111                     usage(); \
112           command = (cmd); \
113 } while (0)
114 
115 /*
116  * Commands that require a "path" argument at the end of the command
117  * line, and the ones which require that none exist.
118  */
119 #define   REQUIRE_PATH        (CMD_D | CMD_a | CMD_c | CMD_d)
120 #define   REQUIRE_NOPATH      (CMD_A | CMD_U | CMD_l | CMD_s | CMD_z | CMD_q)
121 
122 /*
123  * Option flags, and the commands with which they are valid.
124  */
125 static int          kflag;              /* display in 1K^x blocks */
126 #define   KFLAG_CMDS          (CMD_l | CMD_s)
127 #define MFLAG_CMDS  (CMD_l | CMD_s)
128 #define GFLAG_CMDS  (CMD_l | CMD_s)
129 
130 static int          hflag;              /* display with humanize_number */
131 #define HFLAG_CMDS  (CMD_l | CMD_s)
132 
133 static int          pflag;              /* priority was specified */
134 #define   PFLAG_CMDS          (CMD_A | CMD_a | CMD_c)
135 
136 static char         *tflag;             /* swap device type (blk, noblk, auto) */
137 static int          autoflag; /* 1, if tflag is "auto" */
138 #define   TFLAG_CMDS          (CMD_A | CMD_U)
139 
140 static int          fflag;              /* first swap becomes dump */
141 #define   FFLAG_CMDS          (CMD_A)
142 
143 static int          oflag;              /* only autoset dump device */
144 #define   OFLAG_CMDS          (CMD_A)
145 
146 static int          nflag;              /* no execute, just print actions */
147 #define   NFLAG_CMDS          (CMD_A | CMD_U)
148 
149 static int          pri;                /* uses 0 as default pri */
150 
151 static    void change_priority(char *);
152 static    int  add_swap(char *, int);
153 static    int  delete_swap(char *);
154 static    int set_dumpdev1(char *);
155 static    void set_dumpdev(char *);
156 static    int get_dumpdev(void);
157 __dead static       void do_fstab(int);
158 static    int check_fstab(void);
159 static    void do_localdevs(int);
160 static    void do_localdisk(const char *, int);
161 static    int do_wedgesofdisk(int fd, int);
162 static    int do_partitionsofdisk(const char *, int fd, int);
163 __dead static       void usage(void);
164 __dead static       void swapon_command(int, char **);
165 #if 0
166 static    void swapoff_command(int, char **);
167 #endif
168 
169 int
main(int argc,char * argv[])170 main(int argc, char *argv[])
171 {
172           int       c;
173 
174           if (strcmp(getprogname(), "swapon") == 0) {
175                     swapon_command(argc, argv);
176                     /* NOTREACHED */
177           }
178 
179 #if 0
180           if (strcmp(getprogname(), "swapoff") == 0) {
181                     swapoff_command(argc, argv);
182                     /* NOTREACHED */
183           }
184 #endif
185 
186           while ((c = getopt(argc, argv, "ADUacdfghklmnop:qst:z")) != -1) {
187                     switch (c) {
188                     case 'A':
189                               SET_COMMAND(CMD_A);
190                               break;
191 
192                     case 'D':
193                               SET_COMMAND(CMD_D);
194                               break;
195 
196                     case 'U':
197                               SET_COMMAND(CMD_U);
198                               break;
199 
200                     case 'a':
201                               SET_COMMAND(CMD_a);
202                               break;
203 
204                     case 'c':
205                               SET_COMMAND(CMD_c);
206                               break;
207 
208                     case 'd':
209                               SET_COMMAND(CMD_d);
210                               break;
211 
212                     case 'f':
213                               fflag = 1;
214                               break;
215 
216                     case 'g':
217                               kflag = 3; /* 1k ^ 3 */
218                               break;
219 
220                     case 'h':
221                               hflag = 1;
222                               break;
223 
224                     case 'k':
225                               kflag = 1;
226                               break;
227 
228                     case 'l':
229                               SET_COMMAND(CMD_l);
230                               break;
231 
232                     case 'm':
233                               kflag = 2; /* 1k ^ 2 */
234                               break;
235 
236                     case 'n':
237                               nflag = 1;
238                               break;
239 
240                     case 'o':
241                               oflag = 1;
242                               break;
243 
244                     case 'p':
245                               pflag = 1;
246                               /* XXX strtol() */
247                               pri = atoi(optarg);
248                               break;
249 
250                     case 'q':
251                               SET_COMMAND(CMD_q);
252                               break;
253 
254                     case 's':
255                               SET_COMMAND(CMD_s);
256                               break;
257 
258                     case 't':
259                               if (tflag != NULL)
260                                         usage();
261                               tflag = optarg;
262                               if (strcmp(tflag, "auto") == 0)
263                                         autoflag = 1;
264                               break;
265 
266                     case 'z':
267                               SET_COMMAND(CMD_z);
268                               break;
269 
270                     default:
271                               usage();
272                               /* NOTREACHED */
273                     }
274           }
275 
276           /* Did the user specify a command? */
277           if (command == 0)
278                     usage();
279 
280           argv += optind;
281           argc -= optind;
282 
283           switch (argc) {
284           case 0:
285                     if (command & REQUIRE_PATH)
286                               usage();
287                     break;
288 
289           case 1:
290                     if (command & REQUIRE_NOPATH)
291                               usage();
292                     break;
293 
294           default:
295                     usage();
296           }
297 
298           /* To change priority, you have to specify one. */
299           if ((command == CMD_c) && pflag == 0)
300                     usage();
301 
302           /* -f and -o are mutually exclusive */
303           if (fflag && oflag)
304                     usage();
305 
306           /* Sanity-check -t */
307           if (tflag != NULL) {
308                     if (command != CMD_A && command != CMD_U)
309                               usage();
310                     if (strcmp(tflag, "blk") != 0 &&
311                         strcmp(tflag, "noblk") != 0 &&
312                         strcmp(tflag, "auto") != 0)
313                               usage();
314           }
315 
316           /* Dispatch the command. */
317           switch (command) {
318           case CMD_l:
319                     if (!list_swap(pri, kflag, pflag, 0, 1, hflag))
320                               exit(1);
321                     break;
322 
323           case CMD_s:
324                     list_swap(pri, kflag, pflag, 0, 0, hflag);
325                     break;
326 
327           case CMD_c:
328                     change_priority(argv[0]);
329                     break;
330 
331           case CMD_a:
332                     if (! add_swap(argv[0], pri))
333                               exit(1);
334                     break;
335 
336           case CMD_d:
337                     if (! delete_swap(argv[0]))
338                               exit(1);
339                     break;
340 
341           case CMD_A:
342                     if (autoflag)
343                               do_localdevs(1);
344                     else
345                               do_fstab(1);
346                     break;
347 
348           case CMD_D:
349                     set_dumpdev(argv[0]);
350                     break;
351 
352           case CMD_z:
353                     if (!get_dumpdev())
354                               exit(1);
355                     break;
356 
357           case CMD_U:
358                     if (autoflag)
359                               do_localdevs(0);
360                     else
361                               do_fstab(0);
362                     break;
363           case CMD_q:
364                     if (check_fstab()) {
365                               printf("%s: there are swap or dump devices defined in "
366                                   _PATH_FSTAB "\n", getprogname());
367                               exit(0);
368                     } else {
369                               printf("%s: no swap or dump devices in "
370                                   _PATH_FSTAB "\n", getprogname());
371                               exit(1);
372                     }
373           }
374 
375           exit(0);
376 }
377 
378 /*
379  * swapon_command: emulate the old swapon(8) program.
380  */
381 static void
swapon_command(int argc,char ** argv)382 swapon_command(int argc, char **argv)
383 {
384           int ch, fiztab = 0;
385 
386           while ((ch = getopt(argc, argv, "at:")) != -1) {
387                     switch (ch) {
388                     case 'a':
389                               fiztab = 1;
390                               break;
391                     case 't':
392                               if (tflag != NULL)
393                                         usage();
394                               tflag = optarg;
395                               break;
396                     default:
397                               goto swapon_usage;
398                     }
399           }
400           argc -= optind;
401           argv += optind;
402 
403           if (fiztab) {
404                     if (argc)
405                               goto swapon_usage;
406                     /* Sanity-check -t */
407                     if (tflag != NULL) {
408                               if (strcmp(tflag, "blk") != 0 &&
409                                   strcmp(tflag, "noblk") != 0)
410                                         usage();
411                     }
412                     do_fstab(1);
413                     exit(0);
414           } else if (argc == 0 || tflag != NULL)
415                     goto swapon_usage;
416 
417           while (argc) {
418                     if (! add_swap(argv[0], pri))
419                               exit(1);
420                     argc--;
421                     argv++;
422           }
423           exit(0);
424           /* NOTREACHED */
425 
426  swapon_usage:
427           fprintf(stderr, "usage: %s -a [-t blk|noblk]\n", getprogname());
428           fprintf(stderr, "       %s <path> ...\n", getprogname());
429           exit(1);
430 }
431 
432 /*
433  * change_priority:  change the priority of a swap device.
434  */
435 static void
change_priority(char * path)436 change_priority(char *path)
437 {
438 
439           if (swapctl(SWAP_CTL, path, pri) < 0)
440                     err(1, "%s", path);
441 }
442 
443 /*
444  * add_swap:  add the pathname to the list of swap devices.
445  */
446 static int
add_swap(char * path,int priority)447 add_swap(char *path, int priority)
448 {
449           struct stat sb;
450           char buf[MAXPATHLEN];
451           char *spec;
452 
453           if (getfsspecname(buf, sizeof(buf), path) == NULL)
454                     goto oops;
455           spec = buf;
456 
457           if (stat(spec, &sb) < 0)
458                     goto oops;
459 
460           if (sb.st_mode & S_IROTH)
461                     warnx("WARNING: %s is readable by the world", path);
462           if (sb.st_mode & S_IWOTH)
463                     warnx("WARNING: %s is writable by the world", path);
464 
465           if (fflag || oflag) {
466                     set_dumpdev1(spec);
467                     if (oflag)
468                               exit(0);
469                     else
470                               fflag = 0;
471           }
472 
473           if (nflag)
474                     return 1;
475 
476           if (swapctl(SWAP_ON, spec, priority) < 0) {
477 oops:
478                     warn("%s", path);
479                     return 0;
480           }
481           return 1;
482 }
483 
484 /*
485  * delete_swap:  remove the pathname to the list of swap devices.
486  */
487 static int
delete_swap(char * path)488 delete_swap(char *path)
489 {
490           char buf[MAXPATHLEN];
491           char *spec;
492 
493           if (getfsspecname(buf, sizeof(buf), path) == NULL) {
494                     warn("%s", path);
495                     return 0;
496           }
497           spec = buf;
498 
499           if (nflag)
500                     return 1;
501 
502           if (swapctl(SWAP_OFF, spec, pri) < 0) {
503                     warn("%s", path);
504                     return 0;
505           }
506           return 1;
507 }
508 
509 static int
set_dumpdev1(char * spec)510 set_dumpdev1(char *spec)
511 {
512           int rv = 0;
513 
514           if (!nflag) {
515                     if (strcmp(spec, "none") == 0)
516                               rv = swapctl(SWAP_DUMPOFF, NULL, 0);
517                     else
518                               rv = swapctl(SWAP_DUMPDEV, spec, 0);
519           }
520 
521           if (rv == -1)
522                     warn("could not set dump device to %s", spec);
523           else
524                     printf("%s: setting dump device to %s\n", getprogname(), spec);
525 
526           return rv == -1 ? 0 : 1;
527 }
528 
529 static void
set_dumpdev(char * path)530 set_dumpdev(char *path)
531 {
532           char buf[MAXPATHLEN];
533           char *spec;
534 
535           if (getfsspecname(buf, sizeof(buf), path) == NULL)
536                     err(1, "%s", path);
537           spec = buf;
538 
539           if (! set_dumpdev1(spec))
540                     exit(1);
541 }
542 
543 static int
get_dumpdev(void)544 get_dumpdev(void)
545 {
546           dev_t     dev;
547           char      *name;
548 
549           if (swapctl(SWAP_GETDUMPDEV, &dev, 0) == -1) {
550                     warn("could not get dump device");
551                     return 0;
552           } else if (dev == NODEV) {
553                     printf("no dump device set\n");
554                     return 0;
555           } else {
556                     name = devname(dev, S_IFBLK);
557                     printf("dump device is ");
558                     if (name)
559                               printf("%s\n", name);
560                     else
561                               printf("major %llu minor %llu\n",
562                                   (unsigned long long)major(dev),
563                                   (unsigned long long)minor(dev));
564           }
565           return 1;
566 }
567 
568 static void
do_localdevs(int add)569 do_localdevs(int add)
570 {
571           size_t ressize;
572           char *disknames, *disk;
573           static const char mibname[] = "hw.disknames";
574 
575           ressize = 0;
576           if (sysctlbyname(mibname, NULL, &ressize, NULL, 0))
577                     return;
578           ressize += 200;     /* add some arbitrary slope */
579           disknames = malloc(ressize);
580           if (sysctlbyname(mibname, disknames, &ressize, NULL, 0) == 0) {
581                     for (disk = strtok(disknames, " "); disk;
582                         disk = strtok(NULL, " "))
583                               do_localdisk(disk, add);
584           }
585           free(disknames);
586 }
587 
588 static void
do_localdisk(const char * disk,int add)589 do_localdisk(const char *disk, int add)
590 {
591           int fd;
592           char dvname[MAXPATHLEN];
593 
594           if ((fd = opendisk(disk, O_RDONLY, dvname, sizeof(dvname), 0)) == -1)
595                     return;
596 
597           if (!do_wedgesofdisk(fd, add))
598                     do_partitionsofdisk(disk, fd, add);
599 
600           close(fd);
601 }
602 
603 static int
do_wedgesofdisk(int fd,int add)604 do_wedgesofdisk(int fd, int add)
605 {
606           char devicename[MAXPATHLEN];
607           struct dkwedge_info *dkw;
608           struct dkwedge_list dkwl;
609           size_t bufsize;
610           u_int i;
611 
612           dkw = NULL;
613           dkwl.dkwl_buf = dkw;
614           dkwl.dkwl_bufsize = 0;
615 
616           for (;;) {
617                     if (ioctl(fd, DIOCLWEDGES, &dkwl) == -1)
618                               return 0;
619                     if (dkwl.dkwl_nwedges == dkwl.dkwl_ncopied)
620                               break;
621                     bufsize = dkwl.dkwl_nwedges * sizeof(*dkw);
622                     if (dkwl.dkwl_bufsize < bufsize) {
623                               dkw = realloc(dkwl.dkwl_buf, bufsize);
624                               if (dkw == NULL)
625                                         return 0;
626                               dkwl.dkwl_buf = dkw;
627                               dkwl.dkwl_bufsize = bufsize;
628                     }
629           }
630 
631           for (i = 0; i < dkwl.dkwl_ncopied; i++) {
632                     if (strcmp(dkw[i].dkw_ptype, DKW_PTYPE_SWAP) != 0)
633                               continue;
634                     snprintf(devicename, sizeof(devicename), "%s%s", _PATH_DEV,
635                         dkw[i].dkw_devname);
636                     devicename[sizeof(devicename)-1] = '\0';
637 
638                     if (add) {
639                               if (add_swap(devicename, pri)) {
640                                         printf(
641                                         "%s: adding %s as swap device at priority 0\n",
642                                             getprogname(), devicename);
643                               }
644                     } else {
645                               if (delete_swap(devicename)) {
646                                         printf(
647                                             "%s: removing %s as swap device\n",
648                                             getprogname(), devicename);
649                               }
650                     }
651 
652           }
653 
654           free(dkw);
655           return dkwl.dkwl_nwedges != 0;
656 }
657 
658 static int
do_partitionsofdisk(const char * prefix,int fd,int add)659 do_partitionsofdisk(const char *prefix, int fd, int add)
660 {
661           char devicename[MAXPATHLEN];
662           struct disklabel lab;
663           uint i;
664 
665           if (ioctl(fd, DIOCGDINFO, &lab) != 0)
666                     return 0;
667 
668           for (i = 0; i < lab.d_npartitions; i++) {
669                     if (lab.d_partitions[i].p_fstype != FS_SWAP)
670                               continue;
671                     snprintf(devicename, sizeof(devicename), "%s%s%c", _PATH_DEV,
672                         prefix, 'a'+i);
673                     devicename[sizeof(devicename)-1] = '\0';
674 
675                     if (add) {
676                               if (add_swap(devicename, pri)) {
677                                         printf(
678                                         "%s: adding %s as swap device at priority 0\n",
679                                             getprogname(), devicename);
680                               }
681                     } else {
682                               if (delete_swap(devicename)) {
683                                         printf(
684                                             "%s: removing %s as swap device\n",
685                                             getprogname(), devicename);
686                               }
687                     }
688           }
689 
690           return 1;
691 }
692 
693 static int
check_fstab(void)694 check_fstab(void)
695 {
696           struct    fstab *fp;
697 
698           while ((fp = getfsent()) != NULL) {
699                     if (strcmp(fp->fs_type, "dp") == 0)
700                               return 1;
701 
702                     if (strcmp(fp->fs_type, "sw") == 0)
703                               return 1;
704           }
705 
706           return 0;
707 }
708 
709 static void
do_fstab(int add)710 do_fstab(int add)
711 {
712           struct    fstab *fp;
713           char      *s;
714           long      priority;
715           struct    stat st;
716           int       isblk;
717           int       success = 0;        /* set to 1 after a successful operation */
718           int       error = 0;          /* set to 1 after an error */
719 
720 #ifdef RESCUEDIR
721 #define PATH_MOUNT  RESCUEDIR "/mount_nfs"
722 #define PATH_UMOUNT RESCUEDIR "/umount"
723 #else
724 #define PATH_MOUNT  "/sbin/mount_nfs"
725 #define PATH_UMOUNT "/sbin/umount"
726 #endif
727 
728           char      cmd[2*PATH_MAX+sizeof(PATH_MOUNT)+2];
729 
730 #define PRIORITYEQ  "priority="
731 #define NFSMNTPT    "nfsmntpt="
732           while ((fp = getfsent()) != NULL) {
733                     char buf[MAXPATHLEN];
734                     char *spec, *fsspec;
735 
736                     /*
737                      * Ignore any entries which are not related to swapping
738                      */
739                     if (strcmp(fp->fs_type, "sw") != 0 &&
740                         strcmp(fp->fs_type, "dp") != 0)
741                               continue;
742 
743                     if (getfsspecname(buf, sizeof(buf), fp->fs_spec) == NULL) {
744                               warn("%s", buf);
745                               continue;
746                     }
747                     fsspec = spec = buf;
748                     cmd[0] = '\0';
749 
750                     if (strcmp(fp->fs_type, "dp") == 0 && add) {
751                               set_dumpdev1(spec);
752                               continue;
753                     }
754 
755                     /* handle dp as mnt option */
756                     if (strstr(fp->fs_mntops, "dp") && add)
757                               set_dumpdev1(spec);
758 
759                     isblk = 0;
760 
761                     if ((s = strstr(fp->fs_mntops, PRIORITYEQ)) != NULL) {
762                               s += sizeof(PRIORITYEQ) - 1;
763                               priority = atol(s);
764                     } else
765                               priority = pri;
766 
767                     if ((s = strstr(fp->fs_mntops, NFSMNTPT)) != NULL) {
768                               char *t;
769 
770                               /*
771                                * Skip this song and dance if we're only
772                                * doing block devices.
773                                */
774                               if (tflag != NULL && strcmp(tflag, "blk") == 0)
775                                         continue;
776 
777                               t = strpbrk(s, ",");
778                               if (t != 0)
779                                         *t = '\0';
780                               spec = strdup(s + strlen(NFSMNTPT));
781                               if (t != 0)
782                                         *t = ',';
783 
784                               if (spec == NULL)
785                                         errx(1, "Out of memory");
786 
787                               if (strlen(spec) == 0) {
788                                         warnx("empty mountpoint");
789                                         free(spec);
790                                         continue;
791                               }
792                               if (add) {
793                                         snprintf(cmd, sizeof(cmd), "%s %s %s",
794                                                   PATH_MOUNT, fsspec, spec);
795                                         if (system(cmd) != 0) {
796                                                   warnx("%s: mount failed", fsspec);
797                                                   continue;
798                                         }
799                               } else {
800                                         snprintf(cmd, sizeof(cmd), "%s %s",
801                                                   PATH_UMOUNT, fsspec);
802                               }
803                     } else {
804                               /*
805                                * Determine blk-ness.
806                                */
807                               if (stat(spec, &st) < 0) {
808                                         warn("%s", spec);
809                                         continue;
810                               }
811                               if (S_ISBLK(st.st_mode))
812                                         isblk = 1;
813                     }
814 
815                     /*
816                      * Skip this type if we're told to.
817                      */
818                     if (tflag != NULL) {
819                               if (strcmp(tflag, "blk") == 0 && isblk == 0)
820                                         continue;
821                               if (strcmp(tflag, "noblk") == 0 && isblk == 1)
822                                         continue;
823                     }
824 
825                     if (add) {
826                               if (add_swap(spec, (int)priority)) {
827                                         success = 1;
828                                         printf(
829                                         "%s: adding %s as swap device at priority %d\n",
830                                             getprogname(), fsspec, (int)priority);
831                               } else {
832                                         error = 1;
833                                         fprintf(stderr,
834                                             "%s: failed to add %s as swap device\n",
835                                             getprogname(), fsspec);
836                               }
837                     } else {
838                               if (delete_swap(spec)) {
839                                         success = 1;
840                                         printf(
841                                             "%s: removing %s as swap device\n",
842                                             getprogname(), fsspec);
843                               } else {
844                                         error = 1;
845                                         fprintf(stderr,
846                                             "%s: failed to remove %s as swap device\n",
847                                             getprogname(), fsspec);
848                               }
849                               if (cmd[0]) {
850                                         if (system(cmd) != 0) {
851                                                   warnx("%s: umount failed", fsspec);
852                                                   error = 1;
853                                                   continue;
854                                         }
855                               }
856                     }
857 
858                     if (spec != fsspec)
859                               free(spec);
860           }
861           if (error)
862                     exit(1);
863           else if (success)
864                     exit(0);
865           else
866                     exit(2); /* not really an error, but no swap devices found */
867 }
868 
869 static void
usage(void)870 usage(void)
871 {
872           const char *progname = getprogname();
873 
874           fprintf(stderr, "usage: %s -A [-f|-o] [-n] [-p priority] "
875               "[-t blk|noblk|auto]\n", progname);
876           fprintf(stderr, "       %s -a [-p priority] path\n", progname);
877           fprintf(stderr, "       %s -q\n", progname);
878           fprintf(stderr, "       %s -c -p priority path\n", progname);
879           fprintf(stderr, "       %s -D dumpdev|none\n", progname);
880           fprintf(stderr, "       %s -d path\n", progname);
881           fprintf(stderr, "       %s -l | -s [-k|-m|-g|-h]\n", progname);
882           fprintf(stderr, "       %s -U [-n] [-t blk|noblk|auto]\n", progname);
883           fprintf(stderr, "       %s -z\n", progname);
884           exit(1);
885 }
886