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