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