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