swapctl.c revision 1.16 1 /* $NetBSD: swapctl.c,v 1.16 2000/11/17 11:43:41 mrg Exp $ */
2
3 /*
4 * Copyright (c) 1996, 1997, 1999 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 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31 /*
32 * swapctl command:
33 * -A add all devices listed as `sw' in /etc/fstab (also
34 * (sets the dump device, if listed in fstab)
35 * -D <dev> set dumpdev to <dev>
36 * -z show dumpdev
37 * -U remove all devices listed as `sw' in /etc/fstab.
38 * -t [blk|noblk] if -A or -U , add (remove) either all block device
39 * or all non-block devices
40 * -a <dev> add this device
41 * -d <dev> remove this swap device (not supported yet)
42 * -l list swap devices
43 * -s short listing of swap devices
44 * -k use kilobytes
45 * -p <pri> use this priority
46 * -c change priority
47 *
48 * or, if invoked as "swapon" (compatibility mode):
49 *
50 * -a all devices listed as `sw' in /etc/fstab
51 * -t same as -t above (feature not present in old
52 * swapon(8) command)
53 * <dev> add this device
54 */
55
56 #include <sys/param.h>
57 #include <sys/stat.h>
58 #include <sys/swap.h>
59
60 #include <unistd.h>
61 #include <err.h>
62 #include <errno.h>
63 #include <stdio.h>
64 #include <stdlib.h>
65 #include <string.h>
66 #include <fstab.h>
67
68 #include "swapctl.h"
69
70 int command;
71
72 /*
73 * Commands for swapctl(8). These are mutually exclusive.
74 */
75 #define CMD_A 0x01 /* process /etc/fstab for adding */
76 #define CMD_D 0x02 /* set dumpdev */
77 #define CMD_U 0x04 /* process /etc/fstab for removing */
78 #define CMD_a 0x08 /* add a swap file/device */
79 #define CMD_c 0x10 /* change priority of a swap file/device */
80 #define CMD_d 0x20 /* delete a swap file/device */
81 #define CMD_l 0x40 /* list swap files/devices */
82 #define CMD_s 0x80 /* summary of swap files/devices */
83 #define CMD_z 0x100 /* show dump device */
84
85 #define SET_COMMAND(cmd) \
86 do { \
87 if (command) \
88 usage(); \
89 command = (cmd); \
90 } while (0)
91
92 /*
93 * Commands that require a "path" argument at the end of the command
94 * line, and the ones which require that none exist.
95 */
96 #define REQUIRE_PATH (CMD_D | CMD_a | CMD_c | CMD_d)
97 #define REQUIRE_NOPATH (CMD_A | CMD_U | CMD_l | CMD_s | CMD_z)
98
99 /*
100 * Option flags, and the commands with which they are valid.
101 */
102 int kflag; /* display in 1K blocks */
103 #define KFLAG_CMDS (CMD_l | CMD_s)
104
105 int pflag; /* priority was specified */
106 #define PFLAG_CMDS (CMD_A | CMD_a | CMD_c)
107
108 char *tflag; /* swap device type (blk or noblk) */
109 #define TFLAG_CMDS (CMD_A | CMD_U)
110
111 int pri; /* uses 0 as default pri */
112
113 static void change_priority __P((const char *));
114 static int add_swap __P((const char *, int));
115 static int delete_swap __P((const char *));
116 static void set_dumpdev __P((const char *));
117 static void get_dumpdev __P((void));
118 int main __P((int, char *[]));
119 static void do_fstab __P((int));
120 static void usage __P((void));
121 static void swapon_command __P((int, char **));
122 #if 0
123 static void swapoff_command __P((int, char **));
124 #endif
125
126 extern char *__progname; /* from crt0.o */
127
128 int
129 main(argc, argv)
130 int argc;
131 char *argv[];
132 {
133 int c;
134
135 if (strcmp(__progname, "swapon") == 0) {
136 swapon_command(argc, argv);
137 /* NOTREACHED */
138 }
139
140 #if 0
141 if (strcmp(__progname, "swapoff") == 0) {
142 swapoff_command(argc, argv);
143 /* NOTREACHED */
144 }
145 #endif
146
147 while ((c = getopt(argc, argv, "ADUacdlkp:st:z")) != -1) {
148 switch (c) {
149 case 'A':
150 SET_COMMAND(CMD_A);
151 break;
152
153 case 'D':
154 SET_COMMAND(CMD_D);
155 break;
156
157 case 'U':
158 SET_COMMAND(CMD_U);
159 break;
160
161 case 'a':
162 SET_COMMAND(CMD_a);
163 break;
164
165 case 'c':
166 SET_COMMAND(CMD_c);
167 break;
168
169 case 'd':
170 SET_COMMAND(CMD_d);
171 break;
172
173 case 'l':
174 SET_COMMAND(CMD_l);
175 break;
176
177 case 'k':
178 kflag = 1;
179 break;
180
181 case 'p':
182 pflag = 1;
183 /* XXX strtol() */
184 pri = atoi(optarg);
185 break;
186
187 case 's':
188 SET_COMMAND(CMD_s);
189 break;
190
191 case 't':
192 if (tflag != NULL)
193 usage();
194 tflag = optarg;
195 break;
196
197 case 'z':
198 SET_COMMAND(CMD_z);
199 break;
200
201 default:
202 usage();
203 /* NOTREACHED */
204 }
205 }
206
207 /* Did the user specify a command? */
208 if (command == 0)
209 usage();
210
211 argv += optind;
212 argc -= optind;
213
214 switch (argc) {
215 case 0:
216 if (command & REQUIRE_PATH)
217 usage();
218 break;
219
220 case 1:
221 if (command & REQUIRE_NOPATH)
222 usage();
223 break;
224
225 default:
226 usage();
227 }
228
229 /* To change priority, you have to specify one. */
230 if ((command == CMD_c) && pflag == 0)
231 usage();
232
233 /* Sanity-check -t */
234 if (tflag != NULL) {
235 if (command != CMD_A && command != CMD_U)
236 usage();
237 if (strcmp(tflag, "blk") != 0 &&
238 strcmp(tflag, "noblk") != 0)
239 usage();
240 }
241
242 /* Dispatch the command. */
243 switch (command) {
244 case CMD_l:
245 list_swap(pri, kflag, pflag, 0, 1);
246 break;
247
248 case CMD_s:
249 list_swap(pri, kflag, pflag, 0, 0);
250 break;
251
252 case CMD_c:
253 change_priority(argv[0]);
254 break;
255
256 case CMD_a:
257 if (! add_swap(argv[0], pri))
258 exit(1);
259 break;
260
261 case CMD_d:
262 if (! delete_swap(argv[0]))
263 exit(1);
264 break;
265
266 case CMD_A:
267 do_fstab(1);
268 break;
269
270 case CMD_D:
271 set_dumpdev(argv[0]);
272 break;
273
274 case CMD_z:
275 get_dumpdev();
276 break;
277
278 case CMD_U:
279 do_fstab(0);
280 break;
281 }
282
283 exit(0);
284 }
285
286 /*
287 * swapon_command: emulate the old swapon(8) program.
288 */
289 static void
290 swapon_command(argc, argv)
291 int argc;
292 char **argv;
293 {
294 int ch, fiztab = 0;
295
296 while ((ch = getopt(argc, argv, "at:")) != -1) {
297 switch (ch) {
298 case 'a':
299 fiztab = 1;
300 break;
301 case 't':
302 if (tflag != NULL)
303 usage();
304 tflag = optarg;
305 break;
306 default:
307 goto swapon_usage;
308 }
309 }
310 argc -= optind;
311 argv += optind;
312
313 if (fiztab) {
314 if (argc)
315 goto swapon_usage;
316 /* Sanity-check -t */
317 if (tflag != NULL) {
318 if (strcmp(tflag, "blk") != 0 &&
319 strcmp(tflag, "noblk") != 0)
320 usage();
321 }
322 do_fstab(1);
323 exit(0);
324 } else if (argc == 0 || tflag != NULL)
325 goto swapon_usage;
326
327 while (argc) {
328 if (! add_swap(argv[0], pri))
329 exit(1);
330 argc--;
331 argv++;
332 }
333 exit(0);
334 /* NOTREACHED */
335
336 swapon_usage:
337 fprintf(stderr, "usage: %s -a [-t blk|noblk]\n", __progname);
338 fprintf(stderr, " %s <path> ...\n", __progname);
339 exit(1);
340 }
341
342 /*
343 * change_priority: change the priority of a swap device.
344 */
345 static void
346 change_priority(path)
347 const char *path;
348 {
349
350 if (swapctl(SWAP_CTL, path, pri) < 0)
351 warn("%s", path);
352 }
353
354 /*
355 * add_swap: add the pathname to the list of swap devices.
356 */
357 static int
358 add_swap(path, priority)
359 const char *path;
360 int priority;
361 {
362 struct stat sb;
363
364 if (stat(path, &sb) < 0)
365 goto oops;
366
367 if (sb.st_mode & S_IROTH)
368 warnx("%s is readable by the world", path);
369 if (sb.st_mode & S_IWOTH)
370 warnx("%s is writable by the world", path);
371
372 if (swapctl(SWAP_ON, path, priority) < 0) {
373 oops:
374 warn("%s", path);
375 return (0);
376 }
377 return (1);
378 }
379
380 /*
381 * delete_swap: remove the pathname to the list of swap devices.
382 */
383 static int
384 delete_swap(path)
385 const char *path;
386 {
387
388 if (swapctl(SWAP_OFF, path, pri) < 0) {
389 warn("%s", path);
390 return (0);
391 }
392 return (1);
393 }
394
395 static void
396 set_dumpdev(path)
397 const char *path;
398 {
399
400 if (swapctl(SWAP_DUMPDEV, path, NULL) == -1)
401 warn("could not set dump device to %s", path);
402 else
403 printf("%s: setting dump device to %s\n", __progname, path);
404 }
405
406 static void
407 get_dumpdev()
408 {
409 dev_t dev;
410 char *name;
411
412 if (swapctl(SWAP_GETDUMPDEV, &dev, NULL) == -1)
413 warn("could not get dump device");
414 else {
415 name = devname(dev, S_IFBLK);
416 printf("dump device is ");
417 if (name)
418 printf("%s\n", name);
419 else
420 printf("major %d minor %d\n", major(dev), minor(dev));
421 }
422 }
423
424 static void
425 do_fstab(add)
426 int add;
427 {
428 struct fstab *fp;
429 char *s;
430 long priority;
431 struct stat st;
432 int isblk;
433 int gotone = 0;
434 #define PATH_MOUNT "/sbin/mount_nfs"
435 #define PATH_UMOUNT "/sbin/umount"
436 char cmd[2*PATH_MAX+sizeof(PATH_MOUNT)+2];
437
438 #define PRIORITYEQ "priority="
439 #define NFSMNTPT "nfsmntpt="
440 while ((fp = getfsent()) != NULL) {
441 const char *spec;
442
443 spec = fp->fs_spec;
444 cmd[0] = '\0';
445
446 if (strcmp(fp->fs_type, "dp") == 0 && add) {
447 set_dumpdev(spec);
448 continue;
449 }
450
451 if (strcmp(fp->fs_type, "sw") != 0)
452 continue;
453 isblk = 0;
454
455 if ((s = strstr(fp->fs_mntops, PRIORITYEQ)) != NULL) {
456 s += sizeof(PRIORITYEQ) - 1;
457 priority = atol(s);
458 } else
459 priority = pri;
460
461 if ((s = strstr(fp->fs_mntops, NFSMNTPT)) != NULL) {
462 char *t;
463
464 /*
465 * Skip this song and dance if we're only
466 * doing block devices.
467 */
468 if (tflag != NULL && strcmp(tflag, "blk") == 0)
469 continue;
470
471 t = strpbrk(s, ",");
472 if (t != 0)
473 *t = '\0';
474 spec = strdup(s + strlen(NFSMNTPT));
475 if (t != 0)
476 *t = ',';
477
478 if (spec == NULL)
479 errx(1, "Out of memory");
480
481 if (strlen(spec) == 0) {
482 warnx("empty mountpoint");
483 free((char *)spec);
484 continue;
485 }
486 if (add) {
487 snprintf(cmd, sizeof(cmd), "%s %s %s",
488 PATH_MOUNT, fp->fs_spec, spec);
489 if (system(cmd) != 0) {
490 warnx("%s: mount failed", fp->fs_spec);
491 continue;
492 }
493 } else {
494 snprintf(cmd, sizeof(cmd), "%s %s",
495 PATH_UMOUNT, fp->fs_spec);
496 }
497 } else {
498 /*
499 * Determine blk-ness.
500 */
501 if (stat(spec, &st) < 0) {
502 warn("%s", spec);
503 continue;
504 }
505 if (S_ISBLK(st.st_mode))
506 isblk = 1;
507 }
508
509 /*
510 * Skip this type if we're told to.
511 */
512 if (tflag != NULL) {
513 if (strcmp(tflag, "blk") == 0 && isblk == 0)
514 continue;
515 if (strcmp(tflag, "noblk") == 0 && isblk == 1)
516 continue;
517 }
518
519 if (add) {
520 if (add_swap(spec, (int)priority)) {
521 gotone = 1;
522 printf(
523 "%s: adding %s as swap device at priority %d\n",
524 __progname, fp->fs_spec, (int)priority);
525 }
526 } else {
527 if (delete_swap(spec)) {
528 gotone = 1;
529 printf(
530 "%s: removing %s as swap device\n",
531 __progname, fp->fs_spec);
532 }
533 if (cmd[0]) {
534 if (system(cmd) != 0) {
535 warnx("%s: umount failed", fp->fs_spec);
536 continue;
537 }
538 }
539 }
540
541 if (spec != fp->fs_spec)
542 free((char *)spec);
543 }
544 if (gotone == 0)
545 exit(1);
546 }
547
548 static void
549 usage()
550 {
551
552 fprintf(stderr, "usage: %s -A [-p priority] [-t blk|noblk]\n",
553 __progname);
554 fprintf(stderr, " %s -D dumppath\n", __progname);
555 fprintf(stderr, " %s -U [-t blk|noblk]\n", __progname);
556 fprintf(stderr, " %s -a [-p priority] path\n", __progname);
557 fprintf(stderr, " %s -c -p priority path\n", __progname);
558 fprintf(stderr, " %s -d path\n", __progname);
559 fprintf(stderr, " %s -l | -s [-k]\n", __progname);
560 exit(1);
561 }
562