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