xref: /onnv-gate/usr/src/lib/libumem/common/envvar.c (revision 6812:febeba71273d)
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
51528Sjwadams  * Common Development and Distribution License (the "License").
61528Sjwadams  * 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  */
21*5891Sraf 
220Sstevel@tonic-gate /*
23*5891Sraf  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include <ctype.h>
300Sstevel@tonic-gate #include <errno.h>
310Sstevel@tonic-gate #include <limits.h>
320Sstevel@tonic-gate #include <stdlib.h>
330Sstevel@tonic-gate #include <string.h>
340Sstevel@tonic-gate #include <dlfcn.h>
350Sstevel@tonic-gate #include "umem_base.h"
360Sstevel@tonic-gate #include "vmem_base.h"
370Sstevel@tonic-gate 
380Sstevel@tonic-gate /*
390Sstevel@tonic-gate  * A umem environment variable, like UMEM_DEBUG, is set to a series
400Sstevel@tonic-gate  * of items, seperated by ',':
410Sstevel@tonic-gate  *
420Sstevel@tonic-gate  *   UMEM_DEBUG="audit=10,guards,firewall=512"
430Sstevel@tonic-gate  *
440Sstevel@tonic-gate  * This structure describes items.  Each item has a name, type, and
450Sstevel@tonic-gate  * description.  During processing, an item read from the user may
460Sstevel@tonic-gate  * be either "valid" or "invalid".
470Sstevel@tonic-gate  *
480Sstevel@tonic-gate  * A valid item has an argument, if required, and it is of the right
490Sstevel@tonic-gate  * form (doesn't overflow, doesn't contain any unexpected characters).
500Sstevel@tonic-gate  *
510Sstevel@tonic-gate  * If the item is valid, item_flag_target != NULL, and:
520Sstevel@tonic-gate  *	type is not CLEARFLAG, then (*item_flag_target) |= item_flag_value
530Sstevel@tonic-gate  *	type is CLEARFLAG, then (*item_flag_target) &= ~item_flag_value
540Sstevel@tonic-gate  */
550Sstevel@tonic-gate 
560Sstevel@tonic-gate #define	UMEM_ENV_ITEM_MAX	512
570Sstevel@tonic-gate 
580Sstevel@tonic-gate struct umem_env_item;
590Sstevel@tonic-gate 
600Sstevel@tonic-gate typedef int arg_process_t(const struct umem_env_item *item, const char *value);
610Sstevel@tonic-gate #define	ARG_SUCCESS	0	/* processing successful */
620Sstevel@tonic-gate #define	ARG_BAD		1	/* argument had a bad value */
630Sstevel@tonic-gate 
640Sstevel@tonic-gate typedef struct umem_env_item {
650Sstevel@tonic-gate 	const char *item_name;	/* tag in environment variable */
660Sstevel@tonic-gate 	const char *item_interface_stability;
670Sstevel@tonic-gate 	enum {
680Sstevel@tonic-gate 	    ITEM_INVALID,
690Sstevel@tonic-gate 	    ITEM_FLAG,		/* only a flag.  No argument allowed */
700Sstevel@tonic-gate 	    ITEM_CLEARFLAG,	/* only a flag, but clear instead of set */
710Sstevel@tonic-gate 	    ITEM_OPTUINT,	/* optional integer argument */
720Sstevel@tonic-gate 	    ITEM_UINT,		/* required integer argument */
730Sstevel@tonic-gate 	    ITEM_OPTSIZE,	/* optional size_t argument */
740Sstevel@tonic-gate 	    ITEM_SIZE,		/* required size_t argument */
750Sstevel@tonic-gate 	    ITEM_SPECIAL	/* special argument processing */
760Sstevel@tonic-gate 	} item_type;
770Sstevel@tonic-gate 	const char *item_description;
780Sstevel@tonic-gate 	uint_t *item_flag_target; /* the variable containing the flag */
790Sstevel@tonic-gate 	uint_t item_flag_value;	/* the value to OR in */
800Sstevel@tonic-gate 	uint_t *item_uint_target; /* the variable to hold the integer */
810Sstevel@tonic-gate 	size_t *item_size_target;
820Sstevel@tonic-gate 	arg_process_t *item_special; /* callback for special handling */
830Sstevel@tonic-gate } umem_env_item_t;
840Sstevel@tonic-gate 
850Sstevel@tonic-gate #ifndef UMEM_STANDALONE
860Sstevel@tonic-gate static arg_process_t umem_backend_process;
870Sstevel@tonic-gate #endif
880Sstevel@tonic-gate 
890Sstevel@tonic-gate static arg_process_t umem_log_process;
900Sstevel@tonic-gate 
911528Sjwadams static size_t umem_size_tempval;
921528Sjwadams static arg_process_t umem_size_process;
931528Sjwadams 
940Sstevel@tonic-gate const char *____umem_environ_msg_options = "-- UMEM_OPTIONS --";
950Sstevel@tonic-gate 
960Sstevel@tonic-gate static umem_env_item_t umem_options_items[] = {
970Sstevel@tonic-gate #ifndef UMEM_STANDALONE
980Sstevel@tonic-gate 	{ "backend",		"Evolving",	ITEM_SPECIAL,
990Sstevel@tonic-gate 		"=sbrk for sbrk(2), =mmap for mmap(2)",
1000Sstevel@tonic-gate 		NULL, 0, NULL, NULL,
1010Sstevel@tonic-gate 		&umem_backend_process
1020Sstevel@tonic-gate 	},
1030Sstevel@tonic-gate #endif
1040Sstevel@tonic-gate 
1050Sstevel@tonic-gate 	{ "concurrency",	"Private",	ITEM_UINT,
1060Sstevel@tonic-gate 		"Max concurrency",
1070Sstevel@tonic-gate 		NULL, 0,	&umem_max_ncpus
1080Sstevel@tonic-gate 	},
1090Sstevel@tonic-gate 	{ "max_contention",	"Private",	ITEM_UINT,
1100Sstevel@tonic-gate 		"Maximum contention in a reap interval before the depot is "
1110Sstevel@tonic-gate 		    "resized.",
1120Sstevel@tonic-gate 		NULL, 0,	&umem_depot_contention
1130Sstevel@tonic-gate 	},
1140Sstevel@tonic-gate 	{ "nomagazines",	"Private",	ITEM_FLAG,
1150Sstevel@tonic-gate 		"no caches will be multithreaded, and no caching will occur.",
1160Sstevel@tonic-gate 		&umem_flags,	UMF_NOMAGAZINE
1170Sstevel@tonic-gate 	},
1180Sstevel@tonic-gate 	{ "reap_interval",	"Private",	ITEM_UINT,
1190Sstevel@tonic-gate 		"Minimum time between reaps and updates, in seconds.",
1200Sstevel@tonic-gate 		NULL, 0,	&umem_reap_interval
1210Sstevel@tonic-gate 	},
1220Sstevel@tonic-gate 
1231528Sjwadams 	{ "size_add",		"Private",	ITEM_SPECIAL,
1241528Sjwadams 		"add a size to the cache size table",
1251528Sjwadams 		NULL, 0, NULL,
1261528Sjwadams 		&umem_size_tempval,		&umem_size_process
1271528Sjwadams 	},
1281528Sjwadams 	{ "size_clear",		"Private",	ITEM_SPECIAL,
1291528Sjwadams 		"clear all but the largest size from the cache size table",
1301528Sjwadams 		NULL, 0, NULL,
1311528Sjwadams 		&umem_size_tempval,		&umem_size_process
1321528Sjwadams 	},
1331528Sjwadams 	{ "size_remove",	"Private",	ITEM_SPECIAL,
1341528Sjwadams 	    "remove a size from the cache size table",
1351528Sjwadams 		NULL, 0, NULL,
1361528Sjwadams 		&umem_size_tempval,		&umem_size_process
1371528Sjwadams 	},
1381528Sjwadams 
1390Sstevel@tonic-gate #ifndef UMEM_STANDALONE
1401528Sjwadams 	{ "sbrk_minalloc",	"Private",	ITEM_SIZE,
1411528Sjwadams 		"The minimum allocation chunk for the sbrk(2) heap.",
1421528Sjwadams 		NULL, 0, NULL,	&vmem_sbrk_minalloc
1431528Sjwadams 	},
1440Sstevel@tonic-gate 	{ "sbrk_pagesize",	"Private",	ITEM_SIZE,
1450Sstevel@tonic-gate 		"The preferred page size for the sbrk(2) heap.",
1460Sstevel@tonic-gate 		NULL, 0, NULL,	&vmem_sbrk_pagesize
1470Sstevel@tonic-gate 	},
1480Sstevel@tonic-gate #endif
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate 	{ NULL, "-- end of UMEM_OPTIONS --",	ITEM_INVALID }
1510Sstevel@tonic-gate };
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate const char *____umem_environ_msg_debug = "-- UMEM_DEBUG --";
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate static umem_env_item_t umem_debug_items[] = {
1560Sstevel@tonic-gate 	{ "default",		"Unstable",	ITEM_FLAG,
1570Sstevel@tonic-gate 		"audit,contents,guards",
1580Sstevel@tonic-gate 		&umem_flags,
1590Sstevel@tonic-gate 		UMF_AUDIT | UMF_CONTENTS | UMF_DEADBEEF | UMF_REDZONE
1600Sstevel@tonic-gate 	},
1610Sstevel@tonic-gate 	{ "audit",		"Unstable",	ITEM_OPTUINT,
1620Sstevel@tonic-gate 		"Enable auditing.  optionally =frames to set the number of "
1630Sstevel@tonic-gate 		    "stored stack frames",
1640Sstevel@tonic-gate 		&umem_flags,	UMF_AUDIT,	&umem_stack_depth
1650Sstevel@tonic-gate 	},
1660Sstevel@tonic-gate 	{ "contents",		"Unstable",	ITEM_OPTSIZE,
1670Sstevel@tonic-gate 		"Enable contents storing.  UMEM_LOGGING=contents also "
1680Sstevel@tonic-gate 		    "required.  optionally =bytes to set the number of stored "
1690Sstevel@tonic-gate 		    "bytes",
1700Sstevel@tonic-gate 		&umem_flags,	UMF_CONTENTS, NULL,	&umem_content_maxsave
1710Sstevel@tonic-gate 	},
1720Sstevel@tonic-gate 	{ "guards",		"Unstable",	ITEM_FLAG,
1730Sstevel@tonic-gate 		"Enables guards and special patterns",
1740Sstevel@tonic-gate 		&umem_flags,	UMF_DEADBEEF | UMF_REDZONE
1750Sstevel@tonic-gate 	},
1760Sstevel@tonic-gate 	{ "verbose",		"Unstable",	ITEM_FLAG,
1770Sstevel@tonic-gate 		"Enables writing error messages to stderr",
1780Sstevel@tonic-gate 		&umem_output,	1
1790Sstevel@tonic-gate 	},
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate 	{ "nosignal",	"Private",	ITEM_FLAG,
1820Sstevel@tonic-gate 		"Abort if called from a signal handler.  Turns on 'audit'.  "
1830Sstevel@tonic-gate 		    "Note that this is not always a bug.",
1840Sstevel@tonic-gate 		&umem_flags,	UMF_AUDIT | UMF_CHECKSIGNAL
1850Sstevel@tonic-gate 	},
1860Sstevel@tonic-gate 	{ "firewall",		"Private",	ITEM_SIZE,
1870Sstevel@tonic-gate 		"=minbytes.  Every object >= minbytes in size will have its "
1880Sstevel@tonic-gate 		    "end against an unmapped page",
1890Sstevel@tonic-gate 		&umem_flags,	UMF_FIREWALL,	NULL,	&umem_minfirewall
1900Sstevel@tonic-gate 	},
1910Sstevel@tonic-gate 	{ "lite",		"Private",	ITEM_FLAG,
1920Sstevel@tonic-gate 		"debugging-lite",
1930Sstevel@tonic-gate 		&umem_flags,	UMF_LITE
1940Sstevel@tonic-gate 	},
1950Sstevel@tonic-gate 	{ "maxverify",		"Private",	ITEM_SIZE,
1960Sstevel@tonic-gate 		"=maxbytes, Maximum bytes to check when 'guards' is active. "
1970Sstevel@tonic-gate 		    "Normally all bytes are checked.",
1980Sstevel@tonic-gate 		NULL, 0, NULL,	&umem_maxverify
1990Sstevel@tonic-gate 	},
2000Sstevel@tonic-gate 	{ "noabort",		"Private",	ITEM_CLEARFLAG,
2010Sstevel@tonic-gate 		"umem will not abort when a recoverable error occurs "
2020Sstevel@tonic-gate 		    "(i.e. double frees, certain kinds of corruption)",
2030Sstevel@tonic-gate 		&umem_abort,	1
2040Sstevel@tonic-gate 	},
2050Sstevel@tonic-gate 	{ "mtbf",		"Private",	ITEM_UINT,
2060Sstevel@tonic-gate 		"=mtbf, the mean time between injected failures.  Works best "
2070Sstevel@tonic-gate 		    "if prime.\n",
2080Sstevel@tonic-gate 		NULL, 0,	&umem_mtbf
2090Sstevel@tonic-gate 	},
2100Sstevel@tonic-gate 	{ "random",		"Private",	ITEM_FLAG,
2110Sstevel@tonic-gate 		"randomize flags on a per-cache basis",
2120Sstevel@tonic-gate 		&umem_flags,	UMF_RANDOMIZE
2130Sstevel@tonic-gate 	},
2140Sstevel@tonic-gate 	{ "allverbose",		"Private",	ITEM_FLAG,
2150Sstevel@tonic-gate 		"Enables writing all logged messages to stderr",
2160Sstevel@tonic-gate 		&umem_output,	2
2170Sstevel@tonic-gate 	},
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate 	{ NULL, "-- end of UMEM_DEBUG --",	ITEM_INVALID }
2200Sstevel@tonic-gate };
2210Sstevel@tonic-gate 
2220Sstevel@tonic-gate const char *____umem_environ_msg_logging = "-- UMEM_LOGGING --";
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate static umem_env_item_t umem_logging_items[] = {
2250Sstevel@tonic-gate 	{ "transaction",	"Unstable",	ITEM_SPECIAL,
2260Sstevel@tonic-gate 		"If 'audit' is set in UMEM_DEBUG, the audit structures "
2270Sstevel@tonic-gate 		    "from previous transactions are entered into this log.",
2280Sstevel@tonic-gate 		NULL, 0, NULL,
2290Sstevel@tonic-gate 		&umem_transaction_log_size,	&umem_log_process
2300Sstevel@tonic-gate 	},
2310Sstevel@tonic-gate 	{ "contents",		"Unstable",	ITEM_SPECIAL,
2320Sstevel@tonic-gate 		"If 'audit' is set in UMEM_DEBUG, the contents of objects "
2330Sstevel@tonic-gate 		    "are recorded in this log as they are freed.  If the "
2340Sstevel@tonic-gate 		    "'contents' option is not set in UMEM_DEBUG, the first "
2350Sstevel@tonic-gate 		    "256 bytes of each freed buffer will be saved.",
2360Sstevel@tonic-gate 		&umem_flags,	UMF_CONTENTS,	NULL,
2370Sstevel@tonic-gate 		&umem_content_log_size,		&umem_log_process
2380Sstevel@tonic-gate 	},
2390Sstevel@tonic-gate 	{ "fail",		"Unstable",	ITEM_SPECIAL,
2400Sstevel@tonic-gate 		"Records are entered into this log for every failed "
2410Sstevel@tonic-gate 		    "allocation.",
2420Sstevel@tonic-gate 		NULL, 0, NULL,
2430Sstevel@tonic-gate 		&umem_failure_log_size,		&umem_log_process
2440Sstevel@tonic-gate 	},
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate 	{ "slab",		"Private",	ITEM_SPECIAL,
2470Sstevel@tonic-gate 		"Every slab created will be entered into this log.",
2480Sstevel@tonic-gate 		NULL, 0, NULL,
2490Sstevel@tonic-gate 		&umem_slab_log_size,		&umem_log_process
2500Sstevel@tonic-gate 	},
2510Sstevel@tonic-gate 
2520Sstevel@tonic-gate 	{ NULL, "-- end of UMEM_LOGGING --",	ITEM_INVALID }
2530Sstevel@tonic-gate };
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate typedef struct umem_envvar {
2560Sstevel@tonic-gate 	const char *env_name;
2570Sstevel@tonic-gate 	const char *env_func;
2580Sstevel@tonic-gate 	umem_env_item_t	*env_item_list;
2590Sstevel@tonic-gate 	const char *env_getenv_result;
2600Sstevel@tonic-gate 	const char *env_func_result;
2610Sstevel@tonic-gate } umem_envvar_t;
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate static umem_envvar_t umem_envvars[] = {
2640Sstevel@tonic-gate 	{ "UMEM_DEBUG",		"_umem_debug_init",	umem_debug_items },
2650Sstevel@tonic-gate 	{ "UMEM_OPTIONS",	"_umem_options_init",	umem_options_items },
2660Sstevel@tonic-gate 	{ "UMEM_LOGGING",	"_umem_logging_init",	umem_logging_items },
2670Sstevel@tonic-gate 	{ NULL, NULL, NULL }
2680Sstevel@tonic-gate };
2690Sstevel@tonic-gate 
2700Sstevel@tonic-gate static umem_envvar_t *env_current;
2710Sstevel@tonic-gate #define	CURRENT		(env_current->env_name)
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate static int
empty(const char * str)2740Sstevel@tonic-gate empty(const char *str)
2750Sstevel@tonic-gate {
2760Sstevel@tonic-gate 	char c;
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate 	while ((c = *str) != '\0' && isspace(c))
2790Sstevel@tonic-gate 		str++;
2800Sstevel@tonic-gate 
2810Sstevel@tonic-gate 	return (*str == '\0');
2820Sstevel@tonic-gate }
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate static int
item_uint_process(const umem_env_item_t * item,const char * item_arg)2850Sstevel@tonic-gate item_uint_process(const umem_env_item_t *item, const char *item_arg)
2860Sstevel@tonic-gate {
2870Sstevel@tonic-gate 	ulong_t result;
2880Sstevel@tonic-gate 	char *endptr = "";
2890Sstevel@tonic-gate 	int olderrno;
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate 	olderrno = errno;
2920Sstevel@tonic-gate 	errno = 0;
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate 	if (empty(item_arg)) {
2950Sstevel@tonic-gate 		goto badnumber;
2960Sstevel@tonic-gate 	}
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate 	result = strtoul(item_arg, &endptr, 10);
2990Sstevel@tonic-gate 
3000Sstevel@tonic-gate 	if (result == ULONG_MAX && errno == ERANGE) {
3010Sstevel@tonic-gate 		errno = olderrno;
3020Sstevel@tonic-gate 		goto overflow;
3030Sstevel@tonic-gate 	}
3040Sstevel@tonic-gate 	errno = olderrno;
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate 	if (*endptr != '\0')
3070Sstevel@tonic-gate 		goto badnumber;
3080Sstevel@tonic-gate 	if ((uint_t)result != result)
3090Sstevel@tonic-gate 		goto overflow;
3100Sstevel@tonic-gate 
3110Sstevel@tonic-gate 	(*item->item_uint_target) = (uint_t)result;
3120Sstevel@tonic-gate 	return (ARG_SUCCESS);
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate badnumber:
3150Sstevel@tonic-gate 	log_message("%s: %s: not a number\n", CURRENT, item->item_name);
3160Sstevel@tonic-gate 	return (ARG_BAD);
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate overflow:
3190Sstevel@tonic-gate 	log_message("%s: %s: overflowed\n", CURRENT, item->item_name);
3200Sstevel@tonic-gate 	return (ARG_BAD);
3210Sstevel@tonic-gate }
3220Sstevel@tonic-gate 
3230Sstevel@tonic-gate static int
item_size_process(const umem_env_item_t * item,const char * item_arg)3240Sstevel@tonic-gate item_size_process(const umem_env_item_t *item, const char *item_arg)
3250Sstevel@tonic-gate {
3260Sstevel@tonic-gate 	ulong_t result;
3270Sstevel@tonic-gate 	ulong_t result_arg;
3280Sstevel@tonic-gate 	char *endptr = "";
3290Sstevel@tonic-gate 	int olderrno;
3300Sstevel@tonic-gate 
3310Sstevel@tonic-gate 	if (empty(item_arg))
3320Sstevel@tonic-gate 		goto badnumber;
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate 	olderrno = errno;
3350Sstevel@tonic-gate 	errno = 0;
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate 	result_arg = strtoul(item_arg, &endptr, 10);
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate 	if (result_arg == ULONG_MAX && errno == ERANGE) {
3400Sstevel@tonic-gate 		errno = olderrno;
3410Sstevel@tonic-gate 		goto overflow;
3420Sstevel@tonic-gate 	}
3430Sstevel@tonic-gate 	errno = olderrno;
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate 	result = result_arg;
3460Sstevel@tonic-gate 
3470Sstevel@tonic-gate 	switch (*endptr) {
3480Sstevel@tonic-gate 	case 't':
3490Sstevel@tonic-gate 	case 'T':
3500Sstevel@tonic-gate 		result *= 1024;
3510Sstevel@tonic-gate 		if (result < result_arg)
3520Sstevel@tonic-gate 			goto overflow;
3530Sstevel@tonic-gate 		/*FALLTHRU*/
3540Sstevel@tonic-gate 	case 'g':
3550Sstevel@tonic-gate 	case 'G':
3560Sstevel@tonic-gate 		result *= 1024;
3570Sstevel@tonic-gate 		if (result < result_arg)
3580Sstevel@tonic-gate 			goto overflow;
3590Sstevel@tonic-gate 		/*FALLTHRU*/
3600Sstevel@tonic-gate 	case 'm':
3610Sstevel@tonic-gate 	case 'M':
3620Sstevel@tonic-gate 		result *= 1024;
3630Sstevel@tonic-gate 		if (result < result_arg)
3640Sstevel@tonic-gate 			goto overflow;
3650Sstevel@tonic-gate 		/*FALLTHRU*/
3660Sstevel@tonic-gate 	case 'k':
3670Sstevel@tonic-gate 	case 'K':
3680Sstevel@tonic-gate 		result *= 1024;
3690Sstevel@tonic-gate 		if (result < result_arg)
3700Sstevel@tonic-gate 			goto overflow;
3710Sstevel@tonic-gate 		endptr++;		/* skip over the size character */
3720Sstevel@tonic-gate 		break;
3730Sstevel@tonic-gate 	default:
3740Sstevel@tonic-gate 		break;			/* handled later */
3750Sstevel@tonic-gate 	}
3760Sstevel@tonic-gate 
3770Sstevel@tonic-gate 	if (*endptr != '\0')
3780Sstevel@tonic-gate 		goto badnumber;
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate 	(*item->item_size_target) = result;
3810Sstevel@tonic-gate 	return (ARG_SUCCESS);
3820Sstevel@tonic-gate 
3830Sstevel@tonic-gate badnumber:
3840Sstevel@tonic-gate 	log_message("%s: %s: not a number\n", CURRENT, item->item_name);
3850Sstevel@tonic-gate 	return (ARG_BAD);
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate overflow:
3880Sstevel@tonic-gate 	log_message("%s: %s: overflowed\n", CURRENT, item->item_name);
3890Sstevel@tonic-gate 	return (ARG_BAD);
3900Sstevel@tonic-gate }
3910Sstevel@tonic-gate 
3920Sstevel@tonic-gate static int
umem_log_process(const umem_env_item_t * item,const char * item_arg)3930Sstevel@tonic-gate umem_log_process(const umem_env_item_t *item, const char *item_arg)
3940Sstevel@tonic-gate {
3950Sstevel@tonic-gate 	if (item_arg != NULL) {
3960Sstevel@tonic-gate 		int ret;
3970Sstevel@tonic-gate 		ret = item_size_process(item, item_arg);
3980Sstevel@tonic-gate 		if (ret != ARG_SUCCESS)
3990Sstevel@tonic-gate 			return (ret);
4000Sstevel@tonic-gate 
4010Sstevel@tonic-gate 		if (*item->item_size_target == 0)
4020Sstevel@tonic-gate 			return (ARG_SUCCESS);
4030Sstevel@tonic-gate 	} else
4040Sstevel@tonic-gate 		*item->item_size_target = 64*1024;
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate 	umem_logging = 1;
4070Sstevel@tonic-gate 	return (ARG_SUCCESS);
4080Sstevel@tonic-gate }
4090Sstevel@tonic-gate 
4101528Sjwadams static int
umem_size_process(const umem_env_item_t * item,const char * item_arg)4111528Sjwadams umem_size_process(const umem_env_item_t *item, const char *item_arg)
4121528Sjwadams {
4131528Sjwadams 	const char *name = item->item_name;
4141528Sjwadams 	void (*action_func)(size_t);
4151528Sjwadams 
4161528Sjwadams 	size_t result;
4171528Sjwadams 
4181528Sjwadams 	int ret;
4191528Sjwadams 
4201528Sjwadams 	if (strcmp(name, "size_clear") == 0) {
4211528Sjwadams 		if (item_arg != NULL) {
4221528Sjwadams 			log_message("%s: %s: does not take a value. ignored\n",
4231528Sjwadams 			    CURRENT, name);
4241528Sjwadams 			return (ARG_BAD);
4251528Sjwadams 		}
4261528Sjwadams 		umem_alloc_sizes_clear();
4271528Sjwadams 		return (ARG_SUCCESS);
4281528Sjwadams 	} else if (strcmp(name, "size_add") == 0) {
4291528Sjwadams 		action_func = umem_alloc_sizes_add;
4301528Sjwadams 	} else if (strcmp(name, "size_remove") == 0) {
4311528Sjwadams 		action_func = umem_alloc_sizes_remove;
4321528Sjwadams 	} else {
4331528Sjwadams 		log_message("%s: %s: internally unrecognized\n",
4341528Sjwadams 		    CURRENT, name, name, name);
4351528Sjwadams 		return (ARG_BAD);
4361528Sjwadams 	}
4371528Sjwadams 
4381528Sjwadams 	if (item_arg == NULL) {
4391528Sjwadams 		log_message("%s: %s: requires a value. ignored\n",
4401528Sjwadams 		    CURRENT, name);
4411528Sjwadams 		return (ARG_BAD);
4421528Sjwadams 	}
4431528Sjwadams 
4441528Sjwadams 	ret = item_size_process(item, item_arg);
4451528Sjwadams 	if (ret != ARG_SUCCESS)
4461528Sjwadams 		return (ret);
4471528Sjwadams 
4481528Sjwadams 	result = *item->item_size_target;
4491528Sjwadams 	action_func(result);
4501528Sjwadams 	return (ARG_SUCCESS);
4511528Sjwadams }
4521528Sjwadams 
4530Sstevel@tonic-gate #ifndef UMEM_STANDALONE
4540Sstevel@tonic-gate static int
umem_backend_process(const umem_env_item_t * item,const char * item_arg)4550Sstevel@tonic-gate umem_backend_process(const umem_env_item_t *item, const char *item_arg)
4560Sstevel@tonic-gate {
4570Sstevel@tonic-gate 	const char *name = item->item_name;
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate 	if (item_arg == NULL)
4600Sstevel@tonic-gate 		goto fail;
4610Sstevel@tonic-gate 
4620Sstevel@tonic-gate 	if (strcmp(item_arg, "sbrk") == 0)
4630Sstevel@tonic-gate 		vmem_backend |= VMEM_BACKEND_SBRK;
4640Sstevel@tonic-gate 	else if (strcmp(item_arg, "mmap") == 0)
4650Sstevel@tonic-gate 		vmem_backend |= VMEM_BACKEND_MMAP;
4660Sstevel@tonic-gate 	else
4670Sstevel@tonic-gate 		goto fail;
4680Sstevel@tonic-gate 
4690Sstevel@tonic-gate 	return (ARG_SUCCESS);
4700Sstevel@tonic-gate 
4710Sstevel@tonic-gate fail:
4720Sstevel@tonic-gate 	log_message("%s: %s: must be %s=sbrk or %s=mmap\n",
4730Sstevel@tonic-gate 	    CURRENT, name, name, name);
4740Sstevel@tonic-gate 	return (ARG_BAD);
4750Sstevel@tonic-gate }
4760Sstevel@tonic-gate #endif
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate static int
process_item(const umem_env_item_t * item,const char * item_arg)4790Sstevel@tonic-gate process_item(const umem_env_item_t *item, const char *item_arg)
4800Sstevel@tonic-gate {
4810Sstevel@tonic-gate 	int arg_required = 0;
4820Sstevel@tonic-gate 	arg_process_t *processor;
4830Sstevel@tonic-gate 
4840Sstevel@tonic-gate 	switch (item->item_type) {
4850Sstevel@tonic-gate 	case ITEM_FLAG:
4860Sstevel@tonic-gate 	case ITEM_CLEARFLAG:
4870Sstevel@tonic-gate 	case ITEM_OPTUINT:
4880Sstevel@tonic-gate 	case ITEM_OPTSIZE:
4890Sstevel@tonic-gate 	case ITEM_SPECIAL:
4900Sstevel@tonic-gate 		arg_required = 0;
4910Sstevel@tonic-gate 		break;
4920Sstevel@tonic-gate 
4930Sstevel@tonic-gate 	case ITEM_UINT:
4940Sstevel@tonic-gate 	case ITEM_SIZE:
4950Sstevel@tonic-gate 		arg_required = 1;
4960Sstevel@tonic-gate 		break;
4970Sstevel@tonic-gate 	}
4980Sstevel@tonic-gate 
4990Sstevel@tonic-gate 	switch (item->item_type) {
5000Sstevel@tonic-gate 	case ITEM_FLAG:
5010Sstevel@tonic-gate 	case ITEM_CLEARFLAG:
5020Sstevel@tonic-gate 		if (item_arg != NULL) {
5030Sstevel@tonic-gate 			log_message("%s: %s: does not take a value. ignored\n",
5040Sstevel@tonic-gate 			    CURRENT, item->item_name);
5050Sstevel@tonic-gate 			return (1);
5060Sstevel@tonic-gate 		}
5070Sstevel@tonic-gate 		processor = NULL;
5080Sstevel@tonic-gate 		break;
5090Sstevel@tonic-gate 
5100Sstevel@tonic-gate 	case ITEM_UINT:
5110Sstevel@tonic-gate 	case ITEM_OPTUINT:
5120Sstevel@tonic-gate 		processor = item_uint_process;
5130Sstevel@tonic-gate 		break;
5140Sstevel@tonic-gate 
5150Sstevel@tonic-gate 	case ITEM_SIZE:
5160Sstevel@tonic-gate 	case ITEM_OPTSIZE:
5170Sstevel@tonic-gate 		processor = item_size_process;
5180Sstevel@tonic-gate 		break;
5190Sstevel@tonic-gate 
5200Sstevel@tonic-gate 	case ITEM_SPECIAL:
5210Sstevel@tonic-gate 		processor = item->item_special;
5220Sstevel@tonic-gate 		break;
5230Sstevel@tonic-gate 
5240Sstevel@tonic-gate 	default:
5250Sstevel@tonic-gate 		log_message("%s: %s: Invalid type.  Ignored\n",
5260Sstevel@tonic-gate 		    CURRENT, item->item_name);
5270Sstevel@tonic-gate 		return (1);
5280Sstevel@tonic-gate 	}
5290Sstevel@tonic-gate 
5300Sstevel@tonic-gate 	if (arg_required && item_arg == NULL) {
5310Sstevel@tonic-gate 		log_message("%s: %s: Required value missing\n",
5320Sstevel@tonic-gate 		    CURRENT, item->item_name);
5330Sstevel@tonic-gate 		goto invalid;
5340Sstevel@tonic-gate 	}
5350Sstevel@tonic-gate 
5360Sstevel@tonic-gate 	if (item_arg != NULL || item->item_type == ITEM_SPECIAL) {
5370Sstevel@tonic-gate 		if (processor(item, item_arg) != ARG_SUCCESS)
5380Sstevel@tonic-gate 			goto invalid;
5390Sstevel@tonic-gate 	}
5400Sstevel@tonic-gate 
5410Sstevel@tonic-gate 	if (item->item_flag_target) {
5420Sstevel@tonic-gate 		if (item->item_type == ITEM_CLEARFLAG)
5430Sstevel@tonic-gate 			(*item->item_flag_target) &= ~item->item_flag_value;
5440Sstevel@tonic-gate 		else
5450Sstevel@tonic-gate 			(*item->item_flag_target) |= item->item_flag_value;
5460Sstevel@tonic-gate 	}
5470Sstevel@tonic-gate 	return (0);
5480Sstevel@tonic-gate 
5490Sstevel@tonic-gate invalid:
5500Sstevel@tonic-gate 	return (1);
5510Sstevel@tonic-gate }
5520Sstevel@tonic-gate 
5530Sstevel@tonic-gate #define	ENV_SHORT_BYTES	10	/* bytes to print on error */
5540Sstevel@tonic-gate void
umem_process_value(umem_env_item_t * item_list,const char * beg,const char * end)5550Sstevel@tonic-gate umem_process_value(umem_env_item_t *item_list, const char *beg, const char *end)
5560Sstevel@tonic-gate {
5570Sstevel@tonic-gate 	char buf[UMEM_ENV_ITEM_MAX];
5580Sstevel@tonic-gate 	char *argptr;
5590Sstevel@tonic-gate 
5600Sstevel@tonic-gate 	size_t count;
5610Sstevel@tonic-gate 
5620Sstevel@tonic-gate 	while (beg < end && isspace(*beg))
5630Sstevel@tonic-gate 		beg++;
5640Sstevel@tonic-gate 
5650Sstevel@tonic-gate 	while (beg < end && isspace(*(end - 1)))
5660Sstevel@tonic-gate 		end--;
5670Sstevel@tonic-gate 
5680Sstevel@tonic-gate 	if (beg >= end) {
5690Sstevel@tonic-gate 		log_message("%s: empty option\n", CURRENT);
5700Sstevel@tonic-gate 		return;
5710Sstevel@tonic-gate 	}
5720Sstevel@tonic-gate 
5730Sstevel@tonic-gate 	count = end - beg;
5740Sstevel@tonic-gate 
5750Sstevel@tonic-gate 	if (count + 1 > sizeof (buf)) {
5760Sstevel@tonic-gate 		char outbuf[ENV_SHORT_BYTES + 1];
5770Sstevel@tonic-gate 		/*
5780Sstevel@tonic-gate 		 * Have to do this, since sprintf("%10s",...) calls malloc()
5790Sstevel@tonic-gate 		 */
5800Sstevel@tonic-gate 		(void) strncpy(outbuf, beg, ENV_SHORT_BYTES);
5810Sstevel@tonic-gate 		outbuf[ENV_SHORT_BYTES] = 0;
5820Sstevel@tonic-gate 
5830Sstevel@tonic-gate 		log_message("%s: argument \"%s...\" too long\n", CURRENT,
5840Sstevel@tonic-gate 		    outbuf);
5850Sstevel@tonic-gate 		return;
5860Sstevel@tonic-gate 	}
5870Sstevel@tonic-gate 
5880Sstevel@tonic-gate 	(void) strncpy(buf, beg, count);
5890Sstevel@tonic-gate 	buf[count] = 0;
5900Sstevel@tonic-gate 
5910Sstevel@tonic-gate 	argptr = strchr(buf, '=');
5920Sstevel@tonic-gate 
5930Sstevel@tonic-gate 	if (argptr != NULL)
5940Sstevel@tonic-gate 		*argptr++ = 0;
5950Sstevel@tonic-gate 
5960Sstevel@tonic-gate 	for (; item_list->item_name != NULL; item_list++) {
5970Sstevel@tonic-gate 		if (strcmp(buf, item_list->item_name) == 0) {
5980Sstevel@tonic-gate 			(void) process_item(item_list, argptr);
5990Sstevel@tonic-gate 			return;
6000Sstevel@tonic-gate 		}
6010Sstevel@tonic-gate 	}
6020Sstevel@tonic-gate 	log_message("%s: '%s' not recognized\n", CURRENT, buf);
6030Sstevel@tonic-gate }
6040Sstevel@tonic-gate 
6050Sstevel@tonic-gate /*ARGSUSED*/
6060Sstevel@tonic-gate void
umem_setup_envvars(int invalid)6070Sstevel@tonic-gate umem_setup_envvars(int invalid)
6080Sstevel@tonic-gate {
6090Sstevel@tonic-gate 	umem_envvar_t *cur_env;
6100Sstevel@tonic-gate 	static volatile enum {
6110Sstevel@tonic-gate 		STATE_START,
6120Sstevel@tonic-gate 		STATE_GETENV,
613460Sjwadams 		STATE_DLOPEN,
6140Sstevel@tonic-gate 		STATE_DLSYM,
6150Sstevel@tonic-gate 		STATE_FUNC,
6160Sstevel@tonic-gate 		STATE_DONE
6170Sstevel@tonic-gate 	} state = STATE_START;
6180Sstevel@tonic-gate #ifndef UMEM_STANDALONE
6190Sstevel@tonic-gate 	void *h;
6200Sstevel@tonic-gate #endif
6210Sstevel@tonic-gate 
6220Sstevel@tonic-gate 	if (invalid) {
6230Sstevel@tonic-gate 		const char *where;
6240Sstevel@tonic-gate 		/*
6250Sstevel@tonic-gate 		 * One of the calls below invoked malloc() recursively.  We
6260Sstevel@tonic-gate 		 * remove any partial results and return.
6270Sstevel@tonic-gate 		 */
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate 		switch (state) {
6300Sstevel@tonic-gate 		case STATE_START:
6310Sstevel@tonic-gate 			where = "before getenv(3C) calls -- "
6320Sstevel@tonic-gate 			    "getenv(3C) results ignored.";
6330Sstevel@tonic-gate 			break;
6340Sstevel@tonic-gate 		case STATE_GETENV:
6350Sstevel@tonic-gate 			where = "during getenv(3C) calls -- "
6360Sstevel@tonic-gate 			    "getenv(3C) results ignored.";
6370Sstevel@tonic-gate 			break;
638460Sjwadams 		case STATE_DLOPEN:
639460Sjwadams 			where = "during dlopen(3C) call -- "
640460Sjwadams 			    "_umem_*() results ignored.";
641460Sjwadams 			break;
6420Sstevel@tonic-gate 		case STATE_DLSYM:
6430Sstevel@tonic-gate 			where = "during dlsym(3C) call -- "
6440Sstevel@tonic-gate 			    "_umem_*() results ignored.";
6450Sstevel@tonic-gate 			break;
6460Sstevel@tonic-gate 		case STATE_FUNC:
6470Sstevel@tonic-gate 			where = "during _umem_*() call -- "
6480Sstevel@tonic-gate 			    "_umem_*() results ignored.";
6490Sstevel@tonic-gate 			break;
6500Sstevel@tonic-gate 		case STATE_DONE:
6510Sstevel@tonic-gate 			where = "after dlsym() or _umem_*() calls.";
6520Sstevel@tonic-gate 			break;
6530Sstevel@tonic-gate 		default:
6540Sstevel@tonic-gate 			where = "at unknown point -- "
6550Sstevel@tonic-gate 			    "_umem_*() results ignored.";
6560Sstevel@tonic-gate 			break;
6570Sstevel@tonic-gate 		}
6580Sstevel@tonic-gate 
6590Sstevel@tonic-gate 		log_message("recursive allocation %s\n", where);
6600Sstevel@tonic-gate 
6610Sstevel@tonic-gate 		for (cur_env = umem_envvars; cur_env->env_name != NULL;
6620Sstevel@tonic-gate 		    cur_env++) {
6630Sstevel@tonic-gate 			if (state == STATE_GETENV)
6640Sstevel@tonic-gate 				cur_env->env_getenv_result = NULL;
6650Sstevel@tonic-gate 			if (state != STATE_DONE)
6660Sstevel@tonic-gate 				cur_env->env_func_result = NULL;
6670Sstevel@tonic-gate 		}
6680Sstevel@tonic-gate 
6690Sstevel@tonic-gate 		state = STATE_DONE;
6700Sstevel@tonic-gate 		return;
6710Sstevel@tonic-gate 	}
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate 	state = STATE_GETENV;
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate 	for (cur_env = umem_envvars; cur_env->env_name != NULL; cur_env++) {
6760Sstevel@tonic-gate 		cur_env->env_getenv_result = getenv(cur_env->env_name);
6770Sstevel@tonic-gate 		if (state == STATE_DONE)
6780Sstevel@tonic-gate 			return;		/* recursed */
6790Sstevel@tonic-gate 	}
6800Sstevel@tonic-gate 
6810Sstevel@tonic-gate #ifndef UMEM_STANDALONE
682460Sjwadams 	state = STATE_DLOPEN;
683460Sjwadams 
6840Sstevel@tonic-gate 	/* get a handle to the "a.out" object */
6850Sstevel@tonic-gate 	if ((h = dlopen(0, RTLD_FIRST | RTLD_LAZY)) != NULL) {
6860Sstevel@tonic-gate 		for (cur_env = umem_envvars; cur_env->env_name != NULL;
6870Sstevel@tonic-gate 		    cur_env++) {
6880Sstevel@tonic-gate 			const char *(*func)(void);
6890Sstevel@tonic-gate 			const char *value;
6900Sstevel@tonic-gate 
6910Sstevel@tonic-gate 			state = STATE_DLSYM;
6920Sstevel@tonic-gate 			func = (const char *(*)(void))dlsym(h,
6930Sstevel@tonic-gate 			    cur_env->env_func);
6940Sstevel@tonic-gate 
6950Sstevel@tonic-gate 			if (state == STATE_DONE)
6960Sstevel@tonic-gate 				break;		/* recursed */
6970Sstevel@tonic-gate 
6980Sstevel@tonic-gate 			state = STATE_FUNC;
6990Sstevel@tonic-gate 			if (func != NULL) {
7000Sstevel@tonic-gate 				value = func();
7010Sstevel@tonic-gate 				if (state == STATE_DONE)
7020Sstevel@tonic-gate 					break;		/* recursed */
7030Sstevel@tonic-gate 				cur_env->env_func_result = value;
7040Sstevel@tonic-gate 			}
7050Sstevel@tonic-gate 		}
7060Sstevel@tonic-gate 		(void) dlclose(h);
7070Sstevel@tonic-gate 	} else {
7080Sstevel@tonic-gate 		(void) dlerror();		/* snarf dlerror() */
7090Sstevel@tonic-gate 	}
7100Sstevel@tonic-gate #endif /* UMEM_STANDALONE */
7110Sstevel@tonic-gate 
7120Sstevel@tonic-gate 	state = STATE_DONE;
7130Sstevel@tonic-gate }
7140Sstevel@tonic-gate 
7150Sstevel@tonic-gate /*
7160Sstevel@tonic-gate  * Process the environment variables.
7170Sstevel@tonic-gate  */
7180Sstevel@tonic-gate void
umem_process_envvars(void)7190Sstevel@tonic-gate umem_process_envvars(void)
7200Sstevel@tonic-gate {
7210Sstevel@tonic-gate 	const char *value;
7220Sstevel@tonic-gate 	const char *end, *next;
7230Sstevel@tonic-gate 	umem_envvar_t *cur_env;
7240Sstevel@tonic-gate 
7250Sstevel@tonic-gate 	for (cur_env = umem_envvars; cur_env->env_name != NULL; cur_env++) {
7260Sstevel@tonic-gate 		env_current = cur_env;
7270Sstevel@tonic-gate 
7280Sstevel@tonic-gate 		value = cur_env->env_getenv_result;
7290Sstevel@tonic-gate 		if (value == NULL)
7300Sstevel@tonic-gate 			value = cur_env->env_func_result;
7310Sstevel@tonic-gate 
7320Sstevel@tonic-gate 		/* ignore if missing or empty */
7330Sstevel@tonic-gate 		if (value == NULL)
7340Sstevel@tonic-gate 			continue;
7350Sstevel@tonic-gate 
7360Sstevel@tonic-gate 		for (end = value; *end != '\0'; value = next) {
7370Sstevel@tonic-gate 			end = strchr(value, ',');
7380Sstevel@tonic-gate 			if (end != NULL)
7390Sstevel@tonic-gate 				next = end + 1;		/* skip the comma */
7400Sstevel@tonic-gate 			else
7410Sstevel@tonic-gate 				next = end = value + strlen(value);
7420Sstevel@tonic-gate 
7430Sstevel@tonic-gate 			umem_process_value(cur_env->env_item_list, value, end);
7440Sstevel@tonic-gate 		}
7450Sstevel@tonic-gate 	}
7460Sstevel@tonic-gate }
747