7dbfcf9aaefe1d82382e7fecdbabc915ba7283e9
[dragonfly.git] / sbin / swapon / swapon.c
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  */
37
38 #include <sys/param.h>
39 #include <sys/stat.h>
40 #include <sys/sysctl.h>
41 #include <vm/vm_param.h>
42
43 #include <err.h>
44 #include <errno.h>
45 #include <fstab.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <unistd.h>
50 #include <fcntl.h>
51 #include <libutil.h>
52
53 static void usage(void);
54 static int swap_on_off(char *name, int doingall);
55 static void swaplist(int lflag, int sflag, int hflag);
56
57 enum { SWAPON, SWAPOFF, SWAPCTL } orig_prog, which_prog = SWAPCTL;
58
59 int
60 main(int argc, char **argv)
61 {
62         struct fstab *fsp;
63         char *ptr;
64         int ret;
65         int ch;
66         int doall, sflag, lflag, hflag, qflag;
67
68         if ((ptr = strrchr(argv[0], '/')) == NULL)
69                 ptr = argv[0];
70         if (strstr(ptr, "swapon"))
71                 which_prog = SWAPON;
72         else if (strstr(ptr, "swapoff"))
73                 which_prog = SWAPOFF;
74         orig_prog = which_prog;
75
76         sflag = lflag = hflag = qflag = doall = 0;
77         while ((ch = getopt(argc, argv, "AadghklmqsU")) != -1) {
78                 switch((char)ch) {
79                 case 'A':
80                         if (which_prog == SWAPCTL) {
81                                 doall = 1;
82                                 which_prog = SWAPON;
83                         } else {
84                                 usage();
85                         }
86                         break;
87                 case 'a':
88                         if (which_prog == SWAPON || which_prog == SWAPOFF)
89                                 doall = 1;
90                         else
91                                 which_prog = SWAPON;
92                         break;
93                 case 'd':
94                         if (which_prog == SWAPCTL)
95                                 which_prog = SWAPOFF;
96                         else
97                                 usage();
98                         break;
99                 case 'g':
100                         hflag = 'G';
101                         break;
102                 case 'h':
103                         hflag = 'H';
104                         break;
105                 case 'k':
106                         hflag = 'K';
107                         break;
108                 case 'l':
109                         lflag = 1;
110                         break;
111                 case 'm':
112                         hflag = 'M';
113                         break;
114                 case 'q':
115                         if (which_prog == SWAPON || which_prog == SWAPOFF)
116                                 qflag = 1;
117                         break;
118                 case 's':
119                         sflag = 1;
120                         break;
121                 case 'U':
122                         if (which_prog == SWAPCTL) {
123                                 doall = 1;
124                                 which_prog = SWAPOFF;
125                         } else {
126                                 usage();
127                         }
128                         break;
129                 case '?':
130                 default:
131                         usage();
132                 }
133         }
134         argv += optind;
135
136         ret = 0;
137         if (which_prog == SWAPON || which_prog == SWAPOFF) {
138                 if (doall) {
139                         while ((fsp = getfsent()) != NULL) {
140                                 if (strcmp(fsp->fs_type, FSTAB_SW))
141                                         continue;
142                                 if (strstr(fsp->fs_mntops, "noauto"))
143                                         continue;
144                                 if (swap_on_off(fsp->fs_spec, 1)) {
145                                         ret = 1;
146                                 } else {
147                                         if (!qflag) {
148                                                 printf("%s: %sing %s as swap device\n",
149                                                     getprogname(),
150                                                     which_prog == SWAPOFF ? "remov" : "add",
151                                                     fsp->fs_spec);
152                                         }
153                                 }
154                         }
155                 } else if (*argv == NULL) {
156                         usage();
157                 }
158                 for (; *argv; ++argv) {
159                         if (swap_on_off(getdevpath(*argv, 0), 0)) {
160                                 ret = 1;
161                         } else if (orig_prog == SWAPCTL) {
162                                 printf("%s: %sing %s as swap device\n",
163                                     getprogname(),
164                                     which_prog == SWAPOFF ? "remov" : "add",
165                                     *argv);
166                         }
167                 }
168         } else {
169                 if (lflag || sflag)
170                         swaplist(lflag, sflag, hflag);
171                 else
172                         usage();
173         }
174         exit(ret);
175 }
176
177 static int
178 swap_on_off(char *name, int doingall)
179 {
180         if ((which_prog == SWAPOFF ? swapoff(name) : swapon(name)) == -1) {
181                 switch(errno) {
182                 case EBUSY:
183                         if (!doingall)
184                                 warnx("%s: device already in use", name);
185                         break;
186                 case EINVAL:
187                         if (which_prog == SWAPON)
188                                 warnx("%s: NSWAPDEV limit reached", name);
189                         else if (!doingall)
190                                 warn("%s", name);
191                         break;
192                 default:
193                         warn("%s", name);
194                         break;
195                 }
196                 return(1);
197         }
198         return(0);
199 }
200
201 static void
202 usage(void)
203 {
204         fprintf(stderr, "usage: %s ", getprogname());
205         switch (orig_prog) {
206         case SWAPON:
207         case SWAPOFF:
208                 fprintf(stderr, "-aq | file ...\n");
209                 break;
210         case SWAPCTL:
211                 fprintf(stderr, "[-AghklmsU] [-a file ... | -d file ...]\n");
212                 break;
213         }
214         exit(1);
215 }
216
217 static void
218 sizetobuf(char *buf, size_t bufsize, int hflag, long long val, int hlen,
219     long blocksize)
220 {
221         if (hflag == 'H') {
222                 char tmp[16];
223
224                 humanize_number(tmp, 5, (int64_t)val, "", HN_AUTOSCALE,
225                     HN_B | HN_NOSPACE | HN_DECIMAL);
226                 snprintf(buf, bufsize, "%*s", hlen, tmp);
227         } else {
228                 snprintf(buf, bufsize, "%*lld", hlen, val / blocksize);
229         }
230 }
231
232 static void
233 swaplist(int lflag, int sflag, int hflag)
234 {
235         size_t ksize, bytes = 0;
236         char *xswbuf;
237         struct xswdev *xsw;
238         int hlen, pagesize;
239         int i, n;
240         long blocksize;
241         long long total, used, tmp_total, 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         if (sysctlbyname("vm.swap_info_array", NULL, &bytes, NULL, 0) < 0)
273                 err(1, "sysctlbyname()");
274         if (bytes == 0)
275                 err(1, "sysctlbyname()");
276
277         xswbuf = malloc(bytes);
278         if (sysctlbyname("vm.swap_info_array", xswbuf, &bytes, NULL, 0) < 0) {
279                 free(xswbuf);
280                 err(1, "sysctlbyname()");
281         }
282         if (bytes == 0) {
283                 free(xswbuf);
284                 err(1, "sysctlbyname()");
285         }
286
287         /*
288          * Calculate size of xsw entry returned by kernel (it can be larger
289          * than the one we have if there is a version mismatch).
290          */
291         ksize = ((struct xswdev *)xswbuf)->xsw_size;
292         n = (int)(bytes / ksize);
293
294         if (lflag) {
295                 printf("%-13s %*s %*s\n",
296                     "Device:",
297                     hlen, buf,
298                     hlen, "Used:");
299         }
300
301         total = used = tmp_total = tmp_used = 0;
302         for (i = 0; i < n; ++i) {
303                 xsw = (void *)((char *)xswbuf + i * ksize);
304
305                 if (xsw->xsw_nblks == 0)
306                         continue;
307
308                 tmp_total = (long long)xsw->xsw_nblks * pagesize;
309                 tmp_used = (long long)xsw->xsw_used * pagesize;
310                 total += tmp_total;
311                 used += tmp_used;
312                 if (lflag) {
313                         sizetobuf(buf, sizeof(buf), hflag, tmp_total, hlen,
314                             blocksize);
315                         if (xsw->xsw_dev == NODEV) {
316                                 printf("%-13s %s ", "[NFS swap]", buf);
317                         } else {
318                                 printf("/dev/%-8s %s ",
319                                     devname(xsw->xsw_dev, S_IFCHR), buf);
320                         }
321
322                         sizetobuf(buf, sizeof(buf), hflag, tmp_used, hlen,
323                             blocksize);
324                         printf("%s\n", buf);
325                 }
326         }
327
328         if (sflag) {
329                 sizetobuf(buf, sizeof(buf), hflag, total, hlen, blocksize);
330                 printf("Total:        %s ", buf);
331                 sizetobuf(buf, sizeof(buf), hflag, used, hlen, blocksize);
332                 printf("%s\n", buf);
333         }
334 }