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 }