xref: /illumos-gate/usr/src/lib/libtnf/info.c (revision 7c478bd9)
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) 1994, by Sun Microsytems, Inc.
24  */
25 
26 #pragma	ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include "libtnf.h"
29 
30 #define	TAG_INDEX(x)	(TNF_TAG16_ABS16(x) / sizeof (tnf_ref32_t))
31 
32 /*
33  *
34  */
35 
36 static struct taginfo *	add_info(TNF *, tnf_ref32_t *);
37 
38 static struct taginfo *
39 init_abstract_info(TNF *, tnf_ref32_t *, struct taginfo *);
40 
41 static struct taginfo *
42 init_derived_info(TNF *, tnf_ref32_t *, struct taginfo *);
43 
44 static struct taginfo *
45 init_scalar_info(TNF *, tnf_ref32_t *, struct taginfo *);
46 
47 static struct taginfo *
48 init_struct_info(TNF *, tnf_ref32_t *, struct taginfo *);
49 
50 static struct taginfo *
51 init_array_info(TNF *, tnf_ref32_t *, struct taginfo *);
52 
53 static void init_slots(TNF *, tnf_ref32_t *, struct taginfo *);
54 
55 /*
56  * Allocate tag table and directory
57  */
58 
59 tnf_errcode_t
_tnf_init_tags(TNF * tnf)60 _tnf_init_tags(TNF *tnf)
61 {
62 	if ((tnf->tag_table = calloc(TAGTABCNT, sizeof (struct taginfo *)))
63 	    == NULL)
64 		return (TNF_ERR_ALLOCFAIL);
65 	if ((tnf->tag_directory = calloc(TAGDIRCNT(tnf->directory_size),
66 						sizeof (struct taginfo *)))
67 	    == NULL)
68 		return (TNF_ERR_ALLOCFAIL);
69 	return (TNF_ERR_NONE);
70 }
71 
72 /*
73  * Deallocate all taginfos and tables associated with TNF handle
74  */
75 
76 tnf_errcode_t
_tnf_fini_tags(TNF * tnf)77 _tnf_fini_tags(TNF *tnf)
78 {
79 	int		i;
80 	struct taginfo	*info, *link;
81 
82 	/*
83 	 * free taginfos
84 	 */
85 	for (i = 0; i < TAGTABCNT; i++) {
86 		info = tnf->tag_table[i];
87 		while (info) {
88 			/* remember link */
89 			link = info->link;
90 			/* free slot information */
91 			if (info->slotinfo)
92 				free(info->slotinfo);
93 			/* free taginfo */
94 			free(info);
95 			/* next in hash chain */
96 			info = link;
97 		}
98 	}
99 	/*
100 	 * free the tables
101 	 */
102 	free(tnf->tag_table);
103 	tnf->tag_table = NULL;
104 	free(tnf->tag_directory);
105 	tnf->tag_directory = NULL;
106 
107 	return (TNF_ERR_NONE);
108 }
109 
110 /*
111  * Get info for supplied tag
112  */
113 
114 struct taginfo *
_tnf_get_info(TNF * tnf,tnf_ref32_t * tag)115 _tnf_get_info(TNF *tnf, tnf_ref32_t *tag)
116 {
117 	struct taginfo	*bucket, *info;
118 
119 	bucket = tnf->tag_table[TAGHASH(tnf, tag)];
120 	for (info = bucket; info; info = info->link)
121 		if (info->tag == tag)
122 			return (info); /* found it */
123 
124 	/* default: not there, create */
125 	return (add_info(tnf, tag));
126 }
127 
128 /*
129  * Get info for supplied record
130  * Use fast lookup, if possible
131  */
132 
133 struct taginfo *
_tnf_record_info(TNF * tnf,tnf_ref32_t * record)134 _tnf_record_info(TNF *tnf, tnf_ref32_t *record)
135 {
136 	tnf_ref32_t	ref32;
137 	tnf_ref16_t	tag16;
138 	tnf_abs16_t	index;
139 	struct taginfo	*info;
140 
141 	ref32 = _GET_INT32(tnf, record);
142 
143 	index = 0;
144 	if (TNF_REF32_IS_PAIR(ref32)) {
145 		tag16 = TNF_REF32_TAG16(ref32);
146 		if (TNF_TAG16_IS_ABS(tag16))
147 			index = TAG_INDEX(tag16);
148 	}
149 
150 	if (index) {
151 		if ((info = tnf->tag_directory[index]) != NULL)
152 			return (info);
153 		else {		/* not in directory yet */
154 			info = _tnf_get_info(tnf, _tnf_get_tag(tnf, record));
155 			/* enter into tag directory */
156 			return ((tnf->tag_directory[index] = info));
157 		}
158 	}
159 
160 	/* default: not referenced via index */
161 	return (_tnf_get_info(tnf, _tnf_get_tag(tnf, record)));
162 }
163 
164 /*
165  * Add a new taginfo for tag
166  */
167 
168 static struct taginfo *
add_info(TNF * tnf,tnf_ref32_t * tag)169 add_info(TNF *tnf, tnf_ref32_t *tag)
170 {
171 	struct taginfo 	*info, *bucket;
172 	unsigned	hash;
173 	tnf_ref32_t	*meta;
174 
175 	info = (struct taginfo *)calloc(1, sizeof (struct taginfo));
176 
177 	/* Initialize members */
178 	info->tnf 	= tnf;
179 	info->tag 	= tag;
180 	info->name	= _tnf_get_name(tnf, tag);
181 	info->props	= _tnf_get_props(tnf, tag);
182 	info->kind	= _tnf_get_kind(tnf, tag);
183 	info->size	= _tnf_get_storage_size(tnf, tag);
184 	info->align	= _tnf_get_align(tnf, tag);
185 
186 	/* Add it to table */
187 	hash 		= TAGHASH(tnf, tag);
188 	bucket 		= tnf->tag_table[hash];
189 	info->link 	= bucket;
190 	tnf->tag_table[hash] = info;
191 
192 	/* Ensure meta info is available */
193 	meta		= _tnf_get_tag(tnf, tag);
194 	info->meta	= _tnf_get_info(tnf, meta);
195 
196 	/*
197 	 * Initialize info
198 	 * Derived must be first clause due to property inheritance
199 	 */
200 
201 	if (INFO_DERIVED(info))
202 		return (init_derived_info(tnf, tag, info));
203 	else if (INFO_STRUCT(info))
204 		return (init_struct_info(tnf, tag, info));
205 	else if (INFO_ARRAY(info))
206 		return (init_array_info(tnf, tag, info));
207 	else if (INFO_SCALAR(info))
208 		return (init_scalar_info(tnf, tag, info));
209 	else			/* XXX assume abstract type */
210 		return (init_abstract_info(tnf, tag, info));
211 }
212 
213 
214 /*
215  * Initialize info for an abstract tag
216  */
217 
218 static struct taginfo *
219 /* ARGSUSED */
init_abstract_info(TNF * tnf,tnf_ref32_t * tag,struct taginfo * info)220 init_abstract_info(TNF *tnf, tnf_ref32_t *tag, struct taginfo *info)
221 {
222 	if (INFO_SCALAR(info) || INFO_DERIVED(info) ||
223 	    INFO_STRUCT(info) || INFO_ARRAY(info))
224 		_tnf_error(tnf, TNF_ERR_INTERNAL);
225 	if (info->size == (size_t)-1)
226 		_tnf_error(tnf, TNF_ERR_BADTNF);
227 	return (info);
228 }
229 
230 /*
231  * Initialize info for a derived tag
232  */
233 
234 static struct taginfo *
init_derived_info(TNF * tnf,tnf_ref32_t * tag,struct taginfo * info)235 init_derived_info(TNF *tnf, tnf_ref32_t *tag, struct taginfo *info)
236 {
237 	tnf_ref32_t	*base_tag;
238 
239 	if (!INFO_DERIVED(info))
240 		_tnf_error(tnf, TNF_ERR_INTERNAL);
241 
242 	/* Ensure ultimate base information is available */
243 	base_tag 	= _tnf_get_base_tag(tnf, tag);
244 	info->base 	= _tnf_get_info(tnf, base_tag);
245 
246 	return (info);
247 }
248 
249 /*
250  * Initialize info for a scalar tag
251  */
252 
253 static struct taginfo *
254 /* ARGSUSED */
init_scalar_info(TNF * tnf,tnf_ref32_t * tag,struct taginfo * info)255 init_scalar_info(TNF *tnf, tnf_ref32_t *tag, struct taginfo *info)
256 {
257 	if ((!INFO_SCALAR(info)) ||
258 	    (INFO_DERIVED(info) || INFO_ARRAY(info) || INFO_STRUCT(info)))
259 		_tnf_error(tnf, TNF_ERR_INTERNAL);
260 	if (info->size == (size_t)-1)
261 		_tnf_error(tnf, TNF_ERR_BADTNF);
262 
263 	/* XXX alignment already done */
264 
265 	return (info);
266 }
267 
268 /*
269  * Initialize info for a struct tag
270  */
271 
272 static struct taginfo *
init_struct_info(TNF * tnf,tnf_ref32_t * tag,struct taginfo * info)273 init_struct_info(TNF *tnf, tnf_ref32_t *tag, struct taginfo *info)
274 {
275 	if ((!INFO_STRUCT(info)) ||
276 	    (INFO_DERIVED(info) || INFO_ARRAY(info) || INFO_SCALAR(info)))
277 		_tnf_error(tnf, TNF_ERR_INTERNAL);
278 	if (info->size == (size_t)-1)
279 		_tnf_error(tnf, TNF_ERR_BADTNF);
280 
281 	/* Get slot information */
282 	init_slots(tnf, tag, info);
283 
284 	return (info);
285 }
286 
287 /*
288  * Initialize info for an array tag
289  */
290 
291 static struct taginfo *
init_array_info(TNF * tnf,tnf_ref32_t * tag,struct taginfo * info)292 init_array_info(TNF *tnf, tnf_ref32_t *tag, struct taginfo *info)
293 {
294 	tnf_ref32_t	*elt_tag;
295 	int		defeat;
296 
297 	if ((!INFO_ARRAY(info)) ||
298 	    (INFO_DERIVED(info) || INFO_STRUCT(info) || INFO_SCALAR(info)))
299 		_tnf_error(tnf, TNF_ERR_INTERNAL);
300 
301 	/* XXX special-case abstract array tag */
302 	defeat = (strcmp(info->name, TNF_N_ARRAY) == 0);
303 
304 	/* Require all arrays to be self-sized records */
305 	if (!(INFO_TAGGED(info) && (info->size == (size_t)-1)))
306 		if (!defeat)
307 			_tnf_error(tnf, TNF_ERR_BADTNF);
308 
309 	/* Store array header size */
310 	info->hdrsize = _tnf_get_header_size(tnf, tag);
311 	/* XXX Temporary sanity check */
312 	if (info->hdrsize != sizeof (struct tnf_array_hdr))
313 		if (!defeat)
314 			_tnf_error(tnf, TNF_ERR_BADTNF);
315 
316 	/* Get slot information */
317 	init_slots(tnf, tag, info);
318 
319 	/* Get info for element type */
320 	elt_tag = (tnf_ref32_t *)_tnf_get_slot_typed(tnf, tag,
321 		/* LINTED pointer cast may result in improper alignment */
322 						    TNF_N_ELEMENT_TYPE);
323 	/* XXX tnf_array has element_type == NULL */
324 	info->base = elt_tag ? _tnf_get_info(tnf, elt_tag): NULL;
325 
326 	return (info);
327 }
328 
329 /*
330  * Initialize slot information for aggregate tag
331  */
332 
333 static void
init_slots(TNF * tnf,tnf_ref32_t * tag,struct taginfo * info)334 init_slots(TNF *tnf, tnf_ref32_t *tag, struct taginfo *info)
335 {
336 	tnf_ref32_t	*slot_types, *slot_names;
337 	tnf_ref32_t	*types, *names;
338 	unsigned	count, i, offset;
339 	struct slotinfo	*slotinfo;
340 
341 	slot_types = (tnf_ref32_t *)
342 		/* LINTED pointer cast may result in improper alignment */
343 		_tnf_get_slot_typed(tnf, tag, TNF_N_SLOT_TYPES);
344 	slot_names = (tnf_ref32_t *)
345 		/* LINTED pointer cast may result in improper alignment */
346 		_tnf_get_slot_typed(tnf, tag, TNF_N_SLOT_NAMES);
347 
348 	/* abstract tags have no slots */
349 	if (slot_types == TNF_NULL)
350 		return;
351 
352 	count = _tnf_get_element_count(tnf, slot_types, sizeof (tnf_ref32_t));
353 	/* LINTED pointer cast may result in improper alignment */
354 	types = (tnf_ref32_t *)_tnf_get_elements(tnf, slot_types);
355 	names = ((slot_names == TNF_NULL) ? TNF_NULL :
356 		/* LINTED pointer cast may result in improper alignment */
357 			(tnf_ref32_t *)_tnf_get_elements(tnf, slot_names));
358 
359 	slotinfo = (struct slotinfo *)
360 		calloc(1, sizeof (unsigned) + (count * sizeof (struct slot)));
361 	if (slotinfo == (struct slotinfo *)NULL)
362 		_tnf_error(tnf, TNF_ERR_ALLOCFAIL);
363 
364 	slotinfo->slot_count = count;
365 	offset 	= 0;
366 
367 	for (i = 0; i < count; i++) {
368 		tnf_ref32_t	*type_elt, *name_elt;
369 		struct taginfo	*elt_info;
370 		size_t		ref_size, align;
371 
372 		/* XXX No checks here for missing tags */
373 		type_elt = _GET_REF32(tnf, &types[i]);
374 		name_elt = names ? _GET_REF32(tnf, &names[i]) : TNF_NULL;
375 
376 		/* Resolve slot tag into taginfo */
377 		elt_info = _tnf_get_info(tnf, type_elt);
378 		slotinfo->slots[i].slot_type = elt_info;
379 		slotinfo->slots[i].slot_name =
380 			((name_elt != TNF_NULL) ?
381 				_tnf_get_chars(tnf, name_elt) :
382 				_tnf_get_name(tnf, type_elt));
383 
384 		/* Get cached reference size */
385 		ref_size = INFO_REF_SIZE(elt_info);
386 
387 		/* Get cached alignment */
388 		align = INFO_ALIGN(elt_info); /* XXX */
389 
390 		/* Adjust offset to account for alignment, if needed */
391 		offset = ALIGN(offset, align);
392 
393 		slotinfo->slots[i].slot_offset = offset;
394 
395 		/* Bump offset by reference size */
396 		offset += ref_size;
397 	}
398 
399 	info->slotinfo = slotinfo;
400 }
401