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