10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*1978Spetede * Common Development and Distribution License (the "License"). 6*1978Spetede * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*1978Spetede * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 270Sstevel@tonic-gate /* All Rights Reserved */ 280Sstevel@tonic-gate 290Sstevel@tonic-gate /* 300Sstevel@tonic-gate * University Copyright- Copyright (c) 1982, 1986, 1988 310Sstevel@tonic-gate * The Regents of the University of California 320Sstevel@tonic-gate * All Rights Reserved 330Sstevel@tonic-gate * 340Sstevel@tonic-gate * University Acknowledgment- Portions of this document are derived from 350Sstevel@tonic-gate * software developed by the University of California, Berkeley, and its 360Sstevel@tonic-gate * contributors. 370Sstevel@tonic-gate */ 380Sstevel@tonic-gate 390Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 400Sstevel@tonic-gate 410Sstevel@tonic-gate /* 420Sstevel@tonic-gate * Swap administrative interface 430Sstevel@tonic-gate * Used to add/delete/list swap devices. 440Sstevel@tonic-gate */ 450Sstevel@tonic-gate 460Sstevel@tonic-gate #include <sys/types.h> 470Sstevel@tonic-gate #include <sys/dumpadm.h> 480Sstevel@tonic-gate #include <string.h> 490Sstevel@tonic-gate #include <stdio.h> 500Sstevel@tonic-gate #include <stdlib.h> 510Sstevel@tonic-gate #include <unistd.h> 520Sstevel@tonic-gate #include <errno.h> 530Sstevel@tonic-gate #include <sys/param.h> 540Sstevel@tonic-gate #include <dirent.h> 550Sstevel@tonic-gate #include <sys/swap.h> 560Sstevel@tonic-gate #include <sys/sysmacros.h> 570Sstevel@tonic-gate #include <sys/mkdev.h> 580Sstevel@tonic-gate #include <sys/stat.h> 590Sstevel@tonic-gate #include <sys/statvfs.h> 600Sstevel@tonic-gate #include <sys/uadmin.h> 610Sstevel@tonic-gate #include <vm/anon.h> 620Sstevel@tonic-gate #include <fcntl.h> 630Sstevel@tonic-gate #include <locale.h> 640Sstevel@tonic-gate #include <libintl.h> 65767Ssjelinek #include <libdiskmgt.h> 660Sstevel@tonic-gate 670Sstevel@tonic-gate #define LFLAG 0x01 /* swap -l (list swap devices) */ 680Sstevel@tonic-gate #define DFLAG 0x02 /* swap -d (delete swap device) */ 690Sstevel@tonic-gate #define AFLAG 0x04 /* swap -a (add swap device) */ 700Sstevel@tonic-gate #define SFLAG 0x08 /* swap -s (swap info summary) */ 710Sstevel@tonic-gate #define P1FLAG 0x10 /* swap -1 (swapadd pass1; do not modify dump device) */ 720Sstevel@tonic-gate #define P2FLAG 0x20 /* swap -2 (swapadd pass2; do not modify dump device) */ 73*1978Spetede #define HFLAG 0x40 /* swap -h (size in human readable format) */ 74*1978Spetede #define KFLAG 0x80 /* swap -k (size in kilobytes) */ 75*1978Spetede 76*1978Spetede #define NUMBER_WIDTH 64 77*1978Spetede typedef char numbuf_t[NUMBER_WIDTH]; 780Sstevel@tonic-gate 790Sstevel@tonic-gate static char *prognamep; 800Sstevel@tonic-gate 810Sstevel@tonic-gate static int add(char *, off_t, off_t, int); 820Sstevel@tonic-gate static int delete(char *, off_t); 830Sstevel@tonic-gate static void usage(void); 84*1978Spetede static int doswap(int flag); 850Sstevel@tonic-gate static int valid(char *, off_t, off_t); 86*1978Spetede static int list(int flag); 87*1978Spetede static char *number_to_scaled_string(numbuf_t buf, unsigned long long number, 88*1978Spetede unsigned long long unit_from, unsigned long long scale); 89*1978Spetede 900Sstevel@tonic-gate 910Sstevel@tonic-gate int 920Sstevel@tonic-gate main(int argc, char **argv) 930Sstevel@tonic-gate { 940Sstevel@tonic-gate int c, flag = 0; 950Sstevel@tonic-gate int ret; 96767Ssjelinek int error = 0; 970Sstevel@tonic-gate off_t s_offset = 0; 980Sstevel@tonic-gate off_t length = 0; 990Sstevel@tonic-gate char *pathname; 100767Ssjelinek char *msg; 1010Sstevel@tonic-gate 1020Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 1030Sstevel@tonic-gate 1040Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) 1050Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" 1060Sstevel@tonic-gate #endif 1070Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 1080Sstevel@tonic-gate 1090Sstevel@tonic-gate prognamep = argv[0]; 1100Sstevel@tonic-gate if (argc < 2) { 1110Sstevel@tonic-gate usage(); 1120Sstevel@tonic-gate exit(1); 1130Sstevel@tonic-gate } 1140Sstevel@tonic-gate 115*1978Spetede while ((c = getopt(argc, argv, "khlsd:a:12")) != EOF) { 1160Sstevel@tonic-gate char *char_p; 1170Sstevel@tonic-gate switch (c) { 1180Sstevel@tonic-gate case 'l': /* list all the swap devices */ 1190Sstevel@tonic-gate flag |= LFLAG; 1200Sstevel@tonic-gate break; 1210Sstevel@tonic-gate case 's': 1220Sstevel@tonic-gate flag |= SFLAG; 1230Sstevel@tonic-gate break; 1240Sstevel@tonic-gate case 'd': 1250Sstevel@tonic-gate /* 1260Sstevel@tonic-gate * The argument for starting offset is optional. 1270Sstevel@tonic-gate * If no argument is specified, the entire swap file 1280Sstevel@tonic-gate * is added although this will fail if a non-zero 1290Sstevel@tonic-gate * starting offset was specified when added. 1300Sstevel@tonic-gate */ 1310Sstevel@tonic-gate if ((argc - optind) > 1 || flag != 0) { 1320Sstevel@tonic-gate usage(); 1330Sstevel@tonic-gate exit(1); 1340Sstevel@tonic-gate } 1350Sstevel@tonic-gate flag |= DFLAG; 1360Sstevel@tonic-gate pathname = optarg; 1370Sstevel@tonic-gate if (optind < argc) { 1380Sstevel@tonic-gate errno = 0; 1390Sstevel@tonic-gate s_offset = strtol(argv[optind++], &char_p, 10); 1400Sstevel@tonic-gate if (errno != 0 || *char_p != '\0') { 1410Sstevel@tonic-gate (void) fprintf(stderr, 1420Sstevel@tonic-gate gettext("error in [low block]\n")); 1430Sstevel@tonic-gate exit(1); 1440Sstevel@tonic-gate } 1450Sstevel@tonic-gate } 1460Sstevel@tonic-gate ret = delete(pathname, s_offset); 1470Sstevel@tonic-gate break; 1480Sstevel@tonic-gate 1490Sstevel@tonic-gate case 'a': 1500Sstevel@tonic-gate /* 1510Sstevel@tonic-gate * The arguments for starting offset and number of 1520Sstevel@tonic-gate * blocks are optional. If only the starting offset 1530Sstevel@tonic-gate * is specified, all the blocks to the end of the swap 1540Sstevel@tonic-gate * file will be added. If no starting offset is 1550Sstevel@tonic-gate * specified, the entire swap file is assumed. 1560Sstevel@tonic-gate */ 1570Sstevel@tonic-gate if ((argc - optind) > 2 || 1580Sstevel@tonic-gate (flag & ~(P1FLAG | P2FLAG)) != 0) { 1590Sstevel@tonic-gate usage(); 1600Sstevel@tonic-gate exit(1); 1610Sstevel@tonic-gate } 1620Sstevel@tonic-gate if (*optarg != '/') { 1630Sstevel@tonic-gate (void) fprintf(stderr, 1640Sstevel@tonic-gate gettext("%s: path must be absolute\n"), 1650Sstevel@tonic-gate prognamep); 1660Sstevel@tonic-gate exit(1); 1670Sstevel@tonic-gate } 1680Sstevel@tonic-gate flag |= AFLAG; 1690Sstevel@tonic-gate pathname = optarg; 1700Sstevel@tonic-gate if (optind < argc) { 1710Sstevel@tonic-gate errno = 0; 1720Sstevel@tonic-gate s_offset = strtol(argv[optind++], &char_p, 10); 1730Sstevel@tonic-gate if (errno != 0 || *char_p != '\0') { 1740Sstevel@tonic-gate (void) fprintf(stderr, 1750Sstevel@tonic-gate gettext("error in [low block]\n")); 1760Sstevel@tonic-gate exit(1); 1770Sstevel@tonic-gate } 1780Sstevel@tonic-gate } 1790Sstevel@tonic-gate if (optind < argc) { 1800Sstevel@tonic-gate errno = 0; 1810Sstevel@tonic-gate length = strtol(argv[optind++], &char_p, 10); 1820Sstevel@tonic-gate if (errno != 0 || *char_p != '\0') { 1830Sstevel@tonic-gate (void) fprintf(stderr, 1840Sstevel@tonic-gate gettext("error in [nbr of blocks]\n")); 1850Sstevel@tonic-gate exit(1); 1860Sstevel@tonic-gate } 1870Sstevel@tonic-gate } 1880Sstevel@tonic-gate break; 189*1978Spetede case 'h': 190*1978Spetede flag |= HFLAG; 191*1978Spetede break; 192*1978Spetede 193*1978Spetede case 'k': 194*1978Spetede flag |= KFLAG; 195*1978Spetede break; 1960Sstevel@tonic-gate 1970Sstevel@tonic-gate case '1': 1980Sstevel@tonic-gate flag |= P1FLAG; 1990Sstevel@tonic-gate break; 2000Sstevel@tonic-gate 2010Sstevel@tonic-gate case '2': 2020Sstevel@tonic-gate flag |= P2FLAG; 2030Sstevel@tonic-gate break; 2040Sstevel@tonic-gate 2050Sstevel@tonic-gate case '?': 2060Sstevel@tonic-gate usage(); 2070Sstevel@tonic-gate exit(1); 2080Sstevel@tonic-gate } 2090Sstevel@tonic-gate } 210*1978Spetede 211*1978Spetede if (flag & SFLAG) { 212*1978Spetede if (flag & ~SFLAG & ~HFLAG) { 213*1978Spetede /* 214*1978Spetede * The only option that can be used with -s is -h. 215*1978Spetede */ 216*1978Spetede usage(); 217*1978Spetede exit(1); 218*1978Spetede } 219*1978Spetede 220*1978Spetede ret = doswap(flag); 221*1978Spetede 222*1978Spetede } 223*1978Spetede 224*1978Spetede if (flag & LFLAG) { 225*1978Spetede if (flag & ~KFLAG & ~HFLAG & ~LFLAG) { 226*1978Spetede usage(); 227*1978Spetede exit(1); 228*1978Spetede } 229*1978Spetede ret = list(flag); 230*1978Spetede } 231*1978Spetede 232767Ssjelinek /* 233767Ssjelinek * do the add here. Check for in use prior to add. 234767Ssjelinek * The values for length and offset are set above. 235767Ssjelinek */ 236767Ssjelinek if (flag & AFLAG) { 237767Ssjelinek /* 238767Ssjelinek * If device is in use for a swap device, print message 239767Ssjelinek * and exit. 240767Ssjelinek */ 241767Ssjelinek if (dm_inuse(pathname, &msg, DM_WHO_SWAP, &error) || 242767Ssjelinek error) { 243767Ssjelinek if (error != 0) { 244767Ssjelinek (void) fprintf(stderr, gettext("Error occurred" 245767Ssjelinek " with device in use checking: %s\n"), 246767Ssjelinek strerror(error)); 247767Ssjelinek } else { 248767Ssjelinek (void) fprintf(stderr, "%s", msg); 249767Ssjelinek free(msg); 250767Ssjelinek exit(1); 251767Ssjelinek } 252767Ssjelinek } 253767Ssjelinek if ((ret = valid(pathname, 254767Ssjelinek s_offset * 512, length * 512)) == 0) { 255767Ssjelinek ret = add(pathname, s_offset, length, flag); 256767Ssjelinek } 257767Ssjelinek } 258*1978Spetede if (!(flag & ~HFLAG & ~KFLAG)) { 259*1978Spetede /* only -h and/or -k flag, or no flag */ 2600Sstevel@tonic-gate usage(); 2610Sstevel@tonic-gate exit(1); 2620Sstevel@tonic-gate } 2630Sstevel@tonic-gate return (ret); 2640Sstevel@tonic-gate } 2650Sstevel@tonic-gate 2660Sstevel@tonic-gate 2670Sstevel@tonic-gate static void 2680Sstevel@tonic-gate usage(void) 2690Sstevel@tonic-gate { 2700Sstevel@tonic-gate (void) fprintf(stderr, gettext("Usage:\t%s -l\n"), prognamep); 271*1978Spetede (void) fprintf(stderr, gettext("\tsub option :\n")); 272*1978Spetede (void) fprintf(stderr, gettext("\t\t-h : displays size in human " 273*1978Spetede "readable format\n")); 274*1978Spetede (void) fprintf(stderr, gettext("\t\t-k : displays size in KB\n")); 2750Sstevel@tonic-gate (void) fprintf(stderr, "\t%s -s\n", prognamep); 276*1978Spetede (void) fprintf(stderr, gettext("\tsub option :\n")); 277*1978Spetede (void) fprintf(stderr, gettext("\t\t-h : displays size in human " 278*1978Spetede "readable format rather than KB\n")); 2790Sstevel@tonic-gate (void) fprintf(stderr, gettext("\t%s -d <file name> [low block]\n"), 280*1978Spetede prognamep); 2810Sstevel@tonic-gate (void) fprintf(stderr, gettext("\t%s -a <file name> [low block]" 282*1978Spetede " [nbr of blocks]\n"), prognamep); 2830Sstevel@tonic-gate } 2840Sstevel@tonic-gate 2850Sstevel@tonic-gate /* 2860Sstevel@tonic-gate * Implement: 2870Sstevel@tonic-gate * #define ctok(x) ((ctob(x))>>10) 2880Sstevel@tonic-gate * in a machine independent way. (Both assume a click > 1k) 2890Sstevel@tonic-gate */ 2900Sstevel@tonic-gate static size_t 2910Sstevel@tonic-gate ctok(pgcnt_t clicks) 2920Sstevel@tonic-gate { 2930Sstevel@tonic-gate static int factor = -1; 2940Sstevel@tonic-gate 2950Sstevel@tonic-gate if (factor == -1) 2960Sstevel@tonic-gate factor = (int)(sysconf(_SC_PAGESIZE) >> 10); 2970Sstevel@tonic-gate return ((size_t)(clicks * factor)); 2980Sstevel@tonic-gate } 2990Sstevel@tonic-gate 3000Sstevel@tonic-gate 3010Sstevel@tonic-gate static int 302*1978Spetede doswap(int flag) 3030Sstevel@tonic-gate { 3040Sstevel@tonic-gate struct anoninfo ai; 3050Sstevel@tonic-gate pgcnt_t allocated, reserved, available; 306*1978Spetede numbuf_t numbuf; 307*1978Spetede unsigned long long scale = 1024L; 3080Sstevel@tonic-gate 3090Sstevel@tonic-gate /* 3100Sstevel@tonic-gate * max = total amount of swap space including physical memory 3110Sstevel@tonic-gate * ai.ani_max = MAX(anoninfo.ani_resv, anoninfo.ani_max) + 3120Sstevel@tonic-gate * availrmem - swapfs_minfree; 3130Sstevel@tonic-gate * ai.ani_free = amount of unallocated anonymous memory 3140Sstevel@tonic-gate * (ie. = resverved_unallocated + unreserved) 3150Sstevel@tonic-gate * ai.ani_free = anoninfo.ani_free + (availrmem - swapfs_minfree); 3160Sstevel@tonic-gate * ai.ani_resv = total amount of reserved anonymous memory 3170Sstevel@tonic-gate * ai.ani_resv = anoninfo.ani_resv; 3180Sstevel@tonic-gate * 3190Sstevel@tonic-gate * allocated = anon memory not free 3200Sstevel@tonic-gate * reserved = anon memory reserved but not allocated 3210Sstevel@tonic-gate * available = anon memory not reserved 3220Sstevel@tonic-gate */ 3230Sstevel@tonic-gate if (swapctl(SC_AINFO, &ai) == -1) { 3240Sstevel@tonic-gate perror(prognamep); 3250Sstevel@tonic-gate return (2); 3260Sstevel@tonic-gate } 3270Sstevel@tonic-gate 3280Sstevel@tonic-gate allocated = ai.ani_max - ai.ani_free; 3290Sstevel@tonic-gate reserved = ai.ani_resv - allocated; 3300Sstevel@tonic-gate available = ai.ani_max - ai.ani_resv; 3310Sstevel@tonic-gate 3320Sstevel@tonic-gate /* 3330Sstevel@tonic-gate * TRANSLATION_NOTE 3340Sstevel@tonic-gate * Translations (if any) of these keywords should match with 3350Sstevel@tonic-gate * translations (if any) of the swap.1M man page keywords for 3360Sstevel@tonic-gate * -s option: "allocated", "reserved", "used", "available" 3370Sstevel@tonic-gate */ 338*1978Spetede 339*1978Spetede if (flag & HFLAG) { 340*1978Spetede int factor = (int)(sysconf(_SC_PAGESIZE)); 341*1978Spetede (void) printf(gettext("total: %s allocated + "), 342*1978Spetede number_to_scaled_string(numbuf, allocated, 343*1978Spetede factor, scale)); 344*1978Spetede (void) printf(gettext("%s reserved = "), 345*1978Spetede number_to_scaled_string(numbuf, allocated, 346*1978Spetede factor, scale)); 347*1978Spetede (void) printf(gettext("%s used, "), 348*1978Spetede number_to_scaled_string(numbuf, 349*1978Spetede allocated + reserved, factor, scale)); 350*1978Spetede (void) printf(gettext("%s available\n"), 351*1978Spetede number_to_scaled_string(numbuf, available, 352*1978Spetede factor, scale)); 353*1978Spetede } else { 354*1978Spetede (void) printf(gettext("total: %luk bytes allocated + %luk" 355*1978Spetede " reserved = %luk used, %luk available\n"), 356*1978Spetede ctok(allocated), ctok(reserved), 357*1978Spetede ctok(reserved) + ctok(allocated), 358*1978Spetede ctok(available)); 359*1978Spetede } 3600Sstevel@tonic-gate 3610Sstevel@tonic-gate return (0); 3620Sstevel@tonic-gate } 3630Sstevel@tonic-gate 3640Sstevel@tonic-gate static int 365*1978Spetede list(int flag) 3660Sstevel@tonic-gate { 3670Sstevel@tonic-gate struct swaptable *st; 3680Sstevel@tonic-gate struct swapent *swapent; 3690Sstevel@tonic-gate int i; 3700Sstevel@tonic-gate struct stat64 statbuf; 3710Sstevel@tonic-gate char *path; 3720Sstevel@tonic-gate char fullpath[MAXPATHLEN+1]; 3730Sstevel@tonic-gate int num; 374*1978Spetede numbuf_t numbuf; 375*1978Spetede unsigned long long scale = 1024L; 3760Sstevel@tonic-gate 3770Sstevel@tonic-gate if ((num = swapctl(SC_GETNSWP, NULL)) == -1) { 3780Sstevel@tonic-gate perror(prognamep); 3790Sstevel@tonic-gate return (2); 3800Sstevel@tonic-gate } 3810Sstevel@tonic-gate if (num == 0) { 3820Sstevel@tonic-gate (void) fprintf(stderr, gettext("No swap devices configured\n")); 3830Sstevel@tonic-gate return (1); 3840Sstevel@tonic-gate } 3850Sstevel@tonic-gate 3860Sstevel@tonic-gate if ((st = malloc(num * sizeof (swapent_t) + sizeof (int))) 3870Sstevel@tonic-gate == NULL) { 3880Sstevel@tonic-gate (void) fprintf(stderr, 3890Sstevel@tonic-gate gettext("Malloc failed. Please try later.\n")); 3900Sstevel@tonic-gate perror(prognamep); 3910Sstevel@tonic-gate return (2); 3920Sstevel@tonic-gate } 3930Sstevel@tonic-gate if ((path = malloc(num * MAXPATHLEN)) == NULL) { 3940Sstevel@tonic-gate (void) fprintf(stderr, 3950Sstevel@tonic-gate gettext("Malloc failed. Please try later.\n")); 3960Sstevel@tonic-gate perror(prognamep); 3970Sstevel@tonic-gate return (2); 3980Sstevel@tonic-gate } 3990Sstevel@tonic-gate swapent = st->swt_ent; 4000Sstevel@tonic-gate for (i = 0; i < num; i++, swapent++) { 4010Sstevel@tonic-gate swapent->ste_path = path; 4020Sstevel@tonic-gate path += MAXPATHLEN; 4030Sstevel@tonic-gate } 4040Sstevel@tonic-gate 4050Sstevel@tonic-gate st->swt_n = num; 4060Sstevel@tonic-gate if ((num = swapctl(SC_LIST, st)) == -1) { 4070Sstevel@tonic-gate perror(prognamep); 4080Sstevel@tonic-gate return (2); 4090Sstevel@tonic-gate } 4100Sstevel@tonic-gate 4110Sstevel@tonic-gate /* 4120Sstevel@tonic-gate * TRANSLATION_NOTE 4130Sstevel@tonic-gate * Following translations for "swap -l" should account for for 4140Sstevel@tonic-gate * alignment of header and output. 4150Sstevel@tonic-gate * The first translation is for the header. If the alignment 4160Sstevel@tonic-gate * of the header changes, change the next 5 formats as needed 4170Sstevel@tonic-gate * to make alignment of output agree with alignment of the header. 4180Sstevel@tonic-gate * The next four translations are four cases for printing the 4190Sstevel@tonic-gate * 1st & 2nd fields. 4200Sstevel@tonic-gate * The next translation is for printing the 3rd, 4th & 5th fields. 4210Sstevel@tonic-gate * 4220Sstevel@tonic-gate * Translations (if any) of the following keywords should match the 4230Sstevel@tonic-gate * translations (if any) of the swap.1M man page keywords for 4240Sstevel@tonic-gate * -l option: "swapfile", "dev", "swaplo", "blocks", "free" 4250Sstevel@tonic-gate */ 4260Sstevel@tonic-gate (void) printf( 427*1978Spetede gettext("swapfile dev swaplo blocks free\n")); 4280Sstevel@tonic-gate 4290Sstevel@tonic-gate swapent = st->swt_ent; 4300Sstevel@tonic-gate for (i = 0; i < num; i++, swapent++) { 4310Sstevel@tonic-gate if (*swapent->ste_path != '/') 4320Sstevel@tonic-gate (void) snprintf(fullpath, sizeof (fullpath), 4330Sstevel@tonic-gate "/dev/%s", swapent->ste_path); 4340Sstevel@tonic-gate else 4350Sstevel@tonic-gate (void) snprintf(fullpath, sizeof (fullpath), 4360Sstevel@tonic-gate "%s", swapent->ste_path); 4370Sstevel@tonic-gate if (stat64(fullpath, &statbuf) < 0) 4380Sstevel@tonic-gate if (*swapent->ste_path != '/') 4390Sstevel@tonic-gate (void) printf(gettext("%-20s - "), 4400Sstevel@tonic-gate swapent->ste_path); 4410Sstevel@tonic-gate else 4420Sstevel@tonic-gate (void) printf(gettext("%-20s ?,? "), 4430Sstevel@tonic-gate fullpath); 4440Sstevel@tonic-gate else { 445871Scasper if (S_ISBLK(statbuf.st_mode) || 446871Scasper S_ISCHR(statbuf.st_mode)) { 4470Sstevel@tonic-gate (void) printf(gettext("%-19s %2lu,%-2lu"), 4480Sstevel@tonic-gate fullpath, 4490Sstevel@tonic-gate major(statbuf.st_rdev), 4500Sstevel@tonic-gate minor(statbuf.st_rdev)); 451871Scasper } else { 4520Sstevel@tonic-gate (void) printf(gettext("%-20s - "), fullpath); 453871Scasper } 4540Sstevel@tonic-gate } 4550Sstevel@tonic-gate { 4560Sstevel@tonic-gate int diskblks_per_page = 4570Sstevel@tonic-gate (int)(sysconf(_SC_PAGESIZE) >> DEV_BSHIFT); 458*1978Spetede if (flag & HFLAG) { 459*1978Spetede (void) printf(gettext(" %8s"), 460*1978Spetede number_to_scaled_string(numbuf, 461*1978Spetede swapent->ste_start, DEV_BSIZE, 462*1978Spetede scale)); 463*1978Spetede (void) printf(gettext(" %8s"), 464*1978Spetede number_to_scaled_string(numbuf, 465*1978Spetede swapent->ste_pages * 466*1978Spetede diskblks_per_page, 467*1978Spetede DEV_BSIZE, scale)); 468*1978Spetede (void) printf(gettext(" %8s"), 469*1978Spetede number_to_scaled_string(numbuf, 470*1978Spetede swapent->ste_free * 471*1978Spetede diskblks_per_page, 472*1978Spetede DEV_BSIZE, scale)); 473*1978Spetede } else if (flag & KFLAG) { 474*1978Spetede (void) printf(gettext(" %7luK %7luK %7luK"), 475*1978Spetede swapent->ste_start * DEV_BSIZE / 1024, 476*1978Spetede swapent->ste_pages * diskblks_per_page * 477*1978Spetede DEV_BSIZE / 1024, 478*1978Spetede swapent->ste_free * diskblks_per_page * 479*1978Spetede DEV_BSIZE / 1024); 480*1978Spetede } else { 481*1978Spetede (void) printf(gettext(" %8lu %8lu %8lu"), 482*1978Spetede swapent->ste_start, 483*1978Spetede swapent->ste_pages * diskblks_per_page, 484*1978Spetede swapent->ste_free * diskblks_per_page); 485*1978Spetede } 4860Sstevel@tonic-gate } 4870Sstevel@tonic-gate if (swapent->ste_flags & ST_INDEL) 4880Sstevel@tonic-gate (void) printf(" INDEL\n"); 4890Sstevel@tonic-gate else 4900Sstevel@tonic-gate (void) printf("\n"); 4910Sstevel@tonic-gate } 4920Sstevel@tonic-gate return (0); 4930Sstevel@tonic-gate } 4940Sstevel@tonic-gate 495*1978Spetede /* Copied from du.c */ 496*1978Spetede static char * 497*1978Spetede number_to_scaled_string( 498*1978Spetede numbuf_t buf, /* put the result here */ 499*1978Spetede unsigned long long number, /* convert this number */ 500*1978Spetede unsigned long long unit_from, /* number of byes per input unit */ 501*1978Spetede unsigned long long scale) /* 1024 (-h) or 1000 (-H) */ 502*1978Spetede { 503*1978Spetede unsigned long long save = 0; 504*1978Spetede char *M = "KMGTPE"; /* Measurement: kilo, mega, giga, tera, peta, exa */ 505*1978Spetede char *uom = M; /* unit of measurement, initially 'K' (=M[0]) */ 506*1978Spetede 507*1978Spetede if ((long long)number == (long long) -1) { 508*1978Spetede (void) strcpy(buf, "-1"); 509*1978Spetede return (buf); 510*1978Spetede } 511*1978Spetede 512*1978Spetede /* 513*1978Spetede * Convert number from unit_from to given scale (1024 or 1000) 514*1978Spetede * This means multiply number with unit_from and divide by scale. 515*1978Spetede * if number is large enough, we first divide and then multiply 516*1978Spetede * to avoid an overflow (large enough here means 100 (rather arbitrary 517*1978Spetede * value) times scale in order to reduce rounding errors) 518*1978Spetede * otherwise, we first multiply and then divide to avoid an underflow. 519*1978Spetede */ 520*1978Spetede if (number >= 100L * scale) { 521*1978Spetede number = number / scale; 522*1978Spetede number = number * unit_from; 523*1978Spetede } else { 524*1978Spetede number = number * unit_from; 525*1978Spetede number = number / scale; 526*1978Spetede } 527*1978Spetede 528*1978Spetede /* 529*1978Spetede * Now we have number as a count of scale units. 530*1978Spetede * Stop scaling when we reached exa bytes, then something is 531*1978Spetede * probably wrong with our number.probably wrong with our number. 532*1978Spetede */ 533*1978Spetede while ((number >= scale) && (*uom != 'E')) { 534*1978Spetede uom++; /* Next unit of measurement */ 535*1978Spetede save = number; 536*1978Spetede number = (number + (scale / 2)) / scale; 537*1978Spetede } 538*1978Spetede 539*1978Spetede /* Check if we should output a decimal place after the point */ 540*1978Spetede if (save && ((save / scale) < 10)) { 541*1978Spetede /* sprintf() will round for us */ 542*1978Spetede float fnum = (float)save / scale; 543*1978Spetede (void) sprintf(buf, "%.1f%c", fnum, *uom); 544*1978Spetede } else { 545*1978Spetede (void) sprintf(buf, "%llu%c", number, *uom); 546*1978Spetede } 547*1978Spetede return (buf); 548*1978Spetede } 549*1978Spetede 550*1978Spetede 551*1978Spetede 552*1978Spetede 5530Sstevel@tonic-gate static void 5540Sstevel@tonic-gate dumpadm_err(const char *warning) 5550Sstevel@tonic-gate { 5560Sstevel@tonic-gate (void) fprintf(stderr, "%s (%s):\n", warning, strerror(errno)); 5570Sstevel@tonic-gate (void) fprintf(stderr, gettext( 5580Sstevel@tonic-gate "run dumpadm(1M) to verify dump configuration\n")); 5590Sstevel@tonic-gate } 5600Sstevel@tonic-gate 5610Sstevel@tonic-gate static int 5620Sstevel@tonic-gate delete(char *path, off_t offset) 5630Sstevel@tonic-gate { 5640Sstevel@tonic-gate swapres_t swr; 5650Sstevel@tonic-gate int fd; 5660Sstevel@tonic-gate 5670Sstevel@tonic-gate swr.sr_name = path; 5680Sstevel@tonic-gate swr.sr_start = offset; 5690Sstevel@tonic-gate 5700Sstevel@tonic-gate if (swapctl(SC_REMOVE, &swr) < 0) { 5710Sstevel@tonic-gate switch (errno) { 5720Sstevel@tonic-gate case (ENOSYS): 5730Sstevel@tonic-gate (void) fprintf(stderr, gettext( 5740Sstevel@tonic-gate "%s: Invalid operation for this filesystem type\n"), 5750Sstevel@tonic-gate path); 5760Sstevel@tonic-gate break; 5770Sstevel@tonic-gate default: 5780Sstevel@tonic-gate perror(path); 5790Sstevel@tonic-gate break; 5800Sstevel@tonic-gate } 5810Sstevel@tonic-gate return (2); 5820Sstevel@tonic-gate } 5830Sstevel@tonic-gate 5840Sstevel@tonic-gate /* 5850Sstevel@tonic-gate * If our swap -d succeeded, open up /dev/dump and ask what the dump 5860Sstevel@tonic-gate * device is set to. If this returns ENODEV, we just deleted the 5870Sstevel@tonic-gate * dump device, so try to change the dump device to another swap 5880Sstevel@tonic-gate * device. We do this by firing up /usr/sbin/dumpadm -ud swap. 5890Sstevel@tonic-gate */ 5900Sstevel@tonic-gate if ((fd = open("/dev/dump", O_RDONLY)) >= 0) { 5910Sstevel@tonic-gate char dumpdev[MAXPATHLEN]; 5920Sstevel@tonic-gate 5930Sstevel@tonic-gate if (ioctl(fd, DIOCGETDEV, dumpdev) == -1) { 5940Sstevel@tonic-gate if (errno == ENODEV) { 5950Sstevel@tonic-gate (void) printf(gettext("%s was dump device --\n" 5960Sstevel@tonic-gate "invoking dumpadm(1M) -d swap to " 5970Sstevel@tonic-gate "select new dump device\n"), path); 5980Sstevel@tonic-gate /* 5990Sstevel@tonic-gate * Close /dev/dump prior to executing dumpadm 6000Sstevel@tonic-gate * since /dev/dump mandates exclusive open. 6010Sstevel@tonic-gate */ 6020Sstevel@tonic-gate (void) close(fd); 6030Sstevel@tonic-gate 6040Sstevel@tonic-gate if (system("/usr/sbin/dumpadm -ud swap") == -1) 6050Sstevel@tonic-gate dumpadm_err(gettext( 6060Sstevel@tonic-gate "Warning: failed to execute dumpadm -d swap")); 6070Sstevel@tonic-gate } else 6080Sstevel@tonic-gate dumpadm_err(gettext( 6090Sstevel@tonic-gate "Warning: failed to check dump device")); 6100Sstevel@tonic-gate } 6110Sstevel@tonic-gate (void) close(fd); 6120Sstevel@tonic-gate } else 6130Sstevel@tonic-gate dumpadm_err(gettext("Warning: failed to open /dev/dump")); 6140Sstevel@tonic-gate 6150Sstevel@tonic-gate return (0); 6160Sstevel@tonic-gate } 6170Sstevel@tonic-gate 6180Sstevel@tonic-gate /* 6190Sstevel@tonic-gate * swapres_t structure units are in 512-blocks 6200Sstevel@tonic-gate */ 6210Sstevel@tonic-gate static int 6220Sstevel@tonic-gate add(char *path, off_t offset, off_t cnt, int flags) 6230Sstevel@tonic-gate { 6240Sstevel@tonic-gate swapres_t swr; 6250Sstevel@tonic-gate 6260Sstevel@tonic-gate int fd, have_dumpdev = 1; 6270Sstevel@tonic-gate struct statvfs fsb; 6280Sstevel@tonic-gate 6290Sstevel@tonic-gate /* 6300Sstevel@tonic-gate * Before adding swap, we first check to see if we have a dump 6310Sstevel@tonic-gate * device configured. If we don't (errno == ENODEV), and if 6320Sstevel@tonic-gate * our SC_ADD is successful, then run /usr/sbin/dumpadm -ud swap 6330Sstevel@tonic-gate * to attempt to reconfigure the dump device to the new swap. 6340Sstevel@tonic-gate */ 6350Sstevel@tonic-gate if ((fd = open("/dev/dump", O_RDONLY)) >= 0) { 6360Sstevel@tonic-gate char dumpdev[MAXPATHLEN]; 6370Sstevel@tonic-gate 6380Sstevel@tonic-gate if (ioctl(fd, DIOCGETDEV, dumpdev) == -1) { 6390Sstevel@tonic-gate if (errno == ENODEV) 6400Sstevel@tonic-gate have_dumpdev = 0; 6410Sstevel@tonic-gate else 6420Sstevel@tonic-gate dumpadm_err(gettext( 6430Sstevel@tonic-gate "Warning: failed to check dump device")); 6440Sstevel@tonic-gate } 6450Sstevel@tonic-gate 6460Sstevel@tonic-gate (void) close(fd); 6470Sstevel@tonic-gate 6480Sstevel@tonic-gate } else if (!(flags & P1FLAG)) 6490Sstevel@tonic-gate dumpadm_err(gettext("Warning: failed to open /dev/dump")); 6500Sstevel@tonic-gate 6510Sstevel@tonic-gate swr.sr_name = path; 6520Sstevel@tonic-gate swr.sr_start = offset; 6530Sstevel@tonic-gate swr.sr_length = cnt; 6540Sstevel@tonic-gate 6550Sstevel@tonic-gate if (swapctl(SC_ADD, &swr) < 0) { 6560Sstevel@tonic-gate switch (errno) { 6570Sstevel@tonic-gate case (ENOSYS): 6580Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6590Sstevel@tonic-gate "%s: Invalid operation for this filesystem type\n"), 6600Sstevel@tonic-gate path); 6610Sstevel@tonic-gate break; 6620Sstevel@tonic-gate case (EEXIST): 6630Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6640Sstevel@tonic-gate "%s: Overlapping swap files are not allowed\n"), 6650Sstevel@tonic-gate path); 6660Sstevel@tonic-gate break; 6670Sstevel@tonic-gate default: 6680Sstevel@tonic-gate perror(path); 6690Sstevel@tonic-gate break; 6700Sstevel@tonic-gate } 6710Sstevel@tonic-gate return (2); 6720Sstevel@tonic-gate } 6730Sstevel@tonic-gate 6740Sstevel@tonic-gate /* 6750Sstevel@tonic-gate * If the swapctl worked and we don't have a dump device, and /etc 6760Sstevel@tonic-gate * is part of a writeable filesystem, then run dumpadm -ud swap. 6770Sstevel@tonic-gate * If /etc (presumably part of /) is still mounted read-only, then 6780Sstevel@tonic-gate * dumpadm will fail to write its config file, so there's no point 6790Sstevel@tonic-gate * running it now. This also avoids spurious messages during boot 6800Sstevel@tonic-gate * when the first swapadd takes place, at which point / is still ro. 6810Sstevel@tonic-gate * Similarly, if swapadd invoked us with -1 or -2 (but root is 6820Sstevel@tonic-gate * writeable), we don't want to modify the dump device because 6830Sstevel@tonic-gate * /etc/init.d/savecore has yet to execute; if we run dumpadm now 6840Sstevel@tonic-gate * we would lose the user's previous setting. 6850Sstevel@tonic-gate */ 6860Sstevel@tonic-gate if (!have_dumpdev && !(flags & (P1FLAG | P2FLAG)) && 6870Sstevel@tonic-gate statvfs("/etc", &fsb) == 0 && !(fsb.f_flag & ST_RDONLY)) { 6880Sstevel@tonic-gate 6890Sstevel@tonic-gate (void) printf( 6900Sstevel@tonic-gate gettext("operating system crash dump was previously " 6910Sstevel@tonic-gate "disabled --\ninvoking dumpadm(1M) -d swap to select " 6920Sstevel@tonic-gate "new dump device\n")); 6930Sstevel@tonic-gate 6940Sstevel@tonic-gate if (system("/usr/sbin/dumpadm -ud swap") == -1) 6950Sstevel@tonic-gate dumpadm_err(gettext( 6960Sstevel@tonic-gate "Warning: failed to execute dumpadm -d swap")); 6970Sstevel@tonic-gate } 6980Sstevel@tonic-gate 6990Sstevel@tonic-gate return (0); 7000Sstevel@tonic-gate } 7010Sstevel@tonic-gate 7020Sstevel@tonic-gate static int 7030Sstevel@tonic-gate valid(char *pathname, off_t offset, off_t length) 7040Sstevel@tonic-gate { 7050Sstevel@tonic-gate struct stat64 f; 7060Sstevel@tonic-gate struct statvfs64 fs; 7070Sstevel@tonic-gate off_t need; 7080Sstevel@tonic-gate 7090Sstevel@tonic-gate if (stat64(pathname, &f) < 0 || statvfs64(pathname, &fs) < 0) { 7100Sstevel@tonic-gate (void) perror(pathname); 7110Sstevel@tonic-gate return (errno); 7120Sstevel@tonic-gate } 7130Sstevel@tonic-gate 7140Sstevel@tonic-gate if (!((S_ISREG(f.st_mode) && (f.st_mode & S_ISVTX) == S_ISVTX) || 7150Sstevel@tonic-gate S_ISBLK(f.st_mode))) { 7160Sstevel@tonic-gate (void) fprintf(stderr, 7170Sstevel@tonic-gate gettext("\"%s\" is not valid for swapping.\n" 7180Sstevel@tonic-gate "It must be a block device or a regular file with the\n" 7190Sstevel@tonic-gate "\"save user text on execution\" bit set.\n"), 7200Sstevel@tonic-gate pathname); 7210Sstevel@tonic-gate return (EINVAL); 7220Sstevel@tonic-gate } 7230Sstevel@tonic-gate 7240Sstevel@tonic-gate if (S_ISREG(f.st_mode)) { 7250Sstevel@tonic-gate if (length == 0) 7260Sstevel@tonic-gate length = (off_t)f.st_size; 7270Sstevel@tonic-gate 7280Sstevel@tonic-gate /* 7290Sstevel@tonic-gate * "f.st_blocks < 8" because the first eight 7300Sstevel@tonic-gate * 512-byte sectors are always skipped 7310Sstevel@tonic-gate */ 7320Sstevel@tonic-gate 7330Sstevel@tonic-gate if (f.st_size < (length - offset) || f.st_size == 0 || 7340Sstevel@tonic-gate f.st_size > MAXOFF_T || f.st_blocks < 8 || length < 0) { 7350Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: size is invalid\n"), 7360Sstevel@tonic-gate pathname); 7370Sstevel@tonic-gate return (EINVAL); 7380Sstevel@tonic-gate } 7390Sstevel@tonic-gate 7400Sstevel@tonic-gate if (offset < 0) { 7410Sstevel@tonic-gate (void) fprintf(stderr, 7420Sstevel@tonic-gate gettext("%s: low block is invalid\n"), 7430Sstevel@tonic-gate pathname); 7440Sstevel@tonic-gate return (EINVAL); 7450Sstevel@tonic-gate } 7460Sstevel@tonic-gate 7470Sstevel@tonic-gate need = roundup(length, fs.f_bsize) / DEV_BSIZE; 7480Sstevel@tonic-gate 7490Sstevel@tonic-gate /* 7500Sstevel@tonic-gate * "need > f.st_blocks" to account for indirect blocks 7510Sstevel@tonic-gate * Note: 7520Sstevel@tonic-gate * This can be fooled by a file large enough to 7530Sstevel@tonic-gate * contain indirect blocks that also contains holes. 7540Sstevel@tonic-gate * However, we don't know (and don't want to know) 7550Sstevel@tonic-gate * about the underlying storage implementation. 7560Sstevel@tonic-gate * But, if it doesn't have at least this many blocks, 7570Sstevel@tonic-gate * there must be a hole. 7580Sstevel@tonic-gate */ 7590Sstevel@tonic-gate 7600Sstevel@tonic-gate if (need > f.st_blocks) { 7610Sstevel@tonic-gate (void) fprintf(stderr, gettext( 7620Sstevel@tonic-gate "\"%s\" may contain holes - can't swap on it.\n"), 7630Sstevel@tonic-gate pathname); 7640Sstevel@tonic-gate return (EINVAL); 7650Sstevel@tonic-gate } 7660Sstevel@tonic-gate } 7670Sstevel@tonic-gate /* 7680Sstevel@tonic-gate * else, we cannot get st_size for S_ISBLK device and 7690Sstevel@tonic-gate * no meaningful checking can be done. 7700Sstevel@tonic-gate */ 7710Sstevel@tonic-gate 7720Sstevel@tonic-gate return (0); 7730Sstevel@tonic-gate } 774