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 /*ARGSUSED*/ 216 static void 217 dodiscardprint(struct node *lhs, struct node *rhs, void *arg) 218 { 219 char *ename = (char *)lhs; 220 221 out(O_DEBUG, "allow silent discard_if_config_unknown: \"%s\"", ename); 222 } 223 224 extern struct stats *Filecount; 225 226 /* 227 * Call all of the _fini() routines to clean up the exiting DE 228 */ 229 void 230 call_finis(void) 231 { 232 platform_free_eft_files(Efts); 233 Efts = NULL; 234 platform_fini(); 235 fme_fini(); 236 itree_fini(); 237 ipath_fini(); 238 iexpr_fini(); 239 istat_fini(); 240 serd_fini(); 241 lex_free(); 242 check_fini(); 243 tree_fini(); 244 lut_fini(); 245 literals_fini(); 246 stable_fini(); 247 stats_fini(); 248 out_fini(); 249 alloc_fini(); 250 } 251 252 /*ARGSUSED*/ 253 static void 254 doopendict(const char *lhs, void *rhs, void *arg) 255 { 256 out(O_DEBUG, "opendict: \"%s\"", lhs); 257 fmd_hdl_opendict(Hdl, lhs); 258 } 259 260 void 261 _fmd_init(fmd_hdl_t *hdl) 262 { 263 fmd_case_t *casep = NULL; 264 int count; 265 char *fname; 266 267 (void) fmd_hdl_register(hdl, FMD_API_VERSION, &fmd_info); 268 269 /* keep handle for routines like out() which need it */ 270 Hdl = hdl; 271 272 /* set up out(O_ALTFP) first things so it is available for debug */ 273 alloc_init(); 274 out_init("eft"); 275 if ((fname = fmd_prop_get_string(hdl, "status")) != NULL) { 276 FILE *fp; 277 278 if ((fp = fopen(fname, "a")) == NULL) { 279 fmd_prop_free_string(hdl, fname); 280 out(O_DIE|O_SYS, "status property file: %s", fname); 281 } 282 283 (void) setlinebuf(fp); 284 out_altfp(fp); 285 286 out(O_DEBUG, "appending status changes to \"%s\"", fname); 287 fmd_prop_free_string(hdl, fname); 288 289 out(O_ALTFP|O_STAMP, "\neft.so startup"); 290 } 291 292 293 Estats = fmd_prop_get_int32(hdl, "estats"); 294 stats_init(Estats); 295 296 stable_init(0); 297 literals_init(); 298 platform_init(); 299 lut_init(); 300 tree_init(); 301 ipath_init(); 302 iexpr_init(); 303 Efts = platform_get_eft_files(); 304 lex_init(Efts, NULL, 0); 305 check_init(); 306 307 /* 308 * If we read no .eft files, we can't do any 309 * diagnosing, so we just unload ourselves 310 */ 311 if (stats_counter_value(Filecount) == 0) { 312 (void) lex_fini(); 313 call_finis(); 314 fmd_hdl_debug(hdl, "no fault trees provided."); 315 fmd_hdl_unregister(hdl); 316 return; 317 } 318 319 yyparse(); 320 (void) lex_fini(); 321 tree_report(); 322 if (count = out_errcount()) 323 out(O_DIE, "%d language error%s encountered, exiting.", 324 OUTS(count)); 325 326 /* subscribe to events we expect to consume */ 327 lut_walk(Ereportenames, (lut_cb)dosubscribe, NULL); 328 lut_walk(Ereportenames_discard, (lut_cb)dodiscardprint, NULL); 329 330 /* subscribe to repair events so we can clear state on repair */ 331 fmd_hdl_subscribe(hdl, "list.repaired"); 332 333 /* open dictionaries referenced by all .eft files */ 334 lut_walk(Dicts, (lut_cb)doopendict, (void *)0); 335 336 Verbose = fmd_prop_get_int32(hdl, "verbose"); 337 Warn = fmd_prop_get_int32(hdl, "warn"); 338 Autoclose = fmd_prop_get_string(hdl, "autoclose"); 339 Hesitate = fmd_prop_get_int64(hdl, "hesitate"); 340 Serd_Override = fmd_prop_get_string(hdl, "serd_override"); 341 Max_fme = fmd_prop_get_int32(hdl, "maxfme"); 342 343 out(O_DEBUG, "initialized, verbose %d warn %d autoclose %s " 344 "maxfme %d", Verbose, Warn, Autoclose == NULL ? "(NULL)" : 345 Autoclose, Max_fme); 346 347 fme_istat_load(hdl); 348 fme_serd_load(hdl); 349 350 out(O_DEBUG, "reconstituting any existing fmes"); 351 while ((casep = fmd_case_next(hdl, casep)) != NULL) { 352 fme_restart(hdl, casep); 353 } 354 } 355 356 /*ARGSUSED*/ 357 void 358 _fmd_fini(fmd_hdl_t *hdl) 359 { 360 fmd_prop_free_string(hdl, Autoclose); 361 Autoclose = NULL; 362 call_finis(); 363 } 364