xref: /freebsd/sbin/swapon/swapon.c (revision 2227a3e9e1a0bcba8481a8067ee8c4b9a96fdda3)
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;
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, "AadghklmsU")) != -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 's':
121 			sflag = 1;
122 			break;
123 		case 'U':
124 			if (which_prog == SWAPCTL) {
125 				doall = 1;
126 				which_prog = SWAPOFF;
127 			} else {
128 				usage();
129 			}
130 			break;
131 		case '?':
132 		default:
133 			usage();
134 		}
135 	}
136 	argv += optind;
137 
138 	stat = 0;
139 	if (which_prog == SWAPON || which_prog == SWAPOFF) {
140 		if (doall) {
141 			while ((fsp = getfsent()) != NULL) {
142 				if (strcmp(fsp->fs_type, FSTAB_SW))
143 					continue;
144 				if (strstr(fsp->fs_mntops, "noauto"))
145 					continue;
146 				if (swap_on_off(fsp->fs_spec, 1)) {
147 					stat = 1;
148 				} else {
149 					printf("%s: %sing %s as swap device\n",
150 					    getprogname(), which_prog == SWAPOFF ? "remov" : "add",
151 					    fsp->fs_spec);
152 				}
153 			}
154 		}
155 		else if (!*argv)
156 			usage();
157 		for (; *argv; ++argv) {
158 			if (swap_on_off(*argv, 0)) {
159 				stat = 1;
160 			} else if (orig_prog == SWAPCTL) {
161 				printf("%s: %sing %s as swap device\n",
162 				    getprogname(), which_prog == SWAPOFF ? "remov" : "add",
163 				    *argv);
164 			}
165 		}
166 	} else {
167 		if (lflag || sflag)
168 			swaplist(lflag, sflag, hflag);
169 		else
170 			usage();
171 	}
172 	exit(stat);
173 }
174 
175 static int
176 swap_on_off(char *name, int doingall)
177 {
178 	if ((which_prog == SWAPOFF ? swapoff(name) : swapon(name)) == -1) {
179 		switch (errno) {
180 		case EBUSY:
181 			if (!doingall)
182 				warnx("%s: device already in use", name);
183 			break;
184 		case EINVAL:
185 			if (which_prog == SWAPON)
186 				warnx("%s: NSWAPDEV limit reached", name);
187 			else if (!doingall)
188 				warn("%s", name);
189 			break;
190 		default:
191 			warn("%s", name);
192 			break;
193 		}
194 		return(1);
195 	}
196 	return(0);
197 }
198 
199 static void
200 usage(void)
201 {
202 	fprintf(stderr, "usage: %s ", getprogname());
203 	switch(orig_prog) {
204 	case SWAPON:
205 	case SWAPOFF:
206 	    fprintf(stderr, "-a | file ...\n");
207 	    break;
208 	case SWAPCTL:
209 	    fprintf(stderr, "[-AghklmsU] [-a file ... | -d file ...]\n");
210 	    break;
211 	}
212 	exit(1);
213 }
214 
215 static void
216 sizetobuf(char *buf, size_t bufsize, int hflag, long long val, int hlen,
217     long blocksize)
218 {
219 
220 	if (hflag == 'H') {
221 		char tmp[16];
222 
223 		humanize_number(tmp, 5, (int64_t)val, "", HN_AUTOSCALE,
224 		    HN_B | HN_NOSPACE | HN_DECIMAL);
225 		snprintf(buf, bufsize, "%*s", hlen, tmp);
226 	} else {
227 		snprintf(buf, bufsize, "%*lld", hlen, val / blocksize);
228 	}
229 }
230 
231 static void
232 swaplist(int lflag, int sflag, int hflag)
233 {
234 	size_t mibsize, size;
235 	struct xswdev xsw;
236 	int hlen, mib[16], n, pagesize;
237 	long blocksize;
238 	long long total = 0;
239 	long long used = 0;
240 	long long tmp_total;
241 	long long tmp_used;
242 	char buf[32];
243 
244 	pagesize = getpagesize();
245 	switch(hflag) {
246 	case 'G':
247 	    blocksize = 1024 * 1024 * 1024;
248 	    strlcpy(buf, "1GB-blocks", sizeof(buf));
249 	    hlen = 10;
250 	    break;
251 	case 'H':
252 	    blocksize = -1;
253 	    strlcpy(buf, "Bytes", sizeof(buf));
254 	    hlen = 10;
255 	    break;
256 	case 'K':
257 	    blocksize = 1024;
258 	    strlcpy(buf, "1kB-blocks", sizeof(buf));
259 	    hlen = 10;
260 	    break;
261 	case 'M':
262 	    blocksize = 1024 * 1024;
263 	    strlcpy(buf, "1MB-blocks", sizeof(buf));
264 	    hlen = 10;
265 	    break;
266 	default:
267 	    getbsize(&hlen, &blocksize);
268 	    snprintf(buf, sizeof(buf), "%ld-blocks", blocksize);
269 	    break;
270 	}
271 
272 	mibsize = sizeof mib / sizeof mib[0];
273 	if (sysctlnametomib("vm.swap_info", mib, &mibsize) == -1)
274 		err(1, "sysctlnametomib()");
275 
276 	if (lflag) {
277 		printf("%-13s %*s %*s\n",
278 		    "Device:",
279 		    hlen, buf,
280 		    hlen, "Used:");
281 	}
282 
283 	for (n = 0; ; ++n) {
284 		mib[mibsize] = n;
285 		size = sizeof xsw;
286 		if (sysctl(mib, mibsize + 1, &xsw, &size, NULL, 0) == -1)
287 			break;
288 		if (xsw.xsw_version != XSWDEV_VERSION)
289 			errx(1, "xswdev version mismatch");
290 
291 		tmp_total = (long long)xsw.xsw_nblks * pagesize;
292 		tmp_used  = (long long)xsw.xsw_used * pagesize;
293 		total += tmp_total;
294 		used  += tmp_used;
295 		if (lflag) {
296 			sizetobuf(buf, sizeof(buf), hflag, tmp_total, hlen,
297 			    blocksize);
298 			printf("/dev/%-8s %s ", devname(xsw.xsw_dev, S_IFCHR),
299 			    buf);
300 			sizetobuf(buf, sizeof(buf), hflag, tmp_used, hlen,
301 			    blocksize);
302 			printf("%s\n", buf);
303 		}
304 	}
305 	if (errno != ENOENT)
306 		err(1, "sysctl()");
307 
308 	if (sflag) {
309 		sizetobuf(buf, sizeof(buf), hflag, total, hlen, blocksize);
310 		printf("Total:        %s ", buf);
311 		sizetobuf(buf, sizeof(buf), hflag, used, hlen, blocksize);
312 		printf("%s\n", buf);
313 	}
314 }
315 
316