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/*
23 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#pragma ident	"%Z%%M%	%I%	%E% SMI"
28
29/*
30 * Events, FMRIs and authorities must be declared before they can be used.
31 * Routines in this file, driven by the parser, create the data structures
32 * associated with the declarations.
33 */
34
35#include <assert.h>
36#include <string.h>
37
38#include <inj_event.h>
39#include <inj_err.h>
40#include <inj_lex.h>
41#include <inj_list.h>
42#include <inj.h>
43
44static inj_hash_t inj_decls[ITEMTYPE_NITEMS];
45static int inj_decls_initialized;
46
47static inj_hash_t *
48item2hash(inj_itemtype_t item)
49{
50	int i;
51
52	assert(item >= 0 && item < sizeof (inj_decls) / sizeof (inj_hash_t));
53
54	if (!inj_decls_initialized) {
55		for (i = 0; i < sizeof (inj_decls) / sizeof (inj_hash_t); i++)
56			inj_strhash_create(&inj_decls[i]);
57		inj_decls_initialized = 1;
58	}
59
60	return (&inj_decls[item]);
61}
62
63inj_decl_t *
64inj_decl_lookup(const char *name, inj_itemtype_t type)
65{
66	inj_hash_t *hash = item2hash(type);
67	inj_var_t *v;
68
69	if ((v = inj_strhash_lookup(hash, name)) == NULL)
70		return (NULL);
71
72	return (inj_hash_get_cookie(v));
73}
74
75void
76inj_decl_mem_destroy(inj_declmem_t *dlm)
77{
78	inj_strfree(dlm->dlm_name);
79
80	if (dlm->dlm_type == MEMTYPE_ENUM)
81		inj_strhash_destroy(dlm->dlm_enumvals);
82}
83
84inj_declmem_t *
85inj_decl_mem_create(const char *name, inj_memtype_t type)
86{
87	inj_declmem_t *dlm = inj_zalloc(sizeof (inj_declmem_t));
88
89	dlm->dlm_name = name;
90	dlm->dlm_type = type;
91
92	return (dlm);
93}
94
95/* An embedded event, authority, or FMRI */
96inj_declmem_t *
97inj_decl_mem_create_defined(const char *name, const char *declnm,
98    inj_itemtype_t type)
99{
100	inj_declmem_t *dlm = inj_zalloc(sizeof (inj_declmem_t));
101
102	dlm->dlm_name = name;
103	dlm->dlm_type = inj_item2mem(type);
104
105	if ((dlm->dlm_decl = inj_decl_lookup(declnm, type)) == NULL) {
106		yyerror("unknown %s %s", inj_item2str(type), declnm);
107		return (NULL);
108	}
109
110	return (dlm);
111}
112
113inj_declmem_t *
114inj_decl_mem_create_enum(const char *name, inj_hash_t *vals)
115{
116	inj_declmem_t *dlm = inj_zalloc(sizeof (inj_declmem_t));
117
118	dlm->dlm_name = name;
119	dlm->dlm_type = MEMTYPE_ENUM;
120	dlm->dlm_enumvals = vals;
121
122	return (dlm);
123}
124
125/* Turn a previously-declared member into an array */
126void
127inj_decl_mem_make_array(inj_declmem_t *dlm, uint_t dim)
128{
129	dlm->dlm_flags |= DECLMEM_F_ARRAY;
130	dlm->dlm_arrdim = dim;
131}
132
133void
134inj_decl_destroy(inj_decl_t *decl)
135{
136	inj_declmem_t *m, *n;
137
138	inj_strfree(decl->decl_name);
139	inj_strhash_destroy(&decl->decl_memhash);
140
141	for (m = inj_list_next(&decl->decl_members); m != NULL; m = n) {
142		n = inj_list_next(m);
143
144		inj_decl_mem_destroy(m);
145	}
146
147	inj_free(decl, sizeof (inj_declmem_t));
148}
149
150inj_decl_t *
151inj_decl_create(inj_declmem_t *dlm)
152{
153	inj_decl_t *decl = inj_zalloc(sizeof (inj_decl_t));
154
155	decl->decl_lineno = yylineno;
156
157	inj_strhash_create(&decl->decl_memhash);
158
159	inj_list_append(&decl->decl_members, dlm);
160	(void) inj_strhash_insert(&decl->decl_memhash, dlm->dlm_name,
161	    (uintptr_t)dlm);
162
163	return (decl);
164}
165
166void
167inj_decl_addmem(inj_decl_t *decl, inj_declmem_t *dlm)
168{
169	inj_var_t *v;
170
171	if ((v = inj_strhash_lookup(&decl->decl_memhash, dlm->dlm_name)) !=
172	    NULL) {
173		inj_decl_t *other = inj_hash_get_cookie(v);
174
175		yyerror("duplicate member name %s (other on line %d)\n",
176		    dlm->dlm_name, other->decl_lineno);
177		inj_decl_destroy(decl);
178		return;
179	}
180
181	inj_list_append(&decl->decl_members, dlm);
182	(void) inj_strhash_insert(&decl->decl_memhash, dlm->dlm_name,
183	    (uintptr_t)dlm);
184}
185
186/*
187 * The various declaration types - events, FMRIs, and authorities - each have
188 * their own semantic validation requirements.
189 */
190
191/* No user-defined class member.  If ena isn't present, we'll generate it */
192static int
193inj_decl_validate_event(inj_decl_t *decl)
194{
195	if (inj_strhash_lookup(&decl->decl_memhash, "class") != NULL) {
196		yyerror("class may not be explicitly declared\n");
197		return (0);
198	}
199
200	if (inj_strhash_lookup(&decl->decl_memhash, "ena") == NULL)
201		decl->decl_flags |= DECL_F_AUTOENA;
202
203	return (1);
204}
205
206/* FMRIs must have a string scheme member */
207static int
208inj_decl_validate_fmri(inj_decl_t *decl)
209{
210	inj_declmem_t *dlm;
211	inj_var_t *v;
212
213	if ((v = inj_strhash_lookup(&decl->decl_memhash, "scheme")) == NULL) {
214		yyerror("fmri declared without scheme member\n");
215		return (0);
216	}
217
218	dlm = inj_hash_get_cookie(v);
219	if (dlm->dlm_type != MEMTYPE_STRING) {
220		yyerror("scheme member must be a string\n");
221		return (0);
222	}
223
224	return (1);
225}
226
227/*ARGSUSED*/
228static int
229inj_decl_validate_nop(inj_decl_t *decl)
230{
231	return (1);
232}
233
234void
235inj_decl_finish(inj_decl_t *decl, const char *name, inj_itemtype_t type)
236{
237	static int (*const validators[])(inj_decl_t *) = {
238		inj_decl_validate_event,
239		inj_decl_validate_fmri,
240		inj_decl_validate_nop,	/* no validation for auth */
241		inj_decl_validate_nop	/* no validation for lists */
242	};
243
244	inj_hash_t *hash = item2hash(type);
245	inj_var_t *v;
246
247	decl->decl_name = name;
248	decl->decl_type = type;
249
250	if (!validators[type](decl)) {
251		inj_decl_destroy(decl);
252		return;
253	}
254
255	if ((v = inj_strhash_lookup(hash, name)) != NULL) {
256		inj_decl_t *other = inj_hash_get_cookie(v);
257
258		yyerror("duplicate %s name %s (other on line %d)\n",
259		    inj_item2str(type), name, other->decl_lineno);
260		inj_decl_destroy(decl);
261		return;
262	}
263
264	(void) inj_strhash_insert(hash, name, (uintptr_t)decl);
265}
266