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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 23 /* 24 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 #pragma ident "%Z%%M% %I% %E% SMI" 29 30 #include <stdio.h> 31 #include <string.h> 32 #include <fm/fmd_api.h> 33 #include <libnvpair.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 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 /*ARGSUSED*/ 79 static void 80 eft_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, const char *class) 81 { 82 static char prefix[] = "ereport."; 83 84 if (strncmp(class, prefix, sizeof (prefix) - 1)) 85 out(O_DIE, 86 "eft_recv: event class \"%s\" does not begin with %s", 87 class, prefix); 88 89 fme_receive_external_report(hdl, ep, nvl, class); 90 } 91 92 /*ARGSUSED*/ 93 static void 94 eft_timeout(fmd_hdl_t *hdl, id_t tid, void *arg) 95 { 96 out(O_ALTFP|O_STAMP, 97 "\neft.so timer %ld fired with arg %p", tid, arg); 98 99 if (arg == NULL) 100 return; 101 102 fme_timer_fired(arg, tid); 103 } 104 105 static void 106 eft_close(fmd_hdl_t *hdl, fmd_case_t *fmcase) 107 { 108 out(O_ALTFP, "eft_close called for case %s", 109 fmd_case_uuid(hdl, fmcase)); 110 fme_close_case(hdl, fmcase); 111 } 112 113 static const fmd_prop_t eft_props[] = { 114 { "autoclose", FMD_TYPE_STRING, NULL }, 115 { "dupclose", FMD_TYPE_BOOL, "false" }, 116 { "estats", FMD_TYPE_BOOL, "false" }, 117 { "hesitate", FMD_TYPE_INT64, "10000000000" }, 118 { "verbose", FMD_TYPE_INT32, "0" }, 119 { "warn", FMD_TYPE_BOOL, "false" }, 120 { "status", FMD_TYPE_STRING, NULL }, 121 { "maxfme", FMD_TYPE_INT32, "0" }, 122 { NULL, 0, NULL } 123 }; 124 125 static const fmd_hdl_ops_t eft_ops = { 126 eft_recv, /* fmdo_recv */ 127 eft_timeout, /* fmdo_timeout */ 128 eft_close, /* fmdo_close */ 129 NULL, /* fmdo_stats */ 130 NULL, /* fmdo_gc */ 131 }; 132 133 #define xstr(s) str(s) 134 #define str(s) #s 135 136 static const fmd_hdl_info_t fmd_info = { 137 "eft diagnosis engine", 138 xstr(VERSION_MAJOR) "." xstr(VERSION_MINOR), 139 &eft_ops, eft_props 140 }; 141 142 /* 143 * ename_strdup -- like strdup but ename comes in and class string goes out 144 */ 145 static char * 146 ename_strdup(struct node *np) 147 { 148 struct node *mynp; 149 int len; 150 char *buf; 151 152 /* calculate length of buffer required */ 153 len = 0; 154 for (mynp = np; mynp; mynp = mynp->u.name.next) 155 len += strlen(mynp->u.name.s) + 1; /* +1 for dot or NULL */ 156 157 buf = MALLOC(len); 158 buf[0] = '\0'; 159 160 /* now build the string */ 161 while (np) { 162 (void) strcat(buf, np->u.name.s); 163 np = np->u.name.next; 164 if (np) 165 (void) strcat(buf, "."); 166 } 167 168 return (buf); 169 } 170 171 /*ARGSUSED*/ 172 static void 173 dosubscribe(struct node *lhs, struct node *rhs, void *arg) 174 { 175 char *ename = ename_strdup(lhs); 176 177 out(O_DEBUG, "subscribe: \"%s\"", ename); 178 fmd_hdl_subscribe(Hdl, ename); 179 FREE(ename); 180 } 181 182 extern struct stats *Filecount; 183 184 /* 185 * Call all of the _fini() routines to clean up the exiting DE 186 */ 187 void 188 call_finis(void) 189 { 190 platform_free_eft_files(Efts); 191 Efts = NULL; 192 platform_fini(); 193 fme_fini(); 194 itree_fini(); 195 ipath_fini(); 196 iexpr_fini(); 197 istat_fini(); 198 lex_free(); 199 check_fini(); 200 tree_fini(); 201 lut_fini(); 202 literals_fini(); 203 stable_fini(); 204 stats_fini(); 205 out_fini(); 206 alloc_fini(); 207 } 208 209 /*ARGSUSED*/ 210 static void 211 doopendict(const char *lhs, void *rhs, void *arg) 212 { 213 out(O_DEBUG, "opendict: \"%s\"", lhs); 214 fmd_hdl_opendict(Hdl, lhs); 215 } 216 217 void 218 _fmd_init(fmd_hdl_t *hdl) 219 { 220 fmd_case_t *casep = NULL; 221 int count; 222 char *fname; 223 224 (void) fmd_hdl_register(hdl, FMD_API_VERSION, &fmd_info); 225 226 /* keep handle for routines like out() which need it */ 227 Hdl = hdl; 228 229 Estats = fmd_prop_get_int32(hdl, "estats"); 230 231 alloc_init(); 232 out_init("eft"); 233 stats_init(Estats); 234 stable_init(0); 235 literals_init(); 236 platform_init(); 237 lut_init(); 238 tree_init(); 239 ipath_init(); 240 iexpr_init(); 241 Efts = platform_get_eft_files(); 242 lex_init(Efts, NULL, 0); 243 check_init(); 244 245 /* 246 * If we read no .eft files, we can't do any 247 * diagnosing, so we just unload ourselves 248 */ 249 if (stats_counter_value(Filecount) == 0) { 250 (void) lex_fini(); 251 call_finis(); 252 fmd_hdl_debug(hdl, "no fault trees provided."); 253 fmd_hdl_unregister(hdl); 254 return; 255 } 256 257 yyparse(); 258 (void) lex_fini(); 259 tree_report(); 260 if (count = out_errcount()) 261 out(O_DIE, "%d language error%s encountered, exiting.", 262 OUTS(count)); 263 264 /* subscribe to events we expect to consume */ 265 lut_walk(Ereportenames, (lut_cb)dosubscribe, NULL); 266 267 /* open dictionaries referenced by all .eft files */ 268 lut_walk(Dicts, (lut_cb)doopendict, (void *)0); 269 270 Verbose = fmd_prop_get_int32(hdl, "verbose"); 271 Warn = fmd_prop_get_int32(hdl, "warn"); 272 Autoclose = fmd_prop_get_string(hdl, "autoclose"); 273 Dupclose = fmd_prop_get_int32(hdl, "dupclose"); 274 Hesitate = fmd_prop_get_int64(hdl, "hesitate"); 275 Max_fme = fmd_prop_get_int32(hdl, "maxfme"); 276 277 if ((fname = fmd_prop_get_string(hdl, "status")) != NULL) { 278 FILE *fp; 279 280 if ((fp = fopen(fname, "a")) == NULL) { 281 fmd_prop_free_string(hdl, fname); 282 out(O_DIE|O_SYS, "status property file: %s", fname); 283 } 284 285 (void) setlinebuf(fp); 286 out_altfp(fp); 287 288 out(O_DEBUG, "appending status changes to \"%s\"", fname); 289 fmd_prop_free_string(hdl, fname); 290 291 out(O_ALTFP|O_STAMP, "\neft.so startup"); 292 } 293 294 out(O_DEBUG, "initialized, verbose %d warn %d autoclose %s " 295 "dupclose %d maxfme %d", 296 Verbose, Warn, Autoclose == NULL ? "(NULL)" : Autoclose, 297 Dupclose, Max_fme); 298 299 out(O_DEBUG, "reconstituting any existing fmes"); 300 while ((casep = fmd_case_next(hdl, casep)) != NULL) { 301 fme_restart(hdl, casep); 302 } 303 fme_istat_load(hdl); 304 } 305 306 /*ARGSUSED*/ 307 void 308 _fmd_fini(fmd_hdl_t *hdl) 309 { 310 fmd_prop_free_string(hdl, Autoclose); 311 Autoclose = NULL; 312 call_finis(); 313 } 314