3a119e0e50a203ae857cbd1176fd8fca5332c50c
[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 <sys/diskslice.h>
42 #include <sys/ioctl_compat.h>
43 #include <vm/vm_param.h>
44
45 #include <err.h>
46 #include <errno.h>
47 #include <fstab.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <unistd.h>
52 #include <fcntl.h>
53 #include <libutil.h>
54
55 static void usage(void);
56 static int swap_on_off(char *name, int doingall, int trim);
57 static void swaplist(int lflag, int sflag, int hflag);
58
59 enum { SWAPON, SWAPOFF, SWAPCTL } orig_prog, which_prog = SWAPCTL;
60
61 int
62 main(int argc, char **argv)
63 {
64         struct fstab *fsp;
65         char *ptr;
66         int ret;
67         int ch;
68         int doall, sflag, lflag, hflag, qflag, eflag;
69
70         if ((ptr = strrchr(argv[0], '/')) == NULL)
71                 ptr = argv[0];
72         if (strstr(ptr, "swapon"))
73                 which_prog = SWAPON;
74         else if (strstr(ptr, "swapoff"))
75                 which_prog = SWAPOFF;
76         orig_prog = which_prog;
77
78         sflag = lflag = hflag = qflag = doall = eflag = 0;
79         while ((ch = getopt(argc, argv, "AadeghklmqsU")) != -1) {
80                 switch((char)ch) {
81                 case 'A':
82                         if (which_prog == SWAPCTL) {
83                                 doall = 1;
84                                 which_prog = SWAPON;
85                         } else {
86                                 usage();
87                         }
88                         break;
89                 case 'a':
90                         if (which_prog == SWAPON || which_prog == SWAPOFF)
91                                 doall = 1;
92                         else
93                                 which_prog = SWAPON;
94                         break;
95                 case 'd':
96                         if (which_prog == SWAPCTL)
97                                 which_prog = SWAPOFF;
98                         else
99                                 usage();
100                         break;
101                 case 'e':
102                         eflag = 1;
103                         break;
104                 case 'g':
105                         hflag = 'G';
106                         break;
107                 case 'h':
108                         hflag = 'H';
109                         break;
110                 case 'k':
111                         hflag = 'K';
112                         break;
113                 case 'l':
114                         lflag = 1;
115                         break;
116                 case 'm':
117                         hflag = 'M';
118                         break;
119                 case 'q':
120                         if (which_prog == SWAPON || which_prog == SWAPOFF)
121                                 qflag = 1;
122                         break;
123                 case 's':
124                         sflag = 1;
125                         break;
126                 case 'U':
127                         if (which_prog == SWAPCTL) {
128                                 doall = 1;
129                                 which_prog = SWAPOFF;
130                         } else {
131                                 usage();
132                         }
133                         break;
134                 case '?':
135                 default:
136                         usage();
137                 }
138         }
139         argv += optind;
140
141         ret = 0;
142         if (which_prog == SWAPON || which_prog == SWAPOFF) {
143                 if (doall) {
144                         while ((fsp = getfsent()) != NULL) {
145                                 if (strcmp(fsp->fs_type, FSTAB_SW))
146                                         continue;
147                                 if (strstr(fsp->fs_mntops, "noauto"))
148                                         continue;
149                                 if (swap_on_off(fsp->fs_spec, 1, eflag)) {
150                                         ret = 1;
151                                 } else {
152                                         if (!qflag) {
153                                                 printf("%s: %sing %s as swap device\n",
154                                                     getprogname(),
155                                                     which_prog == SWAPOFF ? "remov" : "add",
156                                                     fsp->fs_spec);
157                                         }
158                                 }
159                         }
160                 } else if (*argv == NULL) {
161                         usage();
162                 }
163                 for (; *argv; ++argv) {
164                         if (swap_on_off(getdevpath(*argv, 0), 0, eflag)) {
165                                 ret = 1;
166                         } else if (orig_prog == SWAPCTL) {
167                                 printf("%s: %sing %s as swap device\n",
168                                     getprogname(),
169                                     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(ret);
180 }
181
182 /*
183  * TRIM the device
184  */
185 static
186 void
187 trim_volume(char * name)
188 {       
189         struct partinfo pinfo;
190         int fd,i,n;
191         size_t bytes = 0,ksize;
192         char *xswbuf;
193         struct xswdev *xsw;
194
195
196         /*
197         * Determine if this device is already being used by swap without 
198         * calling swapon(). 
199         */
200         if ((sysctlbyname("vm.swap_info_array", NULL, &bytes, NULL, 0) < 0) ||
201             bytes == 0) {
202                 err(1, "sysctlbyname()");
203         }
204
205         xswbuf = malloc(bytes);
206         if ((sysctlbyname("vm.swap_info_array", xswbuf, &bytes, NULL, 0) < 0) ||
207             bytes == 0) {
208                         free(xswbuf);
209                         err(1, "sysctlbyname()");
210         }
211
212         ksize = ((struct xswdev *)xswbuf)->xsw_size;
213         n = (int)(bytes / ksize);
214         for (i = 0; i < n; ++i) {
215                 xsw = (void *)((char *)xswbuf + i * ksize);
216
217                 if (xsw->xsw_dev == NODEV )
218                         continue;
219                 if(!strcmp(devname(xsw->xsw_dev, S_IFCHR),
220                     name + strlen("/dev/"))) {
221                         warnx("%s: device already a swap device", name);
222                         exit(1);
223                 }
224         }
225         
226         /*
227          * Get the size and offset of this parititon/device
228          */
229         fd = open(name, O_RDWR);
230         if (fd < 0)
231                 err(1, "Unable to open %s R+W", name);
232         if (ioctl(fd, DIOCGPART, &pinfo) < 0) {
233                 printf("Cannot trim regular file\n");
234                 usage ();
235         }
236         off_t ioarg[2];
237         
238         /*Trim the Device*/     
239         ioarg[0] = pinfo.media_offset;
240         ioarg[1] = pinfo.media_size;
241         printf("Trimming Device:%s, sectors (%llu -%llu)\n",name,
242              (unsigned long long)ioarg[0]/512,
243              (unsigned long long)ioarg[1]/512);
244         if (ioctl(fd, IOCTLTRIM, ioarg) < 0) {
245                 printf("Device trim failed\n");
246                 usage ();
247         }
248         close(fd);
249 }
250
251 static int
252 swap_on_off(char *name, int doingall, int trim)
253 {
254         if (which_prog == SWAPON && trim){
255                 char sysctl_name[64];
256                 int trim_enabled = 0;
257                 size_t olen = sizeof(trim_enabled);
258                 char *dev_name = strdup(name);
259                 dev_name = strtok(dev_name + strlen("/dev/da"),"s");
260                 sprintf(sysctl_name, "kern.cam.da.%s.trim_enabled", dev_name);
261                 sysctlbyname(sysctl_name, &trim_enabled, &olen, NULL, 0);
262                 if(errno == ENOENT) {
263                         printf("Device:%s does not support the TRIM command\n",
264                             name);
265                         usage();
266                 }
267                 if(!trim_enabled) {
268                         printf("Erase device option selected, but sysctl (%s) "
269                             "is not enabled\n",sysctl_name);
270                         usage();
271                 }
272
273                 trim_volume(name);
274
275         }
276         if ((which_prog == SWAPOFF ? swapoff(name) : swapon(name)) == -1) {
277                 switch(errno) {
278                 case EBUSY:
279                         if (!doingall)
280                                 warnx("%s: device already in use", name);
281                         break;
282                 case EINVAL:
283                         if (which_prog == SWAPON)
284                                 warnx("%s: NSWAPDEV limit reached", name);
285                         else if (!doingall)
286                                 warn("%s", name);
287                         break;
288                 default:
289                         warn("%s", name);
290                         break;
291                 }
292                 return(1);
293         }
294         return(0);
295 }
296
297 static void
298 usage(void)
299 {
300         fprintf(stderr, "usage: %s ", getprogname());
301         switch (orig_prog) {
302         case SWAPON:
303         case SWAPOFF:
304                 fprintf(stderr, "-aeq | file ...\n");
305                 break;
306         case SWAPCTL:
307                 fprintf(stderr, "[-AeghklmsU] [-a file ... | -d file ...]\n");
308                 break;
309         }
310         exit(1);
311 }
312
313 static void
314 sizetobuf(char *buf, size_t bufsize, int hflag, long long val, int hlen,
315     long blocksize)
316 {
317         if (hflag == 'H') {
318                 char tmp[16];
319
320                 humanize_number(tmp, 5, (int64_t)val, "", HN_AUTOSCALE,
321                     HN_B | HN_NOSPACE | HN_DECIMAL);
322                 snprintf(buf, bufsize, "%*s", hlen, tmp);
323         } else {
324                 snprintf(buf, bufsize, "%*lld", hlen, val / blocksize);
325         }
326 }
327
328 static void
329 swaplist(int lflag, int sflag, int hflag)
330 {
331         size_t ksize, bytes = 0;
332         char *xswbuf;
333         struct xswdev *xsw;
334         int hlen, pagesize;
335         int i, n;
336         long blocksize;
337         long long total, used, tmp_total, tmp_used;
338         char buf[32];
339
340         pagesize = getpagesize();
341         switch(hflag) {
342         case 'G':
343                 blocksize = 1024 * 1024 * 1024;
344                 strlcpy(buf, "1GB-blocks", sizeof(buf));
345                 hlen = 10;
346                 break;
347         case 'H':
348                 blocksize = -1;
349                 strlcpy(buf, "Bytes", sizeof(buf));
350                 hlen = 10;
351                 break;
352         case 'K':
353                 blocksize = 1024;
354                 strlcpy(buf, "1kB-blocks", sizeof(buf));
355                 hlen = 10;
356                 break;
357         case 'M':
358                 blocksize = 1024 * 1024;
359                 strlcpy(buf, "1MB-blocks", sizeof(buf));
360                 hlen = 10;
361                 break;
362         default:
363                 getbsize(&hlen, &blocksize);
364                 snprintf(buf, sizeof(buf), "%ld-blocks", blocksize);
365                 break;
366         }
367
368         if (sysctlbyname("vm.swap_info_array", NULL, &bytes, NULL, 0) < 0)
369                 err(1, "sysctlbyname()");
370         if (bytes == 0)
371                 err(1, "sysctlbyname()");
372
373         xswbuf = malloc(bytes);
374         if (sysctlbyname("vm.swap_info_array", xswbuf, &bytes, NULL, 0) < 0) {
375                 free(xswbuf);
376                 err(1, "sysctlbyname()");
377         }
378         if (bytes == 0) {
379                 free(xswbuf);
380                 err(1, "sysctlbyname()");
381         }
382
383         /*
384          * Calculate size of xsw entry returned by kernel (it can be larger
385          * than the one we have if there is a version mismatch).
386          */
387         ksize = ((struct xswdev *)xswbuf)->xsw_size;
388         n = (int)(bytes / ksize);
389
390         if (lflag) {
391                 printf("%-13s %*s %*s\n",
392                     "Device:",
393                     hlen, buf,
394                     hlen, "Used:");
395         }
396
397         total = used = tmp_total = tmp_used = 0;
398         for (i = 0; i < n; ++i) {
399                 xsw = (void *)((char *)xswbuf + i * ksize);
400
401                 if (xsw->xsw_nblks == 0)
402                         continue;
403
404                 tmp_total = (long long)xsw->xsw_nblks * pagesize;
405                 tmp_used = (long long)xsw->xsw_used * pagesize;
406                 total += tmp_total;
407                 used += tmp_used;
408                 if (lflag) {
409                         sizetobuf(buf, sizeof(buf), hflag, tmp_total, hlen,
410                             blocksize);
411                         if (xsw->xsw_dev == NODEV) {
412                                 printf("%-13s %s ", "[NFS swap]", buf);
413                         } else {
414                                 printf("/dev/%-8s %s ",
415                                     devname(xsw->xsw_dev, S_IFCHR), buf);
416                         }
417
418                         sizetobuf(buf, sizeof(buf), hflag, tmp_used, hlen,
419                             blocksize);
420                         printf("%s\n", buf);
421                 }
422         }
423
424         if (sflag) {
425                 sizetobuf(buf, sizeof(buf), hflag, total, hlen, blocksize);
426                 printf("Total:        %s ", buf);
427                 sizetobuf(buf, sizeof(buf), hflag, used, hlen, blocksize);
428                 printf("%s\n", buf);
429         }
430 }