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 "out.h" 34 #include "stats.h" 35 #include "alloc.h" 36 #include "stable.h" 37 #include "literals.h" 38 #include "lut.h" 39 #include "esclex.h" 40 #include "tree.h" 41 #include "ipath.h" 42 #include "itree.h" 43 #include "iexpr.h" 44 #include "ptree.h" 45 #include "check.h" 46 #include "version.h" 47 #include "fme.h" 48 #include "eval.h" 49 #include "config.h" 50 #include "platform.h" 51 52 /* 53 * eversholt diagnosis engine (eft.so) main entry points 54 */ 55 56 fmd_hdl_t *Hdl; /* handle in global for platform.c */ 57 58 int Debug = 1; /* turn on here and let fmd_hdl_debug() decide if really on */ 59 char *Autoclose; /* close cases automatically after solving */ 60 int Dupclose; /* close cases on duplicate diagosis */ 61 hrtime_t Hesitate; /* hesitation time in ns */ 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 static const fmd_prop_t eft_props[] = { 129 { "autoclose", FMD_TYPE_STRING, NULL }, 130 { "dupclose", FMD_TYPE_BOOL, "false" }, 131 { "estats", FMD_TYPE_BOOL, "false" }, 132 { "hesitate", FMD_TYPE_INT64, "10000000000" }, 133 { "verbose", FMD_TYPE_INT32, "0" }, 134 { "warn", FMD_TYPE_BOOL, "false" }, 135 { "status", FMD_TYPE_STRING, NULL }, 136 { "maxfme", FMD_TYPE_INT32, "0" }, 137 { NULL, 0, NULL } 138 }; 139 140 static const fmd_hdl_ops_t eft_ops = { 141 eft_recv, /* fmdo_recv */ 142 eft_timeout, /* fmdo_timeout */ 143 eft_close, /* fmdo_close */ 144 NULL, /* fmdo_stats */ 145 NULL, /* fmdo_gc */ 146 }; 147 148 #define xstr(s) str(s) 149 #define str(s) #s 150 151 static const fmd_hdl_info_t fmd_info = { 152 "eft diagnosis engine", 153 xstr(VERSION_MAJOR) "." xstr(VERSION_MINOR), 154 &eft_ops, eft_props 155 }; 156 157 /* 158 * ename_strdup -- like strdup but ename comes in and class string goes out 159 */ 160 static char * 161 ename_strdup(struct node *np) 162 { 163 struct node *mynp; 164 int len; 165 char *buf; 166 167 /* calculate length of buffer required */ 168 len = 0; 169 for (mynp = np; mynp; mynp = mynp->u.name.next) 170 len += strlen(mynp->u.name.s) + 1; /* +1 for dot or NULL */ 171 172 buf = MALLOC(len); 173 buf[0] = '\0'; 174 175 /* now build the string */ 176 while (np) { 177 (void) strcat(buf, np->u.name.s); 178 np = np->u.name.next; 179 if (np) 180 (void) strcat(buf, "."); 181 } 182 183 return (buf); 184 } 185 186 /*ARGSUSED*/ 187 static void 188 dosubscribe(struct node *lhs, struct node *rhs, void *arg) 189 { 190 char *ename = ename_strdup(lhs); 191 192 out(O_DEBUG, "subscribe: \"%s\"", ename); 193 fmd_hdl_subscribe(Hdl, ename); 194 FREE(ename); 195 } 196 197 extern struct stats *Filecount; 198 199 /* 200 * Call all of the _fini() routines to clean up the exiting DE 201 */ 202 void 203 call_finis(void) 204 { 205 platform_free_eft_files(Efts); 206 Efts = NULL; 207 platform_fini(); 208 fme_fini(); 209 itree_fini(); 210 ipath_fini(); 211 iexpr_fini(); 212 istat_fini(); 213 serd_fini(); 214 lex_free(); 215 check_fini(); 216 tree_fini(); 217 lut_fini(); 218 literals_fini(); 219 stable_fini(); 220 stats_fini(); 221 out_fini(); 222 alloc_fini(); 223 } 224 225 /*ARGSUSED*/ 226 static void 227 doopendict(const char *lhs, void *rhs, void *arg) 228 { 229 out(O_DEBUG, "opendict: \"%s\"", lhs); 230 fmd_hdl_opendict(Hdl, lhs); 231 } 232 233 void 234 _fmd_init(fmd_hdl_t *hdl) 235 { 236 fmd_case_t *casep = NULL; 237 int count; 238 char *fname; 239 240 (void) fmd_hdl_register(hdl, FMD_API_VERSION, &fmd_info); 241 242 /* keep handle for routines like out() which need it */ 243 Hdl = hdl; 244 245 Estats = fmd_prop_get_int32(hdl, "estats"); 246 247 alloc_init(); 248 out_init("eft"); 249 stats_init(Estats); 250 stable_init(0); 251 literals_init(); 252 platform_init(); 253 lut_init(); 254 tree_init(); 255 ipath_init(); 256 iexpr_init(); 257 Efts = platform_get_eft_files(); 258 lex_init(Efts, NULL, 0); 259 check_init(); 260 261 /* 262 * If we read no .eft files, we can't do any 263 * diagnosing, so we just unload ourselves 264 */ 265 if (stats_counter_value(Filecount) == 0) { 266 (void) lex_fini(); 267 call_finis(); 268 fmd_hdl_debug(hdl, "no fault trees provided."); 269 fmd_hdl_unregister(hdl); 270 return; 271 } 272 273 yyparse(); 274 (void) lex_fini(); 275 tree_report(); 276 if (count = out_errcount()) 277 out(O_DIE, "%d language error%s encountered, exiting.", 278 OUTS(count)); 279 280 /* subscribe to events we expect to consume */ 281 lut_walk(Ereportenames, (lut_cb)dosubscribe, NULL); 282 283 /* subscribe to repair events so we can clear state on repair */ 284 fmd_hdl_subscribe(hdl, "list.repaired"); 285 286 /* open dictionaries referenced by all .eft files */ 287 lut_walk(Dicts, (lut_cb)doopendict, (void *)0); 288 289 Verbose = fmd_prop_get_int32(hdl, "verbose"); 290 Warn = fmd_prop_get_int32(hdl, "warn"); 291 Autoclose = fmd_prop_get_string(hdl, "autoclose"); 292 Dupclose = fmd_prop_get_int32(hdl, "dupclose"); 293 Hesitate = fmd_prop_get_int64(hdl, "hesitate"); 294 Max_fme = fmd_prop_get_int32(hdl, "maxfme"); 295 296 if ((fname = fmd_prop_get_string(hdl, "status")) != NULL) { 297 FILE *fp; 298 299 if ((fp = fopen(fname, "a")) == NULL) { 300 fmd_prop_free_string(hdl, fname); 301 out(O_DIE|O_SYS, "status property file: %s", fname); 302 } 303 304 (void) setlinebuf(fp); 305 out_altfp(fp); 306 307 out(O_DEBUG, "appending status changes to \"%s\"", fname); 308 fmd_prop_free_string(hdl, fname); 309 310 out(O_ALTFP|O_STAMP, "\neft.so startup"); 311 } 312 313 out(O_DEBUG, "initialized, verbose %d warn %d autoclose %s " 314 "dupclose %d maxfme %d", 315 Verbose, Warn, Autoclose == NULL ? "(NULL)" : Autoclose, 316 Dupclose, Max_fme); 317 318 fme_istat_load(hdl); 319 fme_serd_load(hdl); 320 321 out(O_DEBUG, "reconstituting any existing fmes"); 322 while ((casep = fmd_case_next(hdl, casep)) != NULL) { 323 fme_restart(hdl, casep); 324 } 325 } 326 327 /*ARGSUSED*/ 328 void 329 _fmd_fini(fmd_hdl_t *hdl) 330 { 331 fmd_prop_free_string(hdl, Autoclose); 332 Autoclose = NULL; 333 call_finis(); 334 } 335