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#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%token	INJ_TOK_LISTDEF
86
87%token	INJ_TOK_INT8
88%token	INJ_TOK_INT16
89%token	INJ_TOK_INT32
90%token	INJ_TOK_INT64
91%token	INJ_TOK_UINT8
92%token	INJ_TOK_UINT16
93%token	INJ_TOK_UINT32
94%token	INJ_TOK_UINT64
95%token	INJ_TOK_BOOLEAN
96%token	INJ_TOK_STRING
97%token	INJ_TOK_ENUM
98
99%token	INJ_TOK_EVENT
100%token	INJ_TOK_FMRI
101%token	INJ_TOK_AUTH
102%token	INJ_TOK_LIST
103
104%token	INJ_TOK_ADDHRT
105%token	INJ_TOK_ENDHRT
106%token	INJ_TOK_SLEEP
107%token	INJ_TOK_REPEAT
108%token	INJ_TOK_RANDOMIZE
109
110%token	<l_string> INJ_TOK_IDENT
111%token	<l_string> INJ_TOK_FMACLASS
112%token	<l_string> INJ_TOK_IMM
113%token	<l_string> INJ_TOK_QSTRING
114
115%%
116
117statement_list:	/* EMPTY */
118	|	statement_list statement ';'
119	;
120
121statement:	decl
122	|	defn
123	|	command {
124			if ($1 != NULL)
125				inj_cmds_add($1);
126		}
127	;
128
129/*
130 * Event, FMRI, Authority, and list declarations
131 */
132
133decl:		INJ_TOK_EVDEF INJ_TOK_FMACLASS '{' decl_memlist '}' {
134			if ($4 != NULL)
135				inj_decl_finish($4, $2, ITEMTYPE_EVENT);
136		}
137	|	INJ_TOK_FMRIDEF INJ_TOK_IDENT '{' decl_memlist '}' {
138			if ($4 != NULL)
139				inj_decl_finish($4, $2, ITEMTYPE_FMRI);
140		}
141	|	INJ_TOK_AUTHDEF INJ_TOK_IDENT '{' decl_memlist '}' {
142			if ($4 != NULL)
143				inj_decl_finish($4, $2, ITEMTYPE_AUTH);
144		}
145	|	INJ_TOK_LISTDEF INJ_TOK_IDENT '{' decl_memlist '}' {
146			if ($4 != NULL)
147				inj_decl_finish($4, $2, ITEMTYPE_LIST);
148		}
149	;
150
151decl_memlist:	/* EMPTY */	{ $$ = NULL; }
152	|	decl_memlist decl_mem ';' {
153			if ($2 == NULL) {
154				$$ = $1;
155			} else if ($1 == NULL) {
156				$$ = inj_decl_create($2);
157			} else {
158				inj_decl_addmem($1, $2);
159				$$ = $1;
160			}
161		}
162	;
163
164decl_mem:	decl_baremem
165	|	decl_baremem decl_arraydim {
166			if ($1 != NULL)
167				inj_decl_mem_make_array($1, $2);
168			$$ = $1;
169		}
170	;
171
172decl_baremem:	decl_mem_intr
173	|	decl_mem_cplx
174	;
175
176decl_mem_intr:	decl_intr_type INJ_TOK_IDENT {
177			$$ = inj_decl_mem_create($2, $1);
178		}
179	;
180
181decl_intr_type:	INJ_TOK_INT8		{ $$ = MEMTYPE_INT8; }
182	|	INJ_TOK_INT16		{ $$ = MEMTYPE_INT16; }
183	|	INJ_TOK_INT32		{ $$ = MEMTYPE_INT32; }
184	|	INJ_TOK_INT64		{ $$ = MEMTYPE_INT64; }
185	|	INJ_TOK_UINT8		{ $$ = MEMTYPE_UINT8; }
186	|	INJ_TOK_UINT16		{ $$ = MEMTYPE_UINT16; }
187	|	INJ_TOK_UINT32		{ $$ = MEMTYPE_UINT32; }
188	|	INJ_TOK_UINT64		{ $$ = MEMTYPE_UINT64; }
189	|	INJ_TOK_BOOLEAN		{ $$ = MEMTYPE_BOOL; }
190	|	INJ_TOK_STRING		{ $$ = MEMTYPE_STRING; }
191	;
192
193decl_arraydim:	'[' number ']' {
194			$$ = $2;
195		}
196	|	'[' ']' {
197			$$ = 0;
198		}
199	;
200
201decl_mem_cplx:	INJ_TOK_ENUM INJ_TOK_IDENT '{' decl_enumlist '}' {
202			$$ = inj_decl_mem_create_enum($2, $4);
203		}
204	|	INJ_TOK_EVENT INJ_TOK_FMACLASS INJ_TOK_IDENT {
205			$$ = inj_decl_mem_create_defined($3, $2,
206			    ITEMTYPE_EVENT);
207		}
208	|	INJ_TOK_FMRI INJ_TOK_IDENT INJ_TOK_IDENT {
209			$$ = inj_decl_mem_create_defined($3, $2,
210			    ITEMTYPE_FMRI);
211		}
212	|	INJ_TOK_AUTH INJ_TOK_IDENT INJ_TOK_IDENT {
213			$$ = inj_decl_mem_create_defined($3, $2,
214			    ITEMTYPE_AUTH);
215		}
216	|	INJ_TOK_LIST INJ_TOK_IDENT INJ_TOK_IDENT {
217			$$ = inj_decl_mem_create_defined($3, $2,
218			    ITEMTYPE_LIST);
219		}
220	;
221
222decl_enumlist:	INJ_TOK_IDENT {
223			$$ = inj_zalloc(sizeof (inj_hash_t));
224			inj_strhash_create($$);
225
226			inj_strhash_insert($$, $1, 1);
227		}
228	|	decl_enumlist ',' INJ_TOK_IDENT {
229			if (inj_strhash_lookup($1, $3) != NULL)
230				yyerror("duplicate enum value \"%s\"", $3);
231			else
232				inj_strhash_insert($1, $3, 1);
233			$$ = $1;
234		}
235	;
236
237/*
238 * Event, FMRI, Authority, and list definitions
239 */
240
241defn:		INJ_TOK_EVENT INJ_TOK_FMACLASS INJ_TOK_IDENT '='
242		    '{' defn_memlist '}' {
243			inj_defn_finish($6, $2, $3, ITEMTYPE_EVENT);
244			inj_strfree($2);
245		}
246	|	INJ_TOK_FMRI INJ_TOK_IDENT INJ_TOK_IDENT '='
247		    '{' defn_memlist '}' {
248			inj_defn_finish($6, $2, $3, ITEMTYPE_FMRI);
249			inj_strfree($2);
250		}
251	|	INJ_TOK_AUTH INJ_TOK_IDENT INJ_TOK_IDENT '='
252		    '{' defn_memlist '}' {
253			inj_defn_finish($6, $2, $3, ITEMTYPE_AUTH);
254			inj_strfree($2);
255		}
256	;
257
258defn_memlist:	defn_memvals {
259			$$ = inj_defn_create($1);
260		}
261	|	defn_memlist ',' defn_memvals {
262			inj_defn_addmem($1, $3);
263			$$ = $1;
264		}
265	;
266
267defn_memvals:	defn_val
268	|	INJ_TOK_EVENT INJ_TOK_FMACLASS {
269			$$ = inj_defn_mem_create($2, DEFNMEM_EVENT);
270		}
271	|	INJ_TOK_FMRI INJ_TOK_IDENT {
272			$$ = inj_defn_mem_create($2, DEFNMEM_FMRI);
273		}
274	|	INJ_TOK_AUTH INJ_TOK_IDENT {
275			$$ = inj_defn_mem_create($2, DEFNMEM_AUTH);
276		}
277	|	'[' defn_memlist ']' {
278			$$ = inj_defn_mem_create_list($2, DEFNMEM_ARRAY);
279		}
280	|	'{' defn_memlist '}' {
281			$$ = inj_defn_mem_create_list($2, DEFNMEM_LIST);
282		}
283	;
284
285defn_val:	INJ_TOK_IMM {
286			$$ = inj_defn_mem_create($1, DEFNMEM_IMM);
287		}
288	|	INJ_TOK_IDENT {
289			$$ = inj_defn_mem_create($1, DEFNMEM_IDENT);
290		}
291	|	INJ_TOK_QSTRING {
292			$$ = inj_defn_mem_create($1, DEFNMEM_QSTRING);
293		}
294	;
295
296/*
297 * Commands
298 */
299
300command:	cmd_repeatable
301	|	INJ_TOK_ADDHRT hrtime { $$ = inj_cmd_addhrt($2); }
302	|	INJ_TOK_ENDHRT { $$ = inj_cmd_endhrt(); }
303	|	INJ_TOK_SLEEP number { $$ = inj_cmd_sleep($2); }
304	|	INJ_TOK_REPEAT number cmd_repeatable {
305			$$ = ($3 == NULL ? NULL : inj_cmd_repeat($3, $2));
306		}
307	;
308
309cmd_repeatable:	defined_event {
310			$$ = ($1 == NULL ? NULL : inj_cmd_send($1));
311		}
312	|	INJ_TOK_RANDOMIZE '{' rand_problist '}' {
313			$$ = ($3 == NULL ? NULL : inj_cmd_rand($3));
314		}
315	;
316
317rand_problist:	rand_element
318	|	rand_problist ',' rand_element {
319			$$ = ($1 == NULL || $3 == NULL) ?
320			    NULL : inj_rand_add($1, $3);
321		}
322	;
323
324rand_element:	'{' defined_event ',' number '}' {
325			$$ = ($2 == NULL ? NULL : inj_rand_create($2, $4));
326		}
327	;
328
329defined_event:	INJ_TOK_IDENT {
330			inj_defn_t *ev;
331
332			if ((ev = inj_defn_lookup($1, MEMTYPE_EVENT)) ==
333			    NULL) {
334				yyerror("unknown event \"%s\"\n", $1);
335				$$ = NULL;
336			} else
337				$$ = ev;
338		}
339
340number:		INJ_TOK_IMM {
341			u_longlong_t val;
342
343			if (inj_strtoull($1, 32, &val) < 0) {
344				yyerror("invalid number");
345				$$ = 0;
346			} else
347				$$ = (uint32_t)val;
348		}
349
350hrtime:		INJ_TOK_IMM INJ_TOK_IDENT {
351			longlong_t val;
352
353			if (inj_strtoll($1, 64, &val) < 0 ||
354			    inj_strtime(&val, $2) < 0) {
355				yyerror("invalid time");
356				$$ = 0;
357			} else
358				$$ = val;
359		}
360
361%%
362
363inj_list_t *
364inj_program_read(const char *file)
365{
366	if (strcmp(file, "-") == 0) {
367		yyin = stdin;
368		yyinname = "stdin";
369	} else {
370		if ((yyin = fopen(file, "r")) == NULL)
371			die("failed to open %s", file);
372
373		yyinname = strrchr(file, '/');
374		if (yyinname != NULL)
375			yyinname++;
376		else
377			yyinname = file;
378	}
379
380	yyreset();
381	(void) yyparse();
382
383	if (yyin != stdin)
384		(void) fclose(yyin);
385
386	if (yynerrors != 0) {
387		die("parsing failed - %d error%s\n", yynerrors,
388		    (yynerrors > 1 ? "s" : ""));
389	}
390
391	return (inj_cmds_get());
392}
393