1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #include <ctype.h> 30*7c478bd9Sstevel@tonic-gate #include <errno.h> 31*7c478bd9Sstevel@tonic-gate #include <limits.h> 32*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 33*7c478bd9Sstevel@tonic-gate #include <string.h> 34*7c478bd9Sstevel@tonic-gate #include <dlfcn.h> 35*7c478bd9Sstevel@tonic-gate 36*7c478bd9Sstevel@tonic-gate #include "umem_base.h" 37*7c478bd9Sstevel@tonic-gate #include "vmem_base.h" 38*7c478bd9Sstevel@tonic-gate 39*7c478bd9Sstevel@tonic-gate /* 40*7c478bd9Sstevel@tonic-gate * A umem environment variable, like UMEM_DEBUG, is set to a series 41*7c478bd9Sstevel@tonic-gate * of items, seperated by ',': 42*7c478bd9Sstevel@tonic-gate * 43*7c478bd9Sstevel@tonic-gate * UMEM_DEBUG="audit=10,guards,firewall=512" 44*7c478bd9Sstevel@tonic-gate * 45*7c478bd9Sstevel@tonic-gate * This structure describes items. Each item has a name, type, and 46*7c478bd9Sstevel@tonic-gate * description. During processing, an item read from the user may 47*7c478bd9Sstevel@tonic-gate * be either "valid" or "invalid". 48*7c478bd9Sstevel@tonic-gate * 49*7c478bd9Sstevel@tonic-gate * A valid item has an argument, if required, and it is of the right 50*7c478bd9Sstevel@tonic-gate * form (doesn't overflow, doesn't contain any unexpected characters). 51*7c478bd9Sstevel@tonic-gate * 52*7c478bd9Sstevel@tonic-gate * If the item is valid, item_flag_target != NULL, and: 53*7c478bd9Sstevel@tonic-gate * type is not CLEARFLAG, then (*item_flag_target) |= item_flag_value 54*7c478bd9Sstevel@tonic-gate * type is CLEARFLAG, then (*item_flag_target) &= ~item_flag_value 55*7c478bd9Sstevel@tonic-gate */ 56*7c478bd9Sstevel@tonic-gate 57*7c478bd9Sstevel@tonic-gate #define UMEM_ENV_ITEM_MAX 512 58*7c478bd9Sstevel@tonic-gate 59*7c478bd9Sstevel@tonic-gate struct umem_env_item; 60*7c478bd9Sstevel@tonic-gate 61*7c478bd9Sstevel@tonic-gate typedef int arg_process_t(const struct umem_env_item *item, const char *value); 62*7c478bd9Sstevel@tonic-gate #define ARG_SUCCESS 0 /* processing successful */ 63*7c478bd9Sstevel@tonic-gate #define ARG_BAD 1 /* argument had a bad value */ 64*7c478bd9Sstevel@tonic-gate 65*7c478bd9Sstevel@tonic-gate typedef struct umem_env_item { 66*7c478bd9Sstevel@tonic-gate const char *item_name; /* tag in environment variable */ 67*7c478bd9Sstevel@tonic-gate const char *item_interface_stability; 68*7c478bd9Sstevel@tonic-gate enum { 69*7c478bd9Sstevel@tonic-gate ITEM_INVALID, 70*7c478bd9Sstevel@tonic-gate ITEM_FLAG, /* only a flag. No argument allowed */ 71*7c478bd9Sstevel@tonic-gate ITEM_CLEARFLAG, /* only a flag, but clear instead of set */ 72*7c478bd9Sstevel@tonic-gate ITEM_OPTUINT, /* optional integer argument */ 73*7c478bd9Sstevel@tonic-gate ITEM_UINT, /* required integer argument */ 74*7c478bd9Sstevel@tonic-gate ITEM_OPTSIZE, /* optional size_t argument */ 75*7c478bd9Sstevel@tonic-gate ITEM_SIZE, /* required size_t argument */ 76*7c478bd9Sstevel@tonic-gate ITEM_SPECIAL /* special argument processing */ 77*7c478bd9Sstevel@tonic-gate } item_type; 78*7c478bd9Sstevel@tonic-gate const char *item_description; 79*7c478bd9Sstevel@tonic-gate uint_t *item_flag_target; /* the variable containing the flag */ 80*7c478bd9Sstevel@tonic-gate uint_t item_flag_value; /* the value to OR in */ 81*7c478bd9Sstevel@tonic-gate uint_t *item_uint_target; /* the variable to hold the integer */ 82*7c478bd9Sstevel@tonic-gate size_t *item_size_target; 83*7c478bd9Sstevel@tonic-gate arg_process_t *item_special; /* callback for special handling */ 84*7c478bd9Sstevel@tonic-gate } umem_env_item_t; 85*7c478bd9Sstevel@tonic-gate 86*7c478bd9Sstevel@tonic-gate #ifndef UMEM_STANDALONE 87*7c478bd9Sstevel@tonic-gate static arg_process_t umem_backend_process; 88*7c478bd9Sstevel@tonic-gate #endif 89*7c478bd9Sstevel@tonic-gate 90*7c478bd9Sstevel@tonic-gate static arg_process_t umem_log_process; 91*7c478bd9Sstevel@tonic-gate 92*7c478bd9Sstevel@tonic-gate const char *____umem_environ_msg_options = "-- UMEM_OPTIONS --"; 93*7c478bd9Sstevel@tonic-gate 94*7c478bd9Sstevel@tonic-gate static umem_env_item_t umem_options_items[] = { 95*7c478bd9Sstevel@tonic-gate #ifndef UMEM_STANDALONE 96*7c478bd9Sstevel@tonic-gate { "backend", "Evolving", ITEM_SPECIAL, 97*7c478bd9Sstevel@tonic-gate "=sbrk for sbrk(2), =mmap for mmap(2)", 98*7c478bd9Sstevel@tonic-gate NULL, 0, NULL, NULL, 99*7c478bd9Sstevel@tonic-gate &umem_backend_process 100*7c478bd9Sstevel@tonic-gate }, 101*7c478bd9Sstevel@tonic-gate #endif 102*7c478bd9Sstevel@tonic-gate 103*7c478bd9Sstevel@tonic-gate { "concurrency", "Private", ITEM_UINT, 104*7c478bd9Sstevel@tonic-gate "Max concurrency", 105*7c478bd9Sstevel@tonic-gate NULL, 0, &umem_max_ncpus 106*7c478bd9Sstevel@tonic-gate }, 107*7c478bd9Sstevel@tonic-gate { "max_contention", "Private", ITEM_UINT, 108*7c478bd9Sstevel@tonic-gate "Maximum contention in a reap interval before the depot is " 109*7c478bd9Sstevel@tonic-gate "resized.", 110*7c478bd9Sstevel@tonic-gate NULL, 0, &umem_depot_contention 111*7c478bd9Sstevel@tonic-gate }, 112*7c478bd9Sstevel@tonic-gate { "nomagazines", "Private", ITEM_FLAG, 113*7c478bd9Sstevel@tonic-gate "no caches will be multithreaded, and no caching will occur.", 114*7c478bd9Sstevel@tonic-gate &umem_flags, UMF_NOMAGAZINE 115*7c478bd9Sstevel@tonic-gate }, 116*7c478bd9Sstevel@tonic-gate { "reap_interval", "Private", ITEM_UINT, 117*7c478bd9Sstevel@tonic-gate "Minimum time between reaps and updates, in seconds.", 118*7c478bd9Sstevel@tonic-gate NULL, 0, &umem_reap_interval 119*7c478bd9Sstevel@tonic-gate }, 120*7c478bd9Sstevel@tonic-gate 121*7c478bd9Sstevel@tonic-gate #ifndef UMEM_STANDALONE 122*7c478bd9Sstevel@tonic-gate { "sbrk_pagesize", "Private", ITEM_SIZE, 123*7c478bd9Sstevel@tonic-gate "The preferred page size for the sbrk(2) heap.", 124*7c478bd9Sstevel@tonic-gate NULL, 0, NULL, &vmem_sbrk_pagesize 125*7c478bd9Sstevel@tonic-gate }, 126*7c478bd9Sstevel@tonic-gate #endif 127*7c478bd9Sstevel@tonic-gate 128*7c478bd9Sstevel@tonic-gate { NULL, "-- end of UMEM_OPTIONS --", ITEM_INVALID } 129*7c478bd9Sstevel@tonic-gate }; 130*7c478bd9Sstevel@tonic-gate 131*7c478bd9Sstevel@tonic-gate const char *____umem_environ_msg_debug = "-- UMEM_DEBUG --"; 132*7c478bd9Sstevel@tonic-gate 133*7c478bd9Sstevel@tonic-gate static umem_env_item_t umem_debug_items[] = { 134*7c478bd9Sstevel@tonic-gate { "default", "Unstable", ITEM_FLAG, 135*7c478bd9Sstevel@tonic-gate "audit,contents,guards", 136*7c478bd9Sstevel@tonic-gate &umem_flags, 137*7c478bd9Sstevel@tonic-gate UMF_AUDIT | UMF_CONTENTS | UMF_DEADBEEF | UMF_REDZONE 138*7c478bd9Sstevel@tonic-gate }, 139*7c478bd9Sstevel@tonic-gate { "audit", "Unstable", ITEM_OPTUINT, 140*7c478bd9Sstevel@tonic-gate "Enable auditing. optionally =frames to set the number of " 141*7c478bd9Sstevel@tonic-gate "stored stack frames", 142*7c478bd9Sstevel@tonic-gate &umem_flags, UMF_AUDIT, &umem_stack_depth 143*7c478bd9Sstevel@tonic-gate }, 144*7c478bd9Sstevel@tonic-gate { "contents", "Unstable", ITEM_OPTSIZE, 145*7c478bd9Sstevel@tonic-gate "Enable contents storing. UMEM_LOGGING=contents also " 146*7c478bd9Sstevel@tonic-gate "required. optionally =bytes to set the number of stored " 147*7c478bd9Sstevel@tonic-gate "bytes", 148*7c478bd9Sstevel@tonic-gate &umem_flags, UMF_CONTENTS, NULL, &umem_content_maxsave 149*7c478bd9Sstevel@tonic-gate }, 150*7c478bd9Sstevel@tonic-gate { "guards", "Unstable", ITEM_FLAG, 151*7c478bd9Sstevel@tonic-gate "Enables guards and special patterns", 152*7c478bd9Sstevel@tonic-gate &umem_flags, UMF_DEADBEEF | UMF_REDZONE 153*7c478bd9Sstevel@tonic-gate }, 154*7c478bd9Sstevel@tonic-gate { "verbose", "Unstable", ITEM_FLAG, 155*7c478bd9Sstevel@tonic-gate "Enables writing error messages to stderr", 156*7c478bd9Sstevel@tonic-gate &umem_output, 1 157*7c478bd9Sstevel@tonic-gate }, 158*7c478bd9Sstevel@tonic-gate 159*7c478bd9Sstevel@tonic-gate { "nosignal", "Private", ITEM_FLAG, 160*7c478bd9Sstevel@tonic-gate "Abort if called from a signal handler. Turns on 'audit'. " 161*7c478bd9Sstevel@tonic-gate "Note that this is not always a bug.", 162*7c478bd9Sstevel@tonic-gate &umem_flags, UMF_AUDIT | UMF_CHECKSIGNAL 163*7c478bd9Sstevel@tonic-gate }, 164*7c478bd9Sstevel@tonic-gate { "firewall", "Private", ITEM_SIZE, 165*7c478bd9Sstevel@tonic-gate "=minbytes. Every object >= minbytes in size will have its " 166*7c478bd9Sstevel@tonic-gate "end against an unmapped page", 167*7c478bd9Sstevel@tonic-gate &umem_flags, UMF_FIREWALL, NULL, &umem_minfirewall 168*7c478bd9Sstevel@tonic-gate }, 169*7c478bd9Sstevel@tonic-gate { "lite", "Private", ITEM_FLAG, 170*7c478bd9Sstevel@tonic-gate "debugging-lite", 171*7c478bd9Sstevel@tonic-gate &umem_flags, UMF_LITE 172*7c478bd9Sstevel@tonic-gate }, 173*7c478bd9Sstevel@tonic-gate { "maxverify", "Private", ITEM_SIZE, 174*7c478bd9Sstevel@tonic-gate "=maxbytes, Maximum bytes to check when 'guards' is active. " 175*7c478bd9Sstevel@tonic-gate "Normally all bytes are checked.", 176*7c478bd9Sstevel@tonic-gate NULL, 0, NULL, &umem_maxverify 177*7c478bd9Sstevel@tonic-gate }, 178*7c478bd9Sstevel@tonic-gate { "noabort", "Private", ITEM_CLEARFLAG, 179*7c478bd9Sstevel@tonic-gate "umem will not abort when a recoverable error occurs " 180*7c478bd9Sstevel@tonic-gate "(i.e. double frees, certain kinds of corruption)", 181*7c478bd9Sstevel@tonic-gate &umem_abort, 1 182*7c478bd9Sstevel@tonic-gate }, 183*7c478bd9Sstevel@tonic-gate { "mtbf", "Private", ITEM_UINT, 184*7c478bd9Sstevel@tonic-gate "=mtbf, the mean time between injected failures. Works best " 185*7c478bd9Sstevel@tonic-gate "if prime.\n", 186*7c478bd9Sstevel@tonic-gate NULL, 0, &umem_mtbf 187*7c478bd9Sstevel@tonic-gate }, 188*7c478bd9Sstevel@tonic-gate { "random", "Private", ITEM_FLAG, 189*7c478bd9Sstevel@tonic-gate "randomize flags on a per-cache basis", 190*7c478bd9Sstevel@tonic-gate &umem_flags, UMF_RANDOMIZE 191*7c478bd9Sstevel@tonic-gate }, 192*7c478bd9Sstevel@tonic-gate { "allverbose", "Private", ITEM_FLAG, 193*7c478bd9Sstevel@tonic-gate "Enables writing all logged messages to stderr", 194*7c478bd9Sstevel@tonic-gate &umem_output, 2 195*7c478bd9Sstevel@tonic-gate }, 196*7c478bd9Sstevel@tonic-gate 197*7c478bd9Sstevel@tonic-gate { NULL, "-- end of UMEM_DEBUG --", ITEM_INVALID } 198*7c478bd9Sstevel@tonic-gate }; 199*7c478bd9Sstevel@tonic-gate 200*7c478bd9Sstevel@tonic-gate const char *____umem_environ_msg_logging = "-- UMEM_LOGGING --"; 201*7c478bd9Sstevel@tonic-gate 202*7c478bd9Sstevel@tonic-gate static umem_env_item_t umem_logging_items[] = { 203*7c478bd9Sstevel@tonic-gate { "transaction", "Unstable", ITEM_SPECIAL, 204*7c478bd9Sstevel@tonic-gate "If 'audit' is set in UMEM_DEBUG, the audit structures " 205*7c478bd9Sstevel@tonic-gate "from previous transactions are entered into this log.", 206*7c478bd9Sstevel@tonic-gate NULL, 0, NULL, 207*7c478bd9Sstevel@tonic-gate &umem_transaction_log_size, &umem_log_process 208*7c478bd9Sstevel@tonic-gate }, 209*7c478bd9Sstevel@tonic-gate { "contents", "Unstable", ITEM_SPECIAL, 210*7c478bd9Sstevel@tonic-gate "If 'audit' is set in UMEM_DEBUG, the contents of objects " 211*7c478bd9Sstevel@tonic-gate "are recorded in this log as they are freed. If the " 212*7c478bd9Sstevel@tonic-gate "'contents' option is not set in UMEM_DEBUG, the first " 213*7c478bd9Sstevel@tonic-gate "256 bytes of each freed buffer will be saved.", 214*7c478bd9Sstevel@tonic-gate &umem_flags, UMF_CONTENTS, NULL, 215*7c478bd9Sstevel@tonic-gate &umem_content_log_size, &umem_log_process 216*7c478bd9Sstevel@tonic-gate }, 217*7c478bd9Sstevel@tonic-gate { "fail", "Unstable", ITEM_SPECIAL, 218*7c478bd9Sstevel@tonic-gate "Records are entered into this log for every failed " 219*7c478bd9Sstevel@tonic-gate "allocation.", 220*7c478bd9Sstevel@tonic-gate NULL, 0, NULL, 221*7c478bd9Sstevel@tonic-gate &umem_failure_log_size, &umem_log_process 222*7c478bd9Sstevel@tonic-gate }, 223*7c478bd9Sstevel@tonic-gate 224*7c478bd9Sstevel@tonic-gate { "slab", "Private", ITEM_SPECIAL, 225*7c478bd9Sstevel@tonic-gate "Every slab created will be entered into this log.", 226*7c478bd9Sstevel@tonic-gate NULL, 0, NULL, 227*7c478bd9Sstevel@tonic-gate &umem_slab_log_size, &umem_log_process 228*7c478bd9Sstevel@tonic-gate }, 229*7c478bd9Sstevel@tonic-gate 230*7c478bd9Sstevel@tonic-gate { NULL, "-- end of UMEM_LOGGING --", ITEM_INVALID } 231*7c478bd9Sstevel@tonic-gate }; 232*7c478bd9Sstevel@tonic-gate 233*7c478bd9Sstevel@tonic-gate typedef struct umem_envvar { 234*7c478bd9Sstevel@tonic-gate const char *env_name; 235*7c478bd9Sstevel@tonic-gate const char *env_func; 236*7c478bd9Sstevel@tonic-gate umem_env_item_t *env_item_list; 237*7c478bd9Sstevel@tonic-gate const char *env_getenv_result; 238*7c478bd9Sstevel@tonic-gate const char *env_func_result; 239*7c478bd9Sstevel@tonic-gate } umem_envvar_t; 240*7c478bd9Sstevel@tonic-gate 241*7c478bd9Sstevel@tonic-gate static umem_envvar_t umem_envvars[] = { 242*7c478bd9Sstevel@tonic-gate { "UMEM_DEBUG", "_umem_debug_init", umem_debug_items }, 243*7c478bd9Sstevel@tonic-gate { "UMEM_OPTIONS", "_umem_options_init", umem_options_items }, 244*7c478bd9Sstevel@tonic-gate { "UMEM_LOGGING", "_umem_logging_init", umem_logging_items }, 245*7c478bd9Sstevel@tonic-gate { NULL, NULL, NULL } 246*7c478bd9Sstevel@tonic-gate }; 247*7c478bd9Sstevel@tonic-gate 248*7c478bd9Sstevel@tonic-gate static umem_envvar_t *env_current; 249*7c478bd9Sstevel@tonic-gate #define CURRENT (env_current->env_name) 250*7c478bd9Sstevel@tonic-gate 251*7c478bd9Sstevel@tonic-gate static int 252*7c478bd9Sstevel@tonic-gate empty(const char *str) 253*7c478bd9Sstevel@tonic-gate { 254*7c478bd9Sstevel@tonic-gate char c; 255*7c478bd9Sstevel@tonic-gate 256*7c478bd9Sstevel@tonic-gate while ((c = *str) != '\0' && isspace(c)) 257*7c478bd9Sstevel@tonic-gate str++; 258*7c478bd9Sstevel@tonic-gate 259*7c478bd9Sstevel@tonic-gate return (*str == '\0'); 260*7c478bd9Sstevel@tonic-gate } 261*7c478bd9Sstevel@tonic-gate 262*7c478bd9Sstevel@tonic-gate static int 263*7c478bd9Sstevel@tonic-gate item_uint_process(const umem_env_item_t *item, const char *item_arg) 264*7c478bd9Sstevel@tonic-gate { 265*7c478bd9Sstevel@tonic-gate ulong_t result; 266*7c478bd9Sstevel@tonic-gate char *endptr = ""; 267*7c478bd9Sstevel@tonic-gate int olderrno; 268*7c478bd9Sstevel@tonic-gate 269*7c478bd9Sstevel@tonic-gate olderrno = errno; 270*7c478bd9Sstevel@tonic-gate errno = 0; 271*7c478bd9Sstevel@tonic-gate 272*7c478bd9Sstevel@tonic-gate if (empty(item_arg)) { 273*7c478bd9Sstevel@tonic-gate goto badnumber; 274*7c478bd9Sstevel@tonic-gate } 275*7c478bd9Sstevel@tonic-gate 276*7c478bd9Sstevel@tonic-gate result = strtoul(item_arg, &endptr, 10); 277*7c478bd9Sstevel@tonic-gate 278*7c478bd9Sstevel@tonic-gate if (result == ULONG_MAX && errno == ERANGE) { 279*7c478bd9Sstevel@tonic-gate errno = olderrno; 280*7c478bd9Sstevel@tonic-gate goto overflow; 281*7c478bd9Sstevel@tonic-gate } 282*7c478bd9Sstevel@tonic-gate errno = olderrno; 283*7c478bd9Sstevel@tonic-gate 284*7c478bd9Sstevel@tonic-gate if (*endptr != '\0') 285*7c478bd9Sstevel@tonic-gate goto badnumber; 286*7c478bd9Sstevel@tonic-gate if ((uint_t)result != result) 287*7c478bd9Sstevel@tonic-gate goto overflow; 288*7c478bd9Sstevel@tonic-gate 289*7c478bd9Sstevel@tonic-gate (*item->item_uint_target) = (uint_t)result; 290*7c478bd9Sstevel@tonic-gate return (ARG_SUCCESS); 291*7c478bd9Sstevel@tonic-gate 292*7c478bd9Sstevel@tonic-gate badnumber: 293*7c478bd9Sstevel@tonic-gate log_message("%s: %s: not a number\n", CURRENT, item->item_name); 294*7c478bd9Sstevel@tonic-gate return (ARG_BAD); 295*7c478bd9Sstevel@tonic-gate 296*7c478bd9Sstevel@tonic-gate overflow: 297*7c478bd9Sstevel@tonic-gate log_message("%s: %s: overflowed\n", CURRENT, item->item_name); 298*7c478bd9Sstevel@tonic-gate return (ARG_BAD); 299*7c478bd9Sstevel@tonic-gate } 300*7c478bd9Sstevel@tonic-gate 301*7c478bd9Sstevel@tonic-gate static int 302*7c478bd9Sstevel@tonic-gate item_size_process(const umem_env_item_t *item, const char *item_arg) 303*7c478bd9Sstevel@tonic-gate { 304*7c478bd9Sstevel@tonic-gate ulong_t result; 305*7c478bd9Sstevel@tonic-gate ulong_t result_arg; 306*7c478bd9Sstevel@tonic-gate char *endptr = ""; 307*7c478bd9Sstevel@tonic-gate int olderrno; 308*7c478bd9Sstevel@tonic-gate 309*7c478bd9Sstevel@tonic-gate if (empty(item_arg)) 310*7c478bd9Sstevel@tonic-gate goto badnumber; 311*7c478bd9Sstevel@tonic-gate 312*7c478bd9Sstevel@tonic-gate olderrno = errno; 313*7c478bd9Sstevel@tonic-gate errno = 0; 314*7c478bd9Sstevel@tonic-gate 315*7c478bd9Sstevel@tonic-gate result_arg = strtoul(item_arg, &endptr, 10); 316*7c478bd9Sstevel@tonic-gate 317*7c478bd9Sstevel@tonic-gate if (result_arg == ULONG_MAX && errno == ERANGE) { 318*7c478bd9Sstevel@tonic-gate errno = olderrno; 319*7c478bd9Sstevel@tonic-gate goto overflow; 320*7c478bd9Sstevel@tonic-gate } 321*7c478bd9Sstevel@tonic-gate errno = olderrno; 322*7c478bd9Sstevel@tonic-gate 323*7c478bd9Sstevel@tonic-gate result = result_arg; 324*7c478bd9Sstevel@tonic-gate 325*7c478bd9Sstevel@tonic-gate switch (*endptr) { 326*7c478bd9Sstevel@tonic-gate case 't': 327*7c478bd9Sstevel@tonic-gate case 'T': 328*7c478bd9Sstevel@tonic-gate result *= 1024; 329*7c478bd9Sstevel@tonic-gate if (result < result_arg) 330*7c478bd9Sstevel@tonic-gate goto overflow; 331*7c478bd9Sstevel@tonic-gate /*FALLTHRU*/ 332*7c478bd9Sstevel@tonic-gate case 'g': 333*7c478bd9Sstevel@tonic-gate case 'G': 334*7c478bd9Sstevel@tonic-gate result *= 1024; 335*7c478bd9Sstevel@tonic-gate if (result < result_arg) 336*7c478bd9Sstevel@tonic-gate goto overflow; 337*7c478bd9Sstevel@tonic-gate /*FALLTHRU*/ 338*7c478bd9Sstevel@tonic-gate case 'm': 339*7c478bd9Sstevel@tonic-gate case 'M': 340*7c478bd9Sstevel@tonic-gate result *= 1024; 341*7c478bd9Sstevel@tonic-gate if (result < result_arg) 342*7c478bd9Sstevel@tonic-gate goto overflow; 343*7c478bd9Sstevel@tonic-gate /*FALLTHRU*/ 344*7c478bd9Sstevel@tonic-gate case 'k': 345*7c478bd9Sstevel@tonic-gate case 'K': 346*7c478bd9Sstevel@tonic-gate result *= 1024; 347*7c478bd9Sstevel@tonic-gate if (result < result_arg) 348*7c478bd9Sstevel@tonic-gate goto overflow; 349*7c478bd9Sstevel@tonic-gate endptr++; /* skip over the size character */ 350*7c478bd9Sstevel@tonic-gate break; 351*7c478bd9Sstevel@tonic-gate default: 352*7c478bd9Sstevel@tonic-gate break; /* handled later */ 353*7c478bd9Sstevel@tonic-gate } 354*7c478bd9Sstevel@tonic-gate 355*7c478bd9Sstevel@tonic-gate if (*endptr != '\0') 356*7c478bd9Sstevel@tonic-gate goto badnumber; 357*7c478bd9Sstevel@tonic-gate 358*7c478bd9Sstevel@tonic-gate (*item->item_size_target) = result; 359*7c478bd9Sstevel@tonic-gate return (ARG_SUCCESS); 360*7c478bd9Sstevel@tonic-gate 361*7c478bd9Sstevel@tonic-gate badnumber: 362*7c478bd9Sstevel@tonic-gate log_message("%s: %s: not a number\n", CURRENT, item->item_name); 363*7c478bd9Sstevel@tonic-gate return (ARG_BAD); 364*7c478bd9Sstevel@tonic-gate 365*7c478bd9Sstevel@tonic-gate overflow: 366*7c478bd9Sstevel@tonic-gate log_message("%s: %s: overflowed\n", CURRENT, item->item_name); 367*7c478bd9Sstevel@tonic-gate return (ARG_BAD); 368*7c478bd9Sstevel@tonic-gate } 369*7c478bd9Sstevel@tonic-gate 370*7c478bd9Sstevel@tonic-gate static int 371*7c478bd9Sstevel@tonic-gate umem_log_process(const umem_env_item_t *item, const char *item_arg) 372*7c478bd9Sstevel@tonic-gate { 373*7c478bd9Sstevel@tonic-gate if (item_arg != NULL) { 374*7c478bd9Sstevel@tonic-gate int ret; 375*7c478bd9Sstevel@tonic-gate ret = item_size_process(item, item_arg); 376*7c478bd9Sstevel@tonic-gate if (ret != ARG_SUCCESS) 377*7c478bd9Sstevel@tonic-gate return (ret); 378*7c478bd9Sstevel@tonic-gate 379*7c478bd9Sstevel@tonic-gate if (*item->item_size_target == 0) 380*7c478bd9Sstevel@tonic-gate return (ARG_SUCCESS); 381*7c478bd9Sstevel@tonic-gate } else 382*7c478bd9Sstevel@tonic-gate *item->item_size_target = 64*1024; 383*7c478bd9Sstevel@tonic-gate 384*7c478bd9Sstevel@tonic-gate umem_logging = 1; 385*7c478bd9Sstevel@tonic-gate return (ARG_SUCCESS); 386*7c478bd9Sstevel@tonic-gate } 387*7c478bd9Sstevel@tonic-gate 388*7c478bd9Sstevel@tonic-gate #ifndef UMEM_STANDALONE 389*7c478bd9Sstevel@tonic-gate static int 390*7c478bd9Sstevel@tonic-gate umem_backend_process(const umem_env_item_t *item, const char *item_arg) 391*7c478bd9Sstevel@tonic-gate { 392*7c478bd9Sstevel@tonic-gate const char *name = item->item_name; 393*7c478bd9Sstevel@tonic-gate 394*7c478bd9Sstevel@tonic-gate if (item_arg == NULL) 395*7c478bd9Sstevel@tonic-gate goto fail; 396*7c478bd9Sstevel@tonic-gate 397*7c478bd9Sstevel@tonic-gate if (strcmp(item_arg, "sbrk") == 0) 398*7c478bd9Sstevel@tonic-gate vmem_backend |= VMEM_BACKEND_SBRK; 399*7c478bd9Sstevel@tonic-gate else if (strcmp(item_arg, "mmap") == 0) 400*7c478bd9Sstevel@tonic-gate vmem_backend |= VMEM_BACKEND_MMAP; 401*7c478bd9Sstevel@tonic-gate else 402*7c478bd9Sstevel@tonic-gate goto fail; 403*7c478bd9Sstevel@tonic-gate 404*7c478bd9Sstevel@tonic-gate return (ARG_SUCCESS); 405*7c478bd9Sstevel@tonic-gate 406*7c478bd9Sstevel@tonic-gate fail: 407*7c478bd9Sstevel@tonic-gate log_message("%s: %s: must be %s=sbrk or %s=mmap\n", 408*7c478bd9Sstevel@tonic-gate CURRENT, name, name, name); 409*7c478bd9Sstevel@tonic-gate return (ARG_BAD); 410*7c478bd9Sstevel@tonic-gate } 411*7c478bd9Sstevel@tonic-gate #endif 412*7c478bd9Sstevel@tonic-gate 413*7c478bd9Sstevel@tonic-gate static int 414*7c478bd9Sstevel@tonic-gate process_item(const umem_env_item_t *item, const char *item_arg) 415*7c478bd9Sstevel@tonic-gate { 416*7c478bd9Sstevel@tonic-gate int arg_required = 0; 417*7c478bd9Sstevel@tonic-gate arg_process_t *processor; 418*7c478bd9Sstevel@tonic-gate 419*7c478bd9Sstevel@tonic-gate switch (item->item_type) { 420*7c478bd9Sstevel@tonic-gate case ITEM_FLAG: 421*7c478bd9Sstevel@tonic-gate case ITEM_CLEARFLAG: 422*7c478bd9Sstevel@tonic-gate case ITEM_OPTUINT: 423*7c478bd9Sstevel@tonic-gate case ITEM_OPTSIZE: 424*7c478bd9Sstevel@tonic-gate case ITEM_SPECIAL: 425*7c478bd9Sstevel@tonic-gate arg_required = 0; 426*7c478bd9Sstevel@tonic-gate break; 427*7c478bd9Sstevel@tonic-gate 428*7c478bd9Sstevel@tonic-gate case ITEM_UINT: 429*7c478bd9Sstevel@tonic-gate case ITEM_SIZE: 430*7c478bd9Sstevel@tonic-gate arg_required = 1; 431*7c478bd9Sstevel@tonic-gate break; 432*7c478bd9Sstevel@tonic-gate } 433*7c478bd9Sstevel@tonic-gate 434*7c478bd9Sstevel@tonic-gate switch (item->item_type) { 435*7c478bd9Sstevel@tonic-gate case ITEM_FLAG: 436*7c478bd9Sstevel@tonic-gate case ITEM_CLEARFLAG: 437*7c478bd9Sstevel@tonic-gate if (item_arg != NULL) { 438*7c478bd9Sstevel@tonic-gate log_message("%s: %s: does not take a value. ignored\n", 439*7c478bd9Sstevel@tonic-gate CURRENT, item->item_name); 440*7c478bd9Sstevel@tonic-gate return (1); 441*7c478bd9Sstevel@tonic-gate } 442*7c478bd9Sstevel@tonic-gate processor = NULL; 443*7c478bd9Sstevel@tonic-gate break; 444*7c478bd9Sstevel@tonic-gate 445*7c478bd9Sstevel@tonic-gate case ITEM_UINT: 446*7c478bd9Sstevel@tonic-gate case ITEM_OPTUINT: 447*7c478bd9Sstevel@tonic-gate processor = item_uint_process; 448*7c478bd9Sstevel@tonic-gate break; 449*7c478bd9Sstevel@tonic-gate 450*7c478bd9Sstevel@tonic-gate case ITEM_SIZE: 451*7c478bd9Sstevel@tonic-gate case ITEM_OPTSIZE: 452*7c478bd9Sstevel@tonic-gate processor = item_size_process; 453*7c478bd9Sstevel@tonic-gate break; 454*7c478bd9Sstevel@tonic-gate 455*7c478bd9Sstevel@tonic-gate case ITEM_SPECIAL: 456*7c478bd9Sstevel@tonic-gate processor = item->item_special; 457*7c478bd9Sstevel@tonic-gate break; 458*7c478bd9Sstevel@tonic-gate 459*7c478bd9Sstevel@tonic-gate default: 460*7c478bd9Sstevel@tonic-gate log_message("%s: %s: Invalid type. Ignored\n", 461*7c478bd9Sstevel@tonic-gate CURRENT, item->item_name); 462*7c478bd9Sstevel@tonic-gate return (1); 463*7c478bd9Sstevel@tonic-gate } 464*7c478bd9Sstevel@tonic-gate 465*7c478bd9Sstevel@tonic-gate if (arg_required && item_arg == NULL) { 466*7c478bd9Sstevel@tonic-gate log_message("%s: %s: Required value missing\n", 467*7c478bd9Sstevel@tonic-gate CURRENT, item->item_name); 468*7c478bd9Sstevel@tonic-gate goto invalid; 469*7c478bd9Sstevel@tonic-gate } 470*7c478bd9Sstevel@tonic-gate 471*7c478bd9Sstevel@tonic-gate if (item_arg != NULL || item->item_type == ITEM_SPECIAL) { 472*7c478bd9Sstevel@tonic-gate if (processor(item, item_arg) != ARG_SUCCESS) 473*7c478bd9Sstevel@tonic-gate goto invalid; 474*7c478bd9Sstevel@tonic-gate } 475*7c478bd9Sstevel@tonic-gate 476*7c478bd9Sstevel@tonic-gate if (item->item_flag_target) { 477*7c478bd9Sstevel@tonic-gate if (item->item_type == ITEM_CLEARFLAG) 478*7c478bd9Sstevel@tonic-gate (*item->item_flag_target) &= ~item->item_flag_value; 479*7c478bd9Sstevel@tonic-gate else 480*7c478bd9Sstevel@tonic-gate (*item->item_flag_target) |= item->item_flag_value; 481*7c478bd9Sstevel@tonic-gate } 482*7c478bd9Sstevel@tonic-gate return (0); 483*7c478bd9Sstevel@tonic-gate 484*7c478bd9Sstevel@tonic-gate invalid: 485*7c478bd9Sstevel@tonic-gate return (1); 486*7c478bd9Sstevel@tonic-gate } 487*7c478bd9Sstevel@tonic-gate 488*7c478bd9Sstevel@tonic-gate #define ENV_SHORT_BYTES 10 /* bytes to print on error */ 489*7c478bd9Sstevel@tonic-gate void 490*7c478bd9Sstevel@tonic-gate umem_process_value(umem_env_item_t *item_list, const char *beg, const char *end) 491*7c478bd9Sstevel@tonic-gate { 492*7c478bd9Sstevel@tonic-gate char buf[UMEM_ENV_ITEM_MAX]; 493*7c478bd9Sstevel@tonic-gate char *argptr; 494*7c478bd9Sstevel@tonic-gate 495*7c478bd9Sstevel@tonic-gate size_t count; 496*7c478bd9Sstevel@tonic-gate 497*7c478bd9Sstevel@tonic-gate while (beg < end && isspace(*beg)) 498*7c478bd9Sstevel@tonic-gate beg++; 499*7c478bd9Sstevel@tonic-gate 500*7c478bd9Sstevel@tonic-gate while (beg < end && isspace(*(end - 1))) 501*7c478bd9Sstevel@tonic-gate end--; 502*7c478bd9Sstevel@tonic-gate 503*7c478bd9Sstevel@tonic-gate if (beg >= end) { 504*7c478bd9Sstevel@tonic-gate log_message("%s: empty option\n", CURRENT); 505*7c478bd9Sstevel@tonic-gate return; 506*7c478bd9Sstevel@tonic-gate } 507*7c478bd9Sstevel@tonic-gate 508*7c478bd9Sstevel@tonic-gate count = end - beg; 509*7c478bd9Sstevel@tonic-gate 510*7c478bd9Sstevel@tonic-gate if (count + 1 > sizeof (buf)) { 511*7c478bd9Sstevel@tonic-gate char outbuf[ENV_SHORT_BYTES + 1]; 512*7c478bd9Sstevel@tonic-gate /* 513*7c478bd9Sstevel@tonic-gate * Have to do this, since sprintf("%10s",...) calls malloc() 514*7c478bd9Sstevel@tonic-gate */ 515*7c478bd9Sstevel@tonic-gate (void) strncpy(outbuf, beg, ENV_SHORT_BYTES); 516*7c478bd9Sstevel@tonic-gate outbuf[ENV_SHORT_BYTES] = 0; 517*7c478bd9Sstevel@tonic-gate 518*7c478bd9Sstevel@tonic-gate log_message("%s: argument \"%s...\" too long\n", CURRENT, 519*7c478bd9Sstevel@tonic-gate outbuf); 520*7c478bd9Sstevel@tonic-gate return; 521*7c478bd9Sstevel@tonic-gate } 522*7c478bd9Sstevel@tonic-gate 523*7c478bd9Sstevel@tonic-gate (void) strncpy(buf, beg, count); 524*7c478bd9Sstevel@tonic-gate buf[count] = 0; 525*7c478bd9Sstevel@tonic-gate 526*7c478bd9Sstevel@tonic-gate argptr = strchr(buf, '='); 527*7c478bd9Sstevel@tonic-gate 528*7c478bd9Sstevel@tonic-gate if (argptr != NULL) 529*7c478bd9Sstevel@tonic-gate *argptr++ = 0; 530*7c478bd9Sstevel@tonic-gate 531*7c478bd9Sstevel@tonic-gate for (; item_list->item_name != NULL; item_list++) { 532*7c478bd9Sstevel@tonic-gate if (strcmp(buf, item_list->item_name) == 0) { 533*7c478bd9Sstevel@tonic-gate (void) process_item(item_list, argptr); 534*7c478bd9Sstevel@tonic-gate return; 535*7c478bd9Sstevel@tonic-gate } 536*7c478bd9Sstevel@tonic-gate } 537*7c478bd9Sstevel@tonic-gate log_message("%s: '%s' not recognized\n", CURRENT, buf); 538*7c478bd9Sstevel@tonic-gate } 539*7c478bd9Sstevel@tonic-gate 540*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 541*7c478bd9Sstevel@tonic-gate void 542*7c478bd9Sstevel@tonic-gate umem_setup_envvars(int invalid) 543*7c478bd9Sstevel@tonic-gate { 544*7c478bd9Sstevel@tonic-gate umem_envvar_t *cur_env; 545*7c478bd9Sstevel@tonic-gate static volatile enum { 546*7c478bd9Sstevel@tonic-gate STATE_START, 547*7c478bd9Sstevel@tonic-gate STATE_GETENV, 548*7c478bd9Sstevel@tonic-gate STATE_DLSYM, 549*7c478bd9Sstevel@tonic-gate STATE_FUNC, 550*7c478bd9Sstevel@tonic-gate STATE_DONE 551*7c478bd9Sstevel@tonic-gate } state = STATE_START; 552*7c478bd9Sstevel@tonic-gate #ifndef UMEM_STANDALONE 553*7c478bd9Sstevel@tonic-gate void *h; 554*7c478bd9Sstevel@tonic-gate #endif 555*7c478bd9Sstevel@tonic-gate 556*7c478bd9Sstevel@tonic-gate if (invalid) { 557*7c478bd9Sstevel@tonic-gate const char *where; 558*7c478bd9Sstevel@tonic-gate /* 559*7c478bd9Sstevel@tonic-gate * One of the calls below invoked malloc() recursively. We 560*7c478bd9Sstevel@tonic-gate * remove any partial results and return. 561*7c478bd9Sstevel@tonic-gate */ 562*7c478bd9Sstevel@tonic-gate 563*7c478bd9Sstevel@tonic-gate switch (state) { 564*7c478bd9Sstevel@tonic-gate case STATE_START: 565*7c478bd9Sstevel@tonic-gate where = "before getenv(3C) calls -- " 566*7c478bd9Sstevel@tonic-gate "getenv(3C) results ignored."; 567*7c478bd9Sstevel@tonic-gate break; 568*7c478bd9Sstevel@tonic-gate case STATE_GETENV: 569*7c478bd9Sstevel@tonic-gate where = "during getenv(3C) calls -- " 570*7c478bd9Sstevel@tonic-gate "getenv(3C) results ignored."; 571*7c478bd9Sstevel@tonic-gate break; 572*7c478bd9Sstevel@tonic-gate case STATE_DLSYM: 573*7c478bd9Sstevel@tonic-gate where = "during dlsym(3C) call -- " 574*7c478bd9Sstevel@tonic-gate "_umem_*() results ignored."; 575*7c478bd9Sstevel@tonic-gate break; 576*7c478bd9Sstevel@tonic-gate case STATE_FUNC: 577*7c478bd9Sstevel@tonic-gate where = "during _umem_*() call -- " 578*7c478bd9Sstevel@tonic-gate "_umem_*() results ignored."; 579*7c478bd9Sstevel@tonic-gate break; 580*7c478bd9Sstevel@tonic-gate case STATE_DONE: 581*7c478bd9Sstevel@tonic-gate where = "after dlsym() or _umem_*() calls."; 582*7c478bd9Sstevel@tonic-gate break; 583*7c478bd9Sstevel@tonic-gate default: 584*7c478bd9Sstevel@tonic-gate where = "at unknown point -- " 585*7c478bd9Sstevel@tonic-gate "_umem_*() results ignored."; 586*7c478bd9Sstevel@tonic-gate break; 587*7c478bd9Sstevel@tonic-gate } 588*7c478bd9Sstevel@tonic-gate 589*7c478bd9Sstevel@tonic-gate log_message("recursive allocation %s\n", where); 590*7c478bd9Sstevel@tonic-gate 591*7c478bd9Sstevel@tonic-gate for (cur_env = umem_envvars; cur_env->env_name != NULL; 592*7c478bd9Sstevel@tonic-gate cur_env++) { 593*7c478bd9Sstevel@tonic-gate if (state == STATE_GETENV) 594*7c478bd9Sstevel@tonic-gate cur_env->env_getenv_result = NULL; 595*7c478bd9Sstevel@tonic-gate if (state != STATE_DONE) 596*7c478bd9Sstevel@tonic-gate cur_env->env_func_result = NULL; 597*7c478bd9Sstevel@tonic-gate } 598*7c478bd9Sstevel@tonic-gate 599*7c478bd9Sstevel@tonic-gate state = STATE_DONE; 600*7c478bd9Sstevel@tonic-gate return; 601*7c478bd9Sstevel@tonic-gate } 602*7c478bd9Sstevel@tonic-gate 603*7c478bd9Sstevel@tonic-gate state = STATE_GETENV; 604*7c478bd9Sstevel@tonic-gate 605*7c478bd9Sstevel@tonic-gate for (cur_env = umem_envvars; cur_env->env_name != NULL; cur_env++) { 606*7c478bd9Sstevel@tonic-gate cur_env->env_getenv_result = getenv(cur_env->env_name); 607*7c478bd9Sstevel@tonic-gate if (state == STATE_DONE) 608*7c478bd9Sstevel@tonic-gate return; /* recursed */ 609*7c478bd9Sstevel@tonic-gate } 610*7c478bd9Sstevel@tonic-gate 611*7c478bd9Sstevel@tonic-gate #ifndef UMEM_STANDALONE 612*7c478bd9Sstevel@tonic-gate /* get a handle to the "a.out" object */ 613*7c478bd9Sstevel@tonic-gate if ((h = dlopen(0, RTLD_FIRST | RTLD_LAZY)) != NULL) { 614*7c478bd9Sstevel@tonic-gate for (cur_env = umem_envvars; cur_env->env_name != NULL; 615*7c478bd9Sstevel@tonic-gate cur_env++) { 616*7c478bd9Sstevel@tonic-gate const char *(*func)(void); 617*7c478bd9Sstevel@tonic-gate const char *value; 618*7c478bd9Sstevel@tonic-gate 619*7c478bd9Sstevel@tonic-gate state = STATE_DLSYM; 620*7c478bd9Sstevel@tonic-gate func = (const char *(*)(void))dlsym(h, 621*7c478bd9Sstevel@tonic-gate cur_env->env_func); 622*7c478bd9Sstevel@tonic-gate 623*7c478bd9Sstevel@tonic-gate if (state == STATE_DONE) 624*7c478bd9Sstevel@tonic-gate break; /* recursed */ 625*7c478bd9Sstevel@tonic-gate 626*7c478bd9Sstevel@tonic-gate state = STATE_FUNC; 627*7c478bd9Sstevel@tonic-gate if (func != NULL) { 628*7c478bd9Sstevel@tonic-gate value = func(); 629*7c478bd9Sstevel@tonic-gate if (state == STATE_DONE) 630*7c478bd9Sstevel@tonic-gate break; /* recursed */ 631*7c478bd9Sstevel@tonic-gate cur_env->env_func_result = value; 632*7c478bd9Sstevel@tonic-gate } 633*7c478bd9Sstevel@tonic-gate } 634*7c478bd9Sstevel@tonic-gate (void) dlclose(h); 635*7c478bd9Sstevel@tonic-gate } else { 636*7c478bd9Sstevel@tonic-gate (void) dlerror(); /* snarf dlerror() */ 637*7c478bd9Sstevel@tonic-gate } 638*7c478bd9Sstevel@tonic-gate #endif /* UMEM_STANDALONE */ 639*7c478bd9Sstevel@tonic-gate 640*7c478bd9Sstevel@tonic-gate state = STATE_DONE; 641*7c478bd9Sstevel@tonic-gate } 642*7c478bd9Sstevel@tonic-gate 643*7c478bd9Sstevel@tonic-gate /* 644*7c478bd9Sstevel@tonic-gate * Process the environment variables. 645*7c478bd9Sstevel@tonic-gate */ 646*7c478bd9Sstevel@tonic-gate void 647*7c478bd9Sstevel@tonic-gate umem_process_envvars(void) 648*7c478bd9Sstevel@tonic-gate { 649*7c478bd9Sstevel@tonic-gate const char *value; 650*7c478bd9Sstevel@tonic-gate const char *end, *next; 651*7c478bd9Sstevel@tonic-gate umem_envvar_t *cur_env; 652*7c478bd9Sstevel@tonic-gate 653*7c478bd9Sstevel@tonic-gate for (cur_env = umem_envvars; cur_env->env_name != NULL; cur_env++) { 654*7c478bd9Sstevel@tonic-gate env_current = cur_env; 655*7c478bd9Sstevel@tonic-gate 656*7c478bd9Sstevel@tonic-gate value = cur_env->env_getenv_result; 657*7c478bd9Sstevel@tonic-gate if (value == NULL) 658*7c478bd9Sstevel@tonic-gate value = cur_env->env_func_result; 659*7c478bd9Sstevel@tonic-gate 660*7c478bd9Sstevel@tonic-gate /* ignore if missing or empty */ 661*7c478bd9Sstevel@tonic-gate if (value == NULL) 662*7c478bd9Sstevel@tonic-gate continue; 663*7c478bd9Sstevel@tonic-gate 664*7c478bd9Sstevel@tonic-gate for (end = value; *end != '\0'; value = next) { 665*7c478bd9Sstevel@tonic-gate end = strchr(value, ','); 666*7c478bd9Sstevel@tonic-gate if (end != NULL) 667*7c478bd9Sstevel@tonic-gate next = end + 1; /* skip the comma */ 668*7c478bd9Sstevel@tonic-gate else 669*7c478bd9Sstevel@tonic-gate next = end = value + strlen(value); 670*7c478bd9Sstevel@tonic-gate 671*7c478bd9Sstevel@tonic-gate umem_process_value(cur_env->env_item_list, value, end); 672*7c478bd9Sstevel@tonic-gate } 673*7c478bd9Sstevel@tonic-gate } 674*7c478bd9Sstevel@tonic-gate } 675