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