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