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