xref: /onnv-gate/usr/src/cmd/fm/eversholt/common/check.c (revision 2869:324151eecd58)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*2869Sgavinm  * Common Development and Distribution License (the "License").
6*2869Sgavinm  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
221414Scindi  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  *
250Sstevel@tonic-gate  * check.c -- routines for checking the prop tree
260Sstevel@tonic-gate  *
270Sstevel@tonic-gate  * this module provides semantic checks on the parse tree.  most of
280Sstevel@tonic-gate  * these checks happen during the construction of the parse tree,
290Sstevel@tonic-gate  * when the various tree_X() routines call the various check_X()
300Sstevel@tonic-gate  * routines.  in a couple of special cases, a check function will
310Sstevel@tonic-gate  * process the parse tree after it has been fully constructed.  these
320Sstevel@tonic-gate  * cases are noted in the comments above the check function.
330Sstevel@tonic-gate  */
340Sstevel@tonic-gate 
350Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
360Sstevel@tonic-gate 
370Sstevel@tonic-gate #include <stdio.h>
380Sstevel@tonic-gate #include "out.h"
390Sstevel@tonic-gate #include "stable.h"
400Sstevel@tonic-gate #include "literals.h"
410Sstevel@tonic-gate #include "lut.h"
420Sstevel@tonic-gate #include "tree.h"
430Sstevel@tonic-gate #include "ptree.h"
440Sstevel@tonic-gate #include "check.h"
450Sstevel@tonic-gate 
460Sstevel@tonic-gate static int check_reportlist(enum nodetype t, const char *s, struct node *np);
470Sstevel@tonic-gate static int check_num(enum nodetype t, const char *s, struct node *np);
480Sstevel@tonic-gate static int check_quote(enum nodetype t, const char *s, struct node *np);
491414Scindi static int check_action(enum nodetype t, const char *s, struct node *np);
500Sstevel@tonic-gate static int check_num_func(enum nodetype t, const char *s, struct node *np);
510Sstevel@tonic-gate static int check_fru_asru(enum nodetype t, const char *s, struct node *np);
520Sstevel@tonic-gate static int check_engine(enum nodetype t, const char *s, struct node *np);
531414Scindi static int check_count(enum nodetype t, const char *s, struct node *np);
540Sstevel@tonic-gate static int check_timeval(enum nodetype t, const char *s, struct node *np);
550Sstevel@tonic-gate static int check_id(enum nodetype t, const char *s, struct node *np);
560Sstevel@tonic-gate static int check_serd_method(enum nodetype t, const char *s, struct node *np);
571414Scindi static int check_serd_id(enum nodetype t, const char *s, struct node *np);
580Sstevel@tonic-gate static int check_nork(struct node *np);
590Sstevel@tonic-gate static void check_cycle_lhs(struct node *stmtnp, struct node *arrow);
600Sstevel@tonic-gate static void check_cycle_lhs_try(struct node *stmtnp, struct node *lhs,
610Sstevel@tonic-gate     struct node *rhs);
620Sstevel@tonic-gate static void check_cycle_rhs(struct node *rhs);
63854Srw145199 static void check_proplists_lhs(enum nodetype t, struct node *lhs);
640Sstevel@tonic-gate 
650Sstevel@tonic-gate static struct {
660Sstevel@tonic-gate 	enum nodetype t;
670Sstevel@tonic-gate 	const char *name;
680Sstevel@tonic-gate 	int required;
690Sstevel@tonic-gate 	int (*checker)(enum nodetype t, const char *s, struct node *np);
700Sstevel@tonic-gate 	int outflags;
710Sstevel@tonic-gate } Allowednames[] = {
720Sstevel@tonic-gate 	{ T_FAULT, "FITrate", 1, check_num_func, O_ERR },
730Sstevel@tonic-gate 	{ T_FAULT, "FRU", 0, check_fru_asru, O_ERR },
740Sstevel@tonic-gate 	{ T_FAULT, "ASRU", 0, check_fru_asru, O_ERR },
751414Scindi 	{ T_FAULT, "message", 0, check_num_func, O_ERR },
761414Scindi 	{ T_FAULT, "action", 0, check_action, O_ERR },
771414Scindi 	{ T_FAULT, "count", 0, check_count, O_ERR },
780Sstevel@tonic-gate 	{ T_UPSET, "engine", 0, check_engine, O_ERR },
790Sstevel@tonic-gate 	{ T_DEFECT, "FRU", 0, check_fru_asru, O_ERR },
800Sstevel@tonic-gate 	{ T_DEFECT, "ASRU", 0, check_fru_asru, O_ERR },
810Sstevel@tonic-gate 	{ T_EREPORT, "poller", 0, check_id, O_ERR },
820Sstevel@tonic-gate 	{ T_EREPORT, "delivery", 0, check_timeval, O_ERR },
830Sstevel@tonic-gate 	{ T_SERD, "N", 1, check_num, O_ERR },
840Sstevel@tonic-gate 	{ T_SERD, "T", 1, check_timeval, O_ERR },
850Sstevel@tonic-gate 	{ T_SERD, "method", 1, check_serd_method, O_ERR },
860Sstevel@tonic-gate 	{ T_SERD, "trip", 1, check_reportlist, O_ERR },
870Sstevel@tonic-gate 	{ T_SERD, "FRU", 0, check_fru_asru, O_ERR },
881414Scindi 	{ T_SERD, "id", 0, check_serd_id, O_ERR },
890Sstevel@tonic-gate 	{ T_ERROR, "ASRU", 0, check_fru_asru, O_ERR },
900Sstevel@tonic-gate 	{ T_CONFIG, NULL, 0, check_quote, O_ERR },
910Sstevel@tonic-gate 	{ 0, NULL, 0 },
920Sstevel@tonic-gate };
930Sstevel@tonic-gate 
940Sstevel@tonic-gate void
950Sstevel@tonic-gate check_init(void)
960Sstevel@tonic-gate {
970Sstevel@tonic-gate 	int i;
980Sstevel@tonic-gate 
990Sstevel@tonic-gate 	for (i = 0; Allowednames[i].t; i++)
1000Sstevel@tonic-gate 		if (Allowednames[i].name != NULL)
1010Sstevel@tonic-gate 			Allowednames[i].name = stable(Allowednames[i].name);
1020Sstevel@tonic-gate }
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate void
1050Sstevel@tonic-gate check_fini(void)
1060Sstevel@tonic-gate {
1070Sstevel@tonic-gate }
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate /*ARGSUSED*/
1100Sstevel@tonic-gate void
1110Sstevel@tonic-gate check_report_combination(struct node *np)
1120Sstevel@tonic-gate {
1130Sstevel@tonic-gate 	/* nothing to check for here.  poller is only prop and it is optional */
1140Sstevel@tonic-gate }
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate /*
1170Sstevel@tonic-gate  * check_path_iterators -- verify all iterators are explicit
1180Sstevel@tonic-gate  */
1190Sstevel@tonic-gate static void
1200Sstevel@tonic-gate check_path_iterators(struct node *np)
1210Sstevel@tonic-gate {
1220Sstevel@tonic-gate 	if (np == NULL)
1230Sstevel@tonic-gate 		return;
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate 	switch (np->t) {
1260Sstevel@tonic-gate 		case T_ARROW:
1270Sstevel@tonic-gate 			check_path_iterators(np->u.arrow.lhs);
1280Sstevel@tonic-gate 			check_path_iterators(np->u.arrow.rhs);
1290Sstevel@tonic-gate 			break;
1300Sstevel@tonic-gate 
1310Sstevel@tonic-gate 		case T_LIST:
1320Sstevel@tonic-gate 			check_path_iterators(np->u.expr.left);
1330Sstevel@tonic-gate 			check_path_iterators(np->u.expr.right);
1340Sstevel@tonic-gate 			break;
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate 		case T_EVENT:
1370Sstevel@tonic-gate 			check_path_iterators(np->u.event.epname);
1380Sstevel@tonic-gate 			break;
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate 		case T_NAME:
1410Sstevel@tonic-gate 			if (np->u.name.child == NULL)
1420Sstevel@tonic-gate 				outfl(O_DIE, np->file, np->line,
1430Sstevel@tonic-gate 				    "internal error: check_path_iterators: "
1440Sstevel@tonic-gate 				    "unexpected implicit iterator: %s",
1450Sstevel@tonic-gate 				    np->u.name.s);
1460Sstevel@tonic-gate 			check_path_iterators(np->u.name.next);
1470Sstevel@tonic-gate 			break;
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate 		default:
1500Sstevel@tonic-gate 			outfl(O_DIE, np->file, np->line,
1510Sstevel@tonic-gate 			    "internal error: check_path_iterators: "
1520Sstevel@tonic-gate 			    "unexpected type: %s",
1530Sstevel@tonic-gate 			    ptree_nodetype2str(np->t));
1540Sstevel@tonic-gate 	}
1550Sstevel@tonic-gate }
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate void
1580Sstevel@tonic-gate check_arrow(struct node *np)
1590Sstevel@tonic-gate {
1600Sstevel@tonic-gate 	ASSERTinfo(np->t == T_ARROW, ptree_nodetype2str(np->t));
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate 	if (np->u.arrow.lhs->t != T_ARROW &&
1630Sstevel@tonic-gate 	    np->u.arrow.lhs->t != T_LIST &&
1640Sstevel@tonic-gate 	    np->u.arrow.lhs->t != T_EVENT) {
1650Sstevel@tonic-gate 		outfl(O_ERR,
1660Sstevel@tonic-gate 		    np->u.arrow.lhs->file, np->u.arrow.lhs->line,
1670Sstevel@tonic-gate 		    "%s not allowed on left-hand side of arrow",
1680Sstevel@tonic-gate 		    ptree_nodetype2str(np->u.arrow.lhs->t));
1690Sstevel@tonic-gate 	}
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate 	if (!check_nork(np->u.arrow.nnp) ||
1720Sstevel@tonic-gate 		!check_nork(np->u.arrow.knp))
1730Sstevel@tonic-gate 			outfl(O_ERR, np->file, np->line,
1740Sstevel@tonic-gate 			    "counts associated with propagation arrows "
1750Sstevel@tonic-gate 			    "must be integers");
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate 	check_path_iterators(np);
1780Sstevel@tonic-gate }
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate /*
1810Sstevel@tonic-gate  * make sure the nork values are valid.
1820Sstevel@tonic-gate  * Nork values must be "A" for all(T_NAME),
1830Sstevel@tonic-gate  * a number(T_NUM), or a simple
1840Sstevel@tonic-gate  * expression(T_SUB, T_ADD, T_MUL, T_DIV)
1850Sstevel@tonic-gate  */
1860Sstevel@tonic-gate static int
1870Sstevel@tonic-gate check_nork(struct node *np)
1880Sstevel@tonic-gate {
1890Sstevel@tonic-gate 	int rval = 0;
1900Sstevel@tonic-gate 
1910Sstevel@tonic-gate 	/* NULL means no nork value which is allowed */
1920Sstevel@tonic-gate 	if (np == NULL) {
1930Sstevel@tonic-gate 		rval = 1;
1940Sstevel@tonic-gate 	}
1950Sstevel@tonic-gate 	else
1960Sstevel@tonic-gate 	{
1970Sstevel@tonic-gate 		/* if the nork is a name it must be A for "All" */
1980Sstevel@tonic-gate 		if (np->t == T_NAME)
1990Sstevel@tonic-gate 			if (*np->u.name.s == 'A')
2000Sstevel@tonic-gate 				return (1);
2010Sstevel@tonic-gate 
2020Sstevel@tonic-gate 		/*  T_NUM allowed */
2030Sstevel@tonic-gate 		if (np->t == T_NUM)
2040Sstevel@tonic-gate 			rval = 1;
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate 		/*  simple expressions allowed */
2070Sstevel@tonic-gate 		if (np->t == T_SUB ||
2080Sstevel@tonic-gate 			np->t == T_ADD ||
2090Sstevel@tonic-gate 			np->t == T_MUL ||
2100Sstevel@tonic-gate 			np->t == T_DIV)
2110Sstevel@tonic-gate 			rval = 1;
2120Sstevel@tonic-gate 	}
2130Sstevel@tonic-gate 
2140Sstevel@tonic-gate 	return (rval);
2150Sstevel@tonic-gate }
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate static int
2180Sstevel@tonic-gate check_reportlist(enum nodetype t, const char *s, struct node *np)
2190Sstevel@tonic-gate {
2200Sstevel@tonic-gate 	if (np == NULL)
2210Sstevel@tonic-gate 		return (1);
2220Sstevel@tonic-gate 	else if (np->t == T_EVENT) {
2230Sstevel@tonic-gate 		if (np->u.event.ename->u.name.t != N_EREPORT) {
2240Sstevel@tonic-gate 			outfl(O_ERR, np->file, np->line,
2250Sstevel@tonic-gate 			    "%s %s property must begin with \"ereport.\"",
2260Sstevel@tonic-gate 			    ptree_nodetype2str(t), s);
2270Sstevel@tonic-gate 		} else if (tree_event2np_lut_lookup(Ereports, np) == NULL) {
2280Sstevel@tonic-gate 			outfl(O_ERR, np->file, np->line,
2290Sstevel@tonic-gate 			    "%s %s property contains undeclared name",
2300Sstevel@tonic-gate 			    ptree_nodetype2str(t), s);
2310Sstevel@tonic-gate 		}
2320Sstevel@tonic-gate 		check_type_iterator(np);
2330Sstevel@tonic-gate 	} else if (np->t == T_LIST) {
2340Sstevel@tonic-gate 		(void) check_reportlist(t, s, np->u.expr.left);
2350Sstevel@tonic-gate 		(void) check_reportlist(t, s, np->u.expr.right);
2360Sstevel@tonic-gate 	}
2370Sstevel@tonic-gate 	return (1);
2380Sstevel@tonic-gate }
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate static int
2410Sstevel@tonic-gate check_num(enum nodetype t, const char *s, struct node *np)
2420Sstevel@tonic-gate {
2430Sstevel@tonic-gate 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
2440Sstevel@tonic-gate 	if (np->t != T_NUM)
2450Sstevel@tonic-gate 		outfl(O_ERR, np->file, np->line,
2460Sstevel@tonic-gate 		    "%s %s property must be a single number",
2470Sstevel@tonic-gate 		    ptree_nodetype2str(t), s);
2480Sstevel@tonic-gate 	return (1);
2490Sstevel@tonic-gate }
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate /*ARGSUSED1*/
2520Sstevel@tonic-gate static int
2530Sstevel@tonic-gate check_quote(enum nodetype t, const char *s, struct node *np)
2540Sstevel@tonic-gate {
2550Sstevel@tonic-gate 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
2560Sstevel@tonic-gate 	if (np->t != T_QUOTE)
2570Sstevel@tonic-gate 		outfl(O_ERR, np->file, np->line,
2580Sstevel@tonic-gate 		    "%s properties must be quoted strings",
2590Sstevel@tonic-gate 		    ptree_nodetype2str(t));
2600Sstevel@tonic-gate 	return (1);
2610Sstevel@tonic-gate }
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate static int
2641414Scindi check_action(enum nodetype t, const char *s, struct node *np)
2651414Scindi {
2661414Scindi 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
2671414Scindi 
2681414Scindi 	if (np->t != T_FUNC)
2691414Scindi 		outfl(O_ERR, np->file, np->line,
2701414Scindi 		    "%s %s property must be a function or list of functions",
2711414Scindi 		    ptree_nodetype2str(t), s);
2721414Scindi 	return (1);
2731414Scindi }
2741414Scindi 
2751414Scindi static int
2760Sstevel@tonic-gate check_num_func(enum nodetype t, const char *s, struct node *np)
2770Sstevel@tonic-gate {
2780Sstevel@tonic-gate 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
2790Sstevel@tonic-gate 	if (np->t != T_NUM && np->t != T_FUNC)
2800Sstevel@tonic-gate 		outfl(O_ERR, np->file, np->line,
2810Sstevel@tonic-gate 		    "%s %s property must be a number or function",
2820Sstevel@tonic-gate 		    ptree_nodetype2str(t), s);
2830Sstevel@tonic-gate 	return (1);
2840Sstevel@tonic-gate }
2850Sstevel@tonic-gate 
2860Sstevel@tonic-gate static int
2870Sstevel@tonic-gate check_fru_asru(enum nodetype t, const char *s, struct node *np)
2880Sstevel@tonic-gate {
2890Sstevel@tonic-gate 	ASSERT(s != NULL);
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate 	/* make sure it is a node type T_NAME? */
2920Sstevel@tonic-gate 	if (np->t == T_NAME) {
2930Sstevel@tonic-gate 	    if (s == L_ASRU) {
2940Sstevel@tonic-gate 		if (tree_name2np_lut_lookup_name(ASRUs, np) == NULL)
2950Sstevel@tonic-gate 			outfl(O_ERR, np->file, np->line,
2960Sstevel@tonic-gate 			    "ASRU property contains undeclared asru");
2970Sstevel@tonic-gate 	    } else if (s == L_FRU) {
2980Sstevel@tonic-gate 		if (tree_name2np_lut_lookup_name(FRUs, np) == NULL)
2990Sstevel@tonic-gate 			outfl(O_ERR, np->file, np->line,
3000Sstevel@tonic-gate 			    "FRU property contains undeclared fru");
3010Sstevel@tonic-gate 	    } else {
3020Sstevel@tonic-gate 		    outfl(O_ERR, np->file, np->line,
3030Sstevel@tonic-gate 			"illegal property name in %s declaration: %s",
3040Sstevel@tonic-gate 			ptree_nodetype2str(t), s);
3050Sstevel@tonic-gate 	    }
3060Sstevel@tonic-gate 	    check_type_iterator(np);
3070Sstevel@tonic-gate 	} else
3080Sstevel@tonic-gate 		outfl(O_ERR, np->file, np->line,
3090Sstevel@tonic-gate 		    "illegal type used for %s property: %s",
3100Sstevel@tonic-gate 		    s, ptree_nodetype2str(np->t));
3110Sstevel@tonic-gate 	return (1);
3120Sstevel@tonic-gate }
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate static int
3150Sstevel@tonic-gate check_engine(enum nodetype t, const char *s, struct node *np)
3160Sstevel@tonic-gate {
3170Sstevel@tonic-gate 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
3180Sstevel@tonic-gate 	if (np->t != T_EVENT)
3190Sstevel@tonic-gate 		outfl(O_ERR, np->file, np->line,
3200Sstevel@tonic-gate 		    "%s %s property must be an engine name "
3210Sstevel@tonic-gate 		    "(i.e. serd.x or serd.x@a/b)",
3220Sstevel@tonic-gate 		    ptree_nodetype2str(t), s);
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate 	return (1);
3250Sstevel@tonic-gate }
3260Sstevel@tonic-gate 
3270Sstevel@tonic-gate static int
3281414Scindi check_count(enum nodetype t, const char *s, struct node *np)
3291414Scindi {
3301414Scindi 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
3311414Scindi 	if (np->t != T_EVENT)
3321414Scindi 		outfl(O_ERR, np->file, np->line,
3331414Scindi 		    "%s %s property must be an engine name "
3341414Scindi 		    "(i.e. stat.x or stat.x@a/b)",
3351414Scindi 		    ptree_nodetype2str(t), s);
3361414Scindi 
3371414Scindi 	/* XXX confirm engine has been declared */
3381414Scindi 	return (1);
3391414Scindi }
3401414Scindi 
3411414Scindi static int
3420Sstevel@tonic-gate check_timeval(enum nodetype t, const char *s, struct node *np)
3430Sstevel@tonic-gate {
3440Sstevel@tonic-gate 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
3450Sstevel@tonic-gate 	if (np->t != T_TIMEVAL)
3460Sstevel@tonic-gate 		outfl(O_ERR, np->file, np->line,
3470Sstevel@tonic-gate 		    "%s %s property must be a number with time units",
3480Sstevel@tonic-gate 		    ptree_nodetype2str(t), s);
3490Sstevel@tonic-gate 	return (1);
3500Sstevel@tonic-gate }
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate static int
3530Sstevel@tonic-gate check_id(enum nodetype t, const char *s, struct node *np)
3540Sstevel@tonic-gate {
3550Sstevel@tonic-gate 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
3560Sstevel@tonic-gate 	if (np->t != T_NAME || np->u.name.next || np->u.name.child)
3570Sstevel@tonic-gate 		outfl(O_ERR, np->file, np->line,
3580Sstevel@tonic-gate 		    "%s %s property must be simple name",
3590Sstevel@tonic-gate 		    ptree_nodetype2str(t), s);
3600Sstevel@tonic-gate 	return (1);
3610Sstevel@tonic-gate }
3620Sstevel@tonic-gate 
3630Sstevel@tonic-gate static int
3640Sstevel@tonic-gate check_serd_method(enum nodetype t, const char *s, struct node *np)
3650Sstevel@tonic-gate {
3660Sstevel@tonic-gate 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
3670Sstevel@tonic-gate 	if (np->t != T_NAME || np->u.name.next || np->u.name.child ||
3680Sstevel@tonic-gate 	    (np->u.name.s != L_volatile &&
3690Sstevel@tonic-gate 	    np->u.name.s != L_persistent))
3700Sstevel@tonic-gate 		outfl(O_ERR, np->file, np->line,
3710Sstevel@tonic-gate 		    "%s %s property must be \"volatile\" or \"persistent\"",
3720Sstevel@tonic-gate 		    ptree_nodetype2str(t), s);
3730Sstevel@tonic-gate 	return (1);
3740Sstevel@tonic-gate }
3750Sstevel@tonic-gate 
3761414Scindi static int
3771414Scindi check_serd_id(enum nodetype t, const char *s, struct node *np)
3781414Scindi {
3791414Scindi 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
3801414Scindi 	if (np->t != T_GLOBID)
3811414Scindi 		outfl(O_ERR, np->file, np->line,
3821414Scindi 		    "%s %s property must be a global ID",
3831414Scindi 		    ptree_nodetype2str(t), s);
3841414Scindi 	return (1);
3851414Scindi }
3861414Scindi 
3870Sstevel@tonic-gate void
3880Sstevel@tonic-gate check_stmt_required_properties(struct node *stmtnp)
3890Sstevel@tonic-gate {
3900Sstevel@tonic-gate 	struct lut *lutp = stmtnp->u.stmt.lutp;
3910Sstevel@tonic-gate 	struct node *np = stmtnp->u.stmt.np;
3920Sstevel@tonic-gate 	int i;
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 	for (i = 0; Allowednames[i].t; i++)
3950Sstevel@tonic-gate 		if (stmtnp->t == Allowednames[i].t &&
3960Sstevel@tonic-gate 		    Allowednames[i].required &&
3970Sstevel@tonic-gate 		    tree_s2np_lut_lookup(lutp, Allowednames[i].name) == NULL)
3980Sstevel@tonic-gate 			outfl(Allowednames[i].outflags,
3990Sstevel@tonic-gate 			    np->file, np->line,
4000Sstevel@tonic-gate 			    "%s statement missing property: %s",
4010Sstevel@tonic-gate 			    ptree_nodetype2str(stmtnp->t),
4020Sstevel@tonic-gate 			    Allowednames[i].name);
4030Sstevel@tonic-gate }
4040Sstevel@tonic-gate 
4050Sstevel@tonic-gate void
4060Sstevel@tonic-gate check_stmt_allowed_properties(enum nodetype t,
4070Sstevel@tonic-gate     struct node *nvpairnp, struct lut *lutp)
4080Sstevel@tonic-gate {
4090Sstevel@tonic-gate 	int i;
4100Sstevel@tonic-gate 	const char *s = nvpairnp->u.expr.left->u.name.s;
4110Sstevel@tonic-gate 	struct node *np;
4120Sstevel@tonic-gate 
4130Sstevel@tonic-gate 	for (i = 0; Allowednames[i].t; i++)
4140Sstevel@tonic-gate 		if (t == Allowednames[i].t && Allowednames[i].name == NULL) {
4150Sstevel@tonic-gate 			/* NULL name means just call checker */
4160Sstevel@tonic-gate 			(*Allowednames[i].checker)(t, s,
4170Sstevel@tonic-gate 			    nvpairnp->u.expr.right);
4180Sstevel@tonic-gate 			return;
4190Sstevel@tonic-gate 		} else if (t == Allowednames[i].t && s == Allowednames[i].name)
4200Sstevel@tonic-gate 			break;
4210Sstevel@tonic-gate 	if (Allowednames[i].name == NULL)
4220Sstevel@tonic-gate 		outfl(O_ERR, nvpairnp->file, nvpairnp->line,
4230Sstevel@tonic-gate 		    "illegal property name in %s declaration: %s",
4240Sstevel@tonic-gate 		    ptree_nodetype2str(t), s);
4250Sstevel@tonic-gate 	else if ((np = tree_s2np_lut_lookup(lutp, s)) != NULL) {
4260Sstevel@tonic-gate 		/*
4270Sstevel@tonic-gate 		 * redeclaring prop is allowed if value is the same
4280Sstevel@tonic-gate 		 */
4290Sstevel@tonic-gate 		if (np->t != nvpairnp->u.expr.right->t)
4300Sstevel@tonic-gate 			outfl(O_ERR, nvpairnp->file, nvpairnp->line,
4310Sstevel@tonic-gate 			    "property redeclared (with differnt type) "
4320Sstevel@tonic-gate 			    "in %s declaration: %s",
4330Sstevel@tonic-gate 			    ptree_nodetype2str(t), s);
4340Sstevel@tonic-gate 		switch (np->t) {
4350Sstevel@tonic-gate 			case T_NUM:
4360Sstevel@tonic-gate 			case T_TIMEVAL:
4370Sstevel@tonic-gate 				if (np->u.ull == nvpairnp->u.expr.right->u.ull)
4380Sstevel@tonic-gate 					return;
4390Sstevel@tonic-gate 				break;
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 			case T_NAME:
4420Sstevel@tonic-gate 				if (tree_namecmp(np,
4430Sstevel@tonic-gate 				    nvpairnp->u.expr.right) == 0)
4440Sstevel@tonic-gate 					return;
4450Sstevel@tonic-gate 				break;
4460Sstevel@tonic-gate 
4470Sstevel@tonic-gate 			case T_EVENT:
4480Sstevel@tonic-gate 				if (tree_eventcmp(np,
4490Sstevel@tonic-gate 				    nvpairnp->u.expr.right) == 0)
4500Sstevel@tonic-gate 					return;
4510Sstevel@tonic-gate 				break;
4520Sstevel@tonic-gate 
4530Sstevel@tonic-gate 			default:
4540Sstevel@tonic-gate 				outfl(O_ERR, nvpairnp->file, nvpairnp->line,
4550Sstevel@tonic-gate 				    "value for property \"%s\" is an "
4560Sstevel@tonic-gate 				    "invalid type: %s",
4570Sstevel@tonic-gate 				    nvpairnp->u.expr.left->u.name.s,
4580Sstevel@tonic-gate 				    ptree_nodetype2str(np->t));
4590Sstevel@tonic-gate 				return;
4600Sstevel@tonic-gate 		}
4610Sstevel@tonic-gate 		outfl(O_ERR, nvpairnp->file, nvpairnp->line,
4620Sstevel@tonic-gate 		    "property redeclared in %s declaration: %s",
4630Sstevel@tonic-gate 		    ptree_nodetype2str(t), s);
4640Sstevel@tonic-gate 	} else
4650Sstevel@tonic-gate 		(*Allowednames[i].checker)(t, s, nvpairnp->u.expr.right);
4660Sstevel@tonic-gate }
4670Sstevel@tonic-gate 
4680Sstevel@tonic-gate void
4690Sstevel@tonic-gate check_propnames(enum nodetype t, struct node *np, int from, int to)
4700Sstevel@tonic-gate {
4710Sstevel@tonic-gate 	struct node *dnp;
4720Sstevel@tonic-gate 	struct lut *lutp;
4730Sstevel@tonic-gate 
4740Sstevel@tonic-gate 	ASSERT(np != NULL);
4750Sstevel@tonic-gate 	ASSERTinfo(np->t == T_EVENT || np->t == T_LIST || np->t == T_ARROW,
4760Sstevel@tonic-gate 				ptree_nodetype2str(np->t));
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate 	if (np->t == T_EVENT) {
4790Sstevel@tonic-gate 		switch (np->u.event.ename->u.name.t) {
4800Sstevel@tonic-gate 		case N_UNSPEC:
4810Sstevel@tonic-gate 			outfl(O_ERR, np->file, np->line,
4820Sstevel@tonic-gate 			    "name in %s statement must begin with "
4830Sstevel@tonic-gate 			    "type (example: \"error.\")",
4840Sstevel@tonic-gate 			    ptree_nodetype2str(t));
4850Sstevel@tonic-gate 			return;
4860Sstevel@tonic-gate 		case N_FAULT:
4870Sstevel@tonic-gate 			lutp = Faults;
4880Sstevel@tonic-gate 			if (to) {
4890Sstevel@tonic-gate 				outfl(O_ERR, np->file, np->line,
4900Sstevel@tonic-gate 				    "%s has fault on right side of \"->\"",
4910Sstevel@tonic-gate 				    ptree_nodetype2str(t));
4920Sstevel@tonic-gate 				return;
4930Sstevel@tonic-gate 			}
4940Sstevel@tonic-gate 			if (!from) {
4950Sstevel@tonic-gate 				outfl(O_DIE, np->file, np->line,
4960Sstevel@tonic-gate 				    "internal error: %s has fault without "
4970Sstevel@tonic-gate 				    "from flag",
4980Sstevel@tonic-gate 				    ptree_nodetype2str(t));
4990Sstevel@tonic-gate 			}
5000Sstevel@tonic-gate 			break;
5010Sstevel@tonic-gate 		case N_UPSET:
5020Sstevel@tonic-gate 			lutp = Upsets;
5030Sstevel@tonic-gate 			if (to) {
5040Sstevel@tonic-gate 				outfl(O_ERR, np->file, np->line,
5050Sstevel@tonic-gate 				    "%s has upset on right side of \"->\"",
5060Sstevel@tonic-gate 				    ptree_nodetype2str(t));
5070Sstevel@tonic-gate 				return;
5080Sstevel@tonic-gate 			}
5090Sstevel@tonic-gate 			if (!from)
5100Sstevel@tonic-gate 				outfl(O_DIE, np->file, np->line,
5110Sstevel@tonic-gate 				    "internal error: %s has upset without "
5120Sstevel@tonic-gate 				    "from flag",
5130Sstevel@tonic-gate 				    ptree_nodetype2str(t));
5140Sstevel@tonic-gate 			break;
5150Sstevel@tonic-gate 		case N_DEFECT:
5160Sstevel@tonic-gate 			lutp = Defects;
5170Sstevel@tonic-gate 			if (to) {
5180Sstevel@tonic-gate 				outfl(O_ERR, np->file, np->line,
5190Sstevel@tonic-gate 				    "%s has defect on right side of \"->\"",
5200Sstevel@tonic-gate 				    ptree_nodetype2str(t));
5210Sstevel@tonic-gate 				return;
5220Sstevel@tonic-gate 			}
5230Sstevel@tonic-gate 			if (!from) {
5240Sstevel@tonic-gate 				outfl(O_DIE, np->file, np->line,
5250Sstevel@tonic-gate 				    "internal error: %s has defect without "
5260Sstevel@tonic-gate 				    "from flag",
5270Sstevel@tonic-gate 				    ptree_nodetype2str(t));
5280Sstevel@tonic-gate 			}
5290Sstevel@tonic-gate 			break;
5300Sstevel@tonic-gate 		case N_ERROR:
5310Sstevel@tonic-gate 			lutp = Errors;
5320Sstevel@tonic-gate 			if (!from && !to)
5330Sstevel@tonic-gate 				outfl(O_DIE, np->file, np->line,
5340Sstevel@tonic-gate 				    "%s has error without from or to flags",
5350Sstevel@tonic-gate 				    ptree_nodetype2str(t));
5360Sstevel@tonic-gate 			break;
5370Sstevel@tonic-gate 		case N_EREPORT:
5380Sstevel@tonic-gate 			lutp = Ereports;
5390Sstevel@tonic-gate 			if (from) {
5400Sstevel@tonic-gate 				outfl(O_ERR, np->file, np->line,
5410Sstevel@tonic-gate 				    "%s has report on left side of \"->\"",
5420Sstevel@tonic-gate 				    ptree_nodetype2str(t));
5430Sstevel@tonic-gate 				return;
5440Sstevel@tonic-gate 			}
5450Sstevel@tonic-gate 			if (!to)
5460Sstevel@tonic-gate 				outfl(O_DIE, np->file, np->line,
5470Sstevel@tonic-gate 				    "internal error: %s has report without "
5480Sstevel@tonic-gate 				    "to flag",
5490Sstevel@tonic-gate 				    ptree_nodetype2str(t));
5500Sstevel@tonic-gate 			break;
5510Sstevel@tonic-gate 		default:
5520Sstevel@tonic-gate 			outfl(O_DIE, np->file, np->line,
5530Sstevel@tonic-gate 			    "internal error: check_propnames: "
5540Sstevel@tonic-gate 			    "unexpected type: %d", np->u.name.t);
5550Sstevel@tonic-gate 		}
5560Sstevel@tonic-gate 
5570Sstevel@tonic-gate 		if ((dnp = tree_event2np_lut_lookup(lutp, np)) == NULL) {
5580Sstevel@tonic-gate 			outfl(O_ERR, np->file, np->line,
5590Sstevel@tonic-gate 			    "%s statement contains undeclared event",
5600Sstevel@tonic-gate 			    ptree_nodetype2str(t));
5610Sstevel@tonic-gate 		} else
5620Sstevel@tonic-gate 			dnp->u.stmt.flags |= STMT_REF;
5630Sstevel@tonic-gate 		np->u.event.declp = dnp;
5640Sstevel@tonic-gate 	} else if (np->t == T_LIST) {
5650Sstevel@tonic-gate 		check_propnames(t, np->u.expr.left, from, to);
5660Sstevel@tonic-gate 		check_propnames(t, np->u.expr.right, from, to);
5670Sstevel@tonic-gate 	} else if (np->t == T_ARROW) {
5680Sstevel@tonic-gate 		check_propnames(t, np->u.arrow.lhs, 1, to);
5690Sstevel@tonic-gate 		check_propnames(t, np->u.arrow.rhs, from, 1);
5700Sstevel@tonic-gate 	}
5710Sstevel@tonic-gate }
5720Sstevel@tonic-gate 
5730Sstevel@tonic-gate static struct lut *
5740Sstevel@tonic-gate record_iterators(struct node *np, struct lut *ex)
5750Sstevel@tonic-gate {
5760Sstevel@tonic-gate 	if (np == NULL)
5770Sstevel@tonic-gate 		return (ex);
5780Sstevel@tonic-gate 
5790Sstevel@tonic-gate 	switch (np->t) {
5800Sstevel@tonic-gate 	case T_ARROW:
5810Sstevel@tonic-gate 		ex = record_iterators(np->u.arrow.lhs, ex);
5820Sstevel@tonic-gate 		ex = record_iterators(np->u.arrow.rhs, ex);
5830Sstevel@tonic-gate 		break;
5840Sstevel@tonic-gate 
5850Sstevel@tonic-gate 	case T_LIST:
5860Sstevel@tonic-gate 		ex = record_iterators(np->u.expr.left, ex);
5870Sstevel@tonic-gate 		ex = record_iterators(np->u.expr.right, ex);
5880Sstevel@tonic-gate 		break;
5890Sstevel@tonic-gate 
5900Sstevel@tonic-gate 	case T_EVENT:
5910Sstevel@tonic-gate 		ex = record_iterators(np->u.event.epname, ex);
5920Sstevel@tonic-gate 		break;
5930Sstevel@tonic-gate 
5940Sstevel@tonic-gate 	case T_NAME:
5950Sstevel@tonic-gate 		if (np->u.name.child && np->u.name.child->t == T_NAME)
5960Sstevel@tonic-gate 			ex = lut_add(ex, (void *) np->u.name.child->u.name.s,
5970Sstevel@tonic-gate 			    (void *) np, NULL);
5980Sstevel@tonic-gate 		ex = record_iterators(np->u.name.next, ex);
5990Sstevel@tonic-gate 		break;
6000Sstevel@tonic-gate 
6010Sstevel@tonic-gate 	default:
6020Sstevel@tonic-gate 		outfl(O_DIE, np->file, np->line,
6030Sstevel@tonic-gate 		    "record_iterators: internal error: unexpected type: %s",
6040Sstevel@tonic-gate 		    ptree_nodetype2str(np->t));
6050Sstevel@tonic-gate 	}
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate 	return (ex);
6080Sstevel@tonic-gate }
6090Sstevel@tonic-gate 
6100Sstevel@tonic-gate void
6110Sstevel@tonic-gate check_exprscope(struct node *np, struct lut *ex)
6120Sstevel@tonic-gate {
6130Sstevel@tonic-gate 	if (np == NULL)
6140Sstevel@tonic-gate 		return;
6150Sstevel@tonic-gate 
6160Sstevel@tonic-gate 	switch (np->t) {
6170Sstevel@tonic-gate 	case T_EVENT:
6180Sstevel@tonic-gate 		check_exprscope(np->u.event.eexprlist, ex);
6190Sstevel@tonic-gate 		break;
6200Sstevel@tonic-gate 
6210Sstevel@tonic-gate 	case T_ARROW:
6220Sstevel@tonic-gate 		check_exprscope(np->u.arrow.lhs, ex);
6230Sstevel@tonic-gate 		check_exprscope(np->u.arrow.rhs, ex);
6240Sstevel@tonic-gate 		break;
6250Sstevel@tonic-gate 
6260Sstevel@tonic-gate 	case T_NAME:
6270Sstevel@tonic-gate 		if (np->u.name.child && np->u.name.child->t == T_NAME) {
6280Sstevel@tonic-gate 			if (lut_lookup(ex,
6290Sstevel@tonic-gate 					(void *) np->u.name.child->u.name.s,
6300Sstevel@tonic-gate 					NULL) == NULL)
6310Sstevel@tonic-gate 				outfl(O_ERR, np->file, np->line,
6320Sstevel@tonic-gate 					"constraint contains undefined"
6330Sstevel@tonic-gate 					" iterator: %s",
6340Sstevel@tonic-gate 					np->u.name.child->u.name.s);
6350Sstevel@tonic-gate 		}
6360Sstevel@tonic-gate 		check_exprscope(np->u.name.next, ex);
6370Sstevel@tonic-gate 		break;
6380Sstevel@tonic-gate 
6390Sstevel@tonic-gate 	case T_QUOTE:
6400Sstevel@tonic-gate 	case T_GLOBID:
6410Sstevel@tonic-gate 		break;
6420Sstevel@tonic-gate 
6430Sstevel@tonic-gate 	case T_ASSIGN:
6440Sstevel@tonic-gate 	case T_NE:
6450Sstevel@tonic-gate 	case T_EQ:
6460Sstevel@tonic-gate 	case T_LIST:
6470Sstevel@tonic-gate 	case T_AND:
6480Sstevel@tonic-gate 	case T_OR:
6490Sstevel@tonic-gate 	case T_NOT:
6500Sstevel@tonic-gate 	case T_ADD:
6510Sstevel@tonic-gate 	case T_SUB:
6520Sstevel@tonic-gate 	case T_MUL:
6530Sstevel@tonic-gate 	case T_DIV:
6540Sstevel@tonic-gate 	case T_MOD:
6550Sstevel@tonic-gate 	case T_LT:
6560Sstevel@tonic-gate 	case T_LE:
6570Sstevel@tonic-gate 	case T_GT:
6580Sstevel@tonic-gate 	case T_GE:
6590Sstevel@tonic-gate 	case T_BITAND:
6600Sstevel@tonic-gate 	case T_BITOR:
6610Sstevel@tonic-gate 	case T_BITXOR:
6620Sstevel@tonic-gate 	case T_BITNOT:
6630Sstevel@tonic-gate 	case T_LSHIFT:
6640Sstevel@tonic-gate 	case T_RSHIFT:
6650Sstevel@tonic-gate 	case T_CONDIF:
6660Sstevel@tonic-gate 	case T_CONDELSE:
6670Sstevel@tonic-gate 		check_exprscope(np->u.expr.left, ex);
6680Sstevel@tonic-gate 		check_exprscope(np->u.expr.right, ex);
6690Sstevel@tonic-gate 		break;
6700Sstevel@tonic-gate 
6710Sstevel@tonic-gate 	case T_FUNC:
6720Sstevel@tonic-gate 		check_exprscope(np->u.func.arglist, ex);
6730Sstevel@tonic-gate 		break;
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate 	case T_NUM:
6760Sstevel@tonic-gate 	case T_TIMEVAL:
6770Sstevel@tonic-gate 		break;
6780Sstevel@tonic-gate 
6790Sstevel@tonic-gate 	default:
6800Sstevel@tonic-gate 		outfl(O_DIE, np->file, np->line,
6810Sstevel@tonic-gate 		    "check_exprscope: internal error: unexpected type: %s",
6820Sstevel@tonic-gate 		    ptree_nodetype2str(np->t));
6830Sstevel@tonic-gate 	}
6840Sstevel@tonic-gate }
6850Sstevel@tonic-gate 
6860Sstevel@tonic-gate /*
6870Sstevel@tonic-gate  * check_propscope -- check constraints for out of scope variable refs
6880Sstevel@tonic-gate  */
6890Sstevel@tonic-gate void
6900Sstevel@tonic-gate check_propscope(struct node *np)
6910Sstevel@tonic-gate {
6920Sstevel@tonic-gate 	struct lut *ex;
6930Sstevel@tonic-gate 
6940Sstevel@tonic-gate 	ex = record_iterators(np, NULL);
6950Sstevel@tonic-gate 	check_exprscope(np, ex);
6960Sstevel@tonic-gate 	lut_free(ex, NULL, NULL);
6970Sstevel@tonic-gate }
6980Sstevel@tonic-gate 
6990Sstevel@tonic-gate /*
7000Sstevel@tonic-gate  * check_upset_engine -- validate the engine property in an upset statement
7010Sstevel@tonic-gate  *
7020Sstevel@tonic-gate  * we do this after the full parse tree has been constructed rather than while
7030Sstevel@tonic-gate  * building the parse tree because it is inconvenient for the user if we
7040Sstevel@tonic-gate  * require SERD engines to be declared before used in an upset "engine"
7050Sstevel@tonic-gate  * property.
7060Sstevel@tonic-gate  */
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate /*ARGSUSED*/
7090Sstevel@tonic-gate void
7100Sstevel@tonic-gate check_upset_engine(struct node *lhs, struct node *rhs, void *arg)
7110Sstevel@tonic-gate {
7120Sstevel@tonic-gate 	enum nodetype t = (enum nodetype)arg;
7130Sstevel@tonic-gate 	struct node *engnp;
7140Sstevel@tonic-gate 	struct node *declp;
7150Sstevel@tonic-gate 
7160Sstevel@tonic-gate 	ASSERTeq(rhs->t, t, ptree_nodetype2str);
7170Sstevel@tonic-gate 
7180Sstevel@tonic-gate 	if ((engnp = tree_s2np_lut_lookup(rhs->u.stmt.lutp, L_engine)) == NULL)
7190Sstevel@tonic-gate 		return;
7200Sstevel@tonic-gate 
7210Sstevel@tonic-gate 	ASSERT(engnp->t == T_EVENT);
7220Sstevel@tonic-gate 
7230Sstevel@tonic-gate 	if ((declp = tree_event2np_lut_lookup(SERDs, engnp)) == NULL) {
7240Sstevel@tonic-gate 		outfl(O_ERR, engnp->file, engnp->line,
7250Sstevel@tonic-gate 		    "%s %s property contains undeclared name",
7260Sstevel@tonic-gate 		    ptree_nodetype2str(t), L_engine);
7270Sstevel@tonic-gate 		return;
7280Sstevel@tonic-gate 	}
7290Sstevel@tonic-gate 	engnp->u.event.declp = declp;
7300Sstevel@tonic-gate }
7310Sstevel@tonic-gate 
7320Sstevel@tonic-gate /*
7330Sstevel@tonic-gate  * check_refcount -- see if declared names are used
7340Sstevel@tonic-gate  *
7350Sstevel@tonic-gate  * this is run after the entire parse tree is constructed, so a refcount
7360Sstevel@tonic-gate  * of zero means the name has been declared but otherwise not used.
7370Sstevel@tonic-gate  */
7380Sstevel@tonic-gate 
7390Sstevel@tonic-gate void
7400Sstevel@tonic-gate check_refcount(struct node *lhs, struct node *rhs, void *arg)
7410Sstevel@tonic-gate {
7420Sstevel@tonic-gate 	enum nodetype t = (enum nodetype)arg;
7430Sstevel@tonic-gate 
7440Sstevel@tonic-gate 	ASSERTeq(rhs->t, t, ptree_nodetype2str);
7450Sstevel@tonic-gate 
7460Sstevel@tonic-gate 	if (rhs->u.stmt.flags & STMT_REF)
7470Sstevel@tonic-gate 		return;
7480Sstevel@tonic-gate 
7490Sstevel@tonic-gate 	outfl(O_WARN|O_NONL, rhs->file, rhs->line,
7500Sstevel@tonic-gate 	    "%s name declared but not used: ", ptree_nodetype2str(t));
7510Sstevel@tonic-gate 	ptree_name(O_WARN|O_NONL, lhs);
7520Sstevel@tonic-gate 	out(O_WARN, NULL);
7530Sstevel@tonic-gate }
7540Sstevel@tonic-gate 
7550Sstevel@tonic-gate /*
7560Sstevel@tonic-gate  * set check_cycle_warninglevel only for val >= 0
7570Sstevel@tonic-gate  */
7580Sstevel@tonic-gate int
7590Sstevel@tonic-gate check_cycle_level(long long val)
7600Sstevel@tonic-gate {
7610Sstevel@tonic-gate 	static int check_cycle_warninglevel = -1;
7620Sstevel@tonic-gate 
7630Sstevel@tonic-gate 	if (val == 0)
7640Sstevel@tonic-gate 		check_cycle_warninglevel = 0;
7650Sstevel@tonic-gate 	else if (val > 0)
7660Sstevel@tonic-gate 		check_cycle_warninglevel = 1;
7670Sstevel@tonic-gate 
7680Sstevel@tonic-gate 	return (check_cycle_warninglevel);
7690Sstevel@tonic-gate }
7700Sstevel@tonic-gate 
7710Sstevel@tonic-gate /*
7720Sstevel@tonic-gate  * check_cycle -- see props from an error have cycles
7730Sstevel@tonic-gate  *
7740Sstevel@tonic-gate  * this is run after the entire parse tree is constructed, for
7750Sstevel@tonic-gate  * each error that has been declared.
7760Sstevel@tonic-gate  */
7770Sstevel@tonic-gate 
7780Sstevel@tonic-gate /*ARGSUSED*/
7790Sstevel@tonic-gate void
7800Sstevel@tonic-gate check_cycle(struct node *lhs, struct node *rhs, void *arg)
7810Sstevel@tonic-gate {
7820Sstevel@tonic-gate 	struct node *np;
7830Sstevel@tonic-gate 
7840Sstevel@tonic-gate 	ASSERTeq(rhs->t, T_ERROR, ptree_nodetype2str);
7850Sstevel@tonic-gate 
7860Sstevel@tonic-gate 	if (rhs->u.stmt.flags & STMT_CYCLE)
7870Sstevel@tonic-gate 		return;		/* already reported this cycle */
7880Sstevel@tonic-gate 
7890Sstevel@tonic-gate 	if (rhs->u.stmt.flags & STMT_CYMARK) {
7900Sstevel@tonic-gate #ifdef ESC
7910Sstevel@tonic-gate 		int warninglevel;
7920Sstevel@tonic-gate 
7930Sstevel@tonic-gate 		warninglevel = check_cycle_level(-1);
7940Sstevel@tonic-gate 		if (warninglevel <= 0) {
7950Sstevel@tonic-gate 			int olevel = O_ERR;
7960Sstevel@tonic-gate 
7970Sstevel@tonic-gate 			if (warninglevel == 0)
7980Sstevel@tonic-gate 				olevel = O_WARN;
7990Sstevel@tonic-gate 
8000Sstevel@tonic-gate 			out(olevel|O_NONL, "cycle in propagation tree: ");
8010Sstevel@tonic-gate 			ptree_name(olevel|O_NONL, rhs->u.stmt.np);
8020Sstevel@tonic-gate 			out(olevel, NULL);
8030Sstevel@tonic-gate 		}
8040Sstevel@tonic-gate #endif /* ESC */
8050Sstevel@tonic-gate 
8060Sstevel@tonic-gate 		rhs->u.stmt.flags |= STMT_CYCLE;
8070Sstevel@tonic-gate 	}
8080Sstevel@tonic-gate 
8090Sstevel@tonic-gate 	rhs->u.stmt.flags |= STMT_CYMARK;
8100Sstevel@tonic-gate 
8110Sstevel@tonic-gate 	/* for each propagation */
8120Sstevel@tonic-gate 	for (np = Props; np; np = np->u.stmt.next)
8130Sstevel@tonic-gate 		check_cycle_lhs(rhs, np->u.stmt.np);
8140Sstevel@tonic-gate 
8150Sstevel@tonic-gate 	rhs->u.stmt.flags &= ~STMT_CYMARK;
8160Sstevel@tonic-gate }
8170Sstevel@tonic-gate 
8180Sstevel@tonic-gate /*
8190Sstevel@tonic-gate  * check_cycle_lhs -- find the lhs of an arrow for cycle checking
8200Sstevel@tonic-gate  */
8210Sstevel@tonic-gate 
8220Sstevel@tonic-gate static void
8230Sstevel@tonic-gate check_cycle_lhs(struct node *stmtnp, struct node *arrow)
8240Sstevel@tonic-gate {
8250Sstevel@tonic-gate 	struct node *trylhs;
8260Sstevel@tonic-gate 	struct node *tryrhs;
8270Sstevel@tonic-gate 
8280Sstevel@tonic-gate 	/* handle cascaded arrows */
8290Sstevel@tonic-gate 	switch (arrow->u.arrow.lhs->t) {
8300Sstevel@tonic-gate 	case T_ARROW:
8310Sstevel@tonic-gate 		/* first recurse left */
8320Sstevel@tonic-gate 		check_cycle_lhs(stmtnp, arrow->u.arrow.lhs);
8330Sstevel@tonic-gate 
834854Srw145199 		/*
835854Srw145199 		 * return if there's a list of events internal to
836854Srw145199 		 * cascaded props (which is not allowed)
8371414Scindi 		 */
838854Srw145199 		if (arrow->u.arrow.lhs->u.arrow.rhs->t != T_EVENT)
839854Srw145199 			return;
8400Sstevel@tonic-gate 
8410Sstevel@tonic-gate 		/* then try this arrow (thing cascaded *to*) */
8420Sstevel@tonic-gate 		trylhs = arrow->u.arrow.lhs->u.arrow.rhs;
8430Sstevel@tonic-gate 		tryrhs = arrow->u.arrow.rhs;
8440Sstevel@tonic-gate 		break;
8450Sstevel@tonic-gate 
8460Sstevel@tonic-gate 	case T_EVENT:
8470Sstevel@tonic-gate 	case T_LIST:
8480Sstevel@tonic-gate 		trylhs = arrow->u.arrow.lhs;
8490Sstevel@tonic-gate 		tryrhs = arrow->u.arrow.rhs;
8500Sstevel@tonic-gate 		break;
8510Sstevel@tonic-gate 
8520Sstevel@tonic-gate 	default:
8530Sstevel@tonic-gate 		out(O_DIE, "lhs: unexpected type: %s",
8540Sstevel@tonic-gate 		    ptree_nodetype2str(arrow->u.arrow.lhs->t));
8550Sstevel@tonic-gate 		/*NOTREACHED*/
8560Sstevel@tonic-gate 	}
8570Sstevel@tonic-gate 
8580Sstevel@tonic-gate 	check_cycle_lhs_try(stmtnp, trylhs, tryrhs);
8590Sstevel@tonic-gate }
8600Sstevel@tonic-gate 
8610Sstevel@tonic-gate /*
8620Sstevel@tonic-gate  * check_cycle_lhs_try -- try matching an event name on lhs of an arrow
8630Sstevel@tonic-gate  */
8640Sstevel@tonic-gate 
8650Sstevel@tonic-gate static void
8660Sstevel@tonic-gate check_cycle_lhs_try(struct node *stmtnp, struct node *lhs, struct node *rhs)
8670Sstevel@tonic-gate {
8680Sstevel@tonic-gate 	if (lhs->t == T_LIST) {
8690Sstevel@tonic-gate 		check_cycle_lhs_try(stmtnp, lhs->u.expr.left, rhs);
8700Sstevel@tonic-gate 		check_cycle_lhs_try(stmtnp, lhs->u.expr.right, rhs);
8710Sstevel@tonic-gate 		return;
8720Sstevel@tonic-gate 	}
8730Sstevel@tonic-gate 
8740Sstevel@tonic-gate 	ASSERT(lhs->t == T_EVENT);
8750Sstevel@tonic-gate 
8760Sstevel@tonic-gate 	if (tree_eventcmp(stmtnp->u.stmt.np, lhs) != 0)
8770Sstevel@tonic-gate 		return;		/* no match */
8780Sstevel@tonic-gate 
8790Sstevel@tonic-gate 	check_cycle_rhs(rhs);
8800Sstevel@tonic-gate }
8810Sstevel@tonic-gate 
8820Sstevel@tonic-gate /*
8830Sstevel@tonic-gate  * check_cycle_rhs -- foreach error on rhs, see if we cycle to a marked error
8840Sstevel@tonic-gate  */
8850Sstevel@tonic-gate 
8860Sstevel@tonic-gate static void
8870Sstevel@tonic-gate check_cycle_rhs(struct node *rhs)
8880Sstevel@tonic-gate {
8890Sstevel@tonic-gate 	struct node *dnp;
8900Sstevel@tonic-gate 
8910Sstevel@tonic-gate 	if (rhs->t == T_LIST) {
8920Sstevel@tonic-gate 		check_cycle_rhs(rhs->u.expr.left);
8930Sstevel@tonic-gate 		check_cycle_rhs(rhs->u.expr.right);
8940Sstevel@tonic-gate 		return;
8950Sstevel@tonic-gate 	}
8960Sstevel@tonic-gate 
8970Sstevel@tonic-gate 	ASSERT(rhs->t == T_EVENT);
8980Sstevel@tonic-gate 
8990Sstevel@tonic-gate 	if (rhs->u.event.ename->u.name.t != N_ERROR)
9000Sstevel@tonic-gate 		return;
9010Sstevel@tonic-gate 
9020Sstevel@tonic-gate 	if ((dnp = tree_event2np_lut_lookup(Errors, rhs)) == NULL) {
9030Sstevel@tonic-gate 		outfl(O_ERR|O_NONL,
9040Sstevel@tonic-gate 		    rhs->file, rhs->line,
9050Sstevel@tonic-gate 		    "unexpected undeclared event during cycle check");
9060Sstevel@tonic-gate 		ptree_name(O_ERR|O_NONL, rhs);
9070Sstevel@tonic-gate 		out(O_ERR, NULL);
9080Sstevel@tonic-gate 		return;
9090Sstevel@tonic-gate 	}
9100Sstevel@tonic-gate 	check_cycle(NULL, dnp, 0);
9110Sstevel@tonic-gate }
9120Sstevel@tonic-gate 
9130Sstevel@tonic-gate /*
9140Sstevel@tonic-gate  * Force iterators to be simple names, expressions, or numbers
9150Sstevel@tonic-gate  */
9160Sstevel@tonic-gate void
9170Sstevel@tonic-gate check_name_iterator(struct node *np)
9180Sstevel@tonic-gate {
9190Sstevel@tonic-gate 	if (np->u.name.child->t != T_NUM &&
9200Sstevel@tonic-gate 	    np->u.name.child->t != T_NAME &&
9210Sstevel@tonic-gate 	    np->u.name.child->t != T_CONDIF &&
9220Sstevel@tonic-gate 	    np->u.name.child->t != T_SUB &&
9230Sstevel@tonic-gate 	    np->u.name.child->t != T_ADD &&
9240Sstevel@tonic-gate 	    np->u.name.child->t != T_MUL &&
9250Sstevel@tonic-gate 	    np->u.name.child->t != T_DIV &&
9260Sstevel@tonic-gate 	    np->u.name.child->t != T_MOD &&
9270Sstevel@tonic-gate 	    np->u.name.child->t != T_LSHIFT &&
9280Sstevel@tonic-gate 	    np->u.name.child->t != T_RSHIFT) {
9290Sstevel@tonic-gate 		outfl(O_ERR|O_NONL, np->file, np->line,
9300Sstevel@tonic-gate 		"invalid iterator: ");
9310Sstevel@tonic-gate 		ptree_name_iter(O_ERR|O_NONL, np);
9320Sstevel@tonic-gate 		out(O_ERR, NULL);
9330Sstevel@tonic-gate 	}
9340Sstevel@tonic-gate }
9350Sstevel@tonic-gate 
9360Sstevel@tonic-gate /*
9370Sstevel@tonic-gate  * Iterators on a declaration may only be implicit
9380Sstevel@tonic-gate  */
9390Sstevel@tonic-gate void
9400Sstevel@tonic-gate check_type_iterator(struct node *np)
9410Sstevel@tonic-gate {
9420Sstevel@tonic-gate 	while (np != NULL) {
9430Sstevel@tonic-gate 		if (np->t == T_EVENT) {
9440Sstevel@tonic-gate 			np = np->u.event.epname;
9450Sstevel@tonic-gate 		} else if (np->t == T_NAME) {
9460Sstevel@tonic-gate 			if (np->u.name.child != NULL &&
9470Sstevel@tonic-gate 			    np->u.name.child->t != T_NUM) {
9480Sstevel@tonic-gate 				outfl(O_ERR|O_NONL, np->file, np->line,
9490Sstevel@tonic-gate 				    "explicit iterators disallowed "
9500Sstevel@tonic-gate 				    "in declarations: ");
9510Sstevel@tonic-gate 				ptree_name_iter(O_ERR|O_NONL, np);
9520Sstevel@tonic-gate 				out(O_ERR, NULL);
9530Sstevel@tonic-gate 			}
9540Sstevel@tonic-gate 			np = np->u.name.next;
9550Sstevel@tonic-gate 		} else {
9560Sstevel@tonic-gate 			break;
9570Sstevel@tonic-gate 		}
9580Sstevel@tonic-gate 	}
9590Sstevel@tonic-gate }
9600Sstevel@tonic-gate 
9610Sstevel@tonic-gate void
9620Sstevel@tonic-gate check_func(struct node *np)
9630Sstevel@tonic-gate {
9640Sstevel@tonic-gate 	ASSERTinfo(np->t == T_FUNC, ptree_nodetype2str(np->t));
9650Sstevel@tonic-gate 
9660Sstevel@tonic-gate 	if (np->u.func.s == L_within) {
9670Sstevel@tonic-gate 		struct node *arglist = np->u.func.arglist;
9680Sstevel@tonic-gate 		switch (arglist->t) {
9690Sstevel@tonic-gate 			case T_NUM:
9700Sstevel@tonic-gate 				if (arglist->u.ull != 0ULL)
9710Sstevel@tonic-gate 				    outfl(O_ERR, arglist->file, arglist->line,
9720Sstevel@tonic-gate 					"parameter of within must be 0"
9730Sstevel@tonic-gate 					", \"infinity\" or a time value.");
9740Sstevel@tonic-gate 				break;
9750Sstevel@tonic-gate 			case T_NAME:
9760Sstevel@tonic-gate 				if (arglist->u.name.s != L_infinity)
9770Sstevel@tonic-gate 				    outfl(O_ERR, arglist->file, arglist->line,
9780Sstevel@tonic-gate 					"parameter of within must be 0"
9790Sstevel@tonic-gate 					", \"infinity\" or a time value.");
9800Sstevel@tonic-gate 				break;
9810Sstevel@tonic-gate 			case T_LIST:
9820Sstevel@tonic-gate 				/*
9830Sstevel@tonic-gate 				 * if two parameters, the left or min must be
9840Sstevel@tonic-gate 				 * either T_NUM or T_TIMEVAL
9850Sstevel@tonic-gate 				 */
9860Sstevel@tonic-gate 				if (arglist->u.expr.left->t != T_NUM &&
9870Sstevel@tonic-gate 				    arglist->u.expr.left->t != T_TIMEVAL)
9880Sstevel@tonic-gate 					outfl(O_ERR,
9890Sstevel@tonic-gate 					    arglist->file, arglist->line,
9900Sstevel@tonic-gate 					    "first parameter of within must be"
9910Sstevel@tonic-gate 					    " either a time value or zero.");
9920Sstevel@tonic-gate 
9930Sstevel@tonic-gate 				/*
9940Sstevel@tonic-gate 				 * if two parameters, the right or max must
9950Sstevel@tonic-gate 				 * be either T_NUM, T_NAME or T_TIMEVAL
9960Sstevel@tonic-gate 				 */
9970Sstevel@tonic-gate 				if (arglist->u.expr.right->t != T_NUM &&
9980Sstevel@tonic-gate 				    arglist->u.expr.right->t != T_TIMEVAL &&
9990Sstevel@tonic-gate 				    arglist->u.expr.right->t != T_NAME)
10000Sstevel@tonic-gate 					outfl(O_ERR,
10010Sstevel@tonic-gate 					    arglist->file, arglist->line,
10020Sstevel@tonic-gate 					    "second parameter of within must "
10030Sstevel@tonic-gate 					    "be 0, \"infinity\" "
10040Sstevel@tonic-gate 					    "or time value.");
10050Sstevel@tonic-gate 
10060Sstevel@tonic-gate 				/*
10070Sstevel@tonic-gate 				 * if right or left is a T_NUM it must
10080Sstevel@tonic-gate 				 * be zero
10090Sstevel@tonic-gate 				 */
10100Sstevel@tonic-gate 				if (arglist->u.expr.left->t == T_NUM)
10110Sstevel@tonic-gate 					if (arglist->u.expr.left->u.ull != 0ULL)
10120Sstevel@tonic-gate 					    outfl(O_ERR,
10130Sstevel@tonic-gate 						arglist->file, arglist->line,
10140Sstevel@tonic-gate 						"within parameter must be 0 or"
10150Sstevel@tonic-gate 						" a time value.");
10160Sstevel@tonic-gate 				if (arglist->u.expr.right->t == T_NUM)
10170Sstevel@tonic-gate 					if (arglist->u.expr.right->u.ull
10180Sstevel@tonic-gate 					    != 0ULL)
10190Sstevel@tonic-gate 					    outfl(O_ERR,
10200Sstevel@tonic-gate 						arglist->file, arglist->line,
10210Sstevel@tonic-gate 						"within parameter must be 0 or"
10220Sstevel@tonic-gate 						" a time value.");
10230Sstevel@tonic-gate 
10240Sstevel@tonic-gate 				/* if right is a T_NAME it must be "infinity" */
10250Sstevel@tonic-gate 				if (arglist->u.expr.right->t == T_NAME)
10260Sstevel@tonic-gate 					if (arglist->u.expr.right->u.name.s
10270Sstevel@tonic-gate 					    != L_infinity)
10280Sstevel@tonic-gate 					    outfl(O_ERR,
10290Sstevel@tonic-gate 						arglist->file, arglist->line,
10300Sstevel@tonic-gate 						"\"infinity\" is the only valid"
10310Sstevel@tonic-gate 						" name for within parameter.");
10320Sstevel@tonic-gate 
10330Sstevel@tonic-gate 				/*
10340Sstevel@tonic-gate 				 * the first parameter [min] must not be greater
10350Sstevel@tonic-gate 				 * than the second parameter [max].
10360Sstevel@tonic-gate 				 */
10370Sstevel@tonic-gate 				if (arglist->u.expr.left->u.ull >
10380Sstevel@tonic-gate 				    arglist->u.expr.right->u.ull)
10390Sstevel@tonic-gate 					outfl(O_ERR,
10400Sstevel@tonic-gate 					    arglist->file, arglist->line,
10410Sstevel@tonic-gate 					    "the first value (min) of"
10420Sstevel@tonic-gate 					    " within must be less than"
10430Sstevel@tonic-gate 					    " the second (max) value");
10440Sstevel@tonic-gate 				break;
10450Sstevel@tonic-gate 			case T_TIMEVAL:
10460Sstevel@tonic-gate 				break; /* no restrictions on T_TIMEVAL */
10470Sstevel@tonic-gate 			default:
10480Sstevel@tonic-gate 				outfl(O_ERR, arglist->file, arglist->line,
10490Sstevel@tonic-gate 					"parameter of within must be 0"
10500Sstevel@tonic-gate 					", \"infinity\" or a time value.");
10510Sstevel@tonic-gate 		}
10520Sstevel@tonic-gate 	} else if (np->u.func.s == L_call) {
10530Sstevel@tonic-gate 		if (np->u.func.arglist->t != T_QUOTE &&
10540Sstevel@tonic-gate 		    np->u.func.arglist->t != T_LIST &&
10550Sstevel@tonic-gate 		    np->u.func.arglist->t != T_GLOBID &&
10560Sstevel@tonic-gate 		    np->u.func.arglist->t != T_CONDIF &&
10570Sstevel@tonic-gate 		    np->u.func.arglist->t != T_LIST &&
10580Sstevel@tonic-gate 		    np->u.func.arglist->t != T_FUNC)
10590Sstevel@tonic-gate 			outfl(O_ERR, np->u.func.arglist->file,
10600Sstevel@tonic-gate 				np->u.func.arglist->line,
10610Sstevel@tonic-gate 				"invalid first argument to call()");
10620Sstevel@tonic-gate 	} else if (np->u.func.s == L_fru) {
10630Sstevel@tonic-gate 		if (np->u.func.arglist->t != T_NAME)
10640Sstevel@tonic-gate 			outfl(O_ERR, np->u.func.arglist->file,
10650Sstevel@tonic-gate 				np->u.func.arglist->line,
10660Sstevel@tonic-gate 				"argument to fru() must be a path");
10670Sstevel@tonic-gate 	} else if (np->u.func.s == L_asru) {
10680Sstevel@tonic-gate 		if (np->u.func.arglist->t != T_NAME)
10690Sstevel@tonic-gate 			outfl(O_ERR, np->u.func.arglist->file,
10700Sstevel@tonic-gate 				np->u.func.arglist->line,
10710Sstevel@tonic-gate 				"argument to asru() must be a path");
10720Sstevel@tonic-gate 	} else if (np->u.func.s == L_is_connected ||
10730Sstevel@tonic-gate 	    np->u.func.s == L_is_under) {
10740Sstevel@tonic-gate 		if (np->u.func.arglist->t == T_LIST &&
10750Sstevel@tonic-gate 		    (np->u.func.arglist->u.expr.left->t == T_NAME ||
10760Sstevel@tonic-gate 		    (np->u.func.arglist->u.expr.left->t == T_FUNC &&
10770Sstevel@tonic-gate 		    (np->u.func.arglist->u.expr.left->u.func.s == L_fru ||
10780Sstevel@tonic-gate 		    np->u.func.arglist->u.expr.left->u.func.s == L_asru))) &&
10790Sstevel@tonic-gate 		    (np->u.func.arglist->u.expr.right->t == T_NAME ||
10800Sstevel@tonic-gate 		    (np->u.func.arglist->u.expr.right->t == T_FUNC &&
10810Sstevel@tonic-gate 		    (np->u.func.arglist->u.expr.right->u.func.s == L_fru ||
10820Sstevel@tonic-gate 		    np->u.func.arglist->u.expr.right->u.func.s == L_asru)))) {
10830Sstevel@tonic-gate 			if (np->u.func.arglist->u.expr.left->t == T_FUNC)
10840Sstevel@tonic-gate 				check_func(np->u.func.arglist->u.expr.left);
10850Sstevel@tonic-gate 			if (np->u.func.arglist->u.expr.right->t == T_FUNC)
10860Sstevel@tonic-gate 				check_func(np->u.func.arglist->u.expr.right);
10870Sstevel@tonic-gate 		} else {
10880Sstevel@tonic-gate 			outfl(O_ERR, np->u.func.arglist->file,
10890Sstevel@tonic-gate 			    np->u.func.arglist->line,
10900Sstevel@tonic-gate 			    "%s() must have paths or calls to "
10910Sstevel@tonic-gate 			    "fru() and/or asru() as arguments",
10920Sstevel@tonic-gate 			    np->u.func.s);
10930Sstevel@tonic-gate 		}
10940Sstevel@tonic-gate 	} else if (np->u.func.s == L_is_on) {
10950Sstevel@tonic-gate 		if (np->u.func.arglist->t == T_FUNC &&
10960Sstevel@tonic-gate 		    (np->u.func.arglist->u.func.s == L_fru ||
10970Sstevel@tonic-gate 		    np->u.func.arglist->u.func.s == L_asru)) {
10980Sstevel@tonic-gate 			check_func(np->u.func.arglist);
10990Sstevel@tonic-gate 		} else {
11000Sstevel@tonic-gate 			outfl(O_ERR, np->u.func.arglist->file,
11010Sstevel@tonic-gate 			    np->u.func.arglist->line,
11020Sstevel@tonic-gate 			    "argument to is_on() must be a call to "
11030Sstevel@tonic-gate 			    "fru() or asru()");
11040Sstevel@tonic-gate 		}
11050Sstevel@tonic-gate 	} else if (np->u.func.s == L_is_present) {
11060Sstevel@tonic-gate 		if (np->u.func.arglist->t == T_FUNC &&
11070Sstevel@tonic-gate 		    (np->u.func.arglist->u.func.s == L_fru ||
11080Sstevel@tonic-gate 		    np->u.func.arglist->u.func.s == L_asru)) {
11090Sstevel@tonic-gate 			check_func(np->u.func.arglist);
11100Sstevel@tonic-gate 		} else {
11110Sstevel@tonic-gate 			outfl(O_ERR, np->u.func.arglist->file,
11120Sstevel@tonic-gate 			    np->u.func.arglist->line,
11130Sstevel@tonic-gate 			    "argument to is_present() must be a call to "
11140Sstevel@tonic-gate 			    "fru() or asru()");
11150Sstevel@tonic-gate 		}
11160Sstevel@tonic-gate 	} else if (np->u.func.s == L_is_type) {
11170Sstevel@tonic-gate 		if (np->u.func.arglist->t == T_FUNC &&
11180Sstevel@tonic-gate 		    (np->u.func.arglist->u.func.s == L_fru ||
11190Sstevel@tonic-gate 		    np->u.func.arglist->u.func.s == L_asru)) {
11200Sstevel@tonic-gate 			check_func(np->u.func.arglist);
11210Sstevel@tonic-gate 		} else {
11220Sstevel@tonic-gate 			outfl(O_ERR, np->u.func.arglist->file,
11230Sstevel@tonic-gate 			    np->u.func.arglist->line,
11240Sstevel@tonic-gate 			    "argument to is_type() must be a call to "
11250Sstevel@tonic-gate 			    "fru() or asru()");
11260Sstevel@tonic-gate 		}
11271414Scindi 	} else if (np->u.func.s == L_confcall) {
11281414Scindi 		if (np->u.func.arglist->t != T_QUOTE &&
11291414Scindi 		    (np->u.func.arglist->t != T_LIST ||
11301414Scindi 		    np->u.func.arglist->u.expr.left->t != T_QUOTE))
11311414Scindi 			outfl(O_ERR, np->u.func.arglist->file,
11321414Scindi 			    np->u.func.arglist->line,
11331414Scindi 			    "confcall(): first argument must be a string "
11341414Scindi 			    "(the name of the operation)");
1135*2869Sgavinm 	} else if (np->u.func.s == L_confprop ||
1136*2869Sgavinm 	    np->u.func.s == L_confprop_defined) {
11370Sstevel@tonic-gate 		if (np->u.func.arglist->t == T_LIST &&
11380Sstevel@tonic-gate 		    (np->u.func.arglist->u.expr.left->t == T_FUNC &&
11390Sstevel@tonic-gate 		    (np->u.func.arglist->u.expr.left->u.func.s == L_fru ||
11400Sstevel@tonic-gate 		    np->u.func.arglist->u.expr.left->u.func.s == L_asru)) &&
11410Sstevel@tonic-gate 		    np->u.func.arglist->u.expr.right->t == T_QUOTE) {
11420Sstevel@tonic-gate 			check_func(np->u.func.arglist->u.expr.left);
11430Sstevel@tonic-gate 		} else {
11440Sstevel@tonic-gate 			outfl(O_ERR, np->u.func.arglist->file,
11450Sstevel@tonic-gate 			    np->u.func.arglist->line,
1146*2869Sgavinm 			    "%s(): first argument must be a call to "
11470Sstevel@tonic-gate 			    "fru() or asru(); "
1148*2869Sgavinm 			    "second argument must be a string", np->u.func.s);
11490Sstevel@tonic-gate 		}
11501414Scindi 	} else if (np->u.func.s == L_count) {
11511414Scindi 		if (np->u.func.arglist->t != T_EVENT) {
11521414Scindi 			outfl(O_ERR, np->u.func.arglist->file,
11531414Scindi 			    np->u.func.arglist->line,
11541414Scindi 			    "count(): argument must be an engine name");
11551414Scindi 		}
11561414Scindi 	} else if (np->u.func.s == L_defined) {
11571414Scindi 		if (np->u.func.arglist->t != T_GLOBID)
11581414Scindi 			outfl(O_ERR, np->u.func.arglist->file,
11591414Scindi 				np->u.func.arglist->line,
11601414Scindi 				"argument to defined() must be a global");
11610Sstevel@tonic-gate 	} else if (np->u.func.s == L_payloadprop) {
11620Sstevel@tonic-gate 		if (np->u.func.arglist->t != T_QUOTE)
11630Sstevel@tonic-gate 			outfl(O_ERR, np->u.func.arglist->file,
11640Sstevel@tonic-gate 				np->u.func.arglist->line,
11650Sstevel@tonic-gate 				"argument to payloadprop() must be a string");
11661414Scindi 	} else if (np->u.func.s == L_payloadprop_contains) {
11671414Scindi 		if (np->u.func.arglist->t != T_LIST ||
11681414Scindi 		    np->u.func.arglist->u.expr.left->t != T_QUOTE ||
11691414Scindi 		    np->u.func.arglist->u.expr.right == NULL)
11701414Scindi 			outfl(O_ERR, np->u.func.arglist->file,
11711414Scindi 			    np->u.func.arglist->line,
11721414Scindi 			    "args to payloadprop_contains(): must be a quoted "
11731414Scindi 			    "string (property name) and an expression "
11741414Scindi 			    "(to match)");
11751414Scindi 	} else if (np->u.func.s == L_payloadprop_defined) {
11761414Scindi 		if (np->u.func.arglist->t != T_QUOTE)
11771414Scindi 			outfl(O_ERR, np->u.func.arglist->file,
11781414Scindi 			    np->u.func.arglist->line,
11791414Scindi 			    "arg to payloadprop_defined(): must be a quoted "
11801414Scindi 			    "string");
11811414Scindi 	} else if (np->u.func.s == L_setpayloadprop) {
11821414Scindi 		if (np->u.func.arglist->t == T_LIST &&
11831414Scindi 		    np->u.func.arglist->u.expr.left->t == T_QUOTE) {
11841414Scindi 			if (np->u.func.arglist->u.expr.right->t == T_FUNC)
11851414Scindi 				check_func(np->u.func.arglist->u.expr.right);
11861414Scindi 		} else {
11871414Scindi 			outfl(O_ERR, np->u.func.arglist->file,
11881414Scindi 			    np->u.func.arglist->line,
11891414Scindi 			    "setpayloadprop(): "
11901414Scindi 			    "first arg must be a string, "
11911414Scindi 			    "second arg a value");
11921414Scindi 		}
11930Sstevel@tonic-gate 	} else if (np->u.func.s == L_envprop) {
11940Sstevel@tonic-gate 		if (np->u.func.arglist->t != T_QUOTE)
11950Sstevel@tonic-gate 			outfl(O_ERR, np->u.func.arglist->file,
11960Sstevel@tonic-gate 				np->u.func.arglist->line,
11970Sstevel@tonic-gate 				"argument to envprop() must be a string");
11980Sstevel@tonic-gate 	} else
11990Sstevel@tonic-gate 		outfl(O_WARN, np->file, np->line,
12000Sstevel@tonic-gate 			"possible platform-specific function: %s",
12010Sstevel@tonic-gate 			np->u.func.s);
12020Sstevel@tonic-gate }
12030Sstevel@tonic-gate 
12040Sstevel@tonic-gate void
12050Sstevel@tonic-gate check_expr(struct node *np)
12060Sstevel@tonic-gate {
12070Sstevel@tonic-gate 	ASSERT(np != NULL);
12080Sstevel@tonic-gate 
12090Sstevel@tonic-gate 	switch (np->t) {
12100Sstevel@tonic-gate 	case T_ASSIGN:
12110Sstevel@tonic-gate 		ASSERT(np->u.expr.left != NULL);
12120Sstevel@tonic-gate 		if (np->u.expr.left->t != T_GLOBID)
12130Sstevel@tonic-gate 			outfl(O_ERR, np->file, np->line,
12140Sstevel@tonic-gate 			    "assignment only allowed to globals (e.g. $a)");
12150Sstevel@tonic-gate 		break;
12160Sstevel@tonic-gate 	}
12170Sstevel@tonic-gate }
12180Sstevel@tonic-gate 
12190Sstevel@tonic-gate void
12200Sstevel@tonic-gate check_event(struct node *np)
12210Sstevel@tonic-gate {
12220Sstevel@tonic-gate 	ASSERT(np != NULL);
12231414Scindi 	ASSERTinfo(np->t == T_EVENT, ptree_nodetype2str(np->t));
12240Sstevel@tonic-gate 
12250Sstevel@tonic-gate 	if (np->u.event.epname == NULL) {
12260Sstevel@tonic-gate 		outfl(O_ERR|O_NONL, np->file, np->line,
12270Sstevel@tonic-gate 		    "pathless events not allowed: ");
12280Sstevel@tonic-gate 		ptree_name(O_ERR|O_NONL, np->u.event.ename);
12290Sstevel@tonic-gate 		out(O_ERR, NULL);
12300Sstevel@tonic-gate 	}
12310Sstevel@tonic-gate }
12320Sstevel@tonic-gate 
12330Sstevel@tonic-gate /*
12340Sstevel@tonic-gate  * check for properties that are required on declarations. This
12350Sstevel@tonic-gate  * should be done after all declarations since they can be
12360Sstevel@tonic-gate  * redeclared with a different set of properties.
12370Sstevel@tonic-gate  */
12380Sstevel@tonic-gate /*ARGSUSED*/
12390Sstevel@tonic-gate void
12400Sstevel@tonic-gate check_required_props(struct node *lhs, struct node *rhs, void *arg)
12410Sstevel@tonic-gate {
12420Sstevel@tonic-gate 	enum nodetype t = (enum nodetype)arg;
12430Sstevel@tonic-gate 
12440Sstevel@tonic-gate 	ASSERTeq(rhs->t, t, ptree_nodetype2str);
12450Sstevel@tonic-gate 
12460Sstevel@tonic-gate 	check_stmt_required_properties(rhs);
12470Sstevel@tonic-gate }
1248854Srw145199 
1249854Srw145199 /*
1250854Srw145199  * check that cascading prop statements do not contain lists internally.
1251854Srw145199  * the first and last event lists in the cascading prop may be single
1252854Srw145199  * events or lists of events.
1253854Srw145199  */
1254854Srw145199 /*ARGSUSED*/
1255854Srw145199 void
1256854Srw145199 check_proplists(enum nodetype t, struct node *np)
1257854Srw145199 {
1258854Srw145199 	ASSERT(np->t == T_ARROW);
1259854Srw145199 	/*
1260854Srw145199 	 * not checking the right hand side of the top level prop
1261854Srw145199 	 * since it is the last part of the propagation and can be
1262854Srw145199 	 * an event or list of events
1263854Srw145199 	 */
1264854Srw145199 	check_proplists_lhs(t, np->u.arrow.lhs);
1265854Srw145199 }
1266854Srw145199 
1267854Srw145199 /*ARGSUSED*/
1268854Srw145199 static void
1269854Srw145199 check_proplists_lhs(enum nodetype t, struct node *lhs)
1270854Srw145199 {
1271854Srw145199 	if (lhs->t == T_ARROW) {
1272854Srw145199 		if (lhs->u.arrow.rhs->t == T_LIST) {
1273854Srw145199 			outfl(O_ERR, lhs->file, lhs->line,
1274854Srw145199 				"lists are not allowed internally on"
1275854Srw145199 				" cascading %s",
1276854Srw145199 				(t == T_PROP) ? "propagations" : "masks");
1277854Srw145199 		}
1278854Srw145199 		check_proplists_lhs(t, lhs->u.arrow.lhs);
1279854Srw145199 	}
1280854Srw145199 }
1281