15184Sek110237 /*
25184Sek110237  * CDDL HEADER START
35184Sek110237  *
45184Sek110237  * The contents of this file are subject to the terms of the
55184Sek110237  * Common Development and Distribution License (the "License").
65184Sek110237  * You may not use this file except in compliance with the License.
75184Sek110237  *
85184Sek110237  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95184Sek110237  * or http://www.opensolaris.org/os/licensing.
105184Sek110237  * See the License for the specific language governing permissions
115184Sek110237  * and limitations under the License.
125184Sek110237  *
135184Sek110237  * When distributing Covered Code, include this CDDL HEADER in each
145184Sek110237  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155184Sek110237  * If applicable, add the following below this CDDL HEADER, with the
165184Sek110237  * fields enclosed by brackets "[]" replaced with your own identifying
175184Sek110237  * information: Portions Copyright [yyyy] [name of copyright owner]
185184Sek110237  *
195184Sek110237  * CDDL HEADER END
205184Sek110237  */
215184Sek110237 /*
226212Saw148015  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
235184Sek110237  * Use is subject to license terms.
245184Sek110237  */
255184Sek110237 
265184Sek110237 #pragma ident	"%Z%%M%	%I%	%E% SMI"
275184Sek110237 
285184Sek110237 #include <stdlib.h>
295184Sek110237 #include <stdio.h>
305184Sek110237 #include <string.h>
315184Sek110237 #include <errno.h>
325184Sek110237 
335184Sek110237 #include "vars.h"
345184Sek110237 #include "misc.h"
355184Sek110237 #include "utils.h"
365184Sek110237 #include "stats.h"
375184Sek110237 #include "eventgen.h"
385184Sek110237 #include "filebench.h"
396212Saw148015 #include "fb_random.h"
405184Sek110237 
415184Sek110237 static var_t *var_find_dynamic(char *name);
425184Sek110237 
435184Sek110237 /*
446212Saw148015  * The filebench variables system has attribute value descriptors (avd_t)
456212Saw148015  * where an avd contains a boolean, integer, double, string, random
466212Saw148015  * distribution object ptr, boolean ptr, integer ptr, double ptr,
476212Saw148015  * string ptr, or variable ptr. The system also has the variables
486212Saw148015  * themselves, (var_t), which are named, typed entities which can be
496212Saw148015  * allocated, selected and changed using the "set" command and used in
506212Saw148015  * attribute assignments. The variables contain either a boolean, an
516212Saw148015  * integer, a double, a string or pointer to an associated random
526212Saw148015  * distribution object. Both avd_t and var_t entities are allocated
535184Sek110237  * from interprocess shared memory space.
545184Sek110237  *
556212Saw148015  * The attribute descriptors implement delayed binding to variable values,
566212Saw148015  * which is necessary because the values of variables may be changed
576212Saw148015  * between the time the workload file is loaded and it is actually run,
586212Saw148015  * either by further "set" commands in the file or from the command line
596212Saw148015  * interface. For random variables, they actually point to the random
606212Saw148015  * distribution object, allowing FileBench to invoke the appropriate
616212Saw148015  * random distribution function on each access to the attribute. However,
626212Saw148015  * for static attributes, the value is just loaded in the descriptor
636212Saw148015  * directly, avoiding the need to allocate a variable to hold the static
646212Saw148015  * value.
656212Saw148015  *
665184Sek110237  * The routines in this module are used to allocate, locate, and
676212Saw148015  * manipulate the attribute descriptors, and vars. Routines are
686212Saw148015  * also included to convert between the component strings, doubles
696212Saw148015  * and integers of vars, and said components of avd_t.
705184Sek110237  */
715184Sek110237 
725184Sek110237 /*
736212Saw148015  * returns a pointer to a string indicating the type of data contained
746212Saw148015  * in the supplied attribute variable descriptor.
755184Sek110237  */
766212Saw148015 static char *
776212Saw148015 avd_get_type_string(avd_t avd)
785184Sek110237 {
796212Saw148015 	switch (avd->avd_type) {
806212Saw148015 	case AVD_INVALID:
816212Saw148015 		return ("uninitialized");
826212Saw148015 
836212Saw148015 	case AVD_VAL_BOOL:
846212Saw148015 		return ("boolean value");
856212Saw148015 
866212Saw148015 	case AVD_VARVAL_BOOL:
876212Saw148015 		return ("points to boolean in var_t");
886212Saw148015 
896212Saw148015 	case AVD_VAL_INT:
906212Saw148015 		return ("integer value");
916212Saw148015 
926212Saw148015 	case AVD_VARVAL_INT:
936212Saw148015 		return ("points to integer in var_t");
946212Saw148015 
956212Saw148015 	case AVD_VAL_STR:
966212Saw148015 		return ("string");
976212Saw148015 
986212Saw148015 	case AVD_VARVAL_STR:
996212Saw148015 		return ("points to string in var_t");
1006212Saw148015 
1016212Saw148015 	case AVD_VAL_DBL:
1026212Saw148015 		return ("double float value");
1036212Saw148015 
1046212Saw148015 	case AVD_VARVAL_DBL:
1056212Saw148015 		return ("points to double float in var_t");
1066212Saw148015 
1076212Saw148015 	case AVD_IND_VAR:
1086212Saw148015 		return ("points to a var_t");
1096212Saw148015 
1106212Saw148015 	case AVD_IND_RANDVAR:
1116212Saw148015 		return ("points to var_t's random distribution object");
1126212Saw148015 
1136212Saw148015 	default:
1146212Saw148015 		return ("illegal avd type");
1156212Saw148015 	}
1166212Saw148015 }
1176212Saw148015 
1186212Saw148015 /*
1196212Saw148015  * returns a pointer to a string indicating the type of data contained
1206212Saw148015  * in the supplied variable.
1216212Saw148015  */
1226212Saw148015 static char *
1236212Saw148015 var_get_type_string(var_t *ivp)
1246212Saw148015 {
1256212Saw148015 	switch (ivp->var_type & VAR_TYPE_SET_MASK) {
1266212Saw148015 	case VAR_TYPE_BOOL_SET:
1276212Saw148015 		return ("boolean");
1286212Saw148015 
1296212Saw148015 	case VAR_TYPE_INT_SET:
1306212Saw148015 		return ("integer");
1316212Saw148015 
1326212Saw148015 	case VAR_TYPE_STR_SET:
1336212Saw148015 		return ("string");
1346212Saw148015 
1356212Saw148015 	case VAR_TYPE_DBL_SET:
1366212Saw148015 		return ("double float");
1376212Saw148015 
1386212Saw148015 	case VAR_TYPE_RAND_SET:
1396212Saw148015 		return ("random");
1406212Saw148015 
1416212Saw148015 	default:
1426212Saw148015 		return ("empty");
1436212Saw148015 	}
1446212Saw148015 }
1456212Saw148015 
1466212Saw148015 /*
1476212Saw148015  * Returns the fbint_t pointed to by the supplied avd_t "avd".
1486212Saw148015  */
1496212Saw148015 fbint_t
1506212Saw148015 avd_get_int(avd_t avd)
1516212Saw148015 {
1526212Saw148015 	var_t *ivp;
1536212Saw148015 	randdist_t *rndp;
1546212Saw148015 
1556212Saw148015 	if (avd == NULL)
1565184Sek110237 		return (0);
1575184Sek110237 
1586212Saw148015 	switch (avd->avd_type) {
1596212Saw148015 	case AVD_VAL_INT:
1606212Saw148015 		return (avd->avd_val.intval);
1616212Saw148015 
1626212Saw148015 	case AVD_VARVAL_INT:
1636212Saw148015 		if (avd->avd_val.intptr)
1646212Saw148015 			return (*(avd->avd_val.intptr));
1656212Saw148015 		else
1666212Saw148015 			return (0);
1676212Saw148015 
1686212Saw148015 	case AVD_IND_VAR:
1696212Saw148015 		if ((ivp = avd->avd_val.varptr) == NULL)
1706212Saw148015 			return (0);
1716212Saw148015 
1726212Saw148015 		if (VAR_HAS_INTEGER(ivp))
1736212Saw148015 			return (ivp->var_val.integer);
1746212Saw148015 
1756212Saw148015 		if (VAR_HAS_RANDDIST(ivp)) {
1766212Saw148015 			if ((rndp = ivp->var_val.randptr) != NULL)
1776212Saw148015 				return ((fbint_t)rndp->rnd_get(rndp));
1786212Saw148015 		}
1796212Saw148015 
1806212Saw148015 		filebench_log(LOG_ERROR,
1816212Saw148015 		    "Attempt to get integer from %s var $%s",
1826212Saw148015 		    var_get_type_string(ivp), ivp->var_name);
1836212Saw148015 		return (0);
1846212Saw148015 
1856212Saw148015 	case AVD_IND_RANDVAR:
1866212Saw148015 		if ((rndp = avd->avd_val.randptr) == NULL)
1876212Saw148015 			return (0);
1886212Saw148015 		else
1896212Saw148015 			return ((fbint_t)rndp->rnd_get(rndp));
1906212Saw148015 
1916212Saw148015 	default:
1926212Saw148015 		filebench_log(LOG_ERROR,
1936212Saw148015 		    "Attempt to get integer from %s avd",
1946212Saw148015 		    avd_get_type_string(avd));
1956212Saw148015 		return (0);
1966212Saw148015 	}
1975184Sek110237 }
1985184Sek110237 
1995184Sek110237 /*
2006212Saw148015  * Returns the floating point value of a variable pointed to by the
2016212Saw148015  * supplied avd_t "avd". Intended to get the actual (double) value
2026212Saw148015  * supplied by the random variable.
2036212Saw148015  */
2046212Saw148015 double
2056212Saw148015 avd_get_dbl(avd_t avd)
2066212Saw148015 {
2076212Saw148015 	var_t *ivp;
2086212Saw148015 	randdist_t *rndp;
2096212Saw148015 
2106212Saw148015 	if (avd == NULL)
2116212Saw148015 		return (0.0);
2126212Saw148015 
2136212Saw148015 	switch (avd->avd_type) {
2146212Saw148015 	case AVD_VAL_INT:
2156212Saw148015 		return ((double)avd->avd_val.intval);
2166212Saw148015 
2176212Saw148015 	case AVD_VAL_DBL:
2186212Saw148015 		return (avd->avd_val.dblval);
2196212Saw148015 
2206212Saw148015 	case AVD_VARVAL_INT:
2216212Saw148015 		if (avd->avd_val.intptr)
2226212Saw148015 			return ((double)(*(avd->avd_val.intptr)));
2236212Saw148015 		else
2246212Saw148015 			return (0.0);
2256212Saw148015 
2266212Saw148015 	case AVD_VARVAL_DBL:
2276212Saw148015 		if (avd->avd_val.dblptr)
2286212Saw148015 			return (*(avd->avd_val.dblptr));
2296212Saw148015 		else
2306212Saw148015 			return (0.0);
2316212Saw148015 
2326212Saw148015 	case AVD_IND_VAR:
2336212Saw148015 		ivp = avd->avd_val.varptr;
2346212Saw148015 
2356212Saw148015 		if (ivp && VAR_HAS_INTEGER(ivp))
2366212Saw148015 			return ((double)ivp->var_val.integer);
2376212Saw148015 
2386212Saw148015 		if (ivp && VAR_HAS_DOUBLE(ivp))
2396212Saw148015 			return (ivp->var_val.dbl_flt);
2406212Saw148015 
2416212Saw148015 		if (ivp && VAR_HAS_RANDDIST(ivp)) {
2426212Saw148015 			if ((rndp = ivp->var_val.randptr) != NULL)
2436212Saw148015 				return (rndp->rnd_get(rndp));
2446212Saw148015 		}
2456212Saw148015 		filebench_log(LOG_ERROR,
2466212Saw148015 		    "Attempt to get double float from %s var $%s",
2476212Saw148015 		    var_get_type_string(ivp), ivp->var_name);
2486212Saw148015 		return (0.0);
2496212Saw148015 
2506212Saw148015 	case AVD_IND_RANDVAR:
2516212Saw148015 		if ((rndp = avd->avd_val.randptr) == NULL) {
2526212Saw148015 			return (0.0);
2536212Saw148015 		} else
2546212Saw148015 			return (rndp->rnd_get(rndp));
2556212Saw148015 
2566212Saw148015 	default:
2576212Saw148015 		filebench_log(LOG_ERROR,
2586212Saw148015 		    "Attempt to get floating point from %s avd",
2596212Saw148015 		    avd_get_type_string(avd));
2606212Saw148015 		return (0.0);
2616212Saw148015 	}
2626212Saw148015 }
2636212Saw148015 
2646212Saw148015 /*
2656212Saw148015  * Returns the boolean pointed to by the supplied avd_t "avd".
2665184Sek110237  */
2676212Saw148015 boolean_t
2686212Saw148015 avd_get_bool(avd_t avd)
2695184Sek110237 {
2706212Saw148015 	var_t *ivp;
2716212Saw148015 
2726212Saw148015 	if (avd == NULL)
2736212Saw148015 		return (0);
2746212Saw148015 
2756212Saw148015 	switch (avd->avd_type) {
2766212Saw148015 	case AVD_VAL_BOOL:
2776212Saw148015 		return (avd->avd_val.boolval);
2786212Saw148015 
2796212Saw148015 	case AVD_VARVAL_BOOL:
2806212Saw148015 		if (avd->avd_val.boolptr)
2816212Saw148015 			return (*(avd->avd_val.boolptr));
2826212Saw148015 		else
2836212Saw148015 			return (FALSE);
2846212Saw148015 
2856212Saw148015 	/* for backwards compatibility with old workloads */
2866212Saw148015 	case AVD_VAL_INT:
2876212Saw148015 		if (avd->avd_val.intval != 0)
2886212Saw148015 			return (TRUE);
2896212Saw148015 		else
2906212Saw148015 			return (FALSE);
2916212Saw148015 
2926212Saw148015 	case AVD_VARVAL_INT:
2936212Saw148015 		if (avd->avd_val.intptr)
2946212Saw148015 			if (*(avd->avd_val.intptr) != 0)
2956212Saw148015 				return (TRUE);
2966212Saw148015 
2976212Saw148015 		return (FALSE);
2986212Saw148015 
2996212Saw148015 	case AVD_IND_VAR:
3006212Saw148015 		if ((ivp = avd->avd_val.varptr) == NULL)
3016212Saw148015 			return (0);
3026212Saw148015 
3036212Saw148015 		if (VAR_HAS_BOOLEAN(ivp))
3046212Saw148015 			return (ivp->var_val.boolean);
3056212Saw148015 
3066212Saw148015 		if (VAR_HAS_INTEGER(ivp)) {
3076212Saw148015 			if (ivp->var_val.boolean)
3086212Saw148015 				return (TRUE);
3096212Saw148015 			else
3106212Saw148015 				return (FALSE);
3116212Saw148015 		}
3125184Sek110237 
3136212Saw148015 		filebench_log(LOG_ERROR,
3146212Saw148015 		    "Attempt to get boolean from %s var $%s",
3156212Saw148015 		    var_get_type_string(ivp), ivp->var_name);
3166212Saw148015 		return (FALSE);
3176212Saw148015 
3186212Saw148015 	default:
3196212Saw148015 		filebench_log(LOG_ERROR,
3206212Saw148015 		    "Attempt to get boolean from %s avd",
3216212Saw148015 		    avd_get_type_string(avd));
3226212Saw148015 		return (FALSE);
3236212Saw148015 	}
3246212Saw148015 }
3256212Saw148015 
3266212Saw148015 /*
3276212Saw148015  * Returns the string pointed to by the supplied avd_t "avd".
3286212Saw148015  */
3296212Saw148015 char *
3306212Saw148015 avd_get_str(avd_t avd)
3316212Saw148015 {
3326212Saw148015 	var_t *ivp;
3336212Saw148015 
3346212Saw148015 	if (avd == NULL)
3356212Saw148015 		return (NULL);
3366212Saw148015 
3376212Saw148015 	switch (avd->avd_type) {
3386212Saw148015 	case AVD_VAL_STR:
3396212Saw148015 		return (avd->avd_val.strval);
3406212Saw148015 
3416212Saw148015 	case AVD_VARVAL_STR:
3426212Saw148015 		if (avd->avd_val.strptr)
3436212Saw148015 			return (*avd->avd_val.strptr);
3446212Saw148015 		else
3456212Saw148015 			return (NULL);
3466212Saw148015 
3476212Saw148015 	case AVD_IND_VAR:
3486212Saw148015 		ivp = avd->avd_val.varptr;
3496212Saw148015 
3506212Saw148015 		if (ivp && VAR_HAS_STRING(ivp))
3516212Saw148015 			return (ivp->var_val.string);
3526212Saw148015 
3536212Saw148015 		filebench_log(LOG_ERROR,
3546212Saw148015 		    "Attempt to get string from %s var $%s",
3556212Saw148015 		    var_get_type_string(ivp), ivp->var_name);
3566212Saw148015 		return (NULL);
3576212Saw148015 
3586212Saw148015 	default:
3596212Saw148015 		filebench_log(LOG_ERROR,
3606212Saw148015 		    "Attempt to get string from %s avd",
3616212Saw148015 		    avd_get_type_string(avd));
3625184Sek110237 		return (NULL);
3635184Sek110237 	}
3646212Saw148015 }
3655184Sek110237 
3666212Saw148015 /*
3676212Saw148015  * Allocates a avd_t from ipc memory space.
3686212Saw148015  * logs an error and returns NULL on failure.
3696212Saw148015  */
3706212Saw148015 static avd_t
3716212Saw148015 avd_alloc_cmn(void)
3726212Saw148015 {
3736212Saw148015 	avd_t rtn;
3745184Sek110237 
3756212Saw148015 	if ((rtn = (avd_t)ipc_malloc(FILEBENCH_AVD)) == NULL)
3766212Saw148015 		filebench_log(LOG_ERROR, "Avd alloc failed");
3775184Sek110237 
3785184Sek110237 	return (rtn);
3795184Sek110237 }
3805184Sek110237 
3815184Sek110237 /*
3826212Saw148015  * pre-loads the allocated avd_t with the boolean_t "bool".
3836212Saw148015  * Returns the avd_t on success, NULL on failure.
3846212Saw148015  */
3856212Saw148015 avd_t
3866212Saw148015 avd_bool_alloc(boolean_t bool)
3876212Saw148015 {
3886212Saw148015 	avd_t avd;
3896212Saw148015 
3906212Saw148015 	if ((avd = avd_alloc_cmn()) == NULL)
3916212Saw148015 		return (NULL);
3926212Saw148015 
3936212Saw148015 	avd->avd_type = AVD_VAL_BOOL;
3946212Saw148015 	avd->avd_val.boolval = bool;
3956212Saw148015 
3966212Saw148015 	filebench_log(LOG_DEBUG_IMPL, "Alloc boolean %d", bool);
3976212Saw148015 
3986212Saw148015 	return (avd);
3996212Saw148015 }
4006212Saw148015 
4016212Saw148015 /*
4026212Saw148015  * pre-loads the allocated avd_t with the fbint_t "integer".
4036212Saw148015  * Returns the avd_t on success, NULL on failure.
4046212Saw148015  */
4056212Saw148015 avd_t
4066212Saw148015 avd_int_alloc(fbint_t integer)
4076212Saw148015 {
4086212Saw148015 	avd_t avd;
4096212Saw148015 
4106212Saw148015 	if ((avd = avd_alloc_cmn()) == NULL)
4116212Saw148015 		return (NULL);
4126212Saw148015 
4136212Saw148015 	avd->avd_type = AVD_VAL_INT;
4146212Saw148015 	avd->avd_val.intval = integer;
4156212Saw148015 
4166286Saw148015 	filebench_log(LOG_DEBUG_IMPL, "Alloc integer %llu",
4176286Saw148015 	    (u_longlong_t)integer);
4186212Saw148015 
4196212Saw148015 	return (avd);
4206212Saw148015 }
4216212Saw148015 
4226212Saw148015 /*
4236212Saw148015  * Gets a avd_t and points it to the var that
4246212Saw148015  * it will eventually be filled from
4255184Sek110237  */
4266212Saw148015 static avd_t
4276212Saw148015 avd_alloc_var_ptr(var_t *var)
4285184Sek110237 {
4296212Saw148015 	avd_t avd;
4306212Saw148015 
4316212Saw148015 	if (var == NULL)
4326212Saw148015 		return (NULL);
4336212Saw148015 
4346212Saw148015 	if ((avd = avd_alloc_cmn()) == NULL)
4356212Saw148015 		return (NULL);
4366212Saw148015 
4376212Saw148015 	switch (var->var_type & VAR_TYPE_SET_MASK) {
4386212Saw148015 	case VAR_TYPE_BOOL_SET:
4396212Saw148015 		avd->avd_type = AVD_VARVAL_BOOL;
4406212Saw148015 		avd->avd_val.boolptr = (&var->var_val.boolean);
4416212Saw148015 		break;
4426212Saw148015 
4436212Saw148015 	case VAR_TYPE_INT_SET:
4446212Saw148015 		avd->avd_type = AVD_VARVAL_INT;
4456212Saw148015 		avd->avd_val.intptr = (&var->var_val.integer);
4466212Saw148015 		break;
4476212Saw148015 
4486212Saw148015 	case VAR_TYPE_STR_SET:
4496212Saw148015 		avd->avd_type = AVD_VARVAL_STR;
4506212Saw148015 		avd->avd_val.strptr = &(var->var_val.string);
4516212Saw148015 		break;
4525184Sek110237 
4536212Saw148015 	case VAR_TYPE_DBL_SET:
4546212Saw148015 		avd->avd_type = AVD_VARVAL_DBL;
4556212Saw148015 		avd->avd_val.dblptr = &(var->var_val.dbl_flt);
4566212Saw148015 		break;
4576212Saw148015 
4586212Saw148015 	case VAR_TYPE_RAND_SET:
4596212Saw148015 		avd->avd_type = AVD_IND_RANDVAR;
4606212Saw148015 		avd->avd_val.randptr = var->var_val.randptr;
4616212Saw148015 		break;
4626212Saw148015 
4636212Saw148015 	default:
4646212Saw148015 		avd->avd_type = AVD_IND_VAR;
4656212Saw148015 		avd->avd_val.varptr = var;
4666212Saw148015 		break;
4676212Saw148015 	}
4686212Saw148015 	return (avd);
4696212Saw148015 }
4706212Saw148015 
4716212Saw148015 /*
4726212Saw148015  * Gets a avd_t, then allocates and initializes a piece of
4736212Saw148015  * shared string memory, putting the pointer to it into the just
4746212Saw148015  * allocated string pointer location. The routine returns a pointer
4756212Saw148015  * to the string pointer location or returns NULL on error.
4766212Saw148015  */
4776212Saw148015 avd_t
4786212Saw148015 avd_str_alloc(char *string)
4796212Saw148015 {
4806212Saw148015 	avd_t avd;
4816212Saw148015 
4826212Saw148015 	if (string == NULL) {
4836212Saw148015 		filebench_log(LOG_ERROR, "No string supplied\n");
4845184Sek110237 		return (NULL);
4855184Sek110237 	}
4865184Sek110237 
4876212Saw148015 	if ((avd = avd_alloc_cmn()) == NULL)
4886212Saw148015 		return (NULL);
4896212Saw148015 
4906212Saw148015 	avd->avd_type = AVD_VAL_STR;
4916212Saw148015 	avd->avd_val.strval = ipc_stralloc(string);
4925184Sek110237 
4935184Sek110237 	filebench_log(LOG_DEBUG_IMPL,
4945184Sek110237 	    "Alloc string %s ptr %zx",
4956212Saw148015 	    string, avd);
4965184Sek110237 
4976212Saw148015 	return (avd);
4985184Sek110237 }
4995184Sek110237 
5005184Sek110237 /*
5015184Sek110237  * Allocates a var (var_t) from interprocess shared memory.
5025184Sek110237  * Places the allocated var on the end of the globally shared
5035184Sek110237  * var_list. Finally, the routine allocates a string containing
5045184Sek110237  * a copy of the supplied "name" string. If any allocations
5055184Sek110237  * fails, returns NULL, otherwise it returns a pointer to the
5065184Sek110237  * newly allocated var.
5075184Sek110237  */
5085184Sek110237 static var_t *
5096212Saw148015 var_alloc_cmn(char *name, int var_type)
5105184Sek110237 {
5116212Saw148015 	var_t **var_listp;
5125184Sek110237 	var_t *var = NULL;
5135184Sek110237 	var_t *prev = NULL;
5145184Sek110237 	var_t *newvar;
5155184Sek110237 
5165184Sek110237 	if ((newvar = (var_t *)ipc_malloc(FILEBENCH_VARIABLE)) == NULL) {
5175184Sek110237 		filebench_log(LOG_ERROR, "Out of memory for variables");
5185184Sek110237 		return (NULL);
5195184Sek110237 	}
5205184Sek110237 	(void) memset(newvar, 0, sizeof (newvar));
5216212Saw148015 	newvar->var_type = var_type;
5225184Sek110237 
5235184Sek110237 	if ((newvar->var_name = ipc_stralloc(name)) == NULL) {
5245184Sek110237 		filebench_log(LOG_ERROR, "Out of memory for variables");
5255184Sek110237 		return (NULL);
5265184Sek110237 	}
5275184Sek110237 
5286212Saw148015 	switch (var_type & VAR_TYPE_MASK) {
5296212Saw148015 	case VAR_TYPE_RANDOM:
5306212Saw148015 	case VAR_TYPE_GLOBAL:
531*6391Saw148015 		var_listp = &filebench_shm->shm_var_list;
5326212Saw148015 		break;
5336212Saw148015 
5346212Saw148015 	case VAR_TYPE_DYNAMIC:
535*6391Saw148015 		var_listp = &filebench_shm->shm_var_dyn_list;
5366212Saw148015 		break;
5376212Saw148015 
5386212Saw148015 	default:
539*6391Saw148015 		var_listp = &filebench_shm->shm_var_list;
5406212Saw148015 		break;
5416212Saw148015 	}
5426212Saw148015 
5436212Saw148015 	/* add to the end of list */
5446212Saw148015 	for (var = *var_listp; var != NULL; var = var->var_next)
5456212Saw148015 		prev = var; /* Find end of list */
5466212Saw148015 	if (prev != NULL)
5476212Saw148015 		prev->var_next = newvar;
5486212Saw148015 	else
5496212Saw148015 		*var_listp = newvar;
5506212Saw148015 
5515184Sek110237 	return (newvar);
5525184Sek110237 }
5535184Sek110237 
5545184Sek110237 /*
5556212Saw148015  * Allocates a var (var_t) from interprocess shared memory and
5566212Saw148015  * places the allocated var on the end of the globally shared
5576212Saw148015  * var_list. If the allocation fails, returns NULL, otherwise
5586212Saw148015  * it returns a pointer to the newly allocated var.
5596212Saw148015  */
5606212Saw148015 static var_t *
5616212Saw148015 var_alloc(char *name)
5626212Saw148015 {
5636212Saw148015 	return (var_alloc_cmn(name, VAR_TYPE_GLOBAL));
5646212Saw148015 }
5656212Saw148015 
5666212Saw148015 /*
5675184Sek110237  * Allocates a var (var_t) from interprocess shared memory.
5685184Sek110237  * Places the allocated var on the end of the globally shared
5696212Saw148015  * var_dyn_list. If the allocation fails, returns NULL, otherwise
5706212Saw148015  * it returns a pointer to the newly allocated var.
5715184Sek110237  */
5725184Sek110237 static var_t *
5735184Sek110237 var_alloc_dynamic(char *name)
5745184Sek110237 {
5756212Saw148015 	return (var_alloc_cmn(name, VAR_TYPE_DYNAMIC));
5765184Sek110237 }
5775184Sek110237 
5785184Sek110237 /*
5795184Sek110237  * Searches for var_t with name "name" in the master var_list.
5805184Sek110237  * If successful, returns a pointer to the var_t, otherwise
5815184Sek110237  * returns NULL.
5825184Sek110237  */
5835184Sek110237 static var_t *
5845184Sek110237 var_find(char *name)
5855184Sek110237 {
5865184Sek110237 	var_t *var;
5875184Sek110237 
588*6391Saw148015 	for (var = filebench_shm->shm_var_list; var != NULL;
589*6391Saw148015 	    var = var->var_next) {
5905184Sek110237 		if (strcmp(var->var_name, name) == 0)
5915184Sek110237 			return (var);
5925184Sek110237 	}
5935184Sek110237 
5945184Sek110237 	return (NULL);
5955184Sek110237 }
5965184Sek110237 
5975184Sek110237 /*
5985184Sek110237  * Searches for the named var, and, if found, sets its
5996212Saw148015  * var_val.boolean's value to that of the supplied boolean.
6005184Sek110237  * If not found, the routine allocates a new var and sets
6016212Saw148015  * its var_val.boolean's value to that of the supplied
6026212Saw148015  * boolean. If the named var cannot be found or allocated
6036212Saw148015  * the routine returns -1, otherwise it returns 0.
6045184Sek110237  */
6055184Sek110237 int
6066212Saw148015 var_assign_boolean(char *name, boolean_t bool)
6075184Sek110237 {
6085184Sek110237 	var_t *var;
6095184Sek110237 
6106212Saw148015 	if (name == NULL) {
6116212Saw148015 		filebench_log(LOG_ERROR,
6126212Saw148015 		    "var_assign_boolean: Name not supplied");
6136212Saw148015 		return (0);
6146212Saw148015 	}
6156212Saw148015 
6165184Sek110237 	name += 1;
6175184Sek110237 
6186212Saw148015 	if ((var = var_find(name)) == NULL) {
6196212Saw148015 			var = var_alloc(name);
6206212Saw148015 	}
6215184Sek110237 
6225184Sek110237 	if (var == NULL) {
6235184Sek110237 		filebench_log(LOG_ERROR, "Cannot assign variable %s",
6245184Sek110237 		    name);
6255184Sek110237 		return (-1);
6265184Sek110237 	}
6275184Sek110237 
6286212Saw148015 	if ((var->var_type & VAR_TYPE_MASK) == VAR_TYPE_RANDOM) {
6296212Saw148015 		filebench_log(LOG_ERROR,
6306212Saw148015 		    "Cannot assign integer to random variable %s", name);
6316212Saw148015 		return (-1);
6326212Saw148015 	}
6336212Saw148015 
6346212Saw148015 	VAR_SET_BOOL(var, bool);
6356212Saw148015 
6366212Saw148015 	filebench_log(LOG_DEBUG_SCRIPT, "Assign boolean %s=%d",
6376212Saw148015 	    name, bool);
6386212Saw148015 
6396212Saw148015 	return (0);
6406212Saw148015 }
6416212Saw148015 
6426212Saw148015 /*
6436212Saw148015  * Searches for the named var, and, if found, sets its
6446212Saw148015  * var_integer's value to that of the supplied integer.
6456212Saw148015  * If not found, the routine allocates a new var and sets
6466212Saw148015  * its var_integers's value to that of the supplied
6476212Saw148015  * integer. If the named var cannot be found or allocated
6486212Saw148015  * the routine returns -1, otherwise it returns 0.
6496212Saw148015  */
6506212Saw148015 int
6516212Saw148015 var_assign_integer(char *name, fbint_t integer)
6526212Saw148015 {
6536212Saw148015 	var_t *var;
6546212Saw148015 
6556212Saw148015 	if (name == NULL) {
6566212Saw148015 		filebench_log(LOG_ERROR,
6576212Saw148015 		    "var_assign_integer: Name not supplied");
6586212Saw148015 		return (0);
6596212Saw148015 	}
6606212Saw148015 
6616212Saw148015 	name += 1;
6626212Saw148015 
6636212Saw148015 	if ((var = var_find(name)) == NULL) {
6646212Saw148015 			var = var_alloc(name);
6656212Saw148015 	}
6666212Saw148015 
6676212Saw148015 	if (var == NULL) {
6686212Saw148015 		filebench_log(LOG_ERROR, "Cannot assign variable %s",
6696212Saw148015 		    name);
6706212Saw148015 		return (-1);
6716212Saw148015 	}
6726212Saw148015 
6736212Saw148015 	if ((var->var_type & VAR_TYPE_MASK) == VAR_TYPE_RANDOM) {
6746212Saw148015 		filebench_log(LOG_ERROR,
6756212Saw148015 		    "Cannot assign integer to random variable %s", name);
6766212Saw148015 		return (-1);
6776212Saw148015 	}
6786212Saw148015 
6796212Saw148015 	VAR_SET_INT(var, integer);
6805184Sek110237 
6816286Saw148015 	filebench_log(LOG_DEBUG_SCRIPT, "Assign integer %s=%llu",
6826286Saw148015 	    name, (u_longlong_t)integer);
6835184Sek110237 
6845184Sek110237 	return (0);
6855184Sek110237 }
6865184Sek110237 
6875184Sek110237 /*
6886212Saw148015  * Find a variable, and set it to random type.
6896212Saw148015  * If it does not have a random extension, allocate one
6906212Saw148015  */
6916212Saw148015 var_t *
6926212Saw148015 var_find_randvar(char *name)
6936212Saw148015 {
6946212Saw148015 	var_t *newvar;
6956212Saw148015 
6966212Saw148015 	name += 1;
6976212Saw148015 
6986212Saw148015 	if ((newvar = var_find(name)) == NULL) {
6996212Saw148015 		filebench_log(LOG_ERROR,
7006212Saw148015 		    "failed to locate random variable $%s\n", name);
7016212Saw148015 		return (NULL);
7026212Saw148015 	}
7036212Saw148015 
7046212Saw148015 	/* set randdist pointer unless it is already set */
7056212Saw148015 	if (((newvar->var_type & VAR_TYPE_MASK) != VAR_TYPE_RANDOM) ||
7066212Saw148015 	    !VAR_HAS_RANDDIST(newvar)) {
7076212Saw148015 		filebench_log(LOG_ERROR,
7086212Saw148015 		    "Found variable $%s not random\n", name);
7096212Saw148015 		return (NULL);
7106212Saw148015 	}
7116212Saw148015 
7126212Saw148015 	return (newvar);
7136212Saw148015 }
7146212Saw148015 
7156212Saw148015 /*
7166212Saw148015  * Allocate a variable, and set it to random type. Then
7176212Saw148015  * allocate a random extension.
7186212Saw148015  */
7196212Saw148015 var_t *
7206212Saw148015 var_define_randvar(char *name)
7216212Saw148015 {
7226212Saw148015 	var_t *newvar;
7236212Saw148015 	randdist_t *rndp = NULL;
7246212Saw148015 
7256212Saw148015 	name += 1;
7266212Saw148015 
7276212Saw148015 	/* make sure variable doesn't already exist */
7286212Saw148015 	if (var_find(name) != NULL) {
7296212Saw148015 		filebench_log(LOG_ERROR,
7306212Saw148015 		    "variable name already in use\n");
7316212Saw148015 		return (NULL);
7326212Saw148015 	}
7336212Saw148015 
7346212Saw148015 	/* allocate a random variable */
7356212Saw148015 	if ((newvar = var_alloc_cmn(name, VAR_TYPE_RANDOM)) == NULL) {
7366212Saw148015 		filebench_log(LOG_ERROR,
7376212Saw148015 		    "failed to alloc random variable\n");
7386212Saw148015 		return (NULL);
7396212Saw148015 	}
7406212Saw148015 
7416212Saw148015 	/* set randdist pointer */
7426212Saw148015 	if ((rndp = randdist_alloc()) == NULL) {
7436212Saw148015 		filebench_log(LOG_ERROR,
7446212Saw148015 		    "failed to alloc random distribution object\n");
7456212Saw148015 		return (NULL);
7466212Saw148015 	}
7476212Saw148015 
7486212Saw148015 	rndp->rnd_var = newvar;
7496212Saw148015 	VAR_SET_RAND(newvar, rndp);
7506212Saw148015 
7516212Saw148015 	return (newvar);
7526212Saw148015 }
7536212Saw148015 
7546212Saw148015 /*
7556212Saw148015  * Searches for the named var, and if found returns an avd_t
7566212Saw148015  * pointing to the var's var_integer, var_string or var_double
7576212Saw148015  * as appropriate. If not found, attempts to allocate
7586212Saw148015  * a var named "name" and returns an avd_t to it with
7596212Saw148015  * no value set. If the var cannot be found or allocated, an
7605184Sek110237  * error is logged and the run is terminated.
7615184Sek110237  */
7626212Saw148015 avd_t
7636212Saw148015 var_ref_attr(char *name)
7645184Sek110237 {
7655184Sek110237 	var_t *var;
7665184Sek110237 
7675184Sek110237 	name += 1;
7685184Sek110237 
7695184Sek110237 	if ((var = var_find(name)) == NULL)
7705184Sek110237 		var = var_find_dynamic(name);
7715184Sek110237 
7725184Sek110237 	if (var == NULL)
7735184Sek110237 		var = var_alloc(name);
7745184Sek110237 
7755184Sek110237 	if (var == NULL) {
7765184Sek110237 		filebench_log(LOG_ERROR, "Invalid variable $%s",
7775184Sek110237 		    name);
7785184Sek110237 		filebench_shutdown(1);
7795184Sek110237 	}
7805184Sek110237 
7816212Saw148015 	/* allocate pointer to var and return */
7826212Saw148015 	return (avd_alloc_var_ptr(var));
7835184Sek110237 }
7845184Sek110237 
7856212Saw148015 
7865184Sek110237 /*
7876212Saw148015  * Searches for the named var, and if found copies the var_val.string,
7886212Saw148015  * if it exists, a decimal number string representation of
7896212Saw148015  * var_val.integer, the state of var_val.boolean, or the type of random
7906212Saw148015  * distribution employed, into a malloc'd bit of memory using fb_stralloc().
7915184Sek110237  * Returns a pointer to the created string, or NULL on failure.
7925184Sek110237  */
7935184Sek110237 char *
7945184Sek110237 var_to_string(char *name)
7955184Sek110237 {
7965184Sek110237 	var_t *var;
7975184Sek110237 	char tmp[128];
7985184Sek110237 
7995184Sek110237 	name += 1;
8005184Sek110237 
8015184Sek110237 	if ((var = var_find(name)) == NULL)
8025184Sek110237 		var = var_find_dynamic(name);
8035184Sek110237 
8045184Sek110237 	if (var == NULL)
8055184Sek110237 		return (NULL);
8065184Sek110237 
8076212Saw148015 	if ((var->var_type & VAR_TYPE_MASK) == VAR_TYPE_RANDOM) {
8086212Saw148015 		switch (var->var_val.randptr->rnd_type & RAND_TYPE_MASK) {
8096212Saw148015 		case RAND_TYPE_UNIFORM:
8106212Saw148015 			return (fb_stralloc("uniform random var"));
8116212Saw148015 		case RAND_TYPE_GAMMA:
8126212Saw148015 			return (fb_stralloc("gamma random var"));
8136212Saw148015 		case RAND_TYPE_TABLE:
8146212Saw148015 			return (fb_stralloc("tabular random var"));
8156212Saw148015 		default:
8166212Saw148015 			return (fb_stralloc("unitialized random var"));
8176212Saw148015 		}
8186212Saw148015 	}
8195184Sek110237 
8206212Saw148015 	if (VAR_HAS_STRING(var) && var->var_val.string)
8216212Saw148015 		return (fb_stralloc(var->var_val.string));
8225184Sek110237 
8236212Saw148015 	if (VAR_HAS_BOOLEAN(var)) {
8246212Saw148015 		if (var->var_val.boolean)
8256212Saw148015 			return (fb_stralloc("true"));
8266212Saw148015 		else
8276212Saw148015 			return (fb_stralloc("false"));
8286212Saw148015 	}
8296212Saw148015 
8306212Saw148015 	if (VAR_HAS_INTEGER(var)) {
8316286Saw148015 		(void) snprintf(tmp, sizeof (tmp), "%llu",
8326286Saw148015 		    (u_longlong_t)var->var_val.integer);
8336212Saw148015 		return (fb_stralloc(tmp));
8346212Saw148015 	}
8356212Saw148015 
8366212Saw148015 	return (fb_stralloc("No default"));
8375184Sek110237 }
8385184Sek110237 
8395184Sek110237 /*
8405184Sek110237  * Searches for the named var, and if found returns the value,
8416212Saw148015  * of var_val.boolean. If the var is not found, or a boolean
8426212Saw148015  * value has not been set, logs an error and returns 0.
8435184Sek110237  */
8446212Saw148015 boolean_t
8456212Saw148015 var_to_boolean(char *name)
8466212Saw148015 {
8476212Saw148015 	var_t *var;
8486212Saw148015 
8496212Saw148015 	name += 1;
8506212Saw148015 
8516212Saw148015 	if ((var = var_find(name)) == NULL)
8526212Saw148015 		var = var_find_dynamic(name);
8536212Saw148015 
8546212Saw148015 	if ((var != NULL) && VAR_HAS_BOOLEAN(var))
8556212Saw148015 		return (var->var_val.boolean);
8566212Saw148015 
8576212Saw148015 	filebench_log(LOG_ERROR,
8586212Saw148015 	    "Variable %s referenced before set", name);
8596212Saw148015 
8606212Saw148015 	return (0);
8616212Saw148015 }
8626212Saw148015 
8636212Saw148015 /*
8646212Saw148015  * Searches for the named var, and if found returns the value,
8656212Saw148015  * of var_val.integer. If the var is not found, or the an
8666212Saw148015  * integer value has not been set, logs an error and returns 0.
8676212Saw148015  */
8686212Saw148015 fbint_t
8695184Sek110237 var_to_integer(char *name)
8705184Sek110237 {
8715184Sek110237 	var_t *var;
8725184Sek110237 
8735184Sek110237 	name += 1;
8745184Sek110237 
8755184Sek110237 	if ((var = var_find(name)) == NULL)
8765184Sek110237 		var = var_find_dynamic(name);
8775184Sek110237 
8786212Saw148015 	if ((var != NULL) && VAR_HAS_INTEGER(var))
8796212Saw148015 		return (var->var_val.integer);
8805184Sek110237 
8815184Sek110237 	filebench_log(LOG_ERROR,
8825184Sek110237 	    "Variable %s referenced before set", name);
8835184Sek110237 
8845184Sek110237 	return (0);
8855184Sek110237 }
8865184Sek110237 
8875184Sek110237 /*
8886212Saw148015  * Searches for the named random var, and if found, converts the
8896212Saw148015  * requested parameter into a string or a decimal number string
8906212Saw148015  * representation, into a malloc'd bit of memory using fb_stralloc().
8916212Saw148015  * Returns a pointer to the created string, or calls var_to_string()
8926212Saw148015  * if a random variable isn't found.
8936212Saw148015  */
8946212Saw148015 char *
8956212Saw148015 var_randvar_to_string(char *name, int param_name)
8966212Saw148015 {
8976212Saw148015 	var_t *var;
8986212Saw148015 	fbint_t value;
8996212Saw148015 
9006212Saw148015 	if ((var = var_find(name + 1)) == NULL)
9016212Saw148015 		return (var_to_string(name));
9026212Saw148015 
9036212Saw148015 	if (((var->var_type & VAR_TYPE_MASK) != VAR_TYPE_RANDOM) ||
9046212Saw148015 	    !VAR_HAS_RANDDIST(var))
9056212Saw148015 		return (var_to_string(name));
9066212Saw148015 
9076212Saw148015 	switch (param_name) {
9086212Saw148015 	case RAND_PARAM_TYPE:
9096212Saw148015 		switch (var->var_val.randptr->rnd_type & RAND_TYPE_MASK) {
9106212Saw148015 		case RAND_TYPE_UNIFORM:
9116212Saw148015 			return (fb_stralloc("uniform"));
9126212Saw148015 		case RAND_TYPE_GAMMA:
9136212Saw148015 			return (fb_stralloc("gamma"));
9146212Saw148015 		case RAND_TYPE_TABLE:
9156212Saw148015 			return (fb_stralloc("tabular"));
9166212Saw148015 		default:
9176212Saw148015 			return (fb_stralloc("uninitialized"));
9186212Saw148015 		}
9196212Saw148015 
9206212Saw148015 	case RAND_PARAM_SRC:
9216212Saw148015 		if (var->var_val.randptr->rnd_type & RAND_SRC_GENERATOR)
9226212Saw148015 			return (fb_stralloc("rand48"));
9236212Saw148015 		else
9246212Saw148015 			return (fb_stralloc("urandom"));
9256212Saw148015 
9266212Saw148015 	case RAND_PARAM_SEED:
9276212Saw148015 		value = avd_get_int(var->var_val.randptr->rnd_seed);
9286212Saw148015 		break;
9296212Saw148015 
9306212Saw148015 	case RAND_PARAM_MIN:
9316212Saw148015 		value = avd_get_int(var->var_val.randptr->rnd_min);
9326212Saw148015 		break;
9336212Saw148015 
9346212Saw148015 	case RAND_PARAM_MEAN:
9356212Saw148015 		value = avd_get_int(var->var_val.randptr->rnd_mean);
9366212Saw148015 		break;
9376212Saw148015 
9386212Saw148015 	case RAND_PARAM_GAMMA:
9396212Saw148015 		value = avd_get_int(var->var_val.randptr->rnd_gamma);
9406212Saw148015 		break;
9416212Saw148015 
9426212Saw148015 	case RAND_PARAM_ROUND:
9436212Saw148015 		value = avd_get_int(var->var_val.randptr->rnd_round);
9446212Saw148015 		break;
9456212Saw148015 
9466212Saw148015 	default:
9476212Saw148015 		return (NULL);
9486212Saw148015 
9496212Saw148015 	}
9506212Saw148015 
9516212Saw148015 	/* just an integer value if we got here */
9526212Saw148015 	{
9536212Saw148015 		char tmp[128];
9546212Saw148015 
9556286Saw148015 		(void) snprintf(tmp, sizeof (tmp), "%llu",
9566286Saw148015 		    (u_longlong_t)value);
9576212Saw148015 		return (fb_stralloc(tmp));
9586212Saw148015 	}
9596212Saw148015 }
9606212Saw148015 
9616212Saw148015 /*
9625184Sek110237  * Searches for the var named "name", and if not found
9635184Sek110237  * allocates it. The then extracts the var_string from
9645184Sek110237  * the var named "string" and copies it into the var_string
9655184Sek110237  * of the var "name", after first allocating a piece of
9665184Sek110237  * interprocess shared string memory. If the var "name"
9675184Sek110237  * cannot be found or allocated, or the var "string" cannot
9685184Sek110237  * be found, the routine returns -1, otherwise it returns 0.
9695184Sek110237  */
9705184Sek110237 int
9716212Saw148015 var_assign_var(char *name, char *src_name)
9725184Sek110237 {
9736212Saw148015 	var_t *dst_var, *src_var;
9745184Sek110237 
9755184Sek110237 	name += 1;
9766212Saw148015 	src_name += 1;
9775184Sek110237 
9786212Saw148015 	if ((src_var = var_find(src_name)) == NULL) {
9796212Saw148015 		filebench_log(LOG_ERROR,
9806212Saw148015 		    "Cannot find source variable %s", src_name);
9816212Saw148015 		return (-1);
9826212Saw148015 	}
9835184Sek110237 
9846212Saw148015 	if ((dst_var = var_find(name)) == NULL)
9856212Saw148015 		dst_var = var_alloc(name);
9866212Saw148015 
9876212Saw148015 	if (dst_var == NULL) {
9885184Sek110237 		filebench_log(LOG_ERROR, "Cannot assign variable %s",
9895184Sek110237 		    name);
9905184Sek110237 		return (-1);
9915184Sek110237 	}
9925184Sek110237 
9936212Saw148015 	if ((dst_var->var_type & VAR_TYPE_MASK) == VAR_TYPE_RANDOM) {
9946212Saw148015 		filebench_log(LOG_ERROR,
9956212Saw148015 		    "Cannot assign var to Random variable %s", name);
9965184Sek110237 		return (-1);
9975184Sek110237 	}
9986212Saw148015 
9996212Saw148015 	if (VAR_HAS_BOOLEAN(src_var)) {
10006212Saw148015 		VAR_SET_BOOL(dst_var, src_var->var_val.boolean);
10016212Saw148015 		filebench_log(LOG_VERBOSE,
10026212Saw148015 		    "Assign var %s=%d", name, src_var->var_val.boolean);
10036212Saw148015 	}
10046212Saw148015 
10056212Saw148015 	if (VAR_HAS_INTEGER(src_var)) {
10066212Saw148015 		VAR_SET_INT(dst_var, src_var->var_val.integer);
10076212Saw148015 		filebench_log(LOG_VERBOSE,
10086286Saw148015 		    "Assign var %s=%llu",
10096286Saw148015 		    name, (u_longlong_t)src_var->var_val.integer);
10106212Saw148015 	}
10116212Saw148015 
10126212Saw148015 	if (VAR_HAS_DOUBLE(src_var)) {
10136212Saw148015 		VAR_SET_DBL(dst_var, src_var->var_val.dbl_flt);
10146212Saw148015 		filebench_log(LOG_VERBOSE,
10156212Saw148015 		    "Assign var %s=%lf", name, src_var->var_val.dbl_flt);
10166212Saw148015 	}
10176212Saw148015 
10186212Saw148015 	if (VAR_HAS_STRING(src_var)) {
10196212Saw148015 		char *strptr;
10206212Saw148015 
10216212Saw148015 		if ((strptr =
10226212Saw148015 		    ipc_stralloc(src_var->var_val.string)) == NULL) {
10236212Saw148015 			filebench_log(LOG_ERROR,
10246212Saw148015 			    "Cannot assign variable %s",
10256212Saw148015 			    name);
10266212Saw148015 			return (-1);
10276212Saw148015 		}
10286212Saw148015 		VAR_SET_STR(dst_var, strptr);
10296212Saw148015 		filebench_log(LOG_VERBOSE,
10306212Saw148015 		    "Assign var %s=%s", name, src_var->var_val.string);
10316212Saw148015 	}
10325184Sek110237 	return (0);
10335184Sek110237 }
10345184Sek110237 
10355184Sek110237 /*
10365184Sek110237  * Like var_assign_integer, only this routine copies the
10375184Sek110237  * supplied "string" into the var named "name". If the var
10385184Sek110237  * named "name" cannot be found then it is first allocated
10395184Sek110237  * before the copy. Space for the string in the var comes
10405184Sek110237  * from interprocess shared memory. If the var "name"
10415184Sek110237  * cannot be found or allocated, or the memory for the
10425184Sek110237  * var_string copy of "string" cannot be allocated, the
10435184Sek110237  * routine returns -1, otherwise it returns 0.
10445184Sek110237  */
10455184Sek110237 int
10465184Sek110237 var_assign_string(char *name, char *string)
10475184Sek110237 {
10485184Sek110237 	var_t *var;
10496212Saw148015 	char *strptr;
10505184Sek110237 
10515184Sek110237 	name += 1;
10525184Sek110237 
10535184Sek110237 	if ((var = var_find(name)) == NULL)
10545184Sek110237 		var = var_alloc(name);
10555184Sek110237 
10565184Sek110237 	if (var == NULL) {
10575184Sek110237 		filebench_log(LOG_ERROR, "Cannot assign variable %s",
10585184Sek110237 		    name);
10595184Sek110237 		return (-1);
10605184Sek110237 	}
10615184Sek110237 
10626212Saw148015 	if ((var->var_type & VAR_TYPE_MASK) == VAR_TYPE_RANDOM) {
10636212Saw148015 		filebench_log(LOG_ERROR,
10646212Saw148015 		    "Cannot assign string to random variable %s", name);
10656212Saw148015 		return (-1);
10666212Saw148015 	}
10676212Saw148015 
10686212Saw148015 	if ((strptr = ipc_stralloc(string)) == NULL) {
10695184Sek110237 		filebench_log(LOG_ERROR, "Cannot assign variable %s",
10705184Sek110237 		    name);
10715184Sek110237 		return (-1);
10725184Sek110237 	}
10736212Saw148015 	VAR_SET_STR(var, strptr);
10745184Sek110237 
10756212Saw148015 	filebench_log(LOG_DEBUG_SCRIPT,
10766212Saw148015 	    "Var assign string $%s=%s", name, string);
10775184Sek110237 
10785184Sek110237 	return (0);
10795184Sek110237 }
10805184Sek110237 
10815184Sek110237 /*
10826212Saw148015  * Tests to see if the supplied variable name without the portion after
10836212Saw148015  * the last period is that of a random variable. If it is, it returns
10846212Saw148015  * the number of characters to backspace to skip the period and field
10856212Saw148015  * name. Otherwise it returns 0.
10865184Sek110237  */
10876212Saw148015 int
10886212Saw148015 var_is_set4_randvar(char *name)
10895184Sek110237 {
10905184Sek110237 	var_t *var;
10916212Saw148015 	char varname[128];
10926212Saw148015 	int namelength;
10936212Saw148015 	char *sp;
10945184Sek110237 
10956212Saw148015 	(void) strncpy(varname, name, 128);
10966212Saw148015 	namelength = strlen(varname);
10976212Saw148015 	sp = varname + namelength;
10985184Sek110237 
10996212Saw148015 	while (sp != varname) {
11006212Saw148015 		int c = *sp;
11015184Sek110237 
11026212Saw148015 		*sp = 0;
11036212Saw148015 		if (c == '.')
11046212Saw148015 			break;
11056212Saw148015 
11066212Saw148015 		sp--;
11075184Sek110237 	}
11085184Sek110237 
11096212Saw148015 	/* not a variable name + field? */
11106212Saw148015 	if (sp == varname)
11116212Saw148015 		return (0);
11126212Saw148015 
11136212Saw148015 	/* first part not a variable name? */
11146212Saw148015 	if ((var = var_find(varname+1)) == NULL)
11156212Saw148015 		return (0);
11166212Saw148015 
11176212Saw148015 	/* Make sure it is a random variable */
11186212Saw148015 	if ((var->var_type & VAR_TYPE_MASK) != VAR_TYPE_RANDOM)
11196212Saw148015 		return (0);
11206212Saw148015 
11216212Saw148015 	/* calculate offset from end of random variable name */
11226212Saw148015 	return (namelength - (sp - varname));
11235184Sek110237 }
11245184Sek110237 
11255184Sek110237 /*
11265184Sek110237  * Implements a simple path name like scheme for finding values
11275184Sek110237  * to place in certain specially named vars. The first part of
11285184Sek110237  * the name is interpreted as a category of either: stats,
11295184Sek110237  * eventgen, date, script, or host var. If a match is found,
11305184Sek110237  * the appropriate routine is called to fill in the requested
11315184Sek110237  * value in the provided var_t, and a pointer to the supplied
11325184Sek110237  * var_t is returned. If the requested value is not found, NULL
11335184Sek110237  * is returned.
11345184Sek110237  */
11355184Sek110237 static var_t *
11365184Sek110237 var_find_internal(var_t *var)
11375184Sek110237 {
11385184Sek110237 	char *n = fb_stralloc(var->var_name);
11395184Sek110237 	char *name = n;
11405184Sek110237 	var_t *rtn = NULL;
11415184Sek110237 
11425184Sek110237 	name++;
11435184Sek110237 	if (name[strlen(name) - 1] != '}')
11445184Sek110237 		return (NULL);
11455184Sek110237 	name[strlen(name) - 1] = 0;
11465184Sek110237 
11475184Sek110237 	if (strncmp(name, STATS_VAR, strlen(STATS_VAR)) == 0)
11485184Sek110237 		rtn = stats_findvar(var, name + strlen(STATS_VAR));
11495184Sek110237 
11505184Sek110237 	if (strcmp(name, EVENTGEN_VAR) == 0)
11515184Sek110237 		rtn = eventgen_ratevar(var);
11525184Sek110237 
11535184Sek110237 	if (strcmp(name, DATE_VAR) == 0)
11545184Sek110237 		rtn = date_var(var);
11555184Sek110237 
11565184Sek110237 	if (strcmp(name, SCRIPT_VAR) == 0)
11575184Sek110237 		rtn = script_var(var);
11585184Sek110237 
11595184Sek110237 	if (strcmp(name, HOST_VAR) == 0)
11605184Sek110237 		rtn = host_var(var);
11615184Sek110237 
11625184Sek110237 	free(n);
11635184Sek110237 
11645184Sek110237 	return (rtn);
11655184Sek110237 }
11665184Sek110237 
11675184Sek110237 /*
11685184Sek110237  * Calls the C library routine getenv() to obtain the value
11695184Sek110237  * for the environment variable specified by var->var_name.
11706212Saw148015  * If found, the value string is returned in var->var_val.string.
11715184Sek110237  * If the requested value is not found, NULL is returned.
11725184Sek110237  */
11735184Sek110237 static var_t *
11745184Sek110237 var_find_environment(var_t *var)
11755184Sek110237 {
11765184Sek110237 	char *n = fb_stralloc(var->var_name);
11775184Sek110237 	char *name = n;
11786212Saw148015 	char *strptr;
11795184Sek110237 
11805184Sek110237 	name++;
11816212Saw148015 	if (name[strlen(name) - 1] != ')') {
11826212Saw148015 		free(n);
11835184Sek110237 		return (NULL);
11846212Saw148015 	}
11855184Sek110237 	name[strlen(name) - 1] = 0;
11865184Sek110237 
11876212Saw148015 	if ((strptr = getenv(name)) != NULL) {
11885184Sek110237 		free(n);
11896212Saw148015 		VAR_SET_STR(var, strptr);
11905184Sek110237 		return (var);
11915184Sek110237 	} else {
11925184Sek110237 		free(n);
11935184Sek110237 		return (NULL);
11945184Sek110237 	}
11955184Sek110237 }
11965184Sek110237 
11975184Sek110237 /*
11985184Sek110237  * Look up special variables. The "name" argument is used to find
11995184Sek110237  * the desired special var and fill it with an appropriate string
12005184Sek110237  * value. Looks for an already allocated var of the same name on
12015184Sek110237  * the var_dyn_list. If not found a new dynamic var is allocated.
12025184Sek110237  * if the name begins with '{', it is an internal variable, and
12035184Sek110237  * var_find_internal() is called. If the name begins with '(' it
12045184Sek110237  * is an environment varable, and var_find_environment() is
12055184Sek110237  * called. On success, a pointer to the var_t is returned,
12065184Sek110237  * otherwise, NULL is returned.
12075184Sek110237  */
12085184Sek110237 static var_t *
12095184Sek110237 var_find_dynamic(char *name)
12105184Sek110237 {
12115184Sek110237 	var_t *var = NULL;
1212*6391Saw148015 	var_t *v = filebench_shm->shm_var_dyn_list;
12135184Sek110237 	var_t *rtn;
12145184Sek110237 
12155184Sek110237 	/*
12165184Sek110237 	 * Lookup a reference to the var handle for this
12175184Sek110237 	 * special var
12185184Sek110237 	 */
1219*6391Saw148015 	for (v = filebench_shm->shm_var_dyn_list; v != NULL; v = v->var_next) {
12205184Sek110237 		if (strcmp(v->var_name, name) == 0) {
12215184Sek110237 			var = v;
12225184Sek110237 			break;
12235184Sek110237 		}
12245184Sek110237 	}
12255184Sek110237 
12265184Sek110237 	if (var == NULL)
12275184Sek110237 		var = var_alloc_dynamic(name);
12285184Sek110237 
12295184Sek110237 	/* Internal system control variable */
12305184Sek110237 	if (*name == '{') {
12315184Sek110237 		rtn = var_find_internal(var);
12325184Sek110237 		if (rtn == NULL)
12335184Sek110237 			filebench_log(LOG_ERROR,
12345184Sek110237 			    "Cannot find internal variable %s",
12355184Sek110237 			    var->var_name);
12365184Sek110237 		return (rtn);
12375184Sek110237 	}
12385184Sek110237 
12395184Sek110237 	/* Lookup variable in environment */
12405184Sek110237 	if (*name == '(') {
12415184Sek110237 		rtn = var_find_environment(var);
12425184Sek110237 		if (rtn == NULL)
12435184Sek110237 			filebench_log(LOG_ERROR,
12445184Sek110237 			    "Cannot find environment variable %s",
12455184Sek110237 			    var->var_name);
12465184Sek110237 		return (rtn);
12475184Sek110237 	}
12485184Sek110237 
12495184Sek110237 	return (NULL);
12505184Sek110237 }
1251