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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 
23 /*
24  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
25  * Use is subject to license terms.
26  */
27 
28 #pragma ident	"%Z%%M%	%I%	%E% SMI"
29 
30 #include <stdio.h>
31 #include <string.h>
32 #include <fm/fmd_api.h>
33 #include <libnvpair.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 int Dupclose;		/* close cases on duplicate diagosis */
62 hrtime_t Hesitate;	/* hesitation time in ns */
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 /*ARGSUSED*/
79 static void
80 eft_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, const char *class)
81 {
82 	static char prefix[] = "ereport.";
83 
84 	if (strncmp(class, prefix, sizeof (prefix) - 1))
85 		out(O_DIE,
86 		    "eft_recv: event class \"%s\" does not begin with %s",
87 		    class, prefix);
88 
89 	fme_receive_external_report(hdl, ep, nvl, class);
90 }
91 
92 /*ARGSUSED*/
93 static void
94 eft_timeout(fmd_hdl_t *hdl, id_t tid, void *arg)
95 {
96 	out(O_ALTFP|O_STAMP,
97 	    "\neft.so timer %ld fired with arg %p", tid, arg);
98 
99 	if (arg == NULL)
100 		return;
101 
102 	fme_timer_fired(arg, tid);
103 }
104 
105 static void
106 eft_close(fmd_hdl_t *hdl, fmd_case_t *fmcase)
107 {
108 	out(O_ALTFP, "eft_close called for case %s",
109 	    fmd_case_uuid(hdl, fmcase));
110 	fme_close_case(hdl, fmcase);
111 }
112 
113 static const fmd_prop_t eft_props[] = {
114 	{ "autoclose", FMD_TYPE_STRING, NULL },
115 	{ "dupclose", FMD_TYPE_BOOL, "false" },
116 	{ "estats", FMD_TYPE_BOOL, "false" },
117 	{ "hesitate", FMD_TYPE_INT64, "10000000000" },
118 	{ "verbose", FMD_TYPE_INT32, "0" },
119 	{ "warn", FMD_TYPE_BOOL, "false" },
120 	{ "status", FMD_TYPE_STRING, NULL },
121 	{ "maxfme", FMD_TYPE_INT32, "0" },
122 	{ NULL, 0, NULL }
123 };
124 
125 static const fmd_hdl_ops_t eft_ops = {
126 	eft_recv,	/* fmdo_recv */
127 	eft_timeout,	/* fmdo_timeout */
128 	eft_close,	/* fmdo_close */
129 	NULL,		/* fmdo_stats */
130 	NULL,		/* fmdo_gc */
131 };
132 
133 #define	xstr(s) str(s)
134 #define	str(s) #s
135 
136 static const fmd_hdl_info_t fmd_info = {
137 	"eft diagnosis engine",
138 	xstr(VERSION_MAJOR) "." xstr(VERSION_MINOR),
139 	&eft_ops, eft_props
140 };
141 
142 /*
143  * ename_strdup -- like strdup but ename comes in and class string goes out
144  */
145 static char *
146 ename_strdup(struct node *np)
147 {
148 	struct node *mynp;
149 	int len;
150 	char *buf;
151 
152 	/* calculate length of buffer required */
153 	len = 0;
154 	for (mynp = np; mynp; mynp = mynp->u.name.next)
155 		len += strlen(mynp->u.name.s) + 1;	/* +1 for dot or NULL */
156 
157 	buf = MALLOC(len);
158 	buf[0] = '\0';
159 
160 	/* now build the string */
161 	while (np) {
162 		(void) strcat(buf, np->u.name.s);
163 		np = np->u.name.next;
164 		if (np)
165 			(void) strcat(buf, ".");
166 	}
167 
168 	return (buf);
169 }
170 
171 /*ARGSUSED*/
172 static void
173 dosubscribe(struct node *lhs, struct node *rhs, void *arg)
174 {
175 	char *ename = ename_strdup(lhs);
176 
177 	out(O_DEBUG, "subscribe: \"%s\"", ename);
178 	fmd_hdl_subscribe(Hdl, ename);
179 	FREE(ename);
180 }
181 
182 extern struct stats *Filecount;
183 
184 /*
185  * Call all of the _fini() routines to clean up the exiting DE
186  */
187 void
188 call_finis(void)
189 {
190 	platform_free_eft_files(Efts);
191 	Efts = NULL;
192 	platform_fini();
193 	fme_fini();
194 	itree_fini();
195 	ipath_fini();
196 	iexpr_fini();
197 	istat_fini();
198 	lex_free();
199 	check_fini();
200 	tree_fini();
201 	lut_fini();
202 	literals_fini();
203 	stable_fini();
204 	stats_fini();
205 	out_fini();
206 	alloc_fini();
207 }
208 
209 /*ARGSUSED*/
210 static void
211 doopendict(const char *lhs, void *rhs, void *arg)
212 {
213 	out(O_DEBUG, "opendict: \"%s\"", lhs);
214 	fmd_hdl_opendict(Hdl, lhs);
215 }
216 
217 void
218 _fmd_init(fmd_hdl_t *hdl)
219 {
220 	fmd_case_t *casep = NULL;
221 	int count;
222 	char *fname;
223 
224 	(void) fmd_hdl_register(hdl, FMD_API_VERSION, &fmd_info);
225 
226 	/* keep handle for routines like out() which need it */
227 	Hdl = hdl;
228 
229 	Estats = fmd_prop_get_int32(hdl, "estats");
230 
231 	alloc_init();
232 	out_init("eft");
233 	stats_init(Estats);
234 	stable_init(0);
235 	literals_init();
236 	platform_init();
237 	lut_init();
238 	tree_init();
239 	ipath_init();
240 	iexpr_init();
241 	Efts = platform_get_eft_files();
242 	lex_init(Efts, NULL, 0);
243 	check_init();
244 
245 	/*
246 	 *  If we read no .eft files, we can't do any
247 	 *  diagnosing, so we just unload ourselves
248 	 */
249 	if (stats_counter_value(Filecount) == 0) {
250 		(void) lex_fini();
251 		call_finis();
252 		fmd_hdl_debug(hdl, "no fault trees provided.");
253 		fmd_hdl_unregister(hdl);
254 		return;
255 	}
256 
257 	yyparse();
258 	(void) lex_fini();
259 	tree_report();
260 	if (count = out_errcount())
261 		out(O_DIE, "%d language error%s encountered, exiting.",
262 		    OUTS(count));
263 
264 	/* subscribe to events we expect to consume */
265 	lut_walk(Ereportenames, (lut_cb)dosubscribe, NULL);
266 
267 	/* open dictionaries referenced by all .eft files */
268 	lut_walk(Dicts, (lut_cb)doopendict, (void *)0);
269 
270 	Verbose = fmd_prop_get_int32(hdl, "verbose");
271 	Warn = fmd_prop_get_int32(hdl, "warn");
272 	Autoclose = fmd_prop_get_string(hdl, "autoclose");
273 	Dupclose = fmd_prop_get_int32(hdl, "dupclose");
274 	Hesitate = fmd_prop_get_int64(hdl, "hesitate");
275 	Max_fme = fmd_prop_get_int32(hdl, "maxfme");
276 
277 	if ((fname = fmd_prop_get_string(hdl, "status")) != NULL) {
278 		FILE *fp;
279 
280 		if ((fp = fopen(fname, "a")) == NULL) {
281 			fmd_prop_free_string(hdl, fname);
282 			out(O_DIE|O_SYS, "status property file: %s", fname);
283 		}
284 
285 		(void) setlinebuf(fp);
286 		out_altfp(fp);
287 
288 		out(O_DEBUG, "appending status changes to \"%s\"", fname);
289 		fmd_prop_free_string(hdl, fname);
290 
291 		out(O_ALTFP|O_STAMP, "\neft.so startup");
292 	}
293 
294 	out(O_DEBUG, "initialized, verbose %d warn %d autoclose %s "
295 	    "dupclose %d maxfme %d",
296 	    Verbose, Warn, Autoclose == NULL ? "(NULL)" : Autoclose,
297 	    Dupclose, Max_fme);
298 
299 	out(O_DEBUG, "reconstituting any existing fmes");
300 	while ((casep = fmd_case_next(hdl, casep)) != NULL) {
301 		fme_restart(hdl, casep);
302 	}
303 	fme_istat_load(hdl);
304 }
305 
306 /*ARGSUSED*/
307 void
308 _fmd_fini(fmd_hdl_t *hdl)
309 {
310 	fmd_prop_free_string(hdl, Autoclose);
311 	Autoclose = NULL;
312 	call_finis();
313 }
314