xref: /illumos-gate/usr/src/cmd/zonecfg/zonecfg_lex.l (revision c160bf3613805cfb4a89a0433ae896d3594f551f)
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 (the "License").
7  * You may not use this file except in compliance 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 /*
24  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
25  */
26 
27 #include <assert.h>
28 #include <string.h>
29 #include <libintl.h>
30 #include "zonecfg.h"
31 #include "zonecfg_grammar.tab.h"
32 
33 /*
34  * This constant defines the number of entries added to unclaimed_tokens[]
35  * when it runs out of space.
36  */
37 #define	UNCLAIMED_TOKENS_BUFFER_GROWTH	4
38 
39 /*
40  * Invariants:
41  *
42  *	unclaimed_tokens == NULL IFF unclaimed_tokens_size == 0
43  *	unclaimed_tokens_size == 0 IFF num_unclaimed_tokens == 0
44  */
45 static char **unclaimed_tokens;		/* TOKENs produced by Lex (see below) */
46 					/* but not claimed by YACC reduction */
47 					/* rules */
48 static unsigned int unclaimed_tokens_size;	/* size of unclaimed_tokens */
49 static unsigned int num_unclaimed_tokens;	/* number of unclaimed TOKENs */
50 
51 int lex_lineno = 1;	/* line number for error reporting */
52 static int state = INITIAL;
53 extern boolean_t cmd_file_mode;
54 extern boolean_t saw_error;
55 extern void yyerror(char *s);
56 
57 static char *create_token(char *s);
58 %}
59 
60 %a 7000
61 %p 5000
62 %e 2000
63 %n 1000
64 
65 %{
66 /*
67  * The three states below are for tokens, lists and complex property values.
68  * Note that simple property values are a subset of tokens.
69  */
70 %}
71 %s TSTATE
72 %s LSTATE
73 %s CSTATE
74 %%
75 
76 <INITIAL>"#"[^\n]*	{ }
77 
78 <INITIAL>add	{
79 			BEGIN TSTATE;
80 			state = TSTATE;
81 			return ADD;
82 		}
83 
84 <INITIAL>cancel	{
85 			BEGIN TSTATE;
86 			state = TSTATE;
87 			return CANCEL;
88 		}
89 
90 <INITIAL>commit	{
91 			BEGIN TSTATE;
92 			state = TSTATE;
93 			return COMMIT;
94 		}
95 
96 <INITIAL>create	{
97 			BEGIN TSTATE;
98 			state = TSTATE;
99 			return CREATE;
100 		}
101 
102 <INITIAL>delete {
103 			BEGIN TSTATE;
104 			state = TSTATE;
105 			return DELETE;
106 		}
107 
108 <INITIAL>end	{
109 			BEGIN TSTATE;
110 			state = TSTATE;
111 			return END;
112 		}
113 
114 <INITIAL>exit	{
115 			BEGIN TSTATE;
116 			state = TSTATE;
117 			return EXIT;
118 		}
119 
120 <INITIAL>export	{
121 			BEGIN TSTATE;
122 			state = TSTATE;
123 			return EXPORT;
124 		}
125 
126 <INITIAL>"?"|help {
127 			BEGIN TSTATE;
128 			state = TSTATE;
129 			return HELP;
130 		}
131 
132 <INITIAL>info	{
133 			BEGIN TSTATE;
134 			state = TSTATE;
135 			return INFO;
136 		}
137 
138 <INITIAL>remove	{
139 			BEGIN TSTATE;
140 			state = TSTATE;
141 			return REMOVE;
142 		}
143 
144 <INITIAL>revert	{
145 			BEGIN TSTATE;
146 			state = TSTATE;
147 			return REVERT;
148 		}
149 
150 <INITIAL>select {
151 			BEGIN TSTATE;
152 			state = TSTATE;
153 			return SELECT;
154 		}
155 
156 <INITIAL>set {
157 			BEGIN TSTATE;
158 			state = TSTATE;
159 			return SET;
160 		}
161 
162 <INITIAL>clear {
163 			BEGIN TSTATE;
164 			state = TSTATE;
165 			return CLEAR;
166 		}
167 
168 <INITIAL>verify	{
169 			BEGIN TSTATE;
170 			state = TSTATE;
171 			return VERIFY;
172 		}
173 
174 <TSTATE>net	{ return NET; }
175 
176 <TSTATE>fs	{ return FS; }
177 
178 <TSTATE>device	{ return DEVICE; }
179 
180 <TSTATE>rctl	{ return RCTL; }
181 
182 <TSTATE>attr	{ return ATTR; }
183 
184 <TSTATE>admin	{ return ADMIN; }
185 
186 <TSTATE>security-flags { return SECFLAGS; }
187 
188 <TSTATE>zonename	{ return ZONENAME; }
189 <CSTATE>zonename	{ return ZONENAME; }
190 
191 <TSTATE>dataset	{ return DATASET; }
192 
193 <TSTATE>dedicated-cpu	{ return PSET; }
194 
195 <TSTATE>capped-cpu	{ return PCAP; }
196 
197 <TSTATE>capped-memory	{ return MCAP; }
198 
199 <TSTATE>zonepath	{ return ZONEPATH; }
200 <CSTATE>zonepath	{ return ZONEPATH; }
201 
202 <TSTATE>brand	{ return BRAND; }
203 <CSTATE>brand	{ return BRAND; }
204 
205 <TSTATE>autoboot	{ return AUTOBOOT; }
206 <CSTATE>autoboot	{ return AUTOBOOT; }
207 
208 <TSTATE>ip-type		{ return IPTYPE; }
209 <CSTATE>ip-type		{ return IPTYPE; }
210 
211 <TSTATE>pool	{ return POOL; }
212 <CSTATE>pool	{ return POOL; }
213 
214 <TSTATE>limitpriv	{ return LIMITPRIV; }
215 <CSTATE>limitpriv	{ return LIMITPRIV; }
216 
217 <TSTATE>bootargs	{ return BOOTARGS; }
218 <CSTATE>bootargs	{ return BOOTARGS; }
219 
220 <TSTATE>type	{ return TYPE; }
221 <CSTATE>type	{ return TYPE; }
222 
223 <TSTATE>value	{ return VALUE; }
224 <CSTATE>value	{ return VALUE; }
225 
226 <TSTATE>options	{ return OPTIONS; }
227 <CSTATE>options	{ return OPTIONS; }
228 
229 <TSTATE>allowed-address { return ALLOWED_ADDRESS; }
230 <CSTATE>allowed-address { return ALLOWED_ADDRESS; }
231 
232 <TSTATE>address	{ return ADDRESS; }
233 <CSTATE>address	{ return ADDRESS; }
234 
235 <TSTATE>physical	{ return PHYSICAL; }
236 <CSTATE>physical	{ return PHYSICAL; }
237 
238 <TSTATE>defrouter	{ return DEFROUTER; }
239 <CSTATE>defrouter	{ return DEFROUTER; }
240 
241 <TSTATE>dir	{ return DIR; }
242 <CSTATE>dir	{ return DIR; }
243 
244 <TSTATE>special	{ return SPECIAL; }
245 <CSTATE>special	{ return SPECIAL; }
246 
247 <TSTATE>raw	{ return RAW; }
248 <CSTATE>raw	{ return RAW; }
249 
250 <TSTATE>name	{ return NAME; }
251 <CSTATE>name	{ return NAME; }
252 
253 <TSTATE>match	{ return MATCH; }
254 <CSTATE>match	{ return MATCH; }
255 
256 <TSTATE>priv	{ return PRIV; }
257 <CSTATE>priv	{ return PRIV; }
258 
259 <TSTATE>limit	{ return LIMIT; }
260 <CSTATE>limit	{ return LIMIT; }
261 
262 <TSTATE>action	{ return ACTION; }
263 <CSTATE>action	{ return ACTION; }
264 
265 <TSTATE>ncpus	{ return NCPUS; }
266 <CSTATE>ncpus	{ return NCPUS; }
267 
268 <TSTATE>locked	{ return LOCKED; }
269 <CSTATE>locked	{ return LOCKED; }
270 
271 <TSTATE>swap	{ return SWAP; }
272 <CSTATE>swap	{ return SWAP; }
273 
274 <TSTATE>importance	{ return IMPORTANCE; }
275 <CSTATE>importance	{ return IMPORTANCE; }
276 
277 <TSTATE>cpu-shares	{ return SHARES; }
278 <CSTATE>cpu-shares	{ return SHARES; }
279 
280 <TSTATE>max-lwps	{ return MAXLWPS; }
281 <CSTATE>max-lwps	{ return MAXLWPS; }
282 
283 <TSTATE>max-processes	{ return MAXPROCS; }
284 <CSTATE>max-processes	{ return MAXPROCS; }
285 
286 <TSTATE>max-shm-memory	{ return MAXSHMMEM; }
287 <CSTATE>max-shm-memory	{ return MAXSHMMEM; }
288 
289 <TSTATE>max-shm-ids	{ return MAXSHMIDS; }
290 <CSTATE>max-shm-ids	{ return MAXSHMIDS; }
291 
292 <TSTATE>max-msg-ids	{ return MAXMSGIDS; }
293 <CSTATE>max-msg-ids	{ return MAXMSGIDS; }
294 
295 <TSTATE>max-sem-ids	{ return MAXSEMIDS; }
296 <CSTATE>max-sem-ids	{ return MAXSEMIDS; }
297 
298 <TSTATE>scheduling-class	{ return SCHED; }
299 <CSTATE>scheduling-class	{ return SCHED; }
300 
301 <TSTATE>hostid		{ return HOSTID; }
302 <CSTATE>hostid		{ return HOSTID; }
303 
304 <TSTATE>user	{ return USER; }
305 <CSTATE>user	{ return USER; }
306 
307 <TSTATE>auths	{ return AUTHS; }
308 <CSTATE>auths	{ return AUTHS; }
309 
310 <TSTATE>fs-allowed	{ return FS_ALLOWED; }
311 <CSTATE>fs-allowed	{ return FS_ALLOWED; }
312 
313 <TSTATE>default { return DEFAULT; }
314 <CSTATE>default { return DEFAULT; }
315 
316 <TSTATE>lower { return LOWER; }
317 <CSTATE>lower { return LOWER; }
318 
319 <TSTATE>upper { return UPPER; }
320 <CSTATE>upper { return UPPER; }
321 
322 <TSTATE>=	{ return EQUAL; }
323 <LSTATE>=	{ return EQUAL; }
324 <CSTATE>=	{ return EQUAL; }
325 
326 <TSTATE>"["	{
327 			BEGIN LSTATE;
328 			state = LSTATE;
329 			return OPEN_SQ_BRACKET;
330 		}
331 
332 <LSTATE>"]"	{
333 			BEGIN TSTATE;
334 			state = TSTATE;
335 			return CLOSE_SQ_BRACKET;
336 		}
337 
338 <TSTATE>"("	{
339 			BEGIN CSTATE;
340 			return OPEN_PAREN;
341 		}
342 
343 <LSTATE>"("	{
344 			BEGIN CSTATE;
345 			return OPEN_PAREN;
346 		}
347 
348 <CSTATE>")"	{
349 			BEGIN state;
350 			return CLOSE_PAREN;
351 		}
352 
353 <LSTATE>","	{ return COMMA; }
354 <CSTATE>","	{ return COMMA; }
355 
356 <TSTATE>[^ \t\n\";=\[\]\(\)]+	{
357 			yylval.strval = create_token(yytext);
358 			return TOKEN;
359 		}
360 
361 <LSTATE>[^ \t\n\",;=\[\]\(\)]+	{
362 			yylval.strval = create_token(yytext);
363 			return TOKEN;
364 		}
365 
366 <CSTATE>[^ \t\n\",;=\(\)]+	{
367 			yylval.strval = create_token(yytext);
368 			return TOKEN;
369 		}
370 
371 <TSTATE>\"[^\"\n]*[\"\n] {
372 			yylval.strval = create_token(yytext + 1);
373 			if (yylval.strval[yyleng - 2] == '"')
374 				yylval.strval[yyleng - 2] = 0;
375 			return TOKEN;
376 		}
377 
378 <LSTATE>\"[^\"\n]*[\"\n] {
379 			yylval.strval = create_token(yytext + 1);
380 			if (yylval.strval[yyleng - 2] == '"')
381 				yylval.strval[yyleng - 2] = 0;
382 			return TOKEN;
383 		}
384 
385 ";"		{
386 			BEGIN INITIAL;
387 			return (yytext[0]);
388 		}
389 
390 \n		{
391 			lex_lineno++;
392 			BEGIN INITIAL;
393 			return (yytext[0]);
394 		}
395 
396 [ \t]		;	/* Ignore whitespace */
397 
398 .		{
399 			return (yytext[0]);
400 		}
401 
402 %%
403 
404 /*
405  * Assert that there are no unclaimed tokens.  This function enforces the
406  * invariants mentioned at the top of this file.
407  */
408 void
409 assert_no_unclaimed_tokens(void)
410 {
411 	assert(num_unclaimed_tokens == 0);
412 	assert(unclaimed_tokens == NULL);
413 	assert(unclaimed_tokens_size == 0);
414 }
415 
416 /*
417  * Claim the specified unclaimed TOKEN.  YACC reduction rules that
418  * use TOKENs should invoke this function immediately before freeing the TOKENs
419  * or adding them to data structures that will be cleaned up when the YACC
420  * parser finishes or encounters errors.  Reduction rules should only claim the
421  * TOKENs that they use.
422  *
423  * This function returns its argument but does not free its memory.
424  */
425 char *
426 claim_token(char *token)
427 {
428 	unsigned int index;
429 
430 	/*
431 	 * Find the token in the list of unclaimed tokens.
432 	 */
433 	assert(num_unclaimed_tokens > 0);
434 	for (index = 0; index < num_unclaimed_tokens; index++) {
435 		if (unclaimed_tokens[index] == token)
436 			break;
437 	}
438 
439 	/*
440 	 * Abort if we didn't find the token.
441 	 */
442 	assert(index != num_unclaimed_tokens);
443 
444 	/*
445 	 * Replace the token with the last unclaimed token.
446 	 */
447 	num_unclaimed_tokens--;
448 	unclaimed_tokens[index] = unclaimed_tokens[num_unclaimed_tokens];
449 
450 	/*
451 	 * Delete the list of unclaimed tokens if it's empty.
452 	 */
453 	if (num_unclaimed_tokens == 0) {
454 		free(unclaimed_tokens);
455 		unclaimed_tokens = NULL;
456 		unclaimed_tokens_size = 0;
457 	}
458 
459 	return (token);
460 }
461 
462 /*
463  * Free all unclaimed TOKENs.  This should only be invoked when the YACC
464  * parser encounters errors.
465  */
466 static void
467 free_tokens(void)
468 {
469 	if (unclaimed_tokens != NULL) {
470 		while (num_unclaimed_tokens > 0)
471 			free(unclaimed_tokens[--num_unclaimed_tokens]);
472 		free(unclaimed_tokens);
473 		unclaimed_tokens = NULL;
474 		unclaimed_tokens_size = 0;
475 	}
476 	assert_no_unclaimed_tokens();
477 }
478 
479 /*
480  * Create a TOKEN from the specified string.  The TOKEN is merely a duplicate
481  * of the specified string.  TOKENs must be claimed by the YACC reduction rules
482  * that use them; see claim_token() above.
483  */
484 char *
485 create_token(char *s)
486 {
487 	char *result;
488 
489 	if ((result = strdup(s)) == NULL) {
490 		yyerror("Out of memory");
491 		exit(Z_ERR);
492 	}
493 
494 	/*
495 	 * Add the new TOKEN to the list of unclaimed TOKENs.  The list might
496 	 * have to be resized.
497 	 *
498 	 * Reduction rules should claim TOKENs via claim_token() (see above).
499 	 */
500 	if (num_unclaimed_tokens == unclaimed_tokens_size) {
501 		char **new_unclaimed_tokens;
502 
503 		unclaimed_tokens_size += UNCLAIMED_TOKENS_BUFFER_GROWTH;
504 		new_unclaimed_tokens = (char **)realloc(unclaimed_tokens,
505 		    unclaimed_tokens_size * sizeof (char *));
506 		if (new_unclaimed_tokens == NULL) {
507 			yyerror("Out of memory");
508 			free(result);
509 			exit(Z_ERR);
510 		}
511 		unclaimed_tokens = new_unclaimed_tokens;
512 	}
513 	unclaimed_tokens[num_unclaimed_tokens] = result;
514 	num_unclaimed_tokens++;
515 	return (result);
516 }
517 
518 void
519 yyerror(char *s)
520 {
521 	/*
522 	 * Ensure that we won't leak unclaimed tokens.
523 	 */
524 	free_tokens();
525 
526 	/* feof(yyin) is not an error; anything else is, so we set saw_error */
527 	if (yytext[0] == '\0') {
528 		if (!feof(yyin)) {
529 			saw_error = B_TRUE;
530 			(void) fprintf(stderr, gettext("%s, token expected\n"),
531 			    s);
532 		}
533 		return;
534 	}
535 
536 	saw_error = B_TRUE;
537 	if (cmd_file_mode)
538 		(void) fprintf(stderr, gettext("%s on line %d at '%s'\n"), s,
539 		    lex_lineno, (yytext[0] == '\n') ? "\\n" : yytext);
540 	else
541 		(void) fprintf(stderr, gettext("%s at '%s'\n"), s,
542 		    (yytext[0] == '\n') ? "\\n" : yytext);
543 	usage(B_FALSE, HELP_SUBCMDS);
544 }
545