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