Home | History | Annotate | Download | only in eversholt
      1     0  stevel /*
      2     0  stevel  * CDDL HEADER START
      3     0  stevel  *
      4     0  stevel  * The contents of this file are subject to the terms of the
      5  2120  gavinm  * Common Development and Distribution License (the "License").
      6  2120  gavinm  * You may not use this file except in compliance with the License.
      7     0  stevel  *
      8     0  stevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9     0  stevel  * or http://www.opensolaris.org/os/licensing.
     10     0  stevel  * See the License for the specific language governing permissions
     11     0  stevel  * and limitations under the License.
     12     0  stevel  *
     13     0  stevel  * When distributing Covered Code, include this CDDL HEADER in each
     14     0  stevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15     0  stevel  * If applicable, add the following below this CDDL HEADER, with the
     16     0  stevel  * fields enclosed by brackets "[]" replaced with your own identifying
     17     0  stevel  * information: Portions Copyright [yyyy] [name of copyright owner]
     18     0  stevel  *
     19     0  stevel  * CDDL HEADER END
     20     0  stevel  */
     21  1193     mws 
     22     0  stevel /*
     23  6228  stephh  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     24     0  stevel  * Use is subject to license terms.
     25     0  stevel  */
     26     0  stevel 
     27     0  stevel #include <stdio.h>
     28     0  stevel #include <string.h>
     29     0  stevel #include <fm/fmd_api.h>
     30     0  stevel #include <libnvpair.h>
     31  5204  stephh #include <fm/libtopo.h>
     32     0  stevel #include "out.h"
     33     0  stevel #include "stats.h"
     34     0  stevel #include "alloc.h"
     35     0  stevel #include "stable.h"
     36     0  stevel #include "literals.h"
     37     0  stevel #include "lut.h"
     38     0  stevel #include "esclex.h"
     39     0  stevel #include "tree.h"
     40     0  stevel #include "ipath.h"
     41     0  stevel #include "itree.h"
     42  1414   cindi #include "iexpr.h"
     43     0  stevel #include "ptree.h"
     44     0  stevel #include "check.h"
     45     0  stevel #include "version.h"
     46     0  stevel #include "fme.h"
     47     0  stevel #include "eval.h"
     48     0  stevel #include "config.h"
     49     0  stevel #include "platform.h"
     50     0  stevel 
     51     0  stevel /*
     52     0  stevel  * eversholt diagnosis engine (eft.so) main entry points
     53     0  stevel  */
     54     0  stevel 
     55     0  stevel fmd_hdl_t *Hdl;		/* handle in global for platform.c */
     56     0  stevel 
     57     0  stevel int Debug = 1;	/* turn on here and let fmd_hdl_debug() decide if really on */
     58     0  stevel hrtime_t Hesitate;	/* hesitation time in ns */
     59  5204  stephh char *Serd_Override;	/* override for Serd engines */
     60     0  stevel int Verbose;
     61     0  stevel int Estats;
     62     0  stevel int Warn;	/* zero -- eft.so should not issue language warnings */
     63     0  stevel char **Efts;
     64   814   jrutt int Max_fme;		/* Maximum number of open FMEs */
     65     0  stevel 
     66     0  stevel /* stuff exported by yacc-generated parsers */
     67     0  stevel extern void yyparse(void);
     68     0  stevel extern int yydebug;
     69     0  stevel 
     70     0  stevel extern struct lut *Dicts;
     71     0  stevel 
     72     0  stevel extern void literals_init(void);
     73     0  stevel extern void literals_fini(void);
     74     0  stevel 
     75  2120  gavinm struct eftsubr {
     76  2120  gavinm 	const char *prefix;
     77  2120  gavinm 	void (*hdlr)(fmd_hdl_t *, fmd_event_t *, nvlist_t *, const char *);
     78  2120  gavinm } eftsubrs[] = {
     79  2120  gavinm 	{ "ereport.",		fme_receive_external_report },
     80  2120  gavinm 	{ "list.repaired",	fme_receive_repair_list },
     81  2120  gavinm 	{ NULL,			NULL }
     82  2120  gavinm };
     83  2120  gavinm 
     84     0  stevel /*ARGSUSED*/
     85     0  stevel static void
     86     0  stevel eft_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, const char *class)
     87     0  stevel {
     88  2120  gavinm 	struct eftsubr *sp = eftsubrs;
     89     0  stevel 
     90  2120  gavinm 	while (sp->prefix != NULL) {
     91  2120  gavinm 		if (strncmp(class, sp->prefix, strlen(sp->prefix)) == 0)
     92  2120  gavinm 			break;
     93  2120  gavinm 		sp++;
     94  2120  gavinm 	}
     95  2120  gavinm 
     96  2120  gavinm 	if (sp->prefix != NULL) {
     97  2120  gavinm 		(sp->hdlr)(hdl, ep, nvl, class);
     98  2120  gavinm 	} else {
     99     0  stevel 		out(O_DIE,
    100  2120  gavinm 		    "eft_recv: event class \"%s\" does not match our "
    101  2120  gavinm 		    "subscriptions", class);
    102  2120  gavinm 	}
    103     0  stevel }
    104     0  stevel 
    105     0  stevel /*ARGSUSED*/
    106     0  stevel static void
    107     0  stevel eft_timeout(fmd_hdl_t *hdl, id_t tid, void *arg)
    108     0  stevel {
    109     0  stevel 	out(O_ALTFP|O_STAMP,
    110     0  stevel 	    "\neft.so timer %ld fired with arg %p", tid, arg);
    111     0  stevel 
    112     0  stevel 	if (arg == NULL)
    113     0  stevel 		return;
    114     0  stevel 
    115     0  stevel 	fme_timer_fired(arg, tid);
    116     0  stevel }
    117     0  stevel 
    118     0  stevel static void
    119     0  stevel eft_close(fmd_hdl_t *hdl, fmd_case_t *fmcase)
    120     0  stevel {
    121     0  stevel 	out(O_ALTFP, "eft_close called for case %s",
    122     0  stevel 	    fmd_case_uuid(hdl, fmcase));
    123     0  stevel 	fme_close_case(hdl, fmcase);
    124     0  stevel }
    125     0  stevel 
    126  5204  stephh /*
    127  5204  stephh  * The "serd_override" property allows the N and T parameters of specified serd
    128  5204  stephh  * engines to be overridden. The property is a string consisting of one or more
    129  5204  stephh  * space separated triplets. Each triplet is of the form "name,N,T" where "name"
    130  5204  stephh  * is the name of the serd engine and N and T are the new paremeters to use.
    131  5204  stephh  * For example "serd.io.device.nonfatal,5,3h" would set the parameters for the
    132  5204  stephh  * serd.io.device.nonfatal engine to 5 in 3 hours.
    133  5204  stephh  */
    134     0  stevel static const fmd_prop_t eft_props[] = {
    135     0  stevel 	{ "estats", FMD_TYPE_BOOL, "false" },
    136     0  stevel 	{ "hesitate", FMD_TYPE_INT64, "10000000000" },
    137  5204  stephh 	{ "serd_override", FMD_TYPE_STRING, NULL },
    138     0  stevel 	{ "verbose", FMD_TYPE_INT32, "0" },
    139     0  stevel 	{ "warn", FMD_TYPE_BOOL, "false" },
    140     0  stevel 	{ "status", FMD_TYPE_STRING, NULL },
    141   814   jrutt 	{ "maxfme", FMD_TYPE_INT32, "0" },
    142     0  stevel 	{ NULL, 0, NULL }
    143     0  stevel };
    144     0  stevel 
    145  5204  stephh /*ARGSUSED*/
    146  5204  stephh static void
    147  5204  stephh eft_topo_change(fmd_hdl_t *hdl, topo_hdl_t *thp)
    148  5204  stephh {
    149  5204  stephh 	fme_receive_topology_change();
    150  5204  stephh }
    151  5204  stephh 
    152     0  stevel static const fmd_hdl_ops_t eft_ops = {
    153     0  stevel 	eft_recv,	/* fmdo_recv */
    154     0  stevel 	eft_timeout,	/* fmdo_timeout */
    155     0  stevel 	eft_close,	/* fmdo_close */
    156     0  stevel 	NULL,		/* fmdo_stats */
    157     0  stevel 	NULL,		/* fmdo_gc */
    158  5204  stephh 	NULL,		/* fmdo_send */
    159  5204  stephh 	eft_topo_change	/* fmdo_topo_change */
    160     0  stevel };
    161     0  stevel 
    162     0  stevel #define	xstr(s) str(s)
    163     0  stevel #define	str(s) #s
    164     0  stevel 
    165     0  stevel static const fmd_hdl_info_t fmd_info = {
    166     0  stevel 	"eft diagnosis engine",
    167     0  stevel 	xstr(VERSION_MAJOR) "." xstr(VERSION_MINOR),
    168     0  stevel 	&eft_ops, eft_props
    169     0  stevel };
    170     0  stevel 
    171     0  stevel /*
    172     0  stevel  * ename_strdup -- like strdup but ename comes in and class string goes out
    173     0  stevel  */
    174     0  stevel static char *
    175     0  stevel ename_strdup(struct node *np)
    176     0  stevel {
    177     0  stevel 	struct node *mynp;
    178     0  stevel 	int len;
    179     0  stevel 	char *buf;
    180     0  stevel 
    181     0  stevel 	/* calculate length of buffer required */
    182     0  stevel 	len = 0;
    183     0  stevel 	for (mynp = np; mynp; mynp = mynp->u.name.next)
    184     0  stevel 		len += strlen(mynp->u.name.s) + 1;	/* +1 for dot or NULL */
    185     0  stevel 
    186     0  stevel 	buf = MALLOC(len);
    187     0  stevel 	buf[0] = '\0';
    188     0  stevel 
    189     0  stevel 	/* now build the string */
    190     0  stevel 	while (np) {
    191     0  stevel 		(void) strcat(buf, np->u.name.s);
    192     0  stevel 		np = np->u.name.next;
    193     0  stevel 		if (np)
    194     0  stevel 			(void) strcat(buf, ".");
    195     0  stevel 	}
    196     0  stevel 
    197     0  stevel 	return (buf);
    198     0  stevel }
    199     0  stevel 
    200     0  stevel /*ARGSUSED*/
    201     0  stevel static void
    202     0  stevel dosubscribe(struct node *lhs, struct node *rhs, void *arg)
    203     0  stevel {
    204     0  stevel 	char *ename = ename_strdup(lhs);
    205     0  stevel 
    206     0  stevel 	fmd_hdl_subscribe(Hdl, ename);
    207     0  stevel 	FREE(ename);
    208     0  stevel }
    209     0  stevel 
    210  6640     cth /*ARGSUSED*/
    211  6640     cth static void
    212  6640     cth dodiscardprint(struct node *lhs, struct node *rhs, void *arg)
    213  6640     cth {
    214  6640     cth 	char *ename = (char *)lhs;
    215  6640     cth 
    216  6640     cth 	out(O_DEBUG, "allow silent discard_if_config_unknown: \"%s\"", ename);
    217  6640     cth }
    218  6640     cth 
    219     0  stevel extern struct stats *Filecount;
    220     0  stevel 
    221     0  stevel /*
    222     0  stevel  * Call all of the _fini() routines to clean up the exiting DE
    223     0  stevel  */
    224     0  stevel void
    225     0  stevel call_finis(void)
    226     0  stevel {
    227     0  stevel 	platform_free_eft_files(Efts);
    228     0  stevel 	Efts = NULL;
    229     0  stevel 	platform_fini();
    230     0  stevel 	fme_fini();
    231     0  stevel 	itree_fini();
    232     0  stevel 	ipath_fini();
    233  1414   cindi 	iexpr_fini();
    234  1414   cindi 	istat_fini();
    235  4436  stephh 	serd_fini();
    236     0  stevel 	lex_free();
    237     0  stevel 	check_fini();
    238     0  stevel 	tree_fini();
    239     0  stevel 	lut_fini();
    240     0  stevel 	literals_fini();
    241     0  stevel 	stable_fini();
    242     0  stevel 	stats_fini();
    243     0  stevel 	out_fini();
    244     0  stevel 	alloc_fini();
    245     0  stevel }
    246     0  stevel 
    247     0  stevel /*ARGSUSED*/
    248     0  stevel static void
    249     0  stevel doopendict(const char *lhs, void *rhs, void *arg)
    250     0  stevel {
    251     0  stevel 	out(O_DEBUG, "opendict: \"%s\"", lhs);
    252     0  stevel 	fmd_hdl_opendict(Hdl, lhs);
    253     0  stevel }
    254     0  stevel 
    255     0  stevel void
    256     0  stevel _fmd_init(fmd_hdl_t *hdl)
    257     0  stevel {
    258     0  stevel 	fmd_case_t *casep = NULL;
    259     0  stevel 	int count;
    260     0  stevel 	char *fname;
    261     0  stevel 
    262     0  stevel 	(void) fmd_hdl_register(hdl, FMD_API_VERSION, &fmd_info);
    263     0  stevel 
    264     0  stevel 	/* keep handle for routines like out() which need it */
    265     0  stevel 	Hdl = hdl;
    266     0  stevel 
    267  6640     cth 	/* set up out(O_ALTFP) first things so it is available for debug */
    268     0  stevel 	alloc_init();
    269     0  stevel 	out_init("eft");
    270  6640     cth 	if ((fname = fmd_prop_get_string(hdl, "status")) != NULL) {
    271  6640     cth 		FILE *fp;
    272  6640     cth 
    273  6640     cth 		if ((fp = fopen(fname, "a")) == NULL) {
    274  6640     cth 			fmd_prop_free_string(hdl, fname);
    275  6640     cth 			out(O_DIE|O_SYS, "status property file: %s", fname);
    276  6640     cth 		}
    277  6640     cth 
    278  6640     cth 		(void) setlinebuf(fp);
    279  6640     cth 		out_altfp(fp);
    280  6640     cth 
    281  6640     cth 		out(O_DEBUG, "appending status changes to \"%s\"", fname);
    282  6640     cth 		fmd_prop_free_string(hdl, fname);
    283  6640     cth 
    284  6640     cth 		out(O_ALTFP|O_STAMP, "\neft.so startup");
    285  6640     cth 	}
    286  6640     cth 
    287  6640     cth 
    288  6640     cth 	Estats = fmd_prop_get_int32(hdl, "estats");
    289     0  stevel 	stats_init(Estats);
    290  6640     cth 
    291     0  stevel 	stable_init(0);
    292     0  stevel 	literals_init();
    293     0  stevel 	platform_init();
    294     0  stevel 	lut_init();
    295     0  stevel 	tree_init();
    296     0  stevel 	ipath_init();
    297  1414   cindi 	iexpr_init();
    298     0  stevel 	Efts = platform_get_eft_files();
    299     0  stevel 	lex_init(Efts, NULL, 0);
    300     0  stevel 	check_init();
    301     0  stevel 
    302     0  stevel 	/*
    303     0  stevel 	 *  If we read no .eft files, we can't do any
    304     0  stevel 	 *  diagnosing, so we just unload ourselves
    305     0  stevel 	 */
    306     0  stevel 	if (stats_counter_value(Filecount) == 0) {
    307     0  stevel 		(void) lex_fini();
    308     0  stevel 		call_finis();
    309     0  stevel 		fmd_hdl_debug(hdl, "no fault trees provided.");
    310     0  stevel 		fmd_hdl_unregister(hdl);
    311     0  stevel 		return;
    312     0  stevel 	}
    313     0  stevel 
    314     0  stevel 	yyparse();
    315     0  stevel 	(void) lex_fini();
    316     0  stevel 	tree_report();
    317     0  stevel 	if (count = out_errcount())
    318     0  stevel 		out(O_DIE, "%d language error%s encountered, exiting.",
    319     0  stevel 		    OUTS(count));
    320     0  stevel 
    321     0  stevel 	/* subscribe to events we expect to consume */
    322     0  stevel 	lut_walk(Ereportenames, (lut_cb)dosubscribe, NULL);
    323  6640     cth 	lut_walk(Ereportenames_discard, (lut_cb)dodiscardprint, NULL);
    324     0  stevel 
    325  2120  gavinm 	/* subscribe to repair events so we can clear state on repair */
    326  2120  gavinm 	fmd_hdl_subscribe(hdl, "list.repaired");
    327  2120  gavinm 
    328     0  stevel 	/* open dictionaries referenced by all .eft files */
    329     0  stevel 	lut_walk(Dicts, (lut_cb)doopendict, (void *)0);
    330     0  stevel 
    331     0  stevel 	Verbose = fmd_prop_get_int32(hdl, "verbose");
    332     0  stevel 	Warn = fmd_prop_get_int32(hdl, "warn");
    333     0  stevel 	Hesitate = fmd_prop_get_int64(hdl, "hesitate");
    334  5204  stephh 	Serd_Override = fmd_prop_get_string(hdl, "serd_override");
    335   814   jrutt 	Max_fme = fmd_prop_get_int32(hdl, "maxfme");
    336     0  stevel 
    337  7197  stephh 	out(O_DEBUG, "initialized, verbose %d warn %d maxfme %d",
    338  7197  stephh 	    Verbose, Warn, Max_fme);
    339     0  stevel 
    340  4436  stephh 	fme_istat_load(hdl);
    341  4436  stephh 	fme_serd_load(hdl);
    342  4436  stephh 
    343     0  stevel 	out(O_DEBUG, "reconstituting any existing fmes");
    344     0  stevel 	while ((casep = fmd_case_next(hdl, casep)) != NULL) {
    345     0  stevel 		fme_restart(hdl, casep);
    346     0  stevel 	}
    347     0  stevel }
    348     0  stevel 
    349     0  stevel /*ARGSUSED*/
    350     0  stevel void
    351     0  stevel _fmd_fini(fmd_hdl_t *hdl)
    352     0  stevel {
    353     0  stevel 	call_finis();
    354     0  stevel }
    355