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