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