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 * Copyright 2005 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 <sys/types.h> 30 #include <sys/fm/protocol.h> 31 32 #include <unistd.h> 33 #include <signal.h> 34 #include <limits.h> 35 #include <syslog.h> 36 #include <alloca.h> 37 38 #include <fmd_module.h> 39 #include <fmd_api.h> 40 #include <fmd_string.h> 41 #include <fmd_subr.h> 42 #include <fmd_error.h> 43 #include <fmd_event.h> 44 #include <fmd_eventq.h> 45 #include <fmd_dispq.h> 46 #include <fmd_timerq.h> 47 #include <fmd_thread.h> 48 #include <fmd_ustat.h> 49 #include <fmd_case.h> 50 #include <fmd_protocol.h> 51 #include <fmd_buf.h> 52 #include <fmd_asru.h> 53 #include <fmd_fmri.h> 54 #include <fmd_ckpt.h> 55 56 #include <fmd.h> 57 58 /* 59 * Table of configuration file variable types ops-vector pointers. We use this 60 * to convert from the property description array specified by the module to an 61 * array of fmd_conf_formal_t's. The order of this array must match the order 62 * of #define values specified in <fmd_api.h> (i.e. FMD_TYPE_BOOL must be 0). 63 * For now, the fmd_conf_list and fmd_conf_path types are not supported as we 64 * do not believe modules need them and they would require more complexity. 65 */ 66 static const fmd_conf_ops_t *const _fmd_prop_ops[] = { 67 &fmd_conf_bool, /* FMD_TYPE_BOOL */ 68 &fmd_conf_int32, /* FMD_TYPE_INT32 */ 69 &fmd_conf_uint32, /* FMD_TYPE_UINT32 */ 70 &fmd_conf_int64, /* FMD_TYPE_INT64 */ 71 &fmd_conf_uint64, /* FMD_TYPE_UINT64 */ 72 &fmd_conf_string, /* FMD_TYPE_STRING */ 73 &fmd_conf_time, /* FMD_TYPE_TIME */ 74 &fmd_conf_size, /* FMD_TYPE_SIZE */ 75 }; 76 77 /* 78 * fmd_api_vxerror() provides the engine underlying the fmd_hdl_[v]error() API 79 * calls and the fmd_api_[v]error() utility routine defined below. The routine 80 * formats the error, optionally associated with a particular errno code 'err', 81 * and logs it as an ereport associated with the calling module. Depending on 82 * other optional properties, we also emit a message to stderr and to syslog. 83 */ 84 static void 85 fmd_api_vxerror(fmd_module_t *mp, int err, const char *format, va_list ap) 86 { 87 nvlist_t *nvl; 88 fmd_event_t *e; 89 char *class, *msg; 90 size_t len1, len2; 91 char c; 92 93 /* 94 * fmd_api_vxerror() counts as both an error of class EFMD_MODULE 95 * as well as an instance of 'err' w.r.t. our internal bean counters. 96 */ 97 (void) pthread_mutex_lock(&fmd.d_err_lock); 98 fmd.d_errstats[EFMD_MODULE - EFMD_UNKNOWN].fmds_value.ui64++; 99 100 if (err > EFMD_UNKNOWN && err < EFMD_END) 101 fmd.d_errstats[err - EFMD_UNKNOWN].fmds_value.ui64++; 102 103 (void) pthread_mutex_unlock(&fmd.d_err_lock); 104 105 /* 106 * Format the message using vsnprintf(). As usual, if the format has a 107 * newline in it, it is printed alone; otherwise strerror() is added. 108 */ 109 if (strchr(format, '\n') != NULL) 110 err = 0; /* err is not relevant in the message */ 111 112 len1 = vsnprintf(&c, 1, format, ap); 113 len2 = err != 0 ? snprintf(&c, 1, ": %s\n", fmd_strerror(err)) : 0; 114 115 msg = fmd_alloc(len1 + len2 + 1, FMD_SLEEP); 116 (void) vsnprintf(msg, len1 + 1, format, ap); 117 118 if (err != 0) { 119 (void) snprintf(&msg[len1], len2 + 1, 120 ": %s\n", fmd_strerror(err)); 121 } 122 123 /* 124 * Create an error event corresponding to the error, insert it into the 125 * error log, and dispatch it to the fmd-self-diagnosis engine. 126 */ 127 if (mp != fmd.d_self) { 128 if ((c = msg[len1 + len2 - 1]) == '\n') 129 msg[len1 + len2 - 1] = '\0'; /* strip \n for event */ 130 131 nvl = fmd_protocol_moderror(mp, err, msg); 132 133 if (c == '\n') 134 msg[len1 + len2 - 1] = c; 135 136 (void) nvlist_lookup_string(nvl, FM_CLASS, &class); 137 e = fmd_event_create(FMD_EVT_PROTOCOL, FMD_HRT_NOW, nvl, class); 138 139 (void) pthread_rwlock_rdlock(&fmd.d_log_lock); 140 fmd_log_append(fmd.d_errlog, e, NULL); 141 (void) pthread_rwlock_unlock(&fmd.d_log_lock); 142 143 fmd_event_transition(e, FMD_EVS_ACCEPTED); 144 fmd_event_commit(e); 145 146 fmd_dispq_dispatch(fmd.d_disp, e, class); 147 } 148 149 /* 150 * Similar to fmd_vdebug(), if the debugging switches are enabled we 151 * echo the module name and message to stderr and/or syslog. Unlike 152 * fmd_vdebug(), we also print to stderr if foreground mode is enabled. 153 */ 154 if (fmd.d_fg || (fmd.d_hdl_dbout & FMD_DBOUT_STDERR)) { 155 (void) pthread_mutex_lock(&fmd.d_err_lock); 156 (void) fprintf(stderr, "%s: %s: %s", 157 fmd.d_pname, mp->mod_name, msg); 158 (void) pthread_mutex_unlock(&fmd.d_err_lock); 159 } 160 161 if (fmd.d_hdl_dbout & FMD_DBOUT_SYSLOG) { 162 syslog(LOG_ERR | LOG_DAEMON, "%s ERROR: %s: %s", 163 fmd.d_pname, mp->mod_name, msg); 164 } 165 166 fmd_free(msg, len1 + len2 + 1); 167 } 168 169 /*PRINTFLIKE3*/ 170 static void 171 fmd_api_xerror(fmd_module_t *mp, int err, const char *format, ...) 172 { 173 va_list ap; 174 175 va_start(ap, format); 176 fmd_api_vxerror(mp, err, format, ap); 177 va_end(ap); 178 } 179 180 /* 181 * fmd_api_verror() is a wrapper around fmd_api_vxerror() for API subroutines. 182 * It calls fmd_module_unlock() on behalf of its caller, logs the error, and 183 * then aborts the API call and the surrounding module entry point by doing an 184 * fmd_module_abort(), which longjmps to the place where we entered the module. 185 */ 186 static void 187 fmd_api_verror(fmd_module_t *mp, int err, const char *format, va_list ap) 188 { 189 if (fmd_module_locked(mp)) 190 fmd_module_unlock(mp); 191 192 fmd_api_vxerror(mp, err, format, ap); 193 fmd_module_abort(mp, err); 194 } 195 196 /*PRINTFLIKE3*/ 197 static void 198 fmd_api_error(fmd_module_t *mp, int err, const char *format, ...) 199 { 200 va_list ap; 201 202 va_start(ap, format); 203 fmd_api_verror(mp, err, format, ap); 204 va_end(ap); 205 } 206 207 /* 208 * fmd_api_module_lock() is used as a wrapper around fmd_module_lock() and a 209 * common prologue to each fmd_api.c routine. It verifies that the handle is 210 * valid and owned by the current server thread, locks the handle, and then 211 * verifies that the caller is performing an operation on a registered handle. 212 * If any tests fail, the entire API call is aborted by fmd_api_error(). 213 */ 214 static fmd_module_t * 215 fmd_api_module_lock(fmd_hdl_t *hdl) 216 { 217 fmd_thread_t *tp; 218 fmd_module_t *mp; 219 220 /* 221 * If our TSD is not present at all, this is either a serious bug or 222 * someone has created a thread behind our back and is using fmd's API. 223 * We can't call fmd_api_error() because we can't be sure that we can 224 * unwind our state back to an enclosing fmd_module_dispatch(), so we 225 * must panic instead. This is likely a module design or coding error. 226 */ 227 if ((tp = pthread_getspecific(fmd.d_key)) == NULL) { 228 fmd_panic("fmd module api call made using " 229 "client handle %p from unknown thread\n", (void *)hdl); 230 } 231 232 if ((mp = tp->thr_mod) != (fmd_module_t *)hdl) { 233 fmd_api_error(mp, EFMD_HDL_INVAL, 234 "client handle %p is not valid\n", (void *)hdl); 235 } 236 237 if (mp->mod_flags & FMD_MOD_FAIL) { 238 fmd_api_error(mp, EFMD_MOD_FAIL, 239 "module has experienced an unrecoverable error\n"); 240 } 241 242 fmd_module_lock(mp); 243 244 if (mp->mod_info == NULL) { 245 fmd_api_error(mp, EFMD_HDL_NOTREG, 246 "client handle %p has not been registered\n", (void *)hdl); 247 } 248 249 return (mp); 250 } 251 252 /* 253 * Utility function for API entry points that accept fmd_case_t's. We cast cp 254 * to fmd_case_impl_t and check to make sure the case is owned by the caller. 255 */ 256 static fmd_case_impl_t * 257 fmd_api_case_impl(fmd_module_t *mp, fmd_case_t *cp) 258 { 259 fmd_case_impl_t *cip = (fmd_case_impl_t *)cp; 260 261 if (cip == NULL || cip->ci_mod != mp) { 262 fmd_api_error(mp, EFMD_CASE_OWNER, 263 "case %p is not owned by caller\n", (void *)cip); 264 } 265 266 return (cip); 267 } 268 269 /* 270 * fmd_hdl_register() is the one function which cannot use fmd_api_error() to 271 * report errors, because that routine causes the module to abort. Failure to 272 * register is instead handled by having fmd_hdl_register() return an error to 273 * the _fmd_init() function and then detecting no registration when it returns. 274 * So we use this routine for fmd_hdl_register() error paths instead. 275 */ 276 static int 277 fmd_hdl_register_error(fmd_module_t *mp, int err) 278 { 279 if (fmd_module_locked(mp)) 280 fmd_module_unlock(mp); 281 282 fmd_api_xerror(mp, err, "failed to register"); 283 return (fmd_set_errno(err)); 284 } 285 286 static void 287 fmd_hdl_nop(void) 288 { 289 /* empty function for use with unspecified module entry points */ 290 } 291 292 int 293 fmd_hdl_register(fmd_hdl_t *hdl, int version, const fmd_hdl_info_t *mip) 294 { 295 fmd_thread_t *tp = pthread_getspecific(fmd.d_key); 296 fmd_module_t *mp = tp->thr_mod; 297 298 const fmd_prop_t *prop; 299 const fmd_conf_path_t *pap; 300 fmd_conf_formal_t *cfp; 301 fmd_hdl_ops_t *ops; 302 303 const char *conf = NULL; 304 char buf[PATH_MAX]; 305 int i; 306 307 if (mp != (fmd_module_t *)hdl) 308 return (fmd_hdl_register_error(mp, EFMD_HDL_INVAL)); 309 310 fmd_module_lock(mp); 311 312 /* 313 * First perform some sanity checks on our input. The API version must 314 * be supported by FMD and the handle can only be registered once by 315 * the module thread to which we assigned this client handle. The info 316 * provided for the handle must be valid and have the minimal settings. 317 */ 318 if (version > FMD_API_VERSION_2) 319 return (fmd_hdl_register_error(mp, EFMD_VER_NEW)); 320 321 if (version < FMD_API_VERSION_1) 322 return (fmd_hdl_register_error(mp, EFMD_VER_OLD)); 323 324 if (mp->mod_conf != NULL) 325 return (fmd_hdl_register_error(mp, EFMD_HDL_REG)); 326 327 if (pthread_self() != mp->mod_thread->thr_tid) 328 return (fmd_hdl_register_error(mp, EFMD_HDL_TID)); 329 330 if (mip == NULL || mip->fmdi_desc == NULL || mip->fmdi_vers == NULL || 331 mip->fmdi_ops == NULL || mip->fmdi_ops->fmdo_recv == NULL) 332 return (fmd_hdl_register_error(mp, EFMD_HDL_INFO)); 333 334 /* 335 * Make two passes through the property array to initialize the formals 336 * to use for processing the module's .conf file. In the first pass, 337 * we validate the types and count the number of properties. In the 338 * second pass we copy the strings and fill in the appropriate ops. 339 */ 340 for (prop = mip->fmdi_props, i = 0; prop != NULL && 341 prop->fmdp_name != NULL; prop++, i++) { 342 if (prop->fmdp_type >= 343 sizeof (_fmd_prop_ops) / sizeof (_fmd_prop_ops[0])) { 344 fmd_api_xerror(mp, EFMD_HDL_PROP, 345 "property %s uses invalid type %u\n", 346 prop->fmdp_name, prop->fmdp_type); 347 return (fmd_hdl_register_error(mp, EFMD_HDL_PROP)); 348 } 349 } 350 351 mp->mod_argc = i; 352 mp->mod_argv = fmd_zalloc(sizeof (fmd_conf_formal_t) * i, FMD_SLEEP); 353 354 prop = mip->fmdi_props; 355 cfp = mp->mod_argv; 356 357 for (i = 0; i < mp->mod_argc; i++, prop++, cfp++) { 358 cfp->cf_name = fmd_strdup(prop->fmdp_name, FMD_SLEEP); 359 cfp->cf_ops = _fmd_prop_ops[prop->fmdp_type]; 360 cfp->cf_default = fmd_strdup(prop->fmdp_defv, FMD_SLEEP); 361 } 362 363 /* 364 * If this module came from an on-disk file, compute the name of the 365 * corresponding .conf file and parse properties from it if it exists. 366 */ 367 if (mp->mod_path != NULL) { 368 (void) strlcpy(buf, mp->mod_path, sizeof (buf)); 369 (void) fmd_strdirname(buf); 370 371 (void) strlcat(buf, "/", sizeof (buf)); 372 (void) strlcat(buf, mp->mod_name, sizeof (buf)); 373 (void) strlcat(buf, ".conf", sizeof (buf)); 374 375 if (access(buf, F_OK) == 0) 376 conf = buf; 377 } 378 379 if ((mp->mod_conf = fmd_conf_open(conf, 380 mp->mod_argc, mp->mod_argv)) == NULL) 381 return (fmd_hdl_register_error(mp, EFMD_MOD_CONF)); 382 383 /* 384 * Look up the list of the libdiagcode dictionaries associated with the 385 * module. If none were specified, use the value from daemon's config. 386 * We only fail if the module specified an explicit dictionary. 387 */ 388 (void) fmd_conf_getprop(mp->mod_conf, FMD_PROP_DICTIONARIES, &pap); 389 if (pap->cpa_argc == 0 && mp->mod_ops == &fmd_bltin_ops) 390 (void) fmd_conf_getprop(fmd.d_conf, "self.dict", &pap); 391 392 for (i = 0; i < pap->cpa_argc; i++) { 393 if (fmd_module_dc_opendict(mp, pap->cpa_argv[i]) != 0) { 394 fmd_api_xerror(mp, errno, 395 "failed to open dictionary %s", pap->cpa_argv[i]); 396 return (fmd_hdl_register_error(mp, EFMD_MOD_CONF)); 397 } 398 } 399 400 /* 401 * Make a copy of the handle information and store it in mod_info. We 402 * do not need to bother copying fmdi_props since they're already read. 403 */ 404 mp->mod_info = fmd_alloc(sizeof (fmd_hdl_info_t), FMD_SLEEP); 405 mp->mod_info->fmdi_desc = fmd_strdup(mip->fmdi_desc, FMD_SLEEP); 406 mp->mod_info->fmdi_vers = fmd_strdup(mip->fmdi_vers, FMD_SLEEP); 407 mp->mod_info->fmdi_ops = fmd_alloc(sizeof (fmd_hdl_ops_t), FMD_SLEEP); 408 ops = (fmd_hdl_ops_t *)mp->mod_info->fmdi_ops; 409 mp->mod_info->fmdi_props = NULL; 410 411 /* 412 * Fill in the copy of the module ops. If any optional entry points 413 * are NULL, set them to nop so we don't have to check before calling. 414 */ 415 ops->fmdo_recv = mip->fmdi_ops->fmdo_recv ? 416 mip->fmdi_ops->fmdo_recv : (void (*)())fmd_hdl_nop; 417 ops->fmdo_timeout = mip->fmdi_ops->fmdo_timeout ? 418 mip->fmdi_ops->fmdo_timeout : (void (*)())fmd_hdl_nop; 419 ops->fmdo_close = mip->fmdi_ops->fmdo_close ? 420 mip->fmdi_ops->fmdo_close : (void (*)())fmd_hdl_nop; 421 ops->fmdo_stats = mip->fmdi_ops->fmdo_stats ? 422 mip->fmdi_ops->fmdo_stats : (void (*)())fmd_hdl_nop; 423 ops->fmdo_stats = mip->fmdi_ops->fmdo_stats ? 424 mip->fmdi_ops->fmdo_stats : (void (*)())fmd_hdl_nop; 425 ops->fmdo_gc = mip->fmdi_ops->fmdo_gc ? 426 mip->fmdi_ops->fmdo_gc : (void (*)())fmd_hdl_nop; 427 428 /* 429 * Allocate an FMRI representing this module. We'll use this later 430 * if the module decides to publish any events (e.g. list.suspects). 431 */ 432 mp->mod_fmri = fmd_protocol_fmri_module(mp); 433 434 /* 435 * Any subscriptions specified in the conf file are now stored in the 436 * corresponding property. Add all of these to the dispatch queue. 437 */ 438 (void) fmd_conf_getprop(mp->mod_conf, FMD_PROP_SUBSCRIPTIONS, &pap); 439 440 for (i = 0; i < pap->cpa_argc; i++) 441 fmd_dispq_insert(fmd.d_disp, mp, pap->cpa_argv[i]); 442 443 /* 444 * Unlock the module and restore any pre-existing module checkpoint. 445 * If the checkpoint is missing or corrupt, we just keep going. 446 */ 447 fmd_module_unlock(mp); 448 fmd_ckpt_restore(mp); 449 return (0); 450 } 451 452 void 453 fmd_module_unregister(fmd_module_t *mp) 454 { 455 fmd_conf_formal_t *cfp = mp->mod_argv; 456 const fmd_conf_path_t *pap; 457 int i; 458 459 TRACE((FMD_DBG_MOD, "unregister %p (%s)", (void *)mp, mp->mod_name)); 460 ASSERT(fmd_module_locked(mp)); 461 462 if (mp->mod_error == 0) 463 fmd_ckpt_save(mp); /* take one more checkpoint if needed */ 464 465 (void) fmd_conf_getprop(mp->mod_conf, FMD_PROP_SUBSCRIPTIONS, &pap); 466 467 for (i = 0; i < pap->cpa_argc; i++) 468 fmd_dispq_delete(fmd.d_disp, mp, pap->cpa_argv[i]); 469 470 if (mp->mod_ustat != NULL) { 471 (void) pthread_mutex_lock(&mp->mod_stats_lock); 472 fmd_ustat_destroy(mp->mod_ustat); 473 mp->mod_ustat = NULL; 474 mp->mod_stats = NULL; 475 (void) pthread_mutex_unlock(&mp->mod_stats_lock); 476 } 477 478 fmd_conf_close(mp->mod_conf); 479 mp->mod_conf = NULL; 480 481 for (i = 0; i < mp->mod_argc; i++, cfp++) { 482 fmd_strfree((char *)cfp->cf_name); 483 fmd_strfree((char *)cfp->cf_default); 484 } 485 486 fmd_free(mp->mod_argv, sizeof (fmd_conf_formal_t) * mp->mod_argc); 487 mp->mod_argv = NULL; 488 mp->mod_argc = 0; 489 490 nvlist_free(mp->mod_fmri); 491 mp->mod_fmri = NULL; 492 493 fmd_strfree((char *)mp->mod_info->fmdi_desc); 494 fmd_strfree((char *)mp->mod_info->fmdi_vers); 495 fmd_free((void *)mp->mod_info->fmdi_ops, sizeof (fmd_hdl_ops_t)); 496 fmd_free(mp->mod_info, sizeof (fmd_hdl_info_t)); 497 mp->mod_info = NULL; 498 499 fmd_eventq_abort(mp->mod_queue); 500 } 501 502 void 503 fmd_hdl_unregister(fmd_hdl_t *hdl) 504 { 505 fmd_module_t *mp = fmd_api_module_lock(hdl); 506 fmd_module_unregister(mp); 507 fmd_module_unlock(mp); 508 } 509 510 void 511 fmd_hdl_subscribe(fmd_hdl_t *hdl, const char *class) 512 { 513 fmd_module_t *mp = fmd_api_module_lock(hdl); 514 515 if (fmd_conf_setprop(mp->mod_conf, FMD_PROP_SUBSCRIPTIONS, class) == 0) 516 fmd_dispq_insert(fmd.d_disp, mp, class); 517 518 fmd_module_unlock(mp); 519 } 520 521 void 522 fmd_hdl_unsubscribe(fmd_hdl_t *hdl, const char *class) 523 { 524 fmd_module_t *mp = fmd_api_module_lock(hdl); 525 526 if (fmd_conf_delprop(mp->mod_conf, FMD_PROP_SUBSCRIPTIONS, class) == 0) 527 fmd_dispq_delete(fmd.d_disp, mp, class); 528 529 fmd_module_unlock(mp); 530 fmd_eventq_cancel(mp->mod_queue, FMD_EVT_PROTOCOL, (void *)class); 531 } 532 533 void 534 fmd_hdl_setspecific(fmd_hdl_t *hdl, void *spec) 535 { 536 fmd_module_t *mp = fmd_api_module_lock(hdl); 537 538 mp->mod_spec = spec; 539 fmd_module_unlock(mp); 540 } 541 542 void * 543 fmd_hdl_getspecific(fmd_hdl_t *hdl) 544 { 545 fmd_module_t *mp = fmd_api_module_lock(hdl); 546 void *spec = mp->mod_spec; 547 548 fmd_module_unlock(mp); 549 return (spec); 550 } 551 552 void 553 fmd_hdl_opendict(fmd_hdl_t *hdl, const char *dict) 554 { 555 fmd_module_t *mp = fmd_api_module_lock(hdl); 556 const fmd_conf_path_t *pap; 557 int i; 558 559 /* 560 * Update the dictionary property in order to preserve the list of 561 * pathnames and expand any % tokens in the path. Then retrieve the 562 * new dictionary names from cpa_argv[] and open them one at a time. 563 */ 564 (void) fmd_conf_setprop(mp->mod_conf, FMD_PROP_DICTIONARIES, dict); 565 (void) fmd_conf_getprop(mp->mod_conf, FMD_PROP_DICTIONARIES, &pap); 566 567 ASSERT(pap->cpa_argc > mp->mod_dictc); 568 569 for (i = mp->mod_dictc; i < pap->cpa_argc; i++) { 570 if (fmd_module_dc_opendict(mp, pap->cpa_argv[i]) != 0) { 571 fmd_api_error(mp, EFMD_MOD_DICT, 572 "failed to open dictionary %s for module %s", 573 pap->cpa_argv[i], mp->mod_name); 574 } 575 } 576 577 fmd_module_unlock(mp); 578 } 579 580 void * 581 fmd_hdl_alloc(fmd_hdl_t *hdl, size_t size, int flags) 582 { 583 fmd_module_t *mp = fmd_api_module_lock(hdl); 584 void *data; 585 586 if (mp->mod_stats->ms_memlimit.fmds_value.ui64 - 587 mp->mod_stats->ms_memtotal.fmds_value.ui64 < size) { 588 fmd_api_error(mp, EFMD_HDL_NOMEM, "%s's allocation of %lu " 589 "bytes exceeds module memory limit (%llu)\n", 590 mp->mod_name, (ulong_t)size, (u_longlong_t) 591 mp->mod_stats->ms_memtotal.fmds_value.ui64); 592 } 593 594 if ((data = fmd_alloc(size, flags)) != NULL) 595 mp->mod_stats->ms_memtotal.fmds_value.ui64 += size; 596 597 fmd_module_unlock(mp); 598 return (data); 599 } 600 601 void * 602 fmd_hdl_zalloc(fmd_hdl_t *hdl, size_t size, int flags) 603 { 604 void *data = fmd_hdl_alloc(hdl, size, flags); 605 606 if (data != NULL) 607 bzero(data, size); 608 609 return (data); 610 } 611 612 void 613 fmd_hdl_free(fmd_hdl_t *hdl, void *data, size_t size) 614 { 615 fmd_module_t *mp = fmd_api_module_lock(hdl); 616 617 fmd_free(data, size); 618 mp->mod_stats->ms_memtotal.fmds_value.ui64 -= size; 619 620 fmd_module_unlock(mp); 621 } 622 623 char * 624 fmd_hdl_strdup(fmd_hdl_t *hdl, const char *s, int flags) 625 { 626 char *p; 627 628 if (s != NULL) 629 p = fmd_hdl_alloc(hdl, strlen(s) + 1, flags); 630 else 631 p = NULL; 632 633 if (p != NULL) 634 (void) strcpy(p, s); 635 636 return (p); 637 } 638 639 void 640 fmd_hdl_strfree(fmd_hdl_t *hdl, char *s) 641 { 642 if (s != NULL) 643 fmd_hdl_free(hdl, s, strlen(s) + 1); 644 } 645 646 void 647 fmd_hdl_vabort(fmd_hdl_t *hdl, const char *format, va_list ap) 648 { 649 fmd_api_verror(fmd_api_module_lock(hdl), EFMD_HDL_ABORT, format, ap); 650 } 651 652 /*PRINTFLIKE2*/ 653 void 654 fmd_hdl_abort(fmd_hdl_t *hdl, const char *format, ...) 655 { 656 fmd_module_t *mp = fmd_api_module_lock(hdl); 657 va_list ap; 658 659 va_start(ap, format); 660 fmd_api_verror(mp, EFMD_HDL_ABORT, format, ap); 661 va_end(ap); 662 } 663 664 void 665 fmd_hdl_verror(fmd_hdl_t *hdl, const char *format, va_list ap) 666 { 667 fmd_module_t *mp = fmd_api_module_lock(hdl); 668 fmd_api_vxerror(mp, errno, format, ap); 669 fmd_module_unlock(mp); 670 } 671 672 /*PRINTFLIKE2*/ 673 void 674 fmd_hdl_error(fmd_hdl_t *hdl, const char *format, ...) 675 { 676 va_list ap; 677 678 va_start(ap, format); 679 fmd_hdl_verror(hdl, format, ap); 680 va_end(ap); 681 } 682 683 void 684 fmd_hdl_vdebug(fmd_hdl_t *hdl, const char *format, va_list ap) 685 { 686 fmd_module_t *mp = fmd_api_module_lock(hdl); 687 688 char *msg; 689 size_t len; 690 char c; 691 692 if (!(fmd.d_hdl_debug)) { 693 mp->mod_stats->ms_debugdrop.fmds_value.ui64++; 694 fmd_module_unlock(mp); 695 return; 696 } 697 698 len = vsnprintf(&c, 1, format, ap); 699 700 if ((msg = fmd_alloc(len + 2, FMD_NOSLEEP)) == NULL) { 701 mp->mod_stats->ms_debugdrop.fmds_value.ui64++; 702 fmd_module_unlock(mp); 703 return; 704 } 705 706 (void) vsnprintf(msg, len + 1, format, ap); 707 708 if (msg[len - 1] != '\n') 709 (void) strcpy(&msg[len], "\n"); 710 711 if (fmd.d_hdl_dbout & FMD_DBOUT_STDERR) { 712 (void) pthread_mutex_lock(&fmd.d_err_lock); 713 (void) fprintf(stderr, "%s DEBUG: %s: %s", 714 fmd.d_pname, mp->mod_name, msg); 715 (void) pthread_mutex_unlock(&fmd.d_err_lock); 716 } 717 718 if (fmd.d_hdl_dbout & FMD_DBOUT_SYSLOG) { 719 syslog(LOG_DEBUG | LOG_DAEMON, "%s DEBUG: %s: %s", 720 fmd.d_pname, mp->mod_name, msg); 721 } 722 723 fmd_free(msg, len + 2); 724 fmd_module_unlock(mp); 725 } 726 727 /*PRINTFLIKE2*/ 728 void 729 fmd_hdl_debug(fmd_hdl_t *hdl, const char *format, ...) 730 { 731 va_list ap; 732 733 va_start(ap, format); 734 fmd_hdl_vdebug(hdl, format, ap); 735 va_end(ap); 736 } 737 738 int32_t 739 fmd_prop_get_int32(fmd_hdl_t *hdl, const char *name) 740 { 741 fmd_module_t *mp = fmd_api_module_lock(hdl); 742 const fmd_conf_ops_t *ops = fmd_conf_gettype(mp->mod_conf, name); 743 int32_t value = 0; 744 745 if (ops == &fmd_conf_bool || ops == &fmd_conf_int32 || 746 ops == &fmd_conf_uint32) 747 (void) fmd_conf_getprop(mp->mod_conf, name, &value); 748 else if (ops != NULL) { 749 fmd_api_error(mp, EFMD_PROP_TYPE, 750 "property %s is not of int32 type\n", name); 751 } else { 752 fmd_api_error(mp, EFMD_PROP_DEFN, 753 "property %s is not defined\n", name); 754 } 755 756 fmd_module_unlock(mp); 757 return (value); 758 } 759 760 int64_t 761 fmd_prop_get_int64(fmd_hdl_t *hdl, const char *name) 762 { 763 fmd_module_t *mp = fmd_api_module_lock(hdl); 764 const fmd_conf_ops_t *ops = fmd_conf_gettype(mp->mod_conf, name); 765 int64_t value = 0; 766 767 if (ops == &fmd_conf_int64 || ops == &fmd_conf_uint64 || 768 ops == &fmd_conf_time || ops == &fmd_conf_size) 769 (void) fmd_conf_getprop(mp->mod_conf, name, &value); 770 else if (ops != NULL) { 771 fmd_api_error(mp, EFMD_PROP_TYPE, 772 "property %s is not of int64 type\n", name); 773 } else { 774 fmd_api_error(mp, EFMD_PROP_DEFN, 775 "property %s is not defined\n", name); 776 } 777 778 fmd_module_unlock(mp); 779 return (value); 780 } 781 782 char * 783 fmd_prop_get_string(fmd_hdl_t *hdl, const char *name) 784 { 785 fmd_module_t *mp = fmd_api_module_lock(hdl); 786 const fmd_conf_ops_t *ops = fmd_conf_gettype(mp->mod_conf, name); 787 char *value = NULL; 788 const char *s; 789 790 if (ops == &fmd_conf_string) { 791 (void) fmd_conf_getprop(mp->mod_conf, name, &s); 792 value = fmd_strdup(s, FMD_SLEEP); 793 } else if (ops != NULL) { 794 fmd_api_error(mp, EFMD_PROP_TYPE, 795 "property %s is not of string type\n", name); 796 } else { 797 fmd_api_error(mp, EFMD_PROP_DEFN, 798 "property %s is not defined\n", name); 799 } 800 801 fmd_module_unlock(mp); 802 return (value); 803 } 804 805 void 806 fmd_prop_free_string(fmd_hdl_t *hdl, char *s) 807 { 808 fmd_module_t *mp = fmd_api_module_lock(hdl); 809 fmd_strfree(s); 810 fmd_module_unlock(mp); 811 } 812 813 fmd_stat_t * 814 fmd_stat_create(fmd_hdl_t *hdl, uint_t flags, uint_t argc, fmd_stat_t *argv) 815 { 816 fmd_module_t *mp = fmd_api_module_lock(hdl); 817 fmd_stat_t *ep, *sp; 818 819 if (flags & ~FMD_STAT_ALLOC) { 820 fmd_api_error(mp, EFMD_STAT_FLAGS, 821 "invalid flags 0x%x passed to fmd_stat_create\n", flags); 822 } 823 824 if ((sp = fmd_ustat_insert(mp->mod_ustat, 825 flags | FMD_USTAT_VALIDATE, argc, argv, &ep)) == NULL) { 826 fmd_api_error(mp, errno, 827 "failed to publish stat '%s'", ep->fmds_name); 828 } 829 830 fmd_module_unlock(mp); 831 return (sp); 832 } 833 834 void 835 fmd_stat_destroy(fmd_hdl_t *hdl, uint_t argc, fmd_stat_t *argv) 836 { 837 fmd_module_t *mp = fmd_api_module_lock(hdl); 838 fmd_ustat_delete(mp->mod_ustat, argc, argv); 839 fmd_module_unlock(mp); 840 } 841 842 void 843 fmd_stat_setstr(fmd_hdl_t *hdl, fmd_stat_t *sp, const char *s) 844 { 845 char *str = fmd_strdup(s, FMD_SLEEP); 846 fmd_module_t *mp = fmd_api_module_lock(hdl); 847 848 if (sp->fmds_type != FMD_TYPE_STRING) { 849 fmd_strfree(str); 850 fmd_api_error(mp, EFMD_STAT_TYPE, 851 "stat '%s' is not a string\n", sp->fmds_name); 852 } 853 854 fmd_strfree(sp->fmds_value.str); 855 sp->fmds_value.str = str; 856 857 fmd_module_unlock(mp); 858 } 859 860 fmd_case_t * 861 fmd_case_open(fmd_hdl_t *hdl, void *data) 862 { 863 fmd_module_t *mp = fmd_api_module_lock(hdl); 864 fmd_case_t *cp = fmd_case_create(mp, data); 865 fmd_module_unlock(mp); 866 return (cp); 867 } 868 869 void 870 fmd_case_reset(fmd_hdl_t *hdl, fmd_case_t *cp) 871 { 872 fmd_module_t *mp = fmd_api_module_lock(hdl); 873 fmd_case_impl_t *cip = fmd_api_case_impl(mp, cp); 874 875 if (cip->ci_state >= FMD_CASE_SOLVED) { 876 fmd_api_error(mp, EFMD_CASE_STATE, "cannot solve %s: " 877 "case is already solved or closed\n", cip->ci_uuid); 878 } 879 880 fmd_case_reset_suspects(cp); 881 fmd_module_unlock(mp); 882 } 883 884 void 885 fmd_case_solve(fmd_hdl_t *hdl, fmd_case_t *cp) 886 { 887 fmd_module_t *mp = fmd_api_module_lock(hdl); 888 fmd_case_impl_t *cip = fmd_api_case_impl(mp, cp); 889 890 if (cip->ci_state >= FMD_CASE_SOLVED) { 891 fmd_api_error(mp, EFMD_CASE_STATE, "cannot solve %s: " 892 "case is already solved or closed\n", cip->ci_uuid); 893 } 894 895 fmd_case_transition(cp, FMD_CASE_SOLVED); 896 fmd_module_unlock(mp); 897 } 898 899 void 900 fmd_case_convict(fmd_hdl_t *hdl, fmd_case_t *cp, nvlist_t *nvl) 901 { 902 fmd_module_t *mp = fmd_api_module_lock(hdl); 903 fmd_case_impl_t *cip = fmd_api_case_impl(mp, cp); 904 fmd_asru_hash_t *ahp = fmd.d_asrus; 905 906 nvlist_t *fmri; 907 fmd_asru_t *asru; 908 909 if (cip->ci_state > FMD_CASE_SOLVED) { 910 fmd_api_error(mp, EFMD_CASE_STATE, "cannot convict suspect in " 911 "%s: case is already closed\n", cip->ci_uuid); 912 } 913 914 if (nvlist_lookup_nvlist(nvl, FM_FAULT_ASRU, &fmri) != 0) { 915 fmd_api_error(mp, EFMD_CASE_EVENT, "cannot convict suspect in " 916 "%s: suspect event is missing asru\n", cip->ci_uuid); 917 } 918 919 if ((asru = fmd_asru_hash_lookup_nvl(ahp, fmri, FMD_B_TRUE)) == NULL) { 920 fmd_api_error(mp, EFMD_CASE_EVENT, "cannot convict suspect in " 921 "%s: %s\n", cip->ci_uuid, fmd_strerror(errno)); 922 } 923 924 (void) fmd_asru_clrflags(asru, FMD_ASRU_UNUSABLE, cip->ci_uuid, nvl); 925 (void) fmd_asru_setflags(asru, FMD_ASRU_FAULTY, cip->ci_uuid, nvl); 926 927 fmd_asru_hash_release(ahp, asru); 928 fmd_module_unlock(mp); 929 } 930 931 void 932 fmd_case_close(fmd_hdl_t *hdl, fmd_case_t *cp) 933 { 934 fmd_module_t *mp = fmd_api_module_lock(hdl); 935 936 (void) fmd_api_case_impl(mp, cp); /* validate 'cp' */ 937 fmd_case_transition(cp, FMD_CASE_CLOSED); 938 939 fmd_module_unlock(mp); 940 } 941 942 const char * 943 fmd_case_uuid(fmd_hdl_t *hdl, fmd_case_t *cp) 944 { 945 fmd_module_t *mp = fmd_api_module_lock(hdl); 946 fmd_case_impl_t *cip = fmd_api_case_impl(mp, cp); 947 const char *uuid = cip->ci_uuid; 948 949 fmd_module_unlock(mp); 950 return (uuid); 951 } 952 953 fmd_case_t * 954 fmd_case_uulookup(fmd_hdl_t *hdl, const char *uuid) 955 { 956 fmd_module_t *cmp, *mp = fmd_api_module_lock(hdl); 957 fmd_case_t *cp = fmd_case_hash_lookup(fmd.d_cases, uuid); 958 959 if (cp != NULL) { 960 cmp = ((fmd_case_impl_t *)cp)->ci_mod; 961 fmd_case_rele(cp); 962 } else 963 cmp = NULL; 964 965 fmd_module_unlock(mp); 966 return (cmp == mp ? cp : NULL); 967 } 968 969 void 970 fmd_case_uuconvict(fmd_hdl_t *hdl, const char *uuid, nvlist_t *nvl) 971 { 972 fmd_module_t *mp = fmd_api_module_lock(hdl); 973 fmd_case_t *cp = fmd_case_hash_lookup(fmd.d_cases, uuid); 974 fmd_case_impl_t *cip = (fmd_case_impl_t *)cp; 975 fmd_asru_hash_t *ahp = fmd.d_asrus; 976 977 nvlist_t *fmri; 978 fmd_asru_t *asru; 979 980 if (cp == NULL) { 981 fmd_api_error(mp, EFMD_CASE_INVAL, 982 "cannot convict suspect in %s", uuid); 983 } 984 985 if (cip->ci_state > FMD_CASE_SOLVED) { 986 fmd_case_rele(cp); 987 fmd_api_error(mp, EFMD_CASE_STATE, "cannot convict suspect in " 988 "%s: case is already closed\n", uuid); 989 } 990 991 if (nvlist_lookup_nvlist(nvl, FM_FAULT_ASRU, &fmri) != 0) { 992 fmd_case_rele(cp); 993 fmd_api_error(mp, EFMD_CASE_EVENT, "cannot convict suspect in " 994 "%s: suspect event is missing asru\n", uuid); 995 } 996 997 if ((asru = fmd_asru_hash_lookup_nvl(ahp, fmri, FMD_B_TRUE)) == NULL) { 998 fmd_case_rele(cp); 999 fmd_api_error(mp, EFMD_CASE_EVENT, "cannot convict suspect in " 1000 "%s: %s\n", uuid, fmd_strerror(errno)); 1001 } 1002 1003 (void) fmd_asru_clrflags(asru, FMD_ASRU_UNUSABLE, cip->ci_uuid, nvl); 1004 (void) fmd_asru_setflags(asru, FMD_ASRU_FAULTY, cip->ci_uuid, nvl); 1005 1006 fmd_asru_hash_release(ahp, asru); 1007 fmd_case_rele(cp); 1008 fmd_module_unlock(mp); 1009 } 1010 1011 void 1012 fmd_case_uuclose(fmd_hdl_t *hdl, const char *uuid) 1013 { 1014 fmd_module_t *mp = fmd_api_module_lock(hdl); 1015 fmd_case_t *cp = fmd_case_hash_lookup(fmd.d_cases, uuid); 1016 1017 if (cp == NULL) 1018 fmd_api_error(mp, EFMD_CASE_INVAL, "cannot close %s", uuid); 1019 1020 fmd_case_transition(cp, FMD_CASE_CLOSED); 1021 fmd_case_rele(cp); 1022 fmd_module_unlock(mp); 1023 } 1024 1025 int 1026 fmd_case_uuclosed(fmd_hdl_t *hdl, const char *uuid) 1027 { 1028 fmd_module_t *mp = fmd_api_module_lock(hdl); 1029 fmd_case_t *cp = fmd_case_hash_lookup(fmd.d_cases, uuid); 1030 fmd_case_impl_t *cip = (fmd_case_impl_t *)cp; 1031 int rv = FMD_B_TRUE; 1032 1033 if (cip != NULL) { 1034 rv = cip->ci_state >= FMD_CASE_CLOSED; 1035 fmd_case_rele(cp); 1036 } 1037 1038 fmd_module_unlock(mp); 1039 return (rv); 1040 } 1041 1042 static int 1043 fmd_case_instate(fmd_hdl_t *hdl, fmd_case_t *cp, uint_t state) 1044 { 1045 fmd_module_t *mp = fmd_api_module_lock(hdl); 1046 fmd_case_impl_t *cip = fmd_api_case_impl(mp, cp); 1047 int rv = cip->ci_state >= state; 1048 1049 fmd_module_unlock(mp); 1050 return (rv); 1051 } 1052 1053 int 1054 fmd_case_solved(fmd_hdl_t *hdl, fmd_case_t *cp) 1055 { 1056 return (fmd_case_instate(hdl, cp, FMD_CASE_SOLVED)); 1057 } 1058 1059 int 1060 fmd_case_closed(fmd_hdl_t *hdl, fmd_case_t *cp) 1061 { 1062 return (fmd_case_instate(hdl, cp, FMD_CASE_CLOSED)); 1063 } 1064 1065 void 1066 fmd_case_add_ereport(fmd_hdl_t *hdl, fmd_case_t *cp, fmd_event_t *ep) 1067 { 1068 fmd_module_t *mp = fmd_api_module_lock(hdl); 1069 1070 (void) fmd_api_case_impl(mp, cp); /* validate 'cp' */ 1071 fmd_case_insert_event(cp, ep); 1072 mp->mod_stats->ms_accepted.fmds_value.ui64++; 1073 1074 fmd_module_unlock(mp); 1075 } 1076 1077 void 1078 fmd_case_add_serd(fmd_hdl_t *hdl, fmd_case_t *cp, const char *name) 1079 { 1080 fmd_module_t *mp = fmd_api_module_lock(hdl); 1081 fmd_serd_elem_t *sep; 1082 fmd_serd_eng_t *sgp; 1083 1084 if ((sgp = fmd_serd_eng_lookup(&mp->mod_serds, name)) == NULL) { 1085 fmd_api_error(mp, EFMD_SERD_NAME, 1086 "failed to add events from serd engine '%s'", name); 1087 } 1088 1089 (void) fmd_api_case_impl(mp, cp); /* validate 'cp' */ 1090 1091 for (sep = fmd_list_next(&sgp->sg_list); 1092 sep != NULL; sep = fmd_list_next(sep)) 1093 fmd_case_insert_event(cp, sep->se_event); 1094 1095 mp->mod_stats->ms_accepted.fmds_value.ui64 += sgp->sg_count; 1096 fmd_module_unlock(mp); 1097 } 1098 1099 void 1100 fmd_case_add_suspect(fmd_hdl_t *hdl, fmd_case_t *cp, nvlist_t *nvl) 1101 { 1102 fmd_module_t *mp = fmd_api_module_lock(hdl); 1103 fmd_case_impl_t *cip = fmd_api_case_impl(mp, cp); 1104 char *class; 1105 1106 if (cip->ci_state >= FMD_CASE_SOLVED) { 1107 fmd_api_error(mp, EFMD_CASE_STATE, "cannot add suspect to " 1108 "%s: case is already solved or closed\n", cip->ci_uuid); 1109 } 1110 1111 if (nvlist_lookup_string(nvl, FM_CLASS, &class) != 0 || 1112 class == NULL || *class == '\0') { 1113 fmd_api_error(mp, EFMD_CASE_EVENT, "cannot add suspect to " 1114 "%s: suspect event is missing a class\n", cip->ci_uuid); 1115 } 1116 1117 fmd_case_insert_suspect(cp, nvl); 1118 fmd_module_unlock(mp); 1119 } 1120 1121 void 1122 fmd_case_setspecific(fmd_hdl_t *hdl, fmd_case_t *cp, void *data) 1123 { 1124 fmd_module_t *mp = fmd_api_module_lock(hdl); 1125 fmd_case_impl_t *cip = fmd_api_case_impl(mp, cp); 1126 1127 (void) pthread_mutex_lock(&cip->ci_lock); 1128 cip->ci_data = data; 1129 (void) pthread_mutex_unlock(&cip->ci_lock); 1130 1131 fmd_module_unlock(mp); 1132 } 1133 1134 void * 1135 fmd_case_getspecific(fmd_hdl_t *hdl, fmd_case_t *cp) 1136 { 1137 fmd_module_t *mp = fmd_api_module_lock(hdl); 1138 fmd_case_impl_t *cip = fmd_api_case_impl(mp, cp); 1139 void *data; 1140 1141 (void) pthread_mutex_lock(&cip->ci_lock); 1142 data = cip->ci_data; 1143 (void) pthread_mutex_unlock(&cip->ci_lock); 1144 1145 fmd_module_unlock(mp); 1146 return (data); 1147 } 1148 1149 void 1150 fmd_case_setprincipal(fmd_hdl_t *hdl, fmd_case_t *cp, fmd_event_t *ep) 1151 { 1152 fmd_module_t *mp = fmd_api_module_lock(hdl); 1153 1154 (void) fmd_api_case_impl(mp, cp); /* validate 'cp' */ 1155 fmd_case_insert_principal(cp, ep); 1156 mp->mod_stats->ms_accepted.fmds_value.ui64++; 1157 1158 fmd_module_unlock(mp); 1159 } 1160 1161 fmd_event_t * 1162 fmd_case_getprincipal(fmd_hdl_t *hdl, fmd_case_t *cp) 1163 { 1164 fmd_module_t *mp = fmd_api_module_lock(hdl); 1165 fmd_case_impl_t *cip = fmd_api_case_impl(mp, cp); 1166 fmd_event_t *ep; 1167 1168 (void) pthread_mutex_lock(&cip->ci_lock); 1169 ep = cip->ci_principal; 1170 (void) pthread_mutex_unlock(&cip->ci_lock); 1171 1172 fmd_module_unlock(mp); 1173 return (ep); 1174 } 1175 1176 fmd_case_t * 1177 fmd_case_next(fmd_hdl_t *hdl, fmd_case_t *cp) 1178 { 1179 fmd_module_t *mp = fmd_api_module_lock(hdl); 1180 1181 if (cp != NULL) 1182 cp = fmd_list_next(fmd_api_case_impl(mp, cp)); 1183 else 1184 cp = fmd_list_next(&mp->mod_cases); 1185 1186 fmd_module_unlock(mp); 1187 return (cp); 1188 } 1189 1190 fmd_case_t * 1191 fmd_case_prev(fmd_hdl_t *hdl, fmd_case_t *cp) 1192 { 1193 fmd_module_t *mp = fmd_api_module_lock(hdl); 1194 1195 if (cp != NULL) 1196 cp = fmd_list_prev(fmd_api_case_impl(mp, cp)); 1197 else 1198 cp = fmd_list_prev(&mp->mod_cases); 1199 1200 fmd_module_unlock(mp); 1201 return (cp); 1202 } 1203 1204 /* 1205 * Utility function for fmd_buf_* routines. If a case is specified, use the 1206 * case's ci_bufs hash; otherwise use the module's global mod_bufs hash. 1207 */ 1208 static fmd_buf_hash_t * 1209 fmd_buf_gethash(fmd_module_t *mp, fmd_case_t *cp) 1210 { 1211 return (cp ? &fmd_api_case_impl(mp, cp)->ci_bufs : &mp->mod_bufs); 1212 } 1213 1214 void 1215 fmd_buf_create(fmd_hdl_t *hdl, fmd_case_t *cp, const char *name, size_t size) 1216 { 1217 fmd_module_t *mp = fmd_api_module_lock(hdl); 1218 fmd_buf_hash_t *bhp = fmd_buf_gethash(mp, cp); 1219 fmd_buf_t *bp = fmd_buf_lookup(bhp, name); 1220 1221 if (bp == NULL) { 1222 if (fmd_strbadid(name, FMD_B_TRUE) != NULL || size == 0) { 1223 fmd_api_error(mp, EFMD_BUF_INVAL, "cannot create '%s' " 1224 "(size %lu): %s\n", name, (ulong_t)size, 1225 fmd_strerror(EFMD_BUF_INVAL)); 1226 } 1227 1228 if (mp->mod_stats->ms_buflimit.fmds_value.ui64 - 1229 mp->mod_stats->ms_buftotal.fmds_value.ui64 < size) { 1230 fmd_api_error(mp, EFMD_BUF_LIMIT, "cannot create '%s': " 1231 "buf limit exceeded (%llu)\n", name, (u_longlong_t) 1232 mp->mod_stats->ms_buflimit.fmds_value.ui64); 1233 } 1234 1235 mp->mod_stats->ms_buftotal.fmds_value.ui64 += size; 1236 bp = fmd_buf_insert(bhp, name, size); 1237 1238 } else { 1239 fmd_api_error(mp, EFMD_BUF_EXISTS, 1240 "cannot create '%s': buffer already exists\n", name); 1241 } 1242 1243 if (cp != NULL) 1244 fmd_case_setdirty(cp); 1245 else 1246 fmd_module_setdirty(mp); 1247 1248 fmd_module_unlock(mp); 1249 } 1250 1251 void 1252 fmd_buf_destroy(fmd_hdl_t *hdl, fmd_case_t *cp, const char *name) 1253 { 1254 fmd_module_t *mp = fmd_api_module_lock(hdl); 1255 fmd_buf_hash_t *bhp = fmd_buf_gethash(mp, cp); 1256 fmd_buf_t *bp = fmd_buf_lookup(bhp, name); 1257 1258 if (bp != NULL) { 1259 mp->mod_stats->ms_buftotal.fmds_value.ui64 -= bp->buf_size; 1260 fmd_buf_delete(bhp, name); 1261 1262 if (cp != NULL) 1263 fmd_case_setdirty(cp); 1264 else 1265 fmd_module_setdirty(mp); 1266 } 1267 1268 fmd_module_unlock(mp); 1269 } 1270 1271 void 1272 fmd_buf_read(fmd_hdl_t *hdl, fmd_case_t *cp, 1273 const char *name, void *buf, size_t size) 1274 { 1275 fmd_module_t *mp = fmd_api_module_lock(hdl); 1276 fmd_buf_t *bp = fmd_buf_lookup(fmd_buf_gethash(mp, cp), name); 1277 1278 if (bp == NULL) { 1279 fmd_api_error(mp, EFMD_BUF_NOENT, "no buf named '%s' is " 1280 "associated with %s\n", name, cp ? "case" : "module"); 1281 } 1282 1283 bcopy(bp->buf_data, buf, MIN(bp->buf_size, size)); 1284 if (size > bp->buf_size) 1285 bzero((char *)buf + bp->buf_size, size - bp->buf_size); 1286 1287 fmd_module_unlock(mp); 1288 } 1289 1290 void 1291 fmd_buf_write(fmd_hdl_t *hdl, fmd_case_t *cp, 1292 const char *name, const void *buf, size_t size) 1293 { 1294 fmd_module_t *mp = fmd_api_module_lock(hdl); 1295 fmd_buf_hash_t *bhp = fmd_buf_gethash(mp, cp); 1296 fmd_buf_t *bp = fmd_buf_lookup(bhp, name); 1297 1298 if (bp == NULL) { 1299 if (fmd_strbadid(name, FMD_B_TRUE) != NULL || size == 0) { 1300 fmd_api_error(mp, EFMD_BUF_INVAL, "cannot write '%s' " 1301 "(size %lu): %s\n", name, (ulong_t)size, 1302 fmd_strerror(EFMD_BUF_INVAL)); 1303 } 1304 1305 if (mp->mod_stats->ms_buflimit.fmds_value.ui64 - 1306 mp->mod_stats->ms_buftotal.fmds_value.ui64 < size) { 1307 fmd_api_error(mp, EFMD_BUF_LIMIT, "cannot write '%s': " 1308 "buf limit exceeded (%llu)\n", name, (u_longlong_t) 1309 mp->mod_stats->ms_buflimit.fmds_value.ui64); 1310 } 1311 1312 mp->mod_stats->ms_buftotal.fmds_value.ui64 += size; 1313 bp = fmd_buf_insert(bhp, name, size); 1314 1315 } else if (size > bp->buf_size) { 1316 fmd_api_error(mp, EFMD_BUF_OFLOW, 1317 "write to buf '%s' overflows buf size (%lu > %lu)\n", 1318 name, (ulong_t)size, (ulong_t)bp->buf_size); 1319 } 1320 1321 bcopy(buf, bp->buf_data, MIN(bp->buf_size, size)); 1322 bp->buf_flags |= FMD_BUF_DIRTY; 1323 1324 if (cp != NULL) 1325 fmd_case_setdirty(cp); 1326 else 1327 fmd_module_setdirty(mp); 1328 1329 fmd_module_unlock(mp); 1330 } 1331 1332 size_t 1333 fmd_buf_size(fmd_hdl_t *hdl, fmd_case_t *cp, const char *name) 1334 { 1335 fmd_module_t *mp = fmd_api_module_lock(hdl); 1336 fmd_buf_hash_t *bhp = fmd_buf_gethash(mp, cp); 1337 1338 fmd_buf_t *bp; 1339 size_t size; 1340 1341 if ((bp = fmd_buf_lookup(bhp, name)) != NULL) 1342 size = bp->buf_size; 1343 else 1344 size = 0; 1345 1346 fmd_module_unlock(mp); 1347 return (size); 1348 } 1349 1350 void 1351 fmd_serd_create(fmd_hdl_t *hdl, const char *name, uint_t n, hrtime_t t) 1352 { 1353 fmd_module_t *mp = fmd_api_module_lock(hdl); 1354 1355 if (fmd_serd_eng_lookup(&mp->mod_serds, name) != NULL) { 1356 fmd_api_error(mp, EFMD_SERD_EXISTS, 1357 "failed to create serd engine '%s': %s\n", 1358 name, fmd_strerror(EFMD_SERD_EXISTS)); 1359 } 1360 1361 (void) fmd_serd_eng_insert(&mp->mod_serds, name, n, t); 1362 fmd_module_setdirty(mp); 1363 fmd_module_unlock(mp); 1364 } 1365 1366 void 1367 fmd_serd_destroy(fmd_hdl_t *hdl, const char *name) 1368 { 1369 fmd_module_t *mp = fmd_api_module_lock(hdl); 1370 1371 fmd_serd_eng_delete(&mp->mod_serds, name); 1372 fmd_module_setdirty(mp); 1373 fmd_module_unlock(mp); 1374 } 1375 1376 int 1377 fmd_serd_exists(fmd_hdl_t *hdl, const char *name) 1378 { 1379 fmd_module_t *mp = fmd_api_module_lock(hdl); 1380 int rv = (fmd_serd_eng_lookup(&mp->mod_serds, name) != NULL); 1381 fmd_module_unlock(mp); 1382 1383 return (rv); 1384 } 1385 1386 void 1387 fmd_serd_reset(fmd_hdl_t *hdl, const char *name) 1388 { 1389 fmd_module_t *mp = fmd_api_module_lock(hdl); 1390 fmd_serd_eng_t *sgp; 1391 1392 if ((sgp = fmd_serd_eng_lookup(&mp->mod_serds, name)) == NULL) { 1393 fmd_api_error(mp, EFMD_SERD_NAME, 1394 "serd engine '%s' does not exist\n", name); 1395 } 1396 1397 fmd_serd_eng_reset(sgp); 1398 fmd_module_setdirty(mp); 1399 fmd_module_unlock(mp); 1400 } 1401 1402 int 1403 fmd_serd_record(fmd_hdl_t *hdl, const char *name, fmd_event_t *ep) 1404 { 1405 fmd_module_t *mp = fmd_api_module_lock(hdl); 1406 fmd_serd_eng_t *sgp; 1407 int err; 1408 1409 if ((sgp = fmd_serd_eng_lookup(&mp->mod_serds, name)) == NULL) { 1410 fmd_api_error(mp, EFMD_SERD_NAME, 1411 "failed to add record to serd engine '%s'", name); 1412 } 1413 1414 err = fmd_serd_eng_record(sgp, ep); 1415 1416 if (sgp->sg_flags & FMD_SERD_DIRTY) 1417 fmd_module_setdirty(mp); 1418 1419 fmd_module_unlock(mp); 1420 return (err); 1421 } 1422 1423 int 1424 fmd_serd_fired(fmd_hdl_t *hdl, const char *name) 1425 { 1426 fmd_module_t *mp = fmd_api_module_lock(hdl); 1427 fmd_serd_eng_t *sgp; 1428 int err; 1429 1430 if ((sgp = fmd_serd_eng_lookup(&mp->mod_serds, name)) == NULL) { 1431 fmd_api_error(mp, EFMD_SERD_NAME, 1432 "serd engine '%s' does not exist\n", name); 1433 } 1434 1435 err = fmd_serd_eng_fired(sgp); 1436 fmd_module_unlock(mp); 1437 return (err); 1438 } 1439 1440 int 1441 fmd_serd_empty(fmd_hdl_t *hdl, const char *name) 1442 { 1443 fmd_module_t *mp = fmd_api_module_lock(hdl); 1444 fmd_serd_eng_t *sgp; 1445 int empty; 1446 1447 if ((sgp = fmd_serd_eng_lookup(&mp->mod_serds, name)) == NULL) { 1448 fmd_api_error(mp, EFMD_SERD_NAME, 1449 "serd engine '%s' does not exist\n", name); 1450 } 1451 1452 empty = fmd_serd_eng_empty(sgp); 1453 fmd_module_unlock(mp); 1454 return (empty); 1455 } 1456 1457 pthread_t 1458 fmd_thr_create(fmd_hdl_t *hdl, void (*func)(void *), void *arg) 1459 { 1460 fmd_module_t *mp = fmd_api_module_lock(hdl); 1461 fmd_thread_t *tp; 1462 pthread_t tid; 1463 1464 if (pthread_self() != mp->mod_thread->thr_tid) { 1465 fmd_api_error(mp, EFMD_THR_INVAL, "auxiliary thread tried to " 1466 "create another auxiliary thread\n"); 1467 } 1468 1469 if (mp->mod_stats->ms_thrtotal.fmds_value.ui32 >= 1470 mp->mod_stats->ms_thrlimit.fmds_value.ui32) { 1471 fmd_api_error(mp, EFMD_THR_LIMIT, "%s request to create an " 1472 "auxiliary thread exceeds module thread limit (%u)\n", 1473 mp->mod_name, mp->mod_stats->ms_thrlimit.fmds_value.ui32); 1474 } 1475 1476 if ((tp = fmd_thread_create(mp, func, arg)) == NULL) { 1477 fmd_api_error(mp, EFMD_THR_CREATE, 1478 "failed to create auxiliary thread"); 1479 } 1480 1481 tid = tp->thr_tid; 1482 mp->mod_stats->ms_thrtotal.fmds_value.ui32++; 1483 (void) fmd_idspace_xalloc(mp->mod_threads, tid, tp); 1484 1485 fmd_module_unlock(mp); 1486 return (tid); 1487 } 1488 1489 void 1490 fmd_thr_destroy(fmd_hdl_t *hdl, pthread_t tid) 1491 { 1492 fmd_module_t *mp = fmd_api_module_lock(hdl); 1493 fmd_thread_t *tp; 1494 int err; 1495 1496 if (pthread_self() == tid) { 1497 fmd_api_error(mp, EFMD_THR_INVAL, "auxiliary thread tried to " 1498 "destroy itself (tid %u)\n", tid); 1499 } 1500 1501 if ((tp = fmd_idspace_getspecific(mp->mod_threads, tid)) == NULL) { 1502 fmd_api_error(mp, EFMD_THR_INVAL, "auxiliary thread tried to " 1503 "destroy an invalid thread (tid %u)\n", tid); 1504 } 1505 1506 /* 1507 * Wait for the specified thread to exit and then join with it. Since 1508 * the thread may need to make API calls in order to complete its work 1509 * we must sleep with the module lock unheld, and then reacquire it. 1510 */ 1511 fmd_module_unlock(mp); 1512 err = pthread_join(tid, NULL); 1513 mp = fmd_api_module_lock(hdl); 1514 1515 /* 1516 * Since pthread_join() was called without the module lock held, if 1517 * multiple callers attempted to destroy the same auxiliary thread 1518 * simultaneously, one will succeed and the others will get ESRCH. 1519 * Therefore we silently ignore ESRCH but only allow the caller who 1520 * succeessfully joined with the auxiliary thread to destroy it. 1521 */ 1522 if (err != 0 && err != ESRCH) { 1523 fmd_api_error(mp, EFMD_THR_JOIN, 1524 "failed to join with auxiliary thread %u\n", tid); 1525 } 1526 1527 if (err == 0) { 1528 fmd_thread_destroy(tp, FMD_THREAD_NOJOIN); 1529 mp->mod_stats->ms_thrtotal.fmds_value.ui32--; 1530 (void) fmd_idspace_free(mp->mod_threads, tid); 1531 } 1532 1533 fmd_module_unlock(mp); 1534 } 1535 1536 void 1537 fmd_thr_signal(fmd_hdl_t *hdl, pthread_t tid) 1538 { 1539 fmd_module_t *mp = fmd_api_module_lock(hdl); 1540 1541 if (tid != mp->mod_thread->thr_tid && 1542 fmd_idspace_getspecific(mp->mod_threads, tid) == NULL) { 1543 fmd_api_error(mp, EFMD_THR_INVAL, "tid %u is not a valid " 1544 "thread id for module %s\n", tid, mp->mod_name); 1545 } 1546 1547 (void) pthread_kill(tid, fmd.d_thr_sig); 1548 fmd_module_unlock(mp); 1549 } 1550 1551 id_t 1552 fmd_timer_install(fmd_hdl_t *hdl, void *arg, fmd_event_t *ep, hrtime_t delta) 1553 { 1554 fmd_module_t *mp = fmd_api_module_lock(hdl); 1555 fmd_modtimer_t *t; 1556 id_t id; 1557 1558 if (delta < 0) { 1559 fmd_api_error(mp, EFMD_TIMER_INVAL, 1560 "timer delta %lld is not a valid interval\n", delta); 1561 } 1562 1563 t = fmd_alloc(sizeof (fmd_modtimer_t), FMD_SLEEP); 1564 t->mt_mod = mp; 1565 t->mt_arg = arg; 1566 t->mt_id = -1; 1567 1568 if ((id = fmd_timerq_install(fmd.d_timers, mp->mod_timerids, 1569 (fmd_timer_f *)fmd_module_timeout, t, ep, delta)) == -1) { 1570 fmd_free(t, sizeof (fmd_modtimer_t)); 1571 fmd_api_error(mp, EFMD_TIMER_LIMIT, 1572 "failed to install timer +%lld", delta); 1573 } 1574 1575 fmd_module_unlock(mp); 1576 return (id); 1577 } 1578 1579 void 1580 fmd_timer_remove(fmd_hdl_t *hdl, id_t id) 1581 { 1582 fmd_module_t *mp = fmd_api_module_lock(hdl); 1583 fmd_modtimer_t *t; 1584 1585 if (!fmd_idspace_valid(mp->mod_timerids, id)) { 1586 fmd_api_error(mp, EFMD_TIMER_INVAL, 1587 "id %ld is not a valid timer id\n", id); 1588 } 1589 1590 t = fmd_timerq_remove(fmd.d_timers, mp->mod_timerids, id); 1591 fmd_module_unlock(mp); 1592 1593 if (t != NULL) { 1594 fmd_eventq_cancel(mp->mod_queue, FMD_EVT_TIMEOUT, t); 1595 fmd_free(t, sizeof (fmd_modtimer_t)); 1596 } 1597 } 1598 1599 nvlist_t * 1600 fmd_nvl_create_fault(fmd_hdl_t *hdl, const char *class, 1601 uint8_t certainty, nvlist_t *asru, nvlist_t *fru, nvlist_t *rsrc) 1602 { 1603 fmd_module_t *mp = fmd_api_module_lock(hdl); 1604 nvlist_t *nvl; 1605 1606 if (class == NULL || class[0] == '\0') 1607 fmd_api_error(mp, EFMD_NVL_INVAL, "invalid fault class\n"); 1608 1609 nvl = fmd_protocol_fault(class, certainty, asru, fru, rsrc); 1610 fmd_module_unlock(mp); 1611 return (nvl); 1612 } 1613 1614 int 1615 fmd_nvl_class_match(fmd_hdl_t *hdl, nvlist_t *nvl, const char *pattern) 1616 { 1617 fmd_module_t *mp = fmd_api_module_lock(hdl); 1618 char *class; 1619 int rv; 1620 1621 rv = (nvl != NULL && nvlist_lookup_string(nvl, 1622 FM_CLASS, &class) == 0 && fmd_strmatch(class, pattern)); 1623 1624 fmd_module_unlock(mp); 1625 return (rv); 1626 } 1627 1628 int 1629 fmd_nvl_fmri_expand(fmd_hdl_t *hdl, nvlist_t *nvl) 1630 { 1631 fmd_module_t *mp = fmd_api_module_lock(hdl); 1632 int rv; 1633 1634 if (nvl == NULL) { 1635 fmd_api_error(mp, EFMD_NVL_INVAL, 1636 "invalid nvlist %p\n", (void *)nvl); 1637 } 1638 1639 rv = fmd_fmri_expand(nvl); 1640 fmd_module_unlock(mp); 1641 return (rv); 1642 } 1643 1644 int 1645 fmd_nvl_fmri_present(fmd_hdl_t *hdl, nvlist_t *nvl) 1646 { 1647 fmd_module_t *mp = fmd_api_module_lock(hdl); 1648 int rv; 1649 1650 if (nvl == NULL) { 1651 fmd_api_error(mp, EFMD_NVL_INVAL, 1652 "invalid nvlist %p\n", (void *)nvl); 1653 } 1654 1655 rv = fmd_fmri_present(nvl); 1656 fmd_module_unlock(mp); 1657 1658 if (rv < 0) { 1659 fmd_api_error(mp, EFMD_FMRI_OP, "invalid fmri for " 1660 "fmd_nvl_fmri_present\n"); 1661 } 1662 1663 return (rv); 1664 } 1665 1666 int 1667 fmd_nvl_fmri_unusable(fmd_hdl_t *hdl, nvlist_t *nvl) 1668 { 1669 fmd_module_t *mp = fmd_api_module_lock(hdl); 1670 int rv; 1671 1672 if (nvl == NULL) { 1673 fmd_api_error(mp, EFMD_NVL_INVAL, 1674 "invalid nvlist %p\n", (void *)nvl); 1675 } 1676 1677 rv = fmd_fmri_unusable(nvl); 1678 fmd_module_unlock(mp); 1679 1680 if (rv < 0) { 1681 fmd_api_error(mp, EFMD_FMRI_OP, "invalid fmri for " 1682 "fmd_nvl_fmri_unusable\n"); 1683 } 1684 1685 return (rv); 1686 } 1687 1688 int 1689 fmd_nvl_fmri_contains(fmd_hdl_t *hdl, nvlist_t *n1, nvlist_t *n2) 1690 { 1691 fmd_module_t *mp = fmd_api_module_lock(hdl); 1692 int rv; 1693 1694 if (n1 == NULL || n2 == NULL) { 1695 fmd_api_error(mp, EFMD_NVL_INVAL, 1696 "invalid nvlist(s): %p, %p\n", (void *)n1, (void *)n2); 1697 } 1698 1699 rv = fmd_fmri_contains(n1, n2); 1700 fmd_module_unlock(mp); 1701 1702 if (rv < 0) { 1703 fmd_api_error(mp, EFMD_FMRI_OP, "invalid fmri for " 1704 "fmd_nvl_fmri_contains\n"); 1705 } 1706 1707 return (rv); 1708 } 1709