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