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