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