lib: remove unused libnvfru
[unleashed.git] / usr / src / lib / libfru / libfru / libfru.cc
blobc76a70fc673e2674d6e0635663ac35b4c87d1149
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
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.
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.
49 * This algorithim is altered only when dealing with "UNKNOWN" payloads where
50 * it simplifies slightly.
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>
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"
72 #define DATA_SOURCE_OBJ_NAME "data_source"
74 #define ENCRYPTION_LIB_NAME "libfrucrypt.so.1"
75 #define FRU_ENCRYPT_FUNC_NAME "fru_encrypt_func"
77 #define UNKNOWN_PATH "UNKNOWN"
78 #define IS_UNKNOWN_PATH(path) \
79 ((strcmp(path, "/UNKNOWN") == 0) || (strcmp(path, "UNKNOWN") == 0))
81 #define NODEHDL_TO_TREEHDL(nodehdl) (fru_treehdl_t)nodehdl
82 #define TREEHDL_TO_NODEHDL(treehdl) (fru_nodehdl_t)treehdl
84 /* ========================================================================= */
86 * Define a hash of rwlocks for each container.
88 struct cont_lock
90 fru_nodehdl_t handle;
91 pthread_rwlock_t lock;
92 struct cont_lock *next;
94 typedef struct cont_lock cont_lock_t;
96 fru_encrypt_func_t encrypt_func;
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;
102 typedef enum { WRITE_LOCK, READ_LOCK } lock_mode_t;
105 * These control the Data sources available.
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;
113 #define FRU_NORESPONSE_RETRY 500
115 #define RETRY(expr) \
116 { for (int loop = 0; loop < FRU_NORESPONSE_RETRY && \
117 (expr) == FRU_NORESPONSE; loop++) ; \
120 /* ========================================================================= */
121 static const char *fru_errmsg[] =
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"
150 fru_errno_t
151 fru_encryption_supported(void)
153 if (encrypt_func == NULL)
154 return (FRU_NOTSUP);
155 else
156 return (FRU_SUCCESS);
159 extern "C" {
160 void
161 init_libfru(void)
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);
172 #pragma init(init_libfru)
175 /* ========================================================================= */
176 static void
177 add_cont_lock(cont_lock_t *lock)
179 cont_lock_t *prev = NULL;
180 int hash_bucket = lock->handle % CONT_LOCK_HASH_NUM;
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;
190 prev->next = lock;
194 /* ========================================================================= */
195 static cont_lock_t *
196 find_cont_lock(fru_nodehdl_t handle)
198 int hash_bucket = handle % CONT_LOCK_HASH_NUM;
199 cont_lock_t *which = cont_lock_hash[hash_bucket];
201 while (which != NULL) {
202 if (which->handle == handle) {
203 break;
205 which = which->next;
207 return (which);
210 /* ========================================================================= */
211 static cont_lock_t *
212 alloc_cont_lock(fru_nodehdl_t handle)
214 cont_lock_t *lock = (cont_lock_t *)malloc(sizeof (cont_lock_t));
215 if (lock == NULL) {
216 return (NULL);
218 lock->handle = handle;
219 if (pthread_rwlock_init(&(lock->lock), NULL) != 0) {
220 free(lock);
221 return (NULL);
223 lock->next = NULL;
224 return (lock);
227 /* ========================================================================= */
228 static fru_errno_t
229 lock_container(lock_mode_t mode, fru_nodehdl_t handle)
231 cont_lock_t *which = NULL;
232 int hash_bucket = 0;
233 int lock_rc;
235 pthread_mutex_lock(&cont_lock_hash_lock);
237 which = find_cont_lock(handle);
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);
245 add_cont_lock(which);
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;
259 pthread_mutex_unlock(&cont_lock_hash_lock);
260 if (lock_rc != 0) {
261 return (FRU_FAILURE);
263 return (FRU_SUCCESS);
266 /* ========================================================================= */
268 * Macro to make checking unlock_conatiner error code easier
270 #define CHK_UNLOCK_CONTAINER(handle) \
271 if (unlock_container(handle) != FRU_SUCCESS) { \
272 return (FRU_FAILURE); \
274 static fru_errno_t
275 unlock_container(fru_nodehdl_t handle)
277 cont_lock_t *which = NULL;
278 pthread_mutex_lock(&cont_lock_hash_lock);
280 which = find_cont_lock(handle);
281 if (which == NULL) {
282 pthread_mutex_unlock(&cont_lock_hash_lock);
283 return (FRU_NODENOTFOUND);
286 if (pthread_rwlock_unlock(&(which->lock)) != 0) {
287 pthread_mutex_unlock(&cont_lock_hash_lock);
288 return (FRU_FAILURE);
291 pthread_mutex_unlock(&cont_lock_hash_lock);
292 return (FRU_SUCCESS);
295 /* ========================================================================= */
296 static fru_errno_t
297 clear_cont_locks(void)
299 pthread_mutex_lock(&cont_lock_hash_lock);
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);
311 cont_lock_hash[i] = NULL;
314 pthread_mutex_unlock(&cont_lock_hash_lock);
315 return (FRU_SUCCESS);
319 /* ========================================================================= */
320 /* VARARGS */
321 fru_errno_t
322 fru_open_data_source(const char *name, ...)
324 fru_errno_t err = FRU_SUCCESS;
326 va_list args;
327 int num_args = 0;
328 char **init_args = NULL;
329 char *tmp;
330 int i = 0;
332 char ds_name[PATH_MAX];
333 fru_datasource_t *ds = NULL;
334 void *tmp_lib = NULL;
336 pthread_mutex_lock(&ds_lock);
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);
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);
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);
365 va_start(args, name);
366 tmp = va_arg(args, char *);
367 while (tmp != NULL) {
368 num_args++;
369 tmp = va_arg(args, char *);
371 va_end(args);
373 init_args = (char **)malloc(sizeof (char *) * num_args);
374 if (init_args == NULL) {
375 pthread_mutex_unlock(&ds_lock);
376 return (FRU_FAILURE);
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;
385 va_end(args);
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++;
395 free(init_args);
396 pthread_mutex_unlock(&ds_lock);
397 return (err);
401 /* ========================================================================= */
402 fru_errno_t
403 fru_close_data_source(void)
405 fru_errno_t err = FRU_SUCCESS;
407 if (ds_lib_ref_cnt == 0) {
408 return (FRU_FAILURE);
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;
424 pthread_mutex_unlock(&ds_lock);
425 return (err);
428 /* ========================================================================= */
430 segment_is_encrypted(fru_nodehdl_t container, const char *seg_name)
432 fru_errno_t err = FRU_SUCCESS;
433 fru_segdef_t segdef;
435 if (data_source == NULL) {
436 return (0);
439 RETRY(err = data_source->get_seg_def(NODEHDL_TO_TREEHDL(container),
440 seg_name, &segdef))
442 if (err != FRU_SUCCESS) {
443 return (0);
446 return (segdef.desc.field.encrypted == 1);
449 /* ========================================================================= */
450 static fru_errno_t
451 get_seg_list_from_ds(fru_nodehdl_t node, fru_strlist_t *list)
453 fru_errno_t err = FRU_SUCCESS;
454 fru_strlist_t raw_list;
455 if (data_source == NULL) {
456 return (FRU_FAILURE);
459 /* get a list of all segments */
460 RETRY(err = data_source->get_seg_list(NODEHDL_TO_TREEHDL(node),
461 &raw_list))
463 if (err != FRU_SUCCESS) {
464 return (err);
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);
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++;
487 fru_destroy_strlist(&raw_list);
488 return (FRU_SUCCESS);
492 /* ========================================================================= */
493 const char *
494 fru_strerror(fru_errno_t errnum)
496 if ((errnum < (sizeof (fru_errmsg)/sizeof (*fru_errmsg))) &&
497 (errnum >= 0)) {
498 return (gettext(fru_errmsg[errnum]));
500 return (gettext
501 (fru_errmsg[(sizeof (fru_errmsg)/sizeof (*fru_errmsg))]));
504 /* ========================================================================= */
505 fru_errno_t
506 fru_get_root(fru_nodehdl_t *handle)
508 fru_errno_t err = FRU_SUCCESS;
509 fru_treehdl_t tr_root;
510 if (data_source == NULL) {
511 return (FRU_FAILURE);
514 RETRY(err = data_source->get_root(&tr_root))
515 if (err == FRU_SUCCESS) {
516 *handle = TREEHDL_TO_NODEHDL(tr_root);
518 return (err);
521 /* ========================================================================= */
522 fru_errno_t
523 fru_get_child(fru_nodehdl_t handle, fru_nodehdl_t *child)
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);
532 RETRY(err = data_source->get_child(NODEHDL_TO_TREEHDL(handle),
533 &tr_child))
534 if (err != FRU_SUCCESS) {
535 return (err);
538 RETRY(err = data_source->get_node_type(tr_child, &type))
540 if (err != FRU_SUCCESS) {
541 return (err);
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);
551 * if the child is not valid try and find a peer of the child which is
552 * valid
554 do {
555 RETRY(err = data_source->get_peer(tr_child, &tr_child))
556 if (err != FRU_SUCCESS) {
557 return (err);
560 RETRY(err = data_source->get_node_type(tr_child, &type))
561 if (err != FRU_SUCCESS) {
562 return (err);
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);
570 } while (1);
573 /* ========================================================================= */
574 fru_errno_t
575 fru_get_peer(fru_nodehdl_t handle, fru_nodehdl_t *peer)
577 fru_errno_t err = FRU_SUCCESS;
578 fru_treehdl_t tr_peer = NODEHDL_TO_TREEHDL(handle);
579 fru_node_t type;
581 if (data_source == NULL) {
582 return (FRU_FAILURE);
585 do {
586 RETRY(err = data_source->get_peer(tr_peer, &tr_peer))
588 if (err != FRU_SUCCESS) {
589 return (err);
592 RETRY(err = data_source->get_node_type(tr_peer, &type))
593 if (err != FRU_SUCCESS) {
594 return (err);
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);
602 } while (1);
604 /* ========================================================================= */
605 fru_errno_t
606 fru_get_parent(fru_nodehdl_t handle, fru_nodehdl_t *parent)
608 fru_errno_t err = FRU_SUCCESS;
609 fru_treehdl_t tr_parent;
610 if (data_source == NULL) {
611 return (FRU_FAILURE);
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);
619 return (err);
623 /* ========================================================================= */
624 fru_errno_t
625 fru_get_name_from_hdl(fru_nodehdl_t handle, char **name)
627 fru_errno_t err = FRU_SUCCESS;
629 if (data_source == NULL) {
630 return (FRU_FAILURE);
633 RETRY(err = data_source->get_name_from_hdl(NODEHDL_TO_TREEHDL(handle),
634 name))
635 return (err);
638 /* ========================================================================= */
640 * Project-private interface
642 * Apply process_node() to each node in the tree rooted at "node".
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.
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)
661 void *end_args = NULL;
663 char *name = NULL, *path;
665 int prior_length;
667 fru_errno_t status;
669 fru_nodehdl_t next;
671 end_node_fp_t end_node = NULL;
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);
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;
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);
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;
703 /* "Close" node */
704 if (end_node) end_node(node, path, name, end_args);
705 if (status != FRU_SUCCESS)
706 return (status);
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;
714 return (status);
717 /* ========================================================================= */
719 * Project-private interface
721 * Return true if "searchpath" equals "path" or is a tail of "path" and
722 * begins at a component name within "path"
725 fru_pathmatch(const char *path, const char *searchpath)
727 const char *match;
729 if (((match = strstr(path, searchpath)) != NULL) &&
730 ((match + strlen(searchpath)) == (path + strlen(path))) &&
731 ((match == path) || (*(match - 1) == '/')))
732 return (1);
734 return (0);
737 /* ========================================================================= */
738 fru_errno_t
739 fru_get_node_type(fru_nodehdl_t handle, fru_node_t *type)
741 fru_errno_t err = FRU_SUCCESS;
742 fru_node_t tmp;
743 if (data_source == NULL) {
744 return (FRU_FAILURE);
747 RETRY(err = data_source->get_node_type(NODEHDL_TO_TREEHDL(handle),
748 &tmp))
749 if (err == FRU_SUCCESS) {
750 *type = tmp;
752 return (err);
755 /* ========================================================================= */
756 static fru_errno_t
757 is_container(fru_nodehdl_t handle)
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);
764 if (type == FRU_NODE_CONTAINER) {
765 return (FRU_SUCCESS);
767 return (FRU_NOTCONTAINER);
770 /* ========================================================================= */
771 fru_errno_t
772 fru_destroy_enum(fru_enum_t *e)
774 if (e == NULL) {
775 return (FRU_SUCCESS);
777 if (e->text != NULL)
778 free(e->text);
780 return (FRU_SUCCESS);
783 /* ========================================================================= */
785 * NOTE: does not free list. This is allocated by the user and should be
786 * deallocated by the user.
788 fru_errno_t
789 fru_destroy_strlist(fru_strlist_t *list)
791 if (list == NULL) {
792 return (FRU_SUCCESS);
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]);
799 free(list->strs);
802 list->num = 0;
804 return (FRU_SUCCESS);
807 /* ========================================================================= */
808 fru_errno_t
809 fru_destroy_elemdef(fru_elemdef_t *def)
811 if (def == NULL) {
812 return (FRU_SUCCESS);
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);
819 def->enum_count = 0;
821 if (def->example_string != NULL)
822 free(def->example_string);
824 return (FRU_SUCCESS);
827 /* ========================================================================= */
828 fru_errno_t
829 fru_list_segments(fru_nodehdl_t container, fru_strlist_t *list)
831 fru_errno_t err = FRU_SUCCESS;
833 if ((err = is_container(container)) != FRU_SUCCESS) {
834 return (err);
837 if (lock_container(READ_LOCK, container) != FRU_SUCCESS) {
838 return (FRU_FAILURE);
841 err = get_seg_list_from_ds(container, list);
843 CHK_UNLOCK_CONTAINER(container);
844 return (err);
847 /* ========================================================================= */
848 fru_errno_t
849 fru_create_segment(fru_nodehdl_t container, fru_segdef_t *def)
851 fru_errno_t err = FRU_SUCCESS;
852 int i = 0;
854 if (data_source == NULL) {
855 return (FRU_FAILURE);
858 if ((def->desc.field.encrypted == 1) &&
859 (fru_encryption_supported() == FRU_NOTSUP)) {
860 return (FRU_NOTSUP);
863 if ((err = is_container(container)) != FRU_SUCCESS) {
864 return (err);
867 if (lock_container(WRITE_LOCK, container) != FRU_SUCCESS) {
868 return (FRU_FAILURE);
870 fru_strlist_t seg_list;
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);
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);
889 fru_destroy_strlist(&seg_list);
891 RETRY(err = data_source->add_seg(NODEHDL_TO_TREEHDL(container), def))
893 CHK_UNLOCK_CONTAINER(container);
894 return (err);
897 /* ========================================================================= */
898 fru_errno_t
899 fru_remove_segment(fru_nodehdl_t container, const char *seg_name)
901 fru_errno_t err = FRU_SUCCESS;
902 if ((seg_name == NULL) || (strlen(seg_name) > FRU_SEGNAMELEN)) {
903 return (FRU_INVALSEG);
906 if (data_source == NULL) {
907 return (FRU_FAILURE);
910 if ((err = is_container(container)) != FRU_SUCCESS) {
911 return (err);
914 if (lock_container(WRITE_LOCK, container) != FRU_SUCCESS) {
915 return (FRU_FAILURE);
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))
929 CHK_UNLOCK_CONTAINER(container);
930 return (err);
933 /* ========================================================================= */
934 fru_errno_t
935 fru_get_segment_def(fru_nodehdl_t container, const char *seg_name,
936 fru_segdef_t *definition)
938 fru_errno_t err = FRU_SUCCESS;
939 if ((seg_name == NULL) || (strlen(seg_name) > 2)) {
940 return (FRU_INVALSEG);
943 if (data_source == NULL) {
944 return (FRU_FAILURE);
947 if ((err = is_container(container)) != FRU_SUCCESS) {
948 return (err);
951 if (lock_container(READ_LOCK, container) != FRU_SUCCESS) {
952 return (FRU_FAILURE);
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;
959 RETRY(err = data_source->get_seg_def(NODEHDL_TO_TREEHDL(container),
960 seg_name, &segdef))
962 if (err != FRU_SUCCESS) {
963 CHK_UNLOCK_CONTAINER(container);
964 return (err);
967 if ((segdef.desc.field.encrypted == 1) &&
968 (fru_encryption_supported() == FRU_NOTSUP)) {
969 CHK_UNLOCK_CONTAINER(container);
970 return (FRU_INVALSEG);
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;
981 CHK_UNLOCK_CONTAINER(container);
982 return (FRU_SUCCESS);
985 /* ========================================================================= */
986 fru_errno_t
987 fru_list_elems_in(fru_nodehdl_t container, const char *seg_name,
988 fru_strlist_t *list)
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;
996 if ((seg_name == NULL) || (strlen(seg_name) > 2)) {
997 return (FRU_INVALSEG);
1000 if (data_source == NULL) {
1001 return (FRU_FAILURE);
1004 if ((err = is_container(container)) != FRU_SUCCESS) {
1005 return (err);
1008 if (lock_container(READ_LOCK, container) != FRU_SUCCESS) {
1009 return (FRU_FAILURE);
1012 if ((segment_is_encrypted(container, seg_name)) &&
1013 (fru_encryption_supported() == FRU_NOTSUP)) {
1014 CHK_UNLOCK_CONTAINER(container);
1015 return (FRU_INVALSEG);
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);
1024 if (num_tags == 0) {
1025 CHK_UNLOCK_CONTAINER(container);
1026 list->num = 0;
1027 list->strs = NULL;
1028 return (FRU_SUCCESS);
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);
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);
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);
1061 rc_list.num++;
1064 CHK_UNLOCK_CONTAINER(container);
1065 list->num = rc_list.num;
1066 list->strs = rc_list.strs;
1067 free(tags);
1068 return (FRU_SUCCESS);
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)
1078 fru_errno_t status;
1081 if (data_source == NULL) {
1082 return (FRU_FAILURE);
1085 if (lock_container(READ_LOCK, container) != FRU_SUCCESS) {
1086 return (FRU_FAILURE);
1088 RETRY(status =
1089 data_source->for_each_segment(NODEHDL_TO_TREEHDL(container),
1090 function, args))
1091 CHK_UNLOCK_CONTAINER(container);
1092 return (status);
1095 /* ========================================================================= */
1097 * Project-private interface
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
1103 fru_errno_t
1104 fru_get_segment_name(fru_seghdl_t segment, char **name)
1106 fru_errno_t err = FRU_SUCCESS;
1108 assert(data_source != NULL);
1110 RETRY(err = data_source->get_segment_name(NODEHDL_TO_TREEHDL(segment),
1111 name))
1112 return (err);
1115 /* ========================================================================= */
1117 * Project-private interface
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
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)
1129 fru_errno_t err = FRU_SUCCESS;
1131 assert(data_source != NULL);
1133 RETRY(err = data_source->for_each_packet(NODEHDL_TO_TREEHDL(segment),
1134 function, args))
1135 return (err);
1139 /* ========================================================================= */
1140 // To keep track of the number of instances for each type of tag which
1141 // might occur.
1142 struct TagInstPair
1144 int inst;
1145 fru_tag_t tag;
1148 struct tag_inst_hist_t
1150 TagInstPair *pairs;
1151 unsigned size;
1152 unsigned numStored;
1155 static fru_errno_t
1156 update_tag_inst_hist(tag_inst_hist_t *hist, fru_tag_t tag)
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;
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);
1173 (hist->pairs)[(hist->numStored)].tag.raw_data = tag.raw_data;
1174 (hist->pairs)[(hist->numStored)].inst = 0;
1175 (hist->numStored)++;
1177 return (FRU_SUCCESS);
1180 static fru_errno_t
1181 get_tag_inst_from_hist(tag_inst_hist_t *hist, fru_tag_t tag, int *instance)
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);
1190 return (FRU_FAILURE);
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.
1203 static fru_errno_t
1204 find_unknown_element(fru_tag_t *tags, int num_tags,
1205 int *instance, fru_tag_t *tag)
1207 fru_errno_t err = FRU_SUCCESS;
1209 tag_inst_hist_t hist;
1210 hist.pairs = (TagInstPair *)alloca(sizeof (TagInstPair) * num_tags);
1211 if (hist.pairs == NULL) {
1212 return (FRU_FAILURE);
1214 hist.numStored = 0;
1215 hist.size = num_tags;
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)
1225 int i = 0;
1226 for (i = 0; i < num_tags; i++) {
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);
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++;
1247 *instance -= instFound;
1248 if (!found) {
1249 return (FRU_DATANOTFOUND);
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);
1257 return (FRU_SUCCESS);
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
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)
1279 int j = 0;
1280 Ancestor *cur = ants;
1281 int num_posible = 0;
1282 while (cur != NULL) {
1283 num_posible++;
1284 cur = cur->next;
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);
1293 hist.numStored = 0;
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);
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 */
1320 instancesFound += cur->getNumInstances();
1322 cur = cur->next;
1324 /* when found break out of both "for" and "while" loops */
1325 if (found == 1) {
1326 break; /* for loop */
1330 *instance -= instancesFound;
1331 if (!found) {
1332 return (FRU_DATANOTFOUND);
1335 if (get_tag_inst_from_hist(&hist, tags[i], tagInstance)
1336 != FRU_SUCCESS) {
1337 return (FRU_FAILURE);
1340 return (FRU_SUCCESS);
1344 * Same as find_known_element but ONLY searches for absolute paths
1345 * (ie PathDef->head == tag)
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)
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;
1360 cur = cur->next;
1362 if (cur == NULL) {
1363 // serious parser bug might cause this, double check.
1364 return (FRU_FAILURE);
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;
1379 (*tagInstance)++;
1383 *instance -= (*tagInstance);
1384 if (!found) {
1385 return (FRU_DATANOTFOUND);
1388 return (FRU_SUCCESS);
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
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)
1426 int abs_path_flg = 0;
1427 fru_errno_t err = FRU_SUCCESS;
1428 int num_tags = 0;
1429 fru_tag_t *tags = NULL;
1431 if (data_source == NULL) {
1432 return (FRU_FAILURE);
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);
1440 if (num_tags == 0) {
1441 *instLeft = instance;
1442 return (FRU_DATANOTFOUND);
1445 if (IS_UNKNOWN_PATH(field_path)) {
1446 fru_tag_t tagToRead;
1448 *pathDef = NULL;
1449 *correct = *ancestors = NULL;
1450 *tagInstance = 0;
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);
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);
1467 err = fru_field_parser(field_path, ancestors,
1468 &abs_path_flg, pathDef);
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);
1480 if ((mode == UPDATE_MODE) && (abs_path_flg != 1)) {
1481 free(tags);
1482 delete *ancestors; // linked list
1483 delete *pathDef;
1484 return (FRU_INVALPATH);
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);
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);
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;
1523 return (err);
1526 /* ========================================================================= */
1528 * Handle decryption if necessary
1530 static fru_errno_t
1531 do_decryption(fru_nodehdl_t container, const char *seg_name,
1532 uint8_t *payload, size_t payloadLen)
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);
1541 } else {
1542 return (FRU_FAILURE);
1545 return (FRU_SUCCESS);
1548 /* ========================================================================= */
1549 // Same as get_payload except if seg_name is NULL and it will find the one
1550 // used and return it.
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)
1566 fru_errno_t err = FRU_SUCCESS;
1567 if ((err = is_container(container)) != FRU_SUCCESS) {
1568 return (err);
1571 if (field_path == NULL)
1572 return (FRU_INVALPATH);
1574 if ((*seg_name) != NULL) {
1576 // always check for valid segment names.
1577 if (strlen((const char *)(*seg_name)) > FRU_SEGNAMELEN) {
1578 return (FRU_INVALSEG);
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);
1587 return (do_decryption(container, (const char *)(*seg_name),
1588 *payload, *payloadLen));
1590 } else {
1591 fru_strlist_t seg_list;
1593 if ((err = get_seg_list_from_ds(container, &seg_list))
1594 != FRU_SUCCESS) {
1595 return (err);
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);
1622 fru_destroy_strlist(&seg_list);
1623 return (FRU_DATANOTFOUND);
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)
1635 fru_errno_t err = FRU_SUCCESS;
1636 // just init this value for the user
1637 *data = NULL;
1638 *data_len = 0;
1640 if (lock_container(READ_LOCK, container) != FRU_SUCCESS) {
1641 return (FRU_FAILURE);
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);
1654 CHK_UNLOCK_CONTAINER(container);
1656 if (err != FRU_SUCCESS) {
1657 return (err);
1660 if (pathDef == NULL) { // SPECIAL CASE of UNKNOW payload.
1661 delete ancestors;
1662 delete pathDef;
1663 free(payload);
1665 *data = (void *)malloc(payloadLen);
1666 if ((*data) == NULL) {
1667 return (FRU_FAILURE);
1669 memcpy(*data, payload, payloadLen);
1670 *data_len = payloadLen;
1671 if (found_path != NULL) {
1672 *found_path = strdup(UNKNOWN_PATH);
1674 return (FRU_SUCCESS);
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);
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);
1694 sprintf(*found_path, "%s%s",
1695 correctAnt->getPath(instWIPayload),
1696 field_path);
1700 delete ancestors;
1701 return (err);
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)
1711 fru_errno_t err = FRU_SUCCESS;
1713 if ((field_path == NULL) || IS_UNKNOWN_PATH(field_path)) {
1714 return (FRU_INVALPATH);
1715 } else if (seg_name == NULL) {
1716 return (FRU_INVALSEG);
1719 if (data_source == NULL) {
1720 return (FRU_FAILURE);
1723 if (lock_container(WRITE_LOCK, container) != FRU_SUCCESS) {
1724 return (FRU_FAILURE);
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);
1737 if (err != FRU_SUCCESS) {
1738 CHK_UNLOCK_CONTAINER(container);
1739 return (err);
1742 if ((err = do_decryption(container, (const char *)seg_name,
1743 payload, payloadLen)) != FRU_SUCCESS) {
1744 free(payload);
1745 return (err);
1748 // fill in the new data in the payload
1749 err = PayloadReader::updateData(pathDef, correctAnt, instWIPayload,
1750 payload, payloadLen,
1751 data, length);
1753 if (err != FRU_SUCCESS) {
1754 CHK_UNLOCK_CONTAINER(container);
1755 delete ancestors; // linked list.
1756 delete pathDef;
1757 free(payload);
1758 return (err);
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);
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);
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)
1792 // this ensures a more descriptive error message.
1793 fru_errno_t err = FRU_SUCCESS;
1795 if (lock_container(READ_LOCK, container) != FRU_SUCCESS) {
1796 return (FRU_FAILURE);
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);
1809 CHK_UNLOCK_CONTAINER(container);
1811 if (err != FRU_SUCCESS) {
1812 return (err);
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);
1826 delete pathDef;
1827 free(payload);
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);
1838 sprintf(*found_path, "%s%s",
1839 correctAnt->getPath(instWIPayload),
1840 iter_path);
1844 delete ancestors;
1845 return (err);
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)
1856 fru_errno_t rc = FRU_SUCCESS;
1858 if ((def->iterationType == FRU_NOT_ITERATED) ||
1859 (inIteration)) {
1861 if (def->dataType == FDTYPE_Record) {
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;
1874 } // else field, no sub elements; do nothing... ;-)
1876 } else {
1877 data[3] = (char)def->iterationCount;
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));
1889 return (rc);
1892 /* ========================================================================= */
1893 fru_errno_t
1894 fru_add_element(fru_nodehdl_t container,
1895 const char *seg_name,
1896 const char *element)
1898 fru_errno_t err = FRU_SUCCESS;
1900 if ((seg_name == NULL) || (strlen(seg_name) > FRU_SEGNAMELEN)) {
1901 return (FRU_INVALSEG);
1904 const fru_regdef_t *def
1905 = fru_reg_lookup_def_by_name((char *)element);
1906 if (def == NULL) {
1907 return (FRU_NOREGDEF);
1909 if (def->tagType == FRU_X) {
1910 return (FRU_ELEMNOTTAGGED);
1913 if (data_source == NULL) {
1914 return (FRU_FAILURE);
1917 if ((err = is_container(container)) != FRU_SUCCESS) {
1918 return (err);
1921 if (lock_container(WRITE_LOCK, container) != FRU_SUCCESS) {
1922 return (FRU_FAILURE);
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);
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);
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);
1943 if ((err = encrypt_func(FRU_ENCRYPT, data,
1944 def->payloadLen)) != FRU_SUCCESS) {
1945 CHK_UNLOCK_CONTAINER(container);
1946 delete[] data;
1947 return (err);
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);
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)
1965 fru_errno_t err = FRU_SUCCESS;
1967 if ((seg_name == NULL) || (strlen(seg_name) > FRU_SEGNAMELEN)) {
1968 return (FRU_INVALSEG);
1971 if (data_source == NULL) {
1972 return (FRU_FAILURE);
1975 if ((err = is_container(container)) != FRU_SUCCESS) {
1976 return (err);
1979 if (lock_container(WRITE_LOCK, container) != FRU_SUCCESS) {
1980 return (FRU_FAILURE);
1982 if ((segment_is_encrypted(container, seg_name)) &&
1983 (fru_encryption_supported() == FRU_NOTSUP)) {
1984 CHK_UNLOCK_CONTAINER(container);
1985 return (FRU_INVALSEG);
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;
1998 RETRY(err =
1999 data_source->get_tag_list(NODEHDL_TO_TREEHDL(container),
2000 seg_name, &tags, &num_tags))
2002 if (err != FRU_SUCCESS) {
2003 CHK_UNLOCK_CONTAINER(container);
2004 return (err);
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);
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);
2020 if (def->tagType == FRU_X) {
2021 CHK_UNLOCK_CONTAINER(container);
2022 return (FRU_ELEMNOTTAGGED);
2024 mk_tag(def->tagType, def->tagDense, def->payloadLen, &tag);
2027 RETRY(err = data_source->delete_tag(NODEHDL_TO_TREEHDL(container),
2028 seg_name, tag, instance))
2029 CHK_UNLOCK_CONTAINER(container);
2030 return (err);
2033 /* General library support */
2034 /* ========================================================================= */
2035 static fru_errno_t
2036 make_definition(const fru_regdef_t *def, fru_elemdef_t *definition)
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;
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;
2055 // END zzz
2057 definition->disp_type = def->dispType;
2058 definition->purgeable = def->purgeable;
2059 definition->relocatable = def->relocatable;
2061 definition->enum_count = 0;
2062 definition->enum_table = NULL;
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);
2071 memset(definition->enum_table, 0x00,
2072 ((sizeof (fru_enum_t)) * count));
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);
2082 (definition->enum_count)++;
2085 definition->iteration_count = def->iterationCount;
2086 definition->iteration_type = def->iterationType;
2088 definition->example_string = strdup(def->exampleString);
2089 if ((definition->example_string) == NULL) {
2090 fru_destroy_elemdef(definition);
2091 return (FRU_FAILURE);
2094 return (FRU_SUCCESS);
2097 /* ========================================================================= */
2098 fru_errno_t
2099 fru_get_definition(const char *element_name,
2100 fru_elemdef_t *definition)
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;
2108 err = fru_field_parser(element_name, &ancestors,
2109 &abs_path_flg, &pathDef);
2110 if (err != FRU_SUCCESS) {
2111 return (err);
2114 PathDef *last = pathDef;
2115 while (last->next != NULL)
2116 last = last->next;
2118 err = make_definition(last->def, definition);
2120 delete ancestors;
2121 delete pathDef;
2122 return (err);
2125 /* ========================================================================= */
2126 fru_errno_t
2127 fru_get_registry(fru_strlist_t *list)
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);
2135 list->strs = entries;
2136 list->num = number;
2137 return (FRU_SUCCESS);
2140 /* ========================================================================= */
2141 fru_errno_t
2142 fru_get_tagged_parents(const char *element, fru_strlist_t *parents)
2144 Ancestor *ancestors
2145 = Ancestor::listTaggedAncestors((char *)element);
2147 Ancestor *cur = ancestors;
2148 /* count them */
2149 int number = 0;
2150 while (cur != NULL) {
2151 number++;
2152 cur = cur->next;
2155 parents->num = 0;
2156 parents->strs = NULL;
2157 if (number == 0) {
2158 return (FRU_SUCCESS);
2160 parents->strs = (char **)malloc(number * sizeof (char *));
2161 if (parents->strs == NULL) {
2162 return (FRU_FAILURE);
2164 memset(parents->strs, 0x00, (number * sizeof (char *)));
2166 cur = ancestors;
2167 for (int i = 0; i < number; i++) {
2168 if (cur == NULL) {
2169 fru_destroy_strlist(parents);
2170 return (FRU_FAILURE);
2172 parents->strs[i] = strdup(cur->getDef()->name);
2173 if (parents->strs[i] == NULL) {
2174 fru_destroy_strlist(parents);
2175 return (FRU_FAILURE);
2177 parents->num++;
2178 cur = cur->next;
2181 return (FRU_SUCCESS);
2185 * Enum string converters.
2187 /* ========================================================================= */
2188 const char *
2189 get_displaytype_str(fru_displaytype_t e)
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"));
2207 return (gettext("UNDEFINED"));
2210 /* ========================================================================= */
2211 const char *
2212 get_datatype_str(fru_datatype_t e)
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"));
2230 return (gettext("UNDEFINED"));
2232 /* ========================================================================= */
2233 const char *
2234 get_which_str(fru_which_t e)
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"));
2244 return (gettext("WHICH UNDEFINED"));
2246 /* ========================================================================= */
2247 const char *
2248 get_itertype_str(fru_itertype_t e)
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"));
2262 return (gettext("NOT ITERATED"));