%{ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. */ #include #include #include #include "zonecfg.h" #include "zonecfg_grammar.tab.h" /* * This constant defines the number of entries added to unclaimed_tokens[] * when it runs out of space. */ #define UNCLAIMED_TOKENS_BUFFER_GROWTH 4 /* * Invariants: * * unclaimed_tokens == NULL IFF unclaimed_tokens_size == 0 * unclaimed_tokens_size == 0 IFF num_unclaimed_tokens == 0 */ static char **unclaimed_tokens; /* TOKENs produced by Lex (see below) */ /* but not claimed by YACC reduction */ /* rules */ static unsigned int unclaimed_tokens_size; /* size of unclaimed_tokens */ static unsigned int num_unclaimed_tokens; /* number of unclaimed TOKENs */ int lex_lineno = 1; /* line number for error reporting */ static int state = INITIAL; extern boolean_t cmd_file_mode; extern boolean_t saw_error; extern void yyerror(char *s); static char *create_token(char *s); %} %a 7000 %p 5000 %e 2000 %n 1000 %{ /* * The three states below are for tokens, lists and complex property values. * Note that simple property values are a subset of tokens. */ %} %s TSTATE %s LSTATE %s CSTATE %% "#"[^\n]* { } add { BEGIN TSTATE; state = TSTATE; return ADD; } cancel { BEGIN TSTATE; state = TSTATE; return CANCEL; } commit { BEGIN TSTATE; state = TSTATE; return COMMIT; } create { BEGIN TSTATE; state = TSTATE; return CREATE; } delete { BEGIN TSTATE; state = TSTATE; return DELETE; } end { BEGIN TSTATE; state = TSTATE; return END; } exit { BEGIN TSTATE; state = TSTATE; return EXIT; } export { BEGIN TSTATE; state = TSTATE; return EXPORT; } "?"|help { BEGIN TSTATE; state = TSTATE; return HELP; } info { BEGIN TSTATE; state = TSTATE; return INFO; } remove { BEGIN TSTATE; state = TSTATE; return REMOVE; } revert { BEGIN TSTATE; state = TSTATE; return REVERT; } select { BEGIN TSTATE; state = TSTATE; return SELECT; } set { BEGIN TSTATE; state = TSTATE; return SET; } clear { BEGIN TSTATE; state = TSTATE; return CLEAR; } verify { BEGIN TSTATE; state = TSTATE; return VERIFY; } net { return NET; } fs { return FS; } device { return DEVICE; } rctl { return RCTL; } attr { return ATTR; } admin { return ADMIN; } zonename { return ZONENAME; } zonename { return ZONENAME; } dataset { return DATASET; } dedicated-cpu { return PSET; } capped-cpu { return PCAP; } capped-memory { return MCAP; } zonepath { return ZONEPATH; } zonepath { return ZONEPATH; } brand { return BRAND; } brand { return BRAND; } autoboot { return AUTOBOOT; } autoboot { return AUTOBOOT; } ip-type { return IPTYPE; } ip-type { return IPTYPE; } pool { return POOL; } pool { return POOL; } limitpriv { return LIMITPRIV; } limitpriv { return LIMITPRIV; } bootargs { return BOOTARGS; } bootargs { return BOOTARGS; } type { return TYPE; } type { return TYPE; } value { return VALUE; } value { return VALUE; } options { return OPTIONS; } options { return OPTIONS; } allowed-address { return ALLOWED_ADDRESS; } allowed-address { return ALLOWED_ADDRESS; } address { return ADDRESS; } address { return ADDRESS; } physical { return PHYSICAL; } physical { return PHYSICAL; } defrouter { return DEFROUTER; } defrouter { return DEFROUTER; } dir { return DIR; } dir { return DIR; } special { return SPECIAL; } special { return SPECIAL; } raw { return RAW; } raw { return RAW; } name { return NAME; } name { return NAME; } match { return MATCH; } match { return MATCH; } priv { return PRIV; } priv { return PRIV; } limit { return LIMIT; } limit { return LIMIT; } action { return ACTION; } action { return ACTION; } ncpus { return NCPUS; } ncpus { return NCPUS; } locked { return LOCKED; } locked { return LOCKED; } swap { return SWAP; } swap { return SWAP; } importance { return IMPORTANCE; } importance { return IMPORTANCE; } cpu-shares { return SHARES; } cpu-shares { return SHARES; } max-lwps { return MAXLWPS; } max-lwps { return MAXLWPS; } max-processes { return MAXPROCS; } max-processes { return MAXPROCS; } max-shm-memory { return MAXSHMMEM; } max-shm-memory { return MAXSHMMEM; } max-shm-ids { return MAXSHMIDS; } max-shm-ids { return MAXSHMIDS; } max-msg-ids { return MAXMSGIDS; } max-msg-ids { return MAXMSGIDS; } max-sem-ids { return MAXSEMIDS; } max-sem-ids { return MAXSEMIDS; } scheduling-class { return SCHED; } scheduling-class { return SCHED; } hostid { return HOSTID; } hostid { return HOSTID; } user { return USER; } user { return USER; } auths { return AUTHS; } auths { return AUTHS; } fs-allowed { return FS_ALLOWED; } fs-allowed { return FS_ALLOWED; } = { return EQUAL; } = { return EQUAL; } = { return EQUAL; } "[" { BEGIN LSTATE; state = LSTATE; return OPEN_SQ_BRACKET; } "]" { BEGIN TSTATE; state = TSTATE; return CLOSE_SQ_BRACKET; } "(" { BEGIN CSTATE; return OPEN_PAREN; } "(" { BEGIN CSTATE; return OPEN_PAREN; } ")" { BEGIN state; return CLOSE_PAREN; } "," { return COMMA; } "," { return COMMA; } [^ \t\n\";=\[\]\(\)]+ { yylval.strval = create_token(yytext); return TOKEN; } [^ \t\n\",;=\[\]\(\)]+ { yylval.strval = create_token(yytext); return TOKEN; } [^ \t\n\",;=\(\)]+ { yylval.strval = create_token(yytext); return TOKEN; } \"[^\"\n]*[\"\n] { yylval.strval = create_token(yytext + 1); if (yylval.strval[yyleng - 2] == '"') yylval.strval[yyleng - 2] = 0; return TOKEN; } \"[^\"\n]*[\"\n] { yylval.strval = create_token(yytext + 1); if (yylval.strval[yyleng - 2] == '"') yylval.strval[yyleng - 2] = 0; return TOKEN; } ";" { BEGIN INITIAL; return (yytext[0]); } \n { lex_lineno++; BEGIN INITIAL; return (yytext[0]); } [ \t] ; /* Ignore whitespace */ . { return (yytext[0]); } %% /* * Assert that there are no unclaimed tokens. This function enforces the * invariants mentioned at the top of this file. */ void assert_no_unclaimed_tokens(void) { assert(num_unclaimed_tokens == 0); assert(unclaimed_tokens == NULL); assert(unclaimed_tokens_size == 0); } /* * Claim the specified unclaimed TOKEN. YACC reduction rules that * use TOKENs should invoke this function immediately before freeing the TOKENs * or adding them to data structures that will be cleaned up when the YACC * parser finishes or encounters errors. Reduction rules should only claim the * TOKENs that they use. * * This function returns its argument but does not free its memory. */ char * claim_token(char *token) { unsigned int index; /* * Find the token in the list of unclaimed tokens. */ assert(num_unclaimed_tokens > 0); for (index = 0; index < num_unclaimed_tokens; index++) { if (unclaimed_tokens[index] == token) break; } /* * Abort if we didn't find the token. */ assert(index != num_unclaimed_tokens); /* * Replace the token with the last unclaimed token. */ num_unclaimed_tokens--; unclaimed_tokens[index] = unclaimed_tokens[num_unclaimed_tokens]; /* * Delete the list of unclaimed tokens if it's empty. */ if (num_unclaimed_tokens == 0) { free(unclaimed_tokens); unclaimed_tokens = NULL; unclaimed_tokens_size = 0; } return (token); } /* * Free all unclaimed TOKENs. This should only be invoked when the YACC * parser encounters errors. */ static void free_tokens(void) { if (unclaimed_tokens != NULL) { while (num_unclaimed_tokens > 0) free(unclaimed_tokens[--num_unclaimed_tokens]); free(unclaimed_tokens); unclaimed_tokens = NULL; unclaimed_tokens_size = 0; } assert_no_unclaimed_tokens(); } /* * Create a TOKEN from the specified string. The TOKEN is merely a duplicate * of the specified string. TOKENs must be claimed by the YACC reduction rules * that use them; see claim_token() above. */ char * create_token(char *s) { char *result; if ((result = strdup(s)) == NULL) { yyerror("Out of memory"); exit(Z_ERR); } /* * Add the new TOKEN to the list of unclaimed TOKENs. The list might * have to be resized. * * Reduction rules should claim TOKENs via claim_token() (see above). */ if (num_unclaimed_tokens == unclaimed_tokens_size) { char **new_unclaimed_tokens; unclaimed_tokens_size += UNCLAIMED_TOKENS_BUFFER_GROWTH; new_unclaimed_tokens = (char **)realloc(unclaimed_tokens, unclaimed_tokens_size * sizeof (char *)); if (new_unclaimed_tokens == NULL) { yyerror("Out of memory"); free(result); exit(Z_ERR); } unclaimed_tokens = new_unclaimed_tokens; } unclaimed_tokens[num_unclaimed_tokens] = result; num_unclaimed_tokens++; return (result); } void yyerror(char *s) { /* * Ensure that we won't leak unclaimed tokens. */ free_tokens(); /* feof(yyin) is not an error; anything else is, so we set saw_error */ if (yytext[0] == '\0') { if (!feof(yyin)) { saw_error = B_TRUE; (void) fprintf(stderr, gettext("%s, token expected\n"), s); } return; } saw_error = B_TRUE; if (cmd_file_mode) (void) fprintf(stderr, gettext("%s on line %d at '%s'\n"), s, lex_lineno, (yytext[0] == '\n') ? "\\n" : yytext); else (void) fprintf(stderr, gettext("%s at '%s'\n"), s, (yytext[0] == '\n') ? "\\n" : yytext); usage(B_FALSE, HELP_SUBCMDS); }