variable.c (14629B)
1 /* 2 * 3 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 4 * 5 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 6 * 7 * File: variable.c 8 * Purpose: Variable routines with scope support functions. 9 */ 10 11 #include <sal/core/libc.h> 12 #include <sal/appl/sal.h> 13 #include <shared/bsl.h> 14 #include <appl/diag/shell.h> 15 #include <appl/diag/system.h> 16 #include <appl/diag/parse.h> 17 18 #define VAR_IS_SYSTEM(_s) (*(_s) == PARSE_VARIABLE_SYSTEM) 19 20 /* 21 * Typedef: var_t 22 * Purpose: Maps out a circular double linked list entry 23 * representing a single variable. 24 * Notes: Each linked list contains a dummy entry at the 25 * head of the list for easy insert/delete. 26 */ 27 typedef struct var_s { 28 struct var_s *v_next; /* Next in linked list */ 29 struct var_s *v_prev; /* Next in linked list */ 30 char *v_name; /* Variable name */ 31 char *v_value; /* Variable value */ 32 } var_t; 33 34 /* 35 * Typedef: var_scope_t 36 * Purpose: Defines a scope level for local variables. 37 */ 38 typedef struct var_scope_s { 39 struct var_scope_s *vs_next; /* Next in Queue */ 40 var_t vs_local; /* Local variable list */ 41 } var_scope_t; 42 43 /* 44 * Variable: var_scope_list 45 * Purpose: Queue of pushed local variable lists, each queue 46 * entry contains a variable list. 47 */ 48 49 static var_scope_t *var_scope_list = NULL; 50 51 /* 52 * Variable: var_global_list 53 * Purpose: Global variable list. 54 * Notes: List is created with the dummy queue head. 55 */ 56 static var_t var_global_list = 57 {&var_global_list, &var_global_list, NULL, NULL}; 58 59 #define VAR_SYSTEM_STRING \ 60 "\tSystem variables are those that begin with an \"_\". They may be\n\t"\ 61 "referenced but not set. Use printenv to show the system variables.\n" 62 63 void * 64 var_push_scope(void) 65 /* 66 * Function: var_push_scope 67 * Purpose: Push a new variable scope onto the top of the stack. 68 * Parameters: None. 69 * Returns: Pointer to current scope as a cookie. 70 * Notes: The cookie is useful to allow calling routine to know if the 71 * push was done, and also is passed to POP, and the pop is only 72 * done if the cookie matches the top of the queue. This can help 73 * in control-c handing. 74 */ 75 { 76 var_scope_t *vs; 77 int il; /* Don't corrupt list */ 78 79 vs = (var_scope_t *)sal_alloc(sizeof(var_scope_t), "diag_scope"); 80 assert(vs); 81 82 il = sal_splhi(); 83 vs->vs_next = var_scope_list; 84 vs->vs_local.v_next = vs->vs_local.v_prev = &vs->vs_local; 85 vs->vs_local.v_name = vs->vs_local.v_value = NULL; 86 var_scope_list = vs; /* Bang - new scope */ 87 sal_spl(il); 88 return((void *)vs); 89 } 90 91 void 92 var_pop_scope(void *vs_cookie) 93 /* 94 * Function: var_pop_scope 95 * Purpose: Pop the current variable scope, and restore previous. 96 * Parameters: Cookie from PUSH, if does not match TOP of list, POP 97 * not done. 98 * Returns: Nothing. 99 */ 100 { 101 var_scope_t *vs; 102 var_t *v; 103 int il = sal_splhi(); 104 105 vs = var_scope_list; 106 if (vs_cookie == vs) { 107 var_scope_list = vs->vs_next; /* Popped */ 108 sal_spl(il); 109 for (v = vs->vs_local.v_next; v != &vs->vs_local; ) { 110 sal_free(v->v_name); /* Free name */ 111 sal_free(v->v_value); /* Free value */ 112 v = v->v_next; /* Next please */ 113 sal_free(v->v_prev); /* Free last goober */ 114 } 115 sal_free(vs); /* Finally free scope */ 116 } else { 117 sal_spl(il); 118 } 119 } 120 121 STATIC var_t * 122 var_find_list(var_t *vl, const char *name) 123 /* 124 * Function: var_find_list 125 * Purpose: Find a variable in the given list. 126 * Parameters: vl - pointer to dummy entry at head of list. 127 * name - name of variable to find. 128 * Returns: NULL if failed, pointer to var_t if found. 129 */ 130 { 131 var_t *v; 132 133 for (v = vl->v_next; v != vl; v = v->v_next) { 134 if (v->v_name != NULL && name != NULL) { 135 if (sal_strcmp(v->v_name, name) == 0) { 136 return(v); 137 } 138 } 139 } 140 return(NULL); 141 } 142 143 STATIC var_t * 144 var_find(const char *name, int local, int global) 145 /* 146 * Function: var_find 147 * Purpose: Locate a variable. 148 * Parameters: name - name of variable to locate. 149 * local - TRUE if local scope should be checked. 150 * global- TRUE if global scope should be checked. 151 * Returns: Pointer to variable structure or NULL if failed. 152 * Notes: If local is TRUE, the local scope is always 153 * checked before the global scope. 154 */ 155 { 156 var_t *v = NULL; 157 158 if (local && var_scope_list) { 159 v = var_find_list(&var_scope_list->vs_local, name); 160 } 161 if (global && !v) { 162 v = var_find_list(&var_global_list, name); 163 } 164 return(v); 165 } 166 167 STATIC INLINE void 168 var_delete(var_t *v) 169 /* 170 * Function: var_delete 171 * Purpose: Delete a variable from a list 172 * Parameters: v - pointer to variable to delete. 173 * Returns: Nothing. 174 */ 175 { 176 int il = sal_splhi(); /* Don't corrupt list */ 177 178 v->v_prev->v_next = v->v_next; 179 v->v_next->v_prev = v->v_prev; 180 sal_spl(il); 181 sal_free(v->v_name); 182 sal_free(v->v_value); 183 sal_free(v); 184 } 185 186 STATIC void 187 var_set_list(var_t *vl, const char *name, char *val) 188 /* 189 * Function: var_set 190 * Purpose: Set a variable to the specified value. 191 * Parameters: vl - pointer to dummy entry on head of var list. 192 * name - name of variable to set. 193 * val - value to set the variable to. 194 * Returns: Nothing 195 */ 196 { 197 var_t *v; 198 char *old_val_addr; 199 char *v_value = sal_strdup(val); 200 int il; 201 202 assert(v_value); 203 204 if (NULL != (v = var_find_list(vl, name))) { 205 /* If already exists on list, replace value */ 206 il = sal_splhi(); 207 old_val_addr = v->v_value; 208 v->v_value = v_value; 209 sal_spl(il); 210 sal_free(old_val_addr); 211 } else { 212 /* Otherwise, create a new entry and link it on the list */ 213 v = (var_t *)sal_alloc(sizeof(*v), "diag_var"); 214 assert(v); 215 v->v_name = sal_strdup(name); 216 assert(v->v_name); 217 il = sal_splhi(); 218 v->v_prev = vl->v_prev; 219 v->v_next = vl; 220 v->v_prev->v_next = v; 221 v->v_next->v_prev = v; 222 v->v_value = v_value; 223 sal_spl(il); 224 } 225 } 226 227 cmd_result_t 228 var_set_system(char *name, char *value) 229 /* 230 * Function: var_set_system 231 * Purpose: Add a system variable (ie, beginning with '_'). 232 * Parameters: name - name of variable to add 233 * value - value of variable. 234 * Returns: CMD_OK - Variable set. 235 * CMD_FAIL - Invalid variable name. 236 */ 237 { 238 if (*name != PARSE_VARIABLE_SYSTEM) { 239 return(CMD_FAIL); 240 } else { 241 var_set_list(&var_global_list, name, value); 242 return(CMD_OK); 243 } 244 } 245 246 int 247 var_set(const char *name, char *value, int local, int system) 248 /* 249 * Function: var_set 250 * Purpose: Set a variable to the specified variable. 251 * Parameters: name - name of variable to set. 252 * value - value of variable to set. 253 * local - if TRUE, scope of variable is local. 254 * system - if TRUE, first character "_", otherwise, 255 * first character can NOT be "_". 256 * Returns: 0 - success, -1 - invalid name for <system> setting. 257 */ 258 { 259 if ((system && !VAR_IS_SYSTEM(name))||(!system && VAR_IS_SYSTEM(name))){ 260 return(-1); 261 } 262 if (local && var_scope_list) { 263 var_set_list(&var_scope_list->vs_local, name, value); 264 } else { 265 var_set_list(&var_global_list, name, value); 266 } 267 return(0); 268 } 269 270 int 271 var_set_integer(const char *name, int value, int local, int system) 272 /* 273 * Function: var_set_integer 274 * Purpose: Set a variable to an integer value. 275 * Parameters: name - name of variable. 276 * value - integer value to set to. 277 * local - TRUE if local variable. 278 * system - TRUE if system variable. 279 * Returns: 0 - success, -1 - invalid name for <system> setting. 280 */ 281 { 282 char v_str[12]; 283 284 sal_sprintf(v_str, "%d", value); 285 return(var_set(name, v_str, local, system)); 286 } 287 288 int 289 var_set_hex(const char *name, int value, int local, int system) 290 /* 291 * Function: var_set_integer 292 * Purpose: Set a variable to an integer value. 293 * Parameters: name - name of variable. 294 * value - integer value to set to. 295 * local - TRUE if local variable. 296 * system - TRUE if system variable. 297 * Returns: 0 - success, -1 - invalid name for <system> setting. 298 */ 299 { 300 char v_str[12]; 301 302 sal_sprintf(v_str, "0x%04x", value); 303 return(var_set(name, v_str, local, system)); 304 } 305 306 cmd_result_t 307 var_unset_system(const char *name) 308 /* 309 * Function: var_unset_system 310 * Purpose: Delete a system defined variable. 311 * Parameters: name - name of variable to delete. 312 * Returns: CMD_OK - success 313 * CMD_FAIL - variable not found or invalid name. 314 */ 315 { 316 var_t *v; 317 318 if (*name != PARSE_VARIABLE_SYSTEM) { 319 return(CMD_FAIL); 320 } 321 v = var_find(name, FALSE, TRUE); 322 if (!v) { 323 return(CMD_FAIL); 324 } else { 325 var_delete(v); 326 return(CMD_OK); 327 } 328 } 329 330 int 331 var_unset(const char *name, int local, int global, int system) 332 /* 333 * Function: var_unset 334 * Purpose: Unset a variable 335 * Parameters: name - name of variable to unset. 336 * local - if true, variable is looked for on local list 337 * global - if TRUE, variable is looked for on global 338 * list. 339 * system - if TRUE, system variables may be operated on. 340 * Returns: 0 - OK 341 * -1 - failed due to system setting. 342 */ 343 { 344 var_t *v; 345 346 if ((system && !VAR_IS_SYSTEM(name)) || (!system && VAR_IS_SYSTEM(name))) { 347 return(-1); 348 } 349 v = var_find(name, local, global); 350 if (!v) { 351 return(-1); 352 } else { 353 var_delete(v); 354 return(0); 355 } 356 } 357 358 STATIC INLINE void 359 var_display_entry(var_t *v) 360 /* 361 * Function: var_display_entry 362 * Purpose: Print the name and value of a specific variable. 363 * Parameters: v - pointer to variable to display. 364 * Returns: Nothing. 365 */ 366 { 367 cli_out("%20s = %-20s\n", v->v_name, v->v_value); 368 } 369 370 371 STATIC void 372 var_display_list(char *s, var_t *vl) 373 /* 374 * Function: var_display_list 375 * Purpose: Display an entire list of variables. 376 * Parameters: s - String to ID list. 377 * vl - pointer to dummy entry at head of list. 378 * Returns: Nothing. 379 */ 380 { 381 var_t *v; 382 383 cli_out("\n%20s | %-20s\n" 384 "---------------------+---------------------\n", 385 s, "Value"); 386 for (v = vl->v_next; v != vl; v = v->v_next) { 387 var_display_entry(v); 388 } 389 cli_out("-------------------------------------------\n"); 390 } 391 392 char var_display_usage[] = 393 "Parameters: [local|global|all]\n\t" 394 "Display variables and values. If no options are supplied, all local\n\t" 395 "variables in the current scope and global variables are displayed.\n\t" 396 "Options have the following meanings:\n\t" 397 "\tlocal\t- display only local variables in the current scope.\n\t" 398 "\tglobal\t- display all global (exported) variables\n\t" 399 "\tall\t- display all variables in all scopes\n" 400 VAR_SYSTEM_STRING; 401 402 cmd_result_t 403 var_display(int u, args_t *a) 404 /* 405 * Function: var_display 406 * Purpose: Display variable information. 407 * Parameters: u - unit number (ignored) 408 * a - pointer to argument list. 409 * Returns: CMD_OK/CMD_FAIL/CMD_USAGE. 410 */ 411 { 412 int do_local = FALSE, 413 do_global = FALSE, 414 do_all = FALSE; 415 416 COMPILER_REFERENCE(u); 417 418 if (ARG_CNT(a) == 0) { /* everything */ 419 do_local = TRUE; 420 do_global = TRUE; 421 } else if (ARG_CNT(a) != 1) { 422 return(CMD_FAIL); 423 } else if (!sal_strcasecmp("local", _ARG_CUR(a))) { /* Local only */ 424 do_local = TRUE; 425 } else if (!sal_strcasecmp("global", _ARG_CUR(a))) { /* Global only */ 426 do_global = TRUE; 427 } else if (!sal_strcasecmp("all", _ARG_CUR(a))) { /* All scopes */ 428 do_all = TRUE; 429 do_global = TRUE; 430 } 431 if (do_all) { 432 var_scope_t *vs; /* Variable Scope*/ 433 int l; /* Level */ 434 char l_str[64]; 435 for (l = 1, vs = var_scope_list; vs; vs = vs->vs_next, l++) { 436 sal_sprintf(l_str, "Scope Level %d", l); 437 var_display_list(l_str, &vs->vs_local); 438 } 439 } else if (do_local) { 440 if (var_scope_list) { 441 var_display_list("Local Variables", &var_scope_list->vs_local); 442 } 443 } 444 if (do_global) { 445 var_display_list("Global Variables", &var_global_list); 446 } 447 return(CMD_OK); 448 } 449 450 char var_export_usage[] = 451 "Parameters: <variable> [<value>]\n\t" 452 "Set variable <variable> to a specific value <value>, and export it\n\t" 453 "making it visible in all scopes. If <value> is not present, the\n\t" 454 "variable is removed from the global scope.\n" 455 VAR_SYSTEM_STRING; 456 457 /*ARGSUSED*/ 458 cmd_result_t 459 var_export(int u, args_t *a) 460 /* 461 * Function: var_export 462 * Purpose: Create a global variable visible from anywhere. 463 * Parameters: u - unit (IGNORED) 464 * a - arguments 465 * Returns: CMD_OK/CMD_FAIL 466 */ 467 { 468 char *name, *value; 469 int rv = 0; 470 471 COMPILER_REFERENCE(u); 472 473 switch(ARG_CNT(a)) { 474 case 0: 475 var_display_list("Global Variables", &var_global_list); 476 break; 477 case 1: /* Remove variable */ 478 rv = var_unset(ARG_GET(a), FALSE, TRUE, FALSE); 479 break; 480 case 2: /* Add variable */ 481 name = ARG_GET(a); 482 value = ARG_GET(a); 483 if (NULL != var_find(name, TRUE, FALSE)) { 484 cli_out("%s: Warning: variable %s shadowed by local variable\n", 485 ARG_CMD(a), name); 486 } 487 rv = var_set(name, value, FALSE, FALSE); 488 break; 489 default: /* Error */ 490 return(CMD_USAGE); 491 } 492 return(rv ? CMD_FAIL : CMD_OK); 493 } 494 495 char var_local_usage[] = 496 "Parameters: <variable> [<value>]\n\t" 497 "Set variable <variable> to a specific value <value>, in the local\n\t" 498 "scope only. Variable in the local scope are not visible in\n\t" 499 "recursive diag shells or in rc load files.\n\t" 500 VAR_SYSTEM_STRING; 501 502 cmd_result_t 503 var_local(int u, args_t *a) 504 /* 505 * Function: var_local 506 * Purpose: Set/Remove a local variable. 507 * Parameters: u - unit number (ignored) 508 * a -arguments, either a variable name only to delete, 509 * or a variable name and a value. 510 * Returns: CMD_OK or CMD_FAIL if variable not found for removal 511 * or attempt to set/remove a system variable. 512 * CMD_USAGE for invalid number of arguments. 513 */ 514 { 515 char *name, *value; 516 int rv = 0; 517 518 COMPILER_REFERENCE(u); 519 520 switch(ARG_CNT(a)) { 521 case 0: 522 var_display_list("Local Variables", &var_scope_list->vs_local); 523 break; 524 case 1: /* Remove variable */ 525 rv = var_unset(ARG_GET(a), TRUE, FALSE, FALSE); 526 break; 527 case 2: /* Add variable */ 528 name = ARG_GET(a); 529 value= ARG_GET(a); 530 rv = var_set(name, value, TRUE, FALSE); 531 break; 532 default: /* Error */ 533 return(CMD_USAGE); 534 } 535 return(rv ? CMD_FAIL : CMD_OK); 536 } 537 538 char * 539 var_get(const char *name) 540 /* 541 * Function: var_get 542 * Purpose: Perform normal lookup for a variable in the current scope and 543 * then on the global list. 544 * Parameters: name - name of variable to lookup. 545 * Returns: NULL - not found 546 * !NULL - pointer to value of variable. 547 */ 548 { 549 var_t *v; 550 551 v = var_find(name, TRUE, TRUE); 552 return(v ? v->v_value : NULL); 553 }