xref: /onnv-gate/usr/src/cmd/fm/eversholt/common/check.c (revision 11202:9f0b4aa8d573)
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
52869Sgavinm  * Common Development and Distribution License (the "License").
62869Sgavinm  * 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 /*
22*11202SStephen.Hanson@Sun.COM  * Copyright 2009 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 #include <stdio.h>
360Sstevel@tonic-gate #include "out.h"
370Sstevel@tonic-gate #include "stable.h"
380Sstevel@tonic-gate #include "literals.h"
390Sstevel@tonic-gate #include "lut.h"
400Sstevel@tonic-gate #include "tree.h"
410Sstevel@tonic-gate #include "ptree.h"
420Sstevel@tonic-gate #include "check.h"
430Sstevel@tonic-gate 
440Sstevel@tonic-gate static int check_reportlist(enum nodetype t, const char *s, struct node *np);
450Sstevel@tonic-gate static int check_num(enum nodetype t, const char *s, struct node *np);
460Sstevel@tonic-gate static int check_quote(enum nodetype t, const char *s, struct node *np);
471414Scindi static int check_action(enum nodetype t, const char *s, struct node *np);
480Sstevel@tonic-gate static int check_num_func(enum nodetype t, const char *s, struct node *np);
490Sstevel@tonic-gate static int check_fru_asru(enum nodetype t, const char *s, struct node *np);
500Sstevel@tonic-gate static int check_engine(enum nodetype t, const char *s, struct node *np);
511414Scindi static int check_count(enum nodetype t, const char *s, struct node *np);
520Sstevel@tonic-gate static int check_timeval(enum nodetype t, const char *s, struct node *np);
530Sstevel@tonic-gate static int check_id(enum nodetype t, const char *s, struct node *np);
540Sstevel@tonic-gate static int check_serd_method(enum nodetype t, const char *s, struct node *np);
551414Scindi static int check_serd_id(enum nodetype t, const char *s, struct node *np);
560Sstevel@tonic-gate static int check_nork(struct node *np);
570Sstevel@tonic-gate static void check_cycle_lhs(struct node *stmtnp, struct node *arrow);
580Sstevel@tonic-gate static void check_cycle_lhs_try(struct node *stmtnp, struct node *lhs,
590Sstevel@tonic-gate     struct node *rhs);
600Sstevel@tonic-gate static void check_cycle_rhs(struct node *rhs);
61854Srw145199 static void check_proplists_lhs(enum nodetype t, struct node *lhs);
620Sstevel@tonic-gate 
630Sstevel@tonic-gate static struct {
640Sstevel@tonic-gate 	enum nodetype t;
650Sstevel@tonic-gate 	const char *name;
660Sstevel@tonic-gate 	int required;
670Sstevel@tonic-gate 	int (*checker)(enum nodetype t, const char *s, struct node *np);
680Sstevel@tonic-gate 	int outflags;
690Sstevel@tonic-gate } Allowednames[] = {
707197Sstephh 	{ T_FAULT, "FITrate", 0, check_num_func, O_ERR },
710Sstevel@tonic-gate 	{ T_FAULT, "FRU", 0, check_fru_asru, O_ERR },
720Sstevel@tonic-gate 	{ T_FAULT, "ASRU", 0, check_fru_asru, O_ERR },
731414Scindi 	{ T_FAULT, "message", 0, check_num_func, O_ERR },
747197Sstephh 	{ T_FAULT, "retire", 0, check_num_func, O_ERR },
757197Sstephh 	{ T_FAULT, "response", 0, check_num_func, O_ERR },
761414Scindi 	{ T_FAULT, "action", 0, check_action, O_ERR },
771414Scindi 	{ T_FAULT, "count", 0, check_count, O_ERR },
787197Sstephh 	{ T_FAULT, "engine", 0, check_engine, O_ERR },
790Sstevel@tonic-gate 	{ T_UPSET, "engine", 0, check_engine, O_ERR },
800Sstevel@tonic-gate 	{ T_DEFECT, "FRU", 0, check_fru_asru, O_ERR },
810Sstevel@tonic-gate 	{ T_DEFECT, "ASRU", 0, check_fru_asru, O_ERR },
827197Sstephh 	{ T_DEFECT, "engine", 0, check_engine, O_ERR },
838245SStephen.Hanson@Sun.COM 	{ T_DEFECT, "FITrate", 0, check_num_func, O_ERR },
840Sstevel@tonic-gate 	{ T_EREPORT, "poller", 0, check_id, O_ERR },
850Sstevel@tonic-gate 	{ T_EREPORT, "delivery", 0, check_timeval, O_ERR },
866640Scth 	{ T_EREPORT, "discard_if_config_unknown", 0, check_num, O_ERR },
870Sstevel@tonic-gate 	{ T_SERD, "N", 1, check_num, O_ERR },
880Sstevel@tonic-gate 	{ T_SERD, "T", 1, check_timeval, O_ERR },
897197Sstephh 	{ T_SERD, "method", 0, check_serd_method, O_ERR },
907197Sstephh 	{ T_SERD, "trip", 0, check_reportlist, O_ERR },
910Sstevel@tonic-gate 	{ T_SERD, "FRU", 0, check_fru_asru, O_ERR },
921414Scindi 	{ T_SERD, "id", 0, check_serd_id, O_ERR },
930Sstevel@tonic-gate 	{ T_ERROR, "ASRU", 0, check_fru_asru, O_ERR },
940Sstevel@tonic-gate 	{ T_CONFIG, NULL, 0, check_quote, O_ERR },
950Sstevel@tonic-gate 	{ 0, NULL, 0 },
960Sstevel@tonic-gate };
970Sstevel@tonic-gate 
980Sstevel@tonic-gate void
check_init(void)990Sstevel@tonic-gate check_init(void)
1000Sstevel@tonic-gate {
1010Sstevel@tonic-gate 	int i;
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate 	for (i = 0; Allowednames[i].t; i++)
1040Sstevel@tonic-gate 		if (Allowednames[i].name != NULL)
1050Sstevel@tonic-gate 			Allowednames[i].name = stable(Allowednames[i].name);
1060Sstevel@tonic-gate }
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate void
check_fini(void)1090Sstevel@tonic-gate check_fini(void)
1100Sstevel@tonic-gate {
1110Sstevel@tonic-gate }
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate /*ARGSUSED*/
1140Sstevel@tonic-gate void
check_report_combination(struct node * np)1150Sstevel@tonic-gate check_report_combination(struct node *np)
1160Sstevel@tonic-gate {
1170Sstevel@tonic-gate 	/* nothing to check for here.  poller is only prop and it is optional */
1180Sstevel@tonic-gate }
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate /*
1210Sstevel@tonic-gate  * check_path_iterators -- verify all iterators are explicit
1220Sstevel@tonic-gate  */
1230Sstevel@tonic-gate static void
check_path_iterators(struct node * np)1240Sstevel@tonic-gate check_path_iterators(struct node *np)
1250Sstevel@tonic-gate {
1260Sstevel@tonic-gate 	if (np == NULL)
1270Sstevel@tonic-gate 		return;
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate 	switch (np->t) {
1300Sstevel@tonic-gate 		case T_ARROW:
1310Sstevel@tonic-gate 			check_path_iterators(np->u.arrow.lhs);
1320Sstevel@tonic-gate 			check_path_iterators(np->u.arrow.rhs);
1330Sstevel@tonic-gate 			break;
1340Sstevel@tonic-gate 
1350Sstevel@tonic-gate 		case T_LIST:
1360Sstevel@tonic-gate 			check_path_iterators(np->u.expr.left);
1370Sstevel@tonic-gate 			check_path_iterators(np->u.expr.right);
1380Sstevel@tonic-gate 			break;
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate 		case T_EVENT:
1410Sstevel@tonic-gate 			check_path_iterators(np->u.event.epname);
1420Sstevel@tonic-gate 			break;
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate 		case T_NAME:
1450Sstevel@tonic-gate 			if (np->u.name.child == NULL)
1460Sstevel@tonic-gate 				outfl(O_DIE, np->file, np->line,
1470Sstevel@tonic-gate 				    "internal error: check_path_iterators: "
1480Sstevel@tonic-gate 				    "unexpected implicit iterator: %s",
1490Sstevel@tonic-gate 				    np->u.name.s);
1500Sstevel@tonic-gate 			check_path_iterators(np->u.name.next);
1510Sstevel@tonic-gate 			break;
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate 		default:
1540Sstevel@tonic-gate 			outfl(O_DIE, np->file, np->line,
1550Sstevel@tonic-gate 			    "internal error: check_path_iterators: "
1560Sstevel@tonic-gate 			    "unexpected type: %s",
1570Sstevel@tonic-gate 			    ptree_nodetype2str(np->t));
1580Sstevel@tonic-gate 	}
1590Sstevel@tonic-gate }
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate void
check_arrow(struct node * np)1620Sstevel@tonic-gate check_arrow(struct node *np)
1630Sstevel@tonic-gate {
1640Sstevel@tonic-gate 	ASSERTinfo(np->t == T_ARROW, ptree_nodetype2str(np->t));
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate 	if (np->u.arrow.lhs->t != T_ARROW &&
1670Sstevel@tonic-gate 	    np->u.arrow.lhs->t != T_LIST &&
1680Sstevel@tonic-gate 	    np->u.arrow.lhs->t != T_EVENT) {
1690Sstevel@tonic-gate 		outfl(O_ERR,
1700Sstevel@tonic-gate 		    np->u.arrow.lhs->file, np->u.arrow.lhs->line,
1710Sstevel@tonic-gate 		    "%s not allowed on left-hand side of arrow",
1720Sstevel@tonic-gate 		    ptree_nodetype2str(np->u.arrow.lhs->t));
1730Sstevel@tonic-gate 	}
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate 	if (!check_nork(np->u.arrow.nnp) ||
1765633Scy152378 	    !check_nork(np->u.arrow.knp))
1775633Scy152378 		outfl(O_ERR, np->file, np->line,
1785633Scy152378 		    "counts associated with propagation arrows "
1795633Scy152378 		    "must be integers");
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate 	check_path_iterators(np);
1820Sstevel@tonic-gate }
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate /*
1850Sstevel@tonic-gate  * make sure the nork values are valid.
1860Sstevel@tonic-gate  * Nork values must be "A" for all(T_NAME),
1870Sstevel@tonic-gate  * a number(T_NUM), or a simple
1880Sstevel@tonic-gate  * expression(T_SUB, T_ADD, T_MUL, T_DIV)
1890Sstevel@tonic-gate  */
1900Sstevel@tonic-gate static int
check_nork(struct node * np)1910Sstevel@tonic-gate check_nork(struct node *np)
1920Sstevel@tonic-gate {
1930Sstevel@tonic-gate 	int rval = 0;
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate 	/* NULL means no nork value which is allowed */
1960Sstevel@tonic-gate 	if (np == NULL) {
1970Sstevel@tonic-gate 		rval = 1;
1980Sstevel@tonic-gate 	}
1990Sstevel@tonic-gate 	else
2000Sstevel@tonic-gate 	{
2010Sstevel@tonic-gate 		/* if the nork is a name it must be A for "All" */
2020Sstevel@tonic-gate 		if (np->t == T_NAME)
2030Sstevel@tonic-gate 			if (*np->u.name.s == 'A')
2040Sstevel@tonic-gate 				return (1);
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate 		/*  T_NUM allowed */
2070Sstevel@tonic-gate 		if (np->t == T_NUM)
2080Sstevel@tonic-gate 			rval = 1;
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate 		/*  simple expressions allowed */
2110Sstevel@tonic-gate 		if (np->t == T_SUB ||
2125633Scy152378 		    np->t == T_ADD ||
2135633Scy152378 		    np->t == T_MUL ||
2145633Scy152378 		    np->t == T_DIV)
2150Sstevel@tonic-gate 			rval = 1;
2160Sstevel@tonic-gate 	}
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate 	return (rval);
2190Sstevel@tonic-gate }
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate static int
check_reportlist(enum nodetype t,const char * s,struct node * np)2220Sstevel@tonic-gate check_reportlist(enum nodetype t, const char *s, struct node *np)
2230Sstevel@tonic-gate {
2240Sstevel@tonic-gate 	if (np == NULL)
2250Sstevel@tonic-gate 		return (1);
2260Sstevel@tonic-gate 	else if (np->t == T_EVENT) {
2270Sstevel@tonic-gate 		if (np->u.event.ename->u.name.t != N_EREPORT) {
2280Sstevel@tonic-gate 			outfl(O_ERR, np->file, np->line,
2290Sstevel@tonic-gate 			    "%s %s property must begin with \"ereport.\"",
2300Sstevel@tonic-gate 			    ptree_nodetype2str(t), s);
2310Sstevel@tonic-gate 		} else if (tree_event2np_lut_lookup(Ereports, np) == NULL) {
2320Sstevel@tonic-gate 			outfl(O_ERR, np->file, np->line,
2330Sstevel@tonic-gate 			    "%s %s property contains undeclared name",
2340Sstevel@tonic-gate 			    ptree_nodetype2str(t), s);
2350Sstevel@tonic-gate 		}
2360Sstevel@tonic-gate 		check_type_iterator(np);
2370Sstevel@tonic-gate 	} else if (np->t == T_LIST) {
2380Sstevel@tonic-gate 		(void) check_reportlist(t, s, np->u.expr.left);
2390Sstevel@tonic-gate 		(void) check_reportlist(t, s, np->u.expr.right);
2400Sstevel@tonic-gate 	}
2410Sstevel@tonic-gate 	return (1);
2420Sstevel@tonic-gate }
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate static int
check_num(enum nodetype t,const char * s,struct node * np)2450Sstevel@tonic-gate check_num(enum nodetype t, const char *s, struct node *np)
2460Sstevel@tonic-gate {
2470Sstevel@tonic-gate 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
2480Sstevel@tonic-gate 	if (np->t != T_NUM)
2490Sstevel@tonic-gate 		outfl(O_ERR, np->file, np->line,
2500Sstevel@tonic-gate 		    "%s %s property must be a single number",
2510Sstevel@tonic-gate 		    ptree_nodetype2str(t), s);
2520Sstevel@tonic-gate 	return (1);
2530Sstevel@tonic-gate }
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate /*ARGSUSED1*/
2560Sstevel@tonic-gate static int
check_quote(enum nodetype t,const char * s,struct node * np)2570Sstevel@tonic-gate check_quote(enum nodetype t, const char *s, struct node *np)
2580Sstevel@tonic-gate {
2590Sstevel@tonic-gate 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
2600Sstevel@tonic-gate 	if (np->t != T_QUOTE)
2610Sstevel@tonic-gate 		outfl(O_ERR, np->file, np->line,
2620Sstevel@tonic-gate 		    "%s properties must be quoted strings",
2630Sstevel@tonic-gate 		    ptree_nodetype2str(t));
2640Sstevel@tonic-gate 	return (1);
2650Sstevel@tonic-gate }
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate static int
check_action(enum nodetype t,const char * s,struct node * np)2681414Scindi check_action(enum nodetype t, const char *s, struct node *np)
2691414Scindi {
2701414Scindi 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
2711414Scindi 
2721414Scindi 	if (np->t != T_FUNC)
2731414Scindi 		outfl(O_ERR, np->file, np->line,
2741414Scindi 		    "%s %s property must be a function or list of functions",
2751414Scindi 		    ptree_nodetype2str(t), s);
2761414Scindi 	return (1);
2771414Scindi }
2781414Scindi 
2791414Scindi static int
check_num_func(enum nodetype t,const char * s,struct node * np)2800Sstevel@tonic-gate check_num_func(enum nodetype t, const char *s, struct node *np)
2810Sstevel@tonic-gate {
2820Sstevel@tonic-gate 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
2830Sstevel@tonic-gate 	if (np->t != T_NUM && np->t != T_FUNC)
2840Sstevel@tonic-gate 		outfl(O_ERR, np->file, np->line,
2850Sstevel@tonic-gate 		    "%s %s property must be a number or function",
2860Sstevel@tonic-gate 		    ptree_nodetype2str(t), s);
2870Sstevel@tonic-gate 	return (1);
2880Sstevel@tonic-gate }
2890Sstevel@tonic-gate 
2900Sstevel@tonic-gate static int
check_fru_asru(enum nodetype t,const char * s,struct node * np)2910Sstevel@tonic-gate check_fru_asru(enum nodetype t, const char *s, struct node *np)
2920Sstevel@tonic-gate {
2930Sstevel@tonic-gate 	ASSERT(s != NULL);
2940Sstevel@tonic-gate 
2950Sstevel@tonic-gate 	/* make sure it is a node type T_NAME? */
2960Sstevel@tonic-gate 	if (np->t == T_NAME) {
2975633Scy152378 		if (s == L_ASRU) {
2985633Scy152378 			if (tree_name2np_lut_lookup_name(ASRUs, np) == NULL)
2995633Scy152378 				outfl(O_ERR, np->file, np->line,
3005633Scy152378 				    "ASRU property contains undeclared asru");
3015633Scy152378 		} else if (s == L_FRU) {
3025633Scy152378 			if (tree_name2np_lut_lookup_name(FRUs, np) == NULL)
3035633Scy152378 				outfl(O_ERR, np->file, np->line,
3045633Scy152378 				    "FRU property contains undeclared fru");
3055633Scy152378 		} else {
3060Sstevel@tonic-gate 			outfl(O_ERR, np->file, np->line,
3075633Scy152378 			    "illegal property name in %s declaration: %s",
3085633Scy152378 			    ptree_nodetype2str(t), s);
3095633Scy152378 		}
3105633Scy152378 		check_type_iterator(np);
3110Sstevel@tonic-gate 	} else
3120Sstevel@tonic-gate 		outfl(O_ERR, np->file, np->line,
3130Sstevel@tonic-gate 		    "illegal type used for %s property: %s",
3140Sstevel@tonic-gate 		    s, ptree_nodetype2str(np->t));
3150Sstevel@tonic-gate 	return (1);
3160Sstevel@tonic-gate }
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate static int
check_engine(enum nodetype t,const char * s,struct node * np)3190Sstevel@tonic-gate check_engine(enum nodetype t, const char *s, struct node *np)
3200Sstevel@tonic-gate {
3210Sstevel@tonic-gate 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
3220Sstevel@tonic-gate 	if (np->t != T_EVENT)
3230Sstevel@tonic-gate 		outfl(O_ERR, np->file, np->line,
3240Sstevel@tonic-gate 		    "%s %s property must be an engine name "
3250Sstevel@tonic-gate 		    "(i.e. serd.x or serd.x@a/b)",
3260Sstevel@tonic-gate 		    ptree_nodetype2str(t), s);
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate 	return (1);
3290Sstevel@tonic-gate }
3300Sstevel@tonic-gate 
3310Sstevel@tonic-gate static int
check_count(enum nodetype t,const char * s,struct node * np)3321414Scindi check_count(enum nodetype t, const char *s, struct node *np)
3331414Scindi {
3341414Scindi 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
3351414Scindi 	if (np->t != T_EVENT)
3361414Scindi 		outfl(O_ERR, np->file, np->line,
3371414Scindi 		    "%s %s property must be an engine name "
3381414Scindi 		    "(i.e. stat.x or stat.x@a/b)",
3391414Scindi 		    ptree_nodetype2str(t), s);
3401414Scindi 
3411414Scindi 	/* XXX confirm engine has been declared */
3421414Scindi 	return (1);
3431414Scindi }
3441414Scindi 
3451414Scindi static int
check_timeval(enum nodetype t,const char * s,struct node * np)3460Sstevel@tonic-gate check_timeval(enum nodetype t, const char *s, struct node *np)
3470Sstevel@tonic-gate {
3480Sstevel@tonic-gate 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
3490Sstevel@tonic-gate 	if (np->t != T_TIMEVAL)
3500Sstevel@tonic-gate 		outfl(O_ERR, np->file, np->line,
3510Sstevel@tonic-gate 		    "%s %s property must be a number with time units",
3520Sstevel@tonic-gate 		    ptree_nodetype2str(t), s);
3530Sstevel@tonic-gate 	return (1);
3540Sstevel@tonic-gate }
3550Sstevel@tonic-gate 
3560Sstevel@tonic-gate static int
check_id(enum nodetype t,const char * s,struct node * np)3570Sstevel@tonic-gate check_id(enum nodetype t, const char *s, struct node *np)
3580Sstevel@tonic-gate {
3590Sstevel@tonic-gate 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
3600Sstevel@tonic-gate 	if (np->t != T_NAME || np->u.name.next || np->u.name.child)
3610Sstevel@tonic-gate 		outfl(O_ERR, np->file, np->line,
3620Sstevel@tonic-gate 		    "%s %s property must be simple name",
3630Sstevel@tonic-gate 		    ptree_nodetype2str(t), s);
3640Sstevel@tonic-gate 	return (1);
3650Sstevel@tonic-gate }
3660Sstevel@tonic-gate 
3670Sstevel@tonic-gate static int
check_serd_method(enum nodetype t,const char * s,struct node * np)3680Sstevel@tonic-gate check_serd_method(enum nodetype t, const char *s, struct node *np)
3690Sstevel@tonic-gate {
3700Sstevel@tonic-gate 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
3710Sstevel@tonic-gate 	if (np->t != T_NAME || np->u.name.next || np->u.name.child ||
3720Sstevel@tonic-gate 	    (np->u.name.s != L_volatile &&
3730Sstevel@tonic-gate 	    np->u.name.s != L_persistent))
3740Sstevel@tonic-gate 		outfl(O_ERR, np->file, np->line,
3750Sstevel@tonic-gate 		    "%s %s property must be \"volatile\" or \"persistent\"",
3760Sstevel@tonic-gate 		    ptree_nodetype2str(t), s);
3770Sstevel@tonic-gate 	return (1);
3780Sstevel@tonic-gate }
3790Sstevel@tonic-gate 
3801414Scindi static int
check_serd_id(enum nodetype t,const char * s,struct node * np)3811414Scindi check_serd_id(enum nodetype t, const char *s, struct node *np)
3821414Scindi {
3831414Scindi 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
3841414Scindi 	if (np->t != T_GLOBID)
3851414Scindi 		outfl(O_ERR, np->file, np->line,
3861414Scindi 		    "%s %s property must be a global ID",
3871414Scindi 		    ptree_nodetype2str(t), s);
3881414Scindi 	return (1);
3891414Scindi }
3901414Scindi 
3910Sstevel@tonic-gate void
check_stmt_required_properties(struct node * stmtnp)3920Sstevel@tonic-gate check_stmt_required_properties(struct node *stmtnp)
3930Sstevel@tonic-gate {
3940Sstevel@tonic-gate 	struct lut *lutp = stmtnp->u.stmt.lutp;
3950Sstevel@tonic-gate 	struct node *np = stmtnp->u.stmt.np;
3960Sstevel@tonic-gate 	int i;
3970Sstevel@tonic-gate 
3980Sstevel@tonic-gate 	for (i = 0; Allowednames[i].t; i++)
3990Sstevel@tonic-gate 		if (stmtnp->t == Allowednames[i].t &&
4000Sstevel@tonic-gate 		    Allowednames[i].required &&
4010Sstevel@tonic-gate 		    tree_s2np_lut_lookup(lutp, Allowednames[i].name) == NULL)
4020Sstevel@tonic-gate 			outfl(Allowednames[i].outflags,
4030Sstevel@tonic-gate 			    np->file, np->line,
4040Sstevel@tonic-gate 			    "%s statement missing property: %s",
4050Sstevel@tonic-gate 			    ptree_nodetype2str(stmtnp->t),
4060Sstevel@tonic-gate 			    Allowednames[i].name);
4070Sstevel@tonic-gate }
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate void
check_stmt_allowed_properties(enum nodetype t,struct node * nvpairnp,struct lut * lutp)4100Sstevel@tonic-gate check_stmt_allowed_properties(enum nodetype t,
4110Sstevel@tonic-gate     struct node *nvpairnp, struct lut *lutp)
4120Sstevel@tonic-gate {
4130Sstevel@tonic-gate 	int i;
4140Sstevel@tonic-gate 	const char *s = nvpairnp->u.expr.left->u.name.s;
4150Sstevel@tonic-gate 	struct node *np;
4160Sstevel@tonic-gate 
4170Sstevel@tonic-gate 	for (i = 0; Allowednames[i].t; i++)
4180Sstevel@tonic-gate 		if (t == Allowednames[i].t && Allowednames[i].name == NULL) {
4190Sstevel@tonic-gate 			/* NULL name means just call checker */
4200Sstevel@tonic-gate 			(*Allowednames[i].checker)(t, s,
4210Sstevel@tonic-gate 			    nvpairnp->u.expr.right);
4220Sstevel@tonic-gate 			return;
4230Sstevel@tonic-gate 		} else if (t == Allowednames[i].t && s == Allowednames[i].name)
4240Sstevel@tonic-gate 			break;
4250Sstevel@tonic-gate 	if (Allowednames[i].name == NULL)
4260Sstevel@tonic-gate 		outfl(O_ERR, nvpairnp->file, nvpairnp->line,
4270Sstevel@tonic-gate 		    "illegal property name in %s declaration: %s",
4280Sstevel@tonic-gate 		    ptree_nodetype2str(t), s);
4290Sstevel@tonic-gate 	else if ((np = tree_s2np_lut_lookup(lutp, s)) != NULL) {
4300Sstevel@tonic-gate 		/*
4310Sstevel@tonic-gate 		 * redeclaring prop is allowed if value is the same
4320Sstevel@tonic-gate 		 */
4330Sstevel@tonic-gate 		if (np->t != nvpairnp->u.expr.right->t)
4340Sstevel@tonic-gate 			outfl(O_ERR, nvpairnp->file, nvpairnp->line,
4350Sstevel@tonic-gate 			    "property redeclared (with differnt type) "
4360Sstevel@tonic-gate 			    "in %s declaration: %s",
4370Sstevel@tonic-gate 			    ptree_nodetype2str(t), s);
4380Sstevel@tonic-gate 		switch (np->t) {
4390Sstevel@tonic-gate 			case T_NUM:
4400Sstevel@tonic-gate 			case T_TIMEVAL:
4410Sstevel@tonic-gate 				if (np->u.ull == nvpairnp->u.expr.right->u.ull)
4420Sstevel@tonic-gate 					return;
4430Sstevel@tonic-gate 				break;
4440Sstevel@tonic-gate 
4450Sstevel@tonic-gate 			case T_NAME:
4460Sstevel@tonic-gate 				if (tree_namecmp(np,
4470Sstevel@tonic-gate 				    nvpairnp->u.expr.right) == 0)
4480Sstevel@tonic-gate 					return;
4490Sstevel@tonic-gate 				break;
4500Sstevel@tonic-gate 
4510Sstevel@tonic-gate 			case T_EVENT:
4520Sstevel@tonic-gate 				if (tree_eventcmp(np,
4530Sstevel@tonic-gate 				    nvpairnp->u.expr.right) == 0)
4540Sstevel@tonic-gate 					return;
4550Sstevel@tonic-gate 				break;
4560Sstevel@tonic-gate 
4570Sstevel@tonic-gate 			default:
4580Sstevel@tonic-gate 				outfl(O_ERR, nvpairnp->file, nvpairnp->line,
4590Sstevel@tonic-gate 				    "value for property \"%s\" is an "
4600Sstevel@tonic-gate 				    "invalid type: %s",
4610Sstevel@tonic-gate 				    nvpairnp->u.expr.left->u.name.s,
4620Sstevel@tonic-gate 				    ptree_nodetype2str(np->t));
4630Sstevel@tonic-gate 				return;
4640Sstevel@tonic-gate 		}
4650Sstevel@tonic-gate 		outfl(O_ERR, nvpairnp->file, nvpairnp->line,
4660Sstevel@tonic-gate 		    "property redeclared in %s declaration: %s",
4670Sstevel@tonic-gate 		    ptree_nodetype2str(t), s);
4680Sstevel@tonic-gate 	} else
4690Sstevel@tonic-gate 		(*Allowednames[i].checker)(t, s, nvpairnp->u.expr.right);
4700Sstevel@tonic-gate }
4710Sstevel@tonic-gate 
4720Sstevel@tonic-gate void
check_propnames(enum nodetype t,struct node * np,int from,int to)4730Sstevel@tonic-gate check_propnames(enum nodetype t, struct node *np, int from, int to)
4740Sstevel@tonic-gate {
4750Sstevel@tonic-gate 	struct node *dnp;
4760Sstevel@tonic-gate 	struct lut *lutp;
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate 	ASSERT(np != NULL);
4790Sstevel@tonic-gate 	ASSERTinfo(np->t == T_EVENT || np->t == T_LIST || np->t == T_ARROW,
4805633Scy152378 	    ptree_nodetype2str(np->t));
4810Sstevel@tonic-gate 
4820Sstevel@tonic-gate 	if (np->t == T_EVENT) {
4830Sstevel@tonic-gate 		switch (np->u.event.ename->u.name.t) {
4840Sstevel@tonic-gate 		case N_UNSPEC:
4850Sstevel@tonic-gate 			outfl(O_ERR, np->file, np->line,
4860Sstevel@tonic-gate 			    "name in %s statement must begin with "
4870Sstevel@tonic-gate 			    "type (example: \"error.\")",
4880Sstevel@tonic-gate 			    ptree_nodetype2str(t));
4890Sstevel@tonic-gate 			return;
4900Sstevel@tonic-gate 		case N_FAULT:
4910Sstevel@tonic-gate 			lutp = Faults;
4920Sstevel@tonic-gate 			if (to) {
4930Sstevel@tonic-gate 				outfl(O_ERR, np->file, np->line,
4940Sstevel@tonic-gate 				    "%s has fault on right side of \"->\"",
4950Sstevel@tonic-gate 				    ptree_nodetype2str(t));
4960Sstevel@tonic-gate 				return;
4970Sstevel@tonic-gate 			}
4980Sstevel@tonic-gate 			if (!from) {
4990Sstevel@tonic-gate 				outfl(O_DIE, np->file, np->line,
5000Sstevel@tonic-gate 				    "internal error: %s has fault without "
5010Sstevel@tonic-gate 				    "from flag",
5020Sstevel@tonic-gate 				    ptree_nodetype2str(t));
5030Sstevel@tonic-gate 			}
5040Sstevel@tonic-gate 			break;
5050Sstevel@tonic-gate 		case N_UPSET:
5060Sstevel@tonic-gate 			lutp = Upsets;
5070Sstevel@tonic-gate 			if (to) {
5080Sstevel@tonic-gate 				outfl(O_ERR, np->file, np->line,
5090Sstevel@tonic-gate 				    "%s has upset on right side of \"->\"",
5100Sstevel@tonic-gate 				    ptree_nodetype2str(t));
5110Sstevel@tonic-gate 				return;
5120Sstevel@tonic-gate 			}
5130Sstevel@tonic-gate 			if (!from)
5140Sstevel@tonic-gate 				outfl(O_DIE, np->file, np->line,
5150Sstevel@tonic-gate 				    "internal error: %s has upset without "
5160Sstevel@tonic-gate 				    "from flag",
5170Sstevel@tonic-gate 				    ptree_nodetype2str(t));
5180Sstevel@tonic-gate 			break;
5190Sstevel@tonic-gate 		case N_DEFECT:
5200Sstevel@tonic-gate 			lutp = Defects;
5210Sstevel@tonic-gate 			if (to) {
5220Sstevel@tonic-gate 				outfl(O_ERR, np->file, np->line,
5230Sstevel@tonic-gate 				    "%s has defect on right side of \"->\"",
5240Sstevel@tonic-gate 				    ptree_nodetype2str(t));
5250Sstevel@tonic-gate 				return;
5260Sstevel@tonic-gate 			}
5270Sstevel@tonic-gate 			if (!from) {
5280Sstevel@tonic-gate 				outfl(O_DIE, np->file, np->line,
5290Sstevel@tonic-gate 				    "internal error: %s has defect without "
5300Sstevel@tonic-gate 				    "from flag",
5310Sstevel@tonic-gate 				    ptree_nodetype2str(t));
5320Sstevel@tonic-gate 			}
5330Sstevel@tonic-gate 			break;
5340Sstevel@tonic-gate 		case N_ERROR:
5350Sstevel@tonic-gate 			lutp = Errors;
5360Sstevel@tonic-gate 			if (!from && !to)
5370Sstevel@tonic-gate 				outfl(O_DIE, np->file, np->line,
5380Sstevel@tonic-gate 				    "%s has error without from or to flags",
5390Sstevel@tonic-gate 				    ptree_nodetype2str(t));
5400Sstevel@tonic-gate 			break;
5410Sstevel@tonic-gate 		case N_EREPORT:
5420Sstevel@tonic-gate 			lutp = Ereports;
5430Sstevel@tonic-gate 			if (from) {
5440Sstevel@tonic-gate 				outfl(O_ERR, np->file, np->line,
5450Sstevel@tonic-gate 				    "%s has report on left side of \"->\"",
5460Sstevel@tonic-gate 				    ptree_nodetype2str(t));
5470Sstevel@tonic-gate 				return;
5480Sstevel@tonic-gate 			}
5490Sstevel@tonic-gate 			if (!to)
5500Sstevel@tonic-gate 				outfl(O_DIE, np->file, np->line,
5510Sstevel@tonic-gate 				    "internal error: %s has report without "
5520Sstevel@tonic-gate 				    "to flag",
5530Sstevel@tonic-gate 				    ptree_nodetype2str(t));
5540Sstevel@tonic-gate 			break;
5550Sstevel@tonic-gate 		default:
5560Sstevel@tonic-gate 			outfl(O_DIE, np->file, np->line,
5570Sstevel@tonic-gate 			    "internal error: check_propnames: "
5580Sstevel@tonic-gate 			    "unexpected type: %d", np->u.name.t);
5590Sstevel@tonic-gate 		}
5600Sstevel@tonic-gate 
5610Sstevel@tonic-gate 		if ((dnp = tree_event2np_lut_lookup(lutp, np)) == NULL) {
5620Sstevel@tonic-gate 			outfl(O_ERR, np->file, np->line,
5630Sstevel@tonic-gate 			    "%s statement contains undeclared event",
5640Sstevel@tonic-gate 			    ptree_nodetype2str(t));
5650Sstevel@tonic-gate 		} else
5660Sstevel@tonic-gate 			dnp->u.stmt.flags |= STMT_REF;
5670Sstevel@tonic-gate 		np->u.event.declp = dnp;
5680Sstevel@tonic-gate 	} else if (np->t == T_LIST) {
5690Sstevel@tonic-gate 		check_propnames(t, np->u.expr.left, from, to);
5700Sstevel@tonic-gate 		check_propnames(t, np->u.expr.right, from, to);
5710Sstevel@tonic-gate 	} else if (np->t == T_ARROW) {
5720Sstevel@tonic-gate 		check_propnames(t, np->u.arrow.lhs, 1, to);
5730Sstevel@tonic-gate 		check_propnames(t, np->u.arrow.rhs, from, 1);
5740Sstevel@tonic-gate 	}
5750Sstevel@tonic-gate }
5760Sstevel@tonic-gate 
5770Sstevel@tonic-gate static struct lut *
record_iterators(struct node * np,struct lut * ex)5780Sstevel@tonic-gate record_iterators(struct node *np, struct lut *ex)
5790Sstevel@tonic-gate {
5800Sstevel@tonic-gate 	if (np == NULL)
5810Sstevel@tonic-gate 		return (ex);
5820Sstevel@tonic-gate 
5830Sstevel@tonic-gate 	switch (np->t) {
5840Sstevel@tonic-gate 	case T_ARROW:
5850Sstevel@tonic-gate 		ex = record_iterators(np->u.arrow.lhs, ex);
5860Sstevel@tonic-gate 		ex = record_iterators(np->u.arrow.rhs, ex);
5870Sstevel@tonic-gate 		break;
5880Sstevel@tonic-gate 
5890Sstevel@tonic-gate 	case T_LIST:
5900Sstevel@tonic-gate 		ex = record_iterators(np->u.expr.left, ex);
5910Sstevel@tonic-gate 		ex = record_iterators(np->u.expr.right, ex);
5920Sstevel@tonic-gate 		break;
5930Sstevel@tonic-gate 
5940Sstevel@tonic-gate 	case T_EVENT:
5950Sstevel@tonic-gate 		ex = record_iterators(np->u.event.epname, ex);
5960Sstevel@tonic-gate 		break;
5970Sstevel@tonic-gate 
5980Sstevel@tonic-gate 	case T_NAME:
5990Sstevel@tonic-gate 		if (np->u.name.child && np->u.name.child->t == T_NAME)
6000Sstevel@tonic-gate 			ex = lut_add(ex, (void *) np->u.name.child->u.name.s,
6010Sstevel@tonic-gate 			    (void *) np, NULL);
6020Sstevel@tonic-gate 		ex = record_iterators(np->u.name.next, ex);
6030Sstevel@tonic-gate 		break;
6040Sstevel@tonic-gate 
6050Sstevel@tonic-gate 	default:
6060Sstevel@tonic-gate 		outfl(O_DIE, np->file, np->line,
6070Sstevel@tonic-gate 		    "record_iterators: internal error: unexpected type: %s",
6080Sstevel@tonic-gate 		    ptree_nodetype2str(np->t));
6090Sstevel@tonic-gate 	}
6100Sstevel@tonic-gate 
6110Sstevel@tonic-gate 	return (ex);
6120Sstevel@tonic-gate }
6130Sstevel@tonic-gate 
6140Sstevel@tonic-gate void
check_exprscope(struct node * np,struct lut * ex)6150Sstevel@tonic-gate check_exprscope(struct node *np, struct lut *ex)
6160Sstevel@tonic-gate {
6170Sstevel@tonic-gate 	if (np == NULL)
6180Sstevel@tonic-gate 		return;
6190Sstevel@tonic-gate 
6200Sstevel@tonic-gate 	switch (np->t) {
6210Sstevel@tonic-gate 	case T_EVENT:
6220Sstevel@tonic-gate 		check_exprscope(np->u.event.eexprlist, ex);
6230Sstevel@tonic-gate 		break;
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate 	case T_ARROW:
6260Sstevel@tonic-gate 		check_exprscope(np->u.arrow.lhs, ex);
6270Sstevel@tonic-gate 		check_exprscope(np->u.arrow.rhs, ex);
6280Sstevel@tonic-gate 		break;
6290Sstevel@tonic-gate 
6300Sstevel@tonic-gate 	case T_NAME:
6310Sstevel@tonic-gate 		if (np->u.name.child && np->u.name.child->t == T_NAME) {
6320Sstevel@tonic-gate 			if (lut_lookup(ex,
6335633Scy152378 			    (void *) np->u.name.child->u.name.s, NULL) == NULL)
6340Sstevel@tonic-gate 				outfl(O_ERR, np->file, np->line,
6355633Scy152378 				    "constraint contains undefined"
6365633Scy152378 				    " iterator: %s",
6375633Scy152378 				    np->u.name.child->u.name.s);
6380Sstevel@tonic-gate 		}
6390Sstevel@tonic-gate 		check_exprscope(np->u.name.next, ex);
6400Sstevel@tonic-gate 		break;
6410Sstevel@tonic-gate 
6420Sstevel@tonic-gate 	case T_QUOTE:
6430Sstevel@tonic-gate 	case T_GLOBID:
6440Sstevel@tonic-gate 		break;
6450Sstevel@tonic-gate 
6460Sstevel@tonic-gate 	case T_ASSIGN:
6470Sstevel@tonic-gate 	case T_NE:
6480Sstevel@tonic-gate 	case T_EQ:
6490Sstevel@tonic-gate 	case T_LIST:
6500Sstevel@tonic-gate 	case T_AND:
6510Sstevel@tonic-gate 	case T_OR:
6520Sstevel@tonic-gate 	case T_NOT:
6530Sstevel@tonic-gate 	case T_ADD:
6540Sstevel@tonic-gate 	case T_SUB:
6550Sstevel@tonic-gate 	case T_MUL:
6560Sstevel@tonic-gate 	case T_DIV:
6570Sstevel@tonic-gate 	case T_MOD:
6580Sstevel@tonic-gate 	case T_LT:
6590Sstevel@tonic-gate 	case T_LE:
6600Sstevel@tonic-gate 	case T_GT:
6610Sstevel@tonic-gate 	case T_GE:
6620Sstevel@tonic-gate 	case T_BITAND:
6630Sstevel@tonic-gate 	case T_BITOR:
6640Sstevel@tonic-gate 	case T_BITXOR:
6650Sstevel@tonic-gate 	case T_BITNOT:
6660Sstevel@tonic-gate 	case T_LSHIFT:
6670Sstevel@tonic-gate 	case T_RSHIFT:
6680Sstevel@tonic-gate 	case T_CONDIF:
6690Sstevel@tonic-gate 	case T_CONDELSE:
6700Sstevel@tonic-gate 		check_exprscope(np->u.expr.left, ex);
6710Sstevel@tonic-gate 		check_exprscope(np->u.expr.right, ex);
6720Sstevel@tonic-gate 		break;
6730Sstevel@tonic-gate 
6740Sstevel@tonic-gate 	case T_FUNC:
6750Sstevel@tonic-gate 		check_exprscope(np->u.func.arglist, ex);
6760Sstevel@tonic-gate 		break;
6770Sstevel@tonic-gate 
6780Sstevel@tonic-gate 	case T_NUM:
6790Sstevel@tonic-gate 	case T_TIMEVAL:
6800Sstevel@tonic-gate 		break;
6810Sstevel@tonic-gate 
6820Sstevel@tonic-gate 	default:
6830Sstevel@tonic-gate 		outfl(O_DIE, np->file, np->line,
6840Sstevel@tonic-gate 		    "check_exprscope: internal error: unexpected type: %s",
6850Sstevel@tonic-gate 		    ptree_nodetype2str(np->t));
6860Sstevel@tonic-gate 	}
6870Sstevel@tonic-gate }
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate /*
6900Sstevel@tonic-gate  * check_propscope -- check constraints for out of scope variable refs
6910Sstevel@tonic-gate  */
6920Sstevel@tonic-gate void
check_propscope(struct node * np)6930Sstevel@tonic-gate check_propscope(struct node *np)
6940Sstevel@tonic-gate {
6950Sstevel@tonic-gate 	struct lut *ex;
6960Sstevel@tonic-gate 
6970Sstevel@tonic-gate 	ex = record_iterators(np, NULL);
6980Sstevel@tonic-gate 	check_exprscope(np, ex);
6990Sstevel@tonic-gate 	lut_free(ex, NULL, NULL);
7000Sstevel@tonic-gate }
7010Sstevel@tonic-gate 
7020Sstevel@tonic-gate /*
7030Sstevel@tonic-gate  * check_upset_engine -- validate the engine property in an upset statement
7040Sstevel@tonic-gate  *
7050Sstevel@tonic-gate  * we do this after the full parse tree has been constructed rather than while
7060Sstevel@tonic-gate  * building the parse tree because it is inconvenient for the user if we
7070Sstevel@tonic-gate  * require SERD engines to be declared before used in an upset "engine"
7080Sstevel@tonic-gate  * property.
7090Sstevel@tonic-gate  */
7100Sstevel@tonic-gate 
7110Sstevel@tonic-gate /*ARGSUSED*/
7120Sstevel@tonic-gate void
check_upset_engine(struct node * lhs,struct node * rhs,void * arg)7130Sstevel@tonic-gate check_upset_engine(struct node *lhs, struct node *rhs, void *arg)
7140Sstevel@tonic-gate {
7150Sstevel@tonic-gate 	enum nodetype t = (enum nodetype)arg;
7160Sstevel@tonic-gate 	struct node *engnp;
7170Sstevel@tonic-gate 	struct node *declp;
7180Sstevel@tonic-gate 
7190Sstevel@tonic-gate 	ASSERTeq(rhs->t, t, ptree_nodetype2str);
7200Sstevel@tonic-gate 
7210Sstevel@tonic-gate 	if ((engnp = tree_s2np_lut_lookup(rhs->u.stmt.lutp, L_engine)) == NULL)
7220Sstevel@tonic-gate 		return;
7230Sstevel@tonic-gate 
7240Sstevel@tonic-gate 	ASSERT(engnp->t == T_EVENT);
7250Sstevel@tonic-gate 
7260Sstevel@tonic-gate 	if ((declp = tree_event2np_lut_lookup(SERDs, engnp)) == NULL) {
7270Sstevel@tonic-gate 		outfl(O_ERR, engnp->file, engnp->line,
7280Sstevel@tonic-gate 		    "%s %s property contains undeclared name",
7290Sstevel@tonic-gate 		    ptree_nodetype2str(t), L_engine);
7300Sstevel@tonic-gate 		return;
7310Sstevel@tonic-gate 	}
7320Sstevel@tonic-gate 	engnp->u.event.declp = declp;
7330Sstevel@tonic-gate }
7340Sstevel@tonic-gate 
7350Sstevel@tonic-gate /*
7360Sstevel@tonic-gate  * check_refcount -- see if declared names are used
7370Sstevel@tonic-gate  *
7380Sstevel@tonic-gate  * this is run after the entire parse tree is constructed, so a refcount
7390Sstevel@tonic-gate  * of zero means the name has been declared but otherwise not used.
7400Sstevel@tonic-gate  */
7410Sstevel@tonic-gate 
7420Sstevel@tonic-gate void
check_refcount(struct node * lhs,struct node * rhs,void * arg)7430Sstevel@tonic-gate check_refcount(struct node *lhs, struct node *rhs, void *arg)
7440Sstevel@tonic-gate {
7450Sstevel@tonic-gate 	enum nodetype t = (enum nodetype)arg;
7460Sstevel@tonic-gate 
7470Sstevel@tonic-gate 	ASSERTeq(rhs->t, t, ptree_nodetype2str);
7480Sstevel@tonic-gate 
7490Sstevel@tonic-gate 	if (rhs->u.stmt.flags & STMT_REF)
7500Sstevel@tonic-gate 		return;
7510Sstevel@tonic-gate 
7520Sstevel@tonic-gate 	outfl(O_WARN|O_NONL, rhs->file, rhs->line,
7530Sstevel@tonic-gate 	    "%s name declared but not used: ", ptree_nodetype2str(t));
7540Sstevel@tonic-gate 	ptree_name(O_WARN|O_NONL, lhs);
7550Sstevel@tonic-gate 	out(O_WARN, NULL);
7560Sstevel@tonic-gate }
7570Sstevel@tonic-gate 
7580Sstevel@tonic-gate /*
7590Sstevel@tonic-gate  * set check_cycle_warninglevel only for val >= 0
7600Sstevel@tonic-gate  */
7610Sstevel@tonic-gate int
check_cycle_level(long long val)7620Sstevel@tonic-gate check_cycle_level(long long val)
7630Sstevel@tonic-gate {
7640Sstevel@tonic-gate 	static int check_cycle_warninglevel = -1;
7650Sstevel@tonic-gate 
7660Sstevel@tonic-gate 	if (val == 0)
7670Sstevel@tonic-gate 		check_cycle_warninglevel = 0;
7680Sstevel@tonic-gate 	else if (val > 0)
7690Sstevel@tonic-gate 		check_cycle_warninglevel = 1;
7700Sstevel@tonic-gate 
7710Sstevel@tonic-gate 	return (check_cycle_warninglevel);
7720Sstevel@tonic-gate }
7730Sstevel@tonic-gate 
7740Sstevel@tonic-gate /*
7750Sstevel@tonic-gate  * check_cycle -- see props from an error have cycles
7760Sstevel@tonic-gate  *
7770Sstevel@tonic-gate  * this is run after the entire parse tree is constructed, for
7780Sstevel@tonic-gate  * each error that has been declared.
7790Sstevel@tonic-gate  */
7800Sstevel@tonic-gate 
7810Sstevel@tonic-gate /*ARGSUSED*/
7820Sstevel@tonic-gate void
check_cycle(struct node * lhs,struct node * rhs,void * arg)7830Sstevel@tonic-gate check_cycle(struct node *lhs, struct node *rhs, void *arg)
7840Sstevel@tonic-gate {
7850Sstevel@tonic-gate 	struct node *np;
7860Sstevel@tonic-gate 
7870Sstevel@tonic-gate 	ASSERTeq(rhs->t, T_ERROR, ptree_nodetype2str);
7880Sstevel@tonic-gate 
7890Sstevel@tonic-gate 	if (rhs->u.stmt.flags & STMT_CYCLE)
7900Sstevel@tonic-gate 		return;		/* already reported this cycle */
7910Sstevel@tonic-gate 
7920Sstevel@tonic-gate 	if (rhs->u.stmt.flags & STMT_CYMARK) {
7930Sstevel@tonic-gate #ifdef ESC
7940Sstevel@tonic-gate 		int warninglevel;
7950Sstevel@tonic-gate 
7960Sstevel@tonic-gate 		warninglevel = check_cycle_level(-1);
7970Sstevel@tonic-gate 		if (warninglevel <= 0) {
7980Sstevel@tonic-gate 			int olevel = O_ERR;
7990Sstevel@tonic-gate 
8000Sstevel@tonic-gate 			if (warninglevel == 0)
8010Sstevel@tonic-gate 				olevel = O_WARN;
8020Sstevel@tonic-gate 
8030Sstevel@tonic-gate 			out(olevel|O_NONL, "cycle in propagation tree: ");
8040Sstevel@tonic-gate 			ptree_name(olevel|O_NONL, rhs->u.stmt.np);
8050Sstevel@tonic-gate 			out(olevel, NULL);
8060Sstevel@tonic-gate 		}
8070Sstevel@tonic-gate #endif /* ESC */
8080Sstevel@tonic-gate 
8090Sstevel@tonic-gate 		rhs->u.stmt.flags |= STMT_CYCLE;
8100Sstevel@tonic-gate 	}
8110Sstevel@tonic-gate 
8120Sstevel@tonic-gate 	rhs->u.stmt.flags |= STMT_CYMARK;
8130Sstevel@tonic-gate 
8140Sstevel@tonic-gate 	/* for each propagation */
8150Sstevel@tonic-gate 	for (np = Props; np; np = np->u.stmt.next)
8160Sstevel@tonic-gate 		check_cycle_lhs(rhs, np->u.stmt.np);
8170Sstevel@tonic-gate 
8180Sstevel@tonic-gate 	rhs->u.stmt.flags &= ~STMT_CYMARK;
8190Sstevel@tonic-gate }
8200Sstevel@tonic-gate 
8210Sstevel@tonic-gate /*
8220Sstevel@tonic-gate  * check_cycle_lhs -- find the lhs of an arrow for cycle checking
8230Sstevel@tonic-gate  */
8240Sstevel@tonic-gate 
8250Sstevel@tonic-gate static void
check_cycle_lhs(struct node * stmtnp,struct node * arrow)8260Sstevel@tonic-gate check_cycle_lhs(struct node *stmtnp, struct node *arrow)
8270Sstevel@tonic-gate {
8280Sstevel@tonic-gate 	struct node *trylhs;
8290Sstevel@tonic-gate 	struct node *tryrhs;
8300Sstevel@tonic-gate 
8310Sstevel@tonic-gate 	/* handle cascaded arrows */
8320Sstevel@tonic-gate 	switch (arrow->u.arrow.lhs->t) {
8330Sstevel@tonic-gate 	case T_ARROW:
8340Sstevel@tonic-gate 		/* first recurse left */
8350Sstevel@tonic-gate 		check_cycle_lhs(stmtnp, arrow->u.arrow.lhs);
8360Sstevel@tonic-gate 
837854Srw145199 		/*
838854Srw145199 		 * return if there's a list of events internal to
839854Srw145199 		 * cascaded props (which is not allowed)
8401414Scindi 		 */
841854Srw145199 		if (arrow->u.arrow.lhs->u.arrow.rhs->t != T_EVENT)
842854Srw145199 			return;
8430Sstevel@tonic-gate 
8440Sstevel@tonic-gate 		/* then try this arrow (thing cascaded *to*) */
8450Sstevel@tonic-gate 		trylhs = arrow->u.arrow.lhs->u.arrow.rhs;
8460Sstevel@tonic-gate 		tryrhs = arrow->u.arrow.rhs;
8470Sstevel@tonic-gate 		break;
8480Sstevel@tonic-gate 
8490Sstevel@tonic-gate 	case T_EVENT:
8500Sstevel@tonic-gate 	case T_LIST:
8510Sstevel@tonic-gate 		trylhs = arrow->u.arrow.lhs;
8520Sstevel@tonic-gate 		tryrhs = arrow->u.arrow.rhs;
8530Sstevel@tonic-gate 		break;
8540Sstevel@tonic-gate 
8550Sstevel@tonic-gate 	default:
8560Sstevel@tonic-gate 		out(O_DIE, "lhs: unexpected type: %s",
8570Sstevel@tonic-gate 		    ptree_nodetype2str(arrow->u.arrow.lhs->t));
8580Sstevel@tonic-gate 		/*NOTREACHED*/
8590Sstevel@tonic-gate 	}
8600Sstevel@tonic-gate 
8610Sstevel@tonic-gate 	check_cycle_lhs_try(stmtnp, trylhs, tryrhs);
8620Sstevel@tonic-gate }
8630Sstevel@tonic-gate 
8640Sstevel@tonic-gate /*
8650Sstevel@tonic-gate  * check_cycle_lhs_try -- try matching an event name on lhs of an arrow
8660Sstevel@tonic-gate  */
8670Sstevel@tonic-gate 
8680Sstevel@tonic-gate static void
check_cycle_lhs_try(struct node * stmtnp,struct node * lhs,struct node * rhs)8690Sstevel@tonic-gate check_cycle_lhs_try(struct node *stmtnp, struct node *lhs, struct node *rhs)
8700Sstevel@tonic-gate {
8710Sstevel@tonic-gate 	if (lhs->t == T_LIST) {
8720Sstevel@tonic-gate 		check_cycle_lhs_try(stmtnp, lhs->u.expr.left, rhs);
8730Sstevel@tonic-gate 		check_cycle_lhs_try(stmtnp, lhs->u.expr.right, rhs);
8740Sstevel@tonic-gate 		return;
8750Sstevel@tonic-gate 	}
8760Sstevel@tonic-gate 
8770Sstevel@tonic-gate 	ASSERT(lhs->t == T_EVENT);
8780Sstevel@tonic-gate 
8790Sstevel@tonic-gate 	if (tree_eventcmp(stmtnp->u.stmt.np, lhs) != 0)
8800Sstevel@tonic-gate 		return;		/* no match */
8810Sstevel@tonic-gate 
8820Sstevel@tonic-gate 	check_cycle_rhs(rhs);
8830Sstevel@tonic-gate }
8840Sstevel@tonic-gate 
8850Sstevel@tonic-gate /*
8860Sstevel@tonic-gate  * check_cycle_rhs -- foreach error on rhs, see if we cycle to a marked error
8870Sstevel@tonic-gate  */
8880Sstevel@tonic-gate 
8890Sstevel@tonic-gate static void
check_cycle_rhs(struct node * rhs)8900Sstevel@tonic-gate check_cycle_rhs(struct node *rhs)
8910Sstevel@tonic-gate {
8920Sstevel@tonic-gate 	struct node *dnp;
8930Sstevel@tonic-gate 
8940Sstevel@tonic-gate 	if (rhs->t == T_LIST) {
8950Sstevel@tonic-gate 		check_cycle_rhs(rhs->u.expr.left);
8960Sstevel@tonic-gate 		check_cycle_rhs(rhs->u.expr.right);
8970Sstevel@tonic-gate 		return;
8980Sstevel@tonic-gate 	}
8990Sstevel@tonic-gate 
9000Sstevel@tonic-gate 	ASSERT(rhs->t == T_EVENT);
9010Sstevel@tonic-gate 
9020Sstevel@tonic-gate 	if (rhs->u.event.ename->u.name.t != N_ERROR)
9030Sstevel@tonic-gate 		return;
9040Sstevel@tonic-gate 
9050Sstevel@tonic-gate 	if ((dnp = tree_event2np_lut_lookup(Errors, rhs)) == NULL) {
9060Sstevel@tonic-gate 		outfl(O_ERR|O_NONL,
9070Sstevel@tonic-gate 		    rhs->file, rhs->line,
9080Sstevel@tonic-gate 		    "unexpected undeclared event during cycle check");
9090Sstevel@tonic-gate 		ptree_name(O_ERR|O_NONL, rhs);
9100Sstevel@tonic-gate 		out(O_ERR, NULL);
9110Sstevel@tonic-gate 		return;
9120Sstevel@tonic-gate 	}
9130Sstevel@tonic-gate 	check_cycle(NULL, dnp, 0);
9140Sstevel@tonic-gate }
9150Sstevel@tonic-gate 
9160Sstevel@tonic-gate /*
9170Sstevel@tonic-gate  * Force iterators to be simple names, expressions, or numbers
9180Sstevel@tonic-gate  */
9190Sstevel@tonic-gate void
check_name_iterator(struct node * np)9200Sstevel@tonic-gate check_name_iterator(struct node *np)
9210Sstevel@tonic-gate {
9220Sstevel@tonic-gate 	if (np->u.name.child->t != T_NUM &&
9230Sstevel@tonic-gate 	    np->u.name.child->t != T_NAME &&
9240Sstevel@tonic-gate 	    np->u.name.child->t != T_CONDIF &&
9250Sstevel@tonic-gate 	    np->u.name.child->t != T_SUB &&
9260Sstevel@tonic-gate 	    np->u.name.child->t != T_ADD &&
9270Sstevel@tonic-gate 	    np->u.name.child->t != T_MUL &&
9280Sstevel@tonic-gate 	    np->u.name.child->t != T_DIV &&
9290Sstevel@tonic-gate 	    np->u.name.child->t != T_MOD &&
9300Sstevel@tonic-gate 	    np->u.name.child->t != T_LSHIFT &&
9310Sstevel@tonic-gate 	    np->u.name.child->t != T_RSHIFT) {
9320Sstevel@tonic-gate 		outfl(O_ERR|O_NONL, np->file, np->line,
9330Sstevel@tonic-gate 		"invalid iterator: ");
9340Sstevel@tonic-gate 		ptree_name_iter(O_ERR|O_NONL, np);
9350Sstevel@tonic-gate 		out(O_ERR, NULL);
9360Sstevel@tonic-gate 	}
9370Sstevel@tonic-gate }
9380Sstevel@tonic-gate 
9390Sstevel@tonic-gate /*
9400Sstevel@tonic-gate  * Iterators on a declaration may only be implicit
9410Sstevel@tonic-gate  */
9420Sstevel@tonic-gate void
check_type_iterator(struct node * np)9430Sstevel@tonic-gate check_type_iterator(struct node *np)
9440Sstevel@tonic-gate {
9450Sstevel@tonic-gate 	while (np != NULL) {
9460Sstevel@tonic-gate 		if (np->t == T_EVENT) {
9470Sstevel@tonic-gate 			np = np->u.event.epname;
9480Sstevel@tonic-gate 		} else if (np->t == T_NAME) {
9490Sstevel@tonic-gate 			if (np->u.name.child != NULL &&
9500Sstevel@tonic-gate 			    np->u.name.child->t != T_NUM) {
9510Sstevel@tonic-gate 				outfl(O_ERR|O_NONL, np->file, np->line,
9520Sstevel@tonic-gate 				    "explicit iterators disallowed "
9530Sstevel@tonic-gate 				    "in declarations: ");
9540Sstevel@tonic-gate 				ptree_name_iter(O_ERR|O_NONL, np);
9550Sstevel@tonic-gate 				out(O_ERR, NULL);
9560Sstevel@tonic-gate 			}
9570Sstevel@tonic-gate 			np = np->u.name.next;
9580Sstevel@tonic-gate 		} else {
9590Sstevel@tonic-gate 			break;
9600Sstevel@tonic-gate 		}
9610Sstevel@tonic-gate 	}
9620Sstevel@tonic-gate }
9630Sstevel@tonic-gate 
9640Sstevel@tonic-gate void
check_cat_list(struct node * np)965*11202SStephen.Hanson@Sun.COM check_cat_list(struct node *np)
966*11202SStephen.Hanson@Sun.COM {
967*11202SStephen.Hanson@Sun.COM 	if (np->t == T_FUNC)
968*11202SStephen.Hanson@Sun.COM 		check_func(np);
969*11202SStephen.Hanson@Sun.COM 	else if (np->t == T_LIST) {
970*11202SStephen.Hanson@Sun.COM 		check_cat_list(np->u.expr.left);
971*11202SStephen.Hanson@Sun.COM 		check_cat_list(np->u.expr.right);
972*11202SStephen.Hanson@Sun.COM 	}
973*11202SStephen.Hanson@Sun.COM }
974*11202SStephen.Hanson@Sun.COM 
975*11202SStephen.Hanson@Sun.COM void
check_func(struct node * np)9760Sstevel@tonic-gate check_func(struct node *np)
9770Sstevel@tonic-gate {
9786806Scth 	struct node *arglist = np->u.func.arglist;
9796806Scth 
9800Sstevel@tonic-gate 	ASSERTinfo(np->t == T_FUNC, ptree_nodetype2str(np->t));
9810Sstevel@tonic-gate 
9820Sstevel@tonic-gate 	if (np->u.func.s == L_within) {
9830Sstevel@tonic-gate 		switch (arglist->t) {
9846806Scth 		case T_NUM:
9856806Scth 			if (arglist->u.ull != 0ULL) {
9866806Scth 				outfl(O_ERR, arglist->file, arglist->line,
9876806Scth 				    "parameter of within must be 0"
9886806Scth 				    ", \"infinity\" or a time value.");
9896806Scth 			}
9906806Scth 			break;
9916806Scth 
9926806Scth 		case T_NAME:
9936806Scth 			if (arglist->u.name.s != L_infinity) {
9946806Scth 				outfl(O_ERR, arglist->file, arglist->line,
9956806Scth 				    "parameter of within must be 0"
9966806Scth 				    ", \"infinity\" or a time value.");
9976806Scth 			}
9986806Scth 			break;
9996806Scth 
10006806Scth 		case T_LIST:
10016806Scth 			/*
10026806Scth 			 * if two parameters, the left or min must be
10036806Scth 			 * either T_NUM or T_TIMEVAL
10046806Scth 			 */
10056806Scth 			if (arglist->u.expr.left->t != T_NUM &&
10066806Scth 			    arglist->u.expr.left->t != T_TIMEVAL) {
10076806Scth 				outfl(O_ERR, arglist->file, arglist->line,
10086806Scth 				    "first parameter of within must be"
10096806Scth 				    " either a time value or zero.");
10106806Scth 			}
10110Sstevel@tonic-gate 
10126640Scth 			/*
10136640Scth 			 * if two parameters, the right or max must
10146640Scth 			 * be either T_NUM, T_NAME or T_TIMEVAL
10156640Scth 			 */
10166640Scth 			if (arglist->u.expr.right->t != T_NUM &&
10176640Scth 			    arglist->u.expr.right->t != T_TIMEVAL &&
10186806Scth 			    arglist->u.expr.right->t != T_NAME) {
10196806Scth 				outfl(O_ERR, arglist->file, arglist->line,
10206640Scth 				    "second parameter of within must "
10216806Scth 				    "be 0, \"infinity\" or time value.");
10226806Scth 			}
10230Sstevel@tonic-gate 
10246806Scth 			/*
10256806Scth 			 * if right or left is a T_NUM it must
10266806Scth 			 * be zero
10276806Scth 			 */
10286806Scth 			if ((arglist->u.expr.left->t == T_NUM) &&
10296806Scth 			    (arglist->u.expr.left->u.ull != 0ULL)) {
10306806Scth 				outfl(O_ERR, arglist->file, arglist->line,
10316806Scth 				    "within parameter must be "
10326806Scth 				    "0 or a time value.");
10336806Scth 			}
10346806Scth 			if ((arglist->u.expr.right->t == T_NUM) &&
10356806Scth 			    (arglist->u.expr.right->u.ull != 0ULL)) {
10366806Scth 				outfl(O_ERR, arglist->file, arglist->line,
10376806Scth 				    "within parameter must be "
10386806Scth 				    "0 or a time value.");
10396806Scth 			}
10400Sstevel@tonic-gate 
10416806Scth 			/* if right is a T_NAME it must be "infinity" */
10426806Scth 			if ((arglist->u.expr.right->t == T_NAME) &&
10436806Scth 			    (arglist->u.expr.right->u.name.s != L_infinity)) {
10446806Scth 				outfl(O_ERR, arglist->file, arglist->line,
10456806Scth 				    "\"infinity\" is the only "
10466806Scth 				    "valid name for within parameter.");
10476806Scth 			}
10480Sstevel@tonic-gate 
10496640Scth 			/*
10506640Scth 			 * the first parameter [min] must not be greater
10516640Scth 			 * than the second parameter [max].
10526640Scth 			 */
10536640Scth 			if (arglist->u.expr.left->u.ull >
10546806Scth 			    arglist->u.expr.right->u.ull) {
10550Sstevel@tonic-gate 				outfl(O_ERR, arglist->file, arglist->line,
10566806Scth 				    "the first value (min) of"
10576806Scth 				    " within must be less than"
10586806Scth 				    " the second (max) value");
10596806Scth 			}
10606806Scth 			break;
10616806Scth 
10626806Scth 		case T_TIMEVAL:
10636806Scth 			break; /* no restrictions on T_TIMEVAL */
10646806Scth 
10656806Scth 		default:
10666806Scth 			outfl(O_ERR, arglist->file, arglist->line,
10676806Scth 			    "parameter of within must be 0"
10686806Scth 			    ", \"infinity\" or a time value.");
10690Sstevel@tonic-gate 		}
10700Sstevel@tonic-gate 	} else if (np->u.func.s == L_call) {
10716806Scth 		if (arglist->t != T_QUOTE &&
10726806Scth 		    arglist->t != T_LIST &&
10736806Scth 		    arglist->t != T_GLOBID &&
10746806Scth 		    arglist->t != T_CONDIF &&
10756806Scth 		    arglist->t != T_LIST &&
10766806Scth 		    arglist->t != T_FUNC)
10776806Scth 			outfl(O_ERR, arglist->file, arglist->line,
10785633Scy152378 			    "invalid first argument to call()");
10790Sstevel@tonic-gate 	} else if (np->u.func.s == L_fru) {
10806806Scth 		if (arglist->t != T_NAME)
10816806Scth 			outfl(O_ERR, arglist->file, arglist->line,
10825633Scy152378 			    "argument to fru() must be a path");
10830Sstevel@tonic-gate 	} else if (np->u.func.s == L_asru) {
10846806Scth 		if (arglist->t != T_NAME)
10856806Scth 			outfl(O_ERR, arglist->file, arglist->line,
10865633Scy152378 			    "argument to asru() must be a path");
10870Sstevel@tonic-gate 	} else if (np->u.func.s == L_is_connected ||
10880Sstevel@tonic-gate 	    np->u.func.s == L_is_under) {
10896806Scth 		if (arglist->t == T_LIST &&
10906806Scth 		    (arglist->u.expr.left->t == T_NAME ||
1091*11202SStephen.Hanson@Sun.COM 		    arglist->u.expr.left->t == T_FUNC) &&
10926806Scth 		    (arglist->u.expr.right->t == T_NAME ||
1093*11202SStephen.Hanson@Sun.COM 		    arglist->u.expr.right->t == T_FUNC)) {
10946806Scth 			if (arglist->u.expr.left->t == T_FUNC)
10956806Scth 				check_func(arglist->u.expr.left);
10966806Scth 			if (arglist->u.expr.right->t == T_FUNC)
10976806Scth 				check_func(arglist->u.expr.right);
10980Sstevel@tonic-gate 		} else {
10996806Scth 			outfl(O_ERR, arglist->file, arglist->line,
11000Sstevel@tonic-gate 			    "%s() must have paths or calls to "
11010Sstevel@tonic-gate 			    "fru() and/or asru() as arguments",
11020Sstevel@tonic-gate 			    np->u.func.s);
11030Sstevel@tonic-gate 		}
11040Sstevel@tonic-gate 	} else if (np->u.func.s == L_is_on) {
1105*11202SStephen.Hanson@Sun.COM 		if (arglist->t == T_NAME || arglist->t == T_FUNC) {
11067197Sstephh 			if (arglist->t == T_FUNC)
11077197Sstephh 				check_func(arglist);
11080Sstevel@tonic-gate 		} else {
11096806Scth 			outfl(O_ERR, arglist->file, arglist->line,
11107197Sstephh 			    "argument to is_on() must be a path or a call to "
11110Sstevel@tonic-gate 			    "fru() or asru()");
11120Sstevel@tonic-gate 		}
11130Sstevel@tonic-gate 	} else if (np->u.func.s == L_is_present) {
1114*11202SStephen.Hanson@Sun.COM 		if (arglist->t == T_NAME || arglist->t == T_FUNC) {
11157197Sstephh 			if (arglist->t == T_FUNC)
11167197Sstephh 				check_func(arglist);
11170Sstevel@tonic-gate 		} else {
11186806Scth 			outfl(O_ERR, arglist->file, arglist->line,
11197197Sstephh 			    "argument to is_present() must be a path or a call "
11207197Sstephh 			    "to fru() or asru()");
11210Sstevel@tonic-gate 		}
11227275Sstephh 	} else if (np->u.func.s == L_has_fault) {
11237275Sstephh 		if (arglist->t == T_LIST &&
11247275Sstephh 		    (arglist->u.expr.left->t == T_NAME ||
1125*11202SStephen.Hanson@Sun.COM 		    arglist->u.expr.left->t == T_FUNC) &&
11267275Sstephh 		    arglist->u.expr.right->t == T_QUOTE) {
11277275Sstephh 			if (arglist->u.expr.left->t == T_FUNC)
11287275Sstephh 				check_func(arglist->u.expr.left);
11297275Sstephh 		} else {
11307275Sstephh 			outfl(O_ERR, arglist->file, arglist->line,
11317275Sstephh 			    "%s() must have path or call to "
11327275Sstephh 			    "fru() and/or asru() as first argument; "
11337275Sstephh 			    "second argument must be a string", np->u.func.s);
11347275Sstephh 		}
11350Sstevel@tonic-gate 	} else if (np->u.func.s == L_is_type) {
1136*11202SStephen.Hanson@Sun.COM 		if (arglist->t == T_NAME || arglist->t == T_FUNC) {
11377197Sstephh 			if (arglist->t == T_FUNC)
11387197Sstephh 				check_func(arglist);
11390Sstevel@tonic-gate 		} else {
11406806Scth 			outfl(O_ERR, arglist->file, arglist->line,
11417197Sstephh 			    "argument to is_type() must be a path or a call to "
11420Sstevel@tonic-gate 			    "fru() or asru()");
11430Sstevel@tonic-gate 		}
11441414Scindi 	} else if (np->u.func.s == L_confcall) {
11456806Scth 		if (arglist->t != T_QUOTE &&
11466806Scth 		    (arglist->t != T_LIST ||
11476806Scth 		    arglist->u.expr.left->t != T_QUOTE))
11486806Scth 			outfl(O_ERR, arglist->file, arglist->line,
11491414Scindi 			    "confcall(): first argument must be a string "
11501414Scindi 			    "(the name of the operation)");
11512869Sgavinm 	} else if (np->u.func.s == L_confprop ||
11522869Sgavinm 	    np->u.func.s == L_confprop_defined) {
11536806Scth 		if (arglist->t == T_LIST &&
11547197Sstephh 		    (arglist->u.expr.left->t == T_NAME ||
1155*11202SStephen.Hanson@Sun.COM 		    arglist->u.expr.left->t == T_FUNC) &&
11566806Scth 		    arglist->u.expr.right->t == T_QUOTE) {
11577197Sstephh 			if (arglist->u.expr.left->t == T_FUNC)
11587197Sstephh 				check_func(arglist->u.expr.left);
11590Sstevel@tonic-gate 		} else {
11606806Scth 			outfl(O_ERR, arglist->file, arglist->line,
11617197Sstephh 			    "%s(): first argument must be a path or a call to "
11620Sstevel@tonic-gate 			    "fru() or asru(); "
11632869Sgavinm 			    "second argument must be a string", np->u.func.s);
11640Sstevel@tonic-gate 		}
11651414Scindi 	} else if (np->u.func.s == L_count) {
11666806Scth 		if (arglist->t != T_EVENT) {
11676806Scth 			outfl(O_ERR, arglist->file, arglist->line,
11681414Scindi 			    "count(): argument must be an engine name");
11691414Scindi 		}
11701414Scindi 	} else if (np->u.func.s == L_defined) {
11716806Scth 		if (arglist->t != T_GLOBID)
11726806Scth 			outfl(O_ERR, arglist->file, arglist->line,
11735633Scy152378 			    "argument to defined() must be a global");
11740Sstevel@tonic-gate 	} else if (np->u.func.s == L_payloadprop) {
11756806Scth 		if (arglist->t != T_QUOTE)
11766806Scth 			outfl(O_ERR, arglist->file, arglist->line,
11775633Scy152378 			    "argument to payloadprop() must be a string");
11781414Scindi 	} else if (np->u.func.s == L_payloadprop_contains) {
11796806Scth 		if (arglist->t != T_LIST ||
11806806Scth 		    arglist->u.expr.left->t != T_QUOTE ||
11816806Scth 		    arglist->u.expr.right == NULL)
11826806Scth 			outfl(O_ERR, arglist->file, arglist->line,
11831414Scindi 			    "args to payloadprop_contains(): must be a quoted "
11841414Scindi 			    "string (property name) and an expression "
11851414Scindi 			    "(to match)");
11861414Scindi 	} else if (np->u.func.s == L_payloadprop_defined) {
11876806Scth 		if (arglist->t != T_QUOTE)
11886806Scth 			outfl(O_ERR, arglist->file, arglist->line,
11891414Scindi 			    "arg to payloadprop_defined(): must be a quoted "
11901414Scindi 			    "string");
11911414Scindi 	} else if (np->u.func.s == L_setpayloadprop) {
11926806Scth 		if (arglist->t == T_LIST &&
11936806Scth 		    arglist->u.expr.left->t == T_QUOTE) {
11946806Scth 			if (arglist->u.expr.right->t == T_FUNC)
11956806Scth 				check_func(arglist->u.expr.right);
11961414Scindi 		} else {
11976806Scth 			outfl(O_ERR, arglist->file, arglist->line,
11981414Scindi 			    "setpayloadprop(): "
11991414Scindi 			    "first arg must be a string, "
12001414Scindi 			    "second arg a value");
12011414Scindi 		}
12027197Sstephh 	} else if (np->u.func.s == L_setserdn || np->u.func.s == L_setserdt ||
12037197Sstephh 	    np->u.func.s == L_setserdsuffix || np->u.func.s ==
12047197Sstephh 	    L_setserdincrement) {
12057197Sstephh 		if (arglist->t == T_FUNC)
12067197Sstephh 			check_func(arglist);
1207*11202SStephen.Hanson@Sun.COM 	} else if (np->u.func.s == L_cat) {
1208*11202SStephen.Hanson@Sun.COM 		check_cat_list(arglist);
12090Sstevel@tonic-gate 	} else if (np->u.func.s == L_envprop) {
12106806Scth 		if (arglist->t != T_QUOTE)
12116806Scth 			outfl(O_ERR, arglist->file, arglist->line,
12125633Scy152378 			    "argument to envprop() must be a string");
12130Sstevel@tonic-gate 	} else
12140Sstevel@tonic-gate 		outfl(O_WARN, np->file, np->line,
12155633Scy152378 		    "possible platform-specific function: %s",
12165633Scy152378 		    np->u.func.s);
12170Sstevel@tonic-gate }
12180Sstevel@tonic-gate 
12190Sstevel@tonic-gate void
check_expr(struct node * np)12200Sstevel@tonic-gate check_expr(struct node *np)
12210Sstevel@tonic-gate {
12220Sstevel@tonic-gate 	ASSERT(np != NULL);
12230Sstevel@tonic-gate 
12240Sstevel@tonic-gate 	switch (np->t) {
12250Sstevel@tonic-gate 	case T_ASSIGN:
12260Sstevel@tonic-gate 		ASSERT(np->u.expr.left != NULL);
12270Sstevel@tonic-gate 		if (np->u.expr.left->t != T_GLOBID)
12280Sstevel@tonic-gate 			outfl(O_ERR, np->file, np->line,
12290Sstevel@tonic-gate 			    "assignment only allowed to globals (e.g. $a)");
12300Sstevel@tonic-gate 		break;
12310Sstevel@tonic-gate 	}
12320Sstevel@tonic-gate }
12330Sstevel@tonic-gate 
12340Sstevel@tonic-gate void
check_event(struct node * np)12350Sstevel@tonic-gate check_event(struct node *np)
12360Sstevel@tonic-gate {
12370Sstevel@tonic-gate 	ASSERT(np != NULL);
12381414Scindi 	ASSERTinfo(np->t == T_EVENT, ptree_nodetype2str(np->t));
12390Sstevel@tonic-gate 
12400Sstevel@tonic-gate 	if (np->u.event.epname == NULL) {
12410Sstevel@tonic-gate 		outfl(O_ERR|O_NONL, np->file, np->line,
12420Sstevel@tonic-gate 		    "pathless events not allowed: ");
12430Sstevel@tonic-gate 		ptree_name(O_ERR|O_NONL, np->u.event.ename);
12440Sstevel@tonic-gate 		out(O_ERR, NULL);
12450Sstevel@tonic-gate 	}
12460Sstevel@tonic-gate }
12470Sstevel@tonic-gate 
12480Sstevel@tonic-gate /*
12490Sstevel@tonic-gate  * check for properties that are required on declarations. This
12500Sstevel@tonic-gate  * should be done after all declarations since they can be
12510Sstevel@tonic-gate  * redeclared with a different set of properties.
12520Sstevel@tonic-gate  */
12530Sstevel@tonic-gate /*ARGSUSED*/
12540Sstevel@tonic-gate void
check_required_props(struct node * lhs,struct node * rhs,void * arg)12550Sstevel@tonic-gate check_required_props(struct node *lhs, struct node *rhs, void *arg)
12560Sstevel@tonic-gate {
12575633Scy152378 	ASSERTeq(rhs->t, (enum nodetype)arg, ptree_nodetype2str);
12580Sstevel@tonic-gate 
12590Sstevel@tonic-gate 	check_stmt_required_properties(rhs);
12600Sstevel@tonic-gate }
1261854Srw145199 
1262854Srw145199 /*
1263854Srw145199  * check that cascading prop statements do not contain lists internally.
1264854Srw145199  * the first and last event lists in the cascading prop may be single
1265854Srw145199  * events or lists of events.
1266854Srw145199  */
1267854Srw145199 /*ARGSUSED*/
1268854Srw145199 void
check_proplists(enum nodetype t,struct node * np)1269854Srw145199 check_proplists(enum nodetype t, struct node *np)
1270854Srw145199 {
1271854Srw145199 	ASSERT(np->t == T_ARROW);
1272854Srw145199 	/*
1273854Srw145199 	 * not checking the right hand side of the top level prop
1274854Srw145199 	 * since it is the last part of the propagation and can be
1275854Srw145199 	 * an event or list of events
1276854Srw145199 	 */
1277854Srw145199 	check_proplists_lhs(t, np->u.arrow.lhs);
1278854Srw145199 }
1279854Srw145199 
1280854Srw145199 /*ARGSUSED*/
1281854Srw145199 static void
check_proplists_lhs(enum nodetype t,struct node * lhs)1282854Srw145199 check_proplists_lhs(enum nodetype t, struct node *lhs)
1283854Srw145199 {
1284854Srw145199 	if (lhs->t == T_ARROW) {
1285854Srw145199 		if (lhs->u.arrow.rhs->t == T_LIST) {
1286854Srw145199 			outfl(O_ERR, lhs->file, lhs->line,
12875633Scy152378 			    "lists are not allowed internally on cascading %s",
12885633Scy152378 			    (t == T_PROP) ? "propagations" : "masks");
1289854Srw145199 		}
1290854Srw145199 		check_proplists_lhs(t, lhs->u.arrow.lhs);
1291854Srw145199 	}
1292854Srw145199 }
1293