8fcefeee5f7d83369716130ea8d929840c43450f
[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  * $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 }