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