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