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>zonename { return ZONENAME; }
187 <CSTATE>zonename { return ZONENAME; }
188
189 <TSTATE>dataset { return DATASET; }
190
191 <TSTATE>dedicated-cpu { return PSET; }
192
193 <TSTATE>capped-cpu { return PCAP; }
194
195 <TSTATE>capped-memory { return MCAP; }
196
197 <TSTATE>zonepath { return ZONEPATH; }
198 <CSTATE>zonepath { return ZONEPATH; }
199
200 <TSTATE>brand { return BRAND; }
201 <CSTATE>brand { return BRAND; }
202
203 <TSTATE>autoboot { return AUTOBOOT; }
204 <CSTATE>autoboot { return AUTOBOOT; }
205
206 <TSTATE>ip-type { return IPTYPE; }
207 <CSTATE>ip-type { return IPTYPE; }
208
209 <TSTATE>pool { return POOL; }
210 <CSTATE>pool { return POOL; }
211
212 <TSTATE>limitpriv { return LIMITPRIV; }
213 <CSTATE>limitpriv { return LIMITPRIV; }
214
215 <TSTATE>bootargs { return BOOTARGS; }
216 <CSTATE>bootargs { return BOOTARGS; }
217
218 <TSTATE>type { return TYPE; }
219 <CSTATE>type { return TYPE; }
220
221 <TSTATE>value { return VALUE; }
222 <CSTATE>value { return VALUE; }
223
224 <TSTATE>options { return OPTIONS; }
225 <CSTATE>options { return OPTIONS; }
226
227 <TSTATE>allowed-address { return ALLOWED_ADDRESS; }
228 <CSTATE>allowed-address { return ALLOWED_ADDRESS; }
229
230 <TSTATE>address { return ADDRESS; }
231 <CSTATE>address { return ADDRESS; }
232
233 <TSTATE>physical { return PHYSICAL; }
234 <CSTATE>physical { return PHYSICAL; }
235
236 <TSTATE>defrouter { return DEFROUTER; }
237 <CSTATE>defrouter { return DEFROUTER; }
238
239 <TSTATE>dir { return DIR; }
240 <CSTATE>dir { return DIR; }
241
242 <TSTATE>special { return SPECIAL; }
243 <CSTATE>special { return SPECIAL; }
244
245 <TSTATE>raw { return RAW; }
246 <CSTATE>raw { return RAW; }
247
248 <TSTATE>name { return NAME; }
249 <CSTATE>name { return NAME; }
250
251 <TSTATE>match { return MATCH; }
252 <CSTATE>match { return MATCH; }
253
254 <TSTATE>priv { return PRIV; }
255 <CSTATE>priv { return PRIV; }
256
257 <TSTATE>limit { return LIMIT; }
258 <CSTATE>limit { return LIMIT; }
259
260 <TSTATE>action { return ACTION; }
261 <CSTATE>action { return ACTION; }
262
263 <TSTATE>ncpus { return NCPUS; }
264 <CSTATE>ncpus { return NCPUS; }
265
266 <TSTATE>locked { return LOCKED; }
267 <CSTATE>locked { return LOCKED; }
268
269 <TSTATE>swap { return SWAP; }
270 <CSTATE>swap { return SWAP; }
271
272 <TSTATE>importance { return IMPORTANCE; }
273 <CSTATE>importance { return IMPORTANCE; }
274
275 <TSTATE>cpu-shares { return SHARES; }
276 <CSTATE>cpu-shares { return SHARES; }
277
278 <TSTATE>max-lwps { return MAXLWPS; }
279 <CSTATE>max-lwps { return MAXLWPS; }
280
281 <TSTATE>max-processes { return MAXPROCS; }
282 <CSTATE>max-processes { return MAXPROCS; }
283
284 <TSTATE>max-shm-memory { return MAXSHMMEM; }
285 <CSTATE>max-shm-memory { return MAXSHMMEM; }
286
287 <TSTATE>max-shm-ids { return MAXSHMIDS; }
288 <CSTATE>max-shm-ids { return MAXSHMIDS; }
289
290 <TSTATE>max-msg-ids { return MAXMSGIDS; }
291 <CSTATE>max-msg-ids { return MAXMSGIDS; }
292
293 <TSTATE>max-sem-ids { return MAXSEMIDS; }
294 <CSTATE>max-sem-ids { return MAXSEMIDS; }
295
296 <TSTATE>scheduling-class { return SCHED; }
297 <CSTATE>scheduling-class { return SCHED; }
298
299 <TSTATE>hostid { return HOSTID; }
300 <CSTATE>hostid { return HOSTID; }
301
302 <TSTATE>user { return USER; }
303 <CSTATE>user { return USER; }
304
305 <TSTATE>auths { return AUTHS; }
306 <CSTATE>auths { return AUTHS; }
307
308 <TSTATE>fs-allowed { return FS_ALLOWED; }
309 <CSTATE>fs-allowed { return FS_ALLOWED; }
310
311 <TSTATE>= { return EQUAL; }
312 <LSTATE>= { return EQUAL; }
313 <CSTATE>= { return EQUAL; }
314
315 <TSTATE>"[" {
316 BEGIN LSTATE;
317 state = LSTATE;
318 return OPEN_SQ_BRACKET;
319 }
320
321 <LSTATE>"]" {
322 BEGIN TSTATE;
323 state = TSTATE;
324 return CLOSE_SQ_BRACKET;
325 }
326
327 <TSTATE>"(" {
328 BEGIN CSTATE;
329 return OPEN_PAREN;
330 }
331
332 <LSTATE>"(" {
333 BEGIN CSTATE;
334 return OPEN_PAREN;
335 }
336
337 <CSTATE>")" {
338 BEGIN state;
339 return CLOSE_PAREN;
340 }
341
342 <LSTATE>"," { return COMMA; }
343 <CSTATE>"," { return COMMA; }
344
345 <TSTATE>[^ \t\n\";=\[\]\(\)]+ {
346 yylval.strval = create_token(yytext);
347 return TOKEN;
348 }
349
350 <LSTATE>[^ \t\n\",;=\[\]\(\)]+ {
351 yylval.strval = create_token(yytext);
352 return TOKEN;
353 }
354
355 <CSTATE>[^ \t\n\",;=\(\)]+ {
356 yylval.strval = create_token(yytext);
357 return TOKEN;
358 }
359
360 <TSTATE>\"[^\"\n]*[\"\n] {
361 yylval.strval = create_token(yytext + 1);
362 if (yylval.strval[yyleng - 2] == '"')
363 yylval.strval[yyleng - 2] = 0;
364 return TOKEN;
365 }
366
367 <LSTATE>\"[^\"\n]*[\"\n] {
368 yylval.strval = create_token(yytext + 1);
369 if (yylval.strval[yyleng - 2] == '"')
370 yylval.strval[yyleng - 2] = 0;
371 return TOKEN;
372 }
373
374 ";" {
375 BEGIN INITIAL;
376 return (yytext[0]);
377 }
378
379 \n {
380 lex_lineno++;
381 BEGIN INITIAL;
382 return (yytext[0]);
383 }
384
385 [ \t] ; /* Ignore whitespace */
386
387 . {
388 return (yytext[0]);
389 }
390
391 %%
392
393 /*
394 * Assert that there are no unclaimed tokens. This function enforces the
395 * invariants mentioned at the top of this file.
396 */
397 void
398 assert_no_unclaimed_tokens(void)
399 {
400 assert(num_unclaimed_tokens == 0);
401 assert(unclaimed_tokens == NULL);
402 assert(unclaimed_tokens_size == 0);
403 }
404
405 /*
406 * Claim the specified unclaimed TOKEN. YACC reduction rules that
407 * use TOKENs should invoke this function immediately before freeing the TOKENs
408 * or adding them to data structures that will be cleaned up when the YACC
409 * parser finishes or encounters errors. Reduction rules should only claim the
410 * TOKENs that they use.
411 *
412 * This function returns its argument but does not free its memory.
413 */
414 char *
415 claim_token(char *token)
416 {
417 unsigned int index;
418
419 /*
420 * Find the token in the list of unclaimed tokens.
421 */
422 assert(num_unclaimed_tokens > 0);
423 for (index = 0; index < num_unclaimed_tokens; index++) {
424 if (unclaimed_tokens[index] == token)
425 break;
426 }
427
428 /*
429 * Abort if we didn't find the token.
430 */
431 assert(index != num_unclaimed_tokens);
432
433 /*
434 * Replace the token with the last unclaimed token.
435 */
436 num_unclaimed_tokens--;
437 unclaimed_tokens[index] = unclaimed_tokens[num_unclaimed_tokens];
438
439 /*
440 * Delete the list of unclaimed tokens if it's empty.
441 */
442 if (num_unclaimed_tokens == 0) {
443 free(unclaimed_tokens);
444 unclaimed_tokens = NULL;
445 unclaimed_tokens_size = 0;
446 }
447
448 return (token);
449 }
450
451 /*
452 * Free all unclaimed TOKENs. This should only be invoked when the YACC
453 * parser encounters errors.
454 */
455 static void
456 free_tokens(void)
457 {
458 if (unclaimed_tokens != NULL) {
459 while (num_unclaimed_tokens > 0)
460 free(unclaimed_tokens[--num_unclaimed_tokens]);
461 free(unclaimed_tokens);
462 unclaimed_tokens = NULL;
463 unclaimed_tokens_size = 0;
464 }
465 assert_no_unclaimed_tokens();
466 }
467
468 /*
469 * Create a TOKEN from the specified string. The TOKEN is merely a duplicate
470 * of the specified string. TOKENs must be claimed by the YACC reduction rules
471 * that use them; see claim_token() above.
472 */
473 char *
474 create_token(char *s)
475 {
476 char *result;
477
478 if ((result = strdup(s)) == NULL) {
479 yyerror("Out of memory");
480 exit(Z_ERR);
481 }
482
483 /*
484 * Add the new TOKEN to the list of unclaimed TOKENs. The list might
485 * have to be resized.
486 *
487 * Reduction rules should claim TOKENs via claim_token() (see above).
488 */
489 if (num_unclaimed_tokens == unclaimed_tokens_size) {
490 char **new_unclaimed_tokens;
491
492 unclaimed_tokens_size += UNCLAIMED_TOKENS_BUFFER_GROWTH;
493 new_unclaimed_tokens = (char **)realloc(unclaimed_tokens,
494 unclaimed_tokens_size * sizeof (char *));
495 if (new_unclaimed_tokens == NULL) {
496 yyerror("Out of memory");
497 free(result);
498 exit(Z_ERR);
499 }
500 unclaimed_tokens = new_unclaimed_tokens;
501 }
502 unclaimed_tokens[num_unclaimed_tokens] = result;
503 num_unclaimed_tokens++;
504 return (result);
505 }
506
507 void
508 yyerror(char *s)
509 {
510 /*
511 * Ensure that we won't leak unclaimed tokens.
512 */
513 free_tokens();
514
515 /* feof(yyin) is not an error; anything else is, so we set saw_error */
516 if (yytext[0] == '\0') {
517 if (!feof(yyin)) {
518 saw_error = B_TRUE;
519 (void) fprintf(stderr, gettext("%s, token expected\n"),
520 s);
521 }
522 return;
523 }
524
525 saw_error = B_TRUE;
526 if (cmd_file_mode)
527 (void) fprintf(stderr, gettext("%s on line %d at '%s'\n"), s,
528 lex_lineno, (yytext[0] == '\n') ? "\\n" : yytext);
529 else
530 (void) fprintf(stderr, gettext("%s at '%s'\n"), s,
531 (yytext[0] == '\n') ? "\\n" : yytext);
532 usage(B_FALSE, HELP_SUBCMDS);
533 }