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