xref: /onnv-gate/usr/src/cmd/swap/swap.c (revision 6423:437422a29d3a)
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
51978Spetede  * Common Development and Distribution License (the "License").
61978Spetede  * 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*6423Sgw25295  * Copyright 2008 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>
66*6423Sgw25295 #include	<sys/fs/zfs.h>
670Sstevel@tonic-gate 
680Sstevel@tonic-gate #define	LFLAG	0x01	/* swap -l (list swap devices) */
690Sstevel@tonic-gate #define	DFLAG	0x02	/* swap -d (delete swap device) */
700Sstevel@tonic-gate #define	AFLAG	0x04	/* swap -a (add swap device) */
710Sstevel@tonic-gate #define	SFLAG	0x08	/* swap -s (swap info summary) */
720Sstevel@tonic-gate #define	P1FLAG	0x10	/* swap -1 (swapadd pass1; do not modify dump device) */
730Sstevel@tonic-gate #define	P2FLAG	0x20	/* swap -2 (swapadd pass2; do not modify dump device) */
741978Spetede #define	HFLAG	0x40	/* swap -h (size in human readable format) */
751978Spetede #define	KFLAG	0x80	/* swap -k (size in kilobytes) */
761978Spetede 
771978Spetede #define	NUMBER_WIDTH	64
781978Spetede typedef char numbuf_t[NUMBER_WIDTH];
790Sstevel@tonic-gate 
800Sstevel@tonic-gate static char *prognamep;
810Sstevel@tonic-gate 
820Sstevel@tonic-gate static int add(char *, off_t, off_t, int);
830Sstevel@tonic-gate static int delete(char *, off_t);
840Sstevel@tonic-gate static void usage(void);
851978Spetede static int doswap(int flag);
860Sstevel@tonic-gate static int valid(char *, off_t, off_t);
871978Spetede static int list(int flag);
881978Spetede static char *number_to_scaled_string(numbuf_t buf, unsigned long long number,
891978Spetede 		unsigned long long unit_from, unsigned long long scale);
901978Spetede 
910Sstevel@tonic-gate 
920Sstevel@tonic-gate int
main(int argc,char ** argv)930Sstevel@tonic-gate main(int argc, char **argv)
940Sstevel@tonic-gate {
950Sstevel@tonic-gate 	int c, flag = 0;
960Sstevel@tonic-gate 	int ret;
97767Ssjelinek 	int error = 0;
980Sstevel@tonic-gate 	off_t s_offset = 0;
990Sstevel@tonic-gate 	off_t length = 0;
1000Sstevel@tonic-gate 	char *pathname;
101767Ssjelinek 	char *msg;
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
1040Sstevel@tonic-gate 
1050Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
1060Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
1070Sstevel@tonic-gate #endif
1080Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate 	prognamep = argv[0];
1110Sstevel@tonic-gate 	if (argc < 2) {
1120Sstevel@tonic-gate 		usage();
1130Sstevel@tonic-gate 		exit(1);
1140Sstevel@tonic-gate 	}
1150Sstevel@tonic-gate 
1161978Spetede 	while ((c = getopt(argc, argv, "khlsd:a:12")) != EOF) {
1170Sstevel@tonic-gate 		char *char_p;
1180Sstevel@tonic-gate 		switch (c) {
1190Sstevel@tonic-gate 		case 'l': 	/* list all the swap devices */
1200Sstevel@tonic-gate 			flag |= LFLAG;
1210Sstevel@tonic-gate 			break;
1220Sstevel@tonic-gate 		case 's':
1230Sstevel@tonic-gate 			flag |= SFLAG;
1240Sstevel@tonic-gate 			break;
1250Sstevel@tonic-gate 		case 'd':
1260Sstevel@tonic-gate 			/*
1270Sstevel@tonic-gate 			 * The argument for starting offset is optional.
1280Sstevel@tonic-gate 			 * If no argument is specified, the entire swap file
1290Sstevel@tonic-gate 			 * is added although this will fail if a non-zero
1300Sstevel@tonic-gate 			 * starting offset was specified when added.
1310Sstevel@tonic-gate 			 */
1320Sstevel@tonic-gate 			if ((argc - optind) > 1 || flag != 0) {
1330Sstevel@tonic-gate 				usage();
1340Sstevel@tonic-gate 				exit(1);
1350Sstevel@tonic-gate 			}
1360Sstevel@tonic-gate 			flag |= DFLAG;
1370Sstevel@tonic-gate 			pathname = optarg;
1380Sstevel@tonic-gate 			if (optind < argc) {
1390Sstevel@tonic-gate 				errno = 0;
1400Sstevel@tonic-gate 				s_offset = strtol(argv[optind++], &char_p, 10);
1410Sstevel@tonic-gate 				if (errno != 0 || *char_p != '\0') {
1420Sstevel@tonic-gate 					(void) fprintf(stderr,
1430Sstevel@tonic-gate 					    gettext("error in [low block]\n"));
1440Sstevel@tonic-gate 					exit(1);
1450Sstevel@tonic-gate 				}
1460Sstevel@tonic-gate 			}
1470Sstevel@tonic-gate 			ret = delete(pathname, s_offset);
1480Sstevel@tonic-gate 			break;
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate 		case 'a':
1510Sstevel@tonic-gate 			/*
1520Sstevel@tonic-gate 			 * The arguments for starting offset and number of
1530Sstevel@tonic-gate 			 * blocks are optional.  If only the starting offset
1540Sstevel@tonic-gate 			 * is specified, all the blocks to the end of the swap
1550Sstevel@tonic-gate 			 * file will be added.  If no starting offset is
1560Sstevel@tonic-gate 			 * specified, the entire swap file is assumed.
1570Sstevel@tonic-gate 			 */
1580Sstevel@tonic-gate 			if ((argc - optind) > 2 ||
1590Sstevel@tonic-gate 			    (flag & ~(P1FLAG | P2FLAG)) != 0) {
1600Sstevel@tonic-gate 				usage();
1610Sstevel@tonic-gate 				exit(1);
1620Sstevel@tonic-gate 			}
1630Sstevel@tonic-gate 			if (*optarg != '/') {
1640Sstevel@tonic-gate 				(void) fprintf(stderr,
1650Sstevel@tonic-gate 				    gettext("%s: path must be absolute\n"),
1660Sstevel@tonic-gate 				    prognamep);
1670Sstevel@tonic-gate 				exit(1);
1680Sstevel@tonic-gate 			}
1690Sstevel@tonic-gate 			flag |= AFLAG;
1700Sstevel@tonic-gate 			pathname = optarg;
1710Sstevel@tonic-gate 			if (optind < argc) {
1720Sstevel@tonic-gate 				errno = 0;
1730Sstevel@tonic-gate 				s_offset = strtol(argv[optind++], &char_p, 10);
1740Sstevel@tonic-gate 				if (errno != 0 || *char_p != '\0') {
1750Sstevel@tonic-gate 					(void) fprintf(stderr,
1760Sstevel@tonic-gate 					    gettext("error in [low block]\n"));
1770Sstevel@tonic-gate 					exit(1);
1780Sstevel@tonic-gate 				}
1790Sstevel@tonic-gate 			}
1800Sstevel@tonic-gate 			if (optind < argc) {
1810Sstevel@tonic-gate 				errno = 0;
1820Sstevel@tonic-gate 				length = strtol(argv[optind++], &char_p, 10);
1830Sstevel@tonic-gate 				if (errno != 0 || *char_p != '\0') {
1840Sstevel@tonic-gate 					(void) fprintf(stderr,
1850Sstevel@tonic-gate 					gettext("error in [nbr of blocks]\n"));
1860Sstevel@tonic-gate 					exit(1);
1870Sstevel@tonic-gate 				}
1880Sstevel@tonic-gate 			}
1890Sstevel@tonic-gate 			break;
1901978Spetede 		case 'h':
1911978Spetede 			flag |= HFLAG;
1921978Spetede 			break;
1931978Spetede 
1941978Spetede 		case 'k':
1951978Spetede 			flag |= KFLAG;
1961978Spetede 			break;
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate 		case '1':
1990Sstevel@tonic-gate 			flag |= P1FLAG;
2000Sstevel@tonic-gate 			break;
2010Sstevel@tonic-gate 
2020Sstevel@tonic-gate 		case '2':
2030Sstevel@tonic-gate 			flag |= P2FLAG;
2040Sstevel@tonic-gate 			break;
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate 		case '?':
2070Sstevel@tonic-gate 			usage();
2080Sstevel@tonic-gate 			exit(1);
2090Sstevel@tonic-gate 		}
2100Sstevel@tonic-gate 	}
2111978Spetede 
2121978Spetede 	if (flag & SFLAG) {
2131978Spetede 		if (flag & ~SFLAG & ~HFLAG) {
2141978Spetede 			/*
2151978Spetede 			 * The only option that can be used with -s is -h.
2161978Spetede 			 */
2171978Spetede 			usage();
2181978Spetede 			exit(1);
2191978Spetede 		}
2201978Spetede 
2211978Spetede 		ret = doswap(flag);
2221978Spetede 
2231978Spetede 	}
2241978Spetede 
2251978Spetede 	if (flag & LFLAG) {
2261978Spetede 		if (flag & ~KFLAG & ~HFLAG & ~LFLAG) {
2271978Spetede 			usage();
2281978Spetede 			exit(1);
2291978Spetede 		}
2301978Spetede 		ret = list(flag);
2311978Spetede 	}
2321978Spetede 
233767Ssjelinek 	/*
234767Ssjelinek 	 * do the add here. Check for in use prior to add.
235767Ssjelinek 	 * The values for length and offset are set above.
236767Ssjelinek 	 */
237767Ssjelinek 	if (flag & AFLAG) {
238767Ssjelinek 		/*
239767Ssjelinek 		 * If device is in use for a swap device, print message
240767Ssjelinek 		 * and exit.
241767Ssjelinek 		 */
242767Ssjelinek 		if (dm_inuse(pathname, &msg, DM_WHO_SWAP, &error) ||
243767Ssjelinek 		    error) {
244767Ssjelinek 			if (error != 0) {
245767Ssjelinek 				(void) fprintf(stderr, gettext("Error occurred"
246767Ssjelinek 				    " with device in use checking: %s\n"),
247767Ssjelinek 				    strerror(error));
248767Ssjelinek 			} else {
249767Ssjelinek 				(void) fprintf(stderr, "%s", msg);
250767Ssjelinek 				free(msg);
251767Ssjelinek 				exit(1);
252767Ssjelinek 			}
253767Ssjelinek 		}
254767Ssjelinek 		if ((ret = valid(pathname,
255767Ssjelinek 		    s_offset * 512, length * 512)) == 0) {
256767Ssjelinek 		    ret = add(pathname, s_offset, length, flag);
257767Ssjelinek 		}
258767Ssjelinek 	}
2591978Spetede 	if (!(flag & ~HFLAG & ~KFLAG)) {
2601978Spetede 		/* only -h and/or -k flag, or no flag */
2610Sstevel@tonic-gate 		usage();
2620Sstevel@tonic-gate 		exit(1);
2630Sstevel@tonic-gate 	}
2640Sstevel@tonic-gate 	return (ret);
2650Sstevel@tonic-gate }
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate static void
usage(void)2690Sstevel@tonic-gate usage(void)
2700Sstevel@tonic-gate {
2710Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("Usage:\t%s -l\n"), prognamep);
2721978Spetede 	(void) fprintf(stderr, gettext("\tsub option :\n"));
2731978Spetede 	(void) fprintf(stderr, gettext("\t\t-h : displays size in human "
2741978Spetede 				"readable format\n"));
2751978Spetede 	(void) fprintf(stderr, gettext("\t\t-k : displays size in KB\n"));
2760Sstevel@tonic-gate 	(void) fprintf(stderr, "\t%s -s\n", prognamep);
2771978Spetede 	(void) fprintf(stderr, gettext("\tsub option :\n"));
2781978Spetede 	(void) fprintf(stderr, gettext("\t\t-h : displays size in human "
2791978Spetede 				"readable format rather than KB\n"));
2800Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("\t%s -d <file name> [low block]\n"),
2811978Spetede 				prognamep);
2820Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("\t%s -a <file name> [low block]"
2831978Spetede 				" [nbr of blocks]\n"), prognamep);
2840Sstevel@tonic-gate }
2850Sstevel@tonic-gate 
2860Sstevel@tonic-gate /*
2870Sstevel@tonic-gate  * Implement:
2880Sstevel@tonic-gate  *	#define ctok(x) ((ctob(x))>>10)
2890Sstevel@tonic-gate  * in a machine independent way. (Both assume a click > 1k)
2900Sstevel@tonic-gate  */
2910Sstevel@tonic-gate static size_t
ctok(pgcnt_t clicks)2920Sstevel@tonic-gate ctok(pgcnt_t clicks)
2930Sstevel@tonic-gate {
2940Sstevel@tonic-gate 	static int factor = -1;
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate 	if (factor == -1)
2970Sstevel@tonic-gate 		factor = (int)(sysconf(_SC_PAGESIZE) >> 10);
2980Sstevel@tonic-gate 	return ((size_t)(clicks * factor));
2990Sstevel@tonic-gate }
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate static int
doswap(int flag)3031978Spetede doswap(int flag)
3040Sstevel@tonic-gate {
3050Sstevel@tonic-gate 	struct anoninfo ai;
3060Sstevel@tonic-gate 	pgcnt_t allocated, reserved, available;
3071978Spetede 	numbuf_t numbuf;
3081978Spetede 	unsigned long long scale = 1024L;
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 	/*
3110Sstevel@tonic-gate 	 * max = total amount of swap space including physical memory
3120Sstevel@tonic-gate 	 * ai.ani_max = MAX(anoninfo.ani_resv, anoninfo.ani_max) +
3130Sstevel@tonic-gate 	 *	availrmem - swapfs_minfree;
3140Sstevel@tonic-gate 	 * ai.ani_free = amount of unallocated anonymous memory
3150Sstevel@tonic-gate 	 *	(ie. = resverved_unallocated + unreserved)
3160Sstevel@tonic-gate 	 * ai.ani_free = anoninfo.ani_free + (availrmem - swapfs_minfree);
3170Sstevel@tonic-gate 	 * ai.ani_resv = total amount of reserved anonymous memory
3180Sstevel@tonic-gate 	 * ai.ani_resv = anoninfo.ani_resv;
3190Sstevel@tonic-gate 	 *
3200Sstevel@tonic-gate 	 * allocated = anon memory not free
3210Sstevel@tonic-gate 	 * reserved = anon memory reserved but not allocated
3220Sstevel@tonic-gate 	 * available = anon memory not reserved
3230Sstevel@tonic-gate 	 */
3240Sstevel@tonic-gate 	if (swapctl(SC_AINFO, &ai) == -1) {
3250Sstevel@tonic-gate 		perror(prognamep);
3260Sstevel@tonic-gate 		return (2);
3270Sstevel@tonic-gate 	}
3280Sstevel@tonic-gate 
3290Sstevel@tonic-gate 	allocated = ai.ani_max - ai.ani_free;
3300Sstevel@tonic-gate 	reserved = ai.ani_resv - allocated;
3310Sstevel@tonic-gate 	available = ai.ani_max - ai.ani_resv;
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate 	/*
3340Sstevel@tonic-gate 	 * TRANSLATION_NOTE
3350Sstevel@tonic-gate 	 * Translations (if any) of these keywords should match with
3360Sstevel@tonic-gate 	 * translations (if any) of the swap.1M man page keywords for
3370Sstevel@tonic-gate 	 * -s option:  "allocated", "reserved", "used", "available"
3380Sstevel@tonic-gate 	 */
3391978Spetede 
3401978Spetede 	if (flag & HFLAG) {
3411978Spetede 		int factor = (int)(sysconf(_SC_PAGESIZE));
3421978Spetede 		(void) printf(gettext("total: %s allocated + "),
3431978Spetede 				number_to_scaled_string(numbuf, allocated,
3441978Spetede 				factor, scale));
3451978Spetede 		(void) printf(gettext("%s reserved = "),
3461980Spetede 				number_to_scaled_string(numbuf, reserved,
3471978Spetede 				factor, scale));
3481978Spetede 		(void) printf(gettext("%s used, "),
3491978Spetede 				number_to_scaled_string(numbuf,
3501978Spetede 				allocated + reserved, factor, scale));
3511978Spetede 		(void) printf(gettext("%s available\n"),
3521978Spetede 				number_to_scaled_string(numbuf, available,
3531978Spetede 				factor, scale));
3541978Spetede 	} else {
3551978Spetede 		(void) printf(gettext("total: %luk bytes allocated + %luk"
3561978Spetede 				" reserved = %luk used, %luk available\n"),
3571978Spetede 				ctok(allocated), ctok(reserved),
3581978Spetede 				ctok(reserved) + ctok(allocated),
3591978Spetede 				ctok(available));
3601978Spetede 	}
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate 	return (0);
3630Sstevel@tonic-gate }
3640Sstevel@tonic-gate 
3650Sstevel@tonic-gate static int
list(int flag)3661978Spetede list(int flag)
3670Sstevel@tonic-gate {
3680Sstevel@tonic-gate 	struct swaptable 	*st;
3690Sstevel@tonic-gate 	struct swapent	*swapent;
3700Sstevel@tonic-gate 	int	i;
3710Sstevel@tonic-gate 	struct stat64 statbuf;
3720Sstevel@tonic-gate 	char		*path;
3730Sstevel@tonic-gate 	char		fullpath[MAXPATHLEN+1];
3740Sstevel@tonic-gate 	int		num;
3751978Spetede 	numbuf_t numbuf;
3761978Spetede 	unsigned long long scale = 1024L;
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate 	if ((num = swapctl(SC_GETNSWP, NULL)) == -1) {
3790Sstevel@tonic-gate 		perror(prognamep);
3800Sstevel@tonic-gate 		return (2);
3810Sstevel@tonic-gate 	}
3820Sstevel@tonic-gate 	if (num == 0) {
3830Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("No swap devices configured\n"));
3840Sstevel@tonic-gate 		return (1);
3850Sstevel@tonic-gate 	}
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate 	if ((st = malloc(num * sizeof (swapent_t) + sizeof (int)))
3880Sstevel@tonic-gate 	    == NULL) {
3890Sstevel@tonic-gate 		(void) fprintf(stderr,
3900Sstevel@tonic-gate 			gettext("Malloc failed. Please try later.\n"));
3910Sstevel@tonic-gate 		perror(prognamep);
3920Sstevel@tonic-gate 		return (2);
3930Sstevel@tonic-gate 	}
3940Sstevel@tonic-gate 	if ((path = malloc(num * MAXPATHLEN)) == NULL) {
3950Sstevel@tonic-gate 		(void) fprintf(stderr,
3960Sstevel@tonic-gate 			gettext("Malloc failed. Please try later.\n"));
3970Sstevel@tonic-gate 		perror(prognamep);
3980Sstevel@tonic-gate 		return (2);
3990Sstevel@tonic-gate 	}
4000Sstevel@tonic-gate 	swapent = st->swt_ent;
4010Sstevel@tonic-gate 	for (i = 0; i < num; i++, swapent++) {
4020Sstevel@tonic-gate 		swapent->ste_path = path;
4030Sstevel@tonic-gate 		path += MAXPATHLEN;
4040Sstevel@tonic-gate 	}
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate 	st->swt_n = num;
4070Sstevel@tonic-gate 	if ((num = swapctl(SC_LIST, st)) == -1) {
4080Sstevel@tonic-gate 		perror(prognamep);
4090Sstevel@tonic-gate 		return (2);
4100Sstevel@tonic-gate 	}
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate 	/*
4130Sstevel@tonic-gate 	 * TRANSLATION_NOTE
4140Sstevel@tonic-gate 	 * Following translations for "swap -l" should account for for
4150Sstevel@tonic-gate 	 * alignment of header and output.
4160Sstevel@tonic-gate 	 * The first translation is for the header.  If the alignment
4170Sstevel@tonic-gate 	 *	of the header changes, change the next 5 formats as needed
4180Sstevel@tonic-gate 	 *	to make alignment of output agree with alignment of the header.
4190Sstevel@tonic-gate 	 * The next four translations are four cases for printing the
4200Sstevel@tonic-gate 	 * 	1st & 2nd fields.
4210Sstevel@tonic-gate 	 * The next translation is for printing the 3rd, 4th & 5th fields.
4220Sstevel@tonic-gate 	 *
4230Sstevel@tonic-gate 	 * Translations (if any) of the following keywords should match the
4240Sstevel@tonic-gate 	 * translations (if any) of the swap.1M man page keywords for
4250Sstevel@tonic-gate 	 * -l option:  "swapfile", "dev", "swaplo", "blocks", "free"
4260Sstevel@tonic-gate 	 */
4270Sstevel@tonic-gate 	(void) printf(
4281978Spetede 	    gettext("swapfile             dev    swaplo   blocks     free\n"));
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate 	swapent = st->swt_ent;
4310Sstevel@tonic-gate 	for (i = 0; i < num; i++, swapent++) {
4320Sstevel@tonic-gate 		if (*swapent->ste_path != '/')
4330Sstevel@tonic-gate 			(void) snprintf(fullpath, sizeof (fullpath),
4340Sstevel@tonic-gate 				"/dev/%s", swapent->ste_path);
4350Sstevel@tonic-gate 		else
4360Sstevel@tonic-gate 			(void) snprintf(fullpath, sizeof (fullpath),
4370Sstevel@tonic-gate 				"%s", swapent->ste_path);
4380Sstevel@tonic-gate 		if (stat64(fullpath, &statbuf) < 0)
4390Sstevel@tonic-gate 			if (*swapent->ste_path != '/')
4400Sstevel@tonic-gate 				(void) printf(gettext("%-20s  -  "),
4410Sstevel@tonic-gate 					swapent->ste_path);
4420Sstevel@tonic-gate 			else
4430Sstevel@tonic-gate 				(void) printf(gettext("%-20s ?,? "),
4440Sstevel@tonic-gate 					fullpath);
4450Sstevel@tonic-gate 		else {
446871Scasper 			if (S_ISBLK(statbuf.st_mode) ||
447871Scasper 			    S_ISCHR(statbuf.st_mode)) {
4480Sstevel@tonic-gate 				(void) printf(gettext("%-19s %2lu,%-2lu"),
4490Sstevel@tonic-gate 				    fullpath,
4500Sstevel@tonic-gate 				    major(statbuf.st_rdev),
4510Sstevel@tonic-gate 				    minor(statbuf.st_rdev));
452871Scasper 			} else {
4530Sstevel@tonic-gate 				(void) printf(gettext("%-20s  -  "), fullpath);
454871Scasper 			}
4550Sstevel@tonic-gate 		}
4560Sstevel@tonic-gate 		{
4570Sstevel@tonic-gate 		int diskblks_per_page =
4580Sstevel@tonic-gate 			(int)(sysconf(_SC_PAGESIZE) >> DEV_BSHIFT);
4591978Spetede 		if (flag & HFLAG) {
4601978Spetede 			(void) printf(gettext(" %8s"),
4611978Spetede 					number_to_scaled_string(numbuf,
4621978Spetede 					swapent->ste_start, DEV_BSIZE,
4631978Spetede 					scale));
4641978Spetede 			(void) printf(gettext(" %8s"),
4651978Spetede 					number_to_scaled_string(numbuf,
4661978Spetede 					swapent->ste_pages *
4671978Spetede 						diskblks_per_page,
4681978Spetede 					DEV_BSIZE, scale));
4691978Spetede 			(void) printf(gettext(" %8s"),
4701978Spetede 					number_to_scaled_string(numbuf,
4711978Spetede 					swapent->ste_free *
4721978Spetede 						diskblks_per_page,
4731978Spetede 					DEV_BSIZE, scale));
4741978Spetede 		} else if (flag & KFLAG) {
4751978Spetede 			(void) printf(gettext(" %7luK %7luK %7luK"),
4761978Spetede 					swapent->ste_start * DEV_BSIZE / 1024,
4771978Spetede 					swapent->ste_pages * diskblks_per_page *
4781978Spetede 						DEV_BSIZE / 1024,
4791978Spetede 					swapent->ste_free * diskblks_per_page *
4801978Spetede 						DEV_BSIZE / 1024);
4811978Spetede 		} else {
4821978Spetede 			(void) printf(gettext(" %8lu %8lu %8lu"),
4831978Spetede 					swapent->ste_start,
4841978Spetede 					swapent->ste_pages * diskblks_per_page,
4851978Spetede 					swapent->ste_free * diskblks_per_page);
4861978Spetede 		}
4870Sstevel@tonic-gate 		}
4880Sstevel@tonic-gate 		if (swapent->ste_flags & ST_INDEL)
4890Sstevel@tonic-gate 			(void) printf(" INDEL\n");
4900Sstevel@tonic-gate 		else
4910Sstevel@tonic-gate 			(void) printf("\n");
4920Sstevel@tonic-gate 	}
4930Sstevel@tonic-gate 	return (0);
4940Sstevel@tonic-gate }
4950Sstevel@tonic-gate 
4961978Spetede /* Copied from du.c */
4971978Spetede static char *
number_to_scaled_string(numbuf_t buf,unsigned long long number,unsigned long long unit_from,unsigned long long scale)4981978Spetede number_to_scaled_string(
4991978Spetede 	numbuf_t buf,			/* put the result here */
5001978Spetede 	unsigned long long number,	/* convert this number */
5011978Spetede 	unsigned long long unit_from,	/* number of byes per input unit */
5021978Spetede 	unsigned long long scale)	/* 1024 (-h) or 1000 (-H) */
5031978Spetede {
5041978Spetede 	unsigned long long save = 0;
5051978Spetede 	char *M = "KMGTPE"; /* Measurement: kilo, mega, giga, tera, peta, exa */
5061978Spetede 	char *uom = M;	/* unit of measurement, initially 'K' (=M[0]) */
5071978Spetede 
5081978Spetede 	if ((long long)number == (long long) -1) {
5091978Spetede 		(void) strcpy(buf, "-1");
5101978Spetede 		return (buf);
5111978Spetede 	}
5121978Spetede 
5131978Spetede 	/*
5141978Spetede 	 * Convert number from unit_from to given scale (1024 or 1000)
5151978Spetede 	 * This means multiply number with unit_from and divide by scale.
5161978Spetede 	 * if number is large enough, we first divide and then multiply
5171978Spetede 	 * to avoid an overflow (large enough here means 100 (rather arbitrary
5181978Spetede 	 * value) times scale in order to reduce rounding errors)
5191978Spetede 	 * otherwise, we first multiply and then divide to avoid an underflow.
5201978Spetede 	 */
5211978Spetede 	if (number >= 100L * scale) {
5221978Spetede 		number = number / scale;
5231978Spetede 		number = number * unit_from;
5241978Spetede 	} else {
5251978Spetede 		number = number * unit_from;
5261978Spetede 		number = number / scale;
5271978Spetede 	}
5281978Spetede 
5291978Spetede 	/*
5301978Spetede 	 * Now we have number as a count of scale units.
5311978Spetede 	 * Stop scaling when we reached exa bytes, then something is
5321980Spetede 	 * probably wrong with our number.
5331978Spetede 	 */
5341978Spetede 	while ((number >= scale) && (*uom != 'E')) {
5351978Spetede 		uom++;	/* Next unit of measurement */
5361978Spetede 		save = number;
5371978Spetede 		number = (number + (scale / 2)) / scale;
5381978Spetede 	}
5391978Spetede 
5401978Spetede 	/* Check if we should output a decimal place after the point */
5411978Spetede 	if (save && ((save / scale) < 10)) {
5421978Spetede 		/* sprintf() will round for us */
5431978Spetede 		float fnum = (float)save / scale;
5441978Spetede 		(void) sprintf(buf, "%.1f%c", fnum, *uom);
5451978Spetede 	} else {
5461978Spetede 		(void) sprintf(buf, "%llu%c", number, *uom);
5471978Spetede 	}
5481978Spetede 	return (buf);
5491978Spetede }
5501978Spetede 
5511978Spetede 
5521978Spetede 
5531978Spetede 
5540Sstevel@tonic-gate static void
dumpadm_err(const char * warning)5550Sstevel@tonic-gate dumpadm_err(const char *warning)
5560Sstevel@tonic-gate {
5570Sstevel@tonic-gate 	(void) fprintf(stderr, "%s (%s):\n", warning, strerror(errno));
5580Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(
5590Sstevel@tonic-gate 	    "run dumpadm(1M) to verify dump configuration\n"));
5600Sstevel@tonic-gate }
5610Sstevel@tonic-gate 
5620Sstevel@tonic-gate static int
delete(char * path,off_t offset)5630Sstevel@tonic-gate delete(char *path, off_t offset)
5640Sstevel@tonic-gate {
5650Sstevel@tonic-gate 	swapres_t swr;
5660Sstevel@tonic-gate 	int fd;
5670Sstevel@tonic-gate 
5680Sstevel@tonic-gate 	swr.sr_name = path;
5690Sstevel@tonic-gate 	swr.sr_start = offset;
5700Sstevel@tonic-gate 
5710Sstevel@tonic-gate 	if (swapctl(SC_REMOVE, &swr) < 0) {
5720Sstevel@tonic-gate 		switch (errno) {
5730Sstevel@tonic-gate 		case (ENOSYS):
5740Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
5750Sstevel@tonic-gate 			    "%s: Invalid operation for this filesystem type\n"),
5760Sstevel@tonic-gate 			    path);
5770Sstevel@tonic-gate 			break;
5780Sstevel@tonic-gate 		default:
5790Sstevel@tonic-gate 			perror(path);
5800Sstevel@tonic-gate 			break;
5810Sstevel@tonic-gate 		}
5820Sstevel@tonic-gate 		return (2);
5830Sstevel@tonic-gate 	}
5840Sstevel@tonic-gate 
5850Sstevel@tonic-gate 	/*
5860Sstevel@tonic-gate 	 * If our swap -d succeeded, open up /dev/dump and ask what the dump
5870Sstevel@tonic-gate 	 * device is set to.  If this returns ENODEV, we just deleted the
5880Sstevel@tonic-gate 	 * dump device, so try to change the dump device to another swap
5890Sstevel@tonic-gate 	 * device.  We do this by firing up /usr/sbin/dumpadm -ud swap.
5900Sstevel@tonic-gate 	 */
5910Sstevel@tonic-gate 	if ((fd = open("/dev/dump", O_RDONLY)) >= 0) {
5920Sstevel@tonic-gate 		char dumpdev[MAXPATHLEN];
5930Sstevel@tonic-gate 
5940Sstevel@tonic-gate 		if (ioctl(fd, DIOCGETDEV, dumpdev) == -1) {
5950Sstevel@tonic-gate 			if (errno == ENODEV) {
5960Sstevel@tonic-gate 				(void) printf(gettext("%s was dump device --\n"
5970Sstevel@tonic-gate 				    "invoking dumpadm(1M) -d swap to "
5980Sstevel@tonic-gate 				    "select new dump device\n"), path);
5990Sstevel@tonic-gate 				/*
6000Sstevel@tonic-gate 				 * Close /dev/dump prior to executing dumpadm
6010Sstevel@tonic-gate 				 * since /dev/dump mandates exclusive open.
6020Sstevel@tonic-gate 				 */
6030Sstevel@tonic-gate 				(void) close(fd);
6040Sstevel@tonic-gate 
6050Sstevel@tonic-gate 				if (system("/usr/sbin/dumpadm -ud swap") == -1)
6060Sstevel@tonic-gate 					dumpadm_err(gettext(
6070Sstevel@tonic-gate 				"Warning: failed to execute dumpadm -d swap"));
6080Sstevel@tonic-gate 			} else
6090Sstevel@tonic-gate 				dumpadm_err(gettext(
6100Sstevel@tonic-gate 				"Warning: failed to check dump device"));
6110Sstevel@tonic-gate 		}
6120Sstevel@tonic-gate 		(void) close(fd);
6130Sstevel@tonic-gate 	} else
6140Sstevel@tonic-gate 		dumpadm_err(gettext("Warning: failed to open /dev/dump"));
6150Sstevel@tonic-gate 
6160Sstevel@tonic-gate 	return (0);
6170Sstevel@tonic-gate }
6180Sstevel@tonic-gate 
6190Sstevel@tonic-gate /*
6200Sstevel@tonic-gate  * swapres_t structure units are in 512-blocks
6210Sstevel@tonic-gate  */
6220Sstevel@tonic-gate static int
add(char * path,off_t offset,off_t cnt,int flags)6230Sstevel@tonic-gate add(char *path, off_t offset, off_t cnt, int flags)
6240Sstevel@tonic-gate {
6250Sstevel@tonic-gate 	swapres_t swr;
6260Sstevel@tonic-gate 
6270Sstevel@tonic-gate 	int fd, have_dumpdev = 1;
6280Sstevel@tonic-gate 	struct statvfs fsb;
6290Sstevel@tonic-gate 
6300Sstevel@tonic-gate 	/*
6310Sstevel@tonic-gate 	 * Before adding swap, we first check to see if we have a dump
6320Sstevel@tonic-gate 	 * device configured.  If we don't (errno == ENODEV), and if
6330Sstevel@tonic-gate 	 * our SC_ADD is successful, then run /usr/sbin/dumpadm -ud swap
6340Sstevel@tonic-gate 	 * to attempt to reconfigure the dump device to the new swap.
6350Sstevel@tonic-gate 	 */
6360Sstevel@tonic-gate 	if ((fd = open("/dev/dump", O_RDONLY)) >= 0) {
6370Sstevel@tonic-gate 		char dumpdev[MAXPATHLEN];
6380Sstevel@tonic-gate 
6390Sstevel@tonic-gate 		if (ioctl(fd, DIOCGETDEV, dumpdev) == -1) {
6400Sstevel@tonic-gate 			if (errno == ENODEV)
6410Sstevel@tonic-gate 				have_dumpdev = 0;
6420Sstevel@tonic-gate 			else
6430Sstevel@tonic-gate 				dumpadm_err(gettext(
6440Sstevel@tonic-gate 				    "Warning: failed to check dump device"));
6450Sstevel@tonic-gate 		}
6460Sstevel@tonic-gate 
6470Sstevel@tonic-gate 		(void) close(fd);
6480Sstevel@tonic-gate 
649*6423Sgw25295 		/*
650*6423Sgw25295 		 * zvols cannot act as both a swap device and dump device.
651*6423Sgw25295 		 */
652*6423Sgw25295 		if (strncmp(dumpdev, ZVOL_FULL_DEV_DIR,
653*6423Sgw25295 		    strlen(ZVOL_FULL_DEV_DIR)) == 0) {
654*6423Sgw25295 			if (strcmp(dumpdev, path) == 0) {
655*6423Sgw25295 				(void) fprintf(stderr, gettext("%s: zvol "
656*6423Sgw25295 				    "cannot be used as a swap device and a "
657*6423Sgw25295 				    "dump device\n"), path);
658*6423Sgw25295 				return (2);
659*6423Sgw25295 			}
660*6423Sgw25295 		}
661*6423Sgw25295 
6620Sstevel@tonic-gate 	} else if (!(flags & P1FLAG))
6630Sstevel@tonic-gate 		dumpadm_err(gettext("Warning: failed to open /dev/dump"));
6640Sstevel@tonic-gate 
6650Sstevel@tonic-gate 	swr.sr_name = path;
6660Sstevel@tonic-gate 	swr.sr_start = offset;
6670Sstevel@tonic-gate 	swr.sr_length = cnt;
6680Sstevel@tonic-gate 
6690Sstevel@tonic-gate 	if (swapctl(SC_ADD, &swr) < 0) {
6700Sstevel@tonic-gate 		switch (errno) {
6710Sstevel@tonic-gate 		case (ENOSYS):
6720Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
6730Sstevel@tonic-gate 			    "%s: Invalid operation for this filesystem type\n"),
6740Sstevel@tonic-gate 			    path);
6750Sstevel@tonic-gate 			break;
6760Sstevel@tonic-gate 		case (EEXIST):
6770Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
6780Sstevel@tonic-gate 			    "%s: Overlapping swap files are not allowed\n"),
6790Sstevel@tonic-gate 			    path);
6800Sstevel@tonic-gate 			break;
6810Sstevel@tonic-gate 		default:
6820Sstevel@tonic-gate 			perror(path);
6830Sstevel@tonic-gate 			break;
6840Sstevel@tonic-gate 		}
6850Sstevel@tonic-gate 		return (2);
6860Sstevel@tonic-gate 	}
6870Sstevel@tonic-gate 
6880Sstevel@tonic-gate 	/*
6890Sstevel@tonic-gate 	 * If the swapctl worked and we don't have a dump device, and /etc
6900Sstevel@tonic-gate 	 * is part of a writeable filesystem, then run dumpadm -ud swap.
6910Sstevel@tonic-gate 	 * If /etc (presumably part of /) is still mounted read-only, then
6920Sstevel@tonic-gate 	 * dumpadm will fail to write its config file, so there's no point
6930Sstevel@tonic-gate 	 * running it now.  This also avoids spurious messages during boot
6940Sstevel@tonic-gate 	 * when the first swapadd takes place, at which point / is still ro.
6950Sstevel@tonic-gate 	 * Similarly, if swapadd invoked us with -1 or -2 (but root is
6960Sstevel@tonic-gate 	 * writeable), we don't want to modify the dump device because
6970Sstevel@tonic-gate 	 * /etc/init.d/savecore has yet to execute; if we run dumpadm now
6980Sstevel@tonic-gate 	 * we would lose the user's previous setting.
6990Sstevel@tonic-gate 	 */
7000Sstevel@tonic-gate 	if (!have_dumpdev && !(flags & (P1FLAG | P2FLAG)) &&
7010Sstevel@tonic-gate 	    statvfs("/etc", &fsb) == 0 && !(fsb.f_flag & ST_RDONLY)) {
7020Sstevel@tonic-gate 
7030Sstevel@tonic-gate 		(void) printf(
7040Sstevel@tonic-gate 			gettext("operating system crash dump was previously "
7050Sstevel@tonic-gate 		    "disabled --\ninvoking dumpadm(1M) -d swap to select "
7060Sstevel@tonic-gate 		    "new dump device\n"));
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate 		if (system("/usr/sbin/dumpadm -ud swap") == -1)
7090Sstevel@tonic-gate 			dumpadm_err(gettext(
7100Sstevel@tonic-gate 			    "Warning: failed to execute dumpadm -d swap"));
7110Sstevel@tonic-gate 	}
7120Sstevel@tonic-gate 
7130Sstevel@tonic-gate 	return (0);
7140Sstevel@tonic-gate }
7150Sstevel@tonic-gate 
7160Sstevel@tonic-gate static int
valid(char * pathname,off_t offset,off_t length)7170Sstevel@tonic-gate valid(char *pathname, off_t offset, off_t length)
7180Sstevel@tonic-gate {
7190Sstevel@tonic-gate 	struct stat64		f;
7200Sstevel@tonic-gate 	struct statvfs64	fs;
7210Sstevel@tonic-gate 	off_t		need;
7220Sstevel@tonic-gate 
7230Sstevel@tonic-gate 	if (stat64(pathname, &f) < 0 || statvfs64(pathname,  &fs) < 0) {
7240Sstevel@tonic-gate 		(void) perror(pathname);
7250Sstevel@tonic-gate 		return (errno);
7260Sstevel@tonic-gate 	}
7270Sstevel@tonic-gate 
7280Sstevel@tonic-gate 	if (!((S_ISREG(f.st_mode) && (f.st_mode & S_ISVTX) == S_ISVTX) ||
7290Sstevel@tonic-gate 		S_ISBLK(f.st_mode))) {
7300Sstevel@tonic-gate 		(void) fprintf(stderr,
7310Sstevel@tonic-gate 		    gettext("\"%s\" is not valid for swapping.\n"
7320Sstevel@tonic-gate 		    "It must be a block device or a regular file with the\n"
7330Sstevel@tonic-gate 		    "\"save user text on execution\" bit set.\n"),
7340Sstevel@tonic-gate 		    pathname);
7350Sstevel@tonic-gate 		return (EINVAL);
7360Sstevel@tonic-gate 	}
7370Sstevel@tonic-gate 
7380Sstevel@tonic-gate 	if (S_ISREG(f.st_mode)) {
7390Sstevel@tonic-gate 		if (length == 0)
7400Sstevel@tonic-gate 			length = (off_t)f.st_size;
7410Sstevel@tonic-gate 
7420Sstevel@tonic-gate 		/*
7430Sstevel@tonic-gate 		 * "f.st_blocks < 8" because the first eight
7440Sstevel@tonic-gate 		 * 512-byte sectors are always skipped
7450Sstevel@tonic-gate 		 */
7460Sstevel@tonic-gate 
7470Sstevel@tonic-gate 		if (f.st_size < (length - offset) || f.st_size == 0 ||
7480Sstevel@tonic-gate 		    f.st_size > MAXOFF_T || f.st_blocks < 8 || length < 0) {
7490Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("%s: size is invalid\n"),
7500Sstevel@tonic-gate 			    pathname);
7510Sstevel@tonic-gate 			return (EINVAL);
7520Sstevel@tonic-gate 		}
7530Sstevel@tonic-gate 
7540Sstevel@tonic-gate 		if (offset < 0) {
7550Sstevel@tonic-gate 			(void) fprintf(stderr,
7560Sstevel@tonic-gate 				gettext("%s: low block is invalid\n"),
7570Sstevel@tonic-gate 				pathname);
7580Sstevel@tonic-gate 			return (EINVAL);
7590Sstevel@tonic-gate 		}
7600Sstevel@tonic-gate 
7610Sstevel@tonic-gate 		need = roundup(length, fs.f_bsize) / DEV_BSIZE;
7620Sstevel@tonic-gate 
7630Sstevel@tonic-gate 		/*
7640Sstevel@tonic-gate 		 * "need > f.st_blocks" to account for indirect blocks
7650Sstevel@tonic-gate 		 * Note:
7660Sstevel@tonic-gate 		 *  This can be fooled by a file large enough to
7670Sstevel@tonic-gate 		 *  contain indirect blocks that also contains holes.
7680Sstevel@tonic-gate 		 *  However, we don't know (and don't want to know)
7690Sstevel@tonic-gate 		 *  about the underlying storage implementation.
7700Sstevel@tonic-gate 		 *  But, if it doesn't have at least this many blocks,
7710Sstevel@tonic-gate 		 *  there must be a hole.
7720Sstevel@tonic-gate 		 */
7730Sstevel@tonic-gate 
7740Sstevel@tonic-gate 		if (need > f.st_blocks) {
7750Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
7760Sstevel@tonic-gate 			    "\"%s\" may contain holes - can't swap on it.\n"),
7770Sstevel@tonic-gate 			    pathname);
7780Sstevel@tonic-gate 			return (EINVAL);
7790Sstevel@tonic-gate 		}
7800Sstevel@tonic-gate 	}
7810Sstevel@tonic-gate 	/*
7820Sstevel@tonic-gate 	 * else, we cannot get st_size for S_ISBLK device and
7830Sstevel@tonic-gate 	 * no meaningful checking can be done.
7840Sstevel@tonic-gate 	 */
7850Sstevel@tonic-gate 
7860Sstevel@tonic-gate 	return (0);
7870Sstevel@tonic-gate }
788