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