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