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 (c) 2000-2001 by Sun Microsystems, Inc.
24  * All rights reserved.
25  */
26 
27 #include <stdlib.h>
28 #include <string.h>
29 
30 #include "Ancestor.h"
31 
32 /* ========================================================================= */
33 /* Ancestor object definitions. */
34 
Ancestor(Str field,fru_tag_t t,const fru_regdef_t * d)35 Ancestor::Ancestor(Str field, fru_tag_t t, const fru_regdef_t *d)
36 	: field_name(field),
37     tag(t),
38     def(d),
39     numInstances(0),
40     numBufs(1),
41     next(NULL)
42 {
43 	offsets = (uint32_t *)malloc(sizeof (uint32_t)
44 					* ANCESTOR_INST_BUF_SIZE);
45 	paths = (char **)malloc(sizeof (char *)
46 					* ANCESTOR_INST_BUF_SIZE);
47 }
48 
~Ancestor()49 Ancestor::~Ancestor()
50 {
51 	free(offsets);
52 	if (paths != NULL) {
53 		for (int i = 0; i < numInstances; i++) {
54 			free(paths[i]);
55 		}
56 	}
57 	free(paths);
58 	delete next;
59 }
60 
61 /*
62 void
63 Ancestor::print(void)
64 {
65 	fprintf(stderr, "Ancestor Information\n");
66 	fprintf(stderr, "Tag Name: %s\n", def->name);
67 	fprintf(stderr, "Tag Type: %s\n",
68 			get_tagtype_str(get_tag_type(&tag)));
69 	fprintf(stderr, "Num instances: %d\n", numInstances);
70 	fprintf(stderr, "   offsets:\n");
71 	for (int i = 0; i < numInstances; i++) {
72 		fprintf(stderr, "   %d\n", offsets[i]);
73 	}
74 
75 	if (next != NULL) {
76 		next->print();
77 	}
78 }
79 */
80 
81 void
addInstance(const char * path,uint32_t offset)82 Ancestor::addInstance(const char *path, uint32_t offset)
83 {
84 	if (numInstances >= ANCESTOR_INST_BUF_SIZE) {
85 		numBufs++;
86 		offsets = (uint32_t *)realloc(offsets,
87 			(sizeof (uint32_t) *
88 				(ANCESTOR_INST_BUF_SIZE * numBufs)));
89 		paths = (char **)realloc(offsets,
90 			(sizeof (char *) *
91 				(ANCESTOR_INST_BUF_SIZE * numBufs)));
92 	}
93 	offsets[numInstances] = offset;
94 	paths[numInstances++] = strdup(path);
95 }
96 
97 Str
getFieldName(void)98 Ancestor::getFieldName(void)
99 {
100 	return (field_name);
101 }
102 
103 fru_tag_t
getTag(void)104 Ancestor::getTag(void)
105 {
106 	return (tag);
107 }
108 
109 const fru_regdef_t *
getDef(void)110 Ancestor::getDef(void)
111 {
112 	return (def);
113 }
114 
115 int
getNumInstances(void)116 Ancestor::getNumInstances(void)
117 {
118 	return (numInstances);
119 }
120 
121 uint32_t
getInstOffset(int num)122 Ancestor::getInstOffset(int num)
123 {
124 	if (num < numInstances)
125 		return (offsets[num]);
126 	else
127 		return (offsets[numInstances]);
128 }
129 
130 const char *
getPath(int num)131 Ancestor::getPath(int num)
132 {
133 	if (num < numInstances)
134 		return (paths[num]);
135 	else
136 		return (paths[numInstances]);
137 }
138 
139 
140 Ancestor *
listTaggedAncestors(char * element)141 Ancestor::listTaggedAncestors(char *element)
142 {
143 	Ancestor *rc = NULL;
144 	fru_regdef_t *def = NULL;
145 	int i = 0;
146 
147 	unsigned int number = 0;
148 	char **data_elems = fru_reg_list_entries(&number);
149 
150 	if (data_elems == NULL) {
151 		return (NULL);
152 	}
153 
154 	// look through all the elements.
155 	for (i = 0; i < number; i++) {
156 		def = (fru_regdef_t *)
157 			fru_reg_lookup_def_by_name(data_elems[i]);
158 		Ancestor *ant = createTaggedAncestor(def, element);
159 		if (ant != NULL) {
160 			if (rc == NULL) {
161 				rc = ant;
162 			} else {
163 				Ancestor *tmp = rc;
164 				while (tmp->next != NULL) {
165 					tmp = tmp->next;
166 				}
167 				tmp->next = ant;
168 			}
169 		}
170 	}
171 
172 	for (i = 0; i < number; i++) {
173 		free(data_elems[i]);
174 	}
175 	free(data_elems);
176 
177 	return (rc);
178 }
179 
180 Ancestor *
createTaggedAncestor(const fru_regdef_t * def,Str element)181 Ancestor::createTaggedAncestor(const fru_regdef_t *def, Str element)
182 {
183 	// ancestors have to be tagged.
184 	if (def->tagType == FRU_X)
185 		return (NULL);
186 
187 	fru_tag_t tag;
188 	mk_tag(def->tagType, def->tagDense, def->payloadLen, &tag);
189 	Ancestor *rc = new Ancestor(element, tag, def);
190 
191 	if (element.compare(def->name) == 0) {
192 		rc->addInstance("", 0);
193 		return (rc);
194 	}
195 
196 	int found = 0;
197 	if (def->dataType == FDTYPE_Record) {
198 		uint32_t offset = 0;
199 		for (int i = 0; i < def->enumCount; i++) {
200 			const fru_regdef_t *tmp
201 				= fru_reg_lookup_def_by_name
202 					((char *)def->enumTable[i].text);
203 			Str path = "/";
204 			path << def->name;
205 			int f = definitionContains(tmp, def, element,
206 							offset, rc, path);
207 			if (f == 1) found = 1; // found needs to latch at one.
208 				offset += tmp->payloadLen;
209 		}
210 	}
211 
212 	if (!found) {
213 		delete rc;
214 		return (NULL);
215 	}
216 
217 	return (rc);
218 }
219 
220 int
definitionContains(const fru_regdef_t * def,const fru_regdef_t * parent_def,Str element,uint32_t offset,Ancestor * ant,Str path)221 Ancestor::definitionContains(const fru_regdef_t *def,
222 				const fru_regdef_t *parent_def,
223 				Str element,
224 				uint32_t offset,
225 				Ancestor *ant,
226 				Str path)
227 {
228 	if (element.compare(def->name) == 0) {
229 		if (parent_def->iterationType != FRU_NOT_ITERATED) {
230 			offset += 4;
231 			for (int i = 0; i < parent_def->iterationCount; i++) {
232 				Str tmp = path;
233 				tmp << "[" << i << "]/";
234 				ant->addInstance(tmp.peak(), offset);
235 				offset += (parent_def->payloadLen - 4) /
236 						parent_def->iterationCount;
237 			}
238 		} else {
239 			path << "/";
240 			ant->addInstance(path.peak(), offset);
241 		}
242 		return (1);
243 	}
244 
245 	int found = 0;
246 	if (def->dataType == FDTYPE_Record) {
247 		for (int i = 0; i < def->enumCount; i++) {
248 			const fru_regdef_t *tmp
249 				= fru_reg_lookup_def_by_name
250 					((char *)def->enumTable[i].text);
251 			Str newPath = path;
252 			newPath << "/" << def->name;
253 			int f = definitionContains(tmp, def, element,
254 							offset, ant, newPath);
255 			if (f == 1) found = 1; // found needs to latch at one.
256 				offset += tmp->payloadLen;
257 		}
258 	}
259 
260 	return (found);
261 }
262