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]
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
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
45 * 5) Get this tag from the data source and read it with the PayloadReader to
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.
68 #include "libfrureg.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.
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
[] =
126 "No registry definition for this element",
132 "Invalid Data size (does not match registry definition)",
135 "No space available",
136 "Data could not be found",
138 "Invalid Permisions",
139 "Feature not Supported",
140 "Element is not Tagged",
141 "Failed to read container device",
144 "General LIBFRU FAILURE",
151 fru_encryption_supported(void)
153 if (encrypt_func
== NULL
)
156 return (FRU_SUCCESS
);
163 // attempt to find the encryption library.
164 void *crypt_lib
= 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 /* ========================================================================= */
177 add_cont_lock(cont_lock_t
*lock
)
179 cont_lock_t
*prev
= NULL
;
180 int hash_bucket
= lock
->handle
% CONT_LOCK_HASH_NUM
;
183 if (cont_lock_hash
[hash_bucket
] == NULL
) {
184 cont_lock_hash
[hash_bucket
] = lock
;
186 cont_lock_t
*prev
= cont_lock_hash
[hash_bucket
];
187 while (prev
->next
!= NULL
) {
194 /* ========================================================================= */
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
) {
210 /* ========================================================================= */
212 alloc_cont_lock(fru_nodehdl_t handle
)
214 cont_lock_t
*lock
= (cont_lock_t
*)malloc(sizeof (cont_lock_t
));
218 lock
->handle
= handle
;
219 if (pthread_rwlock_init(&(lock
->lock
), NULL
) != 0) {
227 /* ========================================================================= */
229 lock_container(lock_mode_t mode
, fru_nodehdl_t handle
)
231 cont_lock_t
*which
= NULL
;
235 pthread_mutex_lock(&cont_lock_hash_lock
);
237 which
= find_cont_lock(handle
);
239 /* if not found add to hash */
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
);
252 lock_rc
= pthread_rwlock_rdlock(&(which
->lock
));
255 lock_rc
= pthread_rwlock_wrlock(&(which
->lock
));
259 pthread_mutex_unlock(&cont_lock_hash_lock
);
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); \
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
);
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 /* ========================================================================= */
297 clear_cont_locks(void)
299 pthread_mutex_lock(&cont_lock_hash_lock
);
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
;
308 pthread_rwlock_destroy(&(tmp
->lock
));
311 cont_lock_hash
[i
] = NULL
;
314 pthread_mutex_unlock(&cont_lock_hash_lock
);
315 return (FRU_SUCCESS
);
319 /* ========================================================================= */
322 fru_open_data_source(const char *name
, ...)
324 fru_errno_t err
= FRU_SUCCESS
;
328 char **init_args
= NULL
;
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.
343 pthread_mutex_unlock(&ds_lock
);
344 return (FRU_SUCCESS
);
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
);
358 ds
= (fru_datasource_t
*)dlsym(tmp_lib
,
359 DATA_SOURCE_OBJ_NAME
);
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
) {
369 tmp
= va_arg(args
, char *);
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
++) {
387 if ((err
= ds
->initialize(num_args
, init_args
)) == FRU_SUCCESS
) {
388 // don't switch unless the source connects ok.
391 ds_lib_name
= strdup(name
);
396 pthread_mutex_unlock(&ds_lock
);
401 /* ========================================================================= */
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 */
424 pthread_mutex_unlock(&ds_lock
);
428 /* ========================================================================= */
430 segment_is_encrypted(fru_nodehdl_t container
, const char *seg_name
)
432 fru_errno_t err
= FRU_SUCCESS
;
435 if (data_source
== NULL
) {
439 RETRY(err
= data_source
->get_seg_def(NODEHDL_TO_TREEHDL(container
),
442 if (err
!= FRU_SUCCESS
) {
446 return (segdef
.desc
.field
.encrypted
== 1);
449 /* ========================================================================= */
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
),
463 if (err
!= FRU_SUCCESS
) {
467 /* leave out the encrypted segments if necessary */
469 list
->strs
= (char **)malloc(sizeof (*(list
->strs
)) * raw_list
.num
);
470 if (list
->strs
== NULL
) {
471 fru_destroy_strlist(&raw_list
);
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
]);
480 } // else leave it out.
482 list
->strs
[list
->num
] = strdup(raw_list
.strs
[i
]);
487 fru_destroy_strlist(&raw_list
);
488 return (FRU_SUCCESS
);
492 /* ========================================================================= */
494 fru_strerror(fru_errno_t errnum
)
496 if ((errnum
< (sizeof (fru_errmsg
)/sizeof (*fru_errmsg
))) &&
498 return (gettext(fru_errmsg
[errnum
]));
501 (fru_errmsg
[(sizeof (fru_errmsg
)/sizeof (*fru_errmsg
))]));
504 /* ========================================================================= */
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
);
521 /* ========================================================================= */
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
;
528 if (data_source
== NULL
) {
529 return (FRU_FAILURE
);
532 RETRY(err
= data_source
->get_child(NODEHDL_TO_TREEHDL(handle
),
534 if (err
!= FRU_SUCCESS
) {
538 RETRY(err
= data_source
->get_node_type(tr_child
, &type
))
540 if (err
!= FRU_SUCCESS
) {
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
555 RETRY(err
= data_source
->get_peer(tr_child
, &tr_child
))
556 if (err
!= FRU_SUCCESS
) {
560 RETRY(err
= data_source
->get_node_type(tr_child
, &type
))
561 if (err
!= FRU_SUCCESS
) {
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
);
573 /* ========================================================================= */
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
);
581 if (data_source
== NULL
) {
582 return (FRU_FAILURE
);
586 RETRY(err
= data_source
->get_peer(tr_peer
, &tr_peer
))
588 if (err
!= FRU_SUCCESS
) {
592 RETRY(err
= data_source
->get_node_type(tr_peer
, &type
))
593 if (err
!= FRU_SUCCESS
) {
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
);
604 /* ========================================================================= */
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
),
616 if (err
== FRU_SUCCESS
) {
617 *parent
= TREEHDL_TO_NODEHDL(tr_parent
);
623 /* ========================================================================= */
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
),
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
,
656 const char *name
, void *args
,
657 end_node_fp_t
*end_node
,
661 void *end_args
= NULL
;
663 char *name
= NULL
, *path
;
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
)
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
);
684 name
= path
+ prior_length
+ 1;
688 assert(process_node
!= NULL
);
689 if ((status
= process_node(node
, path
, name
, args
,
690 &end_node
, &end_args
))
692 if (end_node
) end_node(node
, path
, name
, end_args
);
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
;
704 if (end_node
) end_node(node
, path
, name
, end_args
);
705 if (status
!= FRU_SUCCESS
)
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
;
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
)
729 if (((match
= strstr(path
, searchpath
)) != NULL
) &&
730 ((match
+ strlen(searchpath
)) == (path
+ strlen(path
))) &&
731 ((match
== path
) || (*(match
- 1) == '/')))
737 /* ========================================================================= */
739 fru_get_node_type(fru_nodehdl_t handle
, fru_node_t
*type
)
741 fru_errno_t err
= FRU_SUCCESS
;
743 if (data_source
== NULL
) {
744 return (FRU_FAILURE
);
747 RETRY(err
= data_source
->get_node_type(NODEHDL_TO_TREEHDL(handle
),
749 if (err
== FRU_SUCCESS
) {
755 /* ========================================================================= */
757 is_container(fru_nodehdl_t handle
)
759 fru_errno_t err
= FRU_SUCCESS
;
761 if ((err
= fru_get_node_type(handle
, &type
)) != FRU_SUCCESS
) {
764 if (type
== FRU_NODE_CONTAINER
) {
765 return (FRU_SUCCESS
);
767 return (FRU_NOTCONTAINER
);
770 /* ========================================================================= */
772 fru_destroy_enum(fru_enum_t
*e
)
775 return (FRU_SUCCESS
);
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.
789 fru_destroy_strlist(fru_strlist_t
*list
)
792 return (FRU_SUCCESS
);
794 if (list
->strs
!= NULL
) {
795 for (int i
= 0; i
< list
->num
; i
++) {
796 if (list
->strs
[i
] != NULL
)
804 return (FRU_SUCCESS
);
807 /* ========================================================================= */
809 fru_destroy_elemdef(fru_elemdef_t
*def
)
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
);
821 if (def
->example_string
!= NULL
)
822 free(def
->example_string
);
824 return (FRU_SUCCESS
);
827 /* ========================================================================= */
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
) {
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
);
847 /* ========================================================================= */
849 fru_create_segment(fru_nodehdl_t container
, fru_segdef_t
*def
)
851 fru_errno_t err
= FRU_SUCCESS
;
854 if (data_source
== NULL
) {
855 return (FRU_FAILURE
);
858 if ((def
->desc
.field
.encrypted
== 1) &&
859 (fru_encryption_supported() == FRU_NOTSUP
)) {
863 if ((err
= is_container(container
)) != FRU_SUCCESS
) {
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
),
876 if (err
!= FRU_SUCCESS
) {
877 CHK_UNLOCK_CONTAINER(container
);
881 for (i
= 0; i
< seg_list
.num
; i
++) {
882 if (strncmp(seg_list
.strs
[i
], def
->name
, FRU_SEGNAMELEN
)
884 fru_destroy_strlist(&seg_list
);
885 CHK_UNLOCK_CONTAINER(container
);
889 fru_destroy_strlist(&seg_list
);
891 RETRY(err
= data_source
->add_seg(NODEHDL_TO_TREEHDL(container
), def
))
893 CHK_UNLOCK_CONTAINER(container
);
897 /* ========================================================================= */
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
) {
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
)) {
925 data_source
->delete_seg(NODEHDL_TO_TREEHDL(container
),
929 CHK_UNLOCK_CONTAINER(container
);
933 /* ========================================================================= */
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
) {
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.
959 RETRY(err
= data_source
->get_seg_def(NODEHDL_TO_TREEHDL(container
),
962 if (err
!= FRU_SUCCESS
) {
963 CHK_UNLOCK_CONTAINER(container
);
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 /* ========================================================================= */
987 fru_list_elems_in(fru_nodehdl_t container
, const char *seg_name
,
990 fru_errno_t err
= FRU_SUCCESS
;
991 fru_tag_t
*tags
= NULL
;
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
) {
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
);
1024 if (num_tags
== 0) {
1025 CHK_UNLOCK_CONTAINER(container
);
1028 return (FRU_SUCCESS
);
1031 // allocate the memory for the names.
1033 rc_list
.strs
= (char **)malloc(num_tags
* sizeof (char *));
1034 if (rc_list
.strs
== NULL
) {
1035 CHK_UNLOCK_CONTAINER(container
);
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
]);
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
);
1049 return (FRU_FAILURE
);
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
);
1058 return (FRU_FAILURE
);
1064 CHK_UNLOCK_CONTAINER(container
);
1065 list
->num
= rc_list
.num
;
1066 list
->strs
= rc_list
.strs
;
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
),
1081 if (data_source
== NULL
) {
1082 return (FRU_FAILURE
);
1085 if (lock_container(READ_LOCK
, container
) != FRU_SUCCESS
) {
1086 return (FRU_FAILURE
);
1089 data_source
->for_each_segment(NODEHDL_TO_TREEHDL(container
),
1091 CHK_UNLOCK_CONTAINER(container
);
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
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
),
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
),
1129 fru_errno_t err
= FRU_SUCCESS
;
1131 assert(data_source
!= NULL
);
1133 RETRY(err
= data_source
->for_each_packet(NODEHDL_TO_TREEHDL(segment
),
1139 /* ========================================================================= */
1140 // To keep track of the number of instances for each type of tag which
1148 struct tag_inst_hist_t
1156 update_tag_inst_hist(tag_inst_hist_t
*hist
, fru_tag_t tag
)
1158 // find if this tag has occured before.
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
++;
1168 // if not add to the end of the array of instance 0.
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
);
1181 get_tag_inst_from_hist(tag_inst_hist_t
*hist
, fru_tag_t tag
, int *instance
)
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 /* ========================================================================= */
1195 // a list of tags and number of them
1196 // and an instance of the unknown payload you are looking for.
1199 // instance == the instance of the tag "tag" to read from the list
1201 // instance == the number of instances remaining.
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
);
1215 hist
.size
= num_tags
;
1217 // search all the tags untill they are exhausted or we find
1218 // the instance we want.
1221 // NOTE: instancesFound is a running total of the instances in the tags
1223 // (ie instances left over == instance - instancesFound)
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.
1231 if (update_tag_inst_hist(&hist
, tags
[i
])
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
1238 if ((instFound
+ 1) > (*instance
)) {
1247 *instance
-= instFound
;
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
);
1261 // a list of tags and number of them
1262 // a list of Ancestors
1263 // the instance we are looking for
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
1270 // instance == the number of instances remaining.
1272 // tagInstance == UNDEFINED
1275 find_known_element(fru_tag_t
*tags
, int num_tags
, Ancestor
*ants
,
1276 int *instance
, Ancestor
**correct
,
1280 Ancestor
*cur
= ants
;
1281 int num_posible
= 0;
1282 while (cur
!= NULL
) {
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
);
1298 int instancesFound
= 0;
1299 // NOTE: instancesFound is a running total of the instances in the tags
1301 // (ie instances left over == instance - instancesFound)
1302 for (i
= 0; i
< num_tags
; i
++) {
1304 while (cur
!= NULL
) {
1305 if (tags_equal(cur
->getTag(), tags
[i
])) {
1306 if (update_tag_inst_hist(&hist
, tags
[i
])
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
1314 if ((instancesFound
+ cur
->getNumInstances())
1318 break; /* while loop */
1320 instancesFound
+= cur
->getNumInstances();
1324 /* when found break out of both "for" and "while" loops */
1326 break; /* for loop */
1330 *instance
-= instancesFound
;
1332 return (FRU_DATANOTFOUND
);
1335 if (get_tag_inst_from_hist(&hist
, tags
[i
], tagInstance
)
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)
1348 find_known_element_abs(fru_tag_t
*tags
, int num_tags
, int *instance
,
1349 PathDef
*head
, Ancestor
*ants
, Ancestor
**correct
,
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) {
1363 // serious parser bug might cause this, double check.
1364 return (FRU_FAILURE
);
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
1374 if (((*tagInstance
) +1) > (*instance
)) {
1383 *instance
-= (*tagInstance
);
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
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
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
1411 #define UPDATE_MODE 1
1412 static fru_errno_t
get_payload(fru_nodehdl_t container
,
1413 const char *seg_name
,
1415 const char *field_path
,
1416 // returns the following...
1418 Ancestor
**ancestors
,
1420 int *tagInstance
, // instance of the tag within the seg
1421 int *instLeft
, // within this payload
1426 int abs_path_flg
= 0;
1427 fru_errno_t err
= FRU_SUCCESS
;
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
) {
1440 if (num_tags
== 0) {
1441 *instLeft
= instance
;
1442 return (FRU_DATANOTFOUND
);
1445 if (IS_UNKNOWN_PATH(field_path
)) {
1446 fru_tag_t tagToRead
;
1449 *correct
= *ancestors
= NULL
;
1452 int unknown_inst
= instance
;
1453 if ((err
= find_unknown_element(tags
, num_tags
, &unknown_inst
,
1454 &tagToRead
)) != FRU_SUCCESS
) {
1455 *instLeft
= unknown_inst
;
1460 data_source
->get_tag_data(NODEHDL_TO_TREEHDL(container
),
1461 seg_name
, tagToRead
, unknown_inst
, payload
,
1467 err
= fru_field_parser(field_path
, ancestors
,
1468 &abs_path_flg
, pathDef
);
1470 if (err
!= FRU_SUCCESS
) {
1473 } else if (ancestors
== NULL
) {
1474 /* without valid ancestors we can't find payloads for this */
1477 return (FRU_INVALELEMENT
);
1480 if ((mode
== UPDATE_MODE
) && (abs_path_flg
!= 1)) {
1482 delete *ancestors
; // linked list
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
))
1491 // set up to search next segment for instances left
1493 *instLeft
= instance
;
1495 delete *ancestors
; // linked list
1500 if ((err
= find_known_element(tags
, num_tags
, *ancestors
,
1501 &instance
, correct
, tagInstance
))
1503 // set up to search next segment for instances left
1505 *instLeft
= instance
;
1507 delete *ancestors
; // linked list
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
,
1519 if (err
!= FRU_SUCCESS
) {
1520 delete *ancestors
; // linked list
1526 /* ========================================================================= */
1528 * Handle decryption if necessary
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
) {
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.
1553 get_seg_and_payload(fru_nodehdl_t container
,
1556 const char *field_path
,
1557 // returns the following...
1559 Ancestor
**ancestors
,
1561 int *tagInstance
, // within the segment.
1562 int *instLeft
, // within this payload
1566 fru_errno_t err
= FRU_SUCCESS
;
1567 if ((err
= is_container(container
)) != FRU_SUCCESS
) {
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
))
1587 return (do_decryption(container
, (const char *)(*seg_name
),
1588 *payload
, *payloadLen
));
1591 fru_strlist_t seg_list
;
1593 if ((err
= get_seg_list_from_ds(container
, &seg_list
))
1599 for (int i
= 0; i
< seg_list
.num
; i
++) {
1600 err
= get_payload(container
,
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
;
1618 fru_destroy_strlist(&seg_list
);
1622 fru_destroy_strlist(&seg_list
);
1623 return (FRU_DATANOTFOUND
);
1627 /* ========================================================================= */
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
,
1635 fru_errno_t err
= FRU_SUCCESS
;
1636 // just init this value for the user
1640 if (lock_container(READ_LOCK
, container
) != FRU_SUCCESS
) {
1641 return (FRU_FAILURE
);
1644 Ancestor
*ancestors
;
1645 Ancestor
*correctAnt
;
1646 int tagInstance
= 0;
1647 int instWIPayload
= 0;
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
) {
1660 if (pathDef
== NULL
) { // SPECIAL CASE of UNKNOW 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
,
1680 payload
, payloadLen
,
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
) {
1692 return (FRU_FAILURE
);
1694 sprintf(*found_path
, "%s%s",
1695 correctAnt
->getPath(instWIPayload
),
1704 /* ========================================================================= */
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
);
1727 Ancestor
*ancestors
;
1728 Ancestor
*correctAnt
;
1729 int tagInstance
= 0;
1730 int instWIPayload
= 0;
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
);
1742 if ((err
= do_decryption(container
, (const char *)seg_name
,
1743 payload
, payloadLen
)) != FRU_SUCCESS
) {
1748 // fill in the new data in the payload
1749 err
= PayloadReader::updateData(pathDef
, correctAnt
, instWIPayload
,
1750 payload
, payloadLen
,
1753 if (err
!= FRU_SUCCESS
) {
1754 CHK_UNLOCK_CONTAINER(container
);
1755 delete ancestors
; // linked list.
1761 if ((segment_is_encrypted(container
, seg_name
)) &&
1762 (fru_encryption_supported() == FRU_SUCCESS
)) {
1763 if ((err
= encrypt_func(FRU_ENCRYPT
, payload
, payloadLen
))
1765 CHK_UNLOCK_CONTAINER(container
);
1766 delete ancestors
; // linked list.
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.
1783 /* ========================================================================= */
1785 fru_get_num_iterations(fru_nodehdl_t container
,
1787 unsigned int instance
,
1788 const char *iter_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
);
1799 Ancestor
*ancestors
;
1800 Ancestor
*correctAnt
;
1801 int tagInstance
= 0;
1802 int instWIPayload
= 0;
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
) {
1815 if (pathDef
== NULL
) { // SPECIAL CASE of UNKNOW payload.
1816 // clean up memory from called functions.
1817 err
= FRU_INVALPATH
;
1819 // get the specific data
1820 err
= PayloadReader::findIterThere(pathDef
, correctAnt
,
1822 payload
, payloadLen
,
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
) {
1836 return (FRU_FAILURE
);
1838 sprintf(*found_path
, "%s%s",
1839 correctAnt
->getPath(instWIPayload
),
1848 /* ========================================================================= */
1849 // When adding a new payload with 0 data the iteration control bytes must be
1850 // filled in with the number possible.
1852 fill_in_iteration_control_bytes(uint8_t *data
,
1853 const fru_regdef_t
*def
,
1856 fru_errno_t rc
= FRU_SUCCESS
;
1858 if ((def
->iterationType
== FRU_NOT_ITERATED
) ||
1861 if (def
->dataType
== FDTYPE_Record
) {
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
);
1868 = fill_in_iteration_control_bytes(&(data
[offset
]), newDef
, 0);
1869 if (rc2
!= FRU_SUCCESS
)
1871 offset
+= newDef
->payloadLen
;
1874 } // else field, no sub elements; do nothing... ;-)
1877 data
[3] = (char)def
->iterationCount
;
1880 for (int i
= 0; i
< def
->iterationCount
; i
++) {
1882 = fill_in_iteration_control_bytes(&(data
[offset
]), def
, 1);
1883 if (rc3
!= FRU_SUCCESS
)
1885 offset
+= ((def
->payloadLen
- 4)/(def
->iterationCount
));
1892 /* ========================================================================= */
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
);
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
) {
1921 if (lock_container(WRITE_LOCK
, container
) != FRU_SUCCESS
) {
1922 return (FRU_FAILURE
);
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
);
1937 if (segment_is_encrypted(container
, seg_name
)) {
1938 if (fru_encryption_supported() == FRU_NOTSUP
) {
1939 CHK_UNLOCK_CONTAINER(container
);
1941 return (FRU_INVALSEG
);
1943 if ((err
= encrypt_func(FRU_ENCRYPT
, data
,
1944 def
->payloadLen
)) != FRU_SUCCESS
) {
1945 CHK_UNLOCK_CONTAINER(container
);
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
);
1958 /* ========================================================================= */
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
) {
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
);
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
;
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
);
2006 if ((err
= find_unknown_element(tags
, num_tags
,
2007 &localInst
, &tag
)) != FRU_SUCCESS
) {
2009 CHK_UNLOCK_CONTAINER(container
);
2014 const fru_regdef_t
*def
2015 = fru_reg_lookup_def_by_name((char *)element
);
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
);
2033 /* General library support */
2034 /* ========================================================================= */
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
;
2043 definition
->tagged
= FRU_No
;
2046 // This should be the following statement.
2047 // (*definition)->data_length = def->dataLength;
2049 if (def
->iterationType
!= FRU_NOT_ITERATED
) {
2050 int elemLen
= ((def
->dataLength
-4)/def
->iterationCount
);
2051 definition
->data_length
= elemLen
;
2053 definition
->data_length
= def
->dataLength
;
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
;
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 /* ========================================================================= */
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
) {
2114 PathDef
*last
= pathDef
;
2115 while (last
->next
!= NULL
)
2118 err
= make_definition(last
->def
, definition
);
2125 /* ========================================================================= */
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
;
2137 return (FRU_SUCCESS
);
2140 /* ========================================================================= */
2142 fru_get_tagged_parents(const char *element
, fru_strlist_t
*parents
)
2145 = Ancestor::listTaggedAncestors((char *)element
);
2147 Ancestor
*cur
= ancestors
;
2150 while (cur
!= NULL
) {
2156 parents
->strs
= NULL
;
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 *)));
2167 for (int i
= 0; i
< number
; i
++) {
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
);
2181 return (FRU_SUCCESS
);
2185 * Enum string converters.
2187 /* ========================================================================= */
2189 get_displaytype_str(fru_displaytype_t e
)
2193 return (gettext("Binary"));
2195 return (gettext("Hex"));
2197 return (gettext("Decimal"));
2199 return (gettext("Octal"));
2201 return (gettext("String"));
2203 return (gettext("Time"));
2204 case FDISP_UNDEFINED
:
2205 return (gettext("UNDEFINED"));
2207 return (gettext("UNDEFINED"));
2210 /* ========================================================================= */
2212 get_datatype_str(fru_datatype_t e
)
2216 return (gettext("Binary"));
2217 case FDTYPE_ByteArray
:
2218 return (gettext("Byte Array"));
2220 return (gettext("ASCII"));
2221 case FDTYPE_Unicode
:
2222 return (gettext("Unicode"));
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 /* ========================================================================= */
2234 get_which_str(fru_which_t e
)
2238 return (gettext("No"));
2240 return (gettext("Yes"));
2241 case FRU_WHICH_UNDEFINED
:
2242 return (gettext("WHICH UNDEFINED"));
2244 return (gettext("WHICH UNDEFINED"));
2246 /* ========================================================================= */
2248 get_itertype_str(fru_itertype_t e
)
2252 return (gettext("FIFO"));
2254 return (gettext("Circular"));
2256 return (gettext("Linear"));
2258 return (gettext("LIFO"));
2259 case FRU_NOT_ITERATED
:
2260 return (gettext("NOT ITERATED"));
2262 return (gettext("NOT ITERATED"));