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