GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/swapctl/swapctl.c Lines: 0 163 0.0 %
Date: 2016-12-06 Branches: 0 148 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: swapctl.c,v 1.23 2016/03/17 19:40:43 krw 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
69
int	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) \
82
do { \
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
 */
98
int	kflag;		/* display in 1K blocks */
99
#define	KFLAG_CMDS	(CMD_l | CMD_s)
100
101
int	pflag;		/* priority was specified */
102
#define	PFLAG_CMDS	(CMD_A | CMD_a | CMD_c)
103
104
char	*tflag;		/* swap device type (blk or noblk) */
105
#define	TFLAG_CMDS	(CMD_A)
106
107
int	pri;		/* uses 0 as default pri */
108
109
static	void change_priority(char *);
110
static	void add_swap(char *);
111
static	void del_swap(char *);
112
static	void do_fstab(void);
113
static	void usage(void);
114
static	int  swapon_command(int, char **);
115
116
extern	char *__progname;	/* from crt0.o */
117
118
int
119
main(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
 */
248
int
249
swapon_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
 */
299
void
300
change_priority(char *path)
301
{
302
303
	if (swapctl(SWAP_CTL, path, pri) < 0)
304
		warn("%s", path);
305
}
306
307
/*
308
 * add_swap:  add the pathname to the list of swap devices.
309
 */
310
void
311
add_swap(char *path)
312
{
313
314
	if (swapctl(SWAP_ON, path, pri) < 0)
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
 */
322
void
323
del_swap(char *path)
324
{
325
326
	if (swapctl(SWAP_OFF, path, pri) < 0)
327
		err(1, "%s", path);
328
}
329
330
void
331
do_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) < 0)
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) < 0) {
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) < 0) {
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
456
void
457
usage(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
}