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, "acdeghiklmqsAEU")) != -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 case 'e': 107 eflag = 1; 108 break; 109 case 'g': 110 hflag = 'G'; 111 break; 112 case 'h': 113 hflag = 'H'; 114 break; 115 case 'i': 116 iflag = 1; 117 break; 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 } 141 break; 142 case '?': 143 default: 144 usage(); 145 } 146 } 147 argv += optind; 148 149 ret = 0; 150 if (which_prog == SWAPON || which_prog == SWAPOFF) { 151 if (doall) { 152 while ((fsp = getfsent()) != NULL) { 153 char *fs_spec; 154 int dotrim = eflag; 155 156 if (strcmp(fsp->fs_type, FSTAB_SW)) 157 continue; 158 if (strstr(fsp->fs_mntops, "noauto")) 159 continue; 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)) { 171 ret = 1; 172 } else { 173 if (cflag || 174 strstr(fsp->fs_mntops, "crypt")) { 175 docrypt(fsp->fs_spec, 2); 176 } 177 if (!qflag) { 178 printf("%s: %sing %s as swap " 179 "device\n", 180 getprogname(), 181 (which_prog == SWAPOFF ? 182 "remov" : "add"), 183 fs_spec); 184 } 185 } 186 free(fs_spec); 187 } 188 } else if (*argv == NULL) { 189 usage(); 190 } 191 for (; *argv; ++argv) { 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)) { 199 ret = 1; 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 } 210 } 211 free(fs_spec); 212 } 213 } else { 214 if (lflag || sflag) 215 swaplist(lflag, sflag, hflag); 216 else 217 usage(); 218 } 219 exit(ret); 220 } 221 222 static 223 char * 224 docrypt(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); 243 free(buf); 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 285 /* 286 * TRIM the device 287 */ 288 static 289 void 290 trim_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; 344 printf("Trimming Device:%s, start=%jd bytes=%jd)\n", 345 name, (intmax_t)ioarg[0], (intmax_t)ioarg[1]); 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 trim_volume(name); 369 } 370 if ((which_prog == SWAPOFF ? swapoff(name) : swapon(name)) == -1) { 371 switch(errno) { 372 case EBUSY: 373 if (!doingall) 374 warnx("%s: device already in use", name); 375 break; 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; 382 default: 383 warn("%s", name); 384 break; 385 } 386 return(1); 387 } 388 return(0); 389 } 390 391 static void 392 usage(void) 393 { 394 fprintf(stderr, "usage: %s ", getprogname()); 395 switch (orig_prog) { 396 case SWAPON: 397 case SWAPOFF: 398 fprintf(stderr, "-aeiq | file ...\n"); 399 break; 400 case SWAPCTL: 401 fprintf(stderr, "[-AeghiklmsU] [-a file ... | -d file ...]\n"); 402 break; 403 } 404 exit(1); 405 } 406 407 static void 408 sizetobuf(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 422 static void 423 swaplist(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 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; 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 } 525