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