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 } 534