usr/src/cmd/zonecfg/zonecfg_grammar.y
author dh155122
Fri, 19 Jan 2007 16:59:38 -0800
changeset 3448 aaf16568054b
parent 3247 e05001c14ea2
child 3792 57ba782523b7
permissions -rw-r--r--
PSARC 2006/366 IP Instances 6289221 RFE: Need virtualized ip-stack for each local zone 6512601 panic in ipsec_in_tag - allocation failure 6514637 error message from dhcpagent: add_pkt_opt: option type 60 is missing required value 6364643 RFE: allow persistent setting of interface flags per zone 6307539 RFE: Invalid network address causes zone boot failure 5041214 Allow IPMP configuration with zones 5005887 RFE: zoneadmd should support plumbing an interface via DHCP 4991139 RFE: zones should provide a mechanism to configure a defaultrouter for a zone 6218378 zoneadmd doesn't set the netmask for non-loopback addresses hosted on lo0 4963280 zones: need to virtualize the IPv6 default address selection mechanism 4963285 zones: need support of stateless address autoconfiguration for IPv6 5048068 zones don't boot if one of its interfaces has failed 5057154 RFE: ability to change interface status from within a zone 4963287 zones should support the plumbing of the first (and only) logical interface 4978517 TCP privileged port space should be partitioned per zone 5023347 zones don't work well with network routes other than default 4963372 investigate whether global zone can act as a router for local zones 6378364 RFE: Allow each zone to have its own virtual IPFilter

%{
/*
 * 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 2007 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"

#include <stdio.h>

#include "zonecfg.h"

static cmd_t *cmd = NULL;		/* Command being processed */
static complex_property_ptr_t complex = NULL;
static list_property_ptr_t new_list = NULL, tmp_list, last,
    list[MAX_EQ_PROP_PAIRS];
static property_value_t property[MAX_EQ_PROP_PAIRS];

extern bool newline_terminated;
extern int num_prop_vals;		/* # of property values */

/* yacc externals */
extern int yydebug;
extern void yyerror(char *s);

%}

%union {
	int ival;
	char *strval;
	cmd_t *cmd;
	complex_property_ptr_t complex;
	list_property_ptr_t list;
}

%start commands

%token HELP CREATE EXPORT ADD DELETE REMOVE SELECT SET INFO CANCEL END VERIFY
%token COMMIT REVERT EXIT SEMICOLON TOKEN ZONENAME ZONEPATH AUTOBOOT POOL NET
%token FS IPD ATTR DEVICE RCTL SPECIAL RAW DIR OPTIONS TYPE ADDRESS PHYSICAL
%token IPTYPE
%token NAME MATCH PRIV LIMIT ACTION VALUE EQUAL OPEN_SQ_BRACKET CLOSE_SQ_BRACKET
%token OPEN_PAREN CLOSE_PAREN COMMA DATASET LIMITPRIV BOOTARGS BRAND PSET
%token MCAP NCPUS IMPORTANCE SHARES MAXLWPS MAXSHMMEM MAXSHMIDS MAXMSGIDS
%token MAXSEMIDS LOCKED SWAP SCHED CLEAR

%type <strval> TOKEN EQUAL OPEN_SQ_BRACKET CLOSE_SQ_BRACKET
    property_value OPEN_PAREN CLOSE_PAREN COMMA simple_prop_val
%type <complex> complex_piece complex_prop_val
%type <ival> resource_type NET FS IPD DEVICE RCTL ATTR DATASET PSET MCAP
%type <ival> property_name SPECIAL RAW DIR OPTIONS TYPE ADDRESS PHYSICAL NAME
    MATCH ZONENAME ZONEPATH AUTOBOOT POOL LIMITPRIV BOOTARGS VALUE PRIV LIMIT
    ACTION BRAND SCHED IPTYPE
%type <cmd> command
%type <cmd> add_command ADD
%type <cmd> cancel_command CANCEL
%type <cmd> commit_command COMMIT
%type <cmd> create_command CREATE
%type <cmd> delete_command DELETE
%type <cmd> end_command END
%type <cmd> exit_command EXIT
%type <cmd> export_command EXPORT
%type <cmd> help_command HELP
%type <cmd> info_command INFO
%type <cmd> remove_command REMOVE
%type <cmd> revert_command REVERT
%type <cmd> select_command SELECT
%type <cmd> set_command SET
%type <cmd> clear_command CLEAR
%type <cmd> verify_command VERIFY
%type <cmd> terminator

%%

commands: command terminator
	{
		if ($1 != NULL) {
			if ($1->cmd_handler != NULL)
				$1->cmd_handler($1);
			free_cmd($1);
			bzero(list, sizeof (list_property_t));
			num_prop_vals = 0;
		}
		return (0);
	}
	| command error terminator
	{
		if ($1 != NULL) {
			free_cmd($1);
			bzero(list, sizeof (list_property_t));
			num_prop_vals = 0;
		}
		if (YYRECOVERING())
			YYABORT;
		yyclearin;
		yyerrok;
	}
	| error terminator
	{
		if (YYRECOVERING())
			YYABORT;
		yyclearin;
		yyerrok;
	}
	| terminator
	{
		return (0);
	}

command: add_command
	| cancel_command
	| clear_command
	| create_command
	| commit_command
	| delete_command
	| end_command
	| exit_command
	| export_command
	| help_command
	| info_command
	| remove_command
	| revert_command
	| select_command
	| set_command
	| verify_command

terminator:	'\n'	{ newline_terminated = TRUE; }
	|	';'	{ newline_terminated = FALSE; }

add_command: ADD
	{
		short_usage(CMD_ADD);
		(void) fputs("\n", stderr);
		usage(FALSE, HELP_RES_PROPS);
		YYERROR;
	}
	| ADD TOKEN
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &add_func;
		$$->cmd_argc = 1;
		$$->cmd_argv[0] = $2;
		$$->cmd_argv[1] = NULL;
	}
	| ADD resource_type
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &add_func;
		$$->cmd_argc = 0;
		$$->cmd_res_type = $2;
		$$->cmd_prop_nv_pairs = 0;
	}
	| ADD property_name property_value
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &add_func;
		$$->cmd_argc = 0;
		$$->cmd_prop_nv_pairs = 1;
		$$->cmd_prop_name[0] = $2;
		$$->cmd_property_ptr[0] = &property[0];
	}

cancel_command: CANCEL
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &cancel_func;
		$$->cmd_argc = 0;
		$$->cmd_argv[0] = NULL;
	}
	| CANCEL TOKEN
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &cancel_func;
		$$->cmd_argc = 1;
		$$->cmd_argv[0] = $2;
		$$->cmd_argv[1] = NULL;
	}

create_command: CREATE
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &create_func;
		$$->cmd_argc = 0;
		$$->cmd_argv[0] = NULL;
	}
	| CREATE TOKEN
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &create_func;
		$$->cmd_argc = 1;
		$$->cmd_argv[0] = $2;
		$$->cmd_argv[1] = NULL;
	}
	| CREATE TOKEN TOKEN
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &create_func;
		$$->cmd_argc = 2;
		$$->cmd_argv[0] = $2;
		$$->cmd_argv[1] = $3;
		$$->cmd_argv[2] = NULL;
	}
	| CREATE TOKEN TOKEN TOKEN
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &create_func;
		$$->cmd_argc = 3;
		$$->cmd_argv[0] = $2;
		$$->cmd_argv[1] = $3;
		$$->cmd_argv[2] = $4;
		$$->cmd_argv[3] = NULL;
	}

commit_command: COMMIT
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &commit_func;
		$$->cmd_argc = 0;
		$$->cmd_argv[0] = NULL;
	}
	| COMMIT TOKEN
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &commit_func;
		$$->cmd_argc = 1;
		$$->cmd_argv[0] = $2;
		$$->cmd_argv[1] = NULL;
	}

delete_command: DELETE
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &delete_func;
		$$->cmd_argc = 0;
		$$->cmd_argv[0] = NULL;
	}
	|	DELETE TOKEN
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &delete_func;
		$$->cmd_argc = 1;
		$$->cmd_argv[0] = $2;
		$$->cmd_argv[1] = NULL;
	}

end_command: END
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &end_func;
		$$->cmd_argc = 0;
		$$->cmd_argv[0] = NULL;
	}
	| END TOKEN
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &end_func;
		$$->cmd_argc = 1;
		$$->cmd_argv[0] = $2;
		$$->cmd_argv[1] = NULL;
	}

exit_command: EXIT
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &exit_func;
		$$->cmd_argc = 0;
		$$->cmd_argv[0] = NULL;
	}
	| EXIT TOKEN
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &exit_func;
		$$->cmd_argc = 1;
		$$->cmd_argv[0] = $2;
		$$->cmd_argv[1] = NULL;
	}

export_command: EXPORT
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &export_func;
		$$->cmd_argc = 0;
		$$->cmd_argv[0] = NULL;
	}
	| EXPORT TOKEN
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &export_func;
		$$->cmd_argc = 1;
		$$->cmd_argv[0] = $2;
		$$->cmd_argv[1] = NULL;
	}
	| EXPORT TOKEN TOKEN
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &export_func;
		$$->cmd_argc = 2;
		$$->cmd_argv[0] = $2;
		$$->cmd_argv[1] = $3;
		$$->cmd_argv[2] = NULL;
	}

help_command:	HELP
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &help_func;
		$$->cmd_argc = 0;
		$$->cmd_argv[0] = NULL;
	}
	|	HELP TOKEN
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &help_func;
		$$->cmd_argc = 1;
		$$->cmd_argv[0] = $2;
		$$->cmd_argv[1] = NULL;
	}

info_command:	INFO
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &info_func;
		$$->cmd_res_type = RT_UNKNOWN;
		$$->cmd_prop_nv_pairs = 0;
	}
	|	INFO TOKEN
	{
		short_usage(CMD_INFO);
		(void) fputs("\n", stderr);
		usage(FALSE, HELP_RES_PROPS);
		free($2);
		YYERROR;
	}
	|	INFO resource_type
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &info_func;
		$$->cmd_res_type = $2;
		$$->cmd_prop_nv_pairs = 0;
	}
	|	INFO ZONENAME
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &info_func;
		$$->cmd_res_type = RT_ZONENAME;
		$$->cmd_prop_nv_pairs = 0;
	}
	|	INFO ZONEPATH
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &info_func;
		$$->cmd_res_type = RT_ZONEPATH;
		$$->cmd_prop_nv_pairs = 0;
	}
	|	INFO BRAND
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &info_func;
		$$->cmd_res_type = RT_BRAND;
		$$->cmd_prop_nv_pairs = 0;
	}
	|	INFO AUTOBOOT
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &info_func;
		$$->cmd_res_type = RT_AUTOBOOT;
		$$->cmd_prop_nv_pairs = 0;
	}
	|	INFO IPTYPE
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &info_func;
		$$->cmd_res_type = RT_IPTYPE;
		$$->cmd_prop_nv_pairs = 0;
	}
	|	INFO POOL
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &info_func;
		$$->cmd_res_type = RT_POOL;
		$$->cmd_prop_nv_pairs = 0;
	}
	|	INFO LIMITPRIV
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &info_func;
		$$->cmd_res_type = RT_LIMITPRIV;
		$$->cmd_prop_nv_pairs = 0;
	}
	|	INFO BOOTARGS
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &info_func;
		$$->cmd_res_type = RT_BOOTARGS;
		$$->cmd_prop_nv_pairs = 0;
	}
	|	INFO SCHED
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &info_func;
		$$->cmd_res_type = RT_SCHED;
		$$->cmd_prop_nv_pairs = 0;
	}
	|	INFO SHARES
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &info_func;
		$$->cmd_res_type = RT_SHARES;
		$$->cmd_prop_nv_pairs = 0;
	}
	|	INFO MAXLWPS
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &info_func;
		$$->cmd_res_type = RT_MAXLWPS;
		$$->cmd_prop_nv_pairs = 0;
	}
	|	INFO MAXSHMMEM
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &info_func;
		$$->cmd_res_type = RT_MAXSHMMEM;
		$$->cmd_prop_nv_pairs = 0;
	}
	|	INFO MAXSHMIDS
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &info_func;
		$$->cmd_res_type = RT_MAXSHMIDS;
		$$->cmd_prop_nv_pairs = 0;
	}
	|	INFO MAXMSGIDS
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &info_func;
		$$->cmd_res_type = RT_MAXMSGIDS;
		$$->cmd_prop_nv_pairs = 0;
	}
	|	INFO MAXSEMIDS
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &info_func;
		$$->cmd_res_type = RT_MAXSEMIDS;
		$$->cmd_prop_nv_pairs = 0;
	}
	|	INFO resource_type property_name EQUAL property_value
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &info_func;
		$$->cmd_res_type = $2;
		$$->cmd_prop_nv_pairs = 1;
		$$->cmd_prop_name[0] = $3;
		$$->cmd_property_ptr[0] = &property[0];
	}
	|	INFO resource_type property_name EQUAL property_value property_name EQUAL property_value
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &info_func;
		$$->cmd_res_type = $2;
		$$->cmd_prop_nv_pairs = 2;
		$$->cmd_prop_name[0] = $3;
		$$->cmd_property_ptr[0] = &property[0];
		$$->cmd_prop_name[1] = $6;
		$$->cmd_property_ptr[1] = &property[1];
	}
	|	INFO resource_type property_name EQUAL property_value property_name EQUAL property_value property_name EQUAL property_value
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &info_func;
		$$->cmd_res_type = $2;
		$$->cmd_prop_nv_pairs = 3;
		$$->cmd_prop_name[0] = $3;
		$$->cmd_property_ptr[0] = &property[0];
		$$->cmd_prop_name[1] = $6;
		$$->cmd_property_ptr[1] = &property[1];
		$$->cmd_prop_name[2] = $9;
		$$->cmd_property_ptr[2] = &property[2];
	}

remove_command: REMOVE
	{
		short_usage(CMD_REMOVE);
		(void) fputs("\n", stderr);
		usage(FALSE, HELP_RES_PROPS);
		YYERROR;
	}
	| REMOVE TOKEN
	{
		short_usage(CMD_REMOVE);
		(void) fputs("\n", stderr);
		usage(FALSE, HELP_RES_PROPS);
		YYERROR;
	}
	| REMOVE resource_type
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &remove_func;
		$$->cmd_res_type = $2;
	}
	| REMOVE TOKEN resource_type
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &remove_func;
		$$->cmd_res_type = $3;
		$$->cmd_argc = 1;
		$$->cmd_argv[0] = $2;
		$$->cmd_argv[1] = NULL;
	}
	| REMOVE property_name property_value
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &remove_func;
		$$->cmd_prop_nv_pairs = 1;
		$$->cmd_prop_name[0] = $2;
		$$->cmd_property_ptr[0] = &property[0];
	}
	| REMOVE resource_type property_name EQUAL property_value
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &remove_func;
		$$->cmd_res_type = $2;
		$$->cmd_prop_nv_pairs = 1;
		$$->cmd_prop_name[0] = $3;
		$$->cmd_property_ptr[0] = &property[0];
	}
	| REMOVE resource_type property_name EQUAL property_value property_name EQUAL property_value
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &remove_func;
		$$->cmd_res_type = $2;
		$$->cmd_prop_nv_pairs = 2;
		$$->cmd_prop_name[0] = $3;
		$$->cmd_property_ptr[0] = &property[0];
		$$->cmd_prop_name[1] = $6;
		$$->cmd_property_ptr[1] = &property[1];
	}
	| REMOVE resource_type property_name EQUAL property_value property_name EQUAL property_value property_name EQUAL property_value
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &remove_func;
		$$->cmd_res_type = $2;
		$$->cmd_prop_nv_pairs = 3;
		$$->cmd_prop_name[0] = $3;
		$$->cmd_property_ptr[0] = &property[0];
		$$->cmd_prop_name[1] = $6;
		$$->cmd_property_ptr[1] = &property[1];
		$$->cmd_prop_name[2] = $9;
		$$->cmd_property_ptr[2] = &property[2];
	}

revert_command: REVERT
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &revert_func;
		$$->cmd_argc = 0;
		$$->cmd_argv[0] = NULL;
	}
	| REVERT TOKEN
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &revert_func;
		$$->cmd_argc = 1;
		$$->cmd_argv[0] = $2;
		$$->cmd_argv[1] = NULL;
	}

select_command: SELECT
	{
		short_usage(CMD_SELECT);
		(void) fputs("\n", stderr);
		usage(FALSE, HELP_RES_PROPS);
		YYERROR;
	}
	| SELECT PSET
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &select_func;
		$$->cmd_res_type = RT_DCPU;
	}
	| SELECT MCAP
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &select_func;
		$$->cmd_res_type = RT_MCAP;
	}
	| SELECT resource_type
	{
		short_usage(CMD_SELECT);
		YYERROR;
	}
	| SELECT resource_type property_name EQUAL property_value
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &select_func;
		$$->cmd_res_type = $2;
		$$->cmd_prop_nv_pairs = 1;
		$$->cmd_prop_name[0] = $3;
		$$->cmd_property_ptr[0] = &property[0];
	}
	| SELECT resource_type property_name EQUAL property_value property_name EQUAL property_value
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &select_func;
		$$->cmd_res_type = $2;
		$$->cmd_prop_nv_pairs = 2;
		$$->cmd_prop_name[0] = $3;
		$$->cmd_property_ptr[0] = &property[0];
		$$->cmd_prop_name[1] = $6;
		$$->cmd_property_ptr[1] = &property[1];
	}
	| SELECT resource_type property_name EQUAL property_value property_name EQUAL property_value property_name EQUAL property_value
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &select_func;
		$$->cmd_res_type = $2;
		$$->cmd_prop_nv_pairs = 3;
		$$->cmd_prop_name[0] = $3;
		$$->cmd_property_ptr[0] = &property[0];
		$$->cmd_prop_name[1] = $6;
		$$->cmd_property_ptr[1] = &property[1];
		$$->cmd_prop_name[2] = $9;
		$$->cmd_property_ptr[2] = &property[2];
	}

set_command: SET
	{
		short_usage(CMD_SET);
		(void) fputs("\n", stderr);
		usage(FALSE, HELP_PROPS);
		YYERROR;
	}
	| SET property_name EQUAL OPEN_SQ_BRACKET CLOSE_SQ_BRACKET
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &set_func;
		$$->cmd_prop_nv_pairs = 0;
		$$->cmd_prop_name[0] = $2;
		property[0].pv_type = PROP_VAL_LIST;
		property[0].pv_list = NULL;
		$$->cmd_property_ptr[0] = &property[0];
	}
	| SET property_name EQUAL property_value
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &set_func;
		$$->cmd_prop_nv_pairs = 1;
		$$->cmd_prop_name[0] = $2;
		$$->cmd_property_ptr[0] = &property[0];
	}
	| SET TOKEN ZONEPATH EQUAL property_value
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_argc = 1;
		$$->cmd_argv[0] = $2;
		$$->cmd_argv[1] = NULL;
		$$->cmd_handler = &set_func;
		$$->cmd_prop_nv_pairs = 1;
		$$->cmd_prop_name[0] = PT_ZONEPATH;
		$$->cmd_property_ptr[0] = &property[0];
	}

clear_command: CLEAR
	{
		short_usage(CMD_CLEAR);
		(void) fputs("\n", stderr);
		usage(FALSE, HELP_PROPS);
		YYERROR;
	}
	| CLEAR property_name
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &clear_func;
		$$->cmd_res_type = $2;
	}

verify_command: VERIFY
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &verify_func;
		$$->cmd_argc = 0;
		$$->cmd_argv[0] = NULL;
	}
	| VERIFY TOKEN
	{
		if (($$ = alloc_cmd()) == NULL)
			YYERROR;
		cmd = $$;
		$$->cmd_handler = &verify_func;
		$$->cmd_argc = 1;
		$$->cmd_argv[0] = $2;
		$$->cmd_argv[1] = NULL;
	}

resource_type: NET	{ $$ = RT_NET; }
	| FS		{ $$ = RT_FS; }
	| IPD		{ $$ = RT_IPD; }
	| DEVICE	{ $$ = RT_DEVICE; }
	| RCTL		{ $$ = RT_RCTL; }
	| ATTR		{ $$ = RT_ATTR; }
	| DATASET	{ $$ = RT_DATASET; }
	| PSET		{ $$ = RT_DCPU; }
	| MCAP		{ $$ = RT_MCAP; }

property_name: SPECIAL	{ $$ = PT_SPECIAL; }
	| RAW		{ $$ = PT_RAW; }
	| DIR		{ $$ = PT_DIR; }
	| TYPE		{ $$ = PT_TYPE; }
	| OPTIONS	{ $$ = PT_OPTIONS; }
	| ZONENAME	{ $$ = PT_ZONENAME; }
	| ZONEPATH	{ $$ = PT_ZONEPATH; }
	| AUTOBOOT	{ $$ = PT_AUTOBOOT; }
	| IPTYPE	{ $$ = PT_IPTYPE; }
	| POOL		{ $$ = PT_POOL; }
	| LIMITPRIV	{ $$ = PT_LIMITPRIV; }
	| BOOTARGS	{ $$ = PT_BOOTARGS; }
	| ADDRESS	{ $$ = PT_ADDRESS; }
	| PHYSICAL	{ $$ = PT_PHYSICAL; }
	| NAME		{ $$ = PT_NAME; }
	| VALUE		{ $$ = PT_VALUE; }
	| MATCH		{ $$ = PT_MATCH; }
	| PRIV		{ $$ = PT_PRIV; }
	| LIMIT		{ $$ = PT_LIMIT; }
	| ACTION	{ $$ = PT_ACTION; }
	| BRAND		{ $$ = PT_BRAND; }
	| NCPUS		{ $$ = PT_NCPUS; }
	| LOCKED	{ $$ = PT_LOCKED; }
	| SWAP		{ $$ = PT_SWAP; }
	| IMPORTANCE	{ $$ = PT_IMPORTANCE; }
	| SHARES	{ $$ = PT_SHARES; }
	| MAXLWPS	{ $$ = PT_MAXLWPS; }
	| MAXSHMMEM	{ $$ = PT_MAXSHMMEM; }
	| MAXSHMIDS	{ $$ = PT_MAXSHMIDS; }
	| MAXMSGIDS	{ $$ = PT_MAXMSGIDS; }
	| MAXSEMIDS	{ $$ = PT_MAXSEMIDS; }
	| SCHED		{ $$ = PT_SCHED; }

/*
 * The grammar builds data structures from the bottom up.  Thus various
 * strings are lexed into TOKENs or commands or resource or property values.
 * Below is where the resource and property values are built up into more
 * complex data structures.
 *
 * There are three kinds of properties: simple (single valued), complex
 * (one or more name=value pairs) and list (concatenation of one or more
 * simple or complex properties).
 *
 * So the property structure has a type which is one of these, and the
 * corresponding _simple, _complex or _list is set to the corresponding
 * lower-level data structure.
 */

property_value: simple_prop_val
	{
		property[num_prop_vals].pv_type = PROP_VAL_SIMPLE;
		property[num_prop_vals].pv_simple = $1;
		if (list[num_prop_vals] != NULL) {
			free_outer_list(list[num_prop_vals]);
			list[num_prop_vals] = NULL;
		}
		num_prop_vals++;
	}
	| complex_prop_val
	{
		property[num_prop_vals].pv_type = PROP_VAL_COMPLEX;
		property[num_prop_vals].pv_complex = complex;
		if (list[num_prop_vals] != NULL) {
			free_outer_list(list[num_prop_vals]);
			list[num_prop_vals] = NULL;
		}
		num_prop_vals++;
	}
	| list_prop_val
	{
		property[num_prop_vals].pv_type = PROP_VAL_LIST;
		property[num_prop_vals].pv_list = list[num_prop_vals];
		num_prop_vals++;
	}

/*
 * One level lower, lists are made up of simple or complex values, so
 * simple_prop_val and complex_prop_val fill in a list structure and
 * insert it into the linked list which is built up.  And because
 * complex properties can have multiple name=value pairs, we keep
 * track of them in another linked list.
 *
 * The complex and list structures for the linked lists are allocated
 * below, and freed by recursive functions which are ultimately called
 * by free_cmd(), which is called from the top-most "commands" part of
 * the grammar.
 */

simple_prop_val: TOKEN
	{
		if ((new_list = alloc_list()) == NULL)
			YYERROR;
		new_list->lp_simple = $1;
		new_list->lp_complex = NULL;
		new_list->lp_next = NULL;
		if (list[num_prop_vals] == NULL) {
			list[num_prop_vals] = new_list;
		} else {
			for (tmp_list = list[num_prop_vals]; tmp_list != NULL;
			    tmp_list = tmp_list->lp_next)
				last = tmp_list;
			last->lp_next = new_list;
		}
	}

complex_prop_val: OPEN_PAREN complex_piece CLOSE_PAREN
	{
		if ((new_list = alloc_list()) == NULL)
			YYERROR;
		new_list->lp_simple = NULL;
		new_list->lp_complex = complex;
		new_list->lp_next = NULL;
		if (list[num_prop_vals] == NULL) {
			list[num_prop_vals] = new_list;
		} else {
			for (tmp_list = list[num_prop_vals]; tmp_list != NULL;
			    tmp_list = tmp_list->lp_next)
				last = tmp_list;
			last->lp_next = new_list;
		}
	}

complex_piece: property_name EQUAL TOKEN
	{
		if (($$ = alloc_complex()) == NULL)
			YYERROR;
		$$->cp_type = $1;
		$$->cp_value = $3;
		$$->cp_next = NULL;
		complex = $$;
	}
	| property_name EQUAL TOKEN COMMA complex_piece 
	{
		if (($$ = alloc_complex()) == NULL)
			YYERROR;
		$$->cp_type = $1;
		$$->cp_value = $3;
		$$->cp_next = complex;
		complex = $$;
	}

list_piece: simple_prop_val
	| complex_prop_val
	| simple_prop_val COMMA list_piece
	| complex_prop_val COMMA list_piece

list_prop_val: OPEN_SQ_BRACKET list_piece CLOSE_SQ_BRACKET
%%