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