xref: /illumos-gate/usr/src/lib/libfru/libfru/libfru.cc (revision 24da5b34)
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
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
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
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 *
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 *
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
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
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
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
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
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
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
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 *
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 *
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 *
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 *
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