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