Home | History | Annotate | Download | only in common
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  *
     25  * Portions Copyright 2008 Denis Cheng
     26  */
     27 
     28 #include <stdlib.h>
     29 #include <stdio.h>
     30 #include <string.h>
     31 #include <errno.h>
     32 
     33 #include "filebench.h"
     34 #include "vars.h"
     35 #include "misc.h"
     36 #include "utils.h"
     37 #include "stats.h"
     38 #include "eventgen.h"
     39 #include "fb_random.h"
     40 
     41 static var_t *var_find_dynamic(char *name);
     42 static boolean_t var_get_bool(var_t *var);
     43 static fbint_t var_get_int(var_t *var);
     44 static double var_get_dbl(var_t *var);
     45 
     46 /*
     47  * The filebench variables system has attribute value descriptors (avd_t)
     48  * where an avd contains a boolean, integer, double, string, random
     49  * distribution object ptr, boolean ptr, integer ptr, double ptr,
     50  * string ptr, or variable ptr. The system also has the variables
     51  * themselves, (var_t), which are named, typed entities which can be
     52  * allocated, selected and changed using the "set" command and used in
     53  * attribute assignments. The variables contain either a boolean, an
     54  * integer, a double, a string or pointer to an associated random
     55  * distribution object. Both avd_t and var_t entities are allocated
     56  * from interprocess shared memory space.
     57  *
     58  * The attribute descriptors implement delayed binding to variable values,
     59  * which is necessary because the values of variables may be changed
     60  * between the time the workload file is loaded and it is actually run,
     61  * either by further "set" commands in the file or from the command line
     62  * interface. For random variables, they actually point to the random
     63  * distribution object, allowing FileBench to invoke the appropriate
     64  * random distribution function on each access to the attribute. However,
     65  * for static attributes, the value is just loaded in the descriptor
     66  * directly, avoiding the need to allocate a variable to hold the static
     67  * value.
     68  *
     69  * The routines in this module are used to allocate, locate, and
     70  * manipulate the attribute descriptors, and vars. Routines are
     71  * also included to convert between the component strings, doubles
     72  * and integers of vars, and said components of avd_t.
     73  */
     74 
     75 
     76 /*
     77  * returns a pointer to a string indicating the type of data contained
     78  * in the supplied attribute variable descriptor.
     79  */
     80 static char *
     81 avd_get_type_string(avd_t avd)
     82 {
     83 	switch (avd->avd_type) {
     84 	case AVD_INVALID:
     85 		return ("uninitialized");
     86 
     87 	case AVD_VAL_BOOL:
     88 		return ("boolean value");
     89 
     90 	case AVD_VARVAL_BOOL:
     91 		return ("points to boolean in var_t");
     92 
     93 	case AVD_VAL_INT:
     94 		return ("integer value");
     95 
     96 	case AVD_VARVAL_INT:
     97 		return ("points to integer in var_t");
     98 
     99 	case AVD_VAL_STR:
    100 		return ("string");
    101 
    102 	case AVD_VARVAL_STR:
    103 		return ("points to string in var_t");
    104 
    105 	case AVD_VAL_DBL:
    106 		return ("double float value");
    107 
    108 	case AVD_VARVAL_DBL:
    109 		return ("points to double float in var_t");
    110 
    111 	case AVD_IND_VAR:
    112 		return ("points to a var_t");
    113 
    114 	case AVD_IND_RANDVAR:
    115 		return ("points to var_t's random distribution object");
    116 
    117 	default:
    118 		return ("illegal avd type");
    119 	}
    120 }
    121 
    122 /*
    123  * returns a pointer to a string indicating the type of data contained
    124  * in the supplied variable.
    125  */
    126 static char *
    127 var_get_type_string(var_t *ivp)
    128 {
    129 	switch (ivp->var_type & VAR_TYPE_SET_MASK) {
    130 	case VAR_TYPE_BOOL_SET:
    131 		return ("boolean");
    132 
    133 	case VAR_TYPE_INT_SET:
    134 		return ("integer");
    135 
    136 	case VAR_TYPE_STR_SET:
    137 		return ("string");
    138 
    139 	case VAR_TYPE_DBL_SET:
    140 		return ("double float");
    141 
    142 	case VAR_TYPE_RAND_SET:
    143 		return ("random");
    144 
    145 	default:
    146 		return ("empty");
    147 	}
    148 }
    149 
    150 /*
    151  * Returns the fbint_t pointed to by the supplied avd_t "avd".
    152  */
    153 fbint_t
    154 avd_get_int(avd_t avd)
    155 {
    156 	randdist_t *rndp;
    157 
    158 	if (avd == NULL)
    159 		return (0);
    160 
    161 	switch (avd->avd_type) {
    162 	case AVD_VAL_INT:
    163 		return (avd->avd_val.intval);
    164 
    165 	case AVD_VARVAL_INT:
    166 		if (avd->avd_val.intptr)
    167 			return (*(avd->avd_val.intptr));
    168 		else
    169 			return (0);
    170 
    171 	case AVD_IND_VAR:
    172 		return (var_get_int(avd->avd_val.varptr));
    173 
    174 	case AVD_IND_RANDVAR:
    175 		if ((rndp = avd->avd_val.randptr) == NULL)
    176 			return (0);
    177 		else
    178 			return ((fbint_t)rndp->rnd_get(rndp));
    179 
    180 	default:
    181 		filebench_log(LOG_ERROR,
    182 		    "Attempt to get integer from %s avd",
    183 		    avd_get_type_string(avd));
    184 		return (0);
    185 	}
    186 }
    187 
    188 /*
    189  * Returns the floating point value of a variable pointed to by the
    190  * supplied avd_t "avd". Intended to get the actual (double) value
    191  * supplied by the random variable.
    192  */
    193 double
    194 avd_get_dbl(avd_t avd)
    195 {
    196 	randdist_t *rndp;
    197 
    198 	if (avd == NULL)
    199 		return (0.0);
    200 
    201 	switch (avd->avd_type) {
    202 	case AVD_VAL_INT:
    203 		return ((double)avd->avd_val.intval);
    204 
    205 	case AVD_VAL_DBL:
    206 		return (avd->avd_val.dblval);
    207 
    208 	case AVD_VARVAL_INT:
    209 		if (avd->avd_val.intptr)
    210 			return ((double)(*(avd->avd_val.intptr)));
    211 		else
    212 			return (0.0);
    213 
    214 	case AVD_VARVAL_DBL:
    215 		if (avd->avd_val.dblptr)
    216 			return (*(avd->avd_val.dblptr));
    217 		else
    218 			return (0.0);
    219 
    220 	case AVD_IND_VAR:
    221 		return (var_get_dbl(avd->avd_val.varptr));
    222 
    223 	case AVD_IND_RANDVAR:
    224 		if ((rndp = avd->avd_val.randptr) == NULL) {
    225 			return (0.0);
    226 		} else
    227 			return (rndp->rnd_get(rndp));
    228 
    229 	default:
    230 		filebench_log(LOG_ERROR,
    231 		    "Attempt to get floating point from %s avd",
    232 		    avd_get_type_string(avd));
    233 		return (0.0);
    234 	}
    235 }
    236 
    237 /*
    238  * Returns the boolean pointed to by the supplied avd_t "avd".
    239  */
    240 boolean_t
    241 avd_get_bool(avd_t avd)
    242 {
    243 	if (avd == NULL)
    244 		return (0);
    245 
    246 	switch (avd->avd_type) {
    247 	case AVD_VAL_BOOL:
    248 		return (avd->avd_val.boolval);
    249 
    250 	case AVD_VARVAL_BOOL:
    251 		if (avd->avd_val.boolptr)
    252 			return (*(avd->avd_val.boolptr));
    253 		else
    254 			return (FALSE);
    255 
    256 	/* for backwards compatibility with old workloads */
    257 	case AVD_VAL_INT:
    258 		if (avd->avd_val.intval != 0)
    259 			return (TRUE);
    260 		else
    261 			return (FALSE);
    262 
    263 	case AVD_VARVAL_INT:
    264 		if (avd->avd_val.intptr)
    265 			if (*(avd->avd_val.intptr) != 0)
    266 				return (TRUE);
    267 
    268 		return (FALSE);
    269 
    270 	case AVD_IND_VAR:
    271 		return (var_get_bool(avd->avd_val.varptr));
    272 
    273 	default:
    274 		filebench_log(LOG_ERROR,
    275 		    "Attempt to get boolean from %s avd",
    276 		    avd_get_type_string(avd));
    277 		return (FALSE);
    278 	}
    279 }
    280 
    281 /*
    282  * Returns the string pointed to by the supplied avd_t "avd".
    283  */
    284 char *
    285 avd_get_str(avd_t avd)
    286 {
    287 	var_t *ivp;
    288 
    289 	if (avd == NULL)
    290 		return (NULL);
    291 
    292 	switch (avd->avd_type) {
    293 	case AVD_VAL_STR:
    294 		return (avd->avd_val.strval);
    295 
    296 	case AVD_VARVAL_STR:
    297 		if (avd->avd_val.strptr)
    298 			return (*avd->avd_val.strptr);
    299 		else
    300 			return (NULL);
    301 
    302 	case AVD_IND_VAR:
    303 		ivp = avd->avd_val.varptr;
    304 
    305 		if (ivp && VAR_HAS_STRING(ivp))
    306 			return (ivp->var_val.string);
    307 
    308 		filebench_log(LOG_ERROR,
    309 		    "Attempt to get string from %s var $%s",
    310 		    var_get_type_string(ivp), ivp->var_name);
    311 		return (NULL);
    312 
    313 	default:
    314 		filebench_log(LOG_ERROR,
    315 		    "Attempt to get string from %s avd",
    316 		    avd_get_type_string(avd));
    317 		return (NULL);
    318 	}
    319 }
    320 
    321 /*
    322  * Allocates a avd_t from ipc memory space.
    323  * logs an error and returns NULL on failure.
    324  */
    325 static avd_t
    326 avd_alloc_cmn(void)
    327 {
    328 	avd_t rtn;
    329 
    330 	if ((rtn = (avd_t)ipc_malloc(FILEBENCH_AVD)) == NULL)
    331 		filebench_log(LOG_ERROR, "Avd alloc failed");
    332 
    333 	return (rtn);
    334 }
    335 
    336 /*
    337  * pre-loads the allocated avd_t with the boolean_t "bool".
    338  * Returns the avd_t on success, NULL on failure.
    339  */
    340 avd_t
    341 avd_bool_alloc(boolean_t bool)
    342 {
    343 	avd_t avd;
    344 
    345 	if ((avd = avd_alloc_cmn()) == NULL)
    346 		return (NULL);
    347 
    348 	avd->avd_type = AVD_VAL_BOOL;
    349 	avd->avd_val.boolval = bool;
    350 
    351 	filebench_log(LOG_DEBUG_IMPL, "Alloc boolean %d", bool);
    352 
    353 	return (avd);
    354 }
    355 
    356 /*
    357  * pre-loads the allocated avd_t with the fbint_t "integer".
    358  * Returns the avd_t on success, NULL on failure.
    359  */
    360 avd_t
    361 avd_int_alloc(fbint_t integer)
    362 {
    363 	avd_t avd;
    364 
    365 	if ((avd = avd_alloc_cmn()) == NULL)
    366 		return (NULL);
    367 
    368 	avd->avd_type = AVD_VAL_INT;
    369 	avd->avd_val.intval = integer;
    370 
    371 	filebench_log(LOG_DEBUG_IMPL, "Alloc integer %llu",
    372 	    (u_longlong_t)integer);
    373 
    374 	return (avd);
    375 }
    376 
    377 /*
    378  * Gets a avd_t and points it to the var that
    379  * it will eventually be filled from
    380  */
    381 static avd_t
    382 avd_alloc_var_ptr(var_t *var)
    383 {
    384 	avd_t avd;
    385 
    386 	if (var == NULL)
    387 		return (NULL);
    388 
    389 	if ((avd = avd_alloc_cmn()) == NULL)
    390 		return (NULL);
    391 
    392 	switch (var->var_type & VAR_TYPE_SET_MASK) {
    393 	case VAR_TYPE_BOOL_SET:
    394 		avd->avd_type = AVD_VARVAL_BOOL;
    395 		avd->avd_val.boolptr = (&var->var_val.boolean);
    396 		break;
    397 
    398 	case VAR_TYPE_INT_SET:
    399 		avd->avd_type = AVD_VARVAL_INT;
    400 		avd->avd_val.intptr = (&var->var_val.integer);
    401 		break;
    402 
    403 	case VAR_TYPE_STR_SET:
    404 		avd->avd_type = AVD_VARVAL_STR;
    405 		avd->avd_val.strptr = &(var->var_val.string);
    406 		break;
    407 
    408 	case VAR_TYPE_DBL_SET:
    409 		avd->avd_type = AVD_VARVAL_DBL;
    410 		avd->avd_val.dblptr = &(var->var_val.dbl_flt);
    411 		break;
    412 
    413 	case VAR_TYPE_RAND_SET:
    414 		avd->avd_type = AVD_IND_RANDVAR;
    415 		avd->avd_val.randptr = var->var_val.randptr;
    416 		break;
    417 
    418 	case VAR_TYPE_INDVAR_SET:
    419 		avd->avd_type = AVD_IND_VAR;
    420 		if ((var->var_type & VAR_INDVAR_MASK) == VAR_IND_ASSIGN)
    421 			avd->avd_val.varptr = var->var_varptr1;
    422 		else
    423 			avd->avd_val.varptr = var;
    424 
    425 		break;
    426 
    427 	default:
    428 		avd->avd_type = AVD_IND_VAR;
    429 		avd->avd_val.varptr = var;
    430 		break;
    431 	}
    432 	return (avd);
    433 }
    434 
    435 /*
    436  * Gets a avd_t, then allocates and initializes a piece of
    437  * shared string memory, putting the pointer to it into the just
    438  * allocated string pointer location. The routine returns a pointer
    439  * to the string pointer location or returns NULL on error.
    440  */
    441 avd_t
    442 avd_str_alloc(char *string)
    443 {
    444 	avd_t avd;
    445 
    446 	if (string == NULL) {
    447 		filebench_log(LOG_ERROR, "No string supplied\n");
    448 		return (NULL);
    449 	}
    450 
    451 	if ((avd = avd_alloc_cmn()) == NULL)
    452 		return (NULL);
    453 
    454 	avd->avd_type = AVD_VAL_STR;
    455 	avd->avd_val.strval = ipc_stralloc(string);
    456 
    457 	filebench_log(LOG_DEBUG_IMPL,
    458 	    "Alloc string %s ptr %zx",
    459 	    string, avd);
    460 
    461 	return (avd);
    462 }
    463 
    464 /*
    465  * Allocates a var (var_t) from interprocess shared memory.
    466  * Places the allocated var on the end of the globally shared
    467  * shm_var_list. Finally, the routine allocates a string containing
    468  * a copy of the supplied "name" string. If any allocations
    469  * fails, returns NULL, otherwise it returns a pointer to the
    470  * newly allocated var.
    471  */
    472 static var_t *
    473 var_alloc_cmn(char *name, int var_type)
    474 {
    475 	var_t **var_listp;
    476 	var_t *var = NULL;
    477 	var_t *prev = NULL;
    478 	var_t *newvar;
    479 
    480 	if ((newvar = (var_t *)ipc_malloc(FILEBENCH_VARIABLE)) == NULL) {
    481 		filebench_log(LOG_ERROR, "Out of memory for variables");
    482 		return (NULL);
    483 	}
    484 	(void) memset(newvar, 0, sizeof (newvar));
    485 	newvar->var_type = var_type;
    486 
    487 	if ((newvar->var_name = ipc_stralloc(name)) == NULL) {
    488 		filebench_log(LOG_ERROR, "Out of memory for variables");
    489 		return (NULL);
    490 	}
    491 
    492 	switch (var_type & VAR_TYPE_MASK) {
    493 	case VAR_TYPE_RANDOM:
    494 	case VAR_TYPE_GLOBAL:
    495 		var_listp = &filebench_shm->shm_var_list;
    496 		break;
    497 
    498 	case VAR_TYPE_DYNAMIC:
    499 		var_listp = &filebench_shm->shm_var_dyn_list;
    500 		break;
    501 
    502 	case VAR_TYPE_LOCAL:
    503 		/* place on head of shared local list */
    504 		newvar->var_next = filebench_shm->shm_var_loc_list;
    505 		filebench_shm->shm_var_loc_list = newvar;
    506 		return (newvar);
    507 
    508 	default:
    509 		var_listp = &filebench_shm->shm_var_list;
    510 		break;
    511 	}
    512 
    513 	/* add to the end of list */
    514 	for (var = *var_listp; var != NULL; var = var->var_next)
    515 		prev = var; /* Find end of list */
    516 	if (prev != NULL)
    517 		prev->var_next = newvar;
    518 	else
    519 		*var_listp = newvar;
    520 
    521 	return (newvar);
    522 }
    523 
    524 /*
    525  * Allocates a var (var_t) from interprocess shared memory after
    526  * first adjusting the name to elminate the leading $. Places the
    527  * allocated var temporarily on the end of the globally
    528  * shared var_loc_list. If the allocation fails, returns NULL,
    529  * otherwise it returns a pointer to the newly allocated var.
    530  */
    531 var_t *
    532 var_lvar_alloc_local(char *name)
    533 {
    534 	if (name[0] == '$')
    535 		name += 1;
    536 
    537 	return (var_alloc_cmn(name, VAR_TYPE_LOCAL));
    538 }
    539 
    540 /*
    541  * Allocates a var (var_t) from interprocess shared memory and
    542  * places the allocated var on the end of the globally shared
    543  * shm_var_list. If the allocation fails, returns NULL, otherwise
    544  * it returns a pointer to the newly allocated var.
    545  */
    546 static var_t *
    547 var_alloc(char *name)
    548 {
    549 	return (var_alloc_cmn(name, VAR_TYPE_GLOBAL));
    550 }
    551 
    552 /*
    553  * Allocates a var (var_t) from interprocess shared memory.
    554  * Places the allocated var on the end of the globally shared
    555  * shm_var_dyn_list. If the allocation fails, returns NULL, otherwise
    556  * it returns a pointer to the newly allocated var.
    557  */
    558 static var_t *
    559 var_alloc_dynamic(char *name)
    560 {
    561 	return (var_alloc_cmn(name, VAR_TYPE_DYNAMIC));
    562 }
    563 
    564 /*
    565  * Searches for var_t with name "name" in the shm_var_loc_list,
    566  * then, if not found, in the global shm_var_list. If a matching
    567  * local or global var is found, returns a pointer to the var_t,
    568  * otherwise returns NULL.
    569  */
    570 static var_t *
    571 var_find(char *name)
    572 {
    573 	var_t *var;
    574 
    575 	for (var = filebench_shm->shm_var_loc_list; var != NULL;
    576 	    var = var->var_next) {
    577 		if (strcmp(var->var_name, name) == 0)
    578 			return (var);
    579 	}
    580 
    581 	for (var = filebench_shm->shm_var_list; var != NULL;
    582 	    var = var->var_next) {
    583 		if (strcmp(var->var_name, name) == 0)
    584 			return (var);
    585 	}
    586 
    587 	return (NULL);
    588 }
    589 
    590 /*
    591  * Searches for var_t with name "name" in the supplied shm_var_list.
    592  * If not found there, checks the global list. If still
    593  * unsuccessful, returns NULL. Otherwise returns a pointer to the var_t.
    594  */
    595 static var_t *
    596 var_find_list_only(char *name, var_t *var_list)
    597 {
    598 	var_t *var;
    599 
    600 	for (var = var_list; var != NULL; var = var->var_next) {
    601 		if (strcmp(var->var_name, name) == 0)
    602 			return (var);
    603 	}
    604 
    605 	return (NULL);
    606 }
    607 
    608 /*
    609  * Searches for var_t with name "name" in the supplied shm_var_list.
    610  * If not found there, checks the global list. If still
    611  * unsuccessful, returns NULL. Otherwise returns a pointer to the var_t.
    612  */
    613 static var_t *
    614 var_find_list(char *name, var_t *var_list)
    615 {
    616 	var_t *var;
    617 
    618 	if ((var = var_find_list_only(name, var_list)) != NULL)
    619 		return (var);
    620 	else
    621 		return (var_find(name));
    622 }
    623 
    624 /*
    625  * Searches for the named var and returns it if found. If not
    626  * found it allocates a new variable
    627  */
    628 static var_t *
    629 var_find_alloc(char *name)
    630 {
    631 	var_t *var;
    632 
    633 	if (name == NULL) {
    634 		filebench_log(LOG_ERROR,
    635 		    "var_find_alloc: Var name not supplied");
    636 		return (NULL);
    637 	}
    638 
    639 	name += 1;
    640 
    641 	if ((var = var_find(name)) == NULL) {
    642 			var = var_alloc(name);
    643 	}
    644 	return (var);
    645 }
    646 
    647 /*
    648  * Searches for the named var, and, if found, sets its
    649  * var_val.boolean's value to that of the supplied boolean.
    650  * If not found, the routine allocates a new var and sets
    651  * its var_val.boolean's value to that of the supplied
    652  * boolean. If the named var cannot be found or allocated
    653  * the routine returns -1, otherwise it returns 0.
    654  */
    655 int
    656 var_assign_boolean(char *name, boolean_t bool)
    657 {
    658 	var_t *var;
    659 
    660 	if ((var = var_find_alloc(name)) == NULL) {
    661 		filebench_log(LOG_ERROR, "Cannot assign variable %s",
    662 		    name);
    663 		return (-1);
    664 	}
    665 
    666 	if ((var->var_type & VAR_TYPE_MASK) == VAR_TYPE_RANDOM) {
    667 		filebench_log(LOG_ERROR,
    668 		    "Cannot assign integer to random variable %s", name);
    669 		return (-1);
    670 	}
    671 
    672 	VAR_SET_BOOL(var, bool);
    673 
    674 	filebench_log(LOG_DEBUG_SCRIPT, "Assign boolean %s=%d",
    675 	    name, bool);
    676 
    677 	return (0);
    678 }
    679 
    680 /*
    681  * Searches for the named var, and, if found, sets its
    682  * var_integer's value to that of the supplied integer.
    683  * If not found, the routine allocates a new var and sets
    684  * its var_integers's value to that of the supplied
    685  * integer. If the named var cannot be found or allocated
    686  * the routine returns -1, otherwise it returns 0.
    687  */
    688 int
    689 var_assign_integer(char *name, fbint_t integer)
    690 {
    691 	var_t *var;
    692 
    693 	if ((var = var_find_alloc(name)) == NULL) {
    694 		filebench_log(LOG_ERROR, "Cannot assign variable %s",
    695 		    name);
    696 		return (-1);
    697 	}
    698 
    699 	if ((var->var_type & VAR_TYPE_MASK) == VAR_TYPE_RANDOM) {
    700 		filebench_log(LOG_ERROR,
    701 		    "Cannot assign integer to random variable %s", name);
    702 		return (-1);
    703 	}
    704 
    705 	VAR_SET_INT(var, integer);
    706 
    707 	filebench_log(LOG_DEBUG_SCRIPT, "Assign integer %s=%llu",
    708 	    name, (u_longlong_t)integer);
    709 
    710 	return (0);
    711 }
    712 
    713 /*
    714  * Add, subtract, multiply or divide two integers based on optype
    715  * passed from caller.
    716  */
    717 static fbint_t
    718 var_binary_integer_op(var_t *var)
    719 {
    720 	fbint_t result;
    721 	fbint_t src1, src2;
    722 
    723 	if (var == NULL)
    724 		return (0);
    725 
    726 	switch (var->var_type & VAR_INDBINOP_MASK) {
    727 	case VAR_IND_BINOP_INT:
    728 		src2 = var->var_val.integer;
    729 		break;
    730 
    731 	case VAR_IND_BINOP_DBL:
    732 		src2 = (fbint_t)var->var_val.dbl_flt;
    733 		break;
    734 
    735 	case VAR_IND_BINOP_VAR:
    736 		if (var->var_val.varptr2 != NULL)
    737 			src2 = var_get_int(var->var_val.varptr2);
    738 		else
    739 			src2 = 0;
    740 		break;
    741 	}
    742 
    743 	if (var->var_varptr1 != NULL)
    744 		src1 = var_get_int(var->var_varptr1);
    745 	else
    746 		src1 = 0;
    747 
    748 	switch (var->var_type & VAR_INDVAR_MASK) {
    749 	case VAR_IND_VAR_SUM_VC:
    750 		result = src1 + src2;
    751 		break;
    752 
    753 	case VAR_IND_VAR_DIF_VC:
    754 		result = src1 - src2;
    755 		break;
    756 
    757 	case VAR_IND_C_DIF_VAR:
    758 		result = src2 - src1;
    759 		break;
    760 
    761 	case VAR_IND_VAR_MUL_VC:
    762 		result = src1 * src2;
    763 		break;
    764 
    765 	case VAR_IND_VAR_DIV_VC:
    766 		result = src1 / src2;
    767 		break;
    768 
    769 	case VAR_IND_C_DIV_VAR:
    770 		result = src2 / src1;
    771 		break;
    772 
    773 	default:
    774 		filebench_log(LOG_DEBUG_IMPL,
    775 		    "var_binary_integer_op: Called with unknown IND_TYPE");
    776 		result = 0;
    777 		break;
    778 	}
    779 	return (result);
    780 }
    781 
    782 /*
    783  * Add, subtract, multiply or divide two double precision floating point
    784  * numbers based on optype passed from caller.
    785  */
    786 static double
    787 var_binary_dbl_flt_op(var_t *var)
    788 {
    789 	double result;
    790 	double src1, src2;
    791 
    792 	if (var == NULL)
    793 		return (0.0);
    794 
    795 	switch (var->var_type & VAR_INDBINOP_MASK) {
    796 	case VAR_IND_BINOP_INT:
    797 		src2 = (double)var->var_val.integer;
    798 		break;
    799 
    800 	case VAR_IND_BINOP_DBL:
    801 		src2 = var->var_val.dbl_flt;
    802 		break;
    803 
    804 	case VAR_IND_BINOP_VAR:
    805 		if (var->var_val.varptr2 != NULL)
    806 			src2 = var_get_dbl(var->var_val.varptr2);
    807 		else
    808 			src2 = 0;
    809 		break;
    810 	}
    811 
    812 	if (var->var_varptr1 != NULL)
    813 		src1 = var_get_dbl(var->var_varptr1);
    814 	else
    815 		src1 = 0;
    816 
    817 	switch (var->var_type & VAR_INDVAR_MASK) {
    818 	case VAR_IND_VAR_SUM_VC:
    819 		result = src1 + src2;
    820 		break;
    821 
    822 	case VAR_IND_VAR_DIF_VC:
    823 		result = src1 - src2;
    824 		break;
    825 
    826 	case VAR_IND_C_DIF_VAR:
    827 		result = src2 - src1;
    828 		break;
    829 
    830 	case VAR_IND_VAR_MUL_VC:
    831 		result = src1 * src2;
    832 		break;
    833 
    834 	case VAR_IND_C_DIV_VAR:
    835 		result = src2 / src1;
    836 		break;
    837 
    838 	case VAR_IND_VAR_DIV_VC:
    839 		result = src1 / src2;
    840 		break;
    841 
    842 	default:
    843 		filebench_log(LOG_DEBUG_IMPL,
    844 		    "var_binary_dbl_flt_op: Called with unknown IND_TYPE");
    845 		result = 0;
    846 		break;
    847 	}
    848 	return (result);
    849 }
    850 
    851 /*
    852  * Perform a binary operation on a variable and an integer
    853  */
    854 int
    855 var_assign_op_var_int(char *name, int optype, char *src1, fbint_t src2)
    856 {
    857 	var_t *var;
    858 	var_t *var_src1;
    859 
    860 	if ((var_src1 = var_find(src1+1)) == NULL)
    861 		return (FILEBENCH_ERROR);
    862 
    863 	if ((var = var_find_alloc(name)) == NULL)
    864 		return (FILEBENCH_ERROR);
    865 
    866 	if ((var->var_type & VAR_TYPE_MASK) == VAR_TYPE_RANDOM) {
    867 		filebench_log(LOG_ERROR,
    868 		    "Cannot assign integer to random variable %s", name);
    869 		return (FILEBENCH_ERROR);
    870 	}
    871 
    872 	VAR_SET_BINOP_INDVAR(var, var_src1, optype);
    873 
    874 	var->var_val.integer = src2;
    875 
    876 	return (FILEBENCH_OK);
    877 }
    878 
    879 int
    880 var_assign_op_var_var(char *name, int optype, char *src1, char *src2)
    881 {
    882 	var_t *var;
    883 	var_t *var_src1;
    884 	var_t *var_src2;
    885 
    886 	if ((var_src1 = var_find(src1+1)) == NULL)
    887 		return (FILEBENCH_ERROR);
    888 
    889 	if ((var_src2 = var_find(src2+1)) == NULL)
    890 		return (FILEBENCH_ERROR);
    891 
    892 	if ((var = var_find_alloc(name)) == NULL)
    893 		return (FILEBENCH_ERROR);
    894 
    895 	if ((var->var_type & VAR_TYPE_MASK) == VAR_TYPE_RANDOM) {
    896 		filebench_log(LOG_ERROR,
    897 		    "Cannot assign integer to random variable %s", name);
    898 		return (FILEBENCH_ERROR);
    899 	}
    900 
    901 	VAR_SET_BINOP_INDVAR(var, var_src1, optype);
    902 
    903 	var->var_val.varptr2 = var_src2;
    904 
    905 	return (FILEBENCH_OK);
    906 }
    907 
    908 /*
    909  * Find a variable, and set it to random type.
    910  * If it does not have a random extension, allocate one
    911  */
    912 var_t *
    913 var_find_randvar(char *name)
    914 {
    915 	var_t *newvar;
    916 
    917 	name += 1;
    918 
    919 	if ((newvar = var_find(name)) == NULL) {
    920 		filebench_log(LOG_ERROR,
    921 		    "failed to locate random variable $%s\n", name);
    922 		return (NULL);
    923 	}
    924 
    925 	/* set randdist pointer unless it is already set */
    926 	if (((newvar->var_type & VAR_TYPE_MASK) != VAR_TYPE_RANDOM) ||
    927 	    !VAR_HAS_RANDDIST(newvar)) {
    928 		filebench_log(LOG_ERROR,
    929 		    "Found variable $%s not random\n", name);
    930 		return (NULL);
    931 	}
    932 
    933 	return (newvar);
    934 }
    935 
    936 /*
    937  * Allocate a variable, and set it to random type. Then
    938  * allocate a random extension.
    939  */
    940 var_t *
    941 var_define_randvar(char *name)
    942 {
    943 	var_t *newvar;
    944 	randdist_t *rndp = NULL;
    945 
    946 	name += 1;
    947 
    948 	/* make sure variable doesn't already exist */
    949 	if (var_find(name) != NULL) {
    950 		filebench_log(LOG_ERROR,
    951 		    "variable name already in use\n");
    952 		return (NULL);
    953 	}
    954 
    955 	/* allocate a random variable */
    956 	if ((newvar = var_alloc_cmn(name, VAR_TYPE_RANDOM)) == NULL) {
    957 		filebench_log(LOG_ERROR,
    958 		    "failed to alloc random variable\n");
    959 		return (NULL);
    960 	}
    961 
    962 	/* set randdist pointer */
    963 	if ((rndp = randdist_alloc()) == NULL) {
    964 		filebench_log(LOG_ERROR,
    965 		    "failed to alloc random distribution object\n");
    966 		return (NULL);
    967 	}
    968 
    969 	rndp->rnd_var = newvar;
    970 	VAR_SET_RAND(newvar, rndp);
    971 
    972 	return (newvar);
    973 }
    974 
    975 /*
    976  * Searches for the named var, and if found returns an avd_t
    977  * pointing to the var's var_integer, var_string or var_double
    978  * as appropriate. If not found, attempts to allocate
    979  * a var named "name" and returns an avd_t to it with
    980  * no value set. If the var cannot be found or allocated, an
    981  * error is logged and the run is terminated.
    982  */
    983 avd_t
    984 var_ref_attr(char *name)
    985 {
    986 	var_t *var;
    987 
    988 	name += 1;
    989 
    990 	if ((var = var_find(name)) == NULL)
    991 		var = var_find_dynamic(name);
    992 
    993 	if (var == NULL)
    994 		var = var_alloc(name);
    995 
    996 	if (var == NULL) {
    997 		filebench_log(LOG_ERROR, "Invalid variable $%s",
    998 		    name);
    999 		filebench_shutdown(1);
   1000 	}
   1001 
   1002 	/* allocate pointer to var and return */
   1003 	return (avd_alloc_var_ptr(var));
   1004 }
   1005 
   1006 /*
   1007  * Converts the contents of a var to a string
   1008  */
   1009 static char *
   1010 var_get_string(var_t *var)
   1011 {
   1012 
   1013 	if ((var->var_type & VAR_TYPE_MASK) == VAR_TYPE_RANDOM) {
   1014 		switch (var->var_val.randptr->rnd_type & RAND_TYPE_MASK) {
   1015 		case RAND_TYPE_UNIFORM:
   1016 			return (fb_stralloc("uniform random var"));
   1017 		case RAND_TYPE_GAMMA:
   1018 			return (fb_stralloc("gamma random var"));
   1019 		case RAND_TYPE_TABLE:
   1020 			return (fb_stralloc("tabular random var"));
   1021 		default:
   1022 			return (fb_stralloc("unitialized random var"));
   1023 		}
   1024 	}
   1025 
   1026 	if (VAR_HAS_STRING(var) && var->var_val.string)
   1027 		return (fb_stralloc(var->var_val.string));
   1028 
   1029 	if (VAR_HAS_BOOLEAN(var)) {
   1030 		if (var->var_val.boolean)
   1031 			return (fb_stralloc("true"));
   1032 		else
   1033 			return (fb_stralloc("false"));
   1034 	}
   1035 
   1036 	if (VAR_HAS_INTEGER(var)) {
   1037 		char tmp[128];
   1038 
   1039 		(void) snprintf(tmp, sizeof (tmp), "%llu",
   1040 		    (u_longlong_t)var->var_val.integer);
   1041 		return (fb_stralloc(tmp));
   1042 	}
   1043 
   1044 	if (VAR_HAS_INDVAR(var)) {
   1045 		var_t *ivp;
   1046 
   1047 		if ((ivp = var->var_varptr1) != NULL) {
   1048 			return (var_get_string(ivp));
   1049 		}
   1050 	}
   1051 
   1052 	if (VAR_HAS_BINOP(var)) {
   1053 		char tmp[128];
   1054 
   1055 		(void) snprintf(tmp, sizeof (tmp), "%llu",
   1056 		    var_binary_integer_op(var));
   1057 		return (fb_stralloc(tmp));
   1058 	}
   1059 
   1060 	return (fb_stralloc("No default"));
   1061 }
   1062 
   1063 /*
   1064  * Searches for the named var, and if found copies the var_val.string,
   1065  * if it exists, a decimal number string representation of
   1066  * var_val.integer, the state of var_val.boolean, or the type of random
   1067  * distribution employed, into a malloc'd bit of memory using fb_stralloc().
   1068  * Returns a pointer to the created string, or NULL on failure.
   1069  */
   1070 char *
   1071 var_to_string(char *name)
   1072 {
   1073 	var_t *var;
   1074 
   1075 	name += 1;
   1076 
   1077 	if ((var = var_find(name)) == NULL)
   1078 		var = var_find_dynamic(name);
   1079 
   1080 	if (var == NULL)
   1081 		return (NULL);
   1082 
   1083 	return (var_get_string(var));
   1084 }
   1085 
   1086 /*
   1087  * Returns the boolean from the supplied var_t "var".
   1088  */
   1089 static boolean_t
   1090 var_get_bool(var_t *var)
   1091 {
   1092 	if (var == NULL)
   1093 		return (0);
   1094 
   1095 	if (VAR_HAS_BOOLEAN(var))
   1096 		return (var->var_val.boolean);
   1097 
   1098 	if (VAR_HAS_INTEGER(var)) {
   1099 		if (var->var_val.integer == 0)
   1100 			return (FALSE);
   1101 		else
   1102 			return (TRUE);
   1103 	}
   1104 
   1105 	filebench_log(LOG_ERROR,
   1106 	    "Attempt to get boolean from %s var $%s",
   1107 	    var_get_type_string(var), var->var_name);
   1108 	return (FALSE);
   1109 }
   1110 
   1111 /*
   1112  * Returns the fbint_t from the supplied var_t "var".
   1113  */
   1114 static fbint_t
   1115 var_get_int(var_t *var)
   1116 {
   1117 	randdist_t *rndp;
   1118 
   1119 	if (var == NULL)
   1120 		return (0);
   1121 
   1122 	if (VAR_HAS_INTEGER(var))
   1123 		return (var->var_val.integer);
   1124 
   1125 	if (VAR_HAS_RANDDIST(var)) {
   1126 		if ((rndp = var->var_val.randptr) != NULL)
   1127 			return ((fbint_t)rndp->rnd_get(rndp));
   1128 	}
   1129 
   1130 	if (VAR_HAS_BINOP(var))
   1131 		return (var_binary_integer_op(var));
   1132 
   1133 	filebench_log(LOG_ERROR,
   1134 	    "Attempt to get integer from %s var $%s",
   1135 	    var_get_type_string(var), var->var_name);
   1136 	return (0);
   1137 }
   1138 
   1139 /*
   1140  * Returns the floating point value of a variable pointed to by the
   1141  * supplied var_t "var". Intended to get the actual (double) value
   1142  * supplied by the random variable.
   1143  */
   1144 static double
   1145 var_get_dbl(var_t *var)
   1146 {
   1147 	randdist_t *rndp;
   1148 
   1149 	if (var == NULL)
   1150 		return (0.0);
   1151 
   1152 	if (VAR_HAS_INTEGER(var))
   1153 		return ((double)var->var_val.integer);
   1154 
   1155 	if (VAR_HAS_DOUBLE(var))
   1156 		return (var->var_val.dbl_flt);
   1157 
   1158 	if (VAR_HAS_RANDDIST(var)) {
   1159 		if ((rndp = var->var_val.randptr) != NULL)
   1160 			return (rndp->rnd_get(rndp));
   1161 	}
   1162 
   1163 	if (VAR_HAS_BINOP(var))
   1164 		return (var_binary_dbl_flt_op(var));
   1165 
   1166 	filebench_log(LOG_ERROR,
   1167 	    "Attempt to get double float from %s var $%s",
   1168 	    var_get_type_string(var), var->var_name);
   1169 	return (0.0);
   1170 }
   1171 
   1172 /*
   1173  * Searches for the named var, and if found returns the value,
   1174  * of var_val.boolean. If the var is not found, or a boolean
   1175  * value has not been set, logs an error and returns 0.
   1176  */
   1177 boolean_t
   1178 var_to_boolean(char *name)
   1179 {
   1180 	var_t *var;
   1181 
   1182 	name += 1;
   1183 
   1184 	if ((var = var_find(name)) == NULL)
   1185 		var = var_find_dynamic(name);
   1186 
   1187 	if (var != NULL)
   1188 		return (var_get_bool(var));
   1189 
   1190 	filebench_log(LOG_ERROR,
   1191 	    "Variable %s referenced before set", name);
   1192 
   1193 	return (FALSE);
   1194 }
   1195 
   1196 /*
   1197  * Searches for the named var, and if found returns the value,
   1198  * of var_val.integer. If the var is not found, or the an
   1199  * integer value has not been set, logs an error and returns 0.
   1200  */
   1201 fbint_t
   1202 var_to_integer(char *name)
   1203 {
   1204 	var_t *var;
   1205 
   1206 	name += 1;
   1207 
   1208 	if ((var = var_find(name)) == NULL)
   1209 		var = var_find_dynamic(name);
   1210 
   1211 	if (var != NULL)
   1212 		return (var_get_int(var));
   1213 
   1214 	filebench_log(LOG_ERROR,
   1215 	    "Variable %s referenced before set", name);
   1216 
   1217 	return (0);
   1218 }
   1219 
   1220 /*
   1221  * Searches for the named var, and if found returns the value,
   1222  * of var_val.dbl_flt. If the var is not found, or the
   1223  * floating value has not been set, logs an error and returns 0.0.
   1224  */
   1225 double
   1226 var_to_double(char *name)
   1227 {
   1228 	var_t *var;
   1229 
   1230 	name += 1;
   1231 
   1232 	if ((var = var_find(name)) == NULL)
   1233 		var = var_find_dynamic(name);
   1234 
   1235 	if (var != NULL)
   1236 		return (var_get_dbl(var));
   1237 
   1238 	filebench_log(LOG_ERROR,
   1239 	    "Variable %s referenced before set", name);
   1240 
   1241 	return (0.0);
   1242 }
   1243 
   1244 /*
   1245  * Searches for the named random var, and if found, converts the
   1246  * requested parameter into a string or a decimal number string
   1247  * representation, into a malloc'd bit of memory using fb_stralloc().
   1248  * Returns a pointer to the created string, or calls var_to_string()
   1249  * if a random variable isn't found.
   1250  */
   1251 char *
   1252 var_randvar_to_string(char *name, int param_name)
   1253 {
   1254 	var_t *var;
   1255 	fbint_t value;
   1256 
   1257 	if ((var = var_find(name + 1)) == NULL)
   1258 		return (var_to_string(name));
   1259 
   1260 	if (((var->var_type & VAR_TYPE_MASK) != VAR_TYPE_RANDOM) ||
   1261 	    !VAR_HAS_RANDDIST(var))
   1262 		return (var_to_string(name));
   1263 
   1264 	switch (param_name) {
   1265 	case RAND_PARAM_TYPE:
   1266 		switch (var->var_val.randptr->rnd_type & RAND_TYPE_MASK) {
   1267 		case RAND_TYPE_UNIFORM:
   1268 			return (fb_stralloc("uniform"));
   1269 		case RAND_TYPE_GAMMA:
   1270 			return (fb_stralloc("gamma"));
   1271 		case RAND_TYPE_TABLE:
   1272 			return (fb_stralloc("tabular"));
   1273 		default:
   1274 			return (fb_stralloc("uninitialized"));
   1275 		}
   1276 
   1277 	case RAND_PARAM_SRC:
   1278 		if (var->var_val.randptr->rnd_type & RAND_SRC_GENERATOR)
   1279 			return (fb_stralloc("rand48"));
   1280 		else
   1281 			return (fb_stralloc("urandom"));
   1282 
   1283 	case RAND_PARAM_SEED:
   1284 		value = avd_get_int(var->var_val.randptr->rnd_seed);
   1285 		break;
   1286 
   1287 	case RAND_PARAM_MIN:
   1288 		value = avd_get_int(var->var_val.randptr->rnd_min);
   1289 		break;
   1290 
   1291 	case RAND_PARAM_MEAN:
   1292 		value = avd_get_int(var->var_val.randptr->rnd_mean);
   1293 		break;
   1294 
   1295 	case RAND_PARAM_GAMMA:
   1296 		value = avd_get_int(var->var_val.randptr->rnd_gamma);
   1297 		break;
   1298 
   1299 	case RAND_PARAM_ROUND:
   1300 		value = avd_get_int(var->var_val.randptr->rnd_round);
   1301 		break;
   1302 
   1303 	default:
   1304 		return (NULL);
   1305 
   1306 	}
   1307 
   1308 	/* just an integer value if we got here */
   1309 	{
   1310 		char tmp[128];
   1311 
   1312 		(void) snprintf(tmp, sizeof (tmp), "%llu",
   1313 		    (u_longlong_t)value);
   1314 		return (fb_stralloc(tmp));
   1315 	}
   1316 }
   1317 
   1318 /*
   1319  * Copies the value stored in the source string into the destination
   1320  * string. Returns -1 if any problems encountered, 0 otherwise.
   1321  */
   1322 static int
   1323 var_copy(var_t *dst_var, var_t *src_var) {
   1324 
   1325 	if (VAR_HAS_BOOLEAN(src_var)) {
   1326 		VAR_SET_BOOL(dst_var, src_var->var_val.boolean);
   1327 		filebench_log(LOG_DEBUG_SCRIPT,
   1328 		    "Assign var %s=%s", dst_var->var_name,
   1329 		    dst_var->var_val.boolean?"true":"false");
   1330 	}
   1331 
   1332 	if (VAR_HAS_INTEGER(src_var)) {
   1333 		VAR_SET_INT(dst_var, src_var->var_val.integer);
   1334 		filebench_log(LOG_DEBUG_SCRIPT,
   1335 		    "Assign var %s=%llu", dst_var->var_name,
   1336 		    (u_longlong_t)dst_var->var_val.integer);
   1337 	}
   1338 
   1339 	if (VAR_HAS_DOUBLE(src_var)) {
   1340 		VAR_SET_DBL(dst_var, src_var->var_val.dbl_flt);
   1341 		filebench_log(LOG_DEBUG_SCRIPT,
   1342 		    "Assign var %s=%lf", dst_var->var_name,
   1343 		    dst_var->var_val.dbl_flt);
   1344 	}
   1345 
   1346 	if (VAR_HAS_STRING(src_var)) {
   1347 		char *strptr;
   1348 
   1349 		if ((strptr =
   1350 		    ipc_stralloc(src_var->var_val.string)) == NULL) {
   1351 			filebench_log(LOG_ERROR,
   1352 			    "Cannot assign string for variable %s",
   1353 			    dst_var->var_name);
   1354 			return (-1);
   1355 		}
   1356 		VAR_SET_STR(dst_var, strptr);
   1357 		filebench_log(LOG_DEBUG_SCRIPT,
   1358 		    "Assign var %s=%s", dst_var->var_name,
   1359 		    dst_var->var_val.string);
   1360 	}
   1361 
   1362 	if (VAR_HAS_INDVAR(src_var)) {
   1363 		VAR_SET_INDVAR(dst_var, src_var->var_varptr1);
   1364 		filebench_log(LOG_DEBUG_SCRIPT,
   1365 		    "Assign var %s to var %s", dst_var->var_name,
   1366 		    src_var->var_name);
   1367 	}
   1368 	return (0);
   1369 }
   1370 
   1371 /*
   1372  * Searches for the var named "name", and if not found
   1373  * allocates it. The then copies the value from
   1374  * the src_var into the destination var "name"
   1375  * If the var "name" cannot be found or allocated, or the var "src_name"
   1376  * cannot be found, the routine returns -1, otherwise it returns 0.
   1377  */
   1378 int
   1379 var_assign_var(char *name, char *src_name)
   1380 {
   1381 	var_t *dst_var, *src_var;
   1382 
   1383 	name += 1;
   1384 	src_name += 1;
   1385 
   1386 	if ((src_var = var_find(src_name)) == NULL) {
   1387 		filebench_log(LOG_ERROR,
   1388 		    "Cannot find source variable %s", src_name);
   1389 		return (-1);
   1390 	}
   1391 
   1392 	if ((dst_var = var_find(name)) == NULL)
   1393 		dst_var = var_alloc(name);
   1394 
   1395 	if (dst_var == NULL) {
   1396 		filebench_log(LOG_ERROR, "Cannot assign variable %s",
   1397 		    name);
   1398 		return (-1);
   1399 	}
   1400 
   1401 	if ((dst_var->var_type & VAR_TYPE_MASK) == VAR_TYPE_RANDOM) {
   1402 		filebench_log(LOG_ERROR,
   1403 		    "Cannot assign var to Random variable %s", name);
   1404 		return (-1);
   1405 	}
   1406 
   1407 	return (var_copy(dst_var, src_var));
   1408 }
   1409 
   1410 /*
   1411  * Like var_assign_integer, only this routine copies the
   1412  * supplied "string" into the var named "name". If the var
   1413  * named "name" cannot be found then it is first allocated
   1414  * before the copy. Space for the string in the var comes
   1415  * from interprocess shared memory. If the var "name"
   1416  * cannot be found or allocated, or the memory for the
   1417  * var_val.string copy of "string" cannot be allocated, the
   1418  * routine returns -1, otherwise it returns 0.
   1419  */
   1420 int
   1421 var_assign_string(char *name, char *string)
   1422 {
   1423 	var_t *var;
   1424 	char *strptr;
   1425 
   1426 	name += 1;
   1427 
   1428 	if ((var = var_find(name)) == NULL)
   1429 		var = var_alloc(name);
   1430 
   1431 	if (var == NULL) {
   1432 		filebench_log(LOG_ERROR, "Cannot assign variable %s",
   1433 		    name);
   1434 		return (-1);
   1435 	}
   1436 
   1437 	if ((var->var_type & VAR_TYPE_MASK) == VAR_TYPE_RANDOM) {
   1438 		filebench_log(LOG_ERROR,
   1439 		    "Cannot assign string to random variable %s", name);
   1440 		return (-1);
   1441 	}
   1442 
   1443 	if ((strptr = ipc_stralloc(string)) == NULL) {
   1444 		filebench_log(LOG_ERROR, "Cannot assign variable %s",
   1445 		    name);
   1446 		return (-1);
   1447 	}
   1448 	VAR_SET_STR(var, strptr);
   1449 
   1450 	filebench_log(LOG_DEBUG_SCRIPT,
   1451 	    "Var assign string $%s=%s", name, string);
   1452 
   1453 	return (0);
   1454 }
   1455 
   1456 /*
   1457  * Allocates a local var. The then extracts the var_string from
   1458  * the var named "string" and copies it into the var_string
   1459  * of the var "name", after first allocating a piece of
   1460  * interprocess shared string memory. Returns a pointer to the
   1461  * newly allocated local var or NULL on error.
   1462  */
   1463 var_t *
   1464 var_lvar_assign_var(char *name, char *src_name)
   1465 {
   1466 	var_t *dst_var, *src_var;
   1467 
   1468 	src_name += 1;
   1469 
   1470 	if ((src_var = var_find(src_name)) == NULL) {
   1471 		filebench_log(LOG_ERROR,
   1472 		    "Cannot find source variable %s", src_name);
   1473 		return (NULL);
   1474 	}
   1475 
   1476 	dst_var = var_lvar_alloc_local(name);
   1477 
   1478 	if (dst_var == NULL) {
   1479 		filebench_log(LOG_ERROR, "Cannot assign variable %s",
   1480 		    name);
   1481 		return (NULL);
   1482 	}
   1483 
   1484 	/*
   1485 	 * if referencing another local var which is currently
   1486 	 * empty, indirect to it
   1487 	 */
   1488 	if ((src_var->var_type & VAR_TYPE_MASK) == VAR_TYPE_LOCAL) {
   1489 		VAR_SET_INDVAR(dst_var, src_var);
   1490 		filebench_log(LOG_DEBUG_SCRIPT,
   1491 		    "Assign local var %s to %s", name, src_name);
   1492 		return (dst_var);
   1493 	}
   1494 
   1495 	if (VAR_HAS_BOOLEAN(src_var)) {
   1496 		VAR_SET_BOOL(dst_var, src_var->var_val.boolean);
   1497 		filebench_log(LOG_DEBUG_SCRIPT,
   1498 		    "Assign var (%s, %p)=%s", name,
   1499 		    dst_var, src_var->var_val.boolean?"true":"false");
   1500 	} else if (VAR_HAS_INTEGER(src_var)) {
   1501 		VAR_SET_INT(dst_var, src_var->var_val.integer);
   1502 		filebench_log(LOG_DEBUG_SCRIPT,
   1503 		    "Assign var (%s, %p)=%llu", name,
   1504 		    dst_var, (u_longlong_t)src_var->var_val.integer);
   1505 	} else if (VAR_HAS_STRING(src_var)) {
   1506 		char *strptr;
   1507 
   1508 		if ((strptr = ipc_stralloc(src_var->var_val.string)) == NULL) {
   1509 			filebench_log(LOG_ERROR,
   1510 			    "Cannot assign variable %s",
   1511 			    name);
   1512 			return (NULL);
   1513 		}
   1514 		VAR_SET_STR(dst_var, strptr);
   1515 		filebench_log(LOG_DEBUG_SCRIPT,
   1516 		    "Assign var (%s, %p)=%s", name,
   1517 		    dst_var, src_var->var_val.string);
   1518 	} else if (VAR_HAS_DOUBLE(src_var)) {
   1519 		/* LINTED E_ASSIGMENT_CAUSE_LOSS_PREC */
   1520 		VAR_SET_INT(dst_var, src_var->var_val.dbl_flt);
   1521 		filebench_log(LOG_DEBUG_SCRIPT,
   1522 		    "Assign var (%s, %p)=%8.2f", name,
   1523 		    dst_var, src_var->var_val.dbl_flt);
   1524 	} else if (VAR_HAS_RANDDIST(src_var)) {
   1525 		VAR_SET_RAND(dst_var, src_var->var_val.randptr);
   1526 		filebench_log(LOG_DEBUG_SCRIPT,
   1527 		    "Assign var (%s, %p)=%llu", name,
   1528 		    dst_var, (u_longlong_t)src_var->var_val.integer);
   1529 	}
   1530 
   1531 	return (dst_var);
   1532 }
   1533 
   1534 /*
   1535  * the routine allocates a new local var and sets
   1536  * its var_boolean's value to that of the supplied
   1537  * boolean. It returns a pointer to the new local var
   1538  */
   1539 var_t *
   1540 var_lvar_assign_boolean(char *name, boolean_t bool)
   1541 {
   1542 	var_t *var;
   1543 
   1544 	var = var_lvar_alloc_local(name);
   1545 
   1546 	if (var == NULL) {
   1547 		filebench_log(LOG_ERROR, "Cannot assign variable %s",
   1548 		    name);
   1549 		return (NULL);
   1550 	}
   1551 
   1552 	VAR_SET_BOOL(var, bool);
   1553 
   1554 	filebench_log(LOG_DEBUG_SCRIPT, "Assign integer %s=%s",
   1555 	    name, bool ? "true" : "false");
   1556 
   1557 	return (var);
   1558 }
   1559 
   1560 /*
   1561  * the routine allocates a new local var and sets
   1562  * its var_integers's value to that of the supplied
   1563  * integer. It returns a pointer to the new local var
   1564  */
   1565 var_t *
   1566 var_lvar_assign_integer(char *name, fbint_t integer)
   1567 {
   1568 	var_t *var;
   1569 
   1570 	var = var_lvar_alloc_local(name);
   1571 
   1572 	if (var == NULL) {
   1573 		filebench_log(LOG_ERROR, "Cannot assign variable %s",
   1574 		    name);
   1575 		return (NULL);
   1576 	}
   1577 
   1578 	VAR_SET_INT(var, integer);
   1579 
   1580 	filebench_log(LOG_DEBUG_SCRIPT, "Assign integer %s=%llu",
   1581 	    name, (u_longlong_t)integer);
   1582 
   1583 	return (var);
   1584 }
   1585 
   1586 /*
   1587  * the routine allocates a new local var and sets
   1588  * its var_dbl_flt value to that of the supplied
   1589  * double precission floating point number. It returns
   1590  * a pointer to the new local var
   1591  */
   1592 var_t *
   1593 var_lvar_assign_double(char *name, double dbl)
   1594 {
   1595 	var_t *var;
   1596 
   1597 	var = var_lvar_alloc_local(name);
   1598 
   1599 	if (var == NULL) {
   1600 		filebench_log(LOG_ERROR, "Cannot assign variable %s",
   1601 		    name);
   1602 		return (NULL);
   1603 	}
   1604 
   1605 	VAR_SET_DBL(var, dbl);
   1606 
   1607 	filebench_log(LOG_DEBUG_SCRIPT, "Assign integer %s=%8.2f", name, dbl);
   1608 
   1609 	return (var);
   1610 }
   1611 
   1612 /*
   1613  * Like var_lvar_assign_integer, only this routine copies the
   1614  * supplied "string" into the var named "name". If the var
   1615  * named "name" cannot be found then it is first allocated
   1616  * before the copy. Space for the string in the var comes
   1617  * from interprocess shared memory. The allocated local var
   1618  * is returned at as a char *, or NULL on error.
   1619  */
   1620 var_t *
   1621 var_lvar_assign_string(char *name, char *string)
   1622 {
   1623 	var_t *var;
   1624 	char *strptr;
   1625 
   1626 	var = var_lvar_alloc_local(name);
   1627 
   1628 	if (var == NULL) {
   1629 		filebench_log(LOG_ERROR, "Cannot assign variable %s",
   1630 		    name);
   1631 		return (NULL);
   1632 	}
   1633 
   1634 	if ((strptr = ipc_stralloc(string)) == NULL) {
   1635 		filebench_log(LOG_ERROR, "Cannot assign variable %s",
   1636 		    name);
   1637 		return (NULL);
   1638 	}
   1639 	VAR_SET_STR(var, strptr);
   1640 
   1641 	filebench_log(LOG_DEBUG_SCRIPT,
   1642 	    "Lvar_assign_string (%s, %p)=%s", name, var, string);
   1643 
   1644 	return (var);
   1645 }
   1646 
   1647 /*
   1648  * Tests to see if the supplied variable name without the portion after
   1649  * the last period is that of a random variable. If it is, it returns
   1650  * the number of characters to backspace to skip the period and field
   1651  * name. Otherwise it returns 0.
   1652  */
   1653 int
   1654 var_is_set4_randvar(char *name)
   1655 {
   1656 	var_t *var;
   1657 	char varname[128];
   1658 	int namelength;
   1659 	char *sp;
   1660 
   1661 	(void) strncpy(varname, name, 128);
   1662 	namelength = strlen(varname);
   1663 	sp = varname + namelength;
   1664 
   1665 	while (sp != varname) {
   1666 		int c = *sp;
   1667 
   1668 		*sp = 0;
   1669 		if (c == '.')
   1670 			break;
   1671 
   1672 		sp--;
   1673 	}
   1674 
   1675 	/* not a variable name + field? */
   1676 	if (sp == varname)
   1677 		return (0);
   1678 
   1679 	/* first part not a variable name? */
   1680 	if ((var = var_find(varname+1)) == NULL)
   1681 		return (0);
   1682 
   1683 	/* Make sure it is a random variable */
   1684 	if ((var->var_type & VAR_TYPE_MASK) != VAR_TYPE_RANDOM)
   1685 		return (0);
   1686 
   1687 	/* calculate offset from end of random variable name */
   1688 	return (namelength - (sp - varname));
   1689 }
   1690 
   1691 /*
   1692  * Implements a simple path name like scheme for finding values
   1693  * to place in certain specially named vars. The first part of
   1694  * the name is interpreted as a category of either: stats,
   1695  * eventgen, date, script, or host var. If a match is found,
   1696  * the appropriate routine is called to fill in the requested
   1697  * value in the provided var_t, and a pointer to the supplied
   1698  * var_t is returned. If the requested value is not found, NULL
   1699  * is returned.
   1700  */
   1701 static var_t *
   1702 var_find_internal(var_t *var)
   1703 {
   1704 	char *n = fb_stralloc(var->var_name);
   1705 	char *name = n;
   1706 	var_t *rtn = NULL;
   1707 
   1708 	name++;
   1709 	if (name[strlen(name) - 1] != '}')
   1710 		return (NULL);
   1711 	name[strlen(name) - 1] = 0;
   1712 
   1713 	if (strncmp(name, STATS_VAR, strlen(STATS_VAR)) == 0)
   1714 		rtn = stats_findvar(var, name + strlen(STATS_VAR));
   1715 
   1716 	if (strcmp(name, EVENTGEN_VAR) == 0)
   1717 		rtn = eventgen_ratevar(var);
   1718 
   1719 	if (strcmp(name, DATE_VAR) == 0)
   1720 		rtn = date_var(var);
   1721 
   1722 	if (strcmp(name, SCRIPT_VAR) == 0)
   1723 		rtn = script_var(var);
   1724 
   1725 	if (strcmp(name, HOST_VAR) == 0)
   1726 		rtn = host_var(var);
   1727 
   1728 	free(n);
   1729 
   1730 	return (rtn);
   1731 }
   1732 
   1733 /*
   1734  * Calls the C library routine getenv() to obtain the value
   1735  * for the environment variable specified by var->var_name.
   1736  * If found, the value string is returned in var->var_val.string.
   1737  * If the requested value is not found, NULL is returned.
   1738  */
   1739 static var_t *
   1740 var_find_environment(var_t *var)
   1741 {
   1742 	char *n = fb_stralloc(var->var_name);
   1743 	char *name = n;
   1744 	char *strptr;
   1745 
   1746 	name++;
   1747 	if (name[strlen(name) - 1] != ')') {
   1748 		free(n);
   1749 		return (NULL);
   1750 	}
   1751 	name[strlen(name) - 1] = 0;
   1752 
   1753 	if ((strptr = getenv(name)) != NULL) {
   1754 		free(n);
   1755 		VAR_SET_STR(var, strptr);
   1756 		return (var);
   1757 	} else {
   1758 		free(n);
   1759 		return (NULL);
   1760 	}
   1761 }
   1762 
   1763 /*
   1764  * Look up special variables. The "name" argument is used to find
   1765  * the desired special var and fill it with an appropriate string
   1766  * value. Looks for an already allocated var of the same name on
   1767  * the shm_var_dyn_list. If not found a new dynamic var is allocated.
   1768  * if the name begins with '{', it is an internal variable, and
   1769  * var_find_internal() is called. If the name begins with '(' it
   1770  * is an environment varable, and var_find_environment() is
   1771  * called. On success, a pointer to the var_t is returned,
   1772  * otherwise, NULL is returned.
   1773  */
   1774 static var_t *
   1775 var_find_dynamic(char *name)
   1776 {
   1777 	var_t *var = NULL;
   1778 	var_t *v = filebench_shm->shm_var_dyn_list;
   1779 	var_t *rtn;
   1780 
   1781 	/*
   1782 	 * Lookup a reference to the var handle for this
   1783 	 * special var
   1784 	 */
   1785 	for (v = filebench_shm->shm_var_dyn_list; v != NULL; v = v->var_next) {
   1786 		if (strcmp(v->var_name, name) == 0) {
   1787 			var = v;
   1788 			break;
   1789 		}
   1790 	}
   1791 
   1792 	if (var == NULL)
   1793 		var = var_alloc_dynamic(name);
   1794 
   1795 	/* Internal system control variable */
   1796 	if (*name == '{') {
   1797 		rtn = var_find_internal(var);
   1798 		if (rtn == NULL)
   1799 			filebench_log(LOG_ERROR,
   1800 			    "Cannot find internal variable %s",
   1801 			    var->var_name);
   1802 		return (rtn);
   1803 	}
   1804 
   1805 	/* Lookup variable in environment */
   1806 	if (*name == '(') {
   1807 		rtn = var_find_environment(var);
   1808 		if (rtn == NULL)
   1809 			filebench_log(LOG_ERROR,
   1810 			    "Cannot find environment variable %s",
   1811 			    var->var_name);
   1812 		return (rtn);
   1813 	}
   1814 
   1815 	return (NULL);
   1816 }
   1817 
   1818 /*
   1819  * replace the avd_t attribute value descriptor in the new FLOW_MASTER flowop
   1820  * that points to a local variable with a new avd_t containing
   1821  * the actual value from the local variable.
   1822  */
   1823 void
   1824 avd_update(avd_t *avdp, var_t *lvar_list)
   1825 {
   1826 	var_t *old_lvar, *new_lvar;
   1827 
   1828 	if ((*avdp)->avd_type == AVD_IND_VAR) {
   1829 
   1830 		/* Make sure there is a local var */
   1831 		if ((old_lvar = (*avdp)->avd_val.varptr) == NULL) {
   1832 			filebench_log(LOG_ERROR,
   1833 			    "avd_update: local var not found");
   1834 			return;
   1835 		}
   1836 	} else {
   1837 		/* Empty or not indirect, so no update needed */
   1838 		return;
   1839 	}
   1840 
   1841 	/*  allocate a new avd using the new or old lvar contents */
   1842 	if ((new_lvar =
   1843 	    var_find_list(old_lvar->var_name, lvar_list)) != NULL)
   1844 		(*avdp) = avd_alloc_var_ptr(new_lvar);
   1845 	else
   1846 		(*avdp) = avd_alloc_var_ptr(old_lvar);
   1847 }
   1848 
   1849 void
   1850 var_update_comp_lvars(var_t *newlvar, var_t *proto_comp_vars,
   1851     var_t *mstr_lvars)
   1852 {
   1853 	var_t *proto_lvar;
   1854 
   1855 	/* find the prototype lvar from the inherited list */
   1856 	proto_lvar = var_find_list_only(newlvar->var_name, proto_comp_vars);
   1857 
   1858 	if (proto_lvar == NULL)
   1859 		return;
   1860 
   1861 	/*
   1862 	 * if the new local variable has not already been assigned
   1863 	 * a value, try to copy a value from the prototype local variable
   1864 	 */
   1865 	if ((newlvar->var_type & VAR_TYPE_SET_MASK) == 0) {
   1866 
   1867 		/* copy value from prototype lvar to new lvar */
   1868 		(void) var_copy(newlvar, proto_lvar);
   1869 	}
   1870 
   1871 	/* If proto lvar is indirect, see if we can colapse indirection */
   1872 	if (VAR_HAS_INDVAR(proto_lvar)) {
   1873 		var_t *uplvp;
   1874 
   1875 		uplvp = (var_t *)proto_lvar->var_varptr1;
   1876 
   1877 		/* search for more current uplvar on comp master list */
   1878 		if (mstr_lvars) {
   1879 			uplvp = var_find_list_only(
   1880 			    uplvp->var_name, mstr_lvars);
   1881 			VAR_SET_INDVAR(newlvar, uplvp);
   1882 		}
   1883 
   1884 		if (VAR_HAS_INDVAR(uplvp))
   1885 			VAR_SET_INDVAR(newlvar, uplvp->var_varptr1);
   1886 	}
   1887 }
   1888