fdisk, gpt - Support trim on recent kernels
[dragonfly.git] / sbin / swapon / swapon.c
CommitLineData
984263bc
MD
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.
dc71b7ab 13 * 3. Neither the name of the University nor the names of its contributors
984263bc
MD
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.
1de703da
MD
28 *
29 * @(#) Copyright (c) 1980, 1993 The Regents of the University of California. All rights reserved.
30 * @(#)swapon.c 8.1 (Berkeley) 6/5/93
31 * $FreeBSD: src/sbin/swapon/swapon.c,v 1.8.2.2 2001/07/30 10:30:11 dd Exp $
984263bc
MD
32 */
33
9f3543c6
MD
34#include <sys/param.h>
35#include <sys/stat.h>
36#include <sys/sysctl.h>
58b7380e 37#include <sys/linker.h>
e0fb398b 38#include <sys/diskslice.h>
9f3543c6
MD
39#include <vm/vm_param.h>
40
984263bc
MD
41#include <err.h>
42#include <errno.h>
43#include <fstab.h>
44#include <stdio.h>
45#include <stdlib.h>
46#include <string.h>
47#include <unistd.h>
9f3543c6
MD
48#include <fcntl.h>
49#include <libutil.h>
984263bc 50
32506cfa
SW
51#include <bus/cam/scsi/scsi_daio.h>
52
9a76cd75 53static void usage(void);
62a3b3b5 54static int swap_on_off(char *name, int doingall, int trim, int ask);
58b7380e 55static char *docrypt(char *fs_spec, int pass);
9f3543c6
MD
56static void swaplist(int lflag, int sflag, int hflag);
57
58b7380e
MD
58static int qflag;
59
9f3543c6 60enum { SWAPON, SWAPOFF, SWAPCTL } orig_prog, which_prog = SWAPCTL;
984263bc
MD
61
62int
63main(int argc, char **argv)
64{
b942f274 65 struct fstab *fsp;
9f3543c6
MD
66 char *ptr;
67 int ret;
68 int ch;
58b7380e 69 int doall, sflag, lflag, hflag, eflag, cflag, iflag;
984263bc 70
9f3543c6
MD
71 if ((ptr = strrchr(argv[0], '/')) == NULL)
72 ptr = argv[0];
73 if (strstr(ptr, "swapon"))
74 which_prog = SWAPON;
75 else if (strstr(ptr, "swapoff"))
76 which_prog = SWAPOFF;
77 orig_prog = which_prog;
78
58b7380e 79 sflag = lflag = hflag = doall = eflag = cflag = iflag = 0;
d9306807 80 while ((ch = getopt(argc, argv, "acdeghiklmqsAEU")) != -1) {
984263bc 81 switch((char)ch) {
9f3543c6
MD
82 case 'A':
83 if (which_prog == SWAPCTL) {
84 doall = 1;
85 which_prog = SWAPON;
86 } else {
87 usage();
88 }
89 break;
984263bc 90 case 'a':
9f3543c6
MD
91 if (which_prog == SWAPON || which_prog == SWAPOFF)
92 doall = 1;
93 else
94 which_prog = SWAPON;
95 break;
96 case 'd':
97 if (which_prog == SWAPCTL)
98 which_prog = SWAPOFF;
99 else
100 usage();
101 break;
58b7380e
MD
102 case 'c':
103 cflag = 1;
104 break;
d9306807 105 case 'E':
e0fb398b
T
106 case 'e':
107 eflag = 1;
108 break;
9f3543c6
MD
109 case 'g':
110 hflag = 'G';
111 break;
112 case 'h':
113 hflag = 'H';
114 break;
62a3b3b5
JG
115 case 'i':
116 iflag = 1;
117 break;
9f3543c6
MD
118 case 'k':
119 hflag = 'K';
120 break;
121 case 'l':
122 lflag = 1;
123 break;
124 case 'm':
125 hflag = 'M';
126 break;
127 case 'q':
128 if (which_prog == SWAPON || which_prog == SWAPOFF)
129 qflag = 1;
130 break;
131 case 's':
132 sflag = 1;
133 break;
134 case 'U':
135 if (which_prog == SWAPCTL) {
136 doall = 1;
137 which_prog = SWAPOFF;
138 } else {
139 usage();
140 }
984263bc
MD
141 break;
142 case '?':
143 default:
144 usage();
145 }
9f3543c6 146 }
984263bc
MD
147 argv += optind;
148
9f3543c6
MD
149 ret = 0;
150 if (which_prog == SWAPON || which_prog == SWAPOFF) {
151 if (doall) {
152 while ((fsp = getfsent()) != NULL) {
58b7380e
MD
153 char *fs_spec;
154 int dotrim = eflag;
155
9f3543c6
MD
156 if (strcmp(fsp->fs_type, FSTAB_SW))
157 continue;
158 if (strstr(fsp->fs_mntops, "noauto"))
159 continue;
58b7380e
MD
160
161 if (strstr(fsp->fs_mntops, "notrim"))
162 dotrim = 0;
163 else if (strstr(fsp->fs_mntops, "trim"))
164 dotrim = 1;
165
166 if (cflag || strstr(fsp->fs_mntops, "crypt"))
167 fs_spec = docrypt(fsp->fs_spec, 1);
168 else
169 fs_spec = strdup(fsp->fs_spec);
170 if (swap_on_off(fs_spec, 1, dotrim, iflag)) {
9f3543c6
MD
171 ret = 1;
172 } else {
58b7380e
MD
173 if (cflag ||
174 strstr(fsp->fs_mntops, "crypt")) {
175 docrypt(fsp->fs_spec, 2);
176 }
9f3543c6 177 if (!qflag) {
58b7380e
MD
178 printf("%s: %sing %s as swap "
179 "device\n",
9f3543c6 180 getprogname(),
58b7380e
MD
181 (which_prog == SWAPOFF ?
182 "remov" : "add"),
183 fs_spec);
9f3543c6
MD
184 }
185 }
58b7380e 186 free(fs_spec);
9f3543c6
MD
187 }
188 } else if (*argv == NULL) {
189 usage();
984263bc 190 }
9f3543c6 191 for (; *argv; ++argv) {
58b7380e
MD
192 char *ospec = getdevpath(*argv, 0);
193 char *fs_spec;
194 if (cflag)
195 fs_spec = docrypt(ospec, 1);
196 else
197 fs_spec = strdup(ospec);
198 if (swap_on_off(fs_spec, 0, eflag, iflag)) {
9f3543c6 199 ret = 1;
58b7380e
MD
200 } else {
201 if (cflag)
202 docrypt(ospec, 2);
203 if (!qflag) {
204 printf("%s: %sing %s as swap device\n",
205 getprogname(),
206 (which_prog == SWAPOFF ?
207 "remov" : "add"),
208 fs_spec);
209 }
9f3543c6 210 }
58b7380e 211 free(fs_spec);
9f3543c6
MD
212 }
213 } else {
214 if (lflag || sflag)
215 swaplist(lflag, sflag, hflag);
216 else
217 usage();
c4d5a9b3 218 }
9f3543c6 219 exit(ret);
984263bc
MD
220}
221
58b7380e
MD
222static
223char *
224docrypt(char *fs_spec, int pass)
225{
226 char *id;
227 char *res;
228 char *buf;
229
230 if ((id = strrchr(fs_spec, '/')) == NULL)
231 id = fs_spec;
232 else
233 ++id;
234 asprintf(&id, "swap-%s", id);
235 asprintf(&res, "/dev/mapper/%s", id);
236
237 switch(which_prog) {
238 case SWAPOFF:
239 if (pass != 2)
240 break;
241 asprintf(&buf, "/sbin/cryptsetup remove %s", id);
242 system(buf);
08c0d58d 243 free(buf);
58b7380e
MD
244 free(id);
245 break;
246 case SWAPON:
247 if (pass != 1)
248 break;
249 if (kldfind("dm_target_crypt") < 0)
250 kldload("dm_target_crypt");
251
252 asprintf(&buf,
253 "/sbin/cryptsetup --key-file /dev/urandom "
254 "--key-size 256 create %s %s",
255 id, fs_spec);
256 if (qflag == 0)
257 printf("%s\n", buf);
258 system(buf);
259 free(buf);
260 free(id);
261
262 /*
263 * NOTE: Don't revert to /dev/da* on error because this could
264 * inadvertently add both /dev/da* and
265 * /dev/mapper/swap-da*.
266 *
267 * Allow the swapon operation to report failure or
268 * report a duplicate.
269 */
270 break;
271 default:
272 free(res);
273 free(id);
274 res = strdup(fs_spec);
275 break;
276 }
277
278 if (pass == 2) {
279 free (res);
280 res = NULL;
281 }
282 return res;
283}
284
e0fb398b
T
285/*
286 * TRIM the device
287 */
288static
289void
290trim_volume(char * name)
291{
292 struct partinfo pinfo;
293 int fd,i,n;
294 size_t bytes = 0,ksize;
295 char *xswbuf;
296 struct xswdev *xsw;
297
298
299 /*
300 * Determine if this device is already being used by swap without
301 * calling swapon().
302 */
303 if ((sysctlbyname("vm.swap_info_array", NULL, &bytes, NULL, 0) < 0) ||
304 bytes == 0) {
305 err(1, "sysctlbyname()");
306 }
307
308 xswbuf = malloc(bytes);
309 if ((sysctlbyname("vm.swap_info_array", xswbuf, &bytes, NULL, 0) < 0) ||
310 bytes == 0) {
311 free(xswbuf);
312 err(1, "sysctlbyname()");
313 }
314
315 ksize = ((struct xswdev *)xswbuf)->xsw_size;
316 n = (int)(bytes / ksize);
317 for (i = 0; i < n; ++i) {
318 xsw = (void *)((char *)xswbuf + i * ksize);
319
320 if (xsw->xsw_dev == NODEV )
321 continue;
322 if(!strcmp(devname(xsw->xsw_dev, S_IFCHR),
323 name + strlen("/dev/"))) {
324 warnx("%s: device already a swap device", name);
325 exit(1);
326 }
327 }
328
329 /*
330 * Get the size and offset of this parititon/device
331 */
332 fd = open(name, O_RDWR);
333 if (fd < 0)
334 err(1, "Unable to open %s R+W", name);
335 if (ioctl(fd, DIOCGPART, &pinfo) < 0) {
336 printf("Cannot trim regular file\n");
337 usage ();
338 }
339 off_t ioarg[2];
340
341 /*Trim the Device*/
342 ioarg[0] = pinfo.media_offset;
343 ioarg[1] = pinfo.media_size;
d9306807
MD
344 printf("Trimming Device:%s, start=%jd bytes=%jd)\n",
345 name, (intmax_t)ioarg[0], (intmax_t)ioarg[1]);
32506cfa 346 if (ioctl(fd, DAIOCTRIM, ioarg) < 0) {
e0fb398b
T
347 printf("Device trim failed\n");
348 usage ();
349 }
350 close(fd);
351}
352
9f3543c6 353static int
62a3b3b5 354swap_on_off(char *name, int doingall, int trim, int ask)
984263bc 355{
62a3b3b5
JG
356
357 if (ask && which_prog == SWAPON) {
358 printf("Do you really want to use device %s as a swap device ?\n", name);
359 printf("You might loose data. [Y/N]");
360
361 int c = fgetc(stdin);
fd459e4b 362 printf("\n");
62a3b3b5
JG
363 if (c != 'y' && c != 'Y')
364 return(1);
365
366 }
58b7380e 367 if (which_prog == SWAPON && trim) {
d9306807 368 trim_volume(name);
e0fb398b 369 }
9f3543c6
MD
370 if ((which_prog == SWAPOFF ? swapoff(name) : swapon(name)) == -1) {
371 switch(errno) {
984263bc 372 case EBUSY:
9f3543c6 373 if (!doingall)
984263bc
MD
374 warnx("%s: device already in use", name);
375 break;
9f3543c6
MD
376 case EINVAL:
377 if (which_prog == SWAPON)
378 warnx("%s: NSWAPDEV limit reached", name);
379 else if (!doingall)
380 warn("%s", name);
381 break;
984263bc
MD
382 default:
383 warn("%s", name);
384 break;
385 }
386 return(1);
387 }
388 return(0);
389}
390
391static void
b5744197 392usage(void)
984263bc 393{
9f3543c6
MD
394 fprintf(stderr, "usage: %s ", getprogname());
395 switch (orig_prog) {
396 case SWAPON:
397 case SWAPOFF:
62a3b3b5 398 fprintf(stderr, "-aeiq | file ...\n");
9f3543c6
MD
399 break;
400 case SWAPCTL:
62a3b3b5 401 fprintf(stderr, "[-AeghiklmsU] [-a file ... | -d file ...]\n");
9f3543c6
MD
402 break;
403 }
984263bc
MD
404 exit(1);
405}
9f3543c6
MD
406
407static void
408sizetobuf(char *buf, size_t bufsize, int hflag, long long val, int hlen,
409 long blocksize)
410{
411 if (hflag == 'H') {
412 char tmp[16];
413
414 humanize_number(tmp, 5, (int64_t)val, "", HN_AUTOSCALE,
415 HN_B | HN_NOSPACE | HN_DECIMAL);
416 snprintf(buf, bufsize, "%*s", hlen, tmp);
417 } else {
418 snprintf(buf, bufsize, "%*lld", hlen, val / blocksize);
419 }
420}
421
422static void
423swaplist(int lflag, int sflag, int hflag)
424{
425 size_t ksize, bytes = 0;
426 char *xswbuf;
427 struct xswdev *xsw;
428 int hlen, pagesize;
429 int i, n;
430 long blocksize;
431 long long total, used, tmp_total, tmp_used;
432 char buf[32];
433
434 pagesize = getpagesize();
435 switch(hflag) {
436 case 'G':
437 blocksize = 1024 * 1024 * 1024;
438 strlcpy(buf, "1GB-blocks", sizeof(buf));
439 hlen = 10;
440 break;
441 case 'H':
442 blocksize = -1;
443 strlcpy(buf, "Bytes", sizeof(buf));
444 hlen = 10;
445 break;
446 case 'K':
447 blocksize = 1024;
448 strlcpy(buf, "1kB-blocks", sizeof(buf));
449 hlen = 10;
450 break;
451 case 'M':
452 blocksize = 1024 * 1024;
453 strlcpy(buf, "1MB-blocks", sizeof(buf));
454 hlen = 10;
455 break;
456 default:
457 getbsize(&hlen, &blocksize);
458 snprintf(buf, sizeof(buf), "%ld-blocks", blocksize);
459 break;
460 }
461
462 if (sysctlbyname("vm.swap_info_array", NULL, &bytes, NULL, 0) < 0)
463 err(1, "sysctlbyname()");
464 if (bytes == 0)
465 err(1, "sysctlbyname()");
466
467 xswbuf = malloc(bytes);
468 if (sysctlbyname("vm.swap_info_array", xswbuf, &bytes, NULL, 0) < 0) {
469 free(xswbuf);
470 err(1, "sysctlbyname()");
471 }
472 if (bytes == 0) {
473 free(xswbuf);
474 err(1, "sysctlbyname()");
475 }
476
477 /*
478 * Calculate size of xsw entry returned by kernel (it can be larger
479 * than the one we have if there is a version mismatch).
480 */
481 ksize = ((struct xswdev *)xswbuf)->xsw_size;
482 n = (int)(bytes / ksize);
483
484 if (lflag) {
485 printf("%-13s %*s %*s\n",
486 "Device:",
487 hlen, buf,
488 hlen, "Used:");
489 }
490
491 total = used = tmp_total = tmp_used = 0;
492 for (i = 0; i < n; ++i) {
493 xsw = (void *)((char *)xswbuf + i * ksize);
494
495 if (xsw->xsw_nblks == 0)
496 continue;
497
ebd20800
SW
498 tmp_total = (long long)xsw->xsw_nblks * pagesize;
499 tmp_used = (long long)xsw->xsw_used * pagesize;
500 total += tmp_total;
501 used += tmp_used;
9f3543c6
MD
502 if (lflag) {
503 sizetobuf(buf, sizeof(buf), hflag, tmp_total, hlen,
504 blocksize);
505 if (xsw->xsw_dev == NODEV) {
506 printf("%-13s %s ", "[NFS swap]", buf);
507 } else {
508 printf("/dev/%-8s %s ",
509 devname(xsw->xsw_dev, S_IFCHR), buf);
510 }
511
512 sizetobuf(buf, sizeof(buf), hflag, tmp_used, hlen,
513 blocksize);
514 printf("%s\n", buf);
515 }
516 }
517
518 if (sflag) {
519 sizetobuf(buf, sizeof(buf), hflag, total, hlen, blocksize);
520 printf("Total: %s ", buf);
521 sizetobuf(buf, sizeof(buf), hflag, used, hlen, blocksize);
522 printf("%s\n", buf);
523 }
524}