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 2007 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 /* 29 * libfru is divided into the following modules: 30 * 1) This file. Support for the API and ties together all the sub-modules. 31 * 2) The parser which parses the field_paths supplied by the user. 32 * 3) The data_source sub-libraries which provide payloads(tags) and the tree 33 * structure of frus and locations. 34 * 4) The PayloadReader which given a payload and a path definition can extract 35 * the exact field the user is looking for. 36 * 5) The Registry which provides the definitions for all the Data Elements 37 * supported. 38 * 39 * The basic algorithim for reading/updating fields is this: 40 * 1) Parse the field_path given by the user. 41 * 2) Using the registry determine which payloads this data MAY appear in. 42 * 3) Figure out which tags of this type are in the container. 43 * 4) Find the specific tag which contains the instance of this data the user 44 * requested. 45 * 5) Get this tag from the data source and read it with the PayloadReader to 46 * read/write data. 47 * 6) For UPDATES write this tag back to the data source. 48 * 49 * This algorithim is altered only when dealing with "UNKNOWN" payloads where 50 * it simplifies slightly. 51 */ 52 53 #include <assert.h> 54 #include <string.h> 55 #include <stdlib.h> 56 #include <stdio.h> 57 #include <libintl.h> 58 #include <pthread.h> 59 #include <stdarg.h> 60 #include <dlfcn.h> 61 #include <alloca.h> 62 #include <limits.h> 63 64 #include "libfru.h" 65 #include "libfrup.h" 66 #include "libfruds.h" 67 #include "Ancestor.h" 68 #include "libfrureg.h" 69 #include "Parser.h" 70 #include "PayloadReader.h" 71 72 #define DATA_SOURCE_OBJ_NAME "data_source" 73 74 #define ENCRYPTION_LIB_NAME "libfrucrypt.so.1" 75 #define FRU_ENCRYPT_FUNC_NAME "fru_encrypt_func" 76 77 #define UNKNOWN_PATH "UNKNOWN" 78 #define IS_UNKNOWN_PATH(path) \ 79 ((strcmp(path, "/UNKNOWN") == 0) || (strcmp(path, "UNKNOWN") == 0)) 80 81 #define NODEHDL_TO_TREEHDL(nodehdl) (fru_treehdl_t)nodehdl 82 #define TREEHDL_TO_NODEHDL(treehdl) (fru_nodehdl_t)treehdl 83 84 /* ========================================================================= */ 85 /* 86 * Define a hash of rwlocks for each container. 87 */ 88 struct cont_lock 89 { 90 fru_nodehdl_t handle; 91 pthread_rwlock_t lock; 92 struct cont_lock *next; 93 }; 94 typedef struct cont_lock cont_lock_t; 95 96 fru_encrypt_func_t encrypt_func; 97 98 #define CONT_LOCK_HASH_NUM 128 99 cont_lock_t *cont_lock_hash[CONT_LOCK_HASH_NUM]; 100 pthread_mutex_t cont_lock_hash_lock; 101 102 typedef enum { WRITE_LOCK, READ_LOCK } lock_mode_t; 103 104 /* 105 * These control the Data sources available. 106 */ 107 static pthread_mutex_t ds_lock; 108 static fru_datasource_t *data_source = NULL; 109 static void *ds_lib = NULL; 110 static int ds_lib_ref_cnt = 0; 111 static char *ds_lib_name = NULL; 112 113 #define FRU_NORESPONSE_RETRY 500 114 115 #define RETRY(expr) \ 116 { for (int loop = 0; loop < FRU_NORESPONSE_RETRY && \ 117 (expr) == FRU_NORESPONSE; loop++) ; \ 118 } 119 120 /* ========================================================================= */ 121 static const char *fru_errmsg[] = 122 { 123 "Success", 124 "Node not found", 125 "IO error", 126 "No registry definition for this element", 127 "Not container", 128 "Invalid handle", 129 "Invalid Segment", 130 "Invalid Path", 131 "Invalid Element", 132 "Invalid Data size (does not match registry definition)", 133 "Duplicate Segment", 134 "Not Field", 135 "No space available", 136 "Data could not be found", 137 "Iteration full", 138 "Invalid Permisions", 139 "Feature not Supported", 140 "Element is not Tagged", 141 "Failed to read container device", 142 "Segment Corrupt", 143 "Data Corrupt", 144 "General LIBFRU FAILURE", 145 "Walk terminated", 146 "FRU No response", 147 "Unknown error" 148 }; 149 150 fru_errno_t 151 fru_encryption_supported(void) 152 { 153 if (encrypt_func == NULL) 154 return (FRU_NOTSUP); 155 else 156 return (FRU_SUCCESS); 157 } 158 159 extern "C" { 160 void 161 init_libfru(void) 162 { 163 // attempt to find the encryption library. 164 void *crypt_lib = NULL; 165 encrypt_func = NULL; 166 crypt_lib = dlopen(ENCRYPTION_LIB_NAME, RTLD_LAZY); 167 if (crypt_lib != NULL) { 168 encrypt_func = (fru_encrypt_func_t)dlsym(crypt_lib, 169 FRU_ENCRYPT_FUNC_NAME); 170 } 171 } 172 #pragma init(init_libfru) 173 } 174 175 /* ========================================================================= */ 176 static void 177 add_cont_lock(cont_lock_t *lock) 178 { 179 cont_lock_t *prev = NULL; 180 int hash_bucket = lock->handle % CONT_LOCK_HASH_NUM; 181 182 /* insert at tail */ 183 if (cont_lock_hash[hash_bucket] == NULL) { 184 cont_lock_hash[hash_bucket] = lock; 185 } else { 186 cont_lock_t *prev = cont_lock_hash[hash_bucket]; 187 while (prev->next != NULL) { 188 prev = prev->next; 189 } 190 prev->next = lock; 191 } 192 } 193 194 /* ========================================================================= */ 195 static cont_lock_t * 196 find_cont_lock(fru_nodehdl_t handle) 197 { 198 int hash_bucket = handle % CONT_LOCK_HASH_NUM; 199 cont_lock_t *which = cont_lock_hash[hash_bucket]; 200 201 while (which != NULL) { 202 if (which->handle == handle) { 203 break; 204 } 205 which = which->next; 206 } 207 return (which); 208 } 209 210 /* ========================================================================= */ 211 static cont_lock_t * 212 alloc_cont_lock(fru_nodehdl_t handle) 213 { 214 cont_lock_t *lock = (cont_lock_t *)malloc(sizeof (cont_lock_t)); 215 if (lock == NULL) { 216 return (NULL); 217 } 218 lock->handle = handle; 219 if (pthread_rwlock_init(&(lock->lock), NULL) != 0) { 220 free(lock); 221 return (NULL); 222 } 223 lock->next = NULL; 224 return (lock); 225 } 226 227 /* ========================================================================= */ 228 static fru_errno_t 229 lock_container(lock_mode_t mode, fru_nodehdl_t handle) 230 { 231 cont_lock_t *which = NULL; 232 int hash_bucket = 0; 233 int lock_rc; 234 235 pthread_mutex_lock(&cont_lock_hash_lock); 236 237 which = find_cont_lock(handle); 238 239 /* if not found add to hash */ 240 if (which == NULL) { 241 if ((which = alloc_cont_lock(handle)) == NULL) { 242 pthread_mutex_unlock(&cont_lock_hash_lock); 243 return (FRU_FAILURE); 244 } 245 add_cont_lock(which); 246 } 247 248 /* execute lock */ 249 lock_rc = 0; 250 switch (mode) { 251 case READ_LOCK: 252 lock_rc = pthread_rwlock_rdlock(&(which->lock)); 253 break; 254 case WRITE_LOCK: 255 lock_rc = pthread_rwlock_wrlock(&(which->lock)); 256 break; 257 } 258 259 pthread_mutex_unlock(&cont_lock_hash_lock); 260 if (lock_rc != 0) { 261 return (FRU_FAILURE); 262 } 263 return (FRU_SUCCESS); 264 } 265 266 /* ========================================================================= */ 267 /* 268 * Macro to make checking unlock_conatiner error code easier 269 */ 270 #define CHK_UNLOCK_CONTAINER(handle) \ 271 if (unlock_container(handle) != FRU_SUCCESS) { \ 272 return (FRU_FAILURE); \ 273 } 274 static fru_errno_t 275 unlock_container(fru_nodehdl_t handle) 276 { 277 cont_lock_t *which = NULL; 278 pthread_mutex_lock(&cont_lock_hash_lock); 279 280 which = find_cont_lock(handle); 281 if (which == NULL) { 282 pthread_mutex_unlock(&cont_lock_hash_lock); 283 return (FRU_NODENOTFOUND); 284 } 285 286 if (pthread_rwlock_unlock(&(which->lock)) != 0) { 287 pthread_mutex_unlock(&cont_lock_hash_lock); 288 return (FRU_FAILURE); 289 } 290 291 pthread_mutex_unlock(&cont_lock_hash_lock); 292 return (FRU_SUCCESS); 293 } 294 295 /* ========================================================================= */ 296 static fru_errno_t 297 clear_cont_locks(void) 298 { 299 pthread_mutex_lock(&cont_lock_hash_lock); 300 301 // for each bucket 302 for (int i = 0; i < CONT_LOCK_HASH_NUM; i++) { 303 // free all the locks 304 cont_lock_t *cur = cont_lock_hash[i]; 305 while (cur != NULL) { 306 cont_lock_t *tmp = cur; 307 cur = cur->next; 308 pthread_rwlock_destroy(&(tmp->lock)); 309 free(tmp); 310 } 311 cont_lock_hash[i] = NULL; 312 } 313 314 pthread_mutex_unlock(&cont_lock_hash_lock); 315 return (FRU_SUCCESS); 316 } 317 318 319 /* ========================================================================= */ 320 /* VARARGS */ 321 fru_errno_t 322 fru_open_data_source(const char *name, ...) 323 { 324 fru_errno_t err = FRU_SUCCESS; 325 326 va_list args; 327 int num_args = 0; 328 char **init_args = NULL; 329 char *tmp; 330 int i = 0; 331 332 char ds_name[PATH_MAX]; 333 fru_datasource_t *ds = NULL; 334 void *tmp_lib = NULL; 335 336 pthread_mutex_lock(&ds_lock); 337 338 if ((ds_lib_name != NULL) && (data_source != NULL)) { 339 // we already have a DS assigned. 340 if ((strcmp(ds_lib_name, name) == 0)) { 341 // user wants to open the same one... ok. 342 ds_lib_ref_cnt++; 343 pthread_mutex_unlock(&ds_lock); 344 return (FRU_SUCCESS); 345 } else { 346 pthread_mutex_unlock(&ds_lock); 347 return (FRU_FAILURE); 348 } 349 } 350 351 snprintf(ds_name, sizeof (ds_name), "libfru%s.so.%d", 352 name, LIBFRU_DS_VER); 353 tmp_lib = dlopen(ds_name, RTLD_LAZY); 354 if (tmp_lib == NULL) { 355 pthread_mutex_unlock(&ds_lock); 356 return (FRU_NOTSUP); 357 } 358 ds = (fru_datasource_t *)dlsym(tmp_lib, 359 DATA_SOURCE_OBJ_NAME); 360 if (ds == NULL) { 361 pthread_mutex_unlock(&ds_lock); 362 return (FRU_FAILURE); 363 } 364 365 va_start(args, name); 366 tmp = va_arg(args, char *); 367 while (tmp != NULL) { 368 num_args++; 369 tmp = va_arg(args, char *); 370 } 371 va_end(args); 372 373 init_args = (char **)malloc(sizeof (char *) * num_args); 374 if (init_args == NULL) { 375 pthread_mutex_unlock(&ds_lock); 376 return (FRU_FAILURE); 377 } 378 379 va_start(args, name); 380 for (tmp = va_arg(args, char *), i = 0; 381 (tmp != NULL) && (i < num_args); 382 tmp = va_arg(args, char *), i++) { 383 init_args[i] = tmp; 384 } 385 va_end(args); 386 387 if ((err = ds->initialize(num_args, init_args)) == FRU_SUCCESS) { 388 // don't switch unless the source connects ok. 389 ds_lib = tmp_lib; 390 data_source = ds; 391 ds_lib_name = strdup(name); 392 ds_lib_ref_cnt++; 393 } 394 395 free(init_args); 396 pthread_mutex_unlock(&ds_lock); 397 return (err); 398 } 399 400 401 /* ========================================================================= */ 402 fru_errno_t 403 fru_close_data_source(void) 404 { 405 fru_errno_t err = FRU_SUCCESS; 406 407 if (ds_lib_ref_cnt == 0) { 408 return (FRU_FAILURE); 409 } 410 411 pthread_mutex_lock(&ds_lock); 412 if ((--ds_lib_ref_cnt) == 0) { 413 /* don't check err code here */ 414 err = data_source->shutdown(); 415 /* continue to clean up libfru and return the err at the end */ 416 clear_cont_locks(); 417 dlclose(ds_lib); 418 ds_lib = NULL; 419 free(ds_lib_name); 420 ds_lib_name = NULL; 421 data_source = NULL; 422 } 423 424 pthread_mutex_unlock(&ds_lock); 425 return (err); 426 } 427 428 /* ========================================================================= */ 429 int 430 segment_is_encrypted(fru_nodehdl_t container, const char *seg_name) 431 { 432 fru_errno_t err = FRU_SUCCESS; 433 fru_segdef_t segdef; 434 435 if (data_source == NULL) { 436 return (0); 437 } 438 439 RETRY(err = data_source->get_seg_def(NODEHDL_TO_TREEHDL(container), 440 seg_name, &segdef)) 441 442 if (err != FRU_SUCCESS) { 443 return (0); 444 } 445 446 return (segdef.desc.field.encrypted == 1); 447 } 448 449 /* ========================================================================= */ 450 static fru_errno_t 451 get_seg_list_from_ds(fru_nodehdl_t node, fru_strlist_t *list) 452 { 453 fru_errno_t err = FRU_SUCCESS; 454 fru_strlist_t raw_list; 455 if (data_source == NULL) { 456 return (FRU_FAILURE); 457 } 458 459 /* get a list of all segments */ 460 RETRY(err = data_source->get_seg_list(NODEHDL_TO_TREEHDL(node), 461 &raw_list)) 462 463 if (err != FRU_SUCCESS) { 464 return (err); 465 } 466 467 /* leave out the encrypted segments if necessary */ 468 list->num = 0; 469 list->strs = (char **)malloc(sizeof (*(list->strs)) * raw_list.num); 470 if (list->strs == NULL) { 471 fru_destroy_strlist(&raw_list); 472 return (err); 473 } 474 for (int i = 0; i < raw_list.num; i++) { 475 if (segment_is_encrypted(node, raw_list.strs[i])) { 476 if (fru_encryption_supported() == FRU_SUCCESS) { 477 list->strs[list->num] 478 = strdup(raw_list.strs[i]); 479 list->num++; 480 } // else leave it out. 481 } else { 482 list->strs[list->num] = strdup(raw_list.strs[i]); 483 list->num++; 484 } 485 } 486 487 fru_destroy_strlist(&raw_list); 488 return (FRU_SUCCESS); 489 } 490 491 492 /* ========================================================================= */ 493 const char * 494 fru_strerror(fru_errno_t errnum) 495 { 496 if ((errnum < (sizeof (fru_errmsg)/sizeof (*fru_errmsg))) && 497 (errnum >= 0)) { 498 return (gettext(fru_errmsg[errnum])); 499 } 500 return (gettext 501 (fru_errmsg[(sizeof (fru_errmsg)/sizeof (*fru_errmsg))])); 502 } 503 504 /* ========================================================================= */ 505 fru_errno_t 506 fru_get_root(fru_nodehdl_t *handle) 507 { 508 fru_errno_t err = FRU_SUCCESS; 509 fru_treehdl_t tr_root; 510 if (data_source == NULL) { 511 return (FRU_FAILURE); 512 } 513 514 RETRY(err = data_source->get_root(&tr_root)) 515 if (err == FRU_SUCCESS) { 516 *handle = TREEHDL_TO_NODEHDL(tr_root); 517 } 518 return (err); 519 } 520 521 /* ========================================================================= */ 522 fru_errno_t 523 fru_get_child(fru_nodehdl_t handle, fru_nodehdl_t *child) 524 { 525 fru_errno_t err = FRU_SUCCESS; 526 fru_treehdl_t tr_child; 527 fru_node_t type; 528 if (data_source == NULL) { 529 return (FRU_FAILURE); 530 } 531 532 RETRY(err = data_source->get_child(NODEHDL_TO_TREEHDL(handle), 533 &tr_child)) 534 if (err != FRU_SUCCESS) { 535 return (err); 536 } 537 538 RETRY(err = data_source->get_node_type(tr_child, &type)) 539 540 if (err != FRU_SUCCESS) { 541 return (err); 542 } 543 if ((type == FRU_NODE_LOCATION) || 544 (type == FRU_NODE_FRU) || 545 (type == FRU_NODE_CONTAINER)) { 546 *child = TREEHDL_TO_NODEHDL(tr_child); 547 return (FRU_SUCCESS); 548 } 549 550 /* 551 * if the child is not valid try and find a peer of the child which is 552 * valid 553 */ 554 do { 555 RETRY(err = data_source->get_peer(tr_child, &tr_child)) 556 if (err != FRU_SUCCESS) { 557 return (err); 558 } 559 560 RETRY(err = data_source->get_node_type(tr_child, &type)) 561 if (err != FRU_SUCCESS) { 562 return (err); 563 } 564 if ((type == FRU_NODE_LOCATION) || 565 (type == FRU_NODE_FRU) || 566 (type == FRU_NODE_CONTAINER)) { 567 *child = TREEHDL_TO_NODEHDL(tr_child); 568 return (FRU_SUCCESS); 569 } 570 } while (1); 571 } 572 573 /* ========================================================================= */ 574 fru_errno_t 575 fru_get_peer(fru_nodehdl_t handle, fru_nodehdl_t *peer) 576 { 577 fru_errno_t err = FRU_SUCCESS; 578 fru_treehdl_t tr_peer = NODEHDL_TO_TREEHDL(handle); 579 fru_node_t type; 580 581 if (data_source == NULL) { 582 return (FRU_FAILURE); 583 } 584 585 do { 586 RETRY(err = data_source->get_peer(tr_peer, &tr_peer)) 587 588 if (err != FRU_SUCCESS) { 589 return (err); 590 } 591 592 RETRY(err = data_source->get_node_type(tr_peer, &type)) 593 if (err != FRU_SUCCESS) { 594 return (err); 595 } 596 if ((type == FRU_NODE_LOCATION) || 597 (type == FRU_NODE_FRU) || 598 (type == FRU_NODE_CONTAINER)) { 599 *peer = TREEHDL_TO_NODEHDL(tr_peer); 600 return (FRU_SUCCESS); 601 } 602 } while (1); 603 } 604 /* ========================================================================= */ 605 fru_errno_t 606 fru_get_parent(fru_nodehdl_t handle, fru_nodehdl_t *parent) 607 { 608 fru_errno_t err = FRU_SUCCESS; 609 fru_treehdl_t tr_parent; 610 if (data_source == NULL) { 611 return (FRU_FAILURE); 612 } 613 614 RETRY(err = data_source->get_parent(NODEHDL_TO_TREEHDL(handle), 615 &tr_parent)) 616 if (err == FRU_SUCCESS) { 617 *parent = TREEHDL_TO_NODEHDL(tr_parent); 618 } 619 return (err); 620 } 621 622 623 /* ========================================================================= */ 624 fru_errno_t 625 fru_get_name_from_hdl(fru_nodehdl_t handle, char **name) 626 { 627 fru_errno_t err = FRU_SUCCESS; 628 629 if (data_source == NULL) { 630 return (FRU_FAILURE); 631 } 632 633 RETRY(err = data_source->get_name_from_hdl(NODEHDL_TO_TREEHDL(handle), 634 name)) 635 return (err); 636 } 637 638 /* ========================================================================= */ 639 /* 640 * Project-private interface 641 * 642 * Apply process_node() to each node in the tree rooted at "node". 643 * 644 * process_node() has available the handle, path (in the subtree from the root 645 * "node" passed to fru_walk_tree()), and name of the node to which it is 646 * applied, as well as any arguments provided via the generic pointer "args". 647 * process_node() also takes a pointer to an end_node() function pointer 648 * argument and a pointer to a generic pointer "end_args" argument. If 649 * non-null, end_node() is called after the node and its children have been 650 * processed, but before the node's siblings are visited. 651 */ 652 extern "C" fru_errno_t 653 fru_walk_tree(fru_nodehdl_t node, const char *prior_path, 654 fru_errno_t (*process_node)(fru_nodehdl_t node, 655 const char *path, 656 const char *name, void *args, 657 end_node_fp_t *end_node, 658 void **end_args), 659 void *args) 660 { 661 void *end_args = NULL; 662 663 char *name = NULL, *path; 664 665 int prior_length; 666 667 fru_errno_t status; 668 669 fru_nodehdl_t next; 670 671 end_node_fp_t end_node = NULL; 672 673 674 /* Build node's path */ 675 if ((status = fru_get_name_from_hdl(node, &name)) != FRU_SUCCESS) 676 return (status); 677 else if (name == NULL) 678 return (FRU_FAILURE); 679 680 prior_length = strlen(prior_path); 681 path = (char *)alloca(prior_length + sizeof ("/") + strlen(name)); 682 (void) sprintf(path, "%s/%s", prior_path, name); 683 free(name); 684 name = path + prior_length + 1; 685 686 687 /* Process node */ 688 assert(process_node != NULL); 689 if ((status = process_node(node, path, name, args, 690 &end_node, &end_args)) 691 != FRU_SUCCESS) { 692 if (end_node) end_node(node, path, name, end_args); 693 return (status); 694 } 695 696 697 /* Process children */ 698 if ((status = fru_get_child(node, &next)) == FRU_SUCCESS) 699 status = fru_walk_tree(next, path, process_node, args); 700 else if (status == FRU_NODENOTFOUND) 701 status = FRU_SUCCESS; 702 703 /* "Close" node */ 704 if (end_node) end_node(node, path, name, end_args); 705 if (status != FRU_SUCCESS) 706 return (status); 707 708 /* Process siblings */ 709 if ((status = fru_get_peer(node, &next)) == FRU_SUCCESS) 710 status = fru_walk_tree(next, prior_path, process_node, args); 711 else if (status == FRU_NODENOTFOUND) 712 status = FRU_SUCCESS; 713 714 return (status); 715 } 716 717 /* ========================================================================= */ 718 /* 719 * Project-private interface 720 * 721 * Return true if "searchpath" equals "path" or is a tail of "path" and 722 * begins at a component name within "path" 723 */ 724 int 725 fru_pathmatch(const char *path, const char *searchpath) 726 { 727 const char *match; 728 729 if (((match = strstr(path, searchpath)) != NULL) && 730 ((match + strlen(searchpath)) == (path + strlen(path))) && 731 ((match == path) || (*(match - 1) == '/'))) 732 return (1); 733 734 return (0); 735 } 736 737 /* ========================================================================= */ 738 fru_errno_t 739 fru_get_node_type(fru_nodehdl_t handle, fru_node_t *type) 740 { 741 fru_errno_t err = FRU_SUCCESS; 742 fru_node_t tmp; 743 if (data_source == NULL) { 744 return (FRU_FAILURE); 745 } 746 747 RETRY(err = data_source->get_node_type(NODEHDL_TO_TREEHDL(handle), 748 &tmp)) 749 if (err == FRU_SUCCESS) { 750 *type = tmp; 751 } 752 return (err); 753 } 754 755 /* ========================================================================= */ 756 static fru_errno_t 757 is_container(fru_nodehdl_t handle) 758 { 759 fru_errno_t err = FRU_SUCCESS; 760 fru_node_t type; 761 if ((err = fru_get_node_type(handle, &type)) != FRU_SUCCESS) { 762 return (err); 763 } 764 if (type == FRU_NODE_CONTAINER) { 765 return (FRU_SUCCESS); 766 } 767 return (FRU_NOTCONTAINER); 768 } 769 770 /* ========================================================================= */ 771 fru_errno_t 772 fru_destroy_enum(fru_enum_t *e) 773 { 774 if (e == NULL) { 775 return (FRU_SUCCESS); 776 } 777 if (e->text != NULL) 778 free(e->text); 779 780 return (FRU_SUCCESS); 781 } 782 783 /* ========================================================================= */ 784 /* 785 * NOTE: does not free list. This is allocated by the user and should be 786 * deallocated by the user. 787 */ 788 fru_errno_t 789 fru_destroy_strlist(fru_strlist_t *list) 790 { 791 if (list == NULL) { 792 return (FRU_SUCCESS); 793 } 794 if (list->strs != NULL) { 795 for (int i = 0; i < list->num; i++) { 796 if (list->strs[i] != NULL) 797 free(list->strs[i]); 798 } 799 free(list->strs); 800 } 801 802 list->num = 0; 803 804 return (FRU_SUCCESS); 805 } 806 807 /* ========================================================================= */ 808 fru_errno_t 809 fru_destroy_elemdef(fru_elemdef_t *def) 810 { 811 if (def == NULL) { 812 return (FRU_SUCCESS); 813 } 814 if (def->enum_table != NULL) { 815 for (int i = 0; i < def->enum_count; i++) 816 fru_destroy_enum(&(def->enum_table[i])); 817 free(def->enum_table); 818 } 819 def->enum_count = 0; 820 821 if (def->example_string != NULL) 822 free(def->example_string); 823 824 return (FRU_SUCCESS); 825 } 826 827 /* ========================================================================= */ 828 fru_errno_t 829 fru_list_segments(fru_nodehdl_t container, fru_strlist_t *list) 830 { 831 fru_errno_t err = FRU_SUCCESS; 832 833 if ((err = is_container(container)) != FRU_SUCCESS) { 834 return (err); 835 } 836 837 if (lock_container(READ_LOCK, container) != FRU_SUCCESS) { 838 return (FRU_FAILURE); 839 } 840 841 err = get_seg_list_from_ds(container, list); 842 843 CHK_UNLOCK_CONTAINER(container); 844 return (err); 845 } 846 847 /* ========================================================================= */ 848 fru_errno_t 849 fru_create_segment(fru_nodehdl_t container, fru_segdef_t *def) 850 { 851 fru_errno_t err = FRU_SUCCESS; 852 int i = 0; 853 854 if (data_source == NULL) { 855 return (FRU_FAILURE); 856 } 857 858 if ((def->desc.field.encrypted == 1) && 859 (fru_encryption_supported() == FRU_NOTSUP)) { 860 return (FRU_NOTSUP); 861 } 862 863 if ((err = is_container(container)) != FRU_SUCCESS) { 864 return (err); 865 } 866 867 if (lock_container(WRITE_LOCK, container) != FRU_SUCCESS) { 868 return (FRU_FAILURE); 869 } 870 fru_strlist_t seg_list; 871 872 /* get a list of all segments */ 873 /* here we do not want to leave out the encrypted segments. */ 874 RETRY(err = data_source->get_seg_list(NODEHDL_TO_TREEHDL(container), 875 &seg_list)) 876 if (err != FRU_SUCCESS) { 877 CHK_UNLOCK_CONTAINER(container); 878 return (err); 879 } 880 881 for (i = 0; i < seg_list.num; i++) { 882 if (strncmp(seg_list.strs[i], def->name, FRU_SEGNAMELEN) 883 == 0) { 884 fru_destroy_strlist(&seg_list); 885 CHK_UNLOCK_CONTAINER(container); 886 return (FRU_DUPSEG); 887 } 888 } 889 fru_destroy_strlist(&seg_list); 890 891 RETRY(err = data_source->add_seg(NODEHDL_TO_TREEHDL(container), def)) 892 893 CHK_UNLOCK_CONTAINER(container); 894 return (err); 895 } 896 897 /* ========================================================================= */ 898 fru_errno_t 899 fru_remove_segment(fru_nodehdl_t container, const char *seg_name) 900 { 901 fru_errno_t err = FRU_SUCCESS; 902 if ((seg_name == NULL) || (strlen(seg_name) > FRU_SEGNAMELEN)) { 903 return (FRU_INVALSEG); 904 } 905 906 if (data_source == NULL) { 907 return (FRU_FAILURE); 908 } 909 910 if ((err = is_container(container)) != FRU_SUCCESS) { 911 return (err); 912 } 913 914 if (lock_container(WRITE_LOCK, container) != FRU_SUCCESS) { 915 return (FRU_FAILURE); 916 } 917 918 /* do not allow encrypted segments to be removed */ 919 /* unless encryption is supported */ 920 if ((segment_is_encrypted(container, seg_name)) && 921 (fru_encryption_supported() == FRU_NOTSUP)) { 922 err = FRU_INVALSEG; 923 } else { 924 RETRY(err = 925 data_source->delete_seg(NODEHDL_TO_TREEHDL(container), 926 seg_name)) 927 } 928 929 CHK_UNLOCK_CONTAINER(container); 930 return (err); 931 } 932 933 /* ========================================================================= */ 934 fru_errno_t 935 fru_get_segment_def(fru_nodehdl_t container, const char *seg_name, 936 fru_segdef_t *definition) 937 { 938 fru_errno_t err = FRU_SUCCESS; 939 if ((seg_name == NULL) || (strlen(seg_name) > 2)) { 940 return (FRU_INVALSEG); 941 } 942 943 if (data_source == NULL) { 944 return (FRU_FAILURE); 945 } 946 947 if ((err = is_container(container)) != FRU_SUCCESS) { 948 return (err); 949 } 950 951 if (lock_container(READ_LOCK, container) != FRU_SUCCESS) { 952 return (FRU_FAILURE); 953 } 954 955 // NOTE: not passing "definition" to this function such that I may 956 // check for encryption before allowing the user to get the data. 957 fru_segdef_t segdef; 958 959 RETRY(err = data_source->get_seg_def(NODEHDL_TO_TREEHDL(container), 960 seg_name, &segdef)) 961 962 if (err != FRU_SUCCESS) { 963 CHK_UNLOCK_CONTAINER(container); 964 return (err); 965 } 966 967 if ((segdef.desc.field.encrypted == 1) && 968 (fru_encryption_supported() == FRU_NOTSUP)) { 969 CHK_UNLOCK_CONTAINER(container); 970 return (FRU_INVALSEG); 971 } 972 973 // After encryption check, copy from my def to users. 974 definition->version = segdef.version; 975 strlcpy(definition->name, segdef.name, FRU_SEGNAMELEN+1); 976 definition->desc = segdef.desc; 977 definition->size = segdef.size; 978 definition->address = segdef.address; 979 definition->hw_desc = segdef.hw_desc; 980 981 CHK_UNLOCK_CONTAINER(container); 982 return (FRU_SUCCESS); 983 } 984 985 /* ========================================================================= */ 986 fru_errno_t 987 fru_list_elems_in(fru_nodehdl_t container, const char *seg_name, 988 fru_strlist_t *list) 989 { 990 fru_errno_t err = FRU_SUCCESS; 991 fru_tag_t *tags = NULL; 992 int i = 0; 993 int num_tags = 0; 994 fru_strlist_t rc_list; 995 996 if ((seg_name == NULL) || (strlen(seg_name) > 2)) { 997 return (FRU_INVALSEG); 998 } 999 1000 if (data_source == NULL) { 1001 return (FRU_FAILURE); 1002 } 1003 1004 if ((err = is_container(container)) != FRU_SUCCESS) { 1005 return (err); 1006 } 1007 1008 if (lock_container(READ_LOCK, container) != FRU_SUCCESS) { 1009 return (FRU_FAILURE); 1010 } 1011 1012 if ((segment_is_encrypted(container, seg_name)) && 1013 (fru_encryption_supported() == FRU_NOTSUP)) { 1014 CHK_UNLOCK_CONTAINER(container); 1015 return (FRU_INVALSEG); 1016 } 1017 1018 RETRY(err = data_source->get_tag_list(NODEHDL_TO_TREEHDL(container), 1019 seg_name, &tags, &num_tags)) 1020 if (err != FRU_SUCCESS) { 1021 CHK_UNLOCK_CONTAINER(container); 1022 return (err); 1023 } 1024 if (num_tags == 0) { 1025 CHK_UNLOCK_CONTAINER(container); 1026 list->num = 0; 1027 list->strs = NULL; 1028 return (FRU_SUCCESS); 1029 } 1030 1031 // allocate the memory for the names. 1032 rc_list.num = 0; 1033 rc_list.strs = (char **)malloc(num_tags * sizeof (char *)); 1034 if (rc_list.strs == NULL) { 1035 CHK_UNLOCK_CONTAINER(container); 1036 free(tags); 1037 return (FRU_FAILURE); 1038 } 1039 1040 // for each tag fill in it's name. 1041 for (i = 0; i < num_tags; i++) { 1042 const fru_regdef_t *def = fru_reg_lookup_def_by_tag(tags[i]); 1043 if (def != NULL) { 1044 rc_list.strs[i] = strdup(def->name); 1045 if (rc_list.strs[i] == NULL) { 1046 CHK_UNLOCK_CONTAINER(container); 1047 fru_destroy_strlist(&rc_list); 1048 free(tags); 1049 return (FRU_FAILURE); 1050 } 1051 } else { 1052 // instead of failing return "UNKNOWN" 1053 rc_list.strs[i] = strdup(UNKNOWN_PATH); 1054 if (rc_list.strs[i] == NULL) { 1055 CHK_UNLOCK_CONTAINER(container); 1056 fru_destroy_strlist(&rc_list); 1057 free(tags); 1058 return (FRU_FAILURE); 1059 } 1060 } 1061 rc_list.num++; 1062 } 1063 1064 CHK_UNLOCK_CONTAINER(container); 1065 list->num = rc_list.num; 1066 list->strs = rc_list.strs; 1067 free(tags); 1068 return (FRU_SUCCESS); 1069 } 1070 1071 /* ========================================================================= */ 1072 /* Project-private interface */ 1073 extern "C" fru_errno_t 1074 fru_for_each_segment(fru_nodehdl_t container, 1075 int (*function)(fru_seghdl_t segment, void *args), 1076 void *args) 1077 { 1078 fru_errno_t status; 1079 1080 1081 if (data_source == NULL) { 1082 return (FRU_FAILURE); 1083 } 1084 1085 if (lock_container(READ_LOCK, container) != FRU_SUCCESS) { 1086 return (FRU_FAILURE); 1087 } 1088 RETRY(status = 1089 data_source->for_each_segment(NODEHDL_TO_TREEHDL(container), 1090 function, args)) 1091 CHK_UNLOCK_CONTAINER(container); 1092 return (status); 1093 } 1094 1095 /* ========================================================================= */ 1096 /* 1097 * Project-private interface 1098 * 1099 * This routine is only safe when called from within fru_for_each_segment() 1100 * (which is currently the only way to get a segment handle) so that the 1101 * segment's container will be locked 1102 */ 1103 fru_errno_t 1104 fru_get_segment_name(fru_seghdl_t segment, char **name) 1105 { 1106 fru_errno_t err = FRU_SUCCESS; 1107 1108 assert(data_source != NULL); 1109 1110 RETRY(err = data_source->get_segment_name(NODEHDL_TO_TREEHDL(segment), 1111 name)) 1112 return (err); 1113 } 1114 1115 /* ========================================================================= */ 1116 /* 1117 * Project-private interface 1118 * 1119 * This routine is only safe when called from within fru_for_each_segment() 1120 * (which is currently the only way to get a segment handle) so that the 1121 * segment's container will be locked 1122 */ 1123 extern "C" fru_errno_t 1124 fru_for_each_packet(fru_seghdl_t segment, 1125 int (*function)(fru_tag_t *tag, uint8_t *payload, 1126 size_t length, void *args), 1127 void *args) 1128 { 1129 fru_errno_t err = FRU_SUCCESS; 1130 1131 assert(data_source != NULL); 1132 1133 RETRY(err = data_source->for_each_packet(NODEHDL_TO_TREEHDL(segment), 1134 function, args)) 1135 return (err); 1136 } 1137 1138 1139 /* ========================================================================= */ 1140 // To keep track of the number of instances for each type of tag which 1141 // might occur. 1142 struct TagInstPair 1143 { 1144 int inst; 1145 fru_tag_t tag; 1146 }; 1147 1148 struct tag_inst_hist_t 1149 { 1150 TagInstPair *pairs; 1151 unsigned size; 1152 unsigned numStored; 1153 }; 1154 1155 static fru_errno_t 1156 update_tag_inst_hist(tag_inst_hist_t *hist, fru_tag_t tag) 1157 { 1158 // find if this tag has occured before. 1159 int found = 0; 1160 for (int s = 0; s < (hist->numStored); s++) { 1161 if (tags_equal((hist->pairs)[s].tag, tag)) { 1162 // if so just add to the instance. 1163 hist->pairs[s].inst++; 1164 found = 1; 1165 break; 1166 } 1167 } 1168 // if not add to the end of the array of instance 0. 1169 if (!found) { 1170 if (hist->numStored > hist->size) { 1171 return (FRU_FAILURE); 1172 } 1173 (hist->pairs)[(hist->numStored)].tag.raw_data = tag.raw_data; 1174 (hist->pairs)[(hist->numStored)].inst = 0; 1175 (hist->numStored)++; 1176 } 1177 return (FRU_SUCCESS); 1178 } 1179 1180 static fru_errno_t 1181 get_tag_inst_from_hist(tag_inst_hist_t *hist, fru_tag_t tag, int *instance) 1182 { 1183 int j = 0; 1184 for (j = 0; j < hist->numStored; j++) { 1185 if (tags_equal((hist->pairs)[j].tag, tag)) { 1186 *instance = (hist->pairs)[j].inst; 1187 return (FRU_SUCCESS); 1188 } 1189 } 1190 return (FRU_FAILURE); 1191 } 1192 1193 /* ========================================================================= */ 1194 // Input: 1195 // a list of tags and number of them 1196 // and an instance of the unknown payload you are looking for. 1197 // Returns: 1198 // on FRU_SUCCESS 1199 // instance == the instance of the tag "tag" to read from the list 1200 // else 1201 // instance == the number of instances remaining. 1202 // 1203 static fru_errno_t 1204 find_unknown_element(fru_tag_t *tags, int num_tags, 1205 int *instance, fru_tag_t *tag) 1206 { 1207 fru_errno_t err = FRU_SUCCESS; 1208 1209 tag_inst_hist_t hist; 1210 hist.pairs = (TagInstPair *)alloca(sizeof (TagInstPair) * num_tags); 1211 if (hist.pairs == NULL) { 1212 return (FRU_FAILURE); 1213 } 1214 hist.numStored = 0; 1215 hist.size = num_tags; 1216 1217 // search all the tags untill they are exhausted or we find 1218 // the instance we want. 1219 int found = 0; 1220 int instFound = 0; 1221 // NOTE: instancesFound is a running total of the instances in the tags 1222 // WE SKIPED! 1223 // (ie instances left over == instance - instancesFound) 1224 1225 int i = 0; 1226 for (i = 0; i < num_tags; i++) { 1227 1228 const fru_regdef_t *def = fru_reg_lookup_def_by_tag(tags[i]); 1229 // unknown tag encountered. 1230 if (def == NULL) { 1231 if (update_tag_inst_hist(&hist, tags[i]) 1232 != FRU_SUCCESS) { 1233 return (FRU_FAILURE); 1234 } 1235 // do this check because everything is 0 based. 1236 // if we do the add before the check we will go 1237 // to far. 1238 if ((instFound + 1) > (*instance)) { 1239 found = 1; 1240 break; 1241 } else { 1242 instFound++; 1243 } 1244 } 1245 } 1246 1247 *instance -= instFound; 1248 if (!found) { 1249 return (FRU_DATANOTFOUND); 1250 } 1251 1252 (*tag).raw_data = tags[i].raw_data; 1253 if (get_tag_inst_from_hist(&hist, tags[i], instance) != FRU_SUCCESS) { 1254 return (FRU_FAILURE); 1255 } 1256 1257 return (FRU_SUCCESS); 1258 } 1259 1260 // Input: 1261 // a list of tags and number of them 1262 // a list of Ancestors 1263 // the instance we are looking for 1264 // Returns: 1265 // on FRU_SUCCESS 1266 // instance == the instance of the field within the payload to read. 1267 // correct == pointer into ants which is correct. 1268 // tagInstance == instance of the tag 1269 // else 1270 // instance == the number of instances remaining. 1271 // correct == NULL 1272 // tagInstance == UNDEFINED 1273 // 1274 static fru_errno_t 1275 find_known_element(fru_tag_t *tags, int num_tags, Ancestor *ants, 1276 int *instance, Ancestor **correct, 1277 int *tagInstance) 1278 { 1279 int j = 0; 1280 Ancestor *cur = ants; 1281 int num_posible = 0; 1282 while (cur != NULL) { 1283 num_posible++; 1284 cur = cur->next; 1285 } 1286 1287 tag_inst_hist_t hist; 1288 hist.pairs = (TagInstPair *)alloca(sizeof (TagInstPair) * num_posible); 1289 hist.size = num_posible; 1290 if (hist.pairs == NULL) { 1291 return (FRU_FAILURE); 1292 } 1293 hist.numStored = 0; 1294 1295 *correct = NULL; 1296 int i = 0; 1297 int found = 0; 1298 int instancesFound = 0; 1299 // NOTE: instancesFound is a running total of the instances in the tags 1300 // WE SKIPED! 1301 // (ie instances left over == instance - instancesFound) 1302 for (i = 0; i < num_tags; i++) { 1303 cur = ants; 1304 while (cur != NULL) { 1305 if (tags_equal(cur->getTag(), tags[i])) { 1306 if (update_tag_inst_hist(&hist, tags[i]) 1307 != FRU_SUCCESS) { 1308 return (FRU_FAILURE); 1309 } 1310 1311 // do this check because everything is 0 based. 1312 // if we do the add before the check we will go 1313 // to far. 1314 if ((instancesFound + cur->getNumInstances()) 1315 > (*instance)) { 1316 *correct = cur; 1317 found = 1; 1318 break; /* while loop */ 1319 } 1320 instancesFound += cur->getNumInstances(); 1321 } 1322 cur = cur->next; 1323 } 1324 /* when found break out of both "for" and "while" loops */ 1325 if (found == 1) { 1326 break; /* for loop */ 1327 } 1328 } 1329 1330 *instance -= instancesFound; 1331 if (!found) { 1332 return (FRU_DATANOTFOUND); 1333 } 1334 1335 if (get_tag_inst_from_hist(&hist, tags[i], tagInstance) 1336 != FRU_SUCCESS) { 1337 return (FRU_FAILURE); 1338 } 1339 1340 return (FRU_SUCCESS); 1341 } 1342 1343 /* 1344 * Same as find_known_element but ONLY searches for absolute paths 1345 * (ie PathDef->head == tag) 1346 */ 1347 static fru_errno_t 1348 find_known_element_abs(fru_tag_t *tags, int num_tags, int *instance, 1349 PathDef *head, Ancestor *ants, Ancestor **correct, 1350 int *tagInstance) 1351 { 1352 *correct = NULL; 1353 // find the exact ancestor we want. 1354 Ancestor *cur = ants; 1355 while (cur != NULL) { 1356 if (strcmp(cur->getDef()->name, head->def->name) == 0) { 1357 *correct = cur; 1358 break; 1359 } 1360 cur = cur->next; 1361 } 1362 if (cur == NULL) { 1363 // serious parser bug might cause this, double check. 1364 return (FRU_FAILURE); 1365 } 1366 1367 int found = 0; 1368 (*tagInstance) = 0; 1369 for (int i = 0; i < num_tags; i++) { 1370 if (tags_equal(cur->getTag(), tags[i])) { 1371 // do this check because everything is 0 based. 1372 // if we do the add before the check we will go 1373 // to far. 1374 if (((*tagInstance) +1) > (*instance)) { 1375 *correct = cur; 1376 found = 1; 1377 break; 1378 } 1379 (*tagInstance)++; 1380 } 1381 } 1382 1383 *instance -= (*tagInstance); 1384 if (!found) { 1385 return (FRU_DATANOTFOUND); 1386 } 1387 1388 return (FRU_SUCCESS); 1389 } 1390 1391 1392 /* ========================================================================= */ 1393 // From the container, seg_name, instance, and field_path get me... 1394 // pathDef: A linked list of Path Def objects which represent the 1395 // field_path 1396 // ancestors: A linked list of Tagged Ancestors which represent the 1397 // possible payloads this data MAY reside in. 1398 // correct: A pointer into the above list which indicates the Ancestor 1399 // in which this instance actually resides. 1400 // tagInstance: The instance of this ancestor in the segment. (ie Tag 1401 // instance) 1402 // instWICur: The instance of this element within the tag itself. 1403 // Or in other words "the instances left" 1404 // payload: The payload data 1405 // 1406 // For an "UNKNOWN" payload this will return NULL for the pathDef, ancestors, 1407 // cur pointers. This will indicate to read that this payload should be 1408 // returned with a special definition for it (UNKNOWN)... What a HACK I 1409 // know... 1410 #define READ_MODE 0 1411 #define UPDATE_MODE 1 1412 static fru_errno_t get_payload(fru_nodehdl_t container, 1413 const char *seg_name, 1414 int instance, 1415 const char *field_path, 1416 // returns the following... 1417 PathDef **pathDef, 1418 Ancestor **ancestors, 1419 Ancestor **correct, 1420 int *tagInstance, // instance of the tag within the seg 1421 int *instLeft, // within this payload 1422 uint8_t **payload, 1423 size_t *payloadLen, 1424 int mode) 1425 { 1426 int abs_path_flg = 0; 1427 fru_errno_t err = FRU_SUCCESS; 1428 int num_tags = 0; 1429 fru_tag_t *tags = NULL; 1430 1431 if (data_source == NULL) { 1432 return (FRU_FAILURE); 1433 } 1434 RETRY(err = data_source->get_tag_list(NODEHDL_TO_TREEHDL(container), 1435 seg_name, &tags, &num_tags)) 1436 if (err != FRU_SUCCESS) { 1437 return (err); 1438 } 1439 1440 if (num_tags == 0) { 1441 *instLeft = instance; 1442 return (FRU_DATANOTFOUND); 1443 } 1444 1445 if (IS_UNKNOWN_PATH(field_path)) { 1446 fru_tag_t tagToRead; 1447 1448 *pathDef = NULL; 1449 *correct = *ancestors = NULL; 1450 *tagInstance = 0; 1451 1452 int unknown_inst = instance; 1453 if ((err = find_unknown_element(tags, num_tags, &unknown_inst, 1454 &tagToRead)) != FRU_SUCCESS) { 1455 *instLeft = unknown_inst; 1456 free(tags); 1457 return (err); 1458 } 1459 RETRY(err = 1460 data_source->get_tag_data(NODEHDL_TO_TREEHDL(container), 1461 seg_name, tagToRead, unknown_inst, payload, 1462 payloadLen)) 1463 free(tags); 1464 return (err); 1465 } 1466 1467 err = fru_field_parser(field_path, ancestors, 1468 &abs_path_flg, pathDef); 1469 1470 if (err != FRU_SUCCESS) { 1471 free(tags); 1472 return (err); 1473 } else if (ancestors == NULL) { 1474 /* without valid ancestors we can't find payloads for this */ 1475 free(tags); 1476 delete pathDef; 1477 return (FRU_INVALELEMENT); 1478 } 1479 1480 if ((mode == UPDATE_MODE) && (abs_path_flg != 1)) { 1481 free(tags); 1482 delete *ancestors; // linked list 1483 delete *pathDef; 1484 return (FRU_INVALPATH); 1485 } 1486 1487 if (abs_path_flg == 1) { 1488 if ((err = find_known_element_abs(tags, num_tags, &instance, 1489 *pathDef, *ancestors, correct, tagInstance)) 1490 != FRU_SUCCESS) { 1491 // set up to search next segment for instances left 1492 // over 1493 *instLeft = instance; 1494 free(tags); 1495 delete *ancestors; // linked list 1496 delete *pathDef; 1497 return (err); 1498 } 1499 } else { 1500 if ((err = find_known_element(tags, num_tags, *ancestors, 1501 &instance, correct, tagInstance)) 1502 != FRU_SUCCESS) { 1503 // set up to search next segment for instances left 1504 // over 1505 *instLeft = instance; 1506 free(tags); 1507 delete *ancestors; // linked list 1508 delete *pathDef; 1509 return (err); 1510 } 1511 } 1512 1513 // if we get here this means the instance number within the payload. 1514 *instLeft = instance; 1515 RETRY(err = data_source->get_tag_data(NODEHDL_TO_TREEHDL(container), 1516 seg_name, (*correct)->getTag(), (*tagInstance), payload, 1517 payloadLen)) 1518 free(tags); 1519 if (err != FRU_SUCCESS) { 1520 delete *ancestors; // linked list 1521 delete *pathDef; 1522 } 1523 return (err); 1524 } 1525 1526 /* ========================================================================= */ 1527 /* 1528 * Handle decryption if necessary 1529 */ 1530 static fru_errno_t 1531 do_decryption(fru_nodehdl_t container, const char *seg_name, 1532 uint8_t *payload, size_t payloadLen) 1533 { 1534 fru_errno_t err = FRU_SUCCESS; 1535 if (segment_is_encrypted(container, seg_name)) { 1536 if (fru_encryption_supported() == FRU_SUCCESS) { 1537 if ((err = encrypt_func(FRU_DECRYPT, 1538 payload, payloadLen)) != FRU_SUCCESS) { 1539 return (err); 1540 } 1541 } else { 1542 return (FRU_FAILURE); 1543 } 1544 } 1545 return (FRU_SUCCESS); 1546 } 1547 1548 /* ========================================================================= */ 1549 // Same as get_payload except if seg_name is NULL and it will find the one 1550 // used and return it. 1551 // 1552 static fru_errno_t 1553 get_seg_and_payload(fru_nodehdl_t container, 1554 char **seg_name, 1555 int instance, 1556 const char *field_path, 1557 // returns the following... 1558 PathDef **pathDef, 1559 Ancestor **ancestors, 1560 Ancestor **correct, 1561 int *tagInstance, // within the segment. 1562 int *instLeft, // within this payload 1563 uint8_t **payload, 1564 size_t *payloadLen) 1565 { 1566 fru_errno_t err = FRU_SUCCESS; 1567 if ((err = is_container(container)) != FRU_SUCCESS) { 1568 return (err); 1569 } 1570 1571 if (field_path == NULL) 1572 return (FRU_INVALPATH); 1573 1574 if ((*seg_name) != NULL) { 1575 1576 // always check for valid segment names. 1577 if (strlen((const char *)(*seg_name)) > FRU_SEGNAMELEN) { 1578 return (FRU_INVALSEG); 1579 } 1580 1581 if ((err = get_payload(container, (const char *)(*seg_name), 1582 instance, field_path, pathDef, ancestors, correct, 1583 tagInstance, instLeft, payload, payloadLen, READ_MODE)) 1584 != FRU_SUCCESS) { 1585 return (err); 1586 } 1587 return (do_decryption(container, (const char *)(*seg_name), 1588 *payload, *payloadLen)); 1589 1590 } else { 1591 fru_strlist_t seg_list; 1592 1593 if ((err = get_seg_list_from_ds(container, &seg_list)) 1594 != FRU_SUCCESS) { 1595 return (err); 1596 } 1597 1598 int found = 0; 1599 for (int i = 0; i < seg_list.num; i++) { 1600 err = get_payload(container, 1601 seg_list.strs[i], 1602 instance, field_path, 1603 pathDef, ancestors, correct, 1604 tagInstance, instLeft, 1605 payload, payloadLen, READ_MODE); 1606 if (err == FRU_SUCCESS) { 1607 (*seg_name) = strdup(seg_list.strs[i]); 1608 fru_destroy_strlist(&seg_list); 1609 return (do_decryption(container, 1610 (const char *)(*seg_name), 1611 *payload, *payloadLen)); 1612 } else if (err == FRU_DATANOTFOUND) { 1613 // we may have found some instances or none at 1614 // all but not enough all together. search 1615 // again with the # of instances left. 1616 instance = *instLeft; 1617 } else { 1618 fru_destroy_strlist(&seg_list); 1619 return (err); 1620 } 1621 } 1622 fru_destroy_strlist(&seg_list); 1623 return (FRU_DATANOTFOUND); 1624 } 1625 } 1626 1627 /* ========================================================================= */ 1628 fru_errno_t 1629 fru_read_field(fru_nodehdl_t container, 1630 char **seg_name, unsigned int instance, 1631 const char *field_path, 1632 void **data, size_t *data_len, 1633 char **found_path) 1634 { 1635 fru_errno_t err = FRU_SUCCESS; 1636 // just init this value for the user 1637 *data = NULL; 1638 *data_len = 0; 1639 1640 if (lock_container(READ_LOCK, container) != FRU_SUCCESS) { 1641 return (FRU_FAILURE); 1642 } 1643 PathDef *pathDef; 1644 Ancestor *ancestors; 1645 Ancestor *correctAnt; 1646 int tagInstance = 0; 1647 int instWIPayload = 0; 1648 uint8_t *payload; 1649 size_t payloadLen = 0; 1650 err = get_seg_and_payload(container, seg_name, instance, field_path, 1651 &pathDef, &ancestors, &correctAnt, &tagInstance, 1652 &instWIPayload, &payload, &payloadLen); 1653 1654 CHK_UNLOCK_CONTAINER(container); 1655 1656 if (err != FRU_SUCCESS) { 1657 return (err); 1658 } 1659 1660 if (pathDef == NULL) { // SPECIAL CASE of UNKNOW payload. 1661 delete ancestors; 1662 delete pathDef; 1663 free(payload); 1664 1665 *data = (void *)malloc(payloadLen); 1666 if ((*data) == NULL) { 1667 return (FRU_FAILURE); 1668 } 1669 memcpy(*data, payload, payloadLen); 1670 *data_len = payloadLen; 1671 if (found_path != NULL) { 1672 *found_path = strdup(UNKNOWN_PATH); 1673 } 1674 return (FRU_SUCCESS); 1675 } 1676 1677 // get the specific data 1678 err = PayloadReader::readData(pathDef, correctAnt, 1679 instWIPayload, 1680 payload, payloadLen, 1681 data, data_len); 1682 delete pathDef; 1683 free(payload); 1684 1685 if (err == FRU_SUCCESS) { 1686 if (found_path != NULL) { 1687 *found_path = (char *)malloc( 1688 strlen(correctAnt->getPath(instWIPayload)) 1689 + strlen(field_path) + 2); 1690 if ((*found_path) == NULL) { 1691 delete ancestors; 1692 return (FRU_FAILURE); 1693 } 1694 sprintf(*found_path, "%s%s", 1695 correctAnt->getPath(instWIPayload), 1696 field_path); 1697 } 1698 } 1699 1700 delete ancestors; 1701 return (err); 1702 } 1703 1704 /* ========================================================================= */ 1705 fru_errno_t 1706 fru_update_field(fru_nodehdl_t container, 1707 char *seg_name, unsigned int instance, 1708 const char *field_path, 1709 void *data, size_t length) 1710 { 1711 fru_errno_t err = FRU_SUCCESS; 1712 1713 if ((field_path == NULL) || IS_UNKNOWN_PATH(field_path)) { 1714 return (FRU_INVALPATH); 1715 } else if (seg_name == NULL) { 1716 return (FRU_INVALSEG); 1717 } 1718 1719 if (data_source == NULL) { 1720 return (FRU_FAILURE); 1721 } 1722 1723 if (lock_container(WRITE_LOCK, container) != FRU_SUCCESS) { 1724 return (FRU_FAILURE); 1725 } 1726 PathDef *pathDef; 1727 Ancestor *ancestors; 1728 Ancestor *correctAnt; 1729 int tagInstance = 0; 1730 int instWIPayload = 0; 1731 uint8_t *payload; 1732 size_t payloadLen = 0; 1733 err = get_payload(container, seg_name, instance, field_path, 1734 &pathDef, &ancestors, &correctAnt, &tagInstance, 1735 &instWIPayload, &payload, &payloadLen, UPDATE_MODE); 1736 1737 if (err != FRU_SUCCESS) { 1738 CHK_UNLOCK_CONTAINER(container); 1739 return (err); 1740 } 1741 1742 if ((err = do_decryption(container, (const char *)seg_name, 1743 payload, payloadLen)) != FRU_SUCCESS) { 1744 free(payload); 1745 return (err); 1746 } 1747 1748 // fill in the new data in the payload 1749 err = PayloadReader::updateData(pathDef, correctAnt, instWIPayload, 1750 payload, payloadLen, 1751 data, length); 1752 1753 if (err != FRU_SUCCESS) { 1754 CHK_UNLOCK_CONTAINER(container); 1755 delete ancestors; // linked list. 1756 delete pathDef; 1757 free(payload); 1758 return (err); 1759 } 1760 1761 if ((segment_is_encrypted(container, seg_name)) && 1762 (fru_encryption_supported() == FRU_SUCCESS)) { 1763 if ((err = encrypt_func(FRU_ENCRYPT, payload, payloadLen)) 1764 != FRU_SUCCESS) { 1765 CHK_UNLOCK_CONTAINER(container); 1766 delete ancestors; // linked list. 1767 delete pathDef; 1768 free(payload); 1769 return (err); 1770 } 1771 } 1772 1773 RETRY(err = data_source->set_tag_data(NODEHDL_TO_TREEHDL(container), 1774 seg_name, correctAnt->getTag(), 1775 tagInstance, payload, payloadLen)) 1776 CHK_UNLOCK_CONTAINER(container); 1777 delete ancestors; // linked list. 1778 free(payload); 1779 delete pathDef; 1780 return (err); 1781 } 1782 1783 /* ========================================================================= */ 1784 fru_errno_t 1785 fru_get_num_iterations(fru_nodehdl_t container, 1786 char **seg_name, 1787 unsigned int instance, 1788 const char *iter_path, 1789 int *num_there, 1790 char **found_path) 1791 { 1792 // this ensures a more descriptive error message. 1793 fru_errno_t err = FRU_SUCCESS; 1794 1795 if (lock_container(READ_LOCK, container) != FRU_SUCCESS) { 1796 return (FRU_FAILURE); 1797 } 1798 PathDef *pathDef; 1799 Ancestor *ancestors; 1800 Ancestor *correctAnt; 1801 int tagInstance = 0; 1802 int instWIPayload = 0; 1803 uint8_t *payload; 1804 size_t payloadLen = 0; 1805 err = get_seg_and_payload(container, seg_name, instance, iter_path, 1806 &pathDef, &ancestors, &correctAnt, &tagInstance, 1807 &instWIPayload, &payload, &payloadLen); 1808 1809 CHK_UNLOCK_CONTAINER(container); 1810 1811 if (err != FRU_SUCCESS) { 1812 return (err); 1813 } 1814 1815 if (pathDef == NULL) { // SPECIAL CASE of UNKNOW payload. 1816 // clean up memory from called functions. 1817 err = FRU_INVALPATH; 1818 } else { 1819 // get the specific data 1820 err = PayloadReader::findIterThere(pathDef, correctAnt, 1821 instWIPayload, 1822 payload, payloadLen, 1823 num_there); 1824 } 1825 1826 delete pathDef; 1827 free(payload); 1828 1829 if (err == FRU_SUCCESS) { 1830 if (found_path != NULL) { 1831 *found_path = (char *)malloc( 1832 strlen(correctAnt->getPath(instWIPayload)) 1833 + strlen(iter_path) + 2); 1834 if ((*found_path) == NULL) { 1835 delete ancestors; 1836 return (FRU_FAILURE); 1837 } 1838 sprintf(*found_path, "%s%s", 1839 correctAnt->getPath(instWIPayload), 1840 iter_path); 1841 } 1842 } 1843 1844 delete ancestors; 1845 return (err); 1846 } 1847 1848 /* ========================================================================= */ 1849 // When adding a new payload with 0 data the iteration control bytes must be 1850 // filled in with the number possible. 1851 fru_errno_t 1852 fill_in_iteration_control_bytes(uint8_t *data, 1853 const fru_regdef_t *def, 1854 int inIteration) 1855 { 1856 fru_errno_t rc = FRU_SUCCESS; 1857 1858 if ((def->iterationType == FRU_NOT_ITERATED) || 1859 (inIteration)) { 1860 1861 if (def->dataType == FDTYPE_Record) { 1862 1863 int offset = 0; 1864 for (int i = 0; i < def->enumCount; i++) { 1865 const fru_regdef_t *newDef 1866 = fru_reg_lookup_def_by_name((char *)def->enumTable[i].text); 1867 fru_errno_t rc2 1868 = fill_in_iteration_control_bytes(&(data[offset]), newDef, 0); 1869 if (rc2 != FRU_SUCCESS) 1870 return (rc2); 1871 offset += newDef->payloadLen; 1872 } 1873 1874 } // else field, no sub elements; do nothing... ;-) 1875 1876 } else { 1877 data[3] = (char)def->iterationCount; 1878 1879 int offset = 3; 1880 for (int i = 0; i < def->iterationCount; i++) { 1881 fru_errno_t rc3 1882 = fill_in_iteration_control_bytes(&(data[offset]), def, 1); 1883 if (rc3 != FRU_SUCCESS) 1884 return (rc3); 1885 offset += ((def->payloadLen - 4)/(def->iterationCount)); 1886 } 1887 } 1888 1889 return (rc); 1890 } 1891 1892 /* ========================================================================= */ 1893 fru_errno_t 1894 fru_add_element(fru_nodehdl_t container, 1895 const char *seg_name, 1896 const char *element) 1897 { 1898 fru_errno_t err = FRU_SUCCESS; 1899 1900 if ((seg_name == NULL) || (strlen(seg_name) > FRU_SEGNAMELEN)) { 1901 return (FRU_INVALSEG); 1902 } 1903 1904 const fru_regdef_t *def 1905 = fru_reg_lookup_def_by_name((char *)element); 1906 if (def == NULL) { 1907 return (FRU_NOREGDEF); 1908 } 1909 if (def->tagType == FRU_X) { 1910 return (FRU_ELEMNOTTAGGED); 1911 } 1912 1913 if (data_source == NULL) { 1914 return (FRU_FAILURE); 1915 } 1916 1917 if ((err = is_container(container)) != FRU_SUCCESS) { 1918 return (err); 1919 } 1920 1921 if (lock_container(WRITE_LOCK, container) != FRU_SUCCESS) { 1922 return (FRU_FAILURE); 1923 } 1924 1925 fru_tag_t tag; 1926 mk_tag(def->tagType, def->tagDense, def->payloadLen, &tag); 1927 uint8_t *data = new uint8_t[def->payloadLen]; 1928 memset(data, 0x00, def->payloadLen); 1929 1930 err = fill_in_iteration_control_bytes(data, def, 0); 1931 if (err != FRU_SUCCESS) { 1932 CHK_UNLOCK_CONTAINER(container); 1933 delete[] data; 1934 return (err); 1935 } 1936 1937 if (segment_is_encrypted(container, seg_name)) { 1938 if (fru_encryption_supported() == FRU_NOTSUP) { 1939 CHK_UNLOCK_CONTAINER(container); 1940 delete[] data; 1941 return (FRU_INVALSEG); 1942 } 1943 if ((err = encrypt_func(FRU_ENCRYPT, data, 1944 def->payloadLen)) != FRU_SUCCESS) { 1945 CHK_UNLOCK_CONTAINER(container); 1946 delete[] data; 1947 return (err); 1948 } 1949 } 1950 1951 RETRY(err = data_source->add_tag_to_seg(NODEHDL_TO_TREEHDL(container), 1952 seg_name, tag, data, def->payloadLen)) 1953 CHK_UNLOCK_CONTAINER(container); 1954 delete[] data; 1955 return (err); 1956 } 1957 1958 /* ========================================================================= */ 1959 fru_errno_t 1960 fru_delete_element(fru_nodehdl_t container, 1961 const char *seg_name, 1962 unsigned int instance, 1963 const char *element) 1964 { 1965 fru_errno_t err = FRU_SUCCESS; 1966 1967 if ((seg_name == NULL) || (strlen(seg_name) > FRU_SEGNAMELEN)) { 1968 return (FRU_INVALSEG); 1969 } 1970 1971 if (data_source == NULL) { 1972 return (FRU_FAILURE); 1973 } 1974 1975 if ((err = is_container(container)) != FRU_SUCCESS) { 1976 return (err); 1977 } 1978 1979 if (lock_container(WRITE_LOCK, container) != FRU_SUCCESS) { 1980 return (FRU_FAILURE); 1981 } 1982 if ((segment_is_encrypted(container, seg_name)) && 1983 (fru_encryption_supported() == FRU_NOTSUP)) { 1984 CHK_UNLOCK_CONTAINER(container); 1985 return (FRU_INVALSEG); 1986 } 1987 1988 fru_tag_t tag; 1989 int localInst = instance; 1990 // again the special case of UNKNOWN. This allows us to delete these 1991 // elements if they are somehow not wanted. 1992 // NOTE: "/UNKNOWN" is not supported just as "/ManR" would not be valid 1993 // either. Both of these will result in returning FRU_NOREGDEF 1994 if (strcmp(element, "UNKNOWN") == 0) { 1995 fru_tag_t *tags = NULL; 1996 int num_tags = 0; 1997 1998 RETRY(err = 1999 data_source->get_tag_list(NODEHDL_TO_TREEHDL(container), 2000 seg_name, &tags, &num_tags)) 2001 2002 if (err != FRU_SUCCESS) { 2003 CHK_UNLOCK_CONTAINER(container); 2004 return (err); 2005 } 2006 if ((err = find_unknown_element(tags, num_tags, 2007 &localInst, &tag)) != FRU_SUCCESS) { 2008 free(tags); 2009 CHK_UNLOCK_CONTAINER(container); 2010 return (err); 2011 } 2012 free(tags); 2013 } else { 2014 const fru_regdef_t *def 2015 = fru_reg_lookup_def_by_name((char *)element); 2016 if (def == NULL) { 2017 CHK_UNLOCK_CONTAINER(container); 2018 return (FRU_NOREGDEF); 2019 } 2020 if (def->tagType == FRU_X) { 2021 CHK_UNLOCK_CONTAINER(container); 2022 return (FRU_ELEMNOTTAGGED); 2023 } 2024 mk_tag(def->tagType, def->tagDense, def->payloadLen, &tag); 2025 } 2026 2027 RETRY(err = data_source->delete_tag(NODEHDL_TO_TREEHDL(container), 2028 seg_name, tag, instance)) 2029 CHK_UNLOCK_CONTAINER(container); 2030 return (err); 2031 } 2032 2033 /* General library support */ 2034 /* ========================================================================= */ 2035 static fru_errno_t 2036 make_definition(const fru_regdef_t *def, fru_elemdef_t *definition) 2037 { 2038 definition->version = FRU_ELEMDEF_REV; 2039 definition->data_type = def->dataType; 2040 if (def->tagType != FRU_X) 2041 definition->tagged = FRU_Yes; 2042 else 2043 definition->tagged = FRU_No; 2044 2045 // zzz 2046 // This should be the following statement. 2047 // (*definition)->data_length = def->dataLength; 2048 // instead of. 2049 if (def->iterationType != FRU_NOT_ITERATED) { 2050 int elemLen = ((def->dataLength-4)/def->iterationCount); 2051 definition->data_length = elemLen; 2052 } else { 2053 definition->data_length = def->dataLength; 2054 } 2055 // END zzz 2056 2057 definition->disp_type = def->dispType; 2058 definition->purgeable = def->purgeable; 2059 definition->relocatable = def->relocatable; 2060 2061 definition->enum_count = 0; 2062 definition->enum_table = NULL; 2063 2064 unsigned int count = def->enumCount; 2065 if (count != 0) { 2066 definition->enum_table = (fru_enum_t *)malloc( 2067 (sizeof (fru_enum_t)) * count); 2068 if ((definition->enum_table) == NULL) { 2069 return (FRU_FAILURE); 2070 } 2071 memset(definition->enum_table, 0x00, 2072 ((sizeof (fru_enum_t)) * count)); 2073 } 2074 2075 for (int i = 0; i < count; i++) { 2076 definition->enum_table[i].value = def->enumTable[i].value; 2077 definition->enum_table[i].text = strdup(def->enumTable[i].text); 2078 if ((definition->enum_table[i].text) == NULL) { 2079 fru_destroy_elemdef(definition); 2080 return (FRU_FAILURE); 2081 } 2082 (definition->enum_count)++; 2083 } 2084 2085 definition->iteration_count = def->iterationCount; 2086 definition->iteration_type = def->iterationType; 2087 2088 definition->example_string = strdup(def->exampleString); 2089 if ((definition->example_string) == NULL) { 2090 fru_destroy_elemdef(definition); 2091 return (FRU_FAILURE); 2092 } 2093 2094 return (FRU_SUCCESS); 2095 } 2096 2097 /* ========================================================================= */ 2098 fru_errno_t 2099 fru_get_definition(const char *element_name, 2100 fru_elemdef_t *definition) 2101 { 2102 // find the last one in the string... 2103 int abs_path_flg = 0; 2104 Ancestor *ancestors = NULL; 2105 PathDef *pathDef = NULL; 2106 fru_errno_t err = FRU_SUCCESS; 2107 2108 err = fru_field_parser(element_name, &ancestors, 2109 &abs_path_flg, &pathDef); 2110 if (err != FRU_SUCCESS) { 2111 return (err); 2112 } 2113 2114 PathDef *last = pathDef; 2115 while (last->next != NULL) 2116 last = last->next; 2117 2118 err = make_definition(last->def, definition); 2119 2120 delete ancestors; 2121 delete pathDef; 2122 return (err); 2123 } 2124 2125 /* ========================================================================= */ 2126 fru_errno_t 2127 fru_get_registry(fru_strlist_t *list) 2128 { 2129 fru_errno_t err = FRU_SUCCESS; 2130 unsigned int number = 0; 2131 char **entries = fru_reg_list_entries(&number); 2132 if (entries == NULL) { 2133 return (FRU_FAILURE); 2134 } 2135 list->strs = entries; 2136 list->num = number; 2137 return (FRU_SUCCESS); 2138 } 2139 2140 /* ========================================================================= */ 2141 fru_errno_t 2142 fru_get_tagged_parents(const char *element, fru_strlist_t *parents) 2143 { 2144 Ancestor *ancestors 2145 = Ancestor::listTaggedAncestors((char *)element); 2146 2147 Ancestor *cur = ancestors; 2148 /* count them */ 2149 int number = 0; 2150 while (cur != NULL) { 2151 number++; 2152 cur = cur->next; 2153 } 2154 2155 parents->num = 0; 2156 parents->strs = NULL; 2157 if (number == 0) { 2158 return (FRU_SUCCESS); 2159 } 2160 parents->strs = (char **)malloc(number * sizeof (char *)); 2161 if (parents->strs == NULL) { 2162 return (FRU_FAILURE); 2163 } 2164 memset(parents->strs, 0x00, (number * sizeof (char *))); 2165 2166 cur = ancestors; 2167 for (int i = 0; i < number; i++) { 2168 if (cur == NULL) { 2169 fru_destroy_strlist(parents); 2170 return (FRU_FAILURE); 2171 } 2172 parents->strs[i] = strdup(cur->getDef()->name); 2173 if (parents->strs[i] == NULL) { 2174 fru_destroy_strlist(parents); 2175 return (FRU_FAILURE); 2176 } 2177 parents->num++; 2178 cur = cur->next; 2179 } 2180 2181 return (FRU_SUCCESS); 2182 } 2183 2184 /* 2185 * Enum string converters. 2186 */ 2187 /* ========================================================================= */ 2188 const char * 2189 get_displaytype_str(fru_displaytype_t e) 2190 { 2191 switch (e) { 2192 case FDISP_Binary: 2193 return (gettext("Binary")); 2194 case FDISP_Hex: 2195 return (gettext("Hex")); 2196 case FDISP_Decimal: 2197 return (gettext("Decimal")); 2198 case FDISP_Octal: 2199 return (gettext("Octal")); 2200 case FDISP_String: 2201 return (gettext("String")); 2202 case FDISP_Time: 2203 return (gettext("Time")); 2204 case FDISP_UNDEFINED: 2205 return (gettext("UNDEFINED")); 2206 } 2207 return (gettext("UNDEFINED")); 2208 } 2209 2210 /* ========================================================================= */ 2211 const char * 2212 get_datatype_str(fru_datatype_t e) 2213 { 2214 switch (e) { 2215 case FDTYPE_Binary: 2216 return (gettext("Binary")); 2217 case FDTYPE_ByteArray: 2218 return (gettext("Byte Array")); 2219 case FDTYPE_ASCII: 2220 return (gettext("ASCII")); 2221 case FDTYPE_Unicode: 2222 return (gettext("Unicode")); 2223 case FDTYPE_Record: 2224 return (gettext("Record")); 2225 case FDTYPE_Enumeration: 2226 return (gettext("Enumeration")); 2227 case FDTYPE_UNDEFINED: 2228 return (gettext("UNDEFINED")); 2229 } 2230 return (gettext("UNDEFINED")); 2231 } 2232 /* ========================================================================= */ 2233 const char * 2234 get_which_str(fru_which_t e) 2235 { 2236 switch (e) { 2237 case FRU_No: 2238 return (gettext("No")); 2239 case FRU_Yes: 2240 return (gettext("Yes")); 2241 case FRU_WHICH_UNDEFINED: 2242 return (gettext("WHICH UNDEFINED")); 2243 } 2244 return (gettext("WHICH UNDEFINED")); 2245 } 2246 /* ========================================================================= */ 2247 const char * 2248 get_itertype_str(fru_itertype_t e) 2249 { 2250 switch (e) { 2251 case FRU_FIFO: 2252 return (gettext("FIFO")); 2253 case FRU_Circular: 2254 return (gettext("Circular")); 2255 case FRU_Linear: 2256 return (gettext("Linear")); 2257 case FRU_LIFO: 2258 return (gettext("LIFO")); 2259 case FRU_NOT_ITERATED: 2260 return (gettext("NOT ITERATED")); 2261 } 2262 return (gettext("NOT ITERATED")); 2263 } 2264