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