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