17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
58a40a695Sgavinm  * Common Development and Distribution License (the "License").
68a40a695Sgavinm  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*b0daa853SStephen Hanson  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  *
257c478bd9Sstevel@tonic-gate  * check.c -- routines for checking the prop tree
267c478bd9Sstevel@tonic-gate  *
277c478bd9Sstevel@tonic-gate  * this module provides semantic checks on the parse tree.  most of
287c478bd9Sstevel@tonic-gate  * these checks happen during the construction of the parse tree,
297c478bd9Sstevel@tonic-gate  * when the various tree_X() routines call the various check_X()
307c478bd9Sstevel@tonic-gate  * routines.  in a couple of special cases, a check function will
317c478bd9Sstevel@tonic-gate  * process the parse tree after it has been fully constructed.  these
327c478bd9Sstevel@tonic-gate  * cases are noted in the comments above the check function.
337c478bd9Sstevel@tonic-gate  */
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate #include <stdio.h>
367c478bd9Sstevel@tonic-gate #include "out.h"
377c478bd9Sstevel@tonic-gate #include "stable.h"
387c478bd9Sstevel@tonic-gate #include "literals.h"
397c478bd9Sstevel@tonic-gate #include "lut.h"
407c478bd9Sstevel@tonic-gate #include "tree.h"
417c478bd9Sstevel@tonic-gate #include "ptree.h"
427c478bd9Sstevel@tonic-gate #include "check.h"
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate static int check_reportlist(enum nodetype t, const char *s, struct node *np);
457c478bd9Sstevel@tonic-gate static int check_num(enum nodetype t, const char *s, struct node *np);
467c478bd9Sstevel@tonic-gate static int check_quote(enum nodetype t, const char *s, struct node *np);
477aec1d6eScindi static int check_action(enum nodetype t, const char *s, struct node *np);
487c478bd9Sstevel@tonic-gate static int check_num_func(enum nodetype t, const char *s, struct node *np);
497c478bd9Sstevel@tonic-gate static int check_fru_asru(enum nodetype t, const char *s, struct node *np);
507c478bd9Sstevel@tonic-gate static int check_engine(enum nodetype t, const char *s, struct node *np);
517aec1d6eScindi static int check_count(enum nodetype t, const char *s, struct node *np);
527c478bd9Sstevel@tonic-gate static int check_timeval(enum nodetype t, const char *s, struct node *np);
537c478bd9Sstevel@tonic-gate static int check_id(enum nodetype t, const char *s, struct node *np);
547c478bd9Sstevel@tonic-gate static int check_serd_method(enum nodetype t, const char *s, struct node *np);
557aec1d6eScindi static int check_serd_id(enum nodetype t, const char *s, struct node *np);
567c478bd9Sstevel@tonic-gate static int check_nork(struct node *np);
577c478bd9Sstevel@tonic-gate static void check_cycle_lhs(struct node *stmtnp, struct node *arrow);
587c478bd9Sstevel@tonic-gate static void check_cycle_lhs_try(struct node *stmtnp, struct node *lhs,
597c478bd9Sstevel@tonic-gate     struct node *rhs);
607c478bd9Sstevel@tonic-gate static void check_cycle_rhs(struct node *rhs);
61f358d892Srw static void check_proplists_lhs(enum nodetype t, struct node *lhs);
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate static struct {
647c478bd9Sstevel@tonic-gate 	enum nodetype t;
657c478bd9Sstevel@tonic-gate 	const char *name;
667c478bd9Sstevel@tonic-gate 	int required;
677c478bd9Sstevel@tonic-gate 	int (*checker)(enum nodetype t, const char *s, struct node *np);
687c478bd9Sstevel@tonic-gate 	int outflags;
697c478bd9Sstevel@tonic-gate } Allowednames[] = {
70b7d3956bSstephh 	{ T_FAULT, "FITrate", 0, check_num_func, O_ERR },
717c478bd9Sstevel@tonic-gate 	{ T_FAULT, "FRU", 0, check_fru_asru, O_ERR },
727c478bd9Sstevel@tonic-gate 	{ T_FAULT, "ASRU", 0, check_fru_asru, O_ERR },
737aec1d6eScindi 	{ T_FAULT, "message", 0, check_num_func, O_ERR },
74b7d3956bSstephh 	{ T_FAULT, "retire", 0, check_num_func, O_ERR },
75b7d3956bSstephh 	{ T_FAULT, "response", 0, check_num_func, O_ERR },
767aec1d6eScindi 	{ T_FAULT, "action", 0, check_action, O_ERR },
777aec1d6eScindi 	{ T_FAULT, "count", 0, check_count, O_ERR },
78b7d3956bSstephh 	{ T_FAULT, "engine", 0, check_engine, O_ERR },
797c478bd9Sstevel@tonic-gate 	{ T_UPSET, "engine", 0, check_engine, O_ERR },
807c478bd9Sstevel@tonic-gate 	{ T_DEFECT, "FRU", 0, check_fru_asru, O_ERR },
817c478bd9Sstevel@tonic-gate 	{ T_DEFECT, "ASRU", 0, check_fru_asru, O_ERR },
82b7d3956bSstephh 	{ T_DEFECT, "engine", 0, check_engine, O_ERR },
838e7248e5SStephen Hanson 	{ T_DEFECT, "FITrate", 0, check_num_func, O_ERR },
847c478bd9Sstevel@tonic-gate 	{ T_EREPORT, "poller", 0, check_id, O_ERR },
857c478bd9Sstevel@tonic-gate 	{ T_EREPORT, "delivery", 0, check_timeval, O_ERR },
86602ca9eaScth 	{ T_EREPORT, "discard_if_config_unknown", 0, check_num, O_ERR },
877c478bd9Sstevel@tonic-gate 	{ T_SERD, "N", 1, check_num, O_ERR },
887c478bd9Sstevel@tonic-gate 	{ T_SERD, "T", 1, check_timeval, O_ERR },
89b7d3956bSstephh 	{ T_SERD, "method", 0, check_serd_method, O_ERR },
90b7d3956bSstephh 	{ T_SERD, "trip", 0, check_reportlist, O_ERR },
917c478bd9Sstevel@tonic-gate 	{ T_SERD, "FRU", 0, check_fru_asru, O_ERR },
927aec1d6eScindi 	{ T_SERD, "id", 0, check_serd_id, O_ERR },
937c478bd9Sstevel@tonic-gate 	{ T_ERROR, "ASRU", 0, check_fru_asru, O_ERR },
947c478bd9Sstevel@tonic-gate 	{ T_CONFIG, NULL, 0, check_quote, O_ERR },
957c478bd9Sstevel@tonic-gate 	{ 0, NULL, 0 },
967c478bd9Sstevel@tonic-gate };
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate void
check_init(void)997c478bd9Sstevel@tonic-gate check_init(void)
1007c478bd9Sstevel@tonic-gate {
1017c478bd9Sstevel@tonic-gate 	int i;
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate 	for (i = 0; Allowednames[i].t; i++)
1047c478bd9Sstevel@tonic-gate 		if (Allowednames[i].name != NULL)
1057c478bd9Sstevel@tonic-gate 			Allowednames[i].name = stable(Allowednames[i].name);
1067c478bd9Sstevel@tonic-gate }
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate void
check_fini(void)1097c478bd9Sstevel@tonic-gate check_fini(void)
1107c478bd9Sstevel@tonic-gate {
1117c478bd9Sstevel@tonic-gate }
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1147c478bd9Sstevel@tonic-gate void
check_report_combination(struct node * np)1157c478bd9Sstevel@tonic-gate check_report_combination(struct node *np)
1167c478bd9Sstevel@tonic-gate {
1177c478bd9Sstevel@tonic-gate 	/* nothing to check for here.  poller is only prop and it is optional */
1187c478bd9Sstevel@tonic-gate }
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate /*
1217c478bd9Sstevel@tonic-gate  * check_path_iterators -- verify all iterators are explicit
1227c478bd9Sstevel@tonic-gate  */
1237c478bd9Sstevel@tonic-gate static void
check_path_iterators(struct node * np)1247c478bd9Sstevel@tonic-gate check_path_iterators(struct node *np)
1257c478bd9Sstevel@tonic-gate {
1267c478bd9Sstevel@tonic-gate 	if (np == NULL)
1277c478bd9Sstevel@tonic-gate 		return;
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate 	switch (np->t) {
1307c478bd9Sstevel@tonic-gate 		case T_ARROW:
1317c478bd9Sstevel@tonic-gate 			check_path_iterators(np->u.arrow.lhs);
1327c478bd9Sstevel@tonic-gate 			check_path_iterators(np->u.arrow.rhs);
1337c478bd9Sstevel@tonic-gate 			break;
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate 		case T_LIST:
1367c478bd9Sstevel@tonic-gate 			check_path_iterators(np->u.expr.left);
1377c478bd9Sstevel@tonic-gate 			check_path_iterators(np->u.expr.right);
1387c478bd9Sstevel@tonic-gate 			break;
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate 		case T_EVENT:
1417c478bd9Sstevel@tonic-gate 			check_path_iterators(np->u.event.epname);
1427c478bd9Sstevel@tonic-gate 			break;
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate 		case T_NAME:
1457c478bd9Sstevel@tonic-gate 			if (np->u.name.child == NULL)
1467c478bd9Sstevel@tonic-gate 				outfl(O_DIE, np->file, np->line,
1477c478bd9Sstevel@tonic-gate 				    "internal error: check_path_iterators: "
1487c478bd9Sstevel@tonic-gate 				    "unexpected implicit iterator: %s",
1497c478bd9Sstevel@tonic-gate 				    np->u.name.s);
1507c478bd9Sstevel@tonic-gate 			check_path_iterators(np->u.name.next);
1517c478bd9Sstevel@tonic-gate 			break;
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate 		default:
1547c478bd9Sstevel@tonic-gate 			outfl(O_DIE, np->file, np->line,
1557c478bd9Sstevel@tonic-gate 			    "internal error: check_path_iterators: "
1567c478bd9Sstevel@tonic-gate 			    "unexpected type: %s",
1577c478bd9Sstevel@tonic-gate 			    ptree_nodetype2str(np->t));
1587c478bd9Sstevel@tonic-gate 	}
1597c478bd9Sstevel@tonic-gate }
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate void
check_arrow(struct node * np)1627c478bd9Sstevel@tonic-gate check_arrow(struct node *np)
1637c478bd9Sstevel@tonic-gate {
1647c478bd9Sstevel@tonic-gate 	ASSERTinfo(np->t == T_ARROW, ptree_nodetype2str(np->t));
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 	if (np->u.arrow.lhs->t != T_ARROW &&
1677c478bd9Sstevel@tonic-gate 	    np->u.arrow.lhs->t != T_LIST &&
1687c478bd9Sstevel@tonic-gate 	    np->u.arrow.lhs->t != T_EVENT) {
1697c478bd9Sstevel@tonic-gate 		outfl(O_ERR,
1707c478bd9Sstevel@tonic-gate 		    np->u.arrow.lhs->file, np->u.arrow.lhs->line,
1717c478bd9Sstevel@tonic-gate 		    "%s not allowed on left-hand side of arrow",
1727c478bd9Sstevel@tonic-gate 		    ptree_nodetype2str(np->u.arrow.lhs->t));
1737c478bd9Sstevel@tonic-gate 	}
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate 	if (!check_nork(np->u.arrow.nnp) ||
176b1f905a8Scy 	    !check_nork(np->u.arrow.knp))
177b1f905a8Scy 		outfl(O_ERR, np->file, np->line,
178b1f905a8Scy 		    "counts associated with propagation arrows "
179b1f905a8Scy 		    "must be integers");
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 	check_path_iterators(np);
1827c478bd9Sstevel@tonic-gate }
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate /*
1857c478bd9Sstevel@tonic-gate  * make sure the nork values are valid.
1867c478bd9Sstevel@tonic-gate  * Nork values must be "A" for all(T_NAME),
1877c478bd9Sstevel@tonic-gate  * a number(T_NUM), or a simple
1887c478bd9Sstevel@tonic-gate  * expression(T_SUB, T_ADD, T_MUL, T_DIV)
1897c478bd9Sstevel@tonic-gate  */
1907c478bd9Sstevel@tonic-gate static int
check_nork(struct node * np)1917c478bd9Sstevel@tonic-gate check_nork(struct node *np)
1927c478bd9Sstevel@tonic-gate {
1937c478bd9Sstevel@tonic-gate 	int rval = 0;
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate 	/* NULL means no nork value which is allowed */
1967c478bd9Sstevel@tonic-gate 	if (np == NULL) {
1977c478bd9Sstevel@tonic-gate 		rval = 1;
1987c478bd9Sstevel@tonic-gate 	}
1997c478bd9Sstevel@tonic-gate 	else
2007c478bd9Sstevel@tonic-gate 	{
2017c478bd9Sstevel@tonic-gate 		/* if the nork is a name it must be A for "All" */
2027c478bd9Sstevel@tonic-gate 		if (np->t == T_NAME)
2037c478bd9Sstevel@tonic-gate 			if (*np->u.name.s == 'A')
2047c478bd9Sstevel@tonic-gate 				return (1);
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate 		/*  T_NUM allowed */
2077c478bd9Sstevel@tonic-gate 		if (np->t == T_NUM)
2087c478bd9Sstevel@tonic-gate 			rval = 1;
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 		/*  simple expressions allowed */
2117c478bd9Sstevel@tonic-gate 		if (np->t == T_SUB ||
212b1f905a8Scy 		    np->t == T_ADD ||
213b1f905a8Scy 		    np->t == T_MUL ||
214b1f905a8Scy 		    np->t == T_DIV)
2157c478bd9Sstevel@tonic-gate 			rval = 1;
2167c478bd9Sstevel@tonic-gate 	}
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate 	return (rval);
2197c478bd9Sstevel@tonic-gate }
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate static int
check_reportlist(enum nodetype t,const char * s,struct node * np)2227c478bd9Sstevel@tonic-gate check_reportlist(enum nodetype t, const char *s, struct node *np)
2237c478bd9Sstevel@tonic-gate {
2247c478bd9Sstevel@tonic-gate 	if (np == NULL)
2257c478bd9Sstevel@tonic-gate 		return (1);
2267c478bd9Sstevel@tonic-gate 	else if (np->t == T_EVENT) {
2277c478bd9Sstevel@tonic-gate 		if (np->u.event.ename->u.name.t != N_EREPORT) {
2287c478bd9Sstevel@tonic-gate 			outfl(O_ERR, np->file, np->line,
2297c478bd9Sstevel@tonic-gate 			    "%s %s property must begin with \"ereport.\"",
2307c478bd9Sstevel@tonic-gate 			    ptree_nodetype2str(t), s);
2317c478bd9Sstevel@tonic-gate 		} else if (tree_event2np_lut_lookup(Ereports, np) == NULL) {
2327c478bd9Sstevel@tonic-gate 			outfl(O_ERR, np->file, np->line,
2337c478bd9Sstevel@tonic-gate 			    "%s %s property contains undeclared name",
2347c478bd9Sstevel@tonic-gate 			    ptree_nodetype2str(t), s);
2357c478bd9Sstevel@tonic-gate 		}
2367c478bd9Sstevel@tonic-gate 		check_type_iterator(np);
2377c478bd9Sstevel@tonic-gate 	} else if (np->t == T_LIST) {
2387c478bd9Sstevel@tonic-gate 		(void) check_reportlist(t, s, np->u.expr.left);
2397c478bd9Sstevel@tonic-gate 		(void) check_reportlist(t, s, np->u.expr.right);
2407c478bd9Sstevel@tonic-gate 	}
2417c478bd9Sstevel@tonic-gate 	return (1);
2427c478bd9Sstevel@tonic-gate }
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate static int
check_num(enum nodetype t,const char * s,struct node * np)2457c478bd9Sstevel@tonic-gate check_num(enum nodetype t, const char *s, struct node *np)
2467c478bd9Sstevel@tonic-gate {
2477c478bd9Sstevel@tonic-gate 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
2487c478bd9Sstevel@tonic-gate 	if (np->t != T_NUM)
2497c478bd9Sstevel@tonic-gate 		outfl(O_ERR, np->file, np->line,
2507c478bd9Sstevel@tonic-gate 		    "%s %s property must be a single number",
2517c478bd9Sstevel@tonic-gate 		    ptree_nodetype2str(t), s);
2527c478bd9Sstevel@tonic-gate 	return (1);
2537c478bd9Sstevel@tonic-gate }
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate /*ARGSUSED1*/
2567c478bd9Sstevel@tonic-gate static int
check_quote(enum nodetype t,const char * s,struct node * np)2577c478bd9Sstevel@tonic-gate check_quote(enum nodetype t, const char *s, struct node *np)
2587c478bd9Sstevel@tonic-gate {
2597c478bd9Sstevel@tonic-gate 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
2607c478bd9Sstevel@tonic-gate 	if (np->t != T_QUOTE)
2617c478bd9Sstevel@tonic-gate 		outfl(O_ERR, np->file, np->line,
2627c478bd9Sstevel@tonic-gate 		    "%s properties must be quoted strings",
2637c478bd9Sstevel@tonic-gate 		    ptree_nodetype2str(t));
2647c478bd9Sstevel@tonic-gate 	return (1);
2657c478bd9Sstevel@tonic-gate }
2667c478bd9Sstevel@tonic-gate 
2677aec1d6eScindi static int
check_action(enum nodetype t,const char * s,struct node * np)2687aec1d6eScindi check_action(enum nodetype t, const char *s, struct node *np)
2697aec1d6eScindi {
2707aec1d6eScindi 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
2717aec1d6eScindi 
2727aec1d6eScindi 	if (np->t != T_FUNC)
2737aec1d6eScindi 		outfl(O_ERR, np->file, np->line,
2747aec1d6eScindi 		    "%s %s property must be a function or list of functions",
2757aec1d6eScindi 		    ptree_nodetype2str(t), s);
2767aec1d6eScindi 	return (1);
2777aec1d6eScindi }
2787aec1d6eScindi 
2797c478bd9Sstevel@tonic-gate static int
check_num_func(enum nodetype t,const char * s,struct node * np)2807c478bd9Sstevel@tonic-gate check_num_func(enum nodetype t, const char *s, struct node *np)
2817c478bd9Sstevel@tonic-gate {
2827c478bd9Sstevel@tonic-gate 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
2837c478bd9Sstevel@tonic-gate 	if (np->t != T_NUM && np->t != T_FUNC)
2847c478bd9Sstevel@tonic-gate 		outfl(O_ERR, np->file, np->line,
2857c478bd9Sstevel@tonic-gate 		    "%s %s property must be a number or function",
2867c478bd9Sstevel@tonic-gate 		    ptree_nodetype2str(t), s);
2877c478bd9Sstevel@tonic-gate 	return (1);
2887c478bd9Sstevel@tonic-gate }
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate static int
check_fru_asru(enum nodetype t,const char * s,struct node * np)2917c478bd9Sstevel@tonic-gate check_fru_asru(enum nodetype t, const char *s, struct node *np)
2927c478bd9Sstevel@tonic-gate {
2937c478bd9Sstevel@tonic-gate 	ASSERT(s != NULL);
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate 	/* make sure it is a node type T_NAME? */
2967c478bd9Sstevel@tonic-gate 	if (np->t == T_NAME) {
297b1f905a8Scy 		if (s == L_ASRU) {
298b1f905a8Scy 			if (tree_name2np_lut_lookup_name(ASRUs, np) == NULL)
299b1f905a8Scy 				outfl(O_ERR, np->file, np->line,
300b1f905a8Scy 				    "ASRU property contains undeclared asru");
301b1f905a8Scy 		} else if (s == L_FRU) {
302b1f905a8Scy 			if (tree_name2np_lut_lookup_name(FRUs, np) == NULL)
303b1f905a8Scy 				outfl(O_ERR, np->file, np->line,
304b1f905a8Scy 				    "FRU property contains undeclared fru");
305b1f905a8Scy 		} else {
3067c478bd9Sstevel@tonic-gate 			outfl(O_ERR, np->file, np->line,
307b1f905a8Scy 			    "illegal property name in %s declaration: %s",
308b1f905a8Scy 			    ptree_nodetype2str(t), s);
309b1f905a8Scy 		}
310b1f905a8Scy 		check_type_iterator(np);
3117c478bd9Sstevel@tonic-gate 	} else
3127c478bd9Sstevel@tonic-gate 		outfl(O_ERR, np->file, np->line,
3137c478bd9Sstevel@tonic-gate 		    "illegal type used for %s property: %s",
3147c478bd9Sstevel@tonic-gate 		    s, ptree_nodetype2str(np->t));
3157c478bd9Sstevel@tonic-gate 	return (1);
3167c478bd9Sstevel@tonic-gate }
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate static int
check_engine(enum nodetype t,const char * s,struct node * np)3197c478bd9Sstevel@tonic-gate check_engine(enum nodetype t, const char *s, struct node *np)
3207c478bd9Sstevel@tonic-gate {
3217c478bd9Sstevel@tonic-gate 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
3227c478bd9Sstevel@tonic-gate 	if (np->t != T_EVENT)
3237c478bd9Sstevel@tonic-gate 		outfl(O_ERR, np->file, np->line,
3247c478bd9Sstevel@tonic-gate 		    "%s %s property must be an engine name "
3257c478bd9Sstevel@tonic-gate 		    "(i.e. serd.x or serd.x@a/b)",
3267c478bd9Sstevel@tonic-gate 		    ptree_nodetype2str(t), s);
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 	return (1);
3297c478bd9Sstevel@tonic-gate }
3307c478bd9Sstevel@tonic-gate 
3317aec1d6eScindi static int
check_count(enum nodetype t,const char * s,struct node * np)3327aec1d6eScindi check_count(enum nodetype t, const char *s, struct node *np)
3337aec1d6eScindi {
3347aec1d6eScindi 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
3357aec1d6eScindi 	if (np->t != T_EVENT)
3367aec1d6eScindi 		outfl(O_ERR, np->file, np->line,
3377aec1d6eScindi 		    "%s %s property must be an engine name "
3387aec1d6eScindi 		    "(i.e. stat.x or stat.x@a/b)",
3397aec1d6eScindi 		    ptree_nodetype2str(t), s);
3407aec1d6eScindi 
3417aec1d6eScindi 	/* XXX confirm engine has been declared */
3427aec1d6eScindi 	return (1);
3437aec1d6eScindi }
3447aec1d6eScindi 
3457c478bd9Sstevel@tonic-gate static int
check_timeval(enum nodetype t,const char * s,struct node * np)3467c478bd9Sstevel@tonic-gate check_timeval(enum nodetype t, const char *s, struct node *np)
3477c478bd9Sstevel@tonic-gate {
3487c478bd9Sstevel@tonic-gate 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
3497c478bd9Sstevel@tonic-gate 	if (np->t != T_TIMEVAL)
3507c478bd9Sstevel@tonic-gate 		outfl(O_ERR, np->file, np->line,
3517c478bd9Sstevel@tonic-gate 		    "%s %s property must be a number with time units",
3527c478bd9Sstevel@tonic-gate 		    ptree_nodetype2str(t), s);
3537c478bd9Sstevel@tonic-gate 	return (1);
3547c478bd9Sstevel@tonic-gate }
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate static int
check_id(enum nodetype t,const char * s,struct node * np)3577c478bd9Sstevel@tonic-gate check_id(enum nodetype t, const char *s, struct node *np)
3587c478bd9Sstevel@tonic-gate {
3597c478bd9Sstevel@tonic-gate 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
3607c478bd9Sstevel@tonic-gate 	if (np->t != T_NAME || np->u.name.next || np->u.name.child)
3617c478bd9Sstevel@tonic-gate 		outfl(O_ERR, np->file, np->line,
3627c478bd9Sstevel@tonic-gate 		    "%s %s property must be simple name",
3637c478bd9Sstevel@tonic-gate 		    ptree_nodetype2str(t), s);
3647c478bd9Sstevel@tonic-gate 	return (1);
3657c478bd9Sstevel@tonic-gate }
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate static int
check_serd_method(enum nodetype t,const char * s,struct node * np)3687c478bd9Sstevel@tonic-gate check_serd_method(enum nodetype t, const char *s, struct node *np)
3697c478bd9Sstevel@tonic-gate {
3707c478bd9Sstevel@tonic-gate 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
3717c478bd9Sstevel@tonic-gate 	if (np->t != T_NAME || np->u.name.next || np->u.name.child ||
3727c478bd9Sstevel@tonic-gate 	    (np->u.name.s != L_volatile &&
3737c478bd9Sstevel@tonic-gate 	    np->u.name.s != L_persistent))
3747c478bd9Sstevel@tonic-gate 		outfl(O_ERR, np->file, np->line,
3757c478bd9Sstevel@tonic-gate 		    "%s %s property must be \"volatile\" or \"persistent\"",
3767c478bd9Sstevel@tonic-gate 		    ptree_nodetype2str(t), s);
3777c478bd9Sstevel@tonic-gate 	return (1);
3787c478bd9Sstevel@tonic-gate }
3797c478bd9Sstevel@tonic-gate 
3807aec1d6eScindi static int
check_serd_id(enum nodetype t,const char * s,struct node * np)3817aec1d6eScindi check_serd_id(enum nodetype t, const char *s, struct node *np)
3827aec1d6eScindi {
3837aec1d6eScindi 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
3847aec1d6eScindi 	if (np->t != T_GLOBID)
3857aec1d6eScindi 		outfl(O_ERR, np->file, np->line,
3867aec1d6eScindi 		    "%s %s property must be a global ID",
3877aec1d6eScindi 		    ptree_nodetype2str(t), s);
3887aec1d6eScindi 	return (1);
3897aec1d6eScindi }
3907aec1d6eScindi 
3917c478bd9Sstevel@tonic-gate void
check_stmt_required_properties(struct node * stmtnp)3927c478bd9Sstevel@tonic-gate check_stmt_required_properties(struct node *stmtnp)
3937c478bd9Sstevel@tonic-gate {
3947c478bd9Sstevel@tonic-gate 	struct lut *lutp = stmtnp->u.stmt.lutp;
3957c478bd9Sstevel@tonic-gate 	struct node *np = stmtnp->u.stmt.np;
3967c478bd9Sstevel@tonic-gate 	int i;
3977c478bd9Sstevel@tonic-gate 
3987c478bd9Sstevel@tonic-gate 	for (i = 0; Allowednames[i].t; i++)
3997c478bd9Sstevel@tonic-gate 		if (stmtnp->t == Allowednames[i].t &&
4007c478bd9Sstevel@tonic-gate 		    Allowednames[i].required &&
4017c478bd9Sstevel@tonic-gate 		    tree_s2np_lut_lookup(lutp, Allowednames[i].name) == NULL)
4027c478bd9Sstevel@tonic-gate 			outfl(Allowednames[i].outflags,
4037c478bd9Sstevel@tonic-gate 			    np->file, np->line,
4047c478bd9Sstevel@tonic-gate 			    "%s statement missing property: %s",
4057c478bd9Sstevel@tonic-gate 			    ptree_nodetype2str(stmtnp->t),
4067c478bd9Sstevel@tonic-gate 			    Allowednames[i].name);
4077c478bd9Sstevel@tonic-gate }
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate void
check_stmt_allowed_properties(enum nodetype t,struct node * nvpairnp,struct lut * lutp)4107c478bd9Sstevel@tonic-gate check_stmt_allowed_properties(enum nodetype t,
4117c478bd9Sstevel@tonic-gate     struct node *nvpairnp, struct lut *lutp)
4127c478bd9Sstevel@tonic-gate {
4137c478bd9Sstevel@tonic-gate 	int i;
4147c478bd9Sstevel@tonic-gate 	const char *s = nvpairnp->u.expr.left->u.name.s;
4157c478bd9Sstevel@tonic-gate 	struct node *np;
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate 	for (i = 0; Allowednames[i].t; i++)
4187c478bd9Sstevel@tonic-gate 		if (t == Allowednames[i].t && Allowednames[i].name == NULL) {
4197c478bd9Sstevel@tonic-gate 			/* NULL name means just call checker */
4207c478bd9Sstevel@tonic-gate 			(*Allowednames[i].checker)(t, s,
4217c478bd9Sstevel@tonic-gate 			    nvpairnp->u.expr.right);
4227c478bd9Sstevel@tonic-gate 			return;
4237c478bd9Sstevel@tonic-gate 		} else if (t == Allowednames[i].t && s == Allowednames[i].name)
4247c478bd9Sstevel@tonic-gate 			break;
4257c478bd9Sstevel@tonic-gate 	if (Allowednames[i].name == NULL)
4267c478bd9Sstevel@tonic-gate 		outfl(O_ERR, nvpairnp->file, nvpairnp->line,
4277c478bd9Sstevel@tonic-gate 		    "illegal property name in %s declaration: %s",
4287c478bd9Sstevel@tonic-gate 		    ptree_nodetype2str(t), s);
4297c478bd9Sstevel@tonic-gate 	else if ((np = tree_s2np_lut_lookup(lutp, s)) != NULL) {
4307c478bd9Sstevel@tonic-gate 		/*
4317c478bd9Sstevel@tonic-gate 		 * redeclaring prop is allowed if value is the same
4327c478bd9Sstevel@tonic-gate 		 */
4337c478bd9Sstevel@tonic-gate 		if (np->t != nvpairnp->u.expr.right->t)
4347c478bd9Sstevel@tonic-gate 			outfl(O_ERR, nvpairnp->file, nvpairnp->line,
4357c478bd9Sstevel@tonic-gate 			    "property redeclared (with differnt type) "
4367c478bd9Sstevel@tonic-gate 			    "in %s declaration: %s",
4377c478bd9Sstevel@tonic-gate 			    ptree_nodetype2str(t), s);
4387c478bd9Sstevel@tonic-gate 		switch (np->t) {
4397c478bd9Sstevel@tonic-gate 			case T_NUM:
4407c478bd9Sstevel@tonic-gate 			case T_TIMEVAL:
4417c478bd9Sstevel@tonic-gate 				if (np->u.ull == nvpairnp->u.expr.right->u.ull)
4427c478bd9Sstevel@tonic-gate 					return;
4437c478bd9Sstevel@tonic-gate 				break;
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate 			case T_NAME:
4467c478bd9Sstevel@tonic-gate 				if (tree_namecmp(np,
4477c478bd9Sstevel@tonic-gate 				    nvpairnp->u.expr.right) == 0)
4487c478bd9Sstevel@tonic-gate 					return;
4497c478bd9Sstevel@tonic-gate 				break;
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate 			case T_EVENT:
4527c478bd9Sstevel@tonic-gate 				if (tree_eventcmp(np,
4537c478bd9Sstevel@tonic-gate 				    nvpairnp->u.expr.right) == 0)
4547c478bd9Sstevel@tonic-gate 					return;
4557c478bd9Sstevel@tonic-gate 				break;
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate 			default:
4587c478bd9Sstevel@tonic-gate 				outfl(O_ERR, nvpairnp->file, nvpairnp->line,
4597c478bd9Sstevel@tonic-gate 				    "value for property \"%s\" is an "
4607c478bd9Sstevel@tonic-gate 				    "invalid type: %s",
4617c478bd9Sstevel@tonic-gate 				    nvpairnp->u.expr.left->u.name.s,
4627c478bd9Sstevel@tonic-gate 				    ptree_nodetype2str(np->t));
4637c478bd9Sstevel@tonic-gate 				return;
4647c478bd9Sstevel@tonic-gate 		}
4657c478bd9Sstevel@tonic-gate 		outfl(O_ERR, nvpairnp->file, nvpairnp->line,
4667c478bd9Sstevel@tonic-gate 		    "property redeclared in %s declaration: %s",
4677c478bd9Sstevel@tonic-gate 		    ptree_nodetype2str(t), s);
4687c478bd9Sstevel@tonic-gate 	} else
4697c478bd9Sstevel@tonic-gate 		(*Allowednames[i].checker)(t, s, nvpairnp->u.expr.right);
4707c478bd9Sstevel@tonic-gate }
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate void
check_propnames(enum nodetype t,struct node * np,int from,int to)4737c478bd9Sstevel@tonic-gate check_propnames(enum nodetype t, struct node *np, int from, int to)
4747c478bd9Sstevel@tonic-gate {
4757c478bd9Sstevel@tonic-gate 	struct node *dnp;
4767c478bd9Sstevel@tonic-gate 	struct lut *lutp;
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate 	ASSERT(np != NULL);
4797c478bd9Sstevel@tonic-gate 	ASSERTinfo(np->t == T_EVENT || np->t == T_LIST || np->t == T_ARROW,
480b1f905a8Scy 	    ptree_nodetype2str(np->t));
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate 	if (np->t == T_EVENT) {
4837c478bd9Sstevel@tonic-gate 		switch (np->u.event.ename->u.name.t) {
4847c478bd9Sstevel@tonic-gate 		case N_UNSPEC:
4857c478bd9Sstevel@tonic-gate 			outfl(O_ERR, np->file, np->line,
4867c478bd9Sstevel@tonic-gate 			    "name in %s statement must begin with "
4877c478bd9Sstevel@tonic-gate 			    "type (example: \"error.\")",
4887c478bd9Sstevel@tonic-gate 			    ptree_nodetype2str(t));
4897c478bd9Sstevel@tonic-gate 			return;
4907c478bd9Sstevel@tonic-gate 		case N_FAULT:
4917c478bd9Sstevel@tonic-gate 			lutp = Faults;
4927c478bd9Sstevel@tonic-gate 			if (to) {
4937c478bd9Sstevel@tonic-gate 				outfl(O_ERR, np->file, np->line,
4947c478bd9Sstevel@tonic-gate 				    "%s has fault on right side of \"->\"",
4957c478bd9Sstevel@tonic-gate 				    ptree_nodetype2str(t));
4967c478bd9Sstevel@tonic-gate 				return;
4977c478bd9Sstevel@tonic-gate 			}
4987c478bd9Sstevel@tonic-gate 			if (!from) {
4997c478bd9Sstevel@tonic-gate 				outfl(O_DIE, np->file, np->line,
5007c478bd9Sstevel@tonic-gate 				    "internal error: %s has fault without "
5017c478bd9Sstevel@tonic-gate 				    "from flag",
5027c478bd9Sstevel@tonic-gate 				    ptree_nodetype2str(t));
5037c478bd9Sstevel@tonic-gate 			}
5047c478bd9Sstevel@tonic-gate 			break;
5057c478bd9Sstevel@tonic-gate 		case N_UPSET:
5067c478bd9Sstevel@tonic-gate 			lutp = Upsets;
5077c478bd9Sstevel@tonic-gate 			if (to) {
5087c478bd9Sstevel@tonic-gate 				outfl(O_ERR, np->file, np->line,
5097c478bd9Sstevel@tonic-gate 				    "%s has upset on right side of \"->\"",
5107c478bd9Sstevel@tonic-gate 				    ptree_nodetype2str(t));
5117c478bd9Sstevel@tonic-gate 				return;
5127c478bd9Sstevel@tonic-gate 			}
5137c478bd9Sstevel@tonic-gate 			if (!from)
5147c478bd9Sstevel@tonic-gate 				outfl(O_DIE, np->file, np->line,
5157c478bd9Sstevel@tonic-gate 				    "internal error: %s has upset without "
5167c478bd9Sstevel@tonic-gate 				    "from flag",
5177c478bd9Sstevel@tonic-gate 				    ptree_nodetype2str(t));
5187c478bd9Sstevel@tonic-gate 			break;
5197c478bd9Sstevel@tonic-gate 		case N_DEFECT:
5207c478bd9Sstevel@tonic-gate 			lutp = Defects;
5217c478bd9Sstevel@tonic-gate 			if (to) {
5227c478bd9Sstevel@tonic-gate 				outfl(O_ERR, np->file, np->line,
5237c478bd9Sstevel@tonic-gate 				    "%s has defect on right side of \"->\"",
5247c478bd9Sstevel@tonic-gate 				    ptree_nodetype2str(t));
5257c478bd9Sstevel@tonic-gate 				return;
5267c478bd9Sstevel@tonic-gate 			}
5277c478bd9Sstevel@tonic-gate 			if (!from) {
5287c478bd9Sstevel@tonic-gate 				outfl(O_DIE, np->file, np->line,
5297c478bd9Sstevel@tonic-gate 				    "internal error: %s has defect without "
5307c478bd9Sstevel@tonic-gate 				    "from flag",
5317c478bd9Sstevel@tonic-gate 				    ptree_nodetype2str(t));
5327c478bd9Sstevel@tonic-gate 			}
5337c478bd9Sstevel@tonic-gate 			break;
5347c478bd9Sstevel@tonic-gate 		case N_ERROR:
5357c478bd9Sstevel@tonic-gate 			lutp = Errors;
5367c478bd9Sstevel@tonic-gate 			if (!from && !to)
5377c478bd9Sstevel@tonic-gate 				outfl(O_DIE, np->file, np->line,
5387c478bd9Sstevel@tonic-gate 				    "%s has error without from or to flags",
5397c478bd9Sstevel@tonic-gate 				    ptree_nodetype2str(t));
5407c478bd9Sstevel@tonic-gate 			break;
5417c478bd9Sstevel@tonic-gate 		case N_EREPORT:
5427c478bd9Sstevel@tonic-gate 			lutp = Ereports;
5437c478bd9Sstevel@tonic-gate 			if (from) {
5447c478bd9Sstevel@tonic-gate 				outfl(O_ERR, np->file, np->line,
5457c478bd9Sstevel@tonic-gate 				    "%s has report on left side of \"->\"",
5467c478bd9Sstevel@tonic-gate 				    ptree_nodetype2str(t));
5477c478bd9Sstevel@tonic-gate 				return;
5487c478bd9Sstevel@tonic-gate 			}
5497c478bd9Sstevel@tonic-gate 			if (!to)
5507c478bd9Sstevel@tonic-gate 				outfl(O_DIE, np->file, np->line,
5517c478bd9Sstevel@tonic-gate 				    "internal error: %s has report without "
5527c478bd9Sstevel@tonic-gate 				    "to flag",
5537c478bd9Sstevel@tonic-gate 				    ptree_nodetype2str(t));
5547c478bd9Sstevel@tonic-gate 			break;
5557c478bd9Sstevel@tonic-gate 		default:
5567c478bd9Sstevel@tonic-gate 			outfl(O_DIE, np->file, np->line,
5577c478bd9Sstevel@tonic-gate 			    "internal error: check_propnames: "
5587c478bd9Sstevel@tonic-gate 			    "unexpected type: %d", np->u.name.t);
5597c478bd9Sstevel@tonic-gate 		}
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate 		if ((dnp = tree_event2np_lut_lookup(lutp, np)) == NULL) {
5627c478bd9Sstevel@tonic-gate 			outfl(O_ERR, np->file, np->line,
5637c478bd9Sstevel@tonic-gate 			    "%s statement contains undeclared event",
5647c478bd9Sstevel@tonic-gate 			    ptree_nodetype2str(t));
5657c478bd9Sstevel@tonic-gate 		} else
5667c478bd9Sstevel@tonic-gate 			dnp->u.stmt.flags |= STMT_REF;
5677c478bd9Sstevel@tonic-gate 		np->u.event.declp = dnp;
5687c478bd9Sstevel@tonic-gate 	} else if (np->t == T_LIST) {
5697c478bd9Sstevel@tonic-gate 		check_propnames(t, np->u.expr.left, from, to);
5707c478bd9Sstevel@tonic-gate 		check_propnames(t, np->u.expr.right, from, to);
5717c478bd9Sstevel@tonic-gate 	} else if (np->t == T_ARROW) {
5727c478bd9Sstevel@tonic-gate 		check_propnames(t, np->u.arrow.lhs, 1, to);
5737c478bd9Sstevel@tonic-gate 		check_propnames(t, np->u.arrow.rhs, from, 1);
5747c478bd9Sstevel@tonic-gate 	}
5757c478bd9Sstevel@tonic-gate }
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate static struct lut *
record_iterators(struct node * np,struct lut * ex)5787c478bd9Sstevel@tonic-gate record_iterators(struct node *np, struct lut *ex)
5797c478bd9Sstevel@tonic-gate {
5807c478bd9Sstevel@tonic-gate 	if (np == NULL)
5817c478bd9Sstevel@tonic-gate 		return (ex);
5827c478bd9Sstevel@tonic-gate 
5837c478bd9Sstevel@tonic-gate 	switch (np->t) {
5847c478bd9Sstevel@tonic-gate 	case T_ARROW:
5857c478bd9Sstevel@tonic-gate 		ex = record_iterators(np->u.arrow.lhs, ex);
5867c478bd9Sstevel@tonic-gate 		ex = record_iterators(np->u.arrow.rhs, ex);
5877c478bd9Sstevel@tonic-gate 		break;
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate 	case T_LIST:
5907c478bd9Sstevel@tonic-gate 		ex = record_iterators(np->u.expr.left, ex);
5917c478bd9Sstevel@tonic-gate 		ex = record_iterators(np->u.expr.right, ex);
5927c478bd9Sstevel@tonic-gate 		break;
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate 	case T_EVENT:
5957c478bd9Sstevel@tonic-gate 		ex = record_iterators(np->u.event.epname, ex);
5967c478bd9Sstevel@tonic-gate 		break;
5977c478bd9Sstevel@tonic-gate 
5987c478bd9Sstevel@tonic-gate 	case T_NAME:
5997c478bd9Sstevel@tonic-gate 		if (np->u.name.child && np->u.name.child->t == T_NAME)
6007c478bd9Sstevel@tonic-gate 			ex = lut_add(ex, (void *) np->u.name.child->u.name.s,
6017c478bd9Sstevel@tonic-gate 			    (void *) np, NULL);
6027c478bd9Sstevel@tonic-gate 		ex = record_iterators(np->u.name.next, ex);
6037c478bd9Sstevel@tonic-gate 		break;
6047c478bd9Sstevel@tonic-gate 
6057c478bd9Sstevel@tonic-gate 	default:
6067c478bd9Sstevel@tonic-gate 		outfl(O_DIE, np->file, np->line,
6077c478bd9Sstevel@tonic-gate 		    "record_iterators: internal error: unexpected type: %s",
6087c478bd9Sstevel@tonic-gate 		    ptree_nodetype2str(np->t));
6097c478bd9Sstevel@tonic-gate 	}
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate 	return (ex);
6127c478bd9Sstevel@tonic-gate }
6137c478bd9Sstevel@tonic-gate 
6147c478bd9Sstevel@tonic-gate void
check_exprscope(struct node * np,struct lut * ex)6157c478bd9Sstevel@tonic-gate check_exprscope(struct node *np, struct lut *ex)
6167c478bd9Sstevel@tonic-gate {
6177c478bd9Sstevel@tonic-gate 	if (np == NULL)
6187c478bd9Sstevel@tonic-gate 		return;
6197c478bd9Sstevel@tonic-gate 
6207c478bd9Sstevel@tonic-gate 	switch (np->t) {
6217c478bd9Sstevel@tonic-gate 	case T_EVENT:
6227c478bd9Sstevel@tonic-gate 		check_exprscope(np->u.event.eexprlist, ex);
6237c478bd9Sstevel@tonic-gate 		break;
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate 	case T_ARROW:
6267c478bd9Sstevel@tonic-gate 		check_exprscope(np->u.arrow.lhs, ex);
6277c478bd9Sstevel@tonic-gate 		check_exprscope(np->u.arrow.rhs, ex);
6287c478bd9Sstevel@tonic-gate 		break;
6297c478bd9Sstevel@tonic-gate 
6307c478bd9Sstevel@tonic-gate 	case T_NAME:
6317c478bd9Sstevel@tonic-gate 		if (np->u.name.child && np->u.name.child->t == T_NAME) {
6327c478bd9Sstevel@tonic-gate 			if (lut_lookup(ex,
633b1f905a8Scy 			    (void *) np->u.name.child->u.name.s, NULL) == NULL)
6347c478bd9Sstevel@tonic-gate 				outfl(O_ERR, np->file, np->line,
635b1f905a8Scy 				    "constraint contains undefined"
636b1f905a8Scy 				    " iterator: %s",
637b1f905a8Scy 				    np->u.name.child->u.name.s);
6387c478bd9Sstevel@tonic-gate 		}
6397c478bd9Sstevel@tonic-gate 		check_exprscope(np->u.name.next, ex);
6407c478bd9Sstevel@tonic-gate 		break;
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate 	case T_QUOTE:
6437c478bd9Sstevel@tonic-gate 	case T_GLOBID:
6447c478bd9Sstevel@tonic-gate 		break;
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate 	case T_ASSIGN:
6477c478bd9Sstevel@tonic-gate 	case T_NE:
6487c478bd9Sstevel@tonic-gate 	case T_EQ:
6497c478bd9Sstevel@tonic-gate 	case T_LIST:
6507c478bd9Sstevel@tonic-gate 	case T_AND:
6517c478bd9Sstevel@tonic-gate 	case T_OR:
6527c478bd9Sstevel@tonic-gate 	case T_NOT:
6537c478bd9Sstevel@tonic-gate 	case T_ADD:
6547c478bd9Sstevel@tonic-gate 	case T_SUB:
6557c478bd9Sstevel@tonic-gate 	case T_MUL:
6567c478bd9Sstevel@tonic-gate 	case T_DIV:
6577c478bd9Sstevel@tonic-gate 	case T_MOD:
6587c478bd9Sstevel@tonic-gate 	case T_LT:
6597c478bd9Sstevel@tonic-gate 	case T_LE:
6607c478bd9Sstevel@tonic-gate 	case T_GT:
6617c478bd9Sstevel@tonic-gate 	case T_GE:
6627c478bd9Sstevel@tonic-gate 	case T_BITAND:
6637c478bd9Sstevel@tonic-gate 	case T_BITOR:
6647c478bd9Sstevel@tonic-gate 	case T_BITXOR:
6657c478bd9Sstevel@tonic-gate 	case T_BITNOT:
6667c478bd9Sstevel@tonic-gate 	case T_LSHIFT:
6677c478bd9Sstevel@tonic-gate 	case T_RSHIFT:
6687c478bd9Sstevel@tonic-gate 	case T_CONDIF:
6697c478bd9Sstevel@tonic-gate 	case T_CONDELSE:
6707c478bd9Sstevel@tonic-gate 		check_exprscope(np->u.expr.left, ex);
6717c478bd9Sstevel@tonic-gate 		check_exprscope(np->u.expr.right, ex);
6727c478bd9Sstevel@tonic-gate 		break;
6737c478bd9Sstevel@tonic-gate 
6747c478bd9Sstevel@tonic-gate 	case T_FUNC:
6757c478bd9Sstevel@tonic-gate 		check_exprscope(np->u.func.arglist, ex);
6767c478bd9Sstevel@tonic-gate 		break;
6777c478bd9Sstevel@tonic-gate 
6787c478bd9Sstevel@tonic-gate 	case T_NUM:
6797c478bd9Sstevel@tonic-gate 	case T_TIMEVAL:
6807c478bd9Sstevel@tonic-gate 		break;
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate 	default:
6837c478bd9Sstevel@tonic-gate 		outfl(O_DIE, np->file, np->line,
6847c478bd9Sstevel@tonic-gate 		    "check_exprscope: internal error: unexpected type: %s",
6857c478bd9Sstevel@tonic-gate 		    ptree_nodetype2str(np->t));
6867c478bd9Sstevel@tonic-gate 	}
6877c478bd9Sstevel@tonic-gate }
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate /*
6907c478bd9Sstevel@tonic-gate  * check_propscope -- check constraints for out of scope variable refs
6917c478bd9Sstevel@tonic-gate  */
6927c478bd9Sstevel@tonic-gate void
check_propscope(struct node * np)6937c478bd9Sstevel@tonic-gate check_propscope(struct node *np)
6947c478bd9Sstevel@tonic-gate {
6957c478bd9Sstevel@tonic-gate 	struct lut *ex;
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate 	ex = record_iterators(np, NULL);
6987c478bd9Sstevel@tonic-gate 	check_exprscope(np, ex);
6997c478bd9Sstevel@tonic-gate 	lut_free(ex, NULL, NULL);
7007c478bd9Sstevel@tonic-gate }
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate /*
7037c478bd9Sstevel@tonic-gate  * check_upset_engine -- validate the engine property in an upset statement
7047c478bd9Sstevel@tonic-gate  *
7057c478bd9Sstevel@tonic-gate  * we do this after the full parse tree has been constructed rather than while
7067c478bd9Sstevel@tonic-gate  * building the parse tree because it is inconvenient for the user if we
7077c478bd9Sstevel@tonic-gate  * require SERD engines to be declared before used in an upset "engine"
7087c478bd9Sstevel@tonic-gate  * property.
7097c478bd9Sstevel@tonic-gate  */
7107c478bd9Sstevel@tonic-gate 
7117c478bd9Sstevel@tonic-gate /*ARGSUSED*/
7127c478bd9Sstevel@tonic-gate void
check_upset_engine(struct node * lhs,struct node * rhs,void * arg)7137c478bd9Sstevel@tonic-gate check_upset_engine(struct node *lhs, struct node *rhs, void *arg)
7147c478bd9Sstevel@tonic-gate {
7157c478bd9Sstevel@tonic-gate 	enum nodetype t = (enum nodetype)arg;
7167c478bd9Sstevel@tonic-gate 	struct node *engnp;
7177c478bd9Sstevel@tonic-gate 	struct node *declp;
7187c478bd9Sstevel@tonic-gate 
7197c478bd9Sstevel@tonic-gate 	ASSERTeq(rhs->t, t, ptree_nodetype2str);
7207c478bd9Sstevel@tonic-gate 
7217c478bd9Sstevel@tonic-gate 	if ((engnp = tree_s2np_lut_lookup(rhs->u.stmt.lutp, L_engine)) == NULL)
7227c478bd9Sstevel@tonic-gate 		return;
7237c478bd9Sstevel@tonic-gate 
7247c478bd9Sstevel@tonic-gate 	ASSERT(engnp->t == T_EVENT);
7257c478bd9Sstevel@tonic-gate 
7267c478bd9Sstevel@tonic-gate 	if ((declp = tree_event2np_lut_lookup(SERDs, engnp)) == NULL) {
7277c478bd9Sstevel@tonic-gate 		outfl(O_ERR, engnp->file, engnp->line,
7287c478bd9Sstevel@tonic-gate 		    "%s %s property contains undeclared name",
7297c478bd9Sstevel@tonic-gate 		    ptree_nodetype2str(t), L_engine);
7307c478bd9Sstevel@tonic-gate 		return;
7317c478bd9Sstevel@tonic-gate 	}
7327c478bd9Sstevel@tonic-gate 	engnp->u.event.declp = declp;
7337c478bd9Sstevel@tonic-gate }
7347c478bd9Sstevel@tonic-gate 
7357c478bd9Sstevel@tonic-gate /*
7367c478bd9Sstevel@tonic-gate  * check_refcount -- see if declared names are used
7377c478bd9Sstevel@tonic-gate  *
7387c478bd9Sstevel@tonic-gate  * this is run after the entire parse tree is constructed, so a refcount
7397c478bd9Sstevel@tonic-gate  * of zero means the name has been declared but otherwise not used.
7407c478bd9Sstevel@tonic-gate  */
7417c478bd9Sstevel@tonic-gate 
7427c478bd9Sstevel@tonic-gate void
check_refcount(struct node * lhs,struct node * rhs,void * arg)7437c478bd9Sstevel@tonic-gate check_refcount(struct node *lhs, struct node *rhs, void *arg)
7447c478bd9Sstevel@tonic-gate {
7457c478bd9Sstevel@tonic-gate 	enum nodetype t = (enum nodetype)arg;
7467c478bd9Sstevel@tonic-gate 
7477c478bd9Sstevel@tonic-gate 	ASSERTeq(rhs->t, t, ptree_nodetype2str);
7487c478bd9Sstevel@tonic-gate 
7497c478bd9Sstevel@tonic-gate 	if (rhs->u.stmt.flags & STMT_REF)
7507c478bd9Sstevel@tonic-gate 		return;
7517c478bd9Sstevel@tonic-gate 
7527c478bd9Sstevel@tonic-gate 	outfl(O_WARN|O_NONL, rhs->file, rhs->line,
7537c478bd9Sstevel@tonic-gate 	    "%s name declared but not used: ", ptree_nodetype2str(t));
7547c478bd9Sstevel@tonic-gate 	ptree_name(O_WARN|O_NONL, lhs);
7557c478bd9Sstevel@tonic-gate 	out(O_WARN, NULL);
7567c478bd9Sstevel@tonic-gate }
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate /*
7597c478bd9Sstevel@tonic-gate  * set check_cycle_warninglevel only for val >= 0
7607c478bd9Sstevel@tonic-gate  */
7617c478bd9Sstevel@tonic-gate int
check_cycle_level(long long val)7627c478bd9Sstevel@tonic-gate check_cycle_level(long long val)
7637c478bd9Sstevel@tonic-gate {
7647c478bd9Sstevel@tonic-gate 	static int check_cycle_warninglevel = -1;
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate 	if (val == 0)
7677c478bd9Sstevel@tonic-gate 		check_cycle_warninglevel = 0;
7687c478bd9Sstevel@tonic-gate 	else if (val > 0)
7697c478bd9Sstevel@tonic-gate 		check_cycle_warninglevel = 1;
7707c478bd9Sstevel@tonic-gate 
7717c478bd9Sstevel@tonic-gate 	return (check_cycle_warninglevel);
7727c478bd9Sstevel@tonic-gate }
7737c478bd9Sstevel@tonic-gate 
7747c478bd9Sstevel@tonic-gate /*
7757c478bd9Sstevel@tonic-gate  * check_cycle -- see props from an error have cycles
7767c478bd9Sstevel@tonic-gate  *
7777c478bd9Sstevel@tonic-gate  * this is run after the entire parse tree is constructed, for
7787c478bd9Sstevel@tonic-gate  * each error that has been declared.
7797c478bd9Sstevel@tonic-gate  */
7807c478bd9Sstevel@tonic-gate 
7817c478bd9Sstevel@tonic-gate /*ARGSUSED*/
7827c478bd9Sstevel@tonic-gate void
check_cycle(struct node * lhs,struct node * rhs,void * arg)7837c478bd9Sstevel@tonic-gate check_cycle(struct node *lhs, struct node *rhs, void *arg)
7847c478bd9Sstevel@tonic-gate {
7857c478bd9Sstevel@tonic-gate 	struct node *np;
7867c478bd9Sstevel@tonic-gate 
7877c478bd9Sstevel@tonic-gate 	ASSERTeq(rhs->t, T_ERROR, ptree_nodetype2str);
7887c478bd9Sstevel@tonic-gate 
7897c478bd9Sstevel@tonic-gate 	if (rhs->u.stmt.flags & STMT_CYCLE)
7907c478bd9Sstevel@tonic-gate 		return;		/* already reported this cycle */
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate 	if (rhs->u.stmt.flags & STMT_CYMARK) {
7937c478bd9Sstevel@tonic-gate #ifdef ESC
7947c478bd9Sstevel@tonic-gate 		int warninglevel;
7957c478bd9Sstevel@tonic-gate 
7967c478bd9Sstevel@tonic-gate 		warninglevel = check_cycle_level(-1);
7977c478bd9Sstevel@tonic-gate 		if (warninglevel <= 0) {
7987c478bd9Sstevel@tonic-gate 			int olevel = O_ERR;
7997c478bd9Sstevel@tonic-gate 
8007c478bd9Sstevel@tonic-gate 			if (warninglevel == 0)
8017c478bd9Sstevel@tonic-gate 				olevel = O_WARN;
8027c478bd9Sstevel@tonic-gate 
8037c478bd9Sstevel@tonic-gate 			out(olevel|O_NONL, "cycle in propagation tree: ");
8047c478bd9Sstevel@tonic-gate 			ptree_name(olevel|O_NONL, rhs->u.stmt.np);
8057c478bd9Sstevel@tonic-gate 			out(olevel, NULL);
8067c478bd9Sstevel@tonic-gate 		}
8077c478bd9Sstevel@tonic-gate #endif /* ESC */
8087c478bd9Sstevel@tonic-gate 
8097c478bd9Sstevel@tonic-gate 		rhs->u.stmt.flags |= STMT_CYCLE;
8107c478bd9Sstevel@tonic-gate 	}
8117c478bd9Sstevel@tonic-gate 
8127c478bd9Sstevel@tonic-gate 	rhs->u.stmt.flags |= STMT_CYMARK;
8137c478bd9Sstevel@tonic-gate 
8147c478bd9Sstevel@tonic-gate 	/* for each propagation */
8157c478bd9Sstevel@tonic-gate 	for (np = Props; np; np = np->u.stmt.next)
8167c478bd9Sstevel@tonic-gate 		check_cycle_lhs(rhs, np->u.stmt.np);
8177c478bd9Sstevel@tonic-gate 
8187c478bd9Sstevel@tonic-gate 	rhs->u.stmt.flags &= ~STMT_CYMARK;
8197c478bd9Sstevel@tonic-gate }
8207c478bd9Sstevel@tonic-gate 
8217c478bd9Sstevel@tonic-gate /*
8227c478bd9Sstevel@tonic-gate  * check_cycle_lhs -- find the lhs of an arrow for cycle checking
8237c478bd9Sstevel@tonic-gate  */
8247c478bd9Sstevel@tonic-gate 
8257c478bd9Sstevel@tonic-gate static void
check_cycle_lhs(struct node * stmtnp,struct node * arrow)8267c478bd9Sstevel@tonic-gate check_cycle_lhs(struct node *stmtnp, struct node *arrow)
8277c478bd9Sstevel@tonic-gate {
8287c478bd9Sstevel@tonic-gate 	struct node *trylhs;
8297c478bd9Sstevel@tonic-gate 	struct node *tryrhs;
8307c478bd9Sstevel@tonic-gate 
8317c478bd9Sstevel@tonic-gate 	/* handle cascaded arrows */
8327c478bd9Sstevel@tonic-gate 	switch (arrow->u.arrow.lhs->t) {
8337c478bd9Sstevel@tonic-gate 	case T_ARROW:
8347c478bd9Sstevel@tonic-gate 		/* first recurse left */
8357c478bd9Sstevel@tonic-gate 		check_cycle_lhs(stmtnp, arrow->u.arrow.lhs);
8367c478bd9Sstevel@tonic-gate 
837f358d892Srw 		/*
838f358d892Srw 		 * return if there's a list of events internal to
839f358d892Srw 		 * cascaded props (which is not allowed)
8407aec1d6eScindi 		 */
841f358d892Srw 		if (arrow->u.arrow.lhs->u.arrow.rhs->t != T_EVENT)
842f358d892Srw 			return;
8437c478bd9Sstevel@tonic-gate 
8447c478bd9Sstevel@tonic-gate 		/* then try this arrow (thing cascaded *to*) */
8457c478bd9Sstevel@tonic-gate 		trylhs = arrow->u.arrow.lhs->u.arrow.rhs;
8467c478bd9Sstevel@tonic-gate 		tryrhs = arrow->u.arrow.rhs;
8477c478bd9Sstevel@tonic-gate 		break;
8487c478bd9Sstevel@tonic-gate 
8497c478bd9Sstevel@tonic-gate 	case T_EVENT:
8507c478bd9Sstevel@tonic-gate 	case T_LIST:
8517c478bd9Sstevel@tonic-gate 		trylhs = arrow->u.arrow.lhs;
8527c478bd9Sstevel@tonic-gate 		tryrhs = arrow->u.arrow.rhs;
8537c478bd9Sstevel@tonic-gate 		break;
8547c478bd9Sstevel@tonic-gate 
8557c478bd9Sstevel@tonic-gate 	default:
8567c478bd9Sstevel@tonic-gate 		out(O_DIE, "lhs: unexpected type: %s",
8577c478bd9Sstevel@tonic-gate 		    ptree_nodetype2str(arrow->u.arrow.lhs->t));
8587c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
8597c478bd9Sstevel@tonic-gate 	}
8607c478bd9Sstevel@tonic-gate 
8617c478bd9Sstevel@tonic-gate 	check_cycle_lhs_try(stmtnp, trylhs, tryrhs);
8627c478bd9Sstevel@tonic-gate }
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate /*
8657c478bd9Sstevel@tonic-gate  * check_cycle_lhs_try -- try matching an event name on lhs of an arrow
8667c478bd9Sstevel@tonic-gate  */
8677c478bd9Sstevel@tonic-gate 
8687c478bd9Sstevel@tonic-gate static void
check_cycle_lhs_try(struct node * stmtnp,struct node * lhs,struct node * rhs)8697c478bd9Sstevel@tonic-gate check_cycle_lhs_try(struct node *stmtnp, struct node *lhs, struct node *rhs)
8707c478bd9Sstevel@tonic-gate {
8717c478bd9Sstevel@tonic-gate 	if (lhs->t == T_LIST) {
8727c478bd9Sstevel@tonic-gate 		check_cycle_lhs_try(stmtnp, lhs->u.expr.left, rhs);
8737c478bd9Sstevel@tonic-gate 		check_cycle_lhs_try(stmtnp, lhs->u.expr.right, rhs);
8747c478bd9Sstevel@tonic-gate 		return;
8757c478bd9Sstevel@tonic-gate 	}
8767c478bd9Sstevel@tonic-gate 
8777c478bd9Sstevel@tonic-gate 	ASSERT(lhs->t == T_EVENT);
8787c478bd9Sstevel@tonic-gate 
8797c478bd9Sstevel@tonic-gate 	if (tree_eventcmp(stmtnp->u.stmt.np, lhs) != 0)
8807c478bd9Sstevel@tonic-gate 		return;		/* no match */
8817c478bd9Sstevel@tonic-gate 
8827c478bd9Sstevel@tonic-gate 	check_cycle_rhs(rhs);
8837c478bd9Sstevel@tonic-gate }
8847c478bd9Sstevel@tonic-gate 
8857c478bd9Sstevel@tonic-gate /*
8867c478bd9Sstevel@tonic-gate  * check_cycle_rhs -- foreach error on rhs, see if we cycle to a marked error
8877c478bd9Sstevel@tonic-gate  */
8887c478bd9Sstevel@tonic-gate 
8897c478bd9Sstevel@tonic-gate static void
check_cycle_rhs(struct node * rhs)8907c478bd9Sstevel@tonic-gate check_cycle_rhs(struct node *rhs)
8917c478bd9Sstevel@tonic-gate {
8927c478bd9Sstevel@tonic-gate 	struct node *dnp;
8937c478bd9Sstevel@tonic-gate 
8947c478bd9Sstevel@tonic-gate 	if (rhs->t == T_LIST) {
8957c478bd9Sstevel@tonic-gate 		check_cycle_rhs(rhs->u.expr.left);
8967c478bd9Sstevel@tonic-gate 		check_cycle_rhs(rhs->u.expr.right);
8977c478bd9Sstevel@tonic-gate 		return;
8987c478bd9Sstevel@tonic-gate 	}
8997c478bd9Sstevel@tonic-gate 
9007c478bd9Sstevel@tonic-gate 	ASSERT(rhs->t == T_EVENT);
9017c478bd9Sstevel@tonic-gate 
9027c478bd9Sstevel@tonic-gate 	if (rhs->u.event.ename->u.name.t != N_ERROR)
9037c478bd9Sstevel@tonic-gate 		return;
9047c478bd9Sstevel@tonic-gate 
9057c478bd9Sstevel@tonic-gate 	if ((dnp = tree_event2np_lut_lookup(Errors, rhs)) == NULL) {
9067c478bd9Sstevel@tonic-gate 		outfl(O_ERR|O_NONL,
9077c478bd9Sstevel@tonic-gate 		    rhs->file, rhs->line,
9087c478bd9Sstevel@tonic-gate 		    "unexpected undeclared event during cycle check");
9097c478bd9Sstevel@tonic-gate 		ptree_name(O_ERR|O_NONL, rhs);
9107c478bd9Sstevel@tonic-gate 		out(O_ERR, NULL);
9117c478bd9Sstevel@tonic-gate 		return;
9127c478bd9Sstevel@tonic-gate 	}
9137c478bd9Sstevel@tonic-gate 	check_cycle(NULL, dnp, 0);
9147c478bd9Sstevel@tonic-gate }
9157c478bd9Sstevel@tonic-gate 
9167c478bd9Sstevel@tonic-gate /*
9177c478bd9Sstevel@tonic-gate  * Force iterators to be simple names, expressions, or numbers
9187c478bd9Sstevel@tonic-gate  */
9197c478bd9Sstevel@tonic-gate void
check_name_iterator(struct node * np)9207c478bd9Sstevel@tonic-gate check_name_iterator(struct node *np)
9217c478bd9Sstevel@tonic-gate {
9227c478bd9Sstevel@tonic-gate 	if (np->u.name.child->t != T_NUM &&
9237c478bd9Sstevel@tonic-gate 	    np->u.name.child->t != T_NAME &&
9247c478bd9Sstevel@tonic-gate 	    np->u.name.child->t != T_CONDIF &&
9257c478bd9Sstevel@tonic-gate 	    np->u.name.child->t != T_SUB &&
9267c478bd9Sstevel@tonic-gate 	    np->u.name.child->t != T_ADD &&
9277c478bd9Sstevel@tonic-gate 	    np->u.name.child->t != T_MUL &&
9287c478bd9Sstevel@tonic-gate 	    np->u.name.child->t != T_DIV &&
9297c478bd9Sstevel@tonic-gate 	    np->u.name.child->t != T_MOD &&
9307c478bd9Sstevel@tonic-gate 	    np->u.name.child->t != T_LSHIFT &&
9317c478bd9Sstevel@tonic-gate 	    np->u.name.child->t != T_RSHIFT) {
9327c478bd9Sstevel@tonic-gate 		outfl(O_ERR|O_NONL, np->file, np->line,
9337c478bd9Sstevel@tonic-gate 		"invalid iterator: ");
9347c478bd9Sstevel@tonic-gate 		ptree_name_iter(O_ERR|O_NONL, np);
9357c478bd9Sstevel@tonic-gate 		out(O_ERR, NULL);
9367c478bd9Sstevel@tonic-gate 	}
9377c478bd9Sstevel@tonic-gate }
9387c478bd9Sstevel@tonic-gate 
9397c478bd9Sstevel@tonic-gate /*
9407c478bd9Sstevel@tonic-gate  * Iterators on a declaration may only be implicit
9417c478bd9Sstevel@tonic-gate  */
9427c478bd9Sstevel@tonic-gate void
check_type_iterator(struct node * np)9437c478bd9Sstevel@tonic-gate check_type_iterator(struct node *np)
9447c478bd9Sstevel@tonic-gate {
9457c478bd9Sstevel@tonic-gate 	while (np != NULL) {
9467c478bd9Sstevel@tonic-gate 		if (np->t == T_EVENT) {
9477c478bd9Sstevel@tonic-gate 			np = np->u.event.epname;
9487c478bd9Sstevel@tonic-gate 		} else if (np->t == T_NAME) {
9497c478bd9Sstevel@tonic-gate 			if (np->u.name.child != NULL &&
9507c478bd9Sstevel@tonic-gate 			    np->u.name.child->t != T_NUM) {
9517c478bd9Sstevel@tonic-gate 				outfl(O_ERR|O_NONL, np->file, np->line,
9527c478bd9Sstevel@tonic-gate 				    "explicit iterators disallowed "
9537c478bd9Sstevel@tonic-gate 				    "in declarations: ");
9547c478bd9Sstevel@tonic-gate 				ptree_name_iter(O_ERR|O_NONL, np);
9557c478bd9Sstevel@tonic-gate 				out(O_ERR, NULL);
9567c478bd9Sstevel@tonic-gate 			}
9577c478bd9Sstevel@tonic-gate 			np = np->u.name.next;
9587c478bd9Sstevel@tonic-gate 		} else {
9597c478bd9Sstevel@tonic-gate 			break;
9607c478bd9Sstevel@tonic-gate 		}
9617c478bd9Sstevel@tonic-gate 	}
9627c478bd9Sstevel@tonic-gate }
9637c478bd9Sstevel@tonic-gate 
964*b0daa853SStephen Hanson void
check_cat_list(struct node * np)965*b0daa853SStephen Hanson check_cat_list(struct node *np)
966*b0daa853SStephen Hanson {
967*b0daa853SStephen Hanson 	if (np->t == T_FUNC)
968*b0daa853SStephen Hanson 		check_func(np);
969*b0daa853SStephen Hanson 	else if (np->t == T_LIST) {
970*b0daa853SStephen Hanson 		check_cat_list(np->u.expr.left);
971*b0daa853SStephen Hanson 		check_cat_list(np->u.expr.right);
972*b0daa853SStephen Hanson 	}
973*b0daa853SStephen Hanson }
974*b0daa853SStephen Hanson 
9757c478bd9Sstevel@tonic-gate void
check_func(struct node * np)9767c478bd9Sstevel@tonic-gate check_func(struct node *np)
9777c478bd9Sstevel@tonic-gate {
978ae223a06Scth 	struct node *arglist = np->u.func.arglist;
979ae223a06Scth 
9807c478bd9Sstevel@tonic-gate 	ASSERTinfo(np->t == T_FUNC, ptree_nodetype2str(np->t));
9817c478bd9Sstevel@tonic-gate 
9827c478bd9Sstevel@tonic-gate 	if (np->u.func.s == L_within) {
9837c478bd9Sstevel@tonic-gate 		switch (arglist->t) {
984ae223a06Scth 		case T_NUM:
985ae223a06Scth 			if (arglist->u.ull != 0ULL) {
986ae223a06Scth 				outfl(O_ERR, arglist->file, arglist->line,
987ae223a06Scth 				    "parameter of within must be 0"
988ae223a06Scth 				    ", \"infinity\" or a time value.");
989ae223a06Scth 			}
990ae223a06Scth 			break;
991ae223a06Scth 
992ae223a06Scth 		case T_NAME:
993ae223a06Scth 			if (arglist->u.name.s != L_infinity) {
994ae223a06Scth 				outfl(O_ERR, arglist->file, arglist->line,
995ae223a06Scth 				    "parameter of within must be 0"
996ae223a06Scth 				    ", \"infinity\" or a time value.");
997ae223a06Scth 			}
998ae223a06Scth 			break;
999ae223a06Scth 
1000ae223a06Scth 		case T_LIST:
1001ae223a06Scth 			/*
1002ae223a06Scth 			 * if two parameters, the left or min must be
1003ae223a06Scth 			 * either T_NUM or T_TIMEVAL
1004ae223a06Scth 			 */
1005ae223a06Scth 			if (arglist->u.expr.left->t != T_NUM &&
1006ae223a06Scth 			    arglist->u.expr.left->t != T_TIMEVAL) {
1007ae223a06Scth 				outfl(O_ERR, arglist->file, arglist->line,
1008ae223a06Scth 				    "first parameter of within must be"
1009ae223a06Scth 				    " either a time value or zero.");
1010ae223a06Scth 			}
10117c478bd9Sstevel@tonic-gate 
1012602ca9eaScth 			/*
1013602ca9eaScth 			 * if two parameters, the right or max must
1014602ca9eaScth 			 * be either T_NUM, T_NAME or T_TIMEVAL
1015602ca9eaScth 			 */
1016602ca9eaScth 			if (arglist->u.expr.right->t != T_NUM &&
1017602ca9eaScth 			    arglist->u.expr.right->t != T_TIMEVAL &&
1018ae223a06Scth 			    arglist->u.expr.right->t != T_NAME) {
1019ae223a06Scth 				outfl(O_ERR, arglist->file, arglist->line,
1020602ca9eaScth 				    "second parameter of within must "
1021ae223a06Scth 				    "be 0, \"infinity\" or time value.");
1022ae223a06Scth 			}
1023ae223a06Scth 
1024ae223a06Scth 			/*
1025ae223a06Scth 			 * if right or left is a T_NUM it must
1026ae223a06Scth 			 * be zero
1027ae223a06Scth 			 */
1028ae223a06Scth 			if ((arglist->u.expr.left->t == T_NUM) &&
1029ae223a06Scth 			    (arglist->u.expr.left->u.ull != 0ULL)) {
1030ae223a06Scth 				outfl(O_ERR, arglist->file, arglist->line,
1031ae223a06Scth 				    "within parameter must be "
1032ae223a06Scth 				    "0 or a time value.");
1033ae223a06Scth 			}
1034ae223a06Scth 			if ((arglist->u.expr.right->t == T_NUM) &&
1035ae223a06Scth 			    (arglist->u.expr.right->u.ull != 0ULL)) {
1036ae223a06Scth 				outfl(O_ERR, arglist->file, arglist->line,
1037ae223a06Scth 				    "within parameter must be "
1038ae223a06Scth 				    "0 or a time value.");
1039ae223a06Scth 			}
1040ae223a06Scth 
1041ae223a06Scth 			/* if right is a T_NAME it must be "infinity" */
1042ae223a06Scth 			if ((arglist->u.expr.right->t == T_NAME) &&
1043ae223a06Scth 			    (arglist->u.expr.right->u.name.s != L_infinity)) {
1044ae223a06Scth 				outfl(O_ERR, arglist->file, arglist->line,
1045ae223a06Scth 				    "\"infinity\" is the only "
1046ae223a06Scth 				    "valid name for within parameter.");
1047ae223a06Scth 			}
10487c478bd9Sstevel@tonic-gate 
1049602ca9eaScth 			/*
1050602ca9eaScth 			 * the first parameter [min] must not be greater
1051602ca9eaScth 			 * than the second parameter [max].
1052602ca9eaScth 			 */
1053602ca9eaScth 			if (arglist->u.expr.left->u.ull >
1054ae223a06Scth 			    arglist->u.expr.right->u.ull) {
10557c478bd9Sstevel@tonic-gate 				outfl(O_ERR, arglist->file, arglist->line,
1056ae223a06Scth 				    "the first value (min) of"
1057ae223a06Scth 				    " within must be less than"
1058ae223a06Scth 				    " the second (max) value");
1059ae223a06Scth 			}
1060ae223a06Scth 			break;
1061ae223a06Scth 
1062ae223a06Scth 		case T_TIMEVAL:
1063ae223a06Scth 			break; /* no restrictions on T_TIMEVAL */
1064ae223a06Scth 
1065ae223a06Scth 		default:
1066ae223a06Scth 			outfl(O_ERR, arglist->file, arglist->line,
1067ae223a06Scth 			    "parameter of within must be 0"
1068ae223a06Scth 			    ", \"infinity\" or a time value.");
10697c478bd9Sstevel@tonic-gate 		}
10707c478bd9Sstevel@tonic-gate 	} else if (np->u.func.s == L_call) {
1071ae223a06Scth 		if (arglist->t != T_QUOTE &&
1072ae223a06Scth 		    arglist->t != T_LIST &&
1073ae223a06Scth 		    arglist->t != T_GLOBID &&
1074ae223a06Scth 		    arglist->t != T_CONDIF &&
1075ae223a06Scth 		    arglist->t != T_LIST &&
1076ae223a06Scth 		    arglist->t != T_FUNC)
1077ae223a06Scth 			outfl(O_ERR, arglist->file, arglist->line,
1078b1f905a8Scy 			    "invalid first argument to call()");
10797c478bd9Sstevel@tonic-gate 	} else if (np->u.func.s == L_fru) {
1080ae223a06Scth 		if (arglist->t != T_NAME)
1081ae223a06Scth 			outfl(O_ERR, arglist->file, arglist->line,
1082b1f905a8Scy 			    "argument to fru() must be a path");
10837c478bd9Sstevel@tonic-gate 	} else if (np->u.func.s == L_asru) {
1084ae223a06Scth 		if (arglist->t != T_NAME)
1085ae223a06Scth 			outfl(O_ERR, arglist->file, arglist->line,
1086b1f905a8Scy 			    "argument to asru() must be a path");
10877c478bd9Sstevel@tonic-gate 	} else if (np->u.func.s == L_is_connected ||
10887c478bd9Sstevel@tonic-gate 	    np->u.func.s == L_is_under) {
1089ae223a06Scth 		if (arglist->t == T_LIST &&
1090ae223a06Scth 		    (arglist->u.expr.left->t == T_NAME ||
1091*b0daa853SStephen Hanson 		    arglist->u.expr.left->t == T_FUNC) &&
1092ae223a06Scth 		    (arglist->u.expr.right->t == T_NAME ||
1093*b0daa853SStephen Hanson 		    arglist->u.expr.right->t == T_FUNC)) {
1094ae223a06Scth 			if (arglist->u.expr.left->t == T_FUNC)
1095ae223a06Scth 				check_func(arglist->u.expr.left);
1096ae223a06Scth 			if (arglist->u.expr.right->t == T_FUNC)
1097ae223a06Scth 				check_func(arglist->u.expr.right);
10987c478bd9Sstevel@tonic-gate 		} else {
1099ae223a06Scth 			outfl(O_ERR, arglist->file, arglist->line,
11007c478bd9Sstevel@tonic-gate 			    "%s() must have paths or calls to "
11017c478bd9Sstevel@tonic-gate 			    "fru() and/or asru() as arguments",
11027c478bd9Sstevel@tonic-gate 			    np->u.func.s);
11037c478bd9Sstevel@tonic-gate 		}
11047c478bd9Sstevel@tonic-gate 	} else if (np->u.func.s == L_is_on) {
1105*b0daa853SStephen Hanson 		if (arglist->t == T_NAME || arglist->t == T_FUNC) {
1106b7d3956bSstephh 			if (arglist->t == T_FUNC)
1107b7d3956bSstephh 				check_func(arglist);
11087c478bd9Sstevel@tonic-gate 		} else {
1109ae223a06Scth 			outfl(O_ERR, arglist->file, arglist->line,
1110b7d3956bSstephh 			    "argument to is_on() must be a path or a call to "
11117c478bd9Sstevel@tonic-gate 			    "fru() or asru()");
11127c478bd9Sstevel@tonic-gate 		}
11137c478bd9Sstevel@tonic-gate 	} else if (np->u.func.s == L_is_present) {
1114*b0daa853SStephen Hanson 		if (arglist->t == T_NAME || arglist->t == T_FUNC) {
1115b7d3956bSstephh 			if (arglist->t == T_FUNC)
1116b7d3956bSstephh 				check_func(arglist);
11177c478bd9Sstevel@tonic-gate 		} else {
1118ae223a06Scth 			outfl(O_ERR, arglist->file, arglist->line,
1119b7d3956bSstephh 			    "argument to is_present() must be a path or a call "
1120b7d3956bSstephh 			    "to fru() or asru()");
11217c478bd9Sstevel@tonic-gate 		}
112225c6ff4bSstephh 	} else if (np->u.func.s == L_has_fault) {
112325c6ff4bSstephh 		if (arglist->t == T_LIST &&
112425c6ff4bSstephh 		    (arglist->u.expr.left->t == T_NAME ||
1125*b0daa853SStephen Hanson 		    arglist->u.expr.left->t == T_FUNC) &&
112625c6ff4bSstephh 		    arglist->u.expr.right->t == T_QUOTE) {
112725c6ff4bSstephh 			if (arglist->u.expr.left->t == T_FUNC)
112825c6ff4bSstephh 				check_func(arglist->u.expr.left);
112925c6ff4bSstephh 		} else {
113025c6ff4bSstephh 			outfl(O_ERR, arglist->file, arglist->line,
113125c6ff4bSstephh 			    "%s() must have path or call to "
113225c6ff4bSstephh 			    "fru() and/or asru() as first argument; "
113325c6ff4bSstephh 			    "second argument must be a string", np->u.func.s);
113425c6ff4bSstephh 		}
11357c478bd9Sstevel@tonic-gate 	} else if (np->u.func.s == L_is_type) {
1136*b0daa853SStephen Hanson 		if (arglist->t == T_NAME || arglist->t == T_FUNC) {
1137b7d3956bSstephh 			if (arglist->t == T_FUNC)
1138b7d3956bSstephh 				check_func(arglist);
11397c478bd9Sstevel@tonic-gate 		} else {
1140ae223a06Scth 			outfl(O_ERR, arglist->file, arglist->line,
1141b7d3956bSstephh 			    "argument to is_type() must be a path or a call to "
11427c478bd9Sstevel@tonic-gate 			    "fru() or asru()");
11437c478bd9Sstevel@tonic-gate 		}
11447aec1d6eScindi 	} else if (np->u.func.s == L_confcall) {
1145ae223a06Scth 		if (arglist->t != T_QUOTE &&
1146ae223a06Scth 		    (arglist->t != T_LIST ||
1147ae223a06Scth 		    arglist->u.expr.left->t != T_QUOTE))
1148ae223a06Scth 			outfl(O_ERR, arglist->file, arglist->line,
11497aec1d6eScindi 			    "confcall(): first argument must be a string "
11507aec1d6eScindi 			    "(the name of the operation)");
11518a40a695Sgavinm 	} else if (np->u.func.s == L_confprop ||
11528a40a695Sgavinm 	    np->u.func.s == L_confprop_defined) {
1153ae223a06Scth 		if (arglist->t == T_LIST &&
1154b7d3956bSstephh 		    (arglist->u.expr.left->t == T_NAME ||
1155*b0daa853SStephen Hanson 		    arglist->u.expr.left->t == T_FUNC) &&
1156ae223a06Scth 		    arglist->u.expr.right->t == T_QUOTE) {
1157b7d3956bSstephh 			if (arglist->u.expr.left->t == T_FUNC)
1158b7d3956bSstephh 				check_func(arglist->u.expr.left);
11597c478bd9Sstevel@tonic-gate 		} else {
1160ae223a06Scth 			outfl(O_ERR, arglist->file, arglist->line,
1161b7d3956bSstephh 			    "%s(): first argument must be a path or a call to "
11627c478bd9Sstevel@tonic-gate 			    "fru() or asru(); "
11638a40a695Sgavinm 			    "second argument must be a string", np->u.func.s);
11647c478bd9Sstevel@tonic-gate 		}
11657aec1d6eScindi 	} else if (np->u.func.s == L_count) {
1166ae223a06Scth 		if (arglist->t != T_EVENT) {
1167ae223a06Scth 			outfl(O_ERR, arglist->file, arglist->line,
11687aec1d6eScindi 			    "count(): argument must be an engine name");
11697aec1d6eScindi 		}
11707aec1d6eScindi 	} else if (np->u.func.s == L_defined) {
1171ae223a06Scth 		if (arglist->t != T_GLOBID)
1172ae223a06Scth 			outfl(O_ERR, arglist->file, arglist->line,
1173b1f905a8Scy 			    "argument to defined() must be a global");
11747c478bd9Sstevel@tonic-gate 	} else if (np->u.func.s == L_payloadprop) {
1175ae223a06Scth 		if (arglist->t != T_QUOTE)
1176ae223a06Scth 			outfl(O_ERR, arglist->file, arglist->line,
1177b1f905a8Scy 			    "argument to payloadprop() must be a string");
11787aec1d6eScindi 	} else if (np->u.func.s == L_payloadprop_contains) {
1179ae223a06Scth 		if (arglist->t != T_LIST ||
1180ae223a06Scth 		    arglist->u.expr.left->t != T_QUOTE ||
1181ae223a06Scth 		    arglist->u.expr.right == NULL)
1182ae223a06Scth 			outfl(O_ERR, arglist->file, arglist->line,
11837aec1d6eScindi 			    "args to payloadprop_contains(): must be a quoted "
11847aec1d6eScindi 			    "string (property name) and an expression "
11857aec1d6eScindi 			    "(to match)");
11867aec1d6eScindi 	} else if (np->u.func.s == L_payloadprop_defined) {
1187ae223a06Scth 		if (arglist->t != T_QUOTE)
1188ae223a06Scth 			outfl(O_ERR, arglist->file, arglist->line,
11897aec1d6eScindi 			    "arg to payloadprop_defined(): must be a quoted "
11907aec1d6eScindi 			    "string");
11917aec1d6eScindi 	} else if (np->u.func.s == L_setpayloadprop) {
1192ae223a06Scth 		if (arglist->t == T_LIST &&
1193ae223a06Scth 		    arglist->u.expr.left->t == T_QUOTE) {
1194ae223a06Scth 			if (arglist->u.expr.right->t == T_FUNC)
1195ae223a06Scth 				check_func(arglist->u.expr.right);
11967aec1d6eScindi 		} else {
1197ae223a06Scth 			outfl(O_ERR, arglist->file, arglist->line,
11987aec1d6eScindi 			    "setpayloadprop(): "
11997aec1d6eScindi 			    "first arg must be a string, "
12007aec1d6eScindi 			    "second arg a value");
12017aec1d6eScindi 		}
1202b7d3956bSstephh 	} else if (np->u.func.s == L_setserdn || np->u.func.s == L_setserdt ||
1203b7d3956bSstephh 	    np->u.func.s == L_setserdsuffix || np->u.func.s ==
1204b7d3956bSstephh 	    L_setserdincrement) {
1205b7d3956bSstephh 		if (arglist->t == T_FUNC)
1206b7d3956bSstephh 			check_func(arglist);
1207*b0daa853SStephen Hanson 	} else if (np->u.func.s == L_cat) {
1208*b0daa853SStephen Hanson 		check_cat_list(arglist);
12097c478bd9Sstevel@tonic-gate 	} else if (np->u.func.s == L_envprop) {
1210ae223a06Scth 		if (arglist->t != T_QUOTE)
1211ae223a06Scth 			outfl(O_ERR, arglist->file, arglist->line,
1212b1f905a8Scy 			    "argument to envprop() must be a string");
12137c478bd9Sstevel@tonic-gate 	} else
12147c478bd9Sstevel@tonic-gate 		outfl(O_WARN, np->file, np->line,
1215b1f905a8Scy 		    "possible platform-specific function: %s",
1216b1f905a8Scy 		    np->u.func.s);
12177c478bd9Sstevel@tonic-gate }
12187c478bd9Sstevel@tonic-gate 
12197c478bd9Sstevel@tonic-gate void
check_expr(struct node * np)12207c478bd9Sstevel@tonic-gate check_expr(struct node *np)
12217c478bd9Sstevel@tonic-gate {
12227c478bd9Sstevel@tonic-gate 	ASSERT(np != NULL);
12237c478bd9Sstevel@tonic-gate 
12247c478bd9Sstevel@tonic-gate 	switch (np->t) {
12257c478bd9Sstevel@tonic-gate 	case T_ASSIGN:
12267c478bd9Sstevel@tonic-gate 		ASSERT(np->u.expr.left != NULL);
12277c478bd9Sstevel@tonic-gate 		if (np->u.expr.left->t != T_GLOBID)
12287c478bd9Sstevel@tonic-gate 			outfl(O_ERR, np->file, np->line,
12297c478bd9Sstevel@tonic-gate 			    "assignment only allowed to globals (e.g. $a)");
12307c478bd9Sstevel@tonic-gate 		break;
12317c478bd9Sstevel@tonic-gate 	}
12327c478bd9Sstevel@tonic-gate }
12337c478bd9Sstevel@tonic-gate 
12347c478bd9Sstevel@tonic-gate void
check_event(struct node * np)12357c478bd9Sstevel@tonic-gate check_event(struct node *np)
12367c478bd9Sstevel@tonic-gate {
12377c478bd9Sstevel@tonic-gate 	ASSERT(np != NULL);
12387aec1d6eScindi 	ASSERTinfo(np->t == T_EVENT, ptree_nodetype2str(np->t));
12397c478bd9Sstevel@tonic-gate 
12407c478bd9Sstevel@tonic-gate 	if (np->u.event.epname == NULL) {
12417c478bd9Sstevel@tonic-gate 		outfl(O_ERR|O_NONL, np->file, np->line,
12427c478bd9Sstevel@tonic-gate 		    "pathless events not allowed: ");
12437c478bd9Sstevel@tonic-gate 		ptree_name(O_ERR|O_NONL, np->u.event.ename);
12447c478bd9Sstevel@tonic-gate 		out(O_ERR, NULL);
12457c478bd9Sstevel@tonic-gate 	}
12467c478bd9Sstevel@tonic-gate }
12477c478bd9Sstevel@tonic-gate 
12487c478bd9Sstevel@tonic-gate /*
12497c478bd9Sstevel@tonic-gate  * check for properties that are required on declarations. This
12507c478bd9Sstevel@tonic-gate  * should be done after all declarations since they can be
12517c478bd9Sstevel@tonic-gate  * redeclared with a different set of properties.
12527c478bd9Sstevel@tonic-gate  */
12537c478bd9Sstevel@tonic-gate /*ARGSUSED*/
12547c478bd9Sstevel@tonic-gate void
check_required_props(struct node * lhs,struct node * rhs,void * arg)12557c478bd9Sstevel@tonic-gate check_required_props(struct node *lhs, struct node *rhs, void *arg)
12567c478bd9Sstevel@tonic-gate {
1257b1f905a8Scy 	ASSERTeq(rhs->t, (enum nodetype)arg, ptree_nodetype2str);
12587c478bd9Sstevel@tonic-gate 
12597c478bd9Sstevel@tonic-gate 	check_stmt_required_properties(rhs);
12607c478bd9Sstevel@tonic-gate }
1261f358d892Srw 
1262f358d892Srw /*
1263f358d892Srw  * check that cascading prop statements do not contain lists internally.
1264f358d892Srw  * the first and last event lists in the cascading prop may be single
1265f358d892Srw  * events or lists of events.
1266f358d892Srw  */
1267f358d892Srw /*ARGSUSED*/
1268f358d892Srw void
check_proplists(enum nodetype t,struct node * np)1269f358d892Srw check_proplists(enum nodetype t, struct node *np)
1270f358d892Srw {
1271f358d892Srw 	ASSERT(np->t == T_ARROW);
1272f358d892Srw 	/*
1273f358d892Srw 	 * not checking the right hand side of the top level prop
1274f358d892Srw 	 * since it is the last part of the propagation and can be
1275f358d892Srw 	 * an event or list of events
1276f358d892Srw 	 */
1277f358d892Srw 	check_proplists_lhs(t, np->u.arrow.lhs);
1278f358d892Srw }
1279f358d892Srw 
1280f358d892Srw /*ARGSUSED*/
1281f358d892Srw static void
check_proplists_lhs(enum nodetype t,struct node * lhs)1282f358d892Srw check_proplists_lhs(enum nodetype t, struct node *lhs)
1283f358d892Srw {
1284f358d892Srw 	if (lhs->t == T_ARROW) {
1285f358d892Srw 		if (lhs->u.arrow.rhs->t == T_LIST) {
1286f358d892Srw 			outfl(O_ERR, lhs->file, lhs->line,
1287b1f905a8Scy 			    "lists are not allowed internally on cascading %s",
1288b1f905a8Scy 			    (t == T_PROP) ? "propagations" : "masks");
1289f358d892Srw 		}
1290f358d892Srw 		check_proplists_lhs(t, lhs->u.arrow.lhs);
1291f358d892Srw 	}
1292f358d892Srw }
1293