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