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