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