xref: /dragonfly/sbin/swapon/swapon.c (revision 10cbe914)
1 /*
2  * Copyright (c) 1980, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * @(#) Copyright (c) 1980, 1993 The Regents of the University of California.  All rights reserved.
34  * @(#)swapon.c	8.1 (Berkeley) 6/5/93
35  * $FreeBSD: src/sbin/swapon/swapon.c,v 1.8.2.2 2001/07/30 10:30:11 dd Exp $
36  * $DragonFly: src/sbin/swapon/swapon.c,v 1.5 2005/11/06 12:50:21 swildner Exp $
37  */
38 
39 #include <sys/param.h>
40 #include <sys/stat.h>
41 #include <sys/sysctl.h>
42 #include <vm/vm_param.h>
43 
44 #include <err.h>
45 #include <errno.h>
46 #include <fstab.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <unistd.h>
51 #include <fcntl.h>
52 #include <libutil.h>
53 
54 static void usage(void);
55 static int swap_on_off(char *name, int doingall);
56 static void swaplist(int lflag, int sflag, int hflag);
57 
58 enum { SWAPON, SWAPOFF, SWAPCTL } orig_prog, which_prog = SWAPCTL;
59 
60 int
61 main(int argc, char **argv)
62 {
63 	struct fstab *fsp;
64 	char *ptr;
65 	int ret;
66 	int ch;
67 	int doall, sflag, lflag, hflag, qflag;
68 
69 	if ((ptr = strrchr(argv[0], '/')) == NULL)
70 		ptr = argv[0];
71 	if (strstr(ptr, "swapon"))
72 		which_prog = SWAPON;
73 	else if (strstr(ptr, "swapoff"))
74 		which_prog = SWAPOFF;
75 	orig_prog = which_prog;
76 
77 	sflag = lflag = hflag = qflag = doall = 0;
78 	while ((ch = getopt(argc, argv, "AadghklmqsU")) != -1) {
79 		switch((char)ch) {
80 		case 'A':
81 			if (which_prog == SWAPCTL) {
82 				doall = 1;
83 				which_prog = SWAPON;
84 			} else {
85 				usage();
86 			}
87 			break;
88 		case 'a':
89 			if (which_prog == SWAPON || which_prog == SWAPOFF)
90 				doall = 1;
91 			else
92 				which_prog = SWAPON;
93 			break;
94 		case 'd':
95 			if (which_prog == SWAPCTL)
96 				which_prog = SWAPOFF;
97 			else
98 				usage();
99 			break;
100 		case 'g':
101 			hflag = 'G';
102 			break;
103 		case 'h':
104 			hflag = 'H';
105 			break;
106 		case 'k':
107 			hflag = 'K';
108 			break;
109 		case 'l':
110 			lflag = 1;
111 			break;
112 		case 'm':
113 			hflag = 'M';
114 			break;
115 		case 'q':
116 			if (which_prog == SWAPON || which_prog == SWAPOFF)
117 				qflag = 1;
118 			break;
119 		case 's':
120 			sflag = 1;
121 			break;
122 		case 'U':
123 			if (which_prog == SWAPCTL) {
124 				doall = 1;
125 				which_prog = SWAPOFF;
126 			} else {
127 				usage();
128 			}
129 			break;
130 		case '?':
131 		default:
132 			usage();
133 		}
134 	}
135 	argv += optind;
136 
137 	ret = 0;
138 	if (which_prog == SWAPON || which_prog == SWAPOFF) {
139 		if (doall) {
140 			while ((fsp = getfsent()) != NULL) {
141 				if (strcmp(fsp->fs_type, FSTAB_SW))
142 					continue;
143 				if (strstr(fsp->fs_mntops, "noauto"))
144 					continue;
145 				if (swap_on_off(fsp->fs_spec, 1)) {
146 					ret = 1;
147 				} else {
148 					if (!qflag) {
149 						printf("%s: %sing %s as swap device\n",
150 						    getprogname(),
151 						    which_prog == SWAPOFF ? "remov" : "add",
152 						    fsp->fs_spec);
153 					}
154 				}
155 			}
156 		} else if (*argv == NULL) {
157 			usage();
158 		}
159 		for (; *argv; ++argv) {
160 			if (swap_on_off(getdevpath(*argv, 0), 0)) {
161 				ret = 1;
162 			} else if (orig_prog == SWAPCTL) {
163 				printf("%s: %sing %s as swap device\n",
164 				    getprogname(),
165 				    which_prog == SWAPOFF ? "remov" : "add",
166 				    *argv);
167 			}
168 		}
169 	} else {
170 		if (lflag || sflag)
171 			swaplist(lflag, sflag, hflag);
172 		else
173 			usage();
174 	}
175 	exit(ret);
176 }
177 
178 static int
179 swap_on_off(char *name, int doingall)
180 {
181 	if ((which_prog == SWAPOFF ? swapoff(name) : swapon(name)) == -1) {
182 		switch(errno) {
183 		case EBUSY:
184 			if (!doingall)
185 				warnx("%s: device already in use", name);
186 			break;
187 		case EINVAL:
188 			if (which_prog == SWAPON)
189 				warnx("%s: NSWAPDEV limit reached", name);
190 			else if (!doingall)
191 				warn("%s", name);
192 			break;
193 		default:
194 			warn("%s", name);
195 			break;
196 		}
197 		return(1);
198 	}
199 	return(0);
200 }
201 
202 static void
203 usage(void)
204 {
205 	fprintf(stderr, "usage: %s ", getprogname());
206 	switch (orig_prog) {
207 	case SWAPON:
208 	case SWAPOFF:
209 		fprintf(stderr, "-aq | file ...\n");
210 		break;
211 	case SWAPCTL:
212 		fprintf(stderr, "[-AghklmsU] [-a file ... | -d file ...]\n");
213 		break;
214 	}
215 	exit(1);
216 }
217 
218 static void
219 sizetobuf(char *buf, size_t bufsize, int hflag, long long val, int hlen,
220     long blocksize)
221 {
222 	if (hflag == 'H') {
223 		char tmp[16];
224 
225 		humanize_number(tmp, 5, (int64_t)val, "", HN_AUTOSCALE,
226 		    HN_B | HN_NOSPACE | HN_DECIMAL);
227 		snprintf(buf, bufsize, "%*s", hlen, tmp);
228 	} else {
229 		snprintf(buf, bufsize, "%*lld", hlen, val / blocksize);
230 	}
231 }
232 
233 static void
234 swaplist(int lflag, int sflag, int hflag)
235 {
236 	size_t ksize, bytes = 0;
237 	char *xswbuf;
238 	struct xswdev *xsw;
239 	int hlen, pagesize;
240 	int i, n;
241 	long blocksize;
242 	long long total, used, tmp_total, tmp_used;
243 	char buf[32];
244 
245 	pagesize = getpagesize();
246 	switch(hflag) {
247 	case 'G':
248 		blocksize = 1024 * 1024 * 1024;
249 		strlcpy(buf, "1GB-blocks", sizeof(buf));
250 		hlen = 10;
251 		break;
252 	case 'H':
253 		blocksize = -1;
254 		strlcpy(buf, "Bytes", sizeof(buf));
255 		hlen = 10;
256 		break;
257 	case 'K':
258 		blocksize = 1024;
259 		strlcpy(buf, "1kB-blocks", sizeof(buf));
260 		hlen = 10;
261 		break;
262 	case 'M':
263 		blocksize = 1024 * 1024;
264 		strlcpy(buf, "1MB-blocks", sizeof(buf));
265 		hlen = 10;
266 		break;
267 	default:
268 		getbsize(&hlen, &blocksize);
269 		snprintf(buf, sizeof(buf), "%ld-blocks", blocksize);
270 		break;
271 	}
272 
273 	if (sysctlbyname("vm.swap_info_array", NULL, &bytes, NULL, 0) < 0)
274 		err(1, "sysctlbyname()");
275 	if (bytes == 0)
276 		err(1, "sysctlbyname()");
277 
278 	xswbuf = malloc(bytes);
279 	if (sysctlbyname("vm.swap_info_array", xswbuf, &bytes, NULL, 0) < 0) {
280 		free(xswbuf);
281 		err(1, "sysctlbyname()");
282 	}
283 	if (bytes == 0) {
284 		free(xswbuf);
285 		err(1, "sysctlbyname()");
286 	}
287 
288 	/*
289 	 * Calculate size of xsw entry returned by kernel (it can be larger
290 	 * than the one we have if there is a version mismatch).
291 	 */
292 	ksize = ((struct xswdev *)xswbuf)->xsw_size;
293 	n = (int)(bytes / ksize);
294 
295 	if (lflag) {
296 		printf("%-13s %*s %*s\n",
297 		    "Device:",
298 		    hlen, buf,
299 		    hlen, "Used:");
300 	}
301 
302 	total = used = tmp_total = tmp_used = 0;
303 	for (i = 0; i < n; ++i) {
304 		xsw = (void *)((char *)xswbuf + i * ksize);
305 
306 		if (xsw->xsw_nblks == 0)
307 			continue;
308 
309 		if (sflag) {
310 			tmp_total = (long long)xsw->xsw_nblks * pagesize;
311 			tmp_used = (long long)xsw->xsw_used * pagesize;
312 			total += tmp_total;
313 			used += tmp_used;
314 		}
315 
316 		if (lflag) {
317 			sizetobuf(buf, sizeof(buf), hflag, tmp_total, hlen,
318 			    blocksize);
319 			if (xsw->xsw_dev == NODEV) {
320 				printf("%-13s %s ", "[NFS swap]", buf);
321 			} else {
322 				printf("/dev/%-8s %s ",
323 				    devname(xsw->xsw_dev, S_IFCHR), buf);
324 			}
325 
326 			sizetobuf(buf, sizeof(buf), hflag, tmp_used, hlen,
327 			    blocksize);
328 			printf("%s\n", buf);
329 		}
330 	}
331 
332 	if (sflag) {
333 		sizetobuf(buf, sizeof(buf), hflag, total, hlen, blocksize);
334 		printf("Total:        %s ", buf);
335 		sizetobuf(buf, sizeof(buf), hflag, used, hlen, blocksize);
336 		printf("%s\n", buf);
337 	}
338 }
339