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 }