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