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 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * FMA Event Injector language parser
29  */
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <limits.h>
34 
35 #include <inj.h>
36 #include <inj_err.h>
37 #include <inj_event.h>
38 #include <inj_hash.h>
39 #include <inj_lex.h>
40 
41 %}
42 
43 %union {
44 	inj_decl_t *l_decl;
45 	inj_declmem_t *l_declmem;
46 	inj_defn_t *l_defn;
47 	inj_defnmem_t *l_defnmem;
48 	inj_cmd_t *l_command;
49 	inj_randelem_t *l_randelem;
50 
51 	inj_hash_t *l_hash;
52 
53 	char *l_string;
54 	uint_t l_number;
55 	hrtime_t l_hrtime;
56 }
57 
58 %type	<l_decl>	decl_memlist
59 %type	<l_declmem>	decl_mem
60 %type	<l_declmem>	decl_baremem
61 %type	<l_declmem>	decl_mem_intr
62 %type	<l_number>	decl_intr_type
63 %type	<l_number>	decl_arraydim
64 %type	<l_declmem>	decl_mem_cplx
65 %type	<l_hash>	decl_enumlist
66 
67 %type	<l_defn>	defn_memlist
68 %type	<l_defnmem>	defn_memvals
69 %type	<l_defnmem>	defn_val
70 
71 %type	<l_command>	command
72 %type	<l_command>	cmd_repeatable
73 %type	<l_randelem>	rand_problist
74 %type	<l_randelem>	rand_element
75 
76 %type	<l_defn>	defined_event
77 %type	<l_number>	number
78 %type	<l_hrtime>	hrtime
79 
80 %token	INJ_TOK_EVDEF
81 %token	INJ_TOK_FMRIDEF
82 %token	INJ_TOK_AUTHDEF
83 %token	INJ_TOK_LISTDEF
84 
85 %token	INJ_TOK_INT8
86 %token	INJ_TOK_INT16
87 %token	INJ_TOK_INT32
88 %token	INJ_TOK_INT64
89 %token	INJ_TOK_UINT8
90 %token	INJ_TOK_UINT16
91 %token	INJ_TOK_UINT32
92 %token	INJ_TOK_UINT64
93 %token	INJ_TOK_BOOLEAN
94 %token	INJ_TOK_STRING
95 %token	INJ_TOK_ENUM
96 
97 %token	INJ_TOK_EVENT
98 %token	INJ_TOK_FMRI
99 %token	INJ_TOK_AUTH
100 %token	INJ_TOK_LIST
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, and list 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 	|	INJ_TOK_LISTDEF INJ_TOK_IDENT '{' decl_memlist '}' {
144 			if ($4 != NULL)
145 				inj_decl_finish($4, $2, ITEMTYPE_LIST);
146 		}
147 	;
148 
149 decl_memlist:	/* EMPTY */	{ $$ = NULL; }
150 	|	decl_memlist decl_mem ';' {
151 			if ($2 == NULL) {
152 				$$ = $1;
153 			} else if ($1 == NULL) {
154 				$$ = inj_decl_create($2);
155 			} else {
156 				inj_decl_addmem($1, $2);
157 				$$ = $1;
158 			}
159 		}
160 	;
161 
162 decl_mem:	decl_baremem
163 	|	decl_baremem decl_arraydim {
164 			if ($1 != NULL)
165 				inj_decl_mem_make_array($1, $2);
166 			$$ = $1;
167 		}
168 	;
169 
170 decl_baremem:	decl_mem_intr
171 	|	decl_mem_cplx
172 	;
173 
174 decl_mem_intr:	decl_intr_type INJ_TOK_IDENT {
175 			$$ = inj_decl_mem_create($2, $1);
176 		}
177 	;
178 
179 decl_intr_type:	INJ_TOK_INT8		{ $$ = MEMTYPE_INT8; }
180 	|	INJ_TOK_INT16		{ $$ = MEMTYPE_INT16; }
181 	|	INJ_TOK_INT32		{ $$ = MEMTYPE_INT32; }
182 	|	INJ_TOK_INT64		{ $$ = MEMTYPE_INT64; }
183 	|	INJ_TOK_UINT8		{ $$ = MEMTYPE_UINT8; }
184 	|	INJ_TOK_UINT16		{ $$ = MEMTYPE_UINT16; }
185 	|	INJ_TOK_UINT32		{ $$ = MEMTYPE_UINT32; }
186 	|	INJ_TOK_UINT64		{ $$ = MEMTYPE_UINT64; }
187 	|	INJ_TOK_BOOLEAN		{ $$ = MEMTYPE_BOOL; }
188 	|	INJ_TOK_STRING		{ $$ = MEMTYPE_STRING; }
189 	;
190 
191 decl_arraydim:	'[' number ']' {
192 			$$ = $2;
193 		}
194 	|	'[' ']' {
195 			$$ = 0;
196 		}
197 	;
198 
199 decl_mem_cplx:	INJ_TOK_ENUM INJ_TOK_IDENT '{' decl_enumlist '}' {
200 			$$ = inj_decl_mem_create_enum($2, $4);
201 		}
202 	|	INJ_TOK_EVENT INJ_TOK_FMACLASS INJ_TOK_IDENT {
203 			$$ = inj_decl_mem_create_defined($3, $2,
204 			    ITEMTYPE_EVENT);
205 		}
206 	|	INJ_TOK_FMRI INJ_TOK_IDENT INJ_TOK_IDENT {
207 			$$ = inj_decl_mem_create_defined($3, $2,
208 			    ITEMTYPE_FMRI);
209 		}
210 	|	INJ_TOK_AUTH INJ_TOK_IDENT INJ_TOK_IDENT {
211 			$$ = inj_decl_mem_create_defined($3, $2,
212 			    ITEMTYPE_AUTH);
213 		}
214 	|	INJ_TOK_LIST INJ_TOK_IDENT INJ_TOK_IDENT {
215 			$$ = inj_decl_mem_create_defined($3, $2,
216 			    ITEMTYPE_LIST);
217 		}
218 	;
219 
220 decl_enumlist:	INJ_TOK_IDENT {
221 			$$ = inj_zalloc(sizeof (inj_hash_t));
222 			inj_strhash_create($$);
223 
224 			inj_strhash_insert($$, $1, 1);
225 		}
226 	|	decl_enumlist ',' INJ_TOK_IDENT {
227 			if (inj_strhash_lookup($1, $3) != NULL)
228 				yyerror("duplicate enum value \"%s\"", $3);
229 			else
230 				inj_strhash_insert($1, $3, 1);
231 			$$ = $1;
232 		}
233 	;
234 
235 /*
236  * Event, FMRI, Authority, and list definitions
237  */
238 
239 defn:		INJ_TOK_EVENT INJ_TOK_FMACLASS INJ_TOK_IDENT '='
240 		    '{' defn_memlist '}' {
241 			inj_defn_finish($6, $2, $3, ITEMTYPE_EVENT);
242 			inj_strfree($2);
243 		}
244 	|	INJ_TOK_FMRI INJ_TOK_IDENT INJ_TOK_IDENT '='
245 		    '{' defn_memlist '}' {
246 			inj_defn_finish($6, $2, $3, ITEMTYPE_FMRI);
247 			inj_strfree($2);
248 		}
249 	|	INJ_TOK_AUTH INJ_TOK_IDENT INJ_TOK_IDENT '='
250 		    '{' defn_memlist '}' {
251 			inj_defn_finish($6, $2, $3, ITEMTYPE_AUTH);
252 			inj_strfree($2);
253 		}
254 	;
255 
256 defn_memlist:	defn_memvals {
257 			$$ = inj_defn_create($1);
258 		}
259 	|	defn_memlist ',' defn_memvals {
260 			inj_defn_addmem($1, $3);
261 			$$ = $1;
262 		}
263 	;
264 
265 defn_memvals:	defn_val
266 	|	INJ_TOK_EVENT INJ_TOK_FMACLASS {
267 			$$ = inj_defn_mem_create($2, DEFNMEM_EVENT);
268 		}
269 	|	INJ_TOK_FMRI INJ_TOK_IDENT {
270 			$$ = inj_defn_mem_create($2, DEFNMEM_FMRI);
271 		}
272 	|	INJ_TOK_AUTH INJ_TOK_IDENT {
273 			$$ = inj_defn_mem_create($2, DEFNMEM_AUTH);
274 		}
275 	|	'[' defn_memlist ']' {
276 			$$ = inj_defn_mem_create_list($2, DEFNMEM_ARRAY);
277 		}
278 	|	'{' defn_memlist '}' {
279 			$$ = inj_defn_mem_create_list($2, DEFNMEM_LIST);
280 		}
281 	;
282 
283 defn_val:	INJ_TOK_IMM {
284 			$$ = inj_defn_mem_create($1, DEFNMEM_IMM);
285 		}
286 	|	INJ_TOK_IDENT {
287 			$$ = inj_defn_mem_create($1, DEFNMEM_IDENT);
288 		}
289 	|	INJ_TOK_QSTRING {
290 			$$ = inj_defn_mem_create($1, DEFNMEM_QSTRING);
291 		}
292 	;
293 
294 /*
295  * Commands
296  */
297 
298 command:	cmd_repeatable
299 	|	INJ_TOK_ADDHRT hrtime { $$ = inj_cmd_addhrt($2); }
300 	|	INJ_TOK_ENDHRT { $$ = inj_cmd_endhrt(); }
301 	|	INJ_TOK_SLEEP number { $$ = inj_cmd_sleep($2); }
302 	|	INJ_TOK_REPEAT number cmd_repeatable {
303 			$$ = ($3 == NULL ? NULL : inj_cmd_repeat($3, $2));
304 		}
305 	;
306 
307 cmd_repeatable:	defined_event {
308 			$$ = ($1 == NULL ? NULL : inj_cmd_send($1));
309 		}
310 	|	INJ_TOK_RANDOMIZE '{' rand_problist '}' {
311 			$$ = ($3 == NULL ? NULL : inj_cmd_rand($3));
312 		}
313 	;
314 
315 rand_problist:	rand_element
316 	|	rand_problist ',' rand_element {
317 			$$ = ($1 == NULL || $3 == NULL) ?
318 			    NULL : inj_rand_add($1, $3);
319 		}
320 	;
321 
322 rand_element:	'{' defined_event ',' number '}' {
323 			$$ = ($2 == NULL ? NULL : inj_rand_create($2, $4));
324 		}
325 	;
326 
327 defined_event:	INJ_TOK_IDENT {
328 			inj_defn_t *ev;
329 
330 			if ((ev = inj_defn_lookup($1, MEMTYPE_EVENT)) ==
331 			    NULL) {
332 				yyerror("unknown event \"%s\"\n", $1);
333 				$$ = NULL;
334 			} else
335 				$$ = ev;
336 		}
337 
338 number:		INJ_TOK_IMM {
339 			u_longlong_t val;
340 
341 			if (inj_strtoull($1, 32, &val) < 0) {
342 				yyerror("invalid number");
343 				$$ = 0;
344 			} else
345 				$$ = (uint32_t)val;
346 		}
347 
348 hrtime:		INJ_TOK_IMM INJ_TOK_IDENT {
349 			longlong_t val;
350 
351 			if (inj_strtoll($1, 64, &val) < 0 ||
352 			    inj_strtime(&val, $2) < 0) {
353 				yyerror("invalid time");
354 				$$ = 0;
355 			} else
356 				$$ = val;
357 		}
358 
359 %%
360 
361 inj_list_t *
362 inj_program_read(const char *file)
363 {
364 	if (strcmp(file, "-") == 0) {
365 		yyin = stdin;
366 		yyinname = "stdin";
367 	} else {
368 		if ((yyin = fopen(file, "r")) == NULL)
369 			die("failed to open %s", file);
370 
371 		yyinname = strrchr(file, '/');
372 		if (yyinname != NULL)
373 			yyinname++;
374 		else
375 			yyinname = file;
376 	}
377 
378 	yyreset();
379 	(void) yyparse();
380 
381 	if (yyin != stdin)
382 		(void) fclose(yyin);
383 
384 	if (yynerrors != 0) {
385 		die("parsing failed - %d error%s\n", yynerrors,
386 		    (yynerrors > 1 ? "s" : ""));
387 	}
388 
389 	return (inj_cmds_get());
390 }
391