15184Sek110237 /*
25184Sek110237  * CDDL HEADER START
35184Sek110237  *
45184Sek110237  * The contents of this file are subject to the terms of the
55184Sek110237  * Common Development and Distribution License (the "License").
65184Sek110237  * You may not use this file except in compliance with the License.
75184Sek110237  *
85184Sek110237  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95184Sek110237  * or http://www.opensolaris.org/os/licensing.
105184Sek110237  * See the License for the specific language governing permissions
115184Sek110237  * and limitations under the License.
125184Sek110237  *
135184Sek110237  * When distributing Covered Code, include this CDDL HEADER in each
145184Sek110237  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155184Sek110237  * If applicable, add the following below this CDDL HEADER, with the
165184Sek110237  * fields enclosed by brackets "[]" replaced with your own identifying
175184Sek110237  * information: Portions Copyright [yyyy] [name of copyright owner]
185184Sek110237  *
195184Sek110237  * CDDL HEADER END
205184Sek110237  */
215184Sek110237 /*
22*6212Saw148015  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
235184Sek110237  * Use is subject to license terms.
245184Sek110237  */
255184Sek110237 
265184Sek110237 #pragma ident	"%Z%%M%	%I%	%E% SMI"
275184Sek110237 
285184Sek110237 #include <stdlib.h>
295184Sek110237 #include <stdio.h>
305184Sek110237 #include <string.h>
315184Sek110237 #include <errno.h>
325184Sek110237 
335184Sek110237 #include "vars.h"
345184Sek110237 #include "misc.h"
355184Sek110237 #include "utils.h"
365184Sek110237 #include "stats.h"
375184Sek110237 #include "eventgen.h"
385184Sek110237 #include "filebench.h"
39*6212Saw148015 #include "fb_random.h"
405184Sek110237 
415184Sek110237 static var_t *var_find_dynamic(char *name);
425184Sek110237 
435184Sek110237 /*
44*6212Saw148015  * The filebench variables system has attribute value descriptors (avd_t)
45*6212Saw148015  * where an avd contains a boolean, integer, double, string, random
46*6212Saw148015  * distribution object ptr, boolean ptr, integer ptr, double ptr,
47*6212Saw148015  * string ptr, or variable ptr. The system also has the variables
48*6212Saw148015  * themselves, (var_t), which are named, typed entities which can be
49*6212Saw148015  * allocated, selected and changed using the "set" command and used in
50*6212Saw148015  * attribute assignments. The variables contain either a boolean, an
51*6212Saw148015  * integer, a double, a string or pointer to an associated random
52*6212Saw148015  * distribution object. Both avd_t and var_t entities are allocated
535184Sek110237  * from interprocess shared memory space.
545184Sek110237  *
55*6212Saw148015  * The attribute descriptors implement delayed binding to variable values,
56*6212Saw148015  * which is necessary because the values of variables may be changed
57*6212Saw148015  * between the time the workload file is loaded and it is actually run,
58*6212Saw148015  * either by further "set" commands in the file or from the command line
59*6212Saw148015  * interface. For random variables, they actually point to the random
60*6212Saw148015  * distribution object, allowing FileBench to invoke the appropriate
61*6212Saw148015  * random distribution function on each access to the attribute. However,
62*6212Saw148015  * for static attributes, the value is just loaded in the descriptor
63*6212Saw148015  * directly, avoiding the need to allocate a variable to hold the static
64*6212Saw148015  * value.
65*6212Saw148015  *
665184Sek110237  * The routines in this module are used to allocate, locate, and
67*6212Saw148015  * manipulate the attribute descriptors, and vars. Routines are
68*6212Saw148015  * also included to convert between the component strings, doubles
69*6212Saw148015  * and integers of vars, and said components of avd_t.
705184Sek110237  */
715184Sek110237 
725184Sek110237 /*
73*6212Saw148015  * returns a pointer to a string indicating the type of data contained
74*6212Saw148015  * in the supplied attribute variable descriptor.
755184Sek110237  */
76*6212Saw148015 static char *
77*6212Saw148015 avd_get_type_string(avd_t avd)
785184Sek110237 {
79*6212Saw148015 	switch (avd->avd_type) {
80*6212Saw148015 	case AVD_INVALID:
81*6212Saw148015 		return ("uninitialized");
82*6212Saw148015 
83*6212Saw148015 	case AVD_VAL_BOOL:
84*6212Saw148015 		return ("boolean value");
85*6212Saw148015 
86*6212Saw148015 	case AVD_VARVAL_BOOL:
87*6212Saw148015 		return ("points to boolean in var_t");
88*6212Saw148015 
89*6212Saw148015 	case AVD_VAL_INT:
90*6212Saw148015 		return ("integer value");
91*6212Saw148015 
92*6212Saw148015 	case AVD_VARVAL_INT:
93*6212Saw148015 		return ("points to integer in var_t");
94*6212Saw148015 
95*6212Saw148015 	case AVD_VAL_STR:
96*6212Saw148015 		return ("string");
97*6212Saw148015 
98*6212Saw148015 	case AVD_VARVAL_STR:
99*6212Saw148015 		return ("points to string in var_t");
100*6212Saw148015 
101*6212Saw148015 	case AVD_VAL_DBL:
102*6212Saw148015 		return ("double float value");
103*6212Saw148015 
104*6212Saw148015 	case AVD_VARVAL_DBL:
105*6212Saw148015 		return ("points to double float in var_t");
106*6212Saw148015 
107*6212Saw148015 	case AVD_IND_VAR:
108*6212Saw148015 		return ("points to a var_t");
109*6212Saw148015 
110*6212Saw148015 	case AVD_IND_RANDVAR:
111*6212Saw148015 		return ("points to var_t's random distribution object");
112*6212Saw148015 
113*6212Saw148015 	default:
114*6212Saw148015 		return ("illegal avd type");
115*6212Saw148015 	}
116*6212Saw148015 }
117*6212Saw148015 
118*6212Saw148015 /*
119*6212Saw148015  * returns a pointer to a string indicating the type of data contained
120*6212Saw148015  * in the supplied variable.
121*6212Saw148015  */
122*6212Saw148015 static char *
123*6212Saw148015 var_get_type_string(var_t *ivp)
124*6212Saw148015 {
125*6212Saw148015 	switch (ivp->var_type & VAR_TYPE_SET_MASK) {
126*6212Saw148015 	case VAR_TYPE_BOOL_SET:
127*6212Saw148015 		return ("boolean");
128*6212Saw148015 
129*6212Saw148015 	case VAR_TYPE_INT_SET:
130*6212Saw148015 		return ("integer");
131*6212Saw148015 
132*6212Saw148015 	case VAR_TYPE_STR_SET:
133*6212Saw148015 		return ("string");
134*6212Saw148015 
135*6212Saw148015 	case VAR_TYPE_DBL_SET:
136*6212Saw148015 		return ("double float");
137*6212Saw148015 
138*6212Saw148015 	case VAR_TYPE_RAND_SET:
139*6212Saw148015 		return ("random");
140*6212Saw148015 
141*6212Saw148015 	default:
142*6212Saw148015 		return ("empty");
143*6212Saw148015 	}
144*6212Saw148015 }
145*6212Saw148015 
146*6212Saw148015 /*
147*6212Saw148015  * Returns the fbint_t pointed to by the supplied avd_t "avd".
148*6212Saw148015  */
149*6212Saw148015 fbint_t
150*6212Saw148015 avd_get_int(avd_t avd)
151*6212Saw148015 {
152*6212Saw148015 	var_t *ivp;
153*6212Saw148015 	randdist_t *rndp;
154*6212Saw148015 
155*6212Saw148015 	if (avd == NULL)
1565184Sek110237 		return (0);
1575184Sek110237 
158*6212Saw148015 	switch (avd->avd_type) {
159*6212Saw148015 	case AVD_VAL_INT:
160*6212Saw148015 		return (avd->avd_val.intval);
161*6212Saw148015 
162*6212Saw148015 	case AVD_VARVAL_INT:
163*6212Saw148015 		if (avd->avd_val.intptr)
164*6212Saw148015 			return (*(avd->avd_val.intptr));
165*6212Saw148015 		else
166*6212Saw148015 			return (0);
167*6212Saw148015 
168*6212Saw148015 	case AVD_IND_VAR:
169*6212Saw148015 		if ((ivp = avd->avd_val.varptr) == NULL)
170*6212Saw148015 			return (0);
171*6212Saw148015 
172*6212Saw148015 		if (VAR_HAS_INTEGER(ivp))
173*6212Saw148015 			return (ivp->var_val.integer);
174*6212Saw148015 
175*6212Saw148015 		if (VAR_HAS_RANDDIST(ivp)) {
176*6212Saw148015 			if ((rndp = ivp->var_val.randptr) != NULL)
177*6212Saw148015 				return ((fbint_t)rndp->rnd_get(rndp));
178*6212Saw148015 		}
179*6212Saw148015 
180*6212Saw148015 		filebench_log(LOG_ERROR,
181*6212Saw148015 		    "Attempt to get integer from %s var $%s",
182*6212Saw148015 		    var_get_type_string(ivp), ivp->var_name);
183*6212Saw148015 		return (0);
184*6212Saw148015 
185*6212Saw148015 	case AVD_IND_RANDVAR:
186*6212Saw148015 		if ((rndp = avd->avd_val.randptr) == NULL)
187*6212Saw148015 			return (0);
188*6212Saw148015 		else
189*6212Saw148015 			return ((fbint_t)rndp->rnd_get(rndp));
190*6212Saw148015 
191*6212Saw148015 	default:
192*6212Saw148015 		filebench_log(LOG_ERROR,
193*6212Saw148015 		    "Attempt to get integer from %s avd",
194*6212Saw148015 		    avd_get_type_string(avd));
195*6212Saw148015 		return (0);
196*6212Saw148015 	}
1975184Sek110237 }
1985184Sek110237 
1995184Sek110237 /*
200*6212Saw148015  * Returns the floating point value of a variable pointed to by the
201*6212Saw148015  * supplied avd_t "avd". Intended to get the actual (double) value
202*6212Saw148015  * supplied by the random variable.
203*6212Saw148015  */
204*6212Saw148015 double
205*6212Saw148015 avd_get_dbl(avd_t avd)
206*6212Saw148015 {
207*6212Saw148015 	var_t *ivp;
208*6212Saw148015 	randdist_t *rndp;
209*6212Saw148015 
210*6212Saw148015 	if (avd == NULL)
211*6212Saw148015 		return (0.0);
212*6212Saw148015 
213*6212Saw148015 	switch (avd->avd_type) {
214*6212Saw148015 	case AVD_VAL_INT:
215*6212Saw148015 		return ((double)avd->avd_val.intval);
216*6212Saw148015 
217*6212Saw148015 	case AVD_VAL_DBL:
218*6212Saw148015 		return (avd->avd_val.dblval);
219*6212Saw148015 
220*6212Saw148015 	case AVD_VARVAL_INT:
221*6212Saw148015 		if (avd->avd_val.intptr)
222*6212Saw148015 			return ((double)(*(avd->avd_val.intptr)));
223*6212Saw148015 		else
224*6212Saw148015 			return (0.0);
225*6212Saw148015 
226*6212Saw148015 	case AVD_VARVAL_DBL:
227*6212Saw148015 		if (avd->avd_val.dblptr)
228*6212Saw148015 			return (*(avd->avd_val.dblptr));
229*6212Saw148015 		else
230*6212Saw148015 			return (0.0);
231*6212Saw148015 
232*6212Saw148015 	case AVD_IND_VAR:
233*6212Saw148015 		ivp = avd->avd_val.varptr;
234*6212Saw148015 
235*6212Saw148015 		if (ivp && VAR_HAS_INTEGER(ivp))
236*6212Saw148015 			return ((double)ivp->var_val.integer);
237*6212Saw148015 
238*6212Saw148015 		if (ivp && VAR_HAS_DOUBLE(ivp))
239*6212Saw148015 			return (ivp->var_val.dbl_flt);
240*6212Saw148015 
241*6212Saw148015 		if (ivp && VAR_HAS_RANDDIST(ivp)) {
242*6212Saw148015 			if ((rndp = ivp->var_val.randptr) != NULL)
243*6212Saw148015 				return (rndp->rnd_get(rndp));
244*6212Saw148015 		}
245*6212Saw148015 		filebench_log(LOG_ERROR,
246*6212Saw148015 		    "Attempt to get double float from %s var $%s",
247*6212Saw148015 		    var_get_type_string(ivp), ivp->var_name);
248*6212Saw148015 		return (0.0);
249*6212Saw148015 
250*6212Saw148015 	case AVD_IND_RANDVAR:
251*6212Saw148015 		if ((rndp = avd->avd_val.randptr) == NULL) {
252*6212Saw148015 			return (0.0);
253*6212Saw148015 		} else
254*6212Saw148015 			return (rndp->rnd_get(rndp));
255*6212Saw148015 
256*6212Saw148015 	default:
257*6212Saw148015 		filebench_log(LOG_ERROR,
258*6212Saw148015 		    "Attempt to get floating point from %s avd",
259*6212Saw148015 		    avd_get_type_string(avd));
260*6212Saw148015 		return (0.0);
261*6212Saw148015 	}
262*6212Saw148015 }
263*6212Saw148015 
264*6212Saw148015 /*
265*6212Saw148015  * Returns the boolean pointed to by the supplied avd_t "avd".
2665184Sek110237  */
267*6212Saw148015 boolean_t
268*6212Saw148015 avd_get_bool(avd_t avd)
2695184Sek110237 {
270*6212Saw148015 	var_t *ivp;
271*6212Saw148015 
272*6212Saw148015 	if (avd == NULL)
273*6212Saw148015 		return (0);
274*6212Saw148015 
275*6212Saw148015 	switch (avd->avd_type) {
276*6212Saw148015 	case AVD_VAL_BOOL:
277*6212Saw148015 		return (avd->avd_val.boolval);
278*6212Saw148015 
279*6212Saw148015 	case AVD_VARVAL_BOOL:
280*6212Saw148015 		if (avd->avd_val.boolptr)
281*6212Saw148015 			return (*(avd->avd_val.boolptr));
282*6212Saw148015 		else
283*6212Saw148015 			return (FALSE);
284*6212Saw148015 
285*6212Saw148015 	/* for backwards compatibility with old workloads */
286*6212Saw148015 	case AVD_VAL_INT:
287*6212Saw148015 		if (avd->avd_val.intval != 0)
288*6212Saw148015 			return (TRUE);
289*6212Saw148015 		else
290*6212Saw148015 			return (FALSE);
291*6212Saw148015 
292*6212Saw148015 	case AVD_VARVAL_INT:
293*6212Saw148015 		if (avd->avd_val.intptr)
294*6212Saw148015 			if (*(avd->avd_val.intptr) != 0)
295*6212Saw148015 				return (TRUE);
296*6212Saw148015 
297*6212Saw148015 		return (FALSE);
298*6212Saw148015 
299*6212Saw148015 	case AVD_IND_VAR:
300*6212Saw148015 		if ((ivp = avd->avd_val.varptr) == NULL)
301*6212Saw148015 			return (0);
302*6212Saw148015 
303*6212Saw148015 		if (VAR_HAS_BOOLEAN(ivp))
304*6212Saw148015 			return (ivp->var_val.boolean);
305*6212Saw148015 
306*6212Saw148015 		if (VAR_HAS_INTEGER(ivp)) {
307*6212Saw148015 			if (ivp->var_val.boolean)
308*6212Saw148015 				return (TRUE);
309*6212Saw148015 			else
310*6212Saw148015 				return (FALSE);
311*6212Saw148015 		}
3125184Sek110237 
313*6212Saw148015 		filebench_log(LOG_ERROR,
314*6212Saw148015 		    "Attempt to get boolean from %s var $%s",
315*6212Saw148015 		    var_get_type_string(ivp), ivp->var_name);
316*6212Saw148015 		return (FALSE);
317*6212Saw148015 
318*6212Saw148015 	default:
319*6212Saw148015 		filebench_log(LOG_ERROR,
320*6212Saw148015 		    "Attempt to get boolean from %s avd",
321*6212Saw148015 		    avd_get_type_string(avd));
322*6212Saw148015 		return (FALSE);
323*6212Saw148015 	}
324*6212Saw148015 }
325*6212Saw148015 
326*6212Saw148015 /*
327*6212Saw148015  * Returns the string pointed to by the supplied avd_t "avd".
328*6212Saw148015  */
329*6212Saw148015 char *
330*6212Saw148015 avd_get_str(avd_t avd)
331*6212Saw148015 {
332*6212Saw148015 	var_t *ivp;
333*6212Saw148015 
334*6212Saw148015 	if (avd == NULL)
335*6212Saw148015 		return (NULL);
336*6212Saw148015 
337*6212Saw148015 	switch (avd->avd_type) {
338*6212Saw148015 	case AVD_VAL_STR:
339*6212Saw148015 		return (avd->avd_val.strval);
340*6212Saw148015 
341*6212Saw148015 	case AVD_VARVAL_STR:
342*6212Saw148015 		if (avd->avd_val.strptr)
343*6212Saw148015 			return (*avd->avd_val.strptr);
344*6212Saw148015 		else
345*6212Saw148015 			return (NULL);
346*6212Saw148015 
347*6212Saw148015 	case AVD_IND_VAR:
348*6212Saw148015 		ivp = avd->avd_val.varptr;
349*6212Saw148015 
350*6212Saw148015 		if (ivp && VAR_HAS_STRING(ivp))
351*6212Saw148015 			return (ivp->var_val.string);
352*6212Saw148015 
353*6212Saw148015 		filebench_log(LOG_ERROR,
354*6212Saw148015 		    "Attempt to get string from %s var $%s",
355*6212Saw148015 		    var_get_type_string(ivp), ivp->var_name);
356*6212Saw148015 		return (NULL);
357*6212Saw148015 
358*6212Saw148015 	default:
359*6212Saw148015 		filebench_log(LOG_ERROR,
360*6212Saw148015 		    "Attempt to get string from %s avd",
361*6212Saw148015 		    avd_get_type_string(avd));
3625184Sek110237 		return (NULL);
3635184Sek110237 	}
364*6212Saw148015 }
3655184Sek110237 
366*6212Saw148015 /*
367*6212Saw148015  * Allocates a avd_t from ipc memory space.
368*6212Saw148015  * logs an error and returns NULL on failure.
369*6212Saw148015  */
370*6212Saw148015 static avd_t
371*6212Saw148015 avd_alloc_cmn(void)
372*6212Saw148015 {
373*6212Saw148015 	avd_t rtn;
3745184Sek110237 
375*6212Saw148015 	if ((rtn = (avd_t)ipc_malloc(FILEBENCH_AVD)) == NULL)
376*6212Saw148015 		filebench_log(LOG_ERROR, "Avd alloc failed");
3775184Sek110237 
3785184Sek110237 	return (rtn);
3795184Sek110237 }
3805184Sek110237 
3815184Sek110237 /*
382*6212Saw148015  * pre-loads the allocated avd_t with the boolean_t "bool".
383*6212Saw148015  * Returns the avd_t on success, NULL on failure.
384*6212Saw148015  */
385*6212Saw148015 avd_t
386*6212Saw148015 avd_bool_alloc(boolean_t bool)
387*6212Saw148015 {
388*6212Saw148015 	avd_t avd;
389*6212Saw148015 
390*6212Saw148015 	if ((avd = avd_alloc_cmn()) == NULL)
391*6212Saw148015 		return (NULL);
392*6212Saw148015 
393*6212Saw148015 	avd->avd_type = AVD_VAL_BOOL;
394*6212Saw148015 	avd->avd_val.boolval = bool;
395*6212Saw148015 
396*6212Saw148015 	filebench_log(LOG_DEBUG_IMPL, "Alloc boolean %d", bool);
397*6212Saw148015 
398*6212Saw148015 	return (avd);
399*6212Saw148015 }
400*6212Saw148015 
401*6212Saw148015 /*
402*6212Saw148015  * pre-loads the allocated avd_t with the fbint_t "integer".
403*6212Saw148015  * Returns the avd_t on success, NULL on failure.
404*6212Saw148015  */
405*6212Saw148015 avd_t
406*6212Saw148015 avd_int_alloc(fbint_t integer)
407*6212Saw148015 {
408*6212Saw148015 	avd_t avd;
409*6212Saw148015 
410*6212Saw148015 	if ((avd = avd_alloc_cmn()) == NULL)
411*6212Saw148015 		return (NULL);
412*6212Saw148015 
413*6212Saw148015 	avd->avd_type = AVD_VAL_INT;
414*6212Saw148015 	avd->avd_val.intval = integer;
415*6212Saw148015 
416*6212Saw148015 	filebench_log(LOG_DEBUG_IMPL, "Alloc integer %lld", integer);
417*6212Saw148015 
418*6212Saw148015 	return (avd);
419*6212Saw148015 }
420*6212Saw148015 
421*6212Saw148015 /*
422*6212Saw148015  * Gets a avd_t and points it to the var that
423*6212Saw148015  * it will eventually be filled from
4245184Sek110237  */
425*6212Saw148015 static avd_t
426*6212Saw148015 avd_alloc_var_ptr(var_t *var)
4275184Sek110237 {
428*6212Saw148015 	avd_t avd;
429*6212Saw148015 
430*6212Saw148015 	if (var == NULL)
431*6212Saw148015 		return (NULL);
432*6212Saw148015 
433*6212Saw148015 	if ((avd = avd_alloc_cmn()) == NULL)
434*6212Saw148015 		return (NULL);
435*6212Saw148015 
436*6212Saw148015 	switch (var->var_type & VAR_TYPE_SET_MASK) {
437*6212Saw148015 	case VAR_TYPE_BOOL_SET:
438*6212Saw148015 		avd->avd_type = AVD_VARVAL_BOOL;
439*6212Saw148015 		avd->avd_val.boolptr = (&var->var_val.boolean);
440*6212Saw148015 		break;
441*6212Saw148015 
442*6212Saw148015 	case VAR_TYPE_INT_SET:
443*6212Saw148015 		avd->avd_type = AVD_VARVAL_INT;
444*6212Saw148015 		avd->avd_val.intptr = (&var->var_val.integer);
445*6212Saw148015 		break;
446*6212Saw148015 
447*6212Saw148015 	case VAR_TYPE_STR_SET:
448*6212Saw148015 		avd->avd_type = AVD_VARVAL_STR;
449*6212Saw148015 		avd->avd_val.strptr = &(var->var_val.string);
450*6212Saw148015 		break;
4515184Sek110237 
452*6212Saw148015 	case VAR_TYPE_DBL_SET:
453*6212Saw148015 		avd->avd_type = AVD_VARVAL_DBL;
454*6212Saw148015 		avd->avd_val.dblptr = &(var->var_val.dbl_flt);
455*6212Saw148015 		break;
456*6212Saw148015 
457*6212Saw148015 	case VAR_TYPE_RAND_SET:
458*6212Saw148015 		avd->avd_type = AVD_IND_RANDVAR;
459*6212Saw148015 		avd->avd_val.randptr = var->var_val.randptr;
460*6212Saw148015 		break;
461*6212Saw148015 
462*6212Saw148015 	default:
463*6212Saw148015 		avd->avd_type = AVD_IND_VAR;
464*6212Saw148015 		avd->avd_val.varptr = var;
465*6212Saw148015 		break;
466*6212Saw148015 	}
467*6212Saw148015 	return (avd);
468*6212Saw148015 }
469*6212Saw148015 
470*6212Saw148015 /*
471*6212Saw148015  * Gets a avd_t, then allocates and initializes a piece of
472*6212Saw148015  * shared string memory, putting the pointer to it into the just
473*6212Saw148015  * allocated string pointer location. The routine returns a pointer
474*6212Saw148015  * to the string pointer location or returns NULL on error.
475*6212Saw148015  */
476*6212Saw148015 avd_t
477*6212Saw148015 avd_str_alloc(char *string)
478*6212Saw148015 {
479*6212Saw148015 	avd_t avd;
480*6212Saw148015 
481*6212Saw148015 	if (string == NULL) {
482*6212Saw148015 		filebench_log(LOG_ERROR, "No string supplied\n");
4835184Sek110237 		return (NULL);
4845184Sek110237 	}
4855184Sek110237 
486*6212Saw148015 	if ((avd = avd_alloc_cmn()) == NULL)
487*6212Saw148015 		return (NULL);
488*6212Saw148015 
489*6212Saw148015 	avd->avd_type = AVD_VAL_STR;
490*6212Saw148015 	avd->avd_val.strval = ipc_stralloc(string);
4915184Sek110237 
4925184Sek110237 	filebench_log(LOG_DEBUG_IMPL,
4935184Sek110237 	    "Alloc string %s ptr %zx",
494*6212Saw148015 	    string, avd);
4955184Sek110237 
496*6212Saw148015 	return (avd);
4975184Sek110237 }
4985184Sek110237 
4995184Sek110237 /*
5005184Sek110237  * Allocates a var (var_t) from interprocess shared memory.
5015184Sek110237  * Places the allocated var on the end of the globally shared
5025184Sek110237  * var_list. Finally, the routine allocates a string containing
5035184Sek110237  * a copy of the supplied "name" string. If any allocations
5045184Sek110237  * fails, returns NULL, otherwise it returns a pointer to the
5055184Sek110237  * newly allocated var.
5065184Sek110237  */
5075184Sek110237 static var_t *
508*6212Saw148015 var_alloc_cmn(char *name, int var_type)
5095184Sek110237 {
510*6212Saw148015 	var_t **var_listp;
5115184Sek110237 	var_t *var = NULL;
5125184Sek110237 	var_t *prev = NULL;
5135184Sek110237 	var_t *newvar;
5145184Sek110237 
5155184Sek110237 	if ((newvar = (var_t *)ipc_malloc(FILEBENCH_VARIABLE)) == NULL) {
5165184Sek110237 		filebench_log(LOG_ERROR, "Out of memory for variables");
5175184Sek110237 		return (NULL);
5185184Sek110237 	}
5195184Sek110237 	(void) memset(newvar, 0, sizeof (newvar));
520*6212Saw148015 	newvar->var_type = var_type;
5215184Sek110237 
5225184Sek110237 	if ((newvar->var_name = ipc_stralloc(name)) == NULL) {
5235184Sek110237 		filebench_log(LOG_ERROR, "Out of memory for variables");
5245184Sek110237 		return (NULL);
5255184Sek110237 	}
5265184Sek110237 
527*6212Saw148015 	switch (var_type & VAR_TYPE_MASK) {
528*6212Saw148015 	case VAR_TYPE_RANDOM:
529*6212Saw148015 	case VAR_TYPE_GLOBAL:
530*6212Saw148015 		var_listp = &filebench_shm->var_list;
531*6212Saw148015 		break;
532*6212Saw148015 
533*6212Saw148015 	case VAR_TYPE_DYNAMIC:
534*6212Saw148015 		var_listp = &filebench_shm->var_dyn_list;
535*6212Saw148015 		break;
536*6212Saw148015 
537*6212Saw148015 	default:
538*6212Saw148015 		var_listp = &filebench_shm->var_list;
539*6212Saw148015 		break;
540*6212Saw148015 	}
541*6212Saw148015 
542*6212Saw148015 	/* add to the end of list */
543*6212Saw148015 	for (var = *var_listp; var != NULL; var = var->var_next)
544*6212Saw148015 		prev = var; /* Find end of list */
545*6212Saw148015 	if (prev != NULL)
546*6212Saw148015 		prev->var_next = newvar;
547*6212Saw148015 	else
548*6212Saw148015 		*var_listp = newvar;
549*6212Saw148015 
5505184Sek110237 	return (newvar);
5515184Sek110237 }
5525184Sek110237 
5535184Sek110237 /*
554*6212Saw148015  * Allocates a var (var_t) from interprocess shared memory and
555*6212Saw148015  * places the allocated var on the end of the globally shared
556*6212Saw148015  * var_list. If the allocation fails, returns NULL, otherwise
557*6212Saw148015  * it returns a pointer to the newly allocated var.
558*6212Saw148015  */
559*6212Saw148015 static var_t *
560*6212Saw148015 var_alloc(char *name)
561*6212Saw148015 {
562*6212Saw148015 	return (var_alloc_cmn(name, VAR_TYPE_GLOBAL));
563*6212Saw148015 }
564*6212Saw148015 
565*6212Saw148015 /*
5665184Sek110237  * Allocates a var (var_t) from interprocess shared memory.
5675184Sek110237  * Places the allocated var on the end of the globally shared
568*6212Saw148015  * var_dyn_list. If the allocation fails, returns NULL, otherwise
569*6212Saw148015  * it returns a pointer to the newly allocated var.
5705184Sek110237  */
5715184Sek110237 static var_t *
5725184Sek110237 var_alloc_dynamic(char *name)
5735184Sek110237 {
574*6212Saw148015 	return (var_alloc_cmn(name, VAR_TYPE_DYNAMIC));
5755184Sek110237 }
5765184Sek110237 
5775184Sek110237 /*
5785184Sek110237  * Searches for var_t with name "name" in the master var_list.
5795184Sek110237  * If successful, returns a pointer to the var_t, otherwise
5805184Sek110237  * returns NULL.
5815184Sek110237  */
5825184Sek110237 static var_t *
5835184Sek110237 var_find(char *name)
5845184Sek110237 {
5855184Sek110237 	var_t *var;
5865184Sek110237 
5875184Sek110237 	for (var = filebench_shm->var_list; var != NULL; var = var->var_next) {
5885184Sek110237 		if (strcmp(var->var_name, name) == 0)
5895184Sek110237 			return (var);
5905184Sek110237 	}
5915184Sek110237 
5925184Sek110237 	return (NULL);
5935184Sek110237 }
5945184Sek110237 
5955184Sek110237 /*
5965184Sek110237  * Searches for the named var, and, if found, sets its
597*6212Saw148015  * var_val.boolean's value to that of the supplied boolean.
5985184Sek110237  * If not found, the routine allocates a new var and sets
599*6212Saw148015  * its var_val.boolean's value to that of the supplied
600*6212Saw148015  * boolean. If the named var cannot be found or allocated
601*6212Saw148015  * the routine returns -1, otherwise it returns 0.
6025184Sek110237  */
6035184Sek110237 int
604*6212Saw148015 var_assign_boolean(char *name, boolean_t bool)
6055184Sek110237 {
6065184Sek110237 	var_t *var;
6075184Sek110237 
608*6212Saw148015 	if (name == NULL) {
609*6212Saw148015 		filebench_log(LOG_ERROR,
610*6212Saw148015 		    "var_assign_boolean: Name not supplied");
611*6212Saw148015 		return (0);
612*6212Saw148015 	}
613*6212Saw148015 
6145184Sek110237 	name += 1;
6155184Sek110237 
616*6212Saw148015 	if ((var = var_find(name)) == NULL) {
617*6212Saw148015 			var = var_alloc(name);
618*6212Saw148015 	}
6195184Sek110237 
6205184Sek110237 	if (var == NULL) {
6215184Sek110237 		filebench_log(LOG_ERROR, "Cannot assign variable %s",
6225184Sek110237 		    name);
6235184Sek110237 		return (-1);
6245184Sek110237 	}
6255184Sek110237 
626*6212Saw148015 	if ((var->var_type & VAR_TYPE_MASK) == VAR_TYPE_RANDOM) {
627*6212Saw148015 		filebench_log(LOG_ERROR,
628*6212Saw148015 		    "Cannot assign integer to random variable %s", name);
629*6212Saw148015 		return (-1);
630*6212Saw148015 	}
631*6212Saw148015 
632*6212Saw148015 	VAR_SET_BOOL(var, bool);
633*6212Saw148015 
634*6212Saw148015 	filebench_log(LOG_DEBUG_SCRIPT, "Assign boolean %s=%d",
635*6212Saw148015 	    name, bool);
636*6212Saw148015 
637*6212Saw148015 	return (0);
638*6212Saw148015 }
639*6212Saw148015 
640*6212Saw148015 /*
641*6212Saw148015  * Searches for the named var, and, if found, sets its
642*6212Saw148015  * var_integer's value to that of the supplied integer.
643*6212Saw148015  * If not found, the routine allocates a new var and sets
644*6212Saw148015  * its var_integers's value to that of the supplied
645*6212Saw148015  * integer. If the named var cannot be found or allocated
646*6212Saw148015  * the routine returns -1, otherwise it returns 0.
647*6212Saw148015  */
648*6212Saw148015 int
649*6212Saw148015 var_assign_integer(char *name, fbint_t integer)
650*6212Saw148015 {
651*6212Saw148015 	var_t *var;
652*6212Saw148015 
653*6212Saw148015 	if (name == NULL) {
654*6212Saw148015 		filebench_log(LOG_ERROR,
655*6212Saw148015 		    "var_assign_integer: Name not supplied");
656*6212Saw148015 		return (0);
657*6212Saw148015 	}
658*6212Saw148015 
659*6212Saw148015 	name += 1;
660*6212Saw148015 
661*6212Saw148015 	if ((var = var_find(name)) == NULL) {
662*6212Saw148015 			var = var_alloc(name);
663*6212Saw148015 	}
664*6212Saw148015 
665*6212Saw148015 	if (var == NULL) {
666*6212Saw148015 		filebench_log(LOG_ERROR, "Cannot assign variable %s",
667*6212Saw148015 		    name);
668*6212Saw148015 		return (-1);
669*6212Saw148015 	}
670*6212Saw148015 
671*6212Saw148015 	if ((var->var_type & VAR_TYPE_MASK) == VAR_TYPE_RANDOM) {
672*6212Saw148015 		filebench_log(LOG_ERROR,
673*6212Saw148015 		    "Cannot assign integer to random variable %s", name);
674*6212Saw148015 		return (-1);
675*6212Saw148015 	}
676*6212Saw148015 
677*6212Saw148015 	VAR_SET_INT(var, integer);
6785184Sek110237 
6795184Sek110237 	filebench_log(LOG_DEBUG_SCRIPT, "Assign integer %s=%lld",
6805184Sek110237 	    name, integer);
6815184Sek110237 
6825184Sek110237 	return (0);
6835184Sek110237 }
6845184Sek110237 
6855184Sek110237 /*
686*6212Saw148015  * Find a variable, and set it to random type.
687*6212Saw148015  * If it does not have a random extension, allocate one
688*6212Saw148015  */
689*6212Saw148015 var_t *
690*6212Saw148015 var_find_randvar(char *name)
691*6212Saw148015 {
692*6212Saw148015 	var_t *newvar;
693*6212Saw148015 
694*6212Saw148015 	name += 1;
695*6212Saw148015 
696*6212Saw148015 	if ((newvar = var_find(name)) == NULL) {
697*6212Saw148015 		filebench_log(LOG_ERROR,
698*6212Saw148015 		    "failed to locate random variable $%s\n", name);
699*6212Saw148015 		return (NULL);
700*6212Saw148015 	}
701*6212Saw148015 
702*6212Saw148015 	/* set randdist pointer unless it is already set */
703*6212Saw148015 	if (((newvar->var_type & VAR_TYPE_MASK) != VAR_TYPE_RANDOM) ||
704*6212Saw148015 	    !VAR_HAS_RANDDIST(newvar)) {
705*6212Saw148015 		filebench_log(LOG_ERROR,
706*6212Saw148015 		    "Found variable $%s not random\n", name);
707*6212Saw148015 		return (NULL);
708*6212Saw148015 	}
709*6212Saw148015 
710*6212Saw148015 	return (newvar);
711*6212Saw148015 }
712*6212Saw148015 
713*6212Saw148015 /*
714*6212Saw148015  * Allocate a variable, and set it to random type. Then
715*6212Saw148015  * allocate a random extension.
716*6212Saw148015  */
717*6212Saw148015 var_t *
718*6212Saw148015 var_define_randvar(char *name)
719*6212Saw148015 {
720*6212Saw148015 	var_t *newvar;
721*6212Saw148015 	randdist_t *rndp = NULL;
722*6212Saw148015 
723*6212Saw148015 	name += 1;
724*6212Saw148015 
725*6212Saw148015 	/* make sure variable doesn't already exist */
726*6212Saw148015 	if (var_find(name) != NULL) {
727*6212Saw148015 		filebench_log(LOG_ERROR,
728*6212Saw148015 		    "variable name already in use\n");
729*6212Saw148015 		return (NULL);
730*6212Saw148015 	}
731*6212Saw148015 
732*6212Saw148015 	/* allocate a random variable */
733*6212Saw148015 	if ((newvar = var_alloc_cmn(name, VAR_TYPE_RANDOM)) == NULL) {
734*6212Saw148015 		filebench_log(LOG_ERROR,
735*6212Saw148015 		    "failed to alloc random variable\n");
736*6212Saw148015 		return (NULL);
737*6212Saw148015 	}
738*6212Saw148015 
739*6212Saw148015 	/* set randdist pointer */
740*6212Saw148015 	if ((rndp = randdist_alloc()) == NULL) {
741*6212Saw148015 		filebench_log(LOG_ERROR,
742*6212Saw148015 		    "failed to alloc random distribution object\n");
743*6212Saw148015 		return (NULL);
744*6212Saw148015 	}
745*6212Saw148015 
746*6212Saw148015 	rndp->rnd_var = newvar;
747*6212Saw148015 	VAR_SET_RAND(newvar, rndp);
748*6212Saw148015 
749*6212Saw148015 	return (newvar);
750*6212Saw148015 }
751*6212Saw148015 
752*6212Saw148015 /*
753*6212Saw148015  * Searches for the named var, and if found returns an avd_t
754*6212Saw148015  * pointing to the var's var_integer, var_string or var_double
755*6212Saw148015  * as appropriate. If not found, attempts to allocate
756*6212Saw148015  * a var named "name" and returns an avd_t to it with
757*6212Saw148015  * no value set. If the var cannot be found or allocated, an
7585184Sek110237  * error is logged and the run is terminated.
7595184Sek110237  */
760*6212Saw148015 avd_t
761*6212Saw148015 var_ref_attr(char *name)
7625184Sek110237 {
7635184Sek110237 	var_t *var;
7645184Sek110237 
7655184Sek110237 	name += 1;
7665184Sek110237 
7675184Sek110237 	if ((var = var_find(name)) == NULL)
7685184Sek110237 		var = var_find_dynamic(name);
7695184Sek110237 
7705184Sek110237 	if (var == NULL)
7715184Sek110237 		var = var_alloc(name);
7725184Sek110237 
7735184Sek110237 	if (var == NULL) {
7745184Sek110237 		filebench_log(LOG_ERROR, "Invalid variable $%s",
7755184Sek110237 		    name);
7765184Sek110237 		filebench_shutdown(1);
7775184Sek110237 	}
7785184Sek110237 
779*6212Saw148015 	/* allocate pointer to var and return */
780*6212Saw148015 	return (avd_alloc_var_ptr(var));
7815184Sek110237 }
7825184Sek110237 
783*6212Saw148015 
7845184Sek110237 /*
785*6212Saw148015  * Searches for the named var, and if found copies the var_val.string,
786*6212Saw148015  * if it exists, a decimal number string representation of
787*6212Saw148015  * var_val.integer, the state of var_val.boolean, or the type of random
788*6212Saw148015  * distribution employed, into a malloc'd bit of memory using fb_stralloc().
7895184Sek110237  * Returns a pointer to the created string, or NULL on failure.
7905184Sek110237  */
7915184Sek110237 char *
7925184Sek110237 var_to_string(char *name)
7935184Sek110237 {
7945184Sek110237 	var_t *var;
7955184Sek110237 	char tmp[128];
7965184Sek110237 
7975184Sek110237 	name += 1;
7985184Sek110237 
7995184Sek110237 	if ((var = var_find(name)) == NULL)
8005184Sek110237 		var = var_find_dynamic(name);
8015184Sek110237 
8025184Sek110237 	if (var == NULL)
8035184Sek110237 		return (NULL);
8045184Sek110237 
805*6212Saw148015 	if ((var->var_type & VAR_TYPE_MASK) == VAR_TYPE_RANDOM) {
806*6212Saw148015 		switch (var->var_val.randptr->rnd_type & RAND_TYPE_MASK) {
807*6212Saw148015 		case RAND_TYPE_UNIFORM:
808*6212Saw148015 			return (fb_stralloc("uniform random var"));
809*6212Saw148015 		case RAND_TYPE_GAMMA:
810*6212Saw148015 			return (fb_stralloc("gamma random var"));
811*6212Saw148015 		case RAND_TYPE_TABLE:
812*6212Saw148015 			return (fb_stralloc("tabular random var"));
813*6212Saw148015 		default:
814*6212Saw148015 			return (fb_stralloc("unitialized random var"));
815*6212Saw148015 		}
816*6212Saw148015 	}
8175184Sek110237 
818*6212Saw148015 	if (VAR_HAS_STRING(var) && var->var_val.string)
819*6212Saw148015 		return (fb_stralloc(var->var_val.string));
8205184Sek110237 
821*6212Saw148015 	if (VAR_HAS_BOOLEAN(var)) {
822*6212Saw148015 		if (var->var_val.boolean)
823*6212Saw148015 			return (fb_stralloc("true"));
824*6212Saw148015 		else
825*6212Saw148015 			return (fb_stralloc("false"));
826*6212Saw148015 	}
827*6212Saw148015 
828*6212Saw148015 	if (VAR_HAS_INTEGER(var)) {
829*6212Saw148015 		(void) snprintf(tmp, sizeof (tmp), "%lld",
830*6212Saw148015 		    var->var_val.integer);
831*6212Saw148015 		return (fb_stralloc(tmp));
832*6212Saw148015 	}
833*6212Saw148015 
834*6212Saw148015 	return (fb_stralloc("No default"));
8355184Sek110237 }
8365184Sek110237 
8375184Sek110237 /*
8385184Sek110237  * Searches for the named var, and if found returns the value,
839*6212Saw148015  * of var_val.boolean. If the var is not found, or a boolean
840*6212Saw148015  * value has not been set, logs an error and returns 0.
8415184Sek110237  */
842*6212Saw148015 boolean_t
843*6212Saw148015 var_to_boolean(char *name)
844*6212Saw148015 {
845*6212Saw148015 	var_t *var;
846*6212Saw148015 
847*6212Saw148015 	name += 1;
848*6212Saw148015 
849*6212Saw148015 	if ((var = var_find(name)) == NULL)
850*6212Saw148015 		var = var_find_dynamic(name);
851*6212Saw148015 
852*6212Saw148015 	if ((var != NULL) && VAR_HAS_BOOLEAN(var))
853*6212Saw148015 		return (var->var_val.boolean);
854*6212Saw148015 
855*6212Saw148015 	filebench_log(LOG_ERROR,
856*6212Saw148015 	    "Variable %s referenced before set", name);
857*6212Saw148015 
858*6212Saw148015 	return (0);
859*6212Saw148015 }
860*6212Saw148015 
861*6212Saw148015 /*
862*6212Saw148015  * Searches for the named var, and if found returns the value,
863*6212Saw148015  * of var_val.integer. If the var is not found, or the an
864*6212Saw148015  * integer value has not been set, logs an error and returns 0.
865*6212Saw148015  */
866*6212Saw148015 fbint_t
8675184Sek110237 var_to_integer(char *name)
8685184Sek110237 {
8695184Sek110237 	var_t *var;
8705184Sek110237 
8715184Sek110237 	name += 1;
8725184Sek110237 
8735184Sek110237 	if ((var = var_find(name)) == NULL)
8745184Sek110237 		var = var_find_dynamic(name);
8755184Sek110237 
876*6212Saw148015 	if ((var != NULL) && VAR_HAS_INTEGER(var))
877*6212Saw148015 		return (var->var_val.integer);
8785184Sek110237 
8795184Sek110237 	filebench_log(LOG_ERROR,
8805184Sek110237 	    "Variable %s referenced before set", name);
8815184Sek110237 
8825184Sek110237 	return (0);
8835184Sek110237 }
8845184Sek110237 
8855184Sek110237 /*
886*6212Saw148015  * Searches for the named random var, and if found, converts the
887*6212Saw148015  * requested parameter into a string or a decimal number string
888*6212Saw148015  * representation, into a malloc'd bit of memory using fb_stralloc().
889*6212Saw148015  * Returns a pointer to the created string, or calls var_to_string()
890*6212Saw148015  * if a random variable isn't found.
891*6212Saw148015  */
892*6212Saw148015 char *
893*6212Saw148015 var_randvar_to_string(char *name, int param_name)
894*6212Saw148015 {
895*6212Saw148015 	var_t *var;
896*6212Saw148015 	fbint_t value;
897*6212Saw148015 
898*6212Saw148015 	if ((var = var_find(name + 1)) == NULL)
899*6212Saw148015 		return (var_to_string(name));
900*6212Saw148015 
901*6212Saw148015 	if (((var->var_type & VAR_TYPE_MASK) != VAR_TYPE_RANDOM) ||
902*6212Saw148015 	    !VAR_HAS_RANDDIST(var))
903*6212Saw148015 		return (var_to_string(name));
904*6212Saw148015 
905*6212Saw148015 	switch (param_name) {
906*6212Saw148015 	case RAND_PARAM_TYPE:
907*6212Saw148015 		switch (var->var_val.randptr->rnd_type & RAND_TYPE_MASK) {
908*6212Saw148015 		case RAND_TYPE_UNIFORM:
909*6212Saw148015 			return (fb_stralloc("uniform"));
910*6212Saw148015 		case RAND_TYPE_GAMMA:
911*6212Saw148015 			return (fb_stralloc("gamma"));
912*6212Saw148015 		case RAND_TYPE_TABLE:
913*6212Saw148015 			return (fb_stralloc("tabular"));
914*6212Saw148015 		default:
915*6212Saw148015 			return (fb_stralloc("uninitialized"));
916*6212Saw148015 		}
917*6212Saw148015 
918*6212Saw148015 	case RAND_PARAM_SRC:
919*6212Saw148015 		if (var->var_val.randptr->rnd_type & RAND_SRC_GENERATOR)
920*6212Saw148015 			return (fb_stralloc("rand48"));
921*6212Saw148015 		else
922*6212Saw148015 			return (fb_stralloc("urandom"));
923*6212Saw148015 
924*6212Saw148015 	case RAND_PARAM_SEED:
925*6212Saw148015 		value = avd_get_int(var->var_val.randptr->rnd_seed);
926*6212Saw148015 		break;
927*6212Saw148015 
928*6212Saw148015 	case RAND_PARAM_MIN:
929*6212Saw148015 		value = avd_get_int(var->var_val.randptr->rnd_min);
930*6212Saw148015 		break;
931*6212Saw148015 
932*6212Saw148015 	case RAND_PARAM_MEAN:
933*6212Saw148015 		value = avd_get_int(var->var_val.randptr->rnd_mean);
934*6212Saw148015 		break;
935*6212Saw148015 
936*6212Saw148015 	case RAND_PARAM_GAMMA:
937*6212Saw148015 		value = avd_get_int(var->var_val.randptr->rnd_gamma);
938*6212Saw148015 		break;
939*6212Saw148015 
940*6212Saw148015 	case RAND_PARAM_ROUND:
941*6212Saw148015 		value = avd_get_int(var->var_val.randptr->rnd_round);
942*6212Saw148015 		break;
943*6212Saw148015 
944*6212Saw148015 	default:
945*6212Saw148015 		return (NULL);
946*6212Saw148015 
947*6212Saw148015 	}
948*6212Saw148015 
949*6212Saw148015 	/* just an integer value if we got here */
950*6212Saw148015 	{
951*6212Saw148015 		char tmp[128];
952*6212Saw148015 
953*6212Saw148015 		(void) snprintf(tmp, sizeof (tmp), "%lld", value);
954*6212Saw148015 		return (fb_stralloc(tmp));
955*6212Saw148015 	}
956*6212Saw148015 }
957*6212Saw148015 
958*6212Saw148015 /*
9595184Sek110237  * Searches for the var named "name", and if not found
9605184Sek110237  * allocates it. The then extracts the var_string from
9615184Sek110237  * the var named "string" and copies it into the var_string
9625184Sek110237  * of the var "name", after first allocating a piece of
9635184Sek110237  * interprocess shared string memory. If the var "name"
9645184Sek110237  * cannot be found or allocated, or the var "string" cannot
9655184Sek110237  * be found, the routine returns -1, otherwise it returns 0.
9665184Sek110237  */
9675184Sek110237 int
968*6212Saw148015 var_assign_var(char *name, char *src_name)
9695184Sek110237 {
970*6212Saw148015 	var_t *dst_var, *src_var;
9715184Sek110237 
9725184Sek110237 	name += 1;
973*6212Saw148015 	src_name += 1;
9745184Sek110237 
975*6212Saw148015 	if ((src_var = var_find(src_name)) == NULL) {
976*6212Saw148015 		filebench_log(LOG_ERROR,
977*6212Saw148015 		    "Cannot find source variable %s", src_name);
978*6212Saw148015 		return (-1);
979*6212Saw148015 	}
9805184Sek110237 
981*6212Saw148015 	if ((dst_var = var_find(name)) == NULL)
982*6212Saw148015 		dst_var = var_alloc(name);
983*6212Saw148015 
984*6212Saw148015 	if (dst_var == NULL) {
9855184Sek110237 		filebench_log(LOG_ERROR, "Cannot assign variable %s",
9865184Sek110237 		    name);
9875184Sek110237 		return (-1);
9885184Sek110237 	}
9895184Sek110237 
990*6212Saw148015 	if ((dst_var->var_type & VAR_TYPE_MASK) == VAR_TYPE_RANDOM) {
991*6212Saw148015 		filebench_log(LOG_ERROR,
992*6212Saw148015 		    "Cannot assign var to Random variable %s", name);
9935184Sek110237 		return (-1);
9945184Sek110237 	}
995*6212Saw148015 
996*6212Saw148015 	if (VAR_HAS_BOOLEAN(src_var)) {
997*6212Saw148015 		VAR_SET_BOOL(dst_var, src_var->var_val.boolean);
998*6212Saw148015 		filebench_log(LOG_VERBOSE,
999*6212Saw148015 		    "Assign var %s=%d", name, src_var->var_val.boolean);
1000*6212Saw148015 	}
1001*6212Saw148015 
1002*6212Saw148015 	if (VAR_HAS_INTEGER(src_var)) {
1003*6212Saw148015 		VAR_SET_INT(dst_var, src_var->var_val.integer);
1004*6212Saw148015 		filebench_log(LOG_VERBOSE,
1005*6212Saw148015 		    "Assign var %s=%lld", name, src_var->var_val.integer);
1006*6212Saw148015 	}
1007*6212Saw148015 
1008*6212Saw148015 	if (VAR_HAS_DOUBLE(src_var)) {
1009*6212Saw148015 		VAR_SET_DBL(dst_var, src_var->var_val.dbl_flt);
1010*6212Saw148015 		filebench_log(LOG_VERBOSE,
1011*6212Saw148015 		    "Assign var %s=%lf", name, src_var->var_val.dbl_flt);
1012*6212Saw148015 	}
1013*6212Saw148015 
1014*6212Saw148015 	if (VAR_HAS_STRING(src_var)) {
1015*6212Saw148015 		char *strptr;
1016*6212Saw148015 
1017*6212Saw148015 		if ((strptr =
1018*6212Saw148015 		    ipc_stralloc(src_var->var_val.string)) == NULL) {
1019*6212Saw148015 			filebench_log(LOG_ERROR,
1020*6212Saw148015 			    "Cannot assign variable %s",
1021*6212Saw148015 			    name);
1022*6212Saw148015 			return (-1);
1023*6212Saw148015 		}
1024*6212Saw148015 		VAR_SET_STR(dst_var, strptr);
1025*6212Saw148015 		filebench_log(LOG_VERBOSE,
1026*6212Saw148015 		    "Assign var %s=%s", name, src_var->var_val.string);
1027*6212Saw148015 	}
10285184Sek110237 	return (0);
10295184Sek110237 }
10305184Sek110237 
10315184Sek110237 /*
10325184Sek110237  * Like var_assign_integer, only this routine copies the
10335184Sek110237  * supplied "string" into the var named "name". If the var
10345184Sek110237  * named "name" cannot be found then it is first allocated
10355184Sek110237  * before the copy. Space for the string in the var comes
10365184Sek110237  * from interprocess shared memory. If the var "name"
10375184Sek110237  * cannot be found or allocated, or the memory for the
10385184Sek110237  * var_string copy of "string" cannot be allocated, the
10395184Sek110237  * routine returns -1, otherwise it returns 0.
10405184Sek110237  */
10415184Sek110237 int
10425184Sek110237 var_assign_string(char *name, char *string)
10435184Sek110237 {
10445184Sek110237 	var_t *var;
1045*6212Saw148015 	char *strptr;
10465184Sek110237 
10475184Sek110237 	name += 1;
10485184Sek110237 
10495184Sek110237 	if ((var = var_find(name)) == NULL)
10505184Sek110237 		var = var_alloc(name);
10515184Sek110237 
10525184Sek110237 	if (var == NULL) {
10535184Sek110237 		filebench_log(LOG_ERROR, "Cannot assign variable %s",
10545184Sek110237 		    name);
10555184Sek110237 		return (-1);
10565184Sek110237 	}
10575184Sek110237 
1058*6212Saw148015 	if ((var->var_type & VAR_TYPE_MASK) == VAR_TYPE_RANDOM) {
1059*6212Saw148015 		filebench_log(LOG_ERROR,
1060*6212Saw148015 		    "Cannot assign string to random variable %s", name);
1061*6212Saw148015 		return (-1);
1062*6212Saw148015 	}
1063*6212Saw148015 
1064*6212Saw148015 	if ((strptr = ipc_stralloc(string)) == NULL) {
10655184Sek110237 		filebench_log(LOG_ERROR, "Cannot assign variable %s",
10665184Sek110237 		    name);
10675184Sek110237 		return (-1);
10685184Sek110237 	}
1069*6212Saw148015 	VAR_SET_STR(var, strptr);
10705184Sek110237 
1071*6212Saw148015 	filebench_log(LOG_DEBUG_SCRIPT,
1072*6212Saw148015 	    "Var assign string $%s=%s", name, string);
10735184Sek110237 
10745184Sek110237 	return (0);
10755184Sek110237 }
10765184Sek110237 
10775184Sek110237 /*
1078*6212Saw148015  * Tests to see if the supplied variable name without the portion after
1079*6212Saw148015  * the last period is that of a random variable. If it is, it returns
1080*6212Saw148015  * the number of characters to backspace to skip the period and field
1081*6212Saw148015  * name. Otherwise it returns 0.
10825184Sek110237  */
1083*6212Saw148015 int
1084*6212Saw148015 var_is_set4_randvar(char *name)
10855184Sek110237 {
10865184Sek110237 	var_t *var;
1087*6212Saw148015 	char varname[128];
1088*6212Saw148015 	int namelength;
1089*6212Saw148015 	char *sp;
10905184Sek110237 
1091*6212Saw148015 	(void) strncpy(varname, name, 128);
1092*6212Saw148015 	namelength = strlen(varname);
1093*6212Saw148015 	sp = varname + namelength;
10945184Sek110237 
1095*6212Saw148015 	while (sp != varname) {
1096*6212Saw148015 		int c = *sp;
10975184Sek110237 
1098*6212Saw148015 		*sp = 0;
1099*6212Saw148015 		if (c == '.')
1100*6212Saw148015 			break;
1101*6212Saw148015 
1102*6212Saw148015 		sp--;
11035184Sek110237 	}
11045184Sek110237 
1105*6212Saw148015 	/* not a variable name + field? */
1106*6212Saw148015 	if (sp == varname)
1107*6212Saw148015 		return (0);
1108*6212Saw148015 
1109*6212Saw148015 	/* first part not a variable name? */
1110*6212Saw148015 	if ((var = var_find(varname+1)) == NULL)
1111*6212Saw148015 		return (0);
1112*6212Saw148015 
1113*6212Saw148015 	/* Make sure it is a random variable */
1114*6212Saw148015 	if ((var->var_type & VAR_TYPE_MASK) != VAR_TYPE_RANDOM)
1115*6212Saw148015 		return (0);
1116*6212Saw148015 
1117*6212Saw148015 	/* calculate offset from end of random variable name */
1118*6212Saw148015 	return (namelength - (sp - varname));
11195184Sek110237 }
11205184Sek110237 
11215184Sek110237 /*
11225184Sek110237  * Implements a simple path name like scheme for finding values
11235184Sek110237  * to place in certain specially named vars. The first part of
11245184Sek110237  * the name is interpreted as a category of either: stats,
11255184Sek110237  * eventgen, date, script, or host var. If a match is found,
11265184Sek110237  * the appropriate routine is called to fill in the requested
11275184Sek110237  * value in the provided var_t, and a pointer to the supplied
11285184Sek110237  * var_t is returned. If the requested value is not found, NULL
11295184Sek110237  * is returned.
11305184Sek110237  */
11315184Sek110237 static var_t *
11325184Sek110237 var_find_internal(var_t *var)
11335184Sek110237 {
11345184Sek110237 	char *n = fb_stralloc(var->var_name);
11355184Sek110237 	char *name = n;
11365184Sek110237 	var_t *rtn = NULL;
11375184Sek110237 
11385184Sek110237 	name++;
11395184Sek110237 	if (name[strlen(name) - 1] != '}')
11405184Sek110237 		return (NULL);
11415184Sek110237 	name[strlen(name) - 1] = 0;
11425184Sek110237 
11435184Sek110237 	if (strncmp(name, STATS_VAR, strlen(STATS_VAR)) == 0)
11445184Sek110237 		rtn = stats_findvar(var, name + strlen(STATS_VAR));
11455184Sek110237 
11465184Sek110237 	if (strcmp(name, EVENTGEN_VAR) == 0)
11475184Sek110237 		rtn = eventgen_ratevar(var);
11485184Sek110237 
11495184Sek110237 	if (strcmp(name, DATE_VAR) == 0)
11505184Sek110237 		rtn = date_var(var);
11515184Sek110237 
11525184Sek110237 	if (strcmp(name, SCRIPT_VAR) == 0)
11535184Sek110237 		rtn = script_var(var);
11545184Sek110237 
11555184Sek110237 	if (strcmp(name, HOST_VAR) == 0)
11565184Sek110237 		rtn = host_var(var);
11575184Sek110237 
11585184Sek110237 	free(n);
11595184Sek110237 
11605184Sek110237 	return (rtn);
11615184Sek110237 }
11625184Sek110237 
11635184Sek110237 /*
11645184Sek110237  * Calls the C library routine getenv() to obtain the value
11655184Sek110237  * for the environment variable specified by var->var_name.
1166*6212Saw148015  * If found, the value string is returned in var->var_val.string.
11675184Sek110237  * If the requested value is not found, NULL is returned.
11685184Sek110237  */
11695184Sek110237 static var_t *
11705184Sek110237 var_find_environment(var_t *var)
11715184Sek110237 {
11725184Sek110237 	char *n = fb_stralloc(var->var_name);
11735184Sek110237 	char *name = n;
1174*6212Saw148015 	char *strptr;
11755184Sek110237 
11765184Sek110237 	name++;
1177*6212Saw148015 	if (name[strlen(name) - 1] != ')') {
1178*6212Saw148015 		free(n);
11795184Sek110237 		return (NULL);
1180*6212Saw148015 	}
11815184Sek110237 	name[strlen(name) - 1] = 0;
11825184Sek110237 
1183*6212Saw148015 	if ((strptr = getenv(name)) != NULL) {
11845184Sek110237 		free(n);
1185*6212Saw148015 		VAR_SET_STR(var, strptr);
11865184Sek110237 		return (var);
11875184Sek110237 	} else {
11885184Sek110237 		free(n);
11895184Sek110237 		return (NULL);
11905184Sek110237 	}
11915184Sek110237 }
11925184Sek110237 
11935184Sek110237 /*
11945184Sek110237  * Look up special variables. The "name" argument is used to find
11955184Sek110237  * the desired special var and fill it with an appropriate string
11965184Sek110237  * value. Looks for an already allocated var of the same name on
11975184Sek110237  * the var_dyn_list. If not found a new dynamic var is allocated.
11985184Sek110237  * if the name begins with '{', it is an internal variable, and
11995184Sek110237  * var_find_internal() is called. If the name begins with '(' it
12005184Sek110237  * is an environment varable, and var_find_environment() is
12015184Sek110237  * called. On success, a pointer to the var_t is returned,
12025184Sek110237  * otherwise, NULL is returned.
12035184Sek110237  */
12045184Sek110237 static var_t *
12055184Sek110237 var_find_dynamic(char *name)
12065184Sek110237 {
12075184Sek110237 	var_t *var = NULL;
12085184Sek110237 	var_t *v = filebench_shm->var_dyn_list;
12095184Sek110237 	var_t *rtn;
12105184Sek110237 
12115184Sek110237 	/*
12125184Sek110237 	 * Lookup a reference to the var handle for this
12135184Sek110237 	 * special var
12145184Sek110237 	 */
12155184Sek110237 	for (v = filebench_shm->var_dyn_list; v != NULL; v = v->var_next) {
12165184Sek110237 		if (strcmp(v->var_name, name) == 0) {
12175184Sek110237 			var = v;
12185184Sek110237 			break;
12195184Sek110237 		}
12205184Sek110237 	}
12215184Sek110237 
12225184Sek110237 	if (var == NULL)
12235184Sek110237 		var = var_alloc_dynamic(name);
12245184Sek110237 
12255184Sek110237 	/* Internal system control variable */
12265184Sek110237 	if (*name == '{') {
12275184Sek110237 		rtn = var_find_internal(var);
12285184Sek110237 		if (rtn == NULL)
12295184Sek110237 			filebench_log(LOG_ERROR,
12305184Sek110237 			    "Cannot find internal variable %s",
12315184Sek110237 			    var->var_name);
12325184Sek110237 		return (rtn);
12335184Sek110237 	}
12345184Sek110237 
12355184Sek110237 	/* Lookup variable in environment */
12365184Sek110237 	if (*name == '(') {
12375184Sek110237 		rtn = var_find_environment(var);
12385184Sek110237 		if (rtn == NULL)
12395184Sek110237 			filebench_log(LOG_ERROR,
12405184Sek110237 			    "Cannot find environment variable %s",
12415184Sek110237 			    var->var_name);
12425184Sek110237 		return (rtn);
12435184Sek110237 	}
12445184Sek110237 
12455184Sek110237 	return (NULL);
12465184Sek110237 }
1247