xref: /freebsd/sbin/swapon/swapon.c (revision f9218d3d4fd34f082473b3a021c6d4d109fb47cf)
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 
34 #ifndef lint
35 static const char copyright[] =
36 "@(#) Copyright (c) 1980, 1993\n\
37 	The Regents of the University of California.  All rights reserved.\n";
38 #endif /* not lint */
39 
40 #ifndef lint
41 #if 0
42 static char sccsid[] = "@(#)swapon.c	8.1 (Berkeley) 6/5/93";
43 #endif
44 static const char rcsid[] =
45   "$FreeBSD$";
46 #endif /* not lint */
47 
48 #include <sys/stat.h>
49 #include <sys/param.h>
50 #include <sys/user.h>
51 #include <sys/sysctl.h>
52 
53 #include <err.h>
54 #include <errno.h>
55 #include <fstab.h>
56 #include <stdio.h>
57 #include <stdlib.h>
58 #include <string.h>
59 #include <unistd.h>
60 #include <fcntl.h>
61 
62 static void usage(void);
63 static int swap_on_off(char *name, int ignoreebusy);
64 static void swaplist(int, int, int);
65 
66 enum { SWAPON, SWAPOFF, SWAPCTL } orig_prog, which_prog = SWAPCTL;
67 
68 int
69 main(int argc, char **argv)
70 {
71 	struct fstab *fsp;
72 	char *ptr;
73 	int stat;
74 	int ch, doall;
75 	int sflag = 0, lflag = 0, hflag = 0;
76 
77 	if ((ptr = strrchr(argv[0], '/')) == NULL)
78 		ptr = argv[0];
79 	if (strstr(ptr, "swapon"))
80 		which_prog = SWAPON;
81 	else if (strstr(ptr, "swapoff"))
82 		which_prog = SWAPOFF;
83 	orig_prog = which_prog;
84 
85 	doall = 0;
86 	while ((ch = getopt(argc, argv, "AadlhksU")) != -1) {
87 		switch(ch) {
88 		case 'A':
89 			if (which_prog == SWAPCTL) {
90 				doall = 1;
91 				which_prog = SWAPON;
92 			} else {
93 				usage();
94 			}
95 			break;
96 		case 'a':
97 			if (which_prog == SWAPON || which_prog == SWAPOFF)
98 				doall = 1;
99 			else
100 				which_prog = SWAPON;
101 			break;
102 		case 'd':
103 			if (which_prog == SWAPCTL)
104 				which_prog = SWAPOFF;
105 			else
106 				usage();
107 			break;
108 		case 's':
109 			sflag = 1;
110 			break;
111 		case 'l':
112 			lflag = 1;
113 			break;
114 		case 'h':
115 			hflag = 'M';
116 			break;
117 		case 'k':
118 			hflag = 'K';
119 			break;
120 		case 'U':
121 			if (which_prog == SWAPCTL) {
122 				doall = 1;
123 				which_prog = SWAPOFF;
124 			} else {
125 				usage();
126 			}
127 			break;
128 		case '?':
129 		default:
130 			usage();
131 		}
132 	}
133 	argv += optind;
134 
135 	stat = 0;
136 	if (which_prog == SWAPON || which_prog == SWAPOFF) {
137 		if (doall) {
138 			while ((fsp = getfsent()) != NULL) {
139 				if (strcmp(fsp->fs_type, FSTAB_SW))
140 					continue;
141 				if (strstr(fsp->fs_mntops, "noauto"))
142 					continue;
143 				if (swap_on_off(fsp->fs_spec, 1)) {
144 					stat = 1;
145 				} else {
146 					printf("%s: %sing %s as swap device\n",
147 					    getprogname(), which_prog == SWAPOFF ? "remov" : "add",
148 					    fsp->fs_spec);
149 				}
150 			}
151 		}
152 		else if (!*argv)
153 			usage();
154 		for (; *argv; ++argv) {
155 			if (swap_on_off(*argv, 0)) {
156 				stat = 1;
157 			} else if (orig_prog == SWAPCTL) {
158 				printf("%s: %sing %s as swap device\n",
159 				    getprogname(), which_prog == SWAPOFF ? "remov" : "add",
160 				    *argv);
161 			}
162 		}
163 	} else {
164 		if (lflag || sflag)
165 			swaplist(lflag, sflag, hflag);
166 		else
167 			usage();
168 	}
169 	exit(stat);
170 }
171 
172 static int
173 swap_on_off(char *name, int doingall)
174 {
175 	if ((which_prog == SWAPOFF ? swapoff(name) : swapon(name)) == -1) {
176 		switch (errno) {
177 		case EBUSY:
178 			if (!doingall)
179 				warnx("%s: device already in use", name);
180 			break;
181 		case EINVAL:
182 			if (which_prog == SWAPON)
183 				warnx("%s: NSWAPDEV limit reached", name);
184 			else if (!doingall)
185 				warn("%s", name);
186 			break;
187 		default:
188 			warn("%s", name);
189 			break;
190 		}
191 		return(1);
192 	}
193 	return(0);
194 }
195 
196 static void
197 usage(void)
198 {
199 	fprintf(stderr, "usage: %s ", getprogname());
200 	switch(orig_prog) {
201 	case SWAPOFF:
202 	    fprintf(stderr, "[-a] [special_file ...]\n");
203 	    break;
204 	case SWAPON:
205 	    fprintf(stderr, "[-a] [special_file ...]\n");
206 	    break;
207 	case SWAPCTL:
208 	    fprintf(stderr, "[-lshAU] [-a/-d special_file ...]\n");
209 	    break;
210 	}
211 	exit(1);
212 }
213 
214 static void
215 swaplist(int lflag, int sflag, int hflag)
216 {
217 	size_t mibsize, size;
218 	struct xswdev xsw;
219 	int hlen, mib[16], n, pagesize;
220 	long blocksize;
221 	long long total = 0;
222 	long long used = 0;
223 	long long tmp_total;
224 	long long tmp_used;
225 
226 	pagesize = getpagesize();
227 	switch(hflag) {
228 	case 'K':
229 	    blocksize = 1024;
230 	    hlen = 10;
231 	    break;
232 	case 'M':
233 	    blocksize = 1024 * 1024;
234 	    hlen = 10;
235 	    break;
236 	default:
237 	    getbsize(&hlen, &blocksize);
238 	    break;
239 	}
240 
241 	mibsize = sizeof mib / sizeof mib[0];
242 	if (sysctlnametomib("vm.swap_info", mib, &mibsize) == -1)
243 		err(1, "sysctlnametomib()");
244 
245 	if (lflag) {
246 		char buf[32];
247 		snprintf(buf, sizeof(buf), "%ld-blocks", blocksize);
248 		printf("%-13s %*s %*s\n",
249 		    "Device:",
250 		    hlen, buf,
251 		    hlen, "Used:");
252 	}
253 
254 	for (n = 0; ; ++n) {
255 		mib[mibsize] = n;
256 		size = sizeof xsw;
257 		if (sysctl(mib, mibsize + 1, &xsw, &size, NULL, NULL) == -1)
258 			break;
259 		if (xsw.xsw_version != XSWDEV_VERSION)
260 			errx(1, "xswdev version mismatch");
261 
262 		tmp_total = (long long)xsw.xsw_nblks * pagesize / blocksize;
263 		tmp_used  = (long long)xsw.xsw_used * pagesize / blocksize;
264 		total += tmp_total;
265 		used  += tmp_used;
266 		if (lflag) {
267 			printf("/dev/%-8s %*lld %*lld\n",
268 			    devname(xsw.xsw_dev, S_IFCHR),
269 			    hlen, tmp_total,
270 			    hlen, tmp_used);
271 		}
272 	}
273 	if (errno != ENOENT)
274 		err(1, "sysctl()");
275 
276 	if (sflag) {
277 		printf("Total:        %*lld %*lld\n",
278 		       hlen, total,
279 		       hlen, used);
280 	}
281 }
282 
283