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