swapctl.c revision 1.24
1/* $OpenBSD: swapctl.c,v 1.24 2019/06/28 13:32:46 deraadt Exp $ */ 2/* $NetBSD: swapctl.c,v 1.9 1998/07/26 20:23:15 mycroft Exp $ */ 3 4/* 5 * Copyright (c) 1996, 1997 Matthew R. Green 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 * 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/* 33 * swapctl command: 34 * -A add all devices listed as `sw' in /etc/fstab 35 * -t [blk|noblk] if -A, add either all block device or all non-block 36 * devices 37 * -a <path> add this device 38 * -d <path> remove this swap device 39 * -l list swap devices 40 * -s short listing of swap devices 41 * -k use kilobytes 42 * -p <pri> use this priority 43 * -c <path> change priority 44 * 45 * or, if invoked as "swapon" (compatibility mode): 46 * 47 * -a all devices listed as `sw' in /etc/fstab 48 * -t same as -t above (feature not present in old 49 * swapon(8) command) 50 * <dev> add this device 51 */ 52 53#include <sys/stat.h> 54#include <sys/swap.h> 55#include <sys/wait.h> 56 57#include <unistd.h> 58#include <err.h> 59#include <errno.h> 60#include <stdio.h> 61#include <stdlib.h> 62#include <limits.h> 63#include <string.h> 64#include <fstab.h> 65#include <util.h> 66 67#include "swapctl.h" 68 69int command; 70 71/* 72 * Commands for swapctl(8). These are mutually exclusive. 73 */ 74#define CMD_A 0x01 /* process /etc/fstab */ 75#define CMD_a 0x02 /* add a swap file/device */ 76#define CMD_c 0x04 /* change priority of a swap file/device */ 77#define CMD_d 0x08 /* delete a swap file/device */ 78#define CMD_l 0x10 /* list swap files/devices */ 79#define CMD_s 0x20 /* summary of swap files/devices */ 80 81#define SET_COMMAND(cmd) \ 82do { \ 83 if (command) \ 84 usage(); \ 85 command = (cmd); \ 86} while (0) 87 88/* 89 * Commands that require a "path" argument at the end of the command 90 * line, and the ones which require that none exist. 91 */ 92#define REQUIRE_PATH (CMD_a | CMD_c | CMD_d) 93#define REQUIRE_NOPATH (CMD_A | CMD_l | CMD_s) 94 95/* 96 * Option flags, and the commands with which they are valid. 97 */ 98int kflag; /* display in 1K blocks */ 99#define KFLAG_CMDS (CMD_l | CMD_s) 100 101int pflag; /* priority was specified */ 102#define PFLAG_CMDS (CMD_A | CMD_a | CMD_c) 103 104char *tflag; /* swap device type (blk or noblk) */ 105#define TFLAG_CMDS (CMD_A) 106 107int pri; /* uses 0 as default pri */ 108 109static void change_priority(char *); 110static void add_swap(char *); 111static void del_swap(char *); 112static void do_fstab(void); 113static void usage(void); 114static int swapon_command(int, char **); 115 116extern char *__progname; /* from crt0.o */ 117 118int 119main(int argc, char *argv[]) 120{ 121 const char *errstr; 122 int c; 123 124 if (strcmp(__progname, "swapon") == 0) 125 return swapon_command(argc, argv); 126 127 while ((c = getopt(argc, argv, "Aacdlkp:st:")) != -1) { 128 switch (c) { 129 case 'A': 130 SET_COMMAND(CMD_A); 131 break; 132 133 case 'a': 134 SET_COMMAND(CMD_a); 135 break; 136 137 case 'c': 138 SET_COMMAND(CMD_c); 139 break; 140 141 case 'd': 142 SET_COMMAND(CMD_d); 143 break; 144 145 case 'l': 146 SET_COMMAND(CMD_l); 147 break; 148 149 case 'k': 150 kflag = 1; 151 break; 152 153 case 'p': 154 pflag = 1; 155 pri = strtonum(optarg, 0, INT_MAX, &errstr); 156 if (errstr) 157 errx(1, "-p %s: %s", errstr, optarg); 158 break; 159 160 case 's': 161 SET_COMMAND(CMD_s); 162 break; 163 164 case 't': 165 if (tflag != NULL) 166 usage(); 167 tflag = optarg; 168 break; 169 170 default: 171 usage(); 172 /* NOTREACHED */ 173 } 174 } 175 176 argv += optind; 177 argc -= optind; 178 179 /* Did the user specify a command? */ 180 if (command == 0) { 181 if (argc == 0) 182 SET_COMMAND(CMD_l); 183 else 184 usage(); 185 } 186 187 switch (argc) { 188 case 0: 189 if (command & REQUIRE_PATH) 190 usage(); 191 break; 192 193 case 1: 194 if (command & REQUIRE_NOPATH) 195 usage(); 196 break; 197 198 default: 199 usage(); 200 } 201 202 /* To change priority, you have to specify one. */ 203 if ((command == CMD_c) && pflag == 0) 204 usage(); 205 206 /* Sanity-check -t */ 207 if (tflag != NULL) { 208 if (command != CMD_A) 209 usage(); 210 if (strcmp(tflag, "blk") != 0 && 211 strcmp(tflag, "noblk") != 0) 212 usage(); 213 } 214 215 /* Dispatch the command. */ 216 switch (command) { 217 case CMD_l: 218 list_swap(pri, kflag, pflag, 1); 219 break; 220 221 case CMD_s: 222 list_swap(pri, kflag, pflag, 0); 223 break; 224 225 case CMD_c: 226 change_priority(argv[0]); 227 break; 228 229 case CMD_a: 230 add_swap(argv[0]); 231 break; 232 233 case CMD_d: 234 del_swap(argv[0]); 235 break; 236 237 case CMD_A: 238 do_fstab(); 239 break; 240 } 241 242 return (0); 243} 244 245/* 246 * swapon_command: emulate the old swapon(8) program. 247 */ 248int 249swapon_command(int argc, char **argv) 250{ 251 int ch, fiztab = 0; 252 253 while ((ch = getopt(argc, argv, "at:")) != -1) { 254 switch (ch) { 255 case 'a': 256 fiztab = 1; 257 break; 258 case 't': 259 if (tflag != NULL) 260 usage(); 261 tflag = optarg; 262 break; 263 default: 264 goto swapon_usage; 265 } 266 } 267 argc -= optind; 268 argv += optind; 269 270 if (fiztab) { 271 if (argc) 272 goto swapon_usage; 273 /* Sanity-check -t */ 274 if (tflag != NULL) { 275 if (strcmp(tflag, "blk") != 0 && 276 strcmp(tflag, "noblk") != 0) 277 usage(); 278 } 279 do_fstab(); 280 return (0); 281 } else if (argc == 0 || tflag != NULL) 282 goto swapon_usage; 283 284 while (argc) { 285 add_swap(argv[0]); 286 argc--; 287 argv++; 288 } 289 return (0); 290 291 swapon_usage: 292 fprintf(stderr, "usage: %s -a | path\n", __progname); 293 return (1); 294} 295 296/* 297 * change_priority: change the priority of a swap device. 298 */ 299void 300change_priority(char *path) 301{ 302 303 if (swapctl(SWAP_CTL, path, pri) == -1) 304 warn("%s", path); 305} 306 307/* 308 * add_swap: add the pathname to the list of swap devices. 309 */ 310void 311add_swap(char *path) 312{ 313 314 if (swapctl(SWAP_ON, path, pri) == -1) 315 if (errno != EBUSY) 316 err(1, "%s", path); 317} 318 319/* 320 * del_swap: remove the pathname from the list of swap devices. 321 */ 322void 323del_swap(char *path) 324{ 325 326 if (swapctl(SWAP_OFF, path, pri) == -1) 327 err(1, "%s", path); 328} 329 330void 331do_fstab(void) 332{ 333 struct fstab *fp; 334 char *s; 335 long priority; 336 struct stat st; 337 mode_t rejecttype; 338 int gotone = 0; 339 340 /* 341 * Select which mount point types to reject, depending on the 342 * value of the -t parameter. 343 */ 344 if (tflag != NULL) { 345 if (strcmp(tflag, "blk") == 0) 346 rejecttype = S_IFREG; 347 else if (strcmp(tflag, "noblk") == 0) 348 rejecttype = S_IFBLK; 349 } else 350 rejecttype = 0; 351 352#define PRIORITYEQ "priority=" 353#define NFSMNTPT "nfsmntpt=" 354#define PATH_MOUNT "/sbin/mount_nfs" 355 while ((fp = getfsent()) != NULL) { 356 const char *spec; 357 358 if (strcmp(fp->fs_type, "sw") != 0) 359 continue; 360 361 spec = fp->fs_spec; 362 363 if ((s = strstr(fp->fs_mntops, PRIORITYEQ)) != NULL) { 364 s += sizeof(PRIORITYEQ) - 1; 365 priority = atol(s); 366 } else 367 priority = pri; 368 369 if ((s = strstr(fp->fs_mntops, NFSMNTPT)) != NULL) { 370 char *t; 371 pid_t pid; 372 int status; 373 374 /* 375 * Skip this song and dance if we're only 376 * doing block devices. 377 */ 378 if (rejecttype == S_IFREG) 379 continue; 380 381 t = strpbrk(s, ","); 382 if (t != 0) 383 *t = '\0'; 384 spec = strdup(s + strlen(NFSMNTPT)); 385 if (spec == NULL) 386 err(1, "strdup"); 387 388 if (t != 0) 389 *t = ','; 390 391 if (strlen(spec) == 0) { 392 warnx("empty mountpoint"); 393 free((char *)spec); 394 continue; 395 } 396 397 switch (pid = vfork()) { 398 case -1: /* error */ 399 err(1, "vfork"); 400 case 0: 401 execl(PATH_MOUNT, PATH_MOUNT, fp->fs_spec, spec, 402 (char *)NULL); 403 err(1, "execl"); 404 } 405 while (waitpid(pid, &status, 0) == -1) 406 if (errno != EINTR) 407 err(1, "waitpid"); 408 if (status != 0) { 409 warnx("%s: mount failed", fp->fs_spec); 410 free((char *)spec); 411 continue; 412 } 413 } else if (isduid(spec, 0)) { 414 if (rejecttype == S_IFBLK) 415 continue; 416 } else { 417 /* 418 * Determine blk-ness. Don't even consider a 419 * mountpoint outside /dev as a block device. 420 */ 421 if (rejecttype == S_IFREG) { 422 if (strncmp("/dev/", spec, 5) != 0) 423 continue; 424 } 425 if (stat(spec, &st) == -1) { 426 warn("%s", spec); 427 continue; 428 } 429 if ((st.st_mode & S_IFMT) == rejecttype) 430 continue; 431 432 /* 433 * Do not allow fancy objects to be swap areas. 434 */ 435 if (!S_ISREG(st.st_mode) && 436 !S_ISBLK(st.st_mode)) 437 continue; 438 } 439 440 if (swapctl(SWAP_ON, spec, (int)priority) == -1) { 441 if (errno != EBUSY) 442 warn("%s", spec); 443 } else { 444 gotone = 1; 445 printf("%s: adding %s as swap device at priority %d\n", 446 __progname, fp->fs_spec, (int)priority); 447 } 448 449 if (spec != fp->fs_spec) 450 free((char *)spec); 451 } 452 if (gotone == 0) 453 exit(1); 454} 455 456void 457usage(void) 458{ 459 460 fprintf(stderr, "usage: %s -A [-p priority] [-t blk | noblk]\n", 461 __progname); 462 fprintf(stderr, " %s -a [-p priority] path\n", __progname); 463 fprintf(stderr, " %s -c -p priority path\n", __progname); 464 fprintf(stderr, " %s -d path\n", __progname); 465 fprintf(stderr, " %s [[-l] | -s] [-k]\n", __progname); 466 exit(1); 467} 468