xref: /titanic_50/usr/src/lib/libumem/common/envvar.c (revision aaf809d7f3d58e48120fe39c7ed18f62d8fef56a)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5789d94c2Sjwadams  * Common Development and Distribution License (the "License").
6789d94c2Sjwadams  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21a574db85Sraf 
227c478bd9Sstevel@tonic-gate /*
23a574db85Sraf  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*aaf809d7SRobert Mustacchi  * Copyright 2012 Joyent, Inc. All rights reserved.
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include <ctype.h>
297c478bd9Sstevel@tonic-gate #include <errno.h>
307c478bd9Sstevel@tonic-gate #include <limits.h>
317c478bd9Sstevel@tonic-gate #include <stdlib.h>
327c478bd9Sstevel@tonic-gate #include <string.h>
337c478bd9Sstevel@tonic-gate #include <dlfcn.h>
347c478bd9Sstevel@tonic-gate #include "umem_base.h"
357c478bd9Sstevel@tonic-gate #include "vmem_base.h"
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate /*
387c478bd9Sstevel@tonic-gate  * A umem environment variable, like UMEM_DEBUG, is set to a series
397c478bd9Sstevel@tonic-gate  * of items, seperated by ',':
407c478bd9Sstevel@tonic-gate  *
417c478bd9Sstevel@tonic-gate  *   UMEM_DEBUG="audit=10,guards,firewall=512"
427c478bd9Sstevel@tonic-gate  *
437c478bd9Sstevel@tonic-gate  * This structure describes items.  Each item has a name, type, and
447c478bd9Sstevel@tonic-gate  * description.  During processing, an item read from the user may
457c478bd9Sstevel@tonic-gate  * be either "valid" or "invalid".
467c478bd9Sstevel@tonic-gate  *
477c478bd9Sstevel@tonic-gate  * A valid item has an argument, if required, and it is of the right
487c478bd9Sstevel@tonic-gate  * form (doesn't overflow, doesn't contain any unexpected characters).
497c478bd9Sstevel@tonic-gate  *
507c478bd9Sstevel@tonic-gate  * If the item is valid, item_flag_target != NULL, and:
517c478bd9Sstevel@tonic-gate  *	type is not CLEARFLAG, then (*item_flag_target) |= item_flag_value
527c478bd9Sstevel@tonic-gate  *	type is CLEARFLAG, then (*item_flag_target) &= ~item_flag_value
537c478bd9Sstevel@tonic-gate  */
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate #define	UMEM_ENV_ITEM_MAX	512
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate struct umem_env_item;
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate typedef int arg_process_t(const struct umem_env_item *item, const char *value);
607c478bd9Sstevel@tonic-gate #define	ARG_SUCCESS	0	/* processing successful */
617c478bd9Sstevel@tonic-gate #define	ARG_BAD		1	/* argument had a bad value */
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate typedef struct umem_env_item {
647c478bd9Sstevel@tonic-gate 	const char *item_name;	/* tag in environment variable */
657c478bd9Sstevel@tonic-gate 	const char *item_interface_stability;
667c478bd9Sstevel@tonic-gate 	enum {
677c478bd9Sstevel@tonic-gate 	    ITEM_INVALID,
687c478bd9Sstevel@tonic-gate 	    ITEM_FLAG,		/* only a flag.  No argument allowed */
697c478bd9Sstevel@tonic-gate 	    ITEM_CLEARFLAG,	/* only a flag, but clear instead of set */
707c478bd9Sstevel@tonic-gate 	    ITEM_OPTUINT,	/* optional integer argument */
717c478bd9Sstevel@tonic-gate 	    ITEM_UINT,		/* required integer argument */
727c478bd9Sstevel@tonic-gate 	    ITEM_OPTSIZE,	/* optional size_t argument */
737c478bd9Sstevel@tonic-gate 	    ITEM_SIZE,		/* required size_t argument */
747c478bd9Sstevel@tonic-gate 	    ITEM_SPECIAL	/* special argument processing */
757c478bd9Sstevel@tonic-gate 	} item_type;
767c478bd9Sstevel@tonic-gate 	const char *item_description;
777c478bd9Sstevel@tonic-gate 	uint_t *item_flag_target; /* the variable containing the flag */
787c478bd9Sstevel@tonic-gate 	uint_t item_flag_value;	/* the value to OR in */
797c478bd9Sstevel@tonic-gate 	uint_t *item_uint_target; /* the variable to hold the integer */
807c478bd9Sstevel@tonic-gate 	size_t *item_size_target;
817c478bd9Sstevel@tonic-gate 	arg_process_t *item_special; /* callback for special handling */
827c478bd9Sstevel@tonic-gate } umem_env_item_t;
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate #ifndef UMEM_STANDALONE
857c478bd9Sstevel@tonic-gate static arg_process_t umem_backend_process;
86*aaf809d7SRobert Mustacchi static arg_process_t umem_allocator_process;
877c478bd9Sstevel@tonic-gate #endif
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate static arg_process_t umem_log_process;
907c478bd9Sstevel@tonic-gate 
91789d94c2Sjwadams static size_t umem_size_tempval;
92789d94c2Sjwadams static arg_process_t umem_size_process;
93789d94c2Sjwadams 
947c478bd9Sstevel@tonic-gate const char *____umem_environ_msg_options = "-- UMEM_OPTIONS --";
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate static umem_env_item_t umem_options_items[] = {
977c478bd9Sstevel@tonic-gate #ifndef UMEM_STANDALONE
987c478bd9Sstevel@tonic-gate 	{ "backend",		"Evolving",	ITEM_SPECIAL,
997c478bd9Sstevel@tonic-gate 		"=sbrk for sbrk(2), =mmap for mmap(2)",
1007c478bd9Sstevel@tonic-gate 		NULL, 0, NULL, NULL,
1017c478bd9Sstevel@tonic-gate 		&umem_backend_process
1027c478bd9Sstevel@tonic-gate 	},
103*aaf809d7SRobert Mustacchi 	{ "allocator",		"Evolving",	ITEM_SPECIAL,
104*aaf809d7SRobert Mustacchi 		"=best, =first, =next, or =instant",
105*aaf809d7SRobert Mustacchi 		NULL, 0, NULL, NULL,
106*aaf809d7SRobert Mustacchi 		&umem_allocator_process
107*aaf809d7SRobert Mustacchi 	},
1087c478bd9Sstevel@tonic-gate #endif
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate 	{ "concurrency",	"Private",	ITEM_UINT,
1117c478bd9Sstevel@tonic-gate 		"Max concurrency",
1127c478bd9Sstevel@tonic-gate 		NULL, 0,	&umem_max_ncpus
1137c478bd9Sstevel@tonic-gate 	},
1147c478bd9Sstevel@tonic-gate 	{ "max_contention",	"Private",	ITEM_UINT,
1157c478bd9Sstevel@tonic-gate 		"Maximum contention in a reap interval before the depot is "
1167c478bd9Sstevel@tonic-gate 		    "resized.",
1177c478bd9Sstevel@tonic-gate 		NULL, 0,	&umem_depot_contention
1187c478bd9Sstevel@tonic-gate 	},
1197c478bd9Sstevel@tonic-gate 	{ "nomagazines",	"Private",	ITEM_FLAG,
1207c478bd9Sstevel@tonic-gate 		"no caches will be multithreaded, and no caching will occur.",
1217c478bd9Sstevel@tonic-gate 		&umem_flags,	UMF_NOMAGAZINE
1227c478bd9Sstevel@tonic-gate 	},
1237c478bd9Sstevel@tonic-gate 	{ "reap_interval",	"Private",	ITEM_UINT,
1247c478bd9Sstevel@tonic-gate 		"Minimum time between reaps and updates, in seconds.",
1257c478bd9Sstevel@tonic-gate 		NULL, 0,	&umem_reap_interval
1267c478bd9Sstevel@tonic-gate 	},
1277c478bd9Sstevel@tonic-gate 
128789d94c2Sjwadams 	{ "size_add",		"Private",	ITEM_SPECIAL,
129789d94c2Sjwadams 		"add a size to the cache size table",
130789d94c2Sjwadams 		NULL, 0, NULL,
131789d94c2Sjwadams 		&umem_size_tempval,		&umem_size_process
132789d94c2Sjwadams 	},
133789d94c2Sjwadams 	{ "size_clear",		"Private",	ITEM_SPECIAL,
134789d94c2Sjwadams 		"clear all but the largest size from the cache size table",
135789d94c2Sjwadams 		NULL, 0, NULL,
136789d94c2Sjwadams 		&umem_size_tempval,		&umem_size_process
137789d94c2Sjwadams 	},
138789d94c2Sjwadams 	{ "size_remove",	"Private",	ITEM_SPECIAL,
139789d94c2Sjwadams 	    "remove a size from the cache size table",
140789d94c2Sjwadams 		NULL, 0, NULL,
141789d94c2Sjwadams 		&umem_size_tempval,		&umem_size_process
142789d94c2Sjwadams 	},
143789d94c2Sjwadams 
1447c478bd9Sstevel@tonic-gate #ifndef UMEM_STANDALONE
145789d94c2Sjwadams 	{ "sbrk_minalloc",	"Private",	ITEM_SIZE,
146789d94c2Sjwadams 		"The minimum allocation chunk for the sbrk(2) heap.",
147789d94c2Sjwadams 		NULL, 0, NULL,	&vmem_sbrk_minalloc
148789d94c2Sjwadams 	},
1497c478bd9Sstevel@tonic-gate 	{ "sbrk_pagesize",	"Private",	ITEM_SIZE,
1507c478bd9Sstevel@tonic-gate 		"The preferred page size for the sbrk(2) heap.",
1517c478bd9Sstevel@tonic-gate 		NULL, 0, NULL,	&vmem_sbrk_pagesize
1527c478bd9Sstevel@tonic-gate 	},
1537c478bd9Sstevel@tonic-gate #endif
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 	{ NULL, "-- end of UMEM_OPTIONS --",	ITEM_INVALID }
1567c478bd9Sstevel@tonic-gate };
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate const char *____umem_environ_msg_debug = "-- UMEM_DEBUG --";
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate static umem_env_item_t umem_debug_items[] = {
1617c478bd9Sstevel@tonic-gate 	{ "default",		"Unstable",	ITEM_FLAG,
1627c478bd9Sstevel@tonic-gate 		"audit,contents,guards",
1637c478bd9Sstevel@tonic-gate 		&umem_flags,
1647c478bd9Sstevel@tonic-gate 		UMF_AUDIT | UMF_CONTENTS | UMF_DEADBEEF | UMF_REDZONE
1657c478bd9Sstevel@tonic-gate 	},
1667c478bd9Sstevel@tonic-gate 	{ "audit",		"Unstable",	ITEM_OPTUINT,
1677c478bd9Sstevel@tonic-gate 		"Enable auditing.  optionally =frames to set the number of "
1687c478bd9Sstevel@tonic-gate 		    "stored stack frames",
1697c478bd9Sstevel@tonic-gate 		&umem_flags,	UMF_AUDIT,	&umem_stack_depth
1707c478bd9Sstevel@tonic-gate 	},
1717c478bd9Sstevel@tonic-gate 	{ "contents",		"Unstable",	ITEM_OPTSIZE,
1727c478bd9Sstevel@tonic-gate 		"Enable contents storing.  UMEM_LOGGING=contents also "
1737c478bd9Sstevel@tonic-gate 		    "required.  optionally =bytes to set the number of stored "
1747c478bd9Sstevel@tonic-gate 		    "bytes",
1757c478bd9Sstevel@tonic-gate 		&umem_flags,	UMF_CONTENTS, NULL,	&umem_content_maxsave
1767c478bd9Sstevel@tonic-gate 	},
1777c478bd9Sstevel@tonic-gate 	{ "guards",		"Unstable",	ITEM_FLAG,
1787c478bd9Sstevel@tonic-gate 		"Enables guards and special patterns",
1797c478bd9Sstevel@tonic-gate 		&umem_flags,	UMF_DEADBEEF | UMF_REDZONE
1807c478bd9Sstevel@tonic-gate 	},
1817c478bd9Sstevel@tonic-gate 	{ "verbose",		"Unstable",	ITEM_FLAG,
1827c478bd9Sstevel@tonic-gate 		"Enables writing error messages to stderr",
1837c478bd9Sstevel@tonic-gate 		&umem_output,	1
1847c478bd9Sstevel@tonic-gate 	},
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate 	{ "nosignal",	"Private",	ITEM_FLAG,
1877c478bd9Sstevel@tonic-gate 		"Abort if called from a signal handler.  Turns on 'audit'.  "
1887c478bd9Sstevel@tonic-gate 		    "Note that this is not always a bug.",
1897c478bd9Sstevel@tonic-gate 		&umem_flags,	UMF_AUDIT | UMF_CHECKSIGNAL
1907c478bd9Sstevel@tonic-gate 	},
1917c478bd9Sstevel@tonic-gate 	{ "firewall",		"Private",	ITEM_SIZE,
1927c478bd9Sstevel@tonic-gate 		"=minbytes.  Every object >= minbytes in size will have its "
1937c478bd9Sstevel@tonic-gate 		    "end against an unmapped page",
1947c478bd9Sstevel@tonic-gate 		&umem_flags,	UMF_FIREWALL,	NULL,	&umem_minfirewall
1957c478bd9Sstevel@tonic-gate 	},
1967c478bd9Sstevel@tonic-gate 	{ "lite",		"Private",	ITEM_FLAG,
1977c478bd9Sstevel@tonic-gate 		"debugging-lite",
1987c478bd9Sstevel@tonic-gate 		&umem_flags,	UMF_LITE
1997c478bd9Sstevel@tonic-gate 	},
2007c478bd9Sstevel@tonic-gate 	{ "maxverify",		"Private",	ITEM_SIZE,
2017c478bd9Sstevel@tonic-gate 		"=maxbytes, Maximum bytes to check when 'guards' is active. "
2027c478bd9Sstevel@tonic-gate 		    "Normally all bytes are checked.",
2037c478bd9Sstevel@tonic-gate 		NULL, 0, NULL,	&umem_maxverify
2047c478bd9Sstevel@tonic-gate 	},
2057c478bd9Sstevel@tonic-gate 	{ "noabort",		"Private",	ITEM_CLEARFLAG,
2067c478bd9Sstevel@tonic-gate 		"umem will not abort when a recoverable error occurs "
2077c478bd9Sstevel@tonic-gate 		    "(i.e. double frees, certain kinds of corruption)",
2087c478bd9Sstevel@tonic-gate 		&umem_abort,	1
2097c478bd9Sstevel@tonic-gate 	},
2107c478bd9Sstevel@tonic-gate 	{ "mtbf",		"Private",	ITEM_UINT,
2117c478bd9Sstevel@tonic-gate 		"=mtbf, the mean time between injected failures.  Works best "
2127c478bd9Sstevel@tonic-gate 		    "if prime.\n",
2137c478bd9Sstevel@tonic-gate 		NULL, 0,	&umem_mtbf
2147c478bd9Sstevel@tonic-gate 	},
2157c478bd9Sstevel@tonic-gate 	{ "random",		"Private",	ITEM_FLAG,
2167c478bd9Sstevel@tonic-gate 		"randomize flags on a per-cache basis",
2177c478bd9Sstevel@tonic-gate 		&umem_flags,	UMF_RANDOMIZE
2187c478bd9Sstevel@tonic-gate 	},
2197c478bd9Sstevel@tonic-gate 	{ "allverbose",		"Private",	ITEM_FLAG,
2207c478bd9Sstevel@tonic-gate 		"Enables writing all logged messages to stderr",
2217c478bd9Sstevel@tonic-gate 		&umem_output,	2
2227c478bd9Sstevel@tonic-gate 	},
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate 	{ NULL, "-- end of UMEM_DEBUG --",	ITEM_INVALID }
2257c478bd9Sstevel@tonic-gate };
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate const char *____umem_environ_msg_logging = "-- UMEM_LOGGING --";
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate static umem_env_item_t umem_logging_items[] = {
2307c478bd9Sstevel@tonic-gate 	{ "transaction",	"Unstable",	ITEM_SPECIAL,
2317c478bd9Sstevel@tonic-gate 		"If 'audit' is set in UMEM_DEBUG, the audit structures "
2327c478bd9Sstevel@tonic-gate 		    "from previous transactions are entered into this log.",
2337c478bd9Sstevel@tonic-gate 		NULL, 0, NULL,
2347c478bd9Sstevel@tonic-gate 		&umem_transaction_log_size,	&umem_log_process
2357c478bd9Sstevel@tonic-gate 	},
2367c478bd9Sstevel@tonic-gate 	{ "contents",		"Unstable",	ITEM_SPECIAL,
2377c478bd9Sstevel@tonic-gate 		"If 'audit' is set in UMEM_DEBUG, the contents of objects "
2387c478bd9Sstevel@tonic-gate 		    "are recorded in this log as they are freed.  If the "
2397c478bd9Sstevel@tonic-gate 		    "'contents' option is not set in UMEM_DEBUG, the first "
2407c478bd9Sstevel@tonic-gate 		    "256 bytes of each freed buffer will be saved.",
2417c478bd9Sstevel@tonic-gate 		&umem_flags,	UMF_CONTENTS,	NULL,
2427c478bd9Sstevel@tonic-gate 		&umem_content_log_size,		&umem_log_process
2437c478bd9Sstevel@tonic-gate 	},
2447c478bd9Sstevel@tonic-gate 	{ "fail",		"Unstable",	ITEM_SPECIAL,
2457c478bd9Sstevel@tonic-gate 		"Records are entered into this log for every failed "
2467c478bd9Sstevel@tonic-gate 		    "allocation.",
2477c478bd9Sstevel@tonic-gate 		NULL, 0, NULL,
2487c478bd9Sstevel@tonic-gate 		&umem_failure_log_size,		&umem_log_process
2497c478bd9Sstevel@tonic-gate 	},
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate 	{ "slab",		"Private",	ITEM_SPECIAL,
2527c478bd9Sstevel@tonic-gate 		"Every slab created will be entered into this log.",
2537c478bd9Sstevel@tonic-gate 		NULL, 0, NULL,
2547c478bd9Sstevel@tonic-gate 		&umem_slab_log_size,		&umem_log_process
2557c478bd9Sstevel@tonic-gate 	},
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 	{ NULL, "-- end of UMEM_LOGGING --",	ITEM_INVALID }
2587c478bd9Sstevel@tonic-gate };
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate typedef struct umem_envvar {
2617c478bd9Sstevel@tonic-gate 	const char *env_name;
2627c478bd9Sstevel@tonic-gate 	const char *env_func;
2637c478bd9Sstevel@tonic-gate 	umem_env_item_t	*env_item_list;
2647c478bd9Sstevel@tonic-gate 	const char *env_getenv_result;
2657c478bd9Sstevel@tonic-gate 	const char *env_func_result;
2667c478bd9Sstevel@tonic-gate } umem_envvar_t;
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate static umem_envvar_t umem_envvars[] = {
2697c478bd9Sstevel@tonic-gate 	{ "UMEM_DEBUG",		"_umem_debug_init",	umem_debug_items },
2707c478bd9Sstevel@tonic-gate 	{ "UMEM_OPTIONS",	"_umem_options_init",	umem_options_items },
2717c478bd9Sstevel@tonic-gate 	{ "UMEM_LOGGING",	"_umem_logging_init",	umem_logging_items },
2727c478bd9Sstevel@tonic-gate 	{ NULL, NULL, NULL }
2737c478bd9Sstevel@tonic-gate };
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate static umem_envvar_t *env_current;
2767c478bd9Sstevel@tonic-gate #define	CURRENT		(env_current->env_name)
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate static int
2797c478bd9Sstevel@tonic-gate empty(const char *str)
2807c478bd9Sstevel@tonic-gate {
2817c478bd9Sstevel@tonic-gate 	char c;
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 	while ((c = *str) != '\0' && isspace(c))
2847c478bd9Sstevel@tonic-gate 		str++;
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate 	return (*str == '\0');
2877c478bd9Sstevel@tonic-gate }
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate static int
2907c478bd9Sstevel@tonic-gate item_uint_process(const umem_env_item_t *item, const char *item_arg)
2917c478bd9Sstevel@tonic-gate {
2927c478bd9Sstevel@tonic-gate 	ulong_t result;
2937c478bd9Sstevel@tonic-gate 	char *endptr = "";
2947c478bd9Sstevel@tonic-gate 	int olderrno;
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate 	olderrno = errno;
2977c478bd9Sstevel@tonic-gate 	errno = 0;
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate 	if (empty(item_arg)) {
3007c478bd9Sstevel@tonic-gate 		goto badnumber;
3017c478bd9Sstevel@tonic-gate 	}
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate 	result = strtoul(item_arg, &endptr, 10);
3047c478bd9Sstevel@tonic-gate 
3057c478bd9Sstevel@tonic-gate 	if (result == ULONG_MAX && errno == ERANGE) {
3067c478bd9Sstevel@tonic-gate 		errno = olderrno;
3077c478bd9Sstevel@tonic-gate 		goto overflow;
3087c478bd9Sstevel@tonic-gate 	}
3097c478bd9Sstevel@tonic-gate 	errno = olderrno;
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate 	if (*endptr != '\0')
3127c478bd9Sstevel@tonic-gate 		goto badnumber;
3137c478bd9Sstevel@tonic-gate 	if ((uint_t)result != result)
3147c478bd9Sstevel@tonic-gate 		goto overflow;
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 	(*item->item_uint_target) = (uint_t)result;
3177c478bd9Sstevel@tonic-gate 	return (ARG_SUCCESS);
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate badnumber:
3207c478bd9Sstevel@tonic-gate 	log_message("%s: %s: not a number\n", CURRENT, item->item_name);
3217c478bd9Sstevel@tonic-gate 	return (ARG_BAD);
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate overflow:
3247c478bd9Sstevel@tonic-gate 	log_message("%s: %s: overflowed\n", CURRENT, item->item_name);
3257c478bd9Sstevel@tonic-gate 	return (ARG_BAD);
3267c478bd9Sstevel@tonic-gate }
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate static int
3297c478bd9Sstevel@tonic-gate item_size_process(const umem_env_item_t *item, const char *item_arg)
3307c478bd9Sstevel@tonic-gate {
3317c478bd9Sstevel@tonic-gate 	ulong_t result;
3327c478bd9Sstevel@tonic-gate 	ulong_t result_arg;
3337c478bd9Sstevel@tonic-gate 	char *endptr = "";
3347c478bd9Sstevel@tonic-gate 	int olderrno;
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 	if (empty(item_arg))
3377c478bd9Sstevel@tonic-gate 		goto badnumber;
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 	olderrno = errno;
3407c478bd9Sstevel@tonic-gate 	errno = 0;
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 	result_arg = strtoul(item_arg, &endptr, 10);
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate 	if (result_arg == ULONG_MAX && errno == ERANGE) {
3457c478bd9Sstevel@tonic-gate 		errno = olderrno;
3467c478bd9Sstevel@tonic-gate 		goto overflow;
3477c478bd9Sstevel@tonic-gate 	}
3487c478bd9Sstevel@tonic-gate 	errno = olderrno;
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 	result = result_arg;
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 	switch (*endptr) {
3537c478bd9Sstevel@tonic-gate 	case 't':
3547c478bd9Sstevel@tonic-gate 	case 'T':
3557c478bd9Sstevel@tonic-gate 		result *= 1024;
3567c478bd9Sstevel@tonic-gate 		if (result < result_arg)
3577c478bd9Sstevel@tonic-gate 			goto overflow;
3587c478bd9Sstevel@tonic-gate 		/*FALLTHRU*/
3597c478bd9Sstevel@tonic-gate 	case 'g':
3607c478bd9Sstevel@tonic-gate 	case 'G':
3617c478bd9Sstevel@tonic-gate 		result *= 1024;
3627c478bd9Sstevel@tonic-gate 		if (result < result_arg)
3637c478bd9Sstevel@tonic-gate 			goto overflow;
3647c478bd9Sstevel@tonic-gate 		/*FALLTHRU*/
3657c478bd9Sstevel@tonic-gate 	case 'm':
3667c478bd9Sstevel@tonic-gate 	case 'M':
3677c478bd9Sstevel@tonic-gate 		result *= 1024;
3687c478bd9Sstevel@tonic-gate 		if (result < result_arg)
3697c478bd9Sstevel@tonic-gate 			goto overflow;
3707c478bd9Sstevel@tonic-gate 		/*FALLTHRU*/
3717c478bd9Sstevel@tonic-gate 	case 'k':
3727c478bd9Sstevel@tonic-gate 	case 'K':
3737c478bd9Sstevel@tonic-gate 		result *= 1024;
3747c478bd9Sstevel@tonic-gate 		if (result < result_arg)
3757c478bd9Sstevel@tonic-gate 			goto overflow;
3767c478bd9Sstevel@tonic-gate 		endptr++;		/* skip over the size character */
3777c478bd9Sstevel@tonic-gate 		break;
3787c478bd9Sstevel@tonic-gate 	default:
3797c478bd9Sstevel@tonic-gate 		break;			/* handled later */
3807c478bd9Sstevel@tonic-gate 	}
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 	if (*endptr != '\0')
3837c478bd9Sstevel@tonic-gate 		goto badnumber;
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 	(*item->item_size_target) = result;
3867c478bd9Sstevel@tonic-gate 	return (ARG_SUCCESS);
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate badnumber:
3897c478bd9Sstevel@tonic-gate 	log_message("%s: %s: not a number\n", CURRENT, item->item_name);
3907c478bd9Sstevel@tonic-gate 	return (ARG_BAD);
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate overflow:
3937c478bd9Sstevel@tonic-gate 	log_message("%s: %s: overflowed\n", CURRENT, item->item_name);
3947c478bd9Sstevel@tonic-gate 	return (ARG_BAD);
3957c478bd9Sstevel@tonic-gate }
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate static int
3987c478bd9Sstevel@tonic-gate umem_log_process(const umem_env_item_t *item, const char *item_arg)
3997c478bd9Sstevel@tonic-gate {
4007c478bd9Sstevel@tonic-gate 	if (item_arg != NULL) {
4017c478bd9Sstevel@tonic-gate 		int ret;
4027c478bd9Sstevel@tonic-gate 		ret = item_size_process(item, item_arg);
4037c478bd9Sstevel@tonic-gate 		if (ret != ARG_SUCCESS)
4047c478bd9Sstevel@tonic-gate 			return (ret);
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate 		if (*item->item_size_target == 0)
4077c478bd9Sstevel@tonic-gate 			return (ARG_SUCCESS);
4087c478bd9Sstevel@tonic-gate 	} else
4097c478bd9Sstevel@tonic-gate 		*item->item_size_target = 64*1024;
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 	umem_logging = 1;
4127c478bd9Sstevel@tonic-gate 	return (ARG_SUCCESS);
4137c478bd9Sstevel@tonic-gate }
4147c478bd9Sstevel@tonic-gate 
415789d94c2Sjwadams static int
416789d94c2Sjwadams umem_size_process(const umem_env_item_t *item, const char *item_arg)
417789d94c2Sjwadams {
418789d94c2Sjwadams 	const char *name = item->item_name;
419789d94c2Sjwadams 	void (*action_func)(size_t);
420789d94c2Sjwadams 
421789d94c2Sjwadams 	size_t result;
422789d94c2Sjwadams 
423789d94c2Sjwadams 	int ret;
424789d94c2Sjwadams 
425789d94c2Sjwadams 	if (strcmp(name, "size_clear") == 0) {
426789d94c2Sjwadams 		if (item_arg != NULL) {
427789d94c2Sjwadams 			log_message("%s: %s: does not take a value. ignored\n",
428789d94c2Sjwadams 			    CURRENT, name);
429789d94c2Sjwadams 			return (ARG_BAD);
430789d94c2Sjwadams 		}
431789d94c2Sjwadams 		umem_alloc_sizes_clear();
432789d94c2Sjwadams 		return (ARG_SUCCESS);
433789d94c2Sjwadams 	} else if (strcmp(name, "size_add") == 0) {
434789d94c2Sjwadams 		action_func = umem_alloc_sizes_add;
435789d94c2Sjwadams 	} else if (strcmp(name, "size_remove") == 0) {
436789d94c2Sjwadams 		action_func = umem_alloc_sizes_remove;
437789d94c2Sjwadams 	} else {
438789d94c2Sjwadams 		log_message("%s: %s: internally unrecognized\n",
439789d94c2Sjwadams 		    CURRENT, name, name, name);
440789d94c2Sjwadams 		return (ARG_BAD);
441789d94c2Sjwadams 	}
442789d94c2Sjwadams 
443789d94c2Sjwadams 	if (item_arg == NULL) {
444789d94c2Sjwadams 		log_message("%s: %s: requires a value. ignored\n",
445789d94c2Sjwadams 		    CURRENT, name);
446789d94c2Sjwadams 		return (ARG_BAD);
447789d94c2Sjwadams 	}
448789d94c2Sjwadams 
449789d94c2Sjwadams 	ret = item_size_process(item, item_arg);
450789d94c2Sjwadams 	if (ret != ARG_SUCCESS)
451789d94c2Sjwadams 		return (ret);
452789d94c2Sjwadams 
453789d94c2Sjwadams 	result = *item->item_size_target;
454789d94c2Sjwadams 	action_func(result);
455789d94c2Sjwadams 	return (ARG_SUCCESS);
456789d94c2Sjwadams }
457789d94c2Sjwadams 
4587c478bd9Sstevel@tonic-gate #ifndef UMEM_STANDALONE
4597c478bd9Sstevel@tonic-gate static int
4607c478bd9Sstevel@tonic-gate umem_backend_process(const umem_env_item_t *item, const char *item_arg)
4617c478bd9Sstevel@tonic-gate {
4627c478bd9Sstevel@tonic-gate 	const char *name = item->item_name;
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate 	if (item_arg == NULL)
4657c478bd9Sstevel@tonic-gate 		goto fail;
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate 	if (strcmp(item_arg, "sbrk") == 0)
4687c478bd9Sstevel@tonic-gate 		vmem_backend |= VMEM_BACKEND_SBRK;
4697c478bd9Sstevel@tonic-gate 	else if (strcmp(item_arg, "mmap") == 0)
4707c478bd9Sstevel@tonic-gate 		vmem_backend |= VMEM_BACKEND_MMAP;
4717c478bd9Sstevel@tonic-gate 	else
4727c478bd9Sstevel@tonic-gate 		goto fail;
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate 	return (ARG_SUCCESS);
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate fail:
4777c478bd9Sstevel@tonic-gate 	log_message("%s: %s: must be %s=sbrk or %s=mmap\n",
4787c478bd9Sstevel@tonic-gate 	    CURRENT, name, name, name);
4797c478bd9Sstevel@tonic-gate 	return (ARG_BAD);
4807c478bd9Sstevel@tonic-gate }
481*aaf809d7SRobert Mustacchi 
482*aaf809d7SRobert Mustacchi 
483*aaf809d7SRobert Mustacchi static int
484*aaf809d7SRobert Mustacchi umem_allocator_process(const umem_env_item_t *item, const char *item_arg)
485*aaf809d7SRobert Mustacchi {
486*aaf809d7SRobert Mustacchi 	const char *name = item->item_name;
487*aaf809d7SRobert Mustacchi 
488*aaf809d7SRobert Mustacchi 	if (item_arg == NULL)
489*aaf809d7SRobert Mustacchi 		goto fail;
490*aaf809d7SRobert Mustacchi 
491*aaf809d7SRobert Mustacchi 	if (strcmp(item_arg, "best") == 0)
492*aaf809d7SRobert Mustacchi 		vmem_allocator = VM_BESTFIT;
493*aaf809d7SRobert Mustacchi 	else if (strcmp(item_arg, "next") == 0)
494*aaf809d7SRobert Mustacchi 		vmem_allocator = VM_NEXTFIT;
495*aaf809d7SRobert Mustacchi 	else if (strcmp(item_arg, "first") == 0)
496*aaf809d7SRobert Mustacchi 		vmem_allocator = VM_FIRSTFIT;
497*aaf809d7SRobert Mustacchi 	else if (strcmp(item_arg, "instant") == 0)
498*aaf809d7SRobert Mustacchi 		vmem_allocator = 0;
499*aaf809d7SRobert Mustacchi 	else
500*aaf809d7SRobert Mustacchi 		goto fail;
501*aaf809d7SRobert Mustacchi 
502*aaf809d7SRobert Mustacchi 	return (ARG_SUCCESS);
503*aaf809d7SRobert Mustacchi 
504*aaf809d7SRobert Mustacchi fail:
505*aaf809d7SRobert Mustacchi 	log_message("%s: %s: must be %s=best, %s=next or %s=first\n",
506*aaf809d7SRobert Mustacchi 	    CURRENT, name, name, name, name);
507*aaf809d7SRobert Mustacchi 	return (ARG_BAD);
508*aaf809d7SRobert Mustacchi 
509*aaf809d7SRobert Mustacchi }
5107c478bd9Sstevel@tonic-gate #endif
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate static int
5137c478bd9Sstevel@tonic-gate process_item(const umem_env_item_t *item, const char *item_arg)
5147c478bd9Sstevel@tonic-gate {
5157c478bd9Sstevel@tonic-gate 	int arg_required = 0;
5167c478bd9Sstevel@tonic-gate 	arg_process_t *processor;
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate 	switch (item->item_type) {
5197c478bd9Sstevel@tonic-gate 	case ITEM_FLAG:
5207c478bd9Sstevel@tonic-gate 	case ITEM_CLEARFLAG:
5217c478bd9Sstevel@tonic-gate 	case ITEM_OPTUINT:
5227c478bd9Sstevel@tonic-gate 	case ITEM_OPTSIZE:
5237c478bd9Sstevel@tonic-gate 	case ITEM_SPECIAL:
5247c478bd9Sstevel@tonic-gate 		arg_required = 0;
5257c478bd9Sstevel@tonic-gate 		break;
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate 	case ITEM_UINT:
5287c478bd9Sstevel@tonic-gate 	case ITEM_SIZE:
5297c478bd9Sstevel@tonic-gate 		arg_required = 1;
5307c478bd9Sstevel@tonic-gate 		break;
5317c478bd9Sstevel@tonic-gate 	}
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate 	switch (item->item_type) {
5347c478bd9Sstevel@tonic-gate 	case ITEM_FLAG:
5357c478bd9Sstevel@tonic-gate 	case ITEM_CLEARFLAG:
5367c478bd9Sstevel@tonic-gate 		if (item_arg != NULL) {
5377c478bd9Sstevel@tonic-gate 			log_message("%s: %s: does not take a value. ignored\n",
5387c478bd9Sstevel@tonic-gate 			    CURRENT, item->item_name);
5397c478bd9Sstevel@tonic-gate 			return (1);
5407c478bd9Sstevel@tonic-gate 		}
5417c478bd9Sstevel@tonic-gate 		processor = NULL;
5427c478bd9Sstevel@tonic-gate 		break;
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate 	case ITEM_UINT:
5457c478bd9Sstevel@tonic-gate 	case ITEM_OPTUINT:
5467c478bd9Sstevel@tonic-gate 		processor = item_uint_process;
5477c478bd9Sstevel@tonic-gate 		break;
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate 	case ITEM_SIZE:
5507c478bd9Sstevel@tonic-gate 	case ITEM_OPTSIZE:
5517c478bd9Sstevel@tonic-gate 		processor = item_size_process;
5527c478bd9Sstevel@tonic-gate 		break;
5537c478bd9Sstevel@tonic-gate 
5547c478bd9Sstevel@tonic-gate 	case ITEM_SPECIAL:
5557c478bd9Sstevel@tonic-gate 		processor = item->item_special;
5567c478bd9Sstevel@tonic-gate 		break;
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate 	default:
5597c478bd9Sstevel@tonic-gate 		log_message("%s: %s: Invalid type.  Ignored\n",
5607c478bd9Sstevel@tonic-gate 		    CURRENT, item->item_name);
5617c478bd9Sstevel@tonic-gate 		return (1);
5627c478bd9Sstevel@tonic-gate 	}
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate 	if (arg_required && item_arg == NULL) {
5657c478bd9Sstevel@tonic-gate 		log_message("%s: %s: Required value missing\n",
5667c478bd9Sstevel@tonic-gate 		    CURRENT, item->item_name);
5677c478bd9Sstevel@tonic-gate 		goto invalid;
5687c478bd9Sstevel@tonic-gate 	}
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate 	if (item_arg != NULL || item->item_type == ITEM_SPECIAL) {
5717c478bd9Sstevel@tonic-gate 		if (processor(item, item_arg) != ARG_SUCCESS)
5727c478bd9Sstevel@tonic-gate 			goto invalid;
5737c478bd9Sstevel@tonic-gate 	}
5747c478bd9Sstevel@tonic-gate 
5757c478bd9Sstevel@tonic-gate 	if (item->item_flag_target) {
5767c478bd9Sstevel@tonic-gate 		if (item->item_type == ITEM_CLEARFLAG)
5777c478bd9Sstevel@tonic-gate 			(*item->item_flag_target) &= ~item->item_flag_value;
5787c478bd9Sstevel@tonic-gate 		else
5797c478bd9Sstevel@tonic-gate 			(*item->item_flag_target) |= item->item_flag_value;
5807c478bd9Sstevel@tonic-gate 	}
5817c478bd9Sstevel@tonic-gate 	return (0);
5827c478bd9Sstevel@tonic-gate 
5837c478bd9Sstevel@tonic-gate invalid:
5847c478bd9Sstevel@tonic-gate 	return (1);
5857c478bd9Sstevel@tonic-gate }
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate #define	ENV_SHORT_BYTES	10	/* bytes to print on error */
5887c478bd9Sstevel@tonic-gate void
5897c478bd9Sstevel@tonic-gate umem_process_value(umem_env_item_t *item_list, const char *beg, const char *end)
5907c478bd9Sstevel@tonic-gate {
5917c478bd9Sstevel@tonic-gate 	char buf[UMEM_ENV_ITEM_MAX];
5927c478bd9Sstevel@tonic-gate 	char *argptr;
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate 	size_t count;
5957c478bd9Sstevel@tonic-gate 
5967c478bd9Sstevel@tonic-gate 	while (beg < end && isspace(*beg))
5977c478bd9Sstevel@tonic-gate 		beg++;
5987c478bd9Sstevel@tonic-gate 
5997c478bd9Sstevel@tonic-gate 	while (beg < end && isspace(*(end - 1)))
6007c478bd9Sstevel@tonic-gate 		end--;
6017c478bd9Sstevel@tonic-gate 
6027c478bd9Sstevel@tonic-gate 	if (beg >= end) {
6037c478bd9Sstevel@tonic-gate 		log_message("%s: empty option\n", CURRENT);
6047c478bd9Sstevel@tonic-gate 		return;
6057c478bd9Sstevel@tonic-gate 	}
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate 	count = end - beg;
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate 	if (count + 1 > sizeof (buf)) {
6107c478bd9Sstevel@tonic-gate 		char outbuf[ENV_SHORT_BYTES + 1];
6117c478bd9Sstevel@tonic-gate 		/*
6127c478bd9Sstevel@tonic-gate 		 * Have to do this, since sprintf("%10s",...) calls malloc()
6137c478bd9Sstevel@tonic-gate 		 */
6147c478bd9Sstevel@tonic-gate 		(void) strncpy(outbuf, beg, ENV_SHORT_BYTES);
6157c478bd9Sstevel@tonic-gate 		outbuf[ENV_SHORT_BYTES] = 0;
6167c478bd9Sstevel@tonic-gate 
6177c478bd9Sstevel@tonic-gate 		log_message("%s: argument \"%s...\" too long\n", CURRENT,
6187c478bd9Sstevel@tonic-gate 		    outbuf);
6197c478bd9Sstevel@tonic-gate 		return;
6207c478bd9Sstevel@tonic-gate 	}
6217c478bd9Sstevel@tonic-gate 
6227c478bd9Sstevel@tonic-gate 	(void) strncpy(buf, beg, count);
6237c478bd9Sstevel@tonic-gate 	buf[count] = 0;
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate 	argptr = strchr(buf, '=');
6267c478bd9Sstevel@tonic-gate 
6277c478bd9Sstevel@tonic-gate 	if (argptr != NULL)
6287c478bd9Sstevel@tonic-gate 		*argptr++ = 0;
6297c478bd9Sstevel@tonic-gate 
6307c478bd9Sstevel@tonic-gate 	for (; item_list->item_name != NULL; item_list++) {
6317c478bd9Sstevel@tonic-gate 		if (strcmp(buf, item_list->item_name) == 0) {
6327c478bd9Sstevel@tonic-gate 			(void) process_item(item_list, argptr);
6337c478bd9Sstevel@tonic-gate 			return;
6347c478bd9Sstevel@tonic-gate 		}
6357c478bd9Sstevel@tonic-gate 	}
6367c478bd9Sstevel@tonic-gate 	log_message("%s: '%s' not recognized\n", CURRENT, buf);
6377c478bd9Sstevel@tonic-gate }
6387c478bd9Sstevel@tonic-gate 
6397c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6407c478bd9Sstevel@tonic-gate void
6417c478bd9Sstevel@tonic-gate umem_setup_envvars(int invalid)
6427c478bd9Sstevel@tonic-gate {
6437c478bd9Sstevel@tonic-gate 	umem_envvar_t *cur_env;
6447c478bd9Sstevel@tonic-gate 	static volatile enum {
6457c478bd9Sstevel@tonic-gate 		STATE_START,
6467c478bd9Sstevel@tonic-gate 		STATE_GETENV,
6472d9e8f45Sjwadams 		STATE_DLOPEN,
6487c478bd9Sstevel@tonic-gate 		STATE_DLSYM,
6497c478bd9Sstevel@tonic-gate 		STATE_FUNC,
6507c478bd9Sstevel@tonic-gate 		STATE_DONE
6517c478bd9Sstevel@tonic-gate 	} state = STATE_START;
6527c478bd9Sstevel@tonic-gate #ifndef UMEM_STANDALONE
6537c478bd9Sstevel@tonic-gate 	void *h;
6547c478bd9Sstevel@tonic-gate #endif
6557c478bd9Sstevel@tonic-gate 
6567c478bd9Sstevel@tonic-gate 	if (invalid) {
6577c478bd9Sstevel@tonic-gate 		const char *where;
6587c478bd9Sstevel@tonic-gate 		/*
6597c478bd9Sstevel@tonic-gate 		 * One of the calls below invoked malloc() recursively.  We
6607c478bd9Sstevel@tonic-gate 		 * remove any partial results and return.
6617c478bd9Sstevel@tonic-gate 		 */
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate 		switch (state) {
6647c478bd9Sstevel@tonic-gate 		case STATE_START:
6657c478bd9Sstevel@tonic-gate 			where = "before getenv(3C) calls -- "
6667c478bd9Sstevel@tonic-gate 			    "getenv(3C) results ignored.";
6677c478bd9Sstevel@tonic-gate 			break;
6687c478bd9Sstevel@tonic-gate 		case STATE_GETENV:
6697c478bd9Sstevel@tonic-gate 			where = "during getenv(3C) calls -- "
6707c478bd9Sstevel@tonic-gate 			    "getenv(3C) results ignored.";
6717c478bd9Sstevel@tonic-gate 			break;
6722d9e8f45Sjwadams 		case STATE_DLOPEN:
6732d9e8f45Sjwadams 			where = "during dlopen(3C) call -- "
6742d9e8f45Sjwadams 			    "_umem_*() results ignored.";
6752d9e8f45Sjwadams 			break;
6767c478bd9Sstevel@tonic-gate 		case STATE_DLSYM:
6777c478bd9Sstevel@tonic-gate 			where = "during dlsym(3C) call -- "
6787c478bd9Sstevel@tonic-gate 			    "_umem_*() results ignored.";
6797c478bd9Sstevel@tonic-gate 			break;
6807c478bd9Sstevel@tonic-gate 		case STATE_FUNC:
6817c478bd9Sstevel@tonic-gate 			where = "during _umem_*() call -- "
6827c478bd9Sstevel@tonic-gate 			    "_umem_*() results ignored.";
6837c478bd9Sstevel@tonic-gate 			break;
6847c478bd9Sstevel@tonic-gate 		case STATE_DONE:
6857c478bd9Sstevel@tonic-gate 			where = "after dlsym() or _umem_*() calls.";
6867c478bd9Sstevel@tonic-gate 			break;
6877c478bd9Sstevel@tonic-gate 		default:
6887c478bd9Sstevel@tonic-gate 			where = "at unknown point -- "
6897c478bd9Sstevel@tonic-gate 			    "_umem_*() results ignored.";
6907c478bd9Sstevel@tonic-gate 			break;
6917c478bd9Sstevel@tonic-gate 		}
6927c478bd9Sstevel@tonic-gate 
6937c478bd9Sstevel@tonic-gate 		log_message("recursive allocation %s\n", where);
6947c478bd9Sstevel@tonic-gate 
6957c478bd9Sstevel@tonic-gate 		for (cur_env = umem_envvars; cur_env->env_name != NULL;
6967c478bd9Sstevel@tonic-gate 		    cur_env++) {
6977c478bd9Sstevel@tonic-gate 			if (state == STATE_GETENV)
6987c478bd9Sstevel@tonic-gate 				cur_env->env_getenv_result = NULL;
6997c478bd9Sstevel@tonic-gate 			if (state != STATE_DONE)
7007c478bd9Sstevel@tonic-gate 				cur_env->env_func_result = NULL;
7017c478bd9Sstevel@tonic-gate 		}
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate 		state = STATE_DONE;
7047c478bd9Sstevel@tonic-gate 		return;
7057c478bd9Sstevel@tonic-gate 	}
7067c478bd9Sstevel@tonic-gate 
7077c478bd9Sstevel@tonic-gate 	state = STATE_GETENV;
7087c478bd9Sstevel@tonic-gate 
7097c478bd9Sstevel@tonic-gate 	for (cur_env = umem_envvars; cur_env->env_name != NULL; cur_env++) {
7107c478bd9Sstevel@tonic-gate 		cur_env->env_getenv_result = getenv(cur_env->env_name);
7117c478bd9Sstevel@tonic-gate 		if (state == STATE_DONE)
7127c478bd9Sstevel@tonic-gate 			return;		/* recursed */
7137c478bd9Sstevel@tonic-gate 	}
7147c478bd9Sstevel@tonic-gate 
7157c478bd9Sstevel@tonic-gate #ifndef UMEM_STANDALONE
7162d9e8f45Sjwadams 	state = STATE_DLOPEN;
7172d9e8f45Sjwadams 
7187c478bd9Sstevel@tonic-gate 	/* get a handle to the "a.out" object */
7197c478bd9Sstevel@tonic-gate 	if ((h = dlopen(0, RTLD_FIRST | RTLD_LAZY)) != NULL) {
7207c478bd9Sstevel@tonic-gate 		for (cur_env = umem_envvars; cur_env->env_name != NULL;
7217c478bd9Sstevel@tonic-gate 		    cur_env++) {
7227c478bd9Sstevel@tonic-gate 			const char *(*func)(void);
7237c478bd9Sstevel@tonic-gate 			const char *value;
7247c478bd9Sstevel@tonic-gate 
7257c478bd9Sstevel@tonic-gate 			state = STATE_DLSYM;
7267c478bd9Sstevel@tonic-gate 			func = (const char *(*)(void))dlsym(h,
7277c478bd9Sstevel@tonic-gate 			    cur_env->env_func);
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate 			if (state == STATE_DONE)
7307c478bd9Sstevel@tonic-gate 				break;		/* recursed */
7317c478bd9Sstevel@tonic-gate 
7327c478bd9Sstevel@tonic-gate 			state = STATE_FUNC;
7337c478bd9Sstevel@tonic-gate 			if (func != NULL) {
7347c478bd9Sstevel@tonic-gate 				value = func();
7357c478bd9Sstevel@tonic-gate 				if (state == STATE_DONE)
7367c478bd9Sstevel@tonic-gate 					break;		/* recursed */
7377c478bd9Sstevel@tonic-gate 				cur_env->env_func_result = value;
7387c478bd9Sstevel@tonic-gate 			}
7397c478bd9Sstevel@tonic-gate 		}
7407c478bd9Sstevel@tonic-gate 		(void) dlclose(h);
7417c478bd9Sstevel@tonic-gate 	} else {
7427c478bd9Sstevel@tonic-gate 		(void) dlerror();		/* snarf dlerror() */
7437c478bd9Sstevel@tonic-gate 	}
7447c478bd9Sstevel@tonic-gate #endif /* UMEM_STANDALONE */
7457c478bd9Sstevel@tonic-gate 
7467c478bd9Sstevel@tonic-gate 	state = STATE_DONE;
7477c478bd9Sstevel@tonic-gate }
7487c478bd9Sstevel@tonic-gate 
7497c478bd9Sstevel@tonic-gate /*
7507c478bd9Sstevel@tonic-gate  * Process the environment variables.
7517c478bd9Sstevel@tonic-gate  */
7527c478bd9Sstevel@tonic-gate void
7537c478bd9Sstevel@tonic-gate umem_process_envvars(void)
7547c478bd9Sstevel@tonic-gate {
7557c478bd9Sstevel@tonic-gate 	const char *value;
7567c478bd9Sstevel@tonic-gate 	const char *end, *next;
7577c478bd9Sstevel@tonic-gate 	umem_envvar_t *cur_env;
7587c478bd9Sstevel@tonic-gate 
7597c478bd9Sstevel@tonic-gate 	for (cur_env = umem_envvars; cur_env->env_name != NULL; cur_env++) {
7607c478bd9Sstevel@tonic-gate 		env_current = cur_env;
7617c478bd9Sstevel@tonic-gate 
7627c478bd9Sstevel@tonic-gate 		value = cur_env->env_getenv_result;
7637c478bd9Sstevel@tonic-gate 		if (value == NULL)
7647c478bd9Sstevel@tonic-gate 			value = cur_env->env_func_result;
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate 		/* ignore if missing or empty */
7677c478bd9Sstevel@tonic-gate 		if (value == NULL)
7687c478bd9Sstevel@tonic-gate 			continue;
7697c478bd9Sstevel@tonic-gate 
7707c478bd9Sstevel@tonic-gate 		for (end = value; *end != '\0'; value = next) {
7717c478bd9Sstevel@tonic-gate 			end = strchr(value, ',');
7727c478bd9Sstevel@tonic-gate 			if (end != NULL)
7737c478bd9Sstevel@tonic-gate 				next = end + 1;		/* skip the comma */
7747c478bd9Sstevel@tonic-gate 			else
7757c478bd9Sstevel@tonic-gate 				next = end = value + strlen(value);
7767c478bd9Sstevel@tonic-gate 
7777c478bd9Sstevel@tonic-gate 			umem_process_value(cur_env->env_item_list, value, end);
7787c478bd9Sstevel@tonic-gate 		}
7797c478bd9Sstevel@tonic-gate 	}
7807c478bd9Sstevel@tonic-gate }
781