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