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 * Copyright 2005 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 "out.h" 34 #include "stats.h" 35 #include "alloc.h" 36 #include "stable.h" 37 #include "literals.h" 38 #include "lut.h" 39 #include "esclex.h" 40 #include "tree.h" 41 #include "ipath.h" 42 #include "itree.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 char *Autoclose; /* close cases automatically after solving */ 59 int Autoconvict; /* true if autoconvict set in conf file */ 60 hrtime_t Hesitate; /* hesitation time in ns */ 61 int Verbose; 62 int Estats; 63 int Warn; /* zero -- eft.so should not issue language warnings */ 64 char **Efts; 65 int Max_fme; /* Maximum number of open FMEs */ 66 67 /* stuff exported by yacc-generated parsers */ 68 extern void yyparse(void); 69 extern int yydebug; 70 71 extern struct lut *Dicts; 72 73 extern void literals_init(void); 74 extern void literals_fini(void); 75 76 /*ARGSUSED*/ 77 static void 78 eft_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, const char *class) 79 { 80 static char prefix[] = "ereport."; 81 82 if (strncmp(class, prefix, sizeof (prefix) - 1)) 83 out(O_DIE, 84 "eft_recv: event class \"%s\" does not begin with %s", 85 class, prefix); 86 87 fme_receive_external_report(hdl, ep, nvl, class); 88 } 89 90 /*ARGSUSED*/ 91 static void 92 eft_timeout(fmd_hdl_t *hdl, id_t tid, void *arg) 93 { 94 out(O_ALTFP|O_STAMP, 95 "\neft.so timer %ld fired with arg %p", tid, arg); 96 97 if (arg == NULL) 98 return; 99 100 fme_timer_fired(arg, tid); 101 } 102 103 /*ARGSUSED*/ 104 static void 105 eft_close(fmd_hdl_t *hdl, fmd_case_t *fmcase) 106 { 107 out(O_ALTFP, "eft_close called for case %s", 108 fmd_case_uuid(hdl, fmcase)); 109 fme_close_case(hdl, fmcase); 110 } 111 112 static const fmd_prop_t eft_props[] = { 113 { "autoconvict", FMD_TYPE_BOOL, NULL }, 114 { "autoclose", FMD_TYPE_STRING, NULL }, 115 { "estats", FMD_TYPE_BOOL, "false" }, 116 { "hesitate", FMD_TYPE_INT64, "10000000000" }, 117 { "verbose", FMD_TYPE_INT32, "0" }, 118 { "warn", FMD_TYPE_BOOL, "false" }, 119 { "status", FMD_TYPE_STRING, NULL }, 120 { "maxfme", FMD_TYPE_INT32, "0" }, 121 { NULL, 0, NULL } 122 }; 123 124 static const fmd_hdl_ops_t eft_ops = { 125 eft_recv, /* fmdo_recv */ 126 eft_timeout, /* fmdo_timeout */ 127 eft_close, /* fmdo_close */ 128 NULL, /* fmdo_stats */ 129 NULL, /* fmdo_gc */ 130 }; 131 132 #define xstr(s) str(s) 133 #define str(s) #s 134 135 static const fmd_hdl_info_t fmd_info = { 136 "eft diagnosis engine", 137 xstr(VERSION_MAJOR) "." xstr(VERSION_MINOR), 138 &eft_ops, eft_props 139 }; 140 141 /* 142 * ename_strdup -- like strdup but ename comes in and class string goes out 143 */ 144 static char * 145 ename_strdup(struct node *np) 146 { 147 struct node *mynp; 148 int len; 149 char *buf; 150 151 /* calculate length of buffer required */ 152 len = 0; 153 for (mynp = np; mynp; mynp = mynp->u.name.next) 154 len += strlen(mynp->u.name.s) + 1; /* +1 for dot or NULL */ 155 156 buf = MALLOC(len); 157 buf[0] = '\0'; 158 159 /* now build the string */ 160 while (np) { 161 (void) strcat(buf, np->u.name.s); 162 np = np->u.name.next; 163 if (np) 164 (void) strcat(buf, "."); 165 } 166 167 return (buf); 168 } 169 170 /*ARGSUSED*/ 171 static void 172 dosubscribe(struct node *lhs, struct node *rhs, void *arg) 173 { 174 char *ename = ename_strdup(lhs); 175 176 out(O_DEBUG, "subscribe: \"%s\"", ename); 177 fmd_hdl_subscribe(Hdl, ename); 178 FREE(ename); 179 } 180 181 extern struct stats *Filecount; 182 183 /* 184 * Call all of the _fini() routines to clean up the exiting DE 185 */ 186 void 187 call_finis(void) 188 { 189 platform_free_eft_files(Efts); 190 Efts = NULL; 191 platform_fini(); 192 fme_fini(); 193 itree_fini(); 194 ipath_fini(); 195 lex_free(); 196 check_fini(); 197 tree_fini(); 198 lut_fini(); 199 literals_fini(); 200 stable_fini(); 201 stats_fini(); 202 out_fini(); 203 alloc_fini(); 204 } 205 206 /*ARGSUSED*/ 207 static void 208 doopendict(const char *lhs, void *rhs, void *arg) 209 { 210 out(O_DEBUG, "opendict: \"%s\"", lhs); 211 fmd_hdl_opendict(Hdl, lhs); 212 } 213 214 void 215 _fmd_init(fmd_hdl_t *hdl) 216 { 217 fmd_case_t *casep = NULL; 218 int count; 219 char *fname; 220 221 (void) fmd_hdl_register(hdl, FMD_API_VERSION, &fmd_info); 222 223 /* keep handle for routines like out() which need it */ 224 Hdl = hdl; 225 226 Estats = fmd_prop_get_int32(hdl, "estats"); 227 228 alloc_init(); 229 out_init("eft"); 230 stats_init(Estats); 231 stable_init(0); 232 literals_init(); 233 platform_init(); 234 lut_init(); 235 tree_init(); 236 ipath_init(); 237 Efts = platform_get_eft_files(); 238 lex_init(Efts, NULL, 0); 239 check_init(); 240 241 /* 242 * If we read no .eft files, we can't do any 243 * diagnosing, so we just unload ourselves 244 */ 245 if (stats_counter_value(Filecount) == 0) { 246 (void) lex_fini(); 247 call_finis(); 248 fmd_hdl_debug(hdl, "no fault trees provided."); 249 fmd_hdl_unregister(hdl); 250 return; 251 } 252 253 yyparse(); 254 (void) lex_fini(); 255 tree_report(); 256 if (count = out_errcount()) 257 out(O_DIE, "%d language error%s encountered, exiting.", 258 OUTS(count)); 259 260 /* subscribe to events we expect to consume */ 261 lut_walk(Ereportenames, (lut_cb)dosubscribe, NULL); 262 263 /* open dictionaries referenced by all .eft files */ 264 lut_walk(Dicts, (lut_cb)doopendict, (void *)0); 265 266 Verbose = fmd_prop_get_int32(hdl, "verbose"); 267 Warn = fmd_prop_get_int32(hdl, "warn"); 268 Autoclose = fmd_prop_get_string(hdl, "autoclose"); 269 Hesitate = fmd_prop_get_int64(hdl, "hesitate"); 270 Autoconvict = fmd_prop_get_int32(hdl, "autoconvict"); 271 Max_fme = fmd_prop_get_int32(hdl, "maxfme"); 272 273 if ((fname = fmd_prop_get_string(hdl, "status")) != NULL) { 274 FILE *fp; 275 276 if ((fp = fopen(fname, "a")) == NULL) { 277 fmd_prop_free_string(hdl, fname); 278 out(O_DIE|O_SYS, "status property file: %s", fname); 279 } 280 281 (void) setlinebuf(fp); 282 out_altfp(fp); 283 284 out(O_DEBUG, "appending status changes to \"%s\"", fname); 285 fmd_prop_free_string(hdl, fname); 286 287 out(O_ALTFP|O_STAMP, "\neft.so startup"); 288 } 289 290 out(O_DEBUG, 291 "initialized, verbose %d warn %d autoclose %s autoconvict %d " 292 "maxfme %d", Verbose, Warn, 293 Autoclose == NULL ? "(NULL)" : Autoclose, Autoconvict, Max_fme); 294 295 out(O_DEBUG, "reconstituting any existing fmes"); 296 while ((casep = fmd_case_next(hdl, casep)) != NULL) { 297 fme_restart(hdl, casep); 298 } 299 } 300 301 /*ARGSUSED*/ 302 void 303 _fmd_fini(fmd_hdl_t *hdl) 304 { 305 fmd_prop_free_string(hdl, Autoclose); 306 Autoclose = NULL; 307 call_finis(); 308 } 309