1 %{
2 /*
3  * CDDL HEADER START
4  *
5  * The contents of this file are subject to the terms of the
6  * Common Development and Distribution License, Version 1.0 only
7  * (the "License").  You may not use this file except in compliance
8  * with the License.
9  *
10  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
11  * or http://www.opensolaris.org/os/licensing.
12  * See the License for the specific language governing permissions
13  * and limitations under the License.
14  *
15  * When distributing Covered Code, include this CDDL HEADER in each
16  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17  * If applicable, add the following below this CDDL HEADER, with the
18  * fields enclosed by brackets "[]" replaced with your own identifying
19  * information: Portions Copyright [yyyy] [name of copyright owner]
20  *
21  * CDDL HEADER END
22  *
23  * Copyright 2004 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  * FMA Event Injector language parser
31  */
32 
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <limits.h>
36 
37 #include <inj.h>
38 #include <inj_err.h>
39 #include <inj_event.h>
40 #include <inj_hash.h>
41 #include <inj_lex.h>
42 
43 %}
44 
45 %union {
46 	inj_decl_t *l_decl;
47 	inj_declmem_t *l_declmem;
48 	inj_defn_t *l_defn;
49 	inj_defnmem_t *l_defnmem;
50 	inj_cmd_t *l_command;
51 	inj_randelem_t *l_randelem;
52 
53 	inj_hash_t *l_hash;
54 
55 	char *l_string;
56 	uint_t l_number;
57 	hrtime_t l_hrtime;
58 }
59 
60 %type	<l_decl>	decl_memlist
61 %type	<l_declmem>	decl_mem
62 %type	<l_declmem>	decl_baremem
63 %type	<l_declmem>	decl_mem_intr
64 %type	<l_number>	decl_intr_type
65 %type	<l_number>	decl_arraydim
66 %type	<l_declmem>	decl_mem_cplx
67 %type	<l_hash>	decl_enumlist
68 
69 %type	<l_defn>	defn_memlist
70 %type	<l_defnmem>	defn_memvals
71 %type	<l_defnmem>	defn_val
72 
73 %type	<l_command>	command
74 %type	<l_command>	cmd_repeatable
75 %type	<l_randelem>	rand_problist
76 %type	<l_randelem>	rand_element
77 
78 %type	<l_defn>	defined_event
79 %type	<l_number>	number
80 %type	<l_hrtime>	hrtime
81 
82 %token	INJ_TOK_EVDEF
83 %token	INJ_TOK_FMRIDEF
84 %token	INJ_TOK_AUTHDEF
85 
86 %token	INJ_TOK_INT8
87 %token	INJ_TOK_INT16
88 %token	INJ_TOK_INT32
89 %token	INJ_TOK_INT64
90 %token	INJ_TOK_UINT8
91 %token	INJ_TOK_UINT16
92 %token	INJ_TOK_UINT32
93 %token	INJ_TOK_UINT64
94 %token	INJ_TOK_BOOLEAN
95 %token	INJ_TOK_STRING
96 %token	INJ_TOK_ENUM
97 
98 %token	INJ_TOK_EVENT
99 %token	INJ_TOK_FMRI
100 %token	INJ_TOK_AUTH
101 
102 %token	INJ_TOK_ADDHRT
103 %token	INJ_TOK_ENDHRT
104 %token	INJ_TOK_SLEEP
105 %token	INJ_TOK_REPEAT
106 %token	INJ_TOK_RANDOMIZE
107 
108 %token	<l_string> INJ_TOK_IDENT
109 %token	<l_string> INJ_TOK_FMACLASS
110 %token	<l_string> INJ_TOK_IMM
111 %token	<l_string> INJ_TOK_QSTRING
112 
113 %%
114 
115 statement_list:	/* EMPTY */
116 	|	statement_list statement ';'
117 	;
118 
119 statement:	decl
120 	|	defn
121 	|	command {
122 			if ($1 != NULL)
123 				inj_cmds_add($1);
124 		}
125 	;
126 
127 /*
128  * Event, FMRI, Authority declarations
129  */
130 
131 decl:		INJ_TOK_EVDEF INJ_TOK_FMACLASS '{' decl_memlist '}' {
132 			if ($4 != NULL)
133 				inj_decl_finish($4, $2, ITEMTYPE_EVENT);
134 		}
135 	|	INJ_TOK_FMRIDEF INJ_TOK_IDENT '{' decl_memlist '}' {
136 			if ($4 != NULL)
137 				inj_decl_finish($4, $2, ITEMTYPE_FMRI);
138 		}
139 	|	INJ_TOK_AUTHDEF INJ_TOK_IDENT '{' decl_memlist '}' {
140 			if ($4 != NULL)
141 				inj_decl_finish($4, $2, ITEMTYPE_AUTH);
142 		}
143 	;
144 
145 decl_memlist:	/* EMPTY */	{ $$ = NULL; }
146 	|	decl_memlist decl_mem ';' {
147 			if ($2 == NULL) {
148 				$$ = $1;
149 			} else if ($1 == NULL) {
150 				$$ = inj_decl_create($2);
151 			} else {
152 				inj_decl_addmem($1, $2);
153 				$$ = $1;
154 			}
155 		}
156 	;
157 
158 decl_mem:	decl_baremem
159 	|	decl_baremem decl_arraydim {
160 			if ($1 != NULL)
161 				inj_decl_mem_make_array($1, $2);
162 			$$ = $1;
163 		}
164 	;
165 
166 decl_baremem:	decl_mem_intr
167 	|	decl_mem_cplx
168 	;
169 
170 decl_mem_intr:	decl_intr_type INJ_TOK_IDENT {
171 			$$ = inj_decl_mem_create($2, $1);
172 		}
173 	;
174 
175 decl_intr_type:	INJ_TOK_INT8		{ $$ = MEMTYPE_INT8; }
176 	|	INJ_TOK_INT16		{ $$ = MEMTYPE_INT16; }
177 	|	INJ_TOK_INT32		{ $$ = MEMTYPE_INT32; }
178 	|	INJ_TOK_INT64		{ $$ = MEMTYPE_INT64; }
179 	|	INJ_TOK_UINT8		{ $$ = MEMTYPE_UINT8; }
180 	|	INJ_TOK_UINT16		{ $$ = MEMTYPE_UINT16; }
181 	|	INJ_TOK_UINT32		{ $$ = MEMTYPE_UINT32; }
182 	|	INJ_TOK_UINT64		{ $$ = MEMTYPE_UINT64; }
183 	|	INJ_TOK_BOOLEAN		{ $$ = MEMTYPE_BOOL; }
184 	|	INJ_TOK_STRING		{ $$ = MEMTYPE_STRING; }
185 	;
186 
187 decl_arraydim:	'[' number ']' {
188 			$$ = $2;
189 		}
190 	|	'[' ']' {
191 			$$ = 0;
192 		}
193 	;
194 
195 decl_mem_cplx:	INJ_TOK_ENUM INJ_TOK_IDENT '{' decl_enumlist '}' {
196 			$$ = inj_decl_mem_create_enum($2, $4);
197 		}
198 	|	INJ_TOK_EVENT INJ_TOK_FMACLASS INJ_TOK_IDENT {
199 			$$ = inj_decl_mem_create_defined($3, $2,
200 			    ITEMTYPE_EVENT);
201 		}
202 	|	INJ_TOK_FMRI INJ_TOK_IDENT INJ_TOK_IDENT {
203 			$$ = inj_decl_mem_create_defined($3, $2,
204 			    ITEMTYPE_FMRI);
205 		}
206 	|	INJ_TOK_AUTH INJ_TOK_IDENT INJ_TOK_IDENT {
207 			$$ = inj_decl_mem_create_defined($3, $2,
208 			    ITEMTYPE_AUTH);
209 		}
210 	;
211 
212 decl_enumlist:	INJ_TOK_IDENT {
213 			$$ = inj_zalloc(sizeof (inj_hash_t));
214 			inj_strhash_create($$);
215 
216 			inj_strhash_insert($$, $1, 1);
217 		}
218 	|	decl_enumlist ',' INJ_TOK_IDENT {
219 			if (inj_strhash_lookup($1, $3) != NULL)
220 				yyerror("duplicate enum value \"%s\"", $3);
221 			else
222 				inj_strhash_insert($1, $3, 1);
223 			$$ = $1;
224 		}
225 	;
226 
227 /*
228  * Event, FMRI, Authority definitions
229  */
230 
231 defn:		INJ_TOK_EVENT INJ_TOK_FMACLASS INJ_TOK_IDENT '='
232 		    '{' defn_memlist '}' {
233 			inj_defn_finish($6, $2, $3, ITEMTYPE_EVENT);
234 			inj_strfree($2);
235 		}
236 	|	INJ_TOK_FMRI INJ_TOK_IDENT INJ_TOK_IDENT '='
237 		    '{' defn_memlist '}' {
238 			inj_defn_finish($6, $2, $3, ITEMTYPE_FMRI);
239 			inj_strfree($2);
240 		}
241 	|	INJ_TOK_AUTH INJ_TOK_IDENT INJ_TOK_IDENT '='
242 		    '{' defn_memlist '}' {
243 			inj_defn_finish($6, $2, $3, ITEMTYPE_AUTH);
244 			inj_strfree($2);
245 		}
246 	;
247 
248 defn_memlist:	defn_memvals {
249 			$$ = inj_defn_create($1);
250 		}
251 	|	defn_memlist ',' defn_memvals {
252 			inj_defn_addmem($1, $3);
253 			$$ = $1;
254 		}
255 	;
256 
257 defn_memvals:	defn_val
258 	|	INJ_TOK_EVENT INJ_TOK_FMACLASS {
259 			$$ = inj_defn_mem_create($2, DEFNMEM_EVENT);
260 		}
261 	|	INJ_TOK_FMRI INJ_TOK_IDENT {
262 			$$ = inj_defn_mem_create($2, DEFNMEM_FMRI);
263 		}
264 	|	INJ_TOK_AUTH INJ_TOK_IDENT {
265 			$$ = inj_defn_mem_create($2, DEFNMEM_AUTH);
266 		}
267 	|	'[' defn_memlist ']' {
268 			$$ = inj_defn_mem_create_list($2, DEFNMEM_ARRAY);
269 		}
270 	|	'{' defn_memlist '}' {
271 			$$ = inj_defn_mem_create_list($2, DEFNMEM_SUBLIST);
272 		}
273 	;
274 
275 defn_val:	INJ_TOK_IMM {
276 			$$ = inj_defn_mem_create($1, DEFNMEM_IMM);
277 		}
278 	|	INJ_TOK_IDENT {
279 			$$ = inj_defn_mem_create($1, DEFNMEM_IDENT);
280 		}
281 	|	INJ_TOK_QSTRING {
282 			$$ = inj_defn_mem_create($1, DEFNMEM_QSTRING);
283 		}
284 	;
285 
286 /*
287  * Commands
288  */
289 
290 command:	cmd_repeatable
291 	|	INJ_TOK_ADDHRT hrtime { $$ = inj_cmd_addhrt($2); }
292 	|	INJ_TOK_ENDHRT { $$ = inj_cmd_endhrt(); }
293 	|	INJ_TOK_SLEEP number { $$ = inj_cmd_sleep($2); }
294 	|	INJ_TOK_REPEAT number cmd_repeatable {
295 			$$ = ($3 == NULL ? NULL : inj_cmd_repeat($3, $2));
296 		}
297 	;
298 
299 cmd_repeatable:	defined_event {
300 			$$ = ($1 == NULL ? NULL : inj_cmd_send($1));
301 		}
302 	|	INJ_TOK_RANDOMIZE '{' rand_problist '}' {
303 			$$ = ($3 == NULL ? NULL : inj_cmd_rand($3));
304 		}
305 	;
306 
307 rand_problist:	rand_element
308 	|	rand_problist ',' rand_element {
309 			$$ = ($1 == NULL || $3 == NULL) ?
310 			    NULL : inj_rand_add($1, $3);
311 		}
312 	;
313 
314 rand_element:	'{' defined_event ',' number '}' {
315 			$$ = ($2 == NULL ? NULL : inj_rand_create($2, $4));
316 		}
317 	;
318 
319 defined_event:	INJ_TOK_IDENT {
320 			inj_defn_t *ev;
321 
322 			if ((ev = inj_defn_lookup($1, MEMTYPE_EVENT)) ==
323 			    NULL) {
324 				yyerror("unknown event \"%s\"\n", $1);
325 				$$ = NULL;
326 			} else
327 				$$ = ev;
328 		}
329 
330 number:		INJ_TOK_IMM {
331 			u_longlong_t val;
332 
333 			if (inj_strtoull($1, 32, &val) < 0) {
334 				yyerror("invalid number");
335 				$$ = 0;
336 			} else
337 				$$ = (uint32_t)val;
338 		}
339 
340 hrtime:		INJ_TOK_IMM INJ_TOK_IDENT {
341 			longlong_t val;
342 
343 			if (inj_strtoll($1, 64, &val) < 0 ||
344 			    inj_strtime(&val, $2) < 0) {
345 				yyerror("invalid time");
346 				$$ = 0;
347 			} else
348 				$$ = val;
349 		}
350 
351 %%
352 
353 inj_list_t *
354 inj_program_read(const char *file)
355 {
356 	if (strcmp(file, "-") == 0) {
357 		yyin = stdin;
358 		yyinname = "stdin";
359 	} else {
360 		if ((yyin = fopen(file, "r")) == NULL)
361 			die("failed to open %s", file);
362 
363 		if ((yyinname = strrchr(file, '/')) == NULL)
364 			yyinname = file;
365 	}
366 
367 	yyreset();
368 	(void) yyparse();
369 
370 	if (yyin != stdin)
371 		(void) fclose(yyin);
372 
373 	if (yynerrors != 0) {
374 		die("parsing failed - %d error%s\n", yynerrors,
375 		    (yynerrors > 1 ? "s" : ""));
376 	}
377 
378 	return (inj_cmds_get());
379 }
380