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