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