17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 22d9638e54Smws 237c478bd9Sstevel@tonic-gate /* 2433129b33Sayznaga * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 257c478bd9Sstevel@tonic-gate * Use is subject to license terms. 267c478bd9Sstevel@tonic-gate */ 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate #include <sys/types.h> 317c478bd9Sstevel@tonic-gate #include <sys/fm/protocol.h> 32*7aec1d6eScindi #include <fm/libtopo.h> 337c478bd9Sstevel@tonic-gate 347c478bd9Sstevel@tonic-gate #include <unistd.h> 357c478bd9Sstevel@tonic-gate #include <signal.h> 367c478bd9Sstevel@tonic-gate #include <limits.h> 377c478bd9Sstevel@tonic-gate #include <syslog.h> 387c478bd9Sstevel@tonic-gate #include <alloca.h> 397c478bd9Sstevel@tonic-gate 407c478bd9Sstevel@tonic-gate #include <fmd_module.h> 417c478bd9Sstevel@tonic-gate #include <fmd_api.h> 427c478bd9Sstevel@tonic-gate #include <fmd_string.h> 437c478bd9Sstevel@tonic-gate #include <fmd_subr.h> 447c478bd9Sstevel@tonic-gate #include <fmd_error.h> 457c478bd9Sstevel@tonic-gate #include <fmd_event.h> 467c478bd9Sstevel@tonic-gate #include <fmd_eventq.h> 477c478bd9Sstevel@tonic-gate #include <fmd_dispq.h> 487c478bd9Sstevel@tonic-gate #include <fmd_timerq.h> 497c478bd9Sstevel@tonic-gate #include <fmd_thread.h> 507c478bd9Sstevel@tonic-gate #include <fmd_ustat.h> 517c478bd9Sstevel@tonic-gate #include <fmd_case.h> 527c478bd9Sstevel@tonic-gate #include <fmd_protocol.h> 537c478bd9Sstevel@tonic-gate #include <fmd_buf.h> 547c478bd9Sstevel@tonic-gate #include <fmd_asru.h> 557c478bd9Sstevel@tonic-gate #include <fmd_fmri.h> 567c478bd9Sstevel@tonic-gate #include <fmd_ckpt.h> 57d9638e54Smws #include <fmd_xprt.h> 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate #include <fmd.h> 607c478bd9Sstevel@tonic-gate 617c478bd9Sstevel@tonic-gate /* 627c478bd9Sstevel@tonic-gate * Table of configuration file variable types ops-vector pointers. We use this 637c478bd9Sstevel@tonic-gate * to convert from the property description array specified by the module to an 647c478bd9Sstevel@tonic-gate * array of fmd_conf_formal_t's. The order of this array must match the order 657c478bd9Sstevel@tonic-gate * of #define values specified in <fmd_api.h> (i.e. FMD_TYPE_BOOL must be 0). 667c478bd9Sstevel@tonic-gate * For now, the fmd_conf_list and fmd_conf_path types are not supported as we 677c478bd9Sstevel@tonic-gate * do not believe modules need them and they would require more complexity. 687c478bd9Sstevel@tonic-gate */ 697c478bd9Sstevel@tonic-gate static const fmd_conf_ops_t *const _fmd_prop_ops[] = { 707c478bd9Sstevel@tonic-gate &fmd_conf_bool, /* FMD_TYPE_BOOL */ 717c478bd9Sstevel@tonic-gate &fmd_conf_int32, /* FMD_TYPE_INT32 */ 727c478bd9Sstevel@tonic-gate &fmd_conf_uint32, /* FMD_TYPE_UINT32 */ 737c478bd9Sstevel@tonic-gate &fmd_conf_int64, /* FMD_TYPE_INT64 */ 747c478bd9Sstevel@tonic-gate &fmd_conf_uint64, /* FMD_TYPE_UINT64 */ 757c478bd9Sstevel@tonic-gate &fmd_conf_string, /* FMD_TYPE_STRING */ 767c478bd9Sstevel@tonic-gate &fmd_conf_time, /* FMD_TYPE_TIME */ 777c478bd9Sstevel@tonic-gate &fmd_conf_size, /* FMD_TYPE_SIZE */ 787c478bd9Sstevel@tonic-gate }; 797c478bd9Sstevel@tonic-gate 807c478bd9Sstevel@tonic-gate /* 817c478bd9Sstevel@tonic-gate * fmd_api_vxerror() provides the engine underlying the fmd_hdl_[v]error() API 827c478bd9Sstevel@tonic-gate * calls and the fmd_api_[v]error() utility routine defined below. The routine 837c478bd9Sstevel@tonic-gate * formats the error, optionally associated with a particular errno code 'err', 847c478bd9Sstevel@tonic-gate * and logs it as an ereport associated with the calling module. Depending on 857c478bd9Sstevel@tonic-gate * other optional properties, we also emit a message to stderr and to syslog. 867c478bd9Sstevel@tonic-gate */ 877c478bd9Sstevel@tonic-gate static void 887c478bd9Sstevel@tonic-gate fmd_api_vxerror(fmd_module_t *mp, int err, const char *format, va_list ap) 897c478bd9Sstevel@tonic-gate { 90d9638e54Smws int raw_err = err; 917c478bd9Sstevel@tonic-gate nvlist_t *nvl; 927c478bd9Sstevel@tonic-gate fmd_event_t *e; 937c478bd9Sstevel@tonic-gate char *class, *msg; 947c478bd9Sstevel@tonic-gate size_t len1, len2; 957c478bd9Sstevel@tonic-gate char c; 967c478bd9Sstevel@tonic-gate 977c478bd9Sstevel@tonic-gate /* 987c478bd9Sstevel@tonic-gate * fmd_api_vxerror() counts as both an error of class EFMD_MODULE 997c478bd9Sstevel@tonic-gate * as well as an instance of 'err' w.r.t. our internal bean counters. 1007c478bd9Sstevel@tonic-gate */ 1017c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&fmd.d_err_lock); 1027c478bd9Sstevel@tonic-gate fmd.d_errstats[EFMD_MODULE - EFMD_UNKNOWN].fmds_value.ui64++; 1037c478bd9Sstevel@tonic-gate 1047c478bd9Sstevel@tonic-gate if (err > EFMD_UNKNOWN && err < EFMD_END) 1057c478bd9Sstevel@tonic-gate fmd.d_errstats[err - EFMD_UNKNOWN].fmds_value.ui64++; 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&fmd.d_err_lock); 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate /* 1107c478bd9Sstevel@tonic-gate * Format the message using vsnprintf(). As usual, if the format has a 1117c478bd9Sstevel@tonic-gate * newline in it, it is printed alone; otherwise strerror() is added. 1127c478bd9Sstevel@tonic-gate */ 1137c478bd9Sstevel@tonic-gate if (strchr(format, '\n') != NULL) 1147c478bd9Sstevel@tonic-gate err = 0; /* err is not relevant in the message */ 1157c478bd9Sstevel@tonic-gate 1167c478bd9Sstevel@tonic-gate len1 = vsnprintf(&c, 1, format, ap); 1177c478bd9Sstevel@tonic-gate len2 = err != 0 ? snprintf(&c, 1, ": %s\n", fmd_strerror(err)) : 0; 1187c478bd9Sstevel@tonic-gate 1197c478bd9Sstevel@tonic-gate msg = fmd_alloc(len1 + len2 + 1, FMD_SLEEP); 1207c478bd9Sstevel@tonic-gate (void) vsnprintf(msg, len1 + 1, format, ap); 1217c478bd9Sstevel@tonic-gate 1227c478bd9Sstevel@tonic-gate if (err != 0) { 1237c478bd9Sstevel@tonic-gate (void) snprintf(&msg[len1], len2 + 1, 1247c478bd9Sstevel@tonic-gate ": %s\n", fmd_strerror(err)); 1257c478bd9Sstevel@tonic-gate } 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate /* 1287c478bd9Sstevel@tonic-gate * Create an error event corresponding to the error, insert it into the 1297c478bd9Sstevel@tonic-gate * error log, and dispatch it to the fmd-self-diagnosis engine. 1307c478bd9Sstevel@tonic-gate */ 131d9638e54Smws if (mp != fmd.d_self && (raw_err != EFMD_HDL_ABORT || fmd.d_running)) { 1327c478bd9Sstevel@tonic-gate if ((c = msg[len1 + len2 - 1]) == '\n') 1337c478bd9Sstevel@tonic-gate msg[len1 + len2 - 1] = '\0'; /* strip \n for event */ 1347c478bd9Sstevel@tonic-gate 1357c478bd9Sstevel@tonic-gate nvl = fmd_protocol_moderror(mp, err, msg); 1367c478bd9Sstevel@tonic-gate 1377c478bd9Sstevel@tonic-gate if (c == '\n') 1387c478bd9Sstevel@tonic-gate msg[len1 + len2 - 1] = c; 1397c478bd9Sstevel@tonic-gate 1407c478bd9Sstevel@tonic-gate (void) nvlist_lookup_string(nvl, FM_CLASS, &class); 1417c478bd9Sstevel@tonic-gate e = fmd_event_create(FMD_EVT_PROTOCOL, FMD_HRT_NOW, nvl, class); 1427c478bd9Sstevel@tonic-gate 1437c478bd9Sstevel@tonic-gate (void) pthread_rwlock_rdlock(&fmd.d_log_lock); 1447c478bd9Sstevel@tonic-gate fmd_log_append(fmd.d_errlog, e, NULL); 1457c478bd9Sstevel@tonic-gate (void) pthread_rwlock_unlock(&fmd.d_log_lock); 1467c478bd9Sstevel@tonic-gate 1477c478bd9Sstevel@tonic-gate fmd_event_transition(e, FMD_EVS_ACCEPTED); 1487c478bd9Sstevel@tonic-gate fmd_event_commit(e); 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate fmd_dispq_dispatch(fmd.d_disp, e, class); 1517c478bd9Sstevel@tonic-gate } 1527c478bd9Sstevel@tonic-gate 1537c478bd9Sstevel@tonic-gate /* 1547c478bd9Sstevel@tonic-gate * Similar to fmd_vdebug(), if the debugging switches are enabled we 1557c478bd9Sstevel@tonic-gate * echo the module name and message to stderr and/or syslog. Unlike 1567c478bd9Sstevel@tonic-gate * fmd_vdebug(), we also print to stderr if foreground mode is enabled. 157d9638e54Smws * We also print the message if a built-in module is aborting before 158d9638e54Smws * fmd has detached from its parent (e.g. default transport failure). 1597c478bd9Sstevel@tonic-gate */ 160d9638e54Smws if (fmd.d_fg || (fmd.d_hdl_dbout & FMD_DBOUT_STDERR) || ( 161d9638e54Smws raw_err == EFMD_HDL_ABORT && !fmd.d_running)) { 1627c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&fmd.d_err_lock); 1637c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: %s: %s", 1647c478bd9Sstevel@tonic-gate fmd.d_pname, mp->mod_name, msg); 1657c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&fmd.d_err_lock); 1667c478bd9Sstevel@tonic-gate } 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate if (fmd.d_hdl_dbout & FMD_DBOUT_SYSLOG) { 1697c478bd9Sstevel@tonic-gate syslog(LOG_ERR | LOG_DAEMON, "%s ERROR: %s: %s", 1707c478bd9Sstevel@tonic-gate fmd.d_pname, mp->mod_name, msg); 1717c478bd9Sstevel@tonic-gate } 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate fmd_free(msg, len1 + len2 + 1); 1747c478bd9Sstevel@tonic-gate } 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate /*PRINTFLIKE3*/ 1777c478bd9Sstevel@tonic-gate static void 1787c478bd9Sstevel@tonic-gate fmd_api_xerror(fmd_module_t *mp, int err, const char *format, ...) 1797c478bd9Sstevel@tonic-gate { 1807c478bd9Sstevel@tonic-gate va_list ap; 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate va_start(ap, format); 1837c478bd9Sstevel@tonic-gate fmd_api_vxerror(mp, err, format, ap); 1847c478bd9Sstevel@tonic-gate va_end(ap); 1857c478bd9Sstevel@tonic-gate } 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate /* 1887c478bd9Sstevel@tonic-gate * fmd_api_verror() is a wrapper around fmd_api_vxerror() for API subroutines. 1897c478bd9Sstevel@tonic-gate * It calls fmd_module_unlock() on behalf of its caller, logs the error, and 1907c478bd9Sstevel@tonic-gate * then aborts the API call and the surrounding module entry point by doing an 1917c478bd9Sstevel@tonic-gate * fmd_module_abort(), which longjmps to the place where we entered the module. 1927c478bd9Sstevel@tonic-gate */ 1937c478bd9Sstevel@tonic-gate static void 1947c478bd9Sstevel@tonic-gate fmd_api_verror(fmd_module_t *mp, int err, const char *format, va_list ap) 1957c478bd9Sstevel@tonic-gate { 1967c478bd9Sstevel@tonic-gate if (fmd_module_locked(mp)) 1977c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate fmd_api_vxerror(mp, err, format, ap); 2007c478bd9Sstevel@tonic-gate fmd_module_abort(mp, err); 2017c478bd9Sstevel@tonic-gate } 2027c478bd9Sstevel@tonic-gate 2037c478bd9Sstevel@tonic-gate /*PRINTFLIKE3*/ 2047c478bd9Sstevel@tonic-gate static void 2057c478bd9Sstevel@tonic-gate fmd_api_error(fmd_module_t *mp, int err, const char *format, ...) 2067c478bd9Sstevel@tonic-gate { 2077c478bd9Sstevel@tonic-gate va_list ap; 2087c478bd9Sstevel@tonic-gate 2097c478bd9Sstevel@tonic-gate va_start(ap, format); 2107c478bd9Sstevel@tonic-gate fmd_api_verror(mp, err, format, ap); 2117c478bd9Sstevel@tonic-gate va_end(ap); 2127c478bd9Sstevel@tonic-gate } 2137c478bd9Sstevel@tonic-gate 2147c478bd9Sstevel@tonic-gate /* 215d9638e54Smws * Common code for fmd_api_module_lock() and fmd_api_transport_impl(). This 216d9638e54Smws * code verifies that the handle is valid and associated with a proper thread. 2177c478bd9Sstevel@tonic-gate */ 2187c478bd9Sstevel@tonic-gate static fmd_module_t * 219d9638e54Smws fmd_api_module(fmd_hdl_t *hdl) 2207c478bd9Sstevel@tonic-gate { 2217c478bd9Sstevel@tonic-gate fmd_thread_t *tp; 2227c478bd9Sstevel@tonic-gate fmd_module_t *mp; 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate /* 2257c478bd9Sstevel@tonic-gate * If our TSD is not present at all, this is either a serious bug or 2267c478bd9Sstevel@tonic-gate * someone has created a thread behind our back and is using fmd's API. 2277c478bd9Sstevel@tonic-gate * We can't call fmd_api_error() because we can't be sure that we can 2287c478bd9Sstevel@tonic-gate * unwind our state back to an enclosing fmd_module_dispatch(), so we 2297c478bd9Sstevel@tonic-gate * must panic instead. This is likely a module design or coding error. 2307c478bd9Sstevel@tonic-gate */ 2317c478bd9Sstevel@tonic-gate if ((tp = pthread_getspecific(fmd.d_key)) == NULL) { 2327c478bd9Sstevel@tonic-gate fmd_panic("fmd module api call made using " 2337c478bd9Sstevel@tonic-gate "client handle %p from unknown thread\n", (void *)hdl); 2347c478bd9Sstevel@tonic-gate } 2357c478bd9Sstevel@tonic-gate 236d9638e54Smws /* 237d9638e54Smws * If our TSD refers to the root module and is a door server thread, 238d9638e54Smws * then it was created asynchronously at the request of a module but 239d9638e54Smws * is using now the module API as an auxiliary module thread. We reset 240d9638e54Smws * tp->thr_mod to the module handle so it can act as a module thread. 241d9638e54Smws */ 242d9638e54Smws if (tp->thr_mod == fmd.d_rmod && tp->thr_func == &fmd_door_server) 243d9638e54Smws tp->thr_mod = (fmd_module_t *)hdl; 244d9638e54Smws 2457c478bd9Sstevel@tonic-gate if ((mp = tp->thr_mod) != (fmd_module_t *)hdl) { 2467c478bd9Sstevel@tonic-gate fmd_api_error(mp, EFMD_HDL_INVAL, 2477c478bd9Sstevel@tonic-gate "client handle %p is not valid\n", (void *)hdl); 2487c478bd9Sstevel@tonic-gate } 2497c478bd9Sstevel@tonic-gate 2507c478bd9Sstevel@tonic-gate if (mp->mod_flags & FMD_MOD_FAIL) { 2517c478bd9Sstevel@tonic-gate fmd_api_error(mp, EFMD_MOD_FAIL, 2527c478bd9Sstevel@tonic-gate "module has experienced an unrecoverable error\n"); 2537c478bd9Sstevel@tonic-gate } 2547c478bd9Sstevel@tonic-gate 255d9638e54Smws return (mp); 256d9638e54Smws } 257d9638e54Smws 258d9638e54Smws /* 259d9638e54Smws * fmd_api_module_lock() is used as a wrapper around fmd_module_lock() and a 260d9638e54Smws * common prologue to each fmd_api.c routine. It verifies that the handle is 261d9638e54Smws * valid and owned by the current server thread, locks the handle, and then 262d9638e54Smws * verifies that the caller is performing an operation on a registered handle. 263d9638e54Smws * If any tests fail, the entire API call is aborted by fmd_api_error(). 264d9638e54Smws */ 265d9638e54Smws static fmd_module_t * 266d9638e54Smws fmd_api_module_lock(fmd_hdl_t *hdl) 267d9638e54Smws { 268d9638e54Smws fmd_module_t *mp = fmd_api_module(hdl); 269d9638e54Smws 2707c478bd9Sstevel@tonic-gate fmd_module_lock(mp); 2717c478bd9Sstevel@tonic-gate 2727c478bd9Sstevel@tonic-gate if (mp->mod_info == NULL) { 2737c478bd9Sstevel@tonic-gate fmd_api_error(mp, EFMD_HDL_NOTREG, 2747c478bd9Sstevel@tonic-gate "client handle %p has not been registered\n", (void *)hdl); 2757c478bd9Sstevel@tonic-gate } 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate return (mp); 2787c478bd9Sstevel@tonic-gate } 2797c478bd9Sstevel@tonic-gate 2807c478bd9Sstevel@tonic-gate /* 2817c478bd9Sstevel@tonic-gate * Utility function for API entry points that accept fmd_case_t's. We cast cp 2827c478bd9Sstevel@tonic-gate * to fmd_case_impl_t and check to make sure the case is owned by the caller. 2837c478bd9Sstevel@tonic-gate */ 2847c478bd9Sstevel@tonic-gate static fmd_case_impl_t * 2857c478bd9Sstevel@tonic-gate fmd_api_case_impl(fmd_module_t *mp, fmd_case_t *cp) 2867c478bd9Sstevel@tonic-gate { 2877c478bd9Sstevel@tonic-gate fmd_case_impl_t *cip = (fmd_case_impl_t *)cp; 2887c478bd9Sstevel@tonic-gate 2897c478bd9Sstevel@tonic-gate if (cip == NULL || cip->ci_mod != mp) { 2907c478bd9Sstevel@tonic-gate fmd_api_error(mp, EFMD_CASE_OWNER, 291d9638e54Smws "case %p is invalid or not owned by caller\n", (void *)cip); 2927c478bd9Sstevel@tonic-gate } 2937c478bd9Sstevel@tonic-gate 2947c478bd9Sstevel@tonic-gate return (cip); 2957c478bd9Sstevel@tonic-gate } 2967c478bd9Sstevel@tonic-gate 2977c478bd9Sstevel@tonic-gate /* 298d9638e54Smws * Utility function for API entry points that accept fmd_xprt_t's. We cast xp 299d9638e54Smws * to fmd_transport_t and check to make sure the case is owned by the caller. 300d9638e54Smws * Note that we could make this check safer by actually walking mp's transport 301d9638e54Smws * list, but that requires holding the module lock and this routine needs to be 302d9638e54Smws * MT-hot w.r.t. auxiliary module threads. Ultimately any loadable module can 303d9638e54Smws * cause us to crash anyway, so we optimize for scalability over safety here. 304d9638e54Smws */ 305d9638e54Smws static fmd_xprt_impl_t * 306d9638e54Smws fmd_api_transport_impl(fmd_hdl_t *hdl, fmd_xprt_t *xp) 307d9638e54Smws { 308d9638e54Smws fmd_module_t *mp = fmd_api_module(hdl); 309d9638e54Smws fmd_xprt_impl_t *xip = (fmd_xprt_impl_t *)xp; 310d9638e54Smws 311d9638e54Smws if (xip == NULL || xip->xi_queue->eq_mod != mp) { 312d9638e54Smws fmd_api_error(mp, EFMD_XPRT_OWNER, 313d9638e54Smws "xprt %p is invalid or not owned by caller\n", (void *)xp); 314d9638e54Smws } 315d9638e54Smws 316d9638e54Smws return (xip); 317d9638e54Smws } 318d9638e54Smws 319d9638e54Smws /* 3207c478bd9Sstevel@tonic-gate * fmd_hdl_register() is the one function which cannot use fmd_api_error() to 3217c478bd9Sstevel@tonic-gate * report errors, because that routine causes the module to abort. Failure to 3227c478bd9Sstevel@tonic-gate * register is instead handled by having fmd_hdl_register() return an error to 3237c478bd9Sstevel@tonic-gate * the _fmd_init() function and then detecting no registration when it returns. 3247c478bd9Sstevel@tonic-gate * So we use this routine for fmd_hdl_register() error paths instead. 3257c478bd9Sstevel@tonic-gate */ 3267c478bd9Sstevel@tonic-gate static int 3277c478bd9Sstevel@tonic-gate fmd_hdl_register_error(fmd_module_t *mp, int err) 3287c478bd9Sstevel@tonic-gate { 3297c478bd9Sstevel@tonic-gate if (fmd_module_locked(mp)) 3307c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate fmd_api_xerror(mp, err, "failed to register"); 3337c478bd9Sstevel@tonic-gate return (fmd_set_errno(err)); 3347c478bd9Sstevel@tonic-gate } 3357c478bd9Sstevel@tonic-gate 3367c478bd9Sstevel@tonic-gate static void 3377c478bd9Sstevel@tonic-gate fmd_hdl_nop(void) 3387c478bd9Sstevel@tonic-gate { 3397c478bd9Sstevel@tonic-gate /* empty function for use with unspecified module entry points */ 3407c478bd9Sstevel@tonic-gate } 3417c478bd9Sstevel@tonic-gate 3427c478bd9Sstevel@tonic-gate int 3437c478bd9Sstevel@tonic-gate fmd_hdl_register(fmd_hdl_t *hdl, int version, const fmd_hdl_info_t *mip) 3447c478bd9Sstevel@tonic-gate { 3457c478bd9Sstevel@tonic-gate fmd_thread_t *tp = pthread_getspecific(fmd.d_key); 3467c478bd9Sstevel@tonic-gate fmd_module_t *mp = tp->thr_mod; 3477c478bd9Sstevel@tonic-gate 3487c478bd9Sstevel@tonic-gate const fmd_prop_t *prop; 3497c478bd9Sstevel@tonic-gate const fmd_conf_path_t *pap; 3507c478bd9Sstevel@tonic-gate fmd_conf_formal_t *cfp; 351d9638e54Smws fmd_hdl_ops_t ops; 3527c478bd9Sstevel@tonic-gate 3537c478bd9Sstevel@tonic-gate const char *conf = NULL; 3547c478bd9Sstevel@tonic-gate char buf[PATH_MAX]; 3557c478bd9Sstevel@tonic-gate int i; 3567c478bd9Sstevel@tonic-gate 3577c478bd9Sstevel@tonic-gate if (mp != (fmd_module_t *)hdl) 3587c478bd9Sstevel@tonic-gate return (fmd_hdl_register_error(mp, EFMD_HDL_INVAL)); 3597c478bd9Sstevel@tonic-gate 3607c478bd9Sstevel@tonic-gate fmd_module_lock(mp); 3617c478bd9Sstevel@tonic-gate 3627c478bd9Sstevel@tonic-gate /* 3637c478bd9Sstevel@tonic-gate * First perform some sanity checks on our input. The API version must 3647c478bd9Sstevel@tonic-gate * be supported by FMD and the handle can only be registered once by 3657c478bd9Sstevel@tonic-gate * the module thread to which we assigned this client handle. The info 3667c478bd9Sstevel@tonic-gate * provided for the handle must be valid and have the minimal settings. 3677c478bd9Sstevel@tonic-gate */ 368d9638e54Smws if (version > FMD_API_VERSION_3) 3697c478bd9Sstevel@tonic-gate return (fmd_hdl_register_error(mp, EFMD_VER_NEW)); 3707c478bd9Sstevel@tonic-gate 3717c478bd9Sstevel@tonic-gate if (version < FMD_API_VERSION_1) 3727c478bd9Sstevel@tonic-gate return (fmd_hdl_register_error(mp, EFMD_VER_OLD)); 3737c478bd9Sstevel@tonic-gate 3747c478bd9Sstevel@tonic-gate if (mp->mod_conf != NULL) 3757c478bd9Sstevel@tonic-gate return (fmd_hdl_register_error(mp, EFMD_HDL_REG)); 3767c478bd9Sstevel@tonic-gate 3777c478bd9Sstevel@tonic-gate if (pthread_self() != mp->mod_thread->thr_tid) 3787c478bd9Sstevel@tonic-gate return (fmd_hdl_register_error(mp, EFMD_HDL_TID)); 3797c478bd9Sstevel@tonic-gate 380d9638e54Smws if (mip == NULL || mip->fmdi_desc == NULL || 381d9638e54Smws mip->fmdi_vers == NULL || mip->fmdi_ops == NULL) 3827c478bd9Sstevel@tonic-gate return (fmd_hdl_register_error(mp, EFMD_HDL_INFO)); 3837c478bd9Sstevel@tonic-gate 3847c478bd9Sstevel@tonic-gate /* 385d9638e54Smws * Copy the module's ops vector into a local variable to account for 386d9638e54Smws * changes in the module ABI. Then if any of the optional entry points 387d9638e54Smws * are NULL, set them to nop so we don't have to check before calling. 388d9638e54Smws */ 389d9638e54Smws bzero(&ops, sizeof (ops)); 390d9638e54Smws 391d9638e54Smws if (version < FMD_API_VERSION_3) 392d9638e54Smws bcopy(mip->fmdi_ops, &ops, sizeof (ops) - sizeof (void *)); 393d9638e54Smws else 394d9638e54Smws bcopy(mip->fmdi_ops, &ops, sizeof (ops)); 395d9638e54Smws 396d9638e54Smws if (ops.fmdo_recv == NULL) 397d9638e54Smws ops.fmdo_recv = (void (*)())fmd_hdl_nop; 398d9638e54Smws if (ops.fmdo_timeout == NULL) 399d9638e54Smws ops.fmdo_timeout = (void (*)())fmd_hdl_nop; 400d9638e54Smws if (ops.fmdo_close == NULL) 401d9638e54Smws ops.fmdo_close = (void (*)())fmd_hdl_nop; 402d9638e54Smws if (ops.fmdo_stats == NULL) 403d9638e54Smws ops.fmdo_stats = (void (*)())fmd_hdl_nop; 404d9638e54Smws if (ops.fmdo_gc == NULL) 405d9638e54Smws ops.fmdo_gc = (void (*)())fmd_hdl_nop; 406d9638e54Smws if (ops.fmdo_send == NULL) 407d9638e54Smws ops.fmdo_send = (int (*)())fmd_hdl_nop; 408d9638e54Smws 409d9638e54Smws /* 4107c478bd9Sstevel@tonic-gate * Make two passes through the property array to initialize the formals 4117c478bd9Sstevel@tonic-gate * to use for processing the module's .conf file. In the first pass, 4127c478bd9Sstevel@tonic-gate * we validate the types and count the number of properties. In the 4137c478bd9Sstevel@tonic-gate * second pass we copy the strings and fill in the appropriate ops. 4147c478bd9Sstevel@tonic-gate */ 4157c478bd9Sstevel@tonic-gate for (prop = mip->fmdi_props, i = 0; prop != NULL && 4167c478bd9Sstevel@tonic-gate prop->fmdp_name != NULL; prop++, i++) { 4177c478bd9Sstevel@tonic-gate if (prop->fmdp_type >= 4187c478bd9Sstevel@tonic-gate sizeof (_fmd_prop_ops) / sizeof (_fmd_prop_ops[0])) { 4197c478bd9Sstevel@tonic-gate fmd_api_xerror(mp, EFMD_HDL_PROP, 4207c478bd9Sstevel@tonic-gate "property %s uses invalid type %u\n", 4217c478bd9Sstevel@tonic-gate prop->fmdp_name, prop->fmdp_type); 4227c478bd9Sstevel@tonic-gate return (fmd_hdl_register_error(mp, EFMD_HDL_PROP)); 4237c478bd9Sstevel@tonic-gate } 4247c478bd9Sstevel@tonic-gate } 4257c478bd9Sstevel@tonic-gate 4267c478bd9Sstevel@tonic-gate mp->mod_argc = i; 4277c478bd9Sstevel@tonic-gate mp->mod_argv = fmd_zalloc(sizeof (fmd_conf_formal_t) * i, FMD_SLEEP); 4287c478bd9Sstevel@tonic-gate 4297c478bd9Sstevel@tonic-gate prop = mip->fmdi_props; 4307c478bd9Sstevel@tonic-gate cfp = mp->mod_argv; 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate for (i = 0; i < mp->mod_argc; i++, prop++, cfp++) { 4337c478bd9Sstevel@tonic-gate cfp->cf_name = fmd_strdup(prop->fmdp_name, FMD_SLEEP); 4347c478bd9Sstevel@tonic-gate cfp->cf_ops = _fmd_prop_ops[prop->fmdp_type]; 4357c478bd9Sstevel@tonic-gate cfp->cf_default = fmd_strdup(prop->fmdp_defv, FMD_SLEEP); 4367c478bd9Sstevel@tonic-gate } 4377c478bd9Sstevel@tonic-gate 4387c478bd9Sstevel@tonic-gate /* 4397c478bd9Sstevel@tonic-gate * If this module came from an on-disk file, compute the name of the 4407c478bd9Sstevel@tonic-gate * corresponding .conf file and parse properties from it if it exists. 4417c478bd9Sstevel@tonic-gate */ 4427c478bd9Sstevel@tonic-gate if (mp->mod_path != NULL) { 4437c478bd9Sstevel@tonic-gate (void) strlcpy(buf, mp->mod_path, sizeof (buf)); 4447c478bd9Sstevel@tonic-gate (void) fmd_strdirname(buf); 4457c478bd9Sstevel@tonic-gate 4467c478bd9Sstevel@tonic-gate (void) strlcat(buf, "/", sizeof (buf)); 4477c478bd9Sstevel@tonic-gate (void) strlcat(buf, mp->mod_name, sizeof (buf)); 4487c478bd9Sstevel@tonic-gate (void) strlcat(buf, ".conf", sizeof (buf)); 4497c478bd9Sstevel@tonic-gate 4507c478bd9Sstevel@tonic-gate if (access(buf, F_OK) == 0) 4517c478bd9Sstevel@tonic-gate conf = buf; 4527c478bd9Sstevel@tonic-gate } 4537c478bd9Sstevel@tonic-gate 4547c478bd9Sstevel@tonic-gate if ((mp->mod_conf = fmd_conf_open(conf, 455d9638e54Smws mp->mod_argc, mp->mod_argv, 0)) == NULL) 4567c478bd9Sstevel@tonic-gate return (fmd_hdl_register_error(mp, EFMD_MOD_CONF)); 4577c478bd9Sstevel@tonic-gate 458d9638e54Smws fmd_conf_propagate(fmd.d_conf, mp->mod_conf, mp->mod_name); 459d9638e54Smws 4607c478bd9Sstevel@tonic-gate /* 4617c478bd9Sstevel@tonic-gate * Look up the list of the libdiagcode dictionaries associated with the 4627c478bd9Sstevel@tonic-gate * module. If none were specified, use the value from daemon's config. 4637c478bd9Sstevel@tonic-gate * We only fail if the module specified an explicit dictionary. 4647c478bd9Sstevel@tonic-gate */ 4657c478bd9Sstevel@tonic-gate (void) fmd_conf_getprop(mp->mod_conf, FMD_PROP_DICTIONARIES, &pap); 4667c478bd9Sstevel@tonic-gate if (pap->cpa_argc == 0 && mp->mod_ops == &fmd_bltin_ops) 4677c478bd9Sstevel@tonic-gate (void) fmd_conf_getprop(fmd.d_conf, "self.dict", &pap); 4687c478bd9Sstevel@tonic-gate 4697c478bd9Sstevel@tonic-gate for (i = 0; i < pap->cpa_argc; i++) { 4707c478bd9Sstevel@tonic-gate if (fmd_module_dc_opendict(mp, pap->cpa_argv[i]) != 0) { 4717c478bd9Sstevel@tonic-gate fmd_api_xerror(mp, errno, 4727c478bd9Sstevel@tonic-gate "failed to open dictionary %s", pap->cpa_argv[i]); 4737c478bd9Sstevel@tonic-gate return (fmd_hdl_register_error(mp, EFMD_MOD_CONF)); 4747c478bd9Sstevel@tonic-gate } 4757c478bd9Sstevel@tonic-gate } 4767c478bd9Sstevel@tonic-gate 4777c478bd9Sstevel@tonic-gate /* 4787c478bd9Sstevel@tonic-gate * Make a copy of the handle information and store it in mod_info. We 4797c478bd9Sstevel@tonic-gate * do not need to bother copying fmdi_props since they're already read. 4807c478bd9Sstevel@tonic-gate */ 4817c478bd9Sstevel@tonic-gate mp->mod_info = fmd_alloc(sizeof (fmd_hdl_info_t), FMD_SLEEP); 4827c478bd9Sstevel@tonic-gate mp->mod_info->fmdi_desc = fmd_strdup(mip->fmdi_desc, FMD_SLEEP); 4837c478bd9Sstevel@tonic-gate mp->mod_info->fmdi_vers = fmd_strdup(mip->fmdi_vers, FMD_SLEEP); 4847c478bd9Sstevel@tonic-gate mp->mod_info->fmdi_ops = fmd_alloc(sizeof (fmd_hdl_ops_t), FMD_SLEEP); 485d9638e54Smws bcopy(&ops, (void *)mp->mod_info->fmdi_ops, sizeof (fmd_hdl_ops_t)); 4867c478bd9Sstevel@tonic-gate mp->mod_info->fmdi_props = NULL; 4877c478bd9Sstevel@tonic-gate 4887c478bd9Sstevel@tonic-gate /* 4897c478bd9Sstevel@tonic-gate * Allocate an FMRI representing this module. We'll use this later 4907c478bd9Sstevel@tonic-gate * if the module decides to publish any events (e.g. list.suspects). 4917c478bd9Sstevel@tonic-gate */ 4927c478bd9Sstevel@tonic-gate mp->mod_fmri = fmd_protocol_fmri_module(mp); 4937c478bd9Sstevel@tonic-gate 4947c478bd9Sstevel@tonic-gate /* 4957c478bd9Sstevel@tonic-gate * Any subscriptions specified in the conf file are now stored in the 4967c478bd9Sstevel@tonic-gate * corresponding property. Add all of these to the dispatch queue. 4977c478bd9Sstevel@tonic-gate */ 4987c478bd9Sstevel@tonic-gate (void) fmd_conf_getprop(mp->mod_conf, FMD_PROP_SUBSCRIPTIONS, &pap); 4997c478bd9Sstevel@tonic-gate 500d9638e54Smws for (i = 0; i < pap->cpa_argc; i++) { 501d9638e54Smws fmd_dispq_insert(fmd.d_disp, mp->mod_queue, pap->cpa_argv[i]); 502d9638e54Smws fmd_xprt_subscribe_all(pap->cpa_argv[i]); 503d9638e54Smws } 5047c478bd9Sstevel@tonic-gate 5057c478bd9Sstevel@tonic-gate /* 5067c478bd9Sstevel@tonic-gate * Unlock the module and restore any pre-existing module checkpoint. 5077c478bd9Sstevel@tonic-gate * If the checkpoint is missing or corrupt, we just keep going. 5087c478bd9Sstevel@tonic-gate */ 5097c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 5107c478bd9Sstevel@tonic-gate fmd_ckpt_restore(mp); 5117c478bd9Sstevel@tonic-gate return (0); 5127c478bd9Sstevel@tonic-gate } 5137c478bd9Sstevel@tonic-gate 514d9638e54Smws /* 515d9638e54Smws * If an auxiliary thread exists for the specified module at unregistration 516d9638e54Smws * time, send it an asynchronous cancellation to force it to exit and then 517d9638e54Smws * join with it (we expect this to either succeed quickly or return ESRCH). 518d9638e54Smws * Once this is complete we can destroy the associated fmd_thread_t data. 519d9638e54Smws */ 520d9638e54Smws static void 521d9638e54Smws fmd_module_thrcancel(fmd_idspace_t *ids, id_t id, fmd_module_t *mp) 522d9638e54Smws { 523d9638e54Smws fmd_thread_t *tp = fmd_idspace_getspecific(ids, id); 524d9638e54Smws 525d9638e54Smws fmd_dprintf(FMD_DBG_MOD, "cancelling %s auxiliary thread %u\n", 526d9638e54Smws mp->mod_name, tp->thr_tid); 527d9638e54Smws 528d9638e54Smws ASSERT(tp->thr_tid == id); 529d9638e54Smws (void) pthread_cancel(tp->thr_tid); 530d9638e54Smws (void) pthread_join(tp->thr_tid, NULL); 531d9638e54Smws 532d9638e54Smws fmd_thread_destroy(tp, FMD_THREAD_NOJOIN); 533d9638e54Smws } 534d9638e54Smws 5357c478bd9Sstevel@tonic-gate void 5367c478bd9Sstevel@tonic-gate fmd_module_unregister(fmd_module_t *mp) 5377c478bd9Sstevel@tonic-gate { 5387c478bd9Sstevel@tonic-gate fmd_conf_formal_t *cfp = mp->mod_argv; 5397c478bd9Sstevel@tonic-gate const fmd_conf_path_t *pap; 540d9638e54Smws fmd_case_t *cp; 541d9638e54Smws fmd_xprt_t *xp; 5427c478bd9Sstevel@tonic-gate int i; 5437c478bd9Sstevel@tonic-gate 5447c478bd9Sstevel@tonic-gate TRACE((FMD_DBG_MOD, "unregister %p (%s)", (void *)mp, mp->mod_name)); 5457c478bd9Sstevel@tonic-gate ASSERT(fmd_module_locked(mp)); 5467c478bd9Sstevel@tonic-gate 547d9638e54Smws /* 548d9638e54Smws * If any transports are still open, they have send threads that are 549d9638e54Smws * using the module handle: shut them down and join with these threads. 550d9638e54Smws */ 551d9638e54Smws while ((xp = fmd_list_next(&mp->mod_transports)) != NULL) 552d9638e54Smws fmd_xprt_destroy(xp); 553d9638e54Smws 554d9638e54Smws /* 555d9638e54Smws * If any auxiliary threads exist, they may be using our module handle, 556d9638e54Smws * and therefore could cause a fault as soon as we start destroying it. 557d9638e54Smws * Module writers should clean up any threads before unregistering: we 558d9638e54Smws * forcibly cancel any remaining auxiliary threads before proceeding. 559d9638e54Smws */ 560d9638e54Smws fmd_idspace_apply(mp->mod_threads, 561d9638e54Smws (void (*)())fmd_module_thrcancel, mp); 562d9638e54Smws 56333129b33Sayznaga if (mp->mod_error == 0) 56433129b33Sayznaga fmd_ckpt_save(mp); /* take one more checkpoint if needed */ 56533129b33Sayznaga 566d9638e54Smws /* 567d9638e54Smws * Delete any cases associated with the module (UNSOLVED, SOLVED, or 568d9638e54Smws * CLOSE_WAIT) as if fmdo_close() has finished processing them. 569d9638e54Smws */ 570d9638e54Smws while ((cp = fmd_list_next(&mp->mod_cases)) != NULL) 571d9638e54Smws fmd_case_delete(cp); 572d9638e54Smws 573d9638e54Smws fmd_ustat_delete_references(mp->mod_ustat); 5747c478bd9Sstevel@tonic-gate (void) fmd_conf_getprop(mp->mod_conf, FMD_PROP_SUBSCRIPTIONS, &pap); 5757c478bd9Sstevel@tonic-gate 576d9638e54Smws for (i = 0; i < pap->cpa_argc; i++) { 577d9638e54Smws fmd_xprt_unsubscribe_all(pap->cpa_argv[i]); 578d9638e54Smws fmd_dispq_delete(fmd.d_disp, mp->mod_queue, pap->cpa_argv[i]); 5797c478bd9Sstevel@tonic-gate } 5807c478bd9Sstevel@tonic-gate 5817c478bd9Sstevel@tonic-gate fmd_conf_close(mp->mod_conf); 5827c478bd9Sstevel@tonic-gate mp->mod_conf = NULL; 5837c478bd9Sstevel@tonic-gate 5847c478bd9Sstevel@tonic-gate for (i = 0; i < mp->mod_argc; i++, cfp++) { 5857c478bd9Sstevel@tonic-gate fmd_strfree((char *)cfp->cf_name); 5867c478bd9Sstevel@tonic-gate fmd_strfree((char *)cfp->cf_default); 5877c478bd9Sstevel@tonic-gate } 5887c478bd9Sstevel@tonic-gate 5897c478bd9Sstevel@tonic-gate fmd_free(mp->mod_argv, sizeof (fmd_conf_formal_t) * mp->mod_argc); 5907c478bd9Sstevel@tonic-gate mp->mod_argv = NULL; 5917c478bd9Sstevel@tonic-gate mp->mod_argc = 0; 5927c478bd9Sstevel@tonic-gate 5937c478bd9Sstevel@tonic-gate nvlist_free(mp->mod_fmri); 5947c478bd9Sstevel@tonic-gate mp->mod_fmri = NULL; 5957c478bd9Sstevel@tonic-gate 5967c478bd9Sstevel@tonic-gate fmd_strfree((char *)mp->mod_info->fmdi_desc); 5977c478bd9Sstevel@tonic-gate fmd_strfree((char *)mp->mod_info->fmdi_vers); 5987c478bd9Sstevel@tonic-gate fmd_free((void *)mp->mod_info->fmdi_ops, sizeof (fmd_hdl_ops_t)); 5997c478bd9Sstevel@tonic-gate fmd_free(mp->mod_info, sizeof (fmd_hdl_info_t)); 6007c478bd9Sstevel@tonic-gate mp->mod_info = NULL; 6017c478bd9Sstevel@tonic-gate 6027c478bd9Sstevel@tonic-gate fmd_eventq_abort(mp->mod_queue); 6037c478bd9Sstevel@tonic-gate } 6047c478bd9Sstevel@tonic-gate 6057c478bd9Sstevel@tonic-gate void 6067c478bd9Sstevel@tonic-gate fmd_hdl_unregister(fmd_hdl_t *hdl) 6077c478bd9Sstevel@tonic-gate { 6087c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 6097c478bd9Sstevel@tonic-gate fmd_module_unregister(mp); 6107c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 6117c478bd9Sstevel@tonic-gate } 6127c478bd9Sstevel@tonic-gate 6137c478bd9Sstevel@tonic-gate void 6147c478bd9Sstevel@tonic-gate fmd_hdl_subscribe(fmd_hdl_t *hdl, const char *class) 6157c478bd9Sstevel@tonic-gate { 6167c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 6177c478bd9Sstevel@tonic-gate 618d9638e54Smws if (fmd_conf_setprop(mp->mod_conf, 619d9638e54Smws FMD_PROP_SUBSCRIPTIONS, class) == 0) { 620d9638e54Smws fmd_dispq_insert(fmd.d_disp, mp->mod_queue, class); 621d9638e54Smws fmd_xprt_subscribe_all(class); 622d9638e54Smws } 6237c478bd9Sstevel@tonic-gate 6247c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 6257c478bd9Sstevel@tonic-gate } 6267c478bd9Sstevel@tonic-gate 627d9638e54Smws 6287c478bd9Sstevel@tonic-gate void 6297c478bd9Sstevel@tonic-gate fmd_hdl_unsubscribe(fmd_hdl_t *hdl, const char *class) 6307c478bd9Sstevel@tonic-gate { 6317c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 6327c478bd9Sstevel@tonic-gate 633d9638e54Smws if (fmd_conf_delprop(mp->mod_conf, 634d9638e54Smws FMD_PROP_SUBSCRIPTIONS, class) == 0) { 635d9638e54Smws fmd_xprt_unsubscribe_all(class); 636d9638e54Smws fmd_dispq_delete(fmd.d_disp, mp->mod_queue, class); 637d9638e54Smws } 6387c478bd9Sstevel@tonic-gate 6397c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 6407c478bd9Sstevel@tonic-gate fmd_eventq_cancel(mp->mod_queue, FMD_EVT_PROTOCOL, (void *)class); 6417c478bd9Sstevel@tonic-gate } 6427c478bd9Sstevel@tonic-gate 6437c478bd9Sstevel@tonic-gate void 6447c478bd9Sstevel@tonic-gate fmd_hdl_setspecific(fmd_hdl_t *hdl, void *spec) 6457c478bd9Sstevel@tonic-gate { 6467c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 6477c478bd9Sstevel@tonic-gate 6487c478bd9Sstevel@tonic-gate mp->mod_spec = spec; 6497c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 6507c478bd9Sstevel@tonic-gate } 6517c478bd9Sstevel@tonic-gate 6527c478bd9Sstevel@tonic-gate void * 6537c478bd9Sstevel@tonic-gate fmd_hdl_getspecific(fmd_hdl_t *hdl) 6547c478bd9Sstevel@tonic-gate { 6557c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 6567c478bd9Sstevel@tonic-gate void *spec = mp->mod_spec; 6577c478bd9Sstevel@tonic-gate 6587c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 6597c478bd9Sstevel@tonic-gate return (spec); 6607c478bd9Sstevel@tonic-gate } 6617c478bd9Sstevel@tonic-gate 6627c478bd9Sstevel@tonic-gate void 6637c478bd9Sstevel@tonic-gate fmd_hdl_opendict(fmd_hdl_t *hdl, const char *dict) 6647c478bd9Sstevel@tonic-gate { 6657c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 6667c478bd9Sstevel@tonic-gate const fmd_conf_path_t *pap; 6677c478bd9Sstevel@tonic-gate int i; 6687c478bd9Sstevel@tonic-gate 6697c478bd9Sstevel@tonic-gate /* 6707c478bd9Sstevel@tonic-gate * Update the dictionary property in order to preserve the list of 6717c478bd9Sstevel@tonic-gate * pathnames and expand any % tokens in the path. Then retrieve the 6727c478bd9Sstevel@tonic-gate * new dictionary names from cpa_argv[] and open them one at a time. 6737c478bd9Sstevel@tonic-gate */ 6747c478bd9Sstevel@tonic-gate (void) fmd_conf_setprop(mp->mod_conf, FMD_PROP_DICTIONARIES, dict); 6757c478bd9Sstevel@tonic-gate (void) fmd_conf_getprop(mp->mod_conf, FMD_PROP_DICTIONARIES, &pap); 6767c478bd9Sstevel@tonic-gate 6777c478bd9Sstevel@tonic-gate ASSERT(pap->cpa_argc > mp->mod_dictc); 6787c478bd9Sstevel@tonic-gate 6797c478bd9Sstevel@tonic-gate for (i = mp->mod_dictc; i < pap->cpa_argc; i++) { 6807c478bd9Sstevel@tonic-gate if (fmd_module_dc_opendict(mp, pap->cpa_argv[i]) != 0) { 6817c478bd9Sstevel@tonic-gate fmd_api_error(mp, EFMD_MOD_DICT, 6827c478bd9Sstevel@tonic-gate "failed to open dictionary %s for module %s", 6837c478bd9Sstevel@tonic-gate pap->cpa_argv[i], mp->mod_name); 6847c478bd9Sstevel@tonic-gate } 6857c478bd9Sstevel@tonic-gate } 6867c478bd9Sstevel@tonic-gate 6877c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 6887c478bd9Sstevel@tonic-gate } 6897c478bd9Sstevel@tonic-gate 690*7aec1d6eScindi topo_hdl_t * 691*7aec1d6eScindi fmd_hdl_topology(fmd_hdl_t *hdl, int v) 692*7aec1d6eScindi { 693*7aec1d6eScindi fmd_module_t *mp = fmd_api_module_lock(hdl); 694*7aec1d6eScindi topo_hdl_t *thp; 695*7aec1d6eScindi 696*7aec1d6eScindi if (v != TOPO_VERSION) { 697*7aec1d6eScindi fmd_api_error(mp, EFMD_MOD_TOPO, "libtopo version mismatch: " 698*7aec1d6eScindi "fmd version %d != client version %d\n", TOPO_VERSION, v); 699*7aec1d6eScindi } 700*7aec1d6eScindi 701*7aec1d6eScindi thp = fmd.d_topo; 702*7aec1d6eScindi fmd_module_unlock(mp); 703*7aec1d6eScindi return (thp); 704*7aec1d6eScindi } 705*7aec1d6eScindi 7067c478bd9Sstevel@tonic-gate void * 7077c478bd9Sstevel@tonic-gate fmd_hdl_alloc(fmd_hdl_t *hdl, size_t size, int flags) 7087c478bd9Sstevel@tonic-gate { 7097c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 7107c478bd9Sstevel@tonic-gate void *data; 7117c478bd9Sstevel@tonic-gate 7127c478bd9Sstevel@tonic-gate if (mp->mod_stats->ms_memlimit.fmds_value.ui64 - 7137c478bd9Sstevel@tonic-gate mp->mod_stats->ms_memtotal.fmds_value.ui64 < size) { 7147c478bd9Sstevel@tonic-gate fmd_api_error(mp, EFMD_HDL_NOMEM, "%s's allocation of %lu " 7157c478bd9Sstevel@tonic-gate "bytes exceeds module memory limit (%llu)\n", 7167c478bd9Sstevel@tonic-gate mp->mod_name, (ulong_t)size, (u_longlong_t) 7177c478bd9Sstevel@tonic-gate mp->mod_stats->ms_memtotal.fmds_value.ui64); 7187c478bd9Sstevel@tonic-gate } 7197c478bd9Sstevel@tonic-gate 7207c478bd9Sstevel@tonic-gate if ((data = fmd_alloc(size, flags)) != NULL) 7217c478bd9Sstevel@tonic-gate mp->mod_stats->ms_memtotal.fmds_value.ui64 += size; 7227c478bd9Sstevel@tonic-gate 7237c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 7247c478bd9Sstevel@tonic-gate return (data); 7257c478bd9Sstevel@tonic-gate } 7267c478bd9Sstevel@tonic-gate 7277c478bd9Sstevel@tonic-gate void * 7287c478bd9Sstevel@tonic-gate fmd_hdl_zalloc(fmd_hdl_t *hdl, size_t size, int flags) 7297c478bd9Sstevel@tonic-gate { 7307c478bd9Sstevel@tonic-gate void *data = fmd_hdl_alloc(hdl, size, flags); 7317c478bd9Sstevel@tonic-gate 7327c478bd9Sstevel@tonic-gate if (data != NULL) 7337c478bd9Sstevel@tonic-gate bzero(data, size); 7347c478bd9Sstevel@tonic-gate 7357c478bd9Sstevel@tonic-gate return (data); 7367c478bd9Sstevel@tonic-gate } 7377c478bd9Sstevel@tonic-gate 7387c478bd9Sstevel@tonic-gate void 7397c478bd9Sstevel@tonic-gate fmd_hdl_free(fmd_hdl_t *hdl, void *data, size_t size) 7407c478bd9Sstevel@tonic-gate { 7417c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 7427c478bd9Sstevel@tonic-gate 7437c478bd9Sstevel@tonic-gate fmd_free(data, size); 7447c478bd9Sstevel@tonic-gate mp->mod_stats->ms_memtotal.fmds_value.ui64 -= size; 7457c478bd9Sstevel@tonic-gate 7467c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 7477c478bd9Sstevel@tonic-gate } 7487c478bd9Sstevel@tonic-gate 7497c478bd9Sstevel@tonic-gate char * 7507c478bd9Sstevel@tonic-gate fmd_hdl_strdup(fmd_hdl_t *hdl, const char *s, int flags) 7517c478bd9Sstevel@tonic-gate { 7527c478bd9Sstevel@tonic-gate char *p; 7537c478bd9Sstevel@tonic-gate 7547c478bd9Sstevel@tonic-gate if (s != NULL) 7557c478bd9Sstevel@tonic-gate p = fmd_hdl_alloc(hdl, strlen(s) + 1, flags); 7567c478bd9Sstevel@tonic-gate else 7577c478bd9Sstevel@tonic-gate p = NULL; 7587c478bd9Sstevel@tonic-gate 7597c478bd9Sstevel@tonic-gate if (p != NULL) 7607c478bd9Sstevel@tonic-gate (void) strcpy(p, s); 7617c478bd9Sstevel@tonic-gate 7627c478bd9Sstevel@tonic-gate return (p); 7637c478bd9Sstevel@tonic-gate } 7647c478bd9Sstevel@tonic-gate 7657c478bd9Sstevel@tonic-gate void 7667c478bd9Sstevel@tonic-gate fmd_hdl_strfree(fmd_hdl_t *hdl, char *s) 7677c478bd9Sstevel@tonic-gate { 7687c478bd9Sstevel@tonic-gate if (s != NULL) 7697c478bd9Sstevel@tonic-gate fmd_hdl_free(hdl, s, strlen(s) + 1); 7707c478bd9Sstevel@tonic-gate } 7717c478bd9Sstevel@tonic-gate 7727c478bd9Sstevel@tonic-gate void 7737c478bd9Sstevel@tonic-gate fmd_hdl_vabort(fmd_hdl_t *hdl, const char *format, va_list ap) 7747c478bd9Sstevel@tonic-gate { 7757c478bd9Sstevel@tonic-gate fmd_api_verror(fmd_api_module_lock(hdl), EFMD_HDL_ABORT, format, ap); 7767c478bd9Sstevel@tonic-gate } 7777c478bd9Sstevel@tonic-gate 7787c478bd9Sstevel@tonic-gate /*PRINTFLIKE2*/ 7797c478bd9Sstevel@tonic-gate void 7807c478bd9Sstevel@tonic-gate fmd_hdl_abort(fmd_hdl_t *hdl, const char *format, ...) 7817c478bd9Sstevel@tonic-gate { 7827c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 7837c478bd9Sstevel@tonic-gate va_list ap; 7847c478bd9Sstevel@tonic-gate 7857c478bd9Sstevel@tonic-gate va_start(ap, format); 7867c478bd9Sstevel@tonic-gate fmd_api_verror(mp, EFMD_HDL_ABORT, format, ap); 7877c478bd9Sstevel@tonic-gate va_end(ap); 7887c478bd9Sstevel@tonic-gate } 7897c478bd9Sstevel@tonic-gate 7907c478bd9Sstevel@tonic-gate void 7917c478bd9Sstevel@tonic-gate fmd_hdl_verror(fmd_hdl_t *hdl, const char *format, va_list ap) 7927c478bd9Sstevel@tonic-gate { 7937c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 7947c478bd9Sstevel@tonic-gate fmd_api_vxerror(mp, errno, format, ap); 7957c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 7967c478bd9Sstevel@tonic-gate } 7977c478bd9Sstevel@tonic-gate 7987c478bd9Sstevel@tonic-gate /*PRINTFLIKE2*/ 7997c478bd9Sstevel@tonic-gate void 8007c478bd9Sstevel@tonic-gate fmd_hdl_error(fmd_hdl_t *hdl, const char *format, ...) 8017c478bd9Sstevel@tonic-gate { 8027c478bd9Sstevel@tonic-gate va_list ap; 8037c478bd9Sstevel@tonic-gate 8047c478bd9Sstevel@tonic-gate va_start(ap, format); 8057c478bd9Sstevel@tonic-gate fmd_hdl_verror(hdl, format, ap); 8067c478bd9Sstevel@tonic-gate va_end(ap); 8077c478bd9Sstevel@tonic-gate } 8087c478bd9Sstevel@tonic-gate 8097c478bd9Sstevel@tonic-gate void 8107c478bd9Sstevel@tonic-gate fmd_hdl_vdebug(fmd_hdl_t *hdl, const char *format, va_list ap) 8117c478bd9Sstevel@tonic-gate { 8127c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 8137c478bd9Sstevel@tonic-gate 8147c478bd9Sstevel@tonic-gate char *msg; 8157c478bd9Sstevel@tonic-gate size_t len; 8167c478bd9Sstevel@tonic-gate char c; 8177c478bd9Sstevel@tonic-gate 8187c478bd9Sstevel@tonic-gate if (!(fmd.d_hdl_debug)) { 8197c478bd9Sstevel@tonic-gate mp->mod_stats->ms_debugdrop.fmds_value.ui64++; 8207c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 8217c478bd9Sstevel@tonic-gate return; 8227c478bd9Sstevel@tonic-gate } 8237c478bd9Sstevel@tonic-gate 8247c478bd9Sstevel@tonic-gate len = vsnprintf(&c, 1, format, ap); 8257c478bd9Sstevel@tonic-gate 8267c478bd9Sstevel@tonic-gate if ((msg = fmd_alloc(len + 2, FMD_NOSLEEP)) == NULL) { 8277c478bd9Sstevel@tonic-gate mp->mod_stats->ms_debugdrop.fmds_value.ui64++; 8287c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 8297c478bd9Sstevel@tonic-gate return; 8307c478bd9Sstevel@tonic-gate } 8317c478bd9Sstevel@tonic-gate 8327c478bd9Sstevel@tonic-gate (void) vsnprintf(msg, len + 1, format, ap); 8337c478bd9Sstevel@tonic-gate 8347c478bd9Sstevel@tonic-gate if (msg[len - 1] != '\n') 8357c478bd9Sstevel@tonic-gate (void) strcpy(&msg[len], "\n"); 8367c478bd9Sstevel@tonic-gate 8377c478bd9Sstevel@tonic-gate if (fmd.d_hdl_dbout & FMD_DBOUT_STDERR) { 8387c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&fmd.d_err_lock); 8397c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s DEBUG: %s: %s", 8407c478bd9Sstevel@tonic-gate fmd.d_pname, mp->mod_name, msg); 8417c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&fmd.d_err_lock); 8427c478bd9Sstevel@tonic-gate } 8437c478bd9Sstevel@tonic-gate 8447c478bd9Sstevel@tonic-gate if (fmd.d_hdl_dbout & FMD_DBOUT_SYSLOG) { 8457c478bd9Sstevel@tonic-gate syslog(LOG_DEBUG | LOG_DAEMON, "%s DEBUG: %s: %s", 8467c478bd9Sstevel@tonic-gate fmd.d_pname, mp->mod_name, msg); 8477c478bd9Sstevel@tonic-gate } 8487c478bd9Sstevel@tonic-gate 8497c478bd9Sstevel@tonic-gate fmd_free(msg, len + 2); 8507c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 8517c478bd9Sstevel@tonic-gate } 8527c478bd9Sstevel@tonic-gate 8537c478bd9Sstevel@tonic-gate /*PRINTFLIKE2*/ 8547c478bd9Sstevel@tonic-gate void 8557c478bd9Sstevel@tonic-gate fmd_hdl_debug(fmd_hdl_t *hdl, const char *format, ...) 8567c478bd9Sstevel@tonic-gate { 8577c478bd9Sstevel@tonic-gate va_list ap; 8587c478bd9Sstevel@tonic-gate 8597c478bd9Sstevel@tonic-gate va_start(ap, format); 8607c478bd9Sstevel@tonic-gate fmd_hdl_vdebug(hdl, format, ap); 8617c478bd9Sstevel@tonic-gate va_end(ap); 8627c478bd9Sstevel@tonic-gate } 8637c478bd9Sstevel@tonic-gate 8647c478bd9Sstevel@tonic-gate int32_t 8657c478bd9Sstevel@tonic-gate fmd_prop_get_int32(fmd_hdl_t *hdl, const char *name) 8667c478bd9Sstevel@tonic-gate { 8677c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 8687c478bd9Sstevel@tonic-gate const fmd_conf_ops_t *ops = fmd_conf_gettype(mp->mod_conf, name); 8697c478bd9Sstevel@tonic-gate int32_t value = 0; 8707c478bd9Sstevel@tonic-gate 8717c478bd9Sstevel@tonic-gate if (ops == &fmd_conf_bool || ops == &fmd_conf_int32 || 8727c478bd9Sstevel@tonic-gate ops == &fmd_conf_uint32) 8737c478bd9Sstevel@tonic-gate (void) fmd_conf_getprop(mp->mod_conf, name, &value); 8747c478bd9Sstevel@tonic-gate else if (ops != NULL) { 8757c478bd9Sstevel@tonic-gate fmd_api_error(mp, EFMD_PROP_TYPE, 8767c478bd9Sstevel@tonic-gate "property %s is not of int32 type\n", name); 8777c478bd9Sstevel@tonic-gate } else { 8787c478bd9Sstevel@tonic-gate fmd_api_error(mp, EFMD_PROP_DEFN, 8797c478bd9Sstevel@tonic-gate "property %s is not defined\n", name); 8807c478bd9Sstevel@tonic-gate } 8817c478bd9Sstevel@tonic-gate 8827c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 8837c478bd9Sstevel@tonic-gate return (value); 8847c478bd9Sstevel@tonic-gate } 8857c478bd9Sstevel@tonic-gate 8867c478bd9Sstevel@tonic-gate int64_t 8877c478bd9Sstevel@tonic-gate fmd_prop_get_int64(fmd_hdl_t *hdl, const char *name) 8887c478bd9Sstevel@tonic-gate { 8897c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 8907c478bd9Sstevel@tonic-gate const fmd_conf_ops_t *ops = fmd_conf_gettype(mp->mod_conf, name); 8917c478bd9Sstevel@tonic-gate int64_t value = 0; 8927c478bd9Sstevel@tonic-gate 8937c478bd9Sstevel@tonic-gate if (ops == &fmd_conf_int64 || ops == &fmd_conf_uint64 || 8947c478bd9Sstevel@tonic-gate ops == &fmd_conf_time || ops == &fmd_conf_size) 8957c478bd9Sstevel@tonic-gate (void) fmd_conf_getprop(mp->mod_conf, name, &value); 8967c478bd9Sstevel@tonic-gate else if (ops != NULL) { 8977c478bd9Sstevel@tonic-gate fmd_api_error(mp, EFMD_PROP_TYPE, 8987c478bd9Sstevel@tonic-gate "property %s is not of int64 type\n", name); 8997c478bd9Sstevel@tonic-gate } else { 9007c478bd9Sstevel@tonic-gate fmd_api_error(mp, EFMD_PROP_DEFN, 9017c478bd9Sstevel@tonic-gate "property %s is not defined\n", name); 9027c478bd9Sstevel@tonic-gate } 9037c478bd9Sstevel@tonic-gate 9047c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 9057c478bd9Sstevel@tonic-gate return (value); 9067c478bd9Sstevel@tonic-gate } 9077c478bd9Sstevel@tonic-gate 9087c478bd9Sstevel@tonic-gate char * 9097c478bd9Sstevel@tonic-gate fmd_prop_get_string(fmd_hdl_t *hdl, const char *name) 9107c478bd9Sstevel@tonic-gate { 9117c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 9127c478bd9Sstevel@tonic-gate const fmd_conf_ops_t *ops = fmd_conf_gettype(mp->mod_conf, name); 9137c478bd9Sstevel@tonic-gate char *value = NULL; 9147c478bd9Sstevel@tonic-gate const char *s; 9157c478bd9Sstevel@tonic-gate 9167c478bd9Sstevel@tonic-gate if (ops == &fmd_conf_string) { 9177c478bd9Sstevel@tonic-gate (void) fmd_conf_getprop(mp->mod_conf, name, &s); 9187c478bd9Sstevel@tonic-gate value = fmd_strdup(s, FMD_SLEEP); 9197c478bd9Sstevel@tonic-gate } else if (ops != NULL) { 9207c478bd9Sstevel@tonic-gate fmd_api_error(mp, EFMD_PROP_TYPE, 9217c478bd9Sstevel@tonic-gate "property %s is not of string type\n", name); 9227c478bd9Sstevel@tonic-gate } else { 9237c478bd9Sstevel@tonic-gate fmd_api_error(mp, EFMD_PROP_DEFN, 9247c478bd9Sstevel@tonic-gate "property %s is not defined\n", name); 9257c478bd9Sstevel@tonic-gate } 9267c478bd9Sstevel@tonic-gate 9277c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 9287c478bd9Sstevel@tonic-gate return (value); 9297c478bd9Sstevel@tonic-gate } 9307c478bd9Sstevel@tonic-gate 9317c478bd9Sstevel@tonic-gate void 9327c478bd9Sstevel@tonic-gate fmd_prop_free_string(fmd_hdl_t *hdl, char *s) 9337c478bd9Sstevel@tonic-gate { 9347c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 9357c478bd9Sstevel@tonic-gate fmd_strfree(s); 9367c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 9377c478bd9Sstevel@tonic-gate } 9387c478bd9Sstevel@tonic-gate 9397c478bd9Sstevel@tonic-gate fmd_stat_t * 9407c478bd9Sstevel@tonic-gate fmd_stat_create(fmd_hdl_t *hdl, uint_t flags, uint_t argc, fmd_stat_t *argv) 9417c478bd9Sstevel@tonic-gate { 9427c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 9437c478bd9Sstevel@tonic-gate fmd_stat_t *ep, *sp; 9447c478bd9Sstevel@tonic-gate 9457c478bd9Sstevel@tonic-gate if (flags & ~FMD_STAT_ALLOC) { 9467c478bd9Sstevel@tonic-gate fmd_api_error(mp, EFMD_STAT_FLAGS, 9477c478bd9Sstevel@tonic-gate "invalid flags 0x%x passed to fmd_stat_create\n", flags); 9487c478bd9Sstevel@tonic-gate } 9497c478bd9Sstevel@tonic-gate 9507c478bd9Sstevel@tonic-gate if ((sp = fmd_ustat_insert(mp->mod_ustat, 9517c478bd9Sstevel@tonic-gate flags | FMD_USTAT_VALIDATE, argc, argv, &ep)) == NULL) { 9527c478bd9Sstevel@tonic-gate fmd_api_error(mp, errno, 9537c478bd9Sstevel@tonic-gate "failed to publish stat '%s'", ep->fmds_name); 9547c478bd9Sstevel@tonic-gate } 9557c478bd9Sstevel@tonic-gate 9567c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 9577c478bd9Sstevel@tonic-gate return (sp); 9587c478bd9Sstevel@tonic-gate } 9597c478bd9Sstevel@tonic-gate 9607c478bd9Sstevel@tonic-gate void 9617c478bd9Sstevel@tonic-gate fmd_stat_destroy(fmd_hdl_t *hdl, uint_t argc, fmd_stat_t *argv) 9627c478bd9Sstevel@tonic-gate { 9637c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 9647c478bd9Sstevel@tonic-gate fmd_ustat_delete(mp->mod_ustat, argc, argv); 9657c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 9667c478bd9Sstevel@tonic-gate } 9677c478bd9Sstevel@tonic-gate 9687c478bd9Sstevel@tonic-gate void 9697c478bd9Sstevel@tonic-gate fmd_stat_setstr(fmd_hdl_t *hdl, fmd_stat_t *sp, const char *s) 9707c478bd9Sstevel@tonic-gate { 9717c478bd9Sstevel@tonic-gate char *str = fmd_strdup(s, FMD_SLEEP); 9727c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 9737c478bd9Sstevel@tonic-gate 9747c478bd9Sstevel@tonic-gate if (sp->fmds_type != FMD_TYPE_STRING) { 9757c478bd9Sstevel@tonic-gate fmd_strfree(str); 9767c478bd9Sstevel@tonic-gate fmd_api_error(mp, EFMD_STAT_TYPE, 9777c478bd9Sstevel@tonic-gate "stat '%s' is not a string\n", sp->fmds_name); 9787c478bd9Sstevel@tonic-gate } 9797c478bd9Sstevel@tonic-gate 9807c478bd9Sstevel@tonic-gate fmd_strfree(sp->fmds_value.str); 9817c478bd9Sstevel@tonic-gate sp->fmds_value.str = str; 9827c478bd9Sstevel@tonic-gate 9837c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 9847c478bd9Sstevel@tonic-gate } 9857c478bd9Sstevel@tonic-gate 9867c478bd9Sstevel@tonic-gate fmd_case_t * 9877c478bd9Sstevel@tonic-gate fmd_case_open(fmd_hdl_t *hdl, void *data) 9887c478bd9Sstevel@tonic-gate { 9897c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 9907c478bd9Sstevel@tonic-gate fmd_case_t *cp = fmd_case_create(mp, data); 9917c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 9927c478bd9Sstevel@tonic-gate return (cp); 9937c478bd9Sstevel@tonic-gate } 9947c478bd9Sstevel@tonic-gate 9957c478bd9Sstevel@tonic-gate void 9967c478bd9Sstevel@tonic-gate fmd_case_reset(fmd_hdl_t *hdl, fmd_case_t *cp) 9977c478bd9Sstevel@tonic-gate { 9987c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 9997c478bd9Sstevel@tonic-gate fmd_case_impl_t *cip = fmd_api_case_impl(mp, cp); 10007c478bd9Sstevel@tonic-gate 10017c478bd9Sstevel@tonic-gate if (cip->ci_state >= FMD_CASE_SOLVED) { 10027c478bd9Sstevel@tonic-gate fmd_api_error(mp, EFMD_CASE_STATE, "cannot solve %s: " 10037c478bd9Sstevel@tonic-gate "case is already solved or closed\n", cip->ci_uuid); 10047c478bd9Sstevel@tonic-gate } 10057c478bd9Sstevel@tonic-gate 10067c478bd9Sstevel@tonic-gate fmd_case_reset_suspects(cp); 10077c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 10087c478bd9Sstevel@tonic-gate } 10097c478bd9Sstevel@tonic-gate 10107c478bd9Sstevel@tonic-gate void 10117c478bd9Sstevel@tonic-gate fmd_case_solve(fmd_hdl_t *hdl, fmd_case_t *cp) 10127c478bd9Sstevel@tonic-gate { 10137c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 10147c478bd9Sstevel@tonic-gate fmd_case_impl_t *cip = fmd_api_case_impl(mp, cp); 10157c478bd9Sstevel@tonic-gate 10167c478bd9Sstevel@tonic-gate if (cip->ci_state >= FMD_CASE_SOLVED) { 10177c478bd9Sstevel@tonic-gate fmd_api_error(mp, EFMD_CASE_STATE, "cannot solve %s: " 10187c478bd9Sstevel@tonic-gate "case is already solved or closed\n", cip->ci_uuid); 10197c478bd9Sstevel@tonic-gate } 10207c478bd9Sstevel@tonic-gate 1021d9638e54Smws fmd_case_transition(cp, FMD_CASE_SOLVED, FMD_CF_SOLVED); 10227c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 10237c478bd9Sstevel@tonic-gate } 10247c478bd9Sstevel@tonic-gate 10257c478bd9Sstevel@tonic-gate void 10267c478bd9Sstevel@tonic-gate fmd_case_close(fmd_hdl_t *hdl, fmd_case_t *cp) 10277c478bd9Sstevel@tonic-gate { 10287c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 10297c478bd9Sstevel@tonic-gate 10307c478bd9Sstevel@tonic-gate (void) fmd_api_case_impl(mp, cp); /* validate 'cp' */ 1031d9638e54Smws fmd_case_transition(cp, FMD_CASE_CLOSE_WAIT, FMD_CF_ISOLATED); 10327c478bd9Sstevel@tonic-gate 10337c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 10347c478bd9Sstevel@tonic-gate } 10357c478bd9Sstevel@tonic-gate 10367c478bd9Sstevel@tonic-gate const char * 10377c478bd9Sstevel@tonic-gate fmd_case_uuid(fmd_hdl_t *hdl, fmd_case_t *cp) 10387c478bd9Sstevel@tonic-gate { 10397c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 10407c478bd9Sstevel@tonic-gate fmd_case_impl_t *cip = fmd_api_case_impl(mp, cp); 10417c478bd9Sstevel@tonic-gate const char *uuid = cip->ci_uuid; 10427c478bd9Sstevel@tonic-gate 10437c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 10447c478bd9Sstevel@tonic-gate return (uuid); 10457c478bd9Sstevel@tonic-gate } 10467c478bd9Sstevel@tonic-gate 10477c478bd9Sstevel@tonic-gate fmd_case_t * 10487c478bd9Sstevel@tonic-gate fmd_case_uulookup(fmd_hdl_t *hdl, const char *uuid) 10497c478bd9Sstevel@tonic-gate { 10507c478bd9Sstevel@tonic-gate fmd_module_t *cmp, *mp = fmd_api_module_lock(hdl); 10517c478bd9Sstevel@tonic-gate fmd_case_t *cp = fmd_case_hash_lookup(fmd.d_cases, uuid); 10527c478bd9Sstevel@tonic-gate 10537c478bd9Sstevel@tonic-gate if (cp != NULL) { 10547c478bd9Sstevel@tonic-gate cmp = ((fmd_case_impl_t *)cp)->ci_mod; 10557c478bd9Sstevel@tonic-gate fmd_case_rele(cp); 10567c478bd9Sstevel@tonic-gate } else 10577c478bd9Sstevel@tonic-gate cmp = NULL; 10587c478bd9Sstevel@tonic-gate 10597c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 10607c478bd9Sstevel@tonic-gate return (cmp == mp ? cp : NULL); 10617c478bd9Sstevel@tonic-gate } 10627c478bd9Sstevel@tonic-gate 10637c478bd9Sstevel@tonic-gate void 10647c478bd9Sstevel@tonic-gate fmd_case_uuclose(fmd_hdl_t *hdl, const char *uuid) 10657c478bd9Sstevel@tonic-gate { 10667c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 10677c478bd9Sstevel@tonic-gate fmd_case_t *cp = fmd_case_hash_lookup(fmd.d_cases, uuid); 10687c478bd9Sstevel@tonic-gate 1069d9638e54Smws if (cp != NULL) { 1070d9638e54Smws fmd_case_transition(cp, FMD_CASE_CLOSE_WAIT, FMD_CF_ISOLATED); 10717c478bd9Sstevel@tonic-gate fmd_case_rele(cp); 1072d9638e54Smws } 1073d9638e54Smws 10747c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 10757c478bd9Sstevel@tonic-gate } 10767c478bd9Sstevel@tonic-gate 10777c478bd9Sstevel@tonic-gate int 10787c478bd9Sstevel@tonic-gate fmd_case_uuclosed(fmd_hdl_t *hdl, const char *uuid) 10797c478bd9Sstevel@tonic-gate { 10807c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 10817c478bd9Sstevel@tonic-gate fmd_case_t *cp = fmd_case_hash_lookup(fmd.d_cases, uuid); 10827c478bd9Sstevel@tonic-gate fmd_case_impl_t *cip = (fmd_case_impl_t *)cp; 10837c478bd9Sstevel@tonic-gate int rv = FMD_B_TRUE; 10847c478bd9Sstevel@tonic-gate 10857c478bd9Sstevel@tonic-gate if (cip != NULL) { 1086d9638e54Smws rv = cip->ci_state >= FMD_CASE_CLOSE_WAIT; 10877c478bd9Sstevel@tonic-gate fmd_case_rele(cp); 10887c478bd9Sstevel@tonic-gate } 10897c478bd9Sstevel@tonic-gate 10907c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 10917c478bd9Sstevel@tonic-gate return (rv); 10927c478bd9Sstevel@tonic-gate } 10937c478bd9Sstevel@tonic-gate 10947c478bd9Sstevel@tonic-gate static int 10957c478bd9Sstevel@tonic-gate fmd_case_instate(fmd_hdl_t *hdl, fmd_case_t *cp, uint_t state) 10967c478bd9Sstevel@tonic-gate { 10977c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 10987c478bd9Sstevel@tonic-gate fmd_case_impl_t *cip = fmd_api_case_impl(mp, cp); 10997c478bd9Sstevel@tonic-gate int rv = cip->ci_state >= state; 11007c478bd9Sstevel@tonic-gate 11017c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 11027c478bd9Sstevel@tonic-gate return (rv); 11037c478bd9Sstevel@tonic-gate } 11047c478bd9Sstevel@tonic-gate 11057c478bd9Sstevel@tonic-gate int 11067c478bd9Sstevel@tonic-gate fmd_case_solved(fmd_hdl_t *hdl, fmd_case_t *cp) 11077c478bd9Sstevel@tonic-gate { 11087c478bd9Sstevel@tonic-gate return (fmd_case_instate(hdl, cp, FMD_CASE_SOLVED)); 11097c478bd9Sstevel@tonic-gate } 11107c478bd9Sstevel@tonic-gate 11117c478bd9Sstevel@tonic-gate int 11127c478bd9Sstevel@tonic-gate fmd_case_closed(fmd_hdl_t *hdl, fmd_case_t *cp) 11137c478bd9Sstevel@tonic-gate { 1114d9638e54Smws return (fmd_case_instate(hdl, cp, FMD_CASE_CLOSE_WAIT)); 11157c478bd9Sstevel@tonic-gate } 11167c478bd9Sstevel@tonic-gate 11177c478bd9Sstevel@tonic-gate void 11187c478bd9Sstevel@tonic-gate fmd_case_add_ereport(fmd_hdl_t *hdl, fmd_case_t *cp, fmd_event_t *ep) 11197c478bd9Sstevel@tonic-gate { 11207c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 11217c478bd9Sstevel@tonic-gate 11227c478bd9Sstevel@tonic-gate (void) fmd_api_case_impl(mp, cp); /* validate 'cp' */ 1123*7aec1d6eScindi 1124*7aec1d6eScindi if (fmd_case_insert_event(cp, ep)) 11257c478bd9Sstevel@tonic-gate mp->mod_stats->ms_accepted.fmds_value.ui64++; 11267c478bd9Sstevel@tonic-gate 11277c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 11287c478bd9Sstevel@tonic-gate } 11297c478bd9Sstevel@tonic-gate 11307c478bd9Sstevel@tonic-gate void 11317c478bd9Sstevel@tonic-gate fmd_case_add_serd(fmd_hdl_t *hdl, fmd_case_t *cp, const char *name) 11327c478bd9Sstevel@tonic-gate { 11337c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 11347c478bd9Sstevel@tonic-gate fmd_serd_elem_t *sep; 11357c478bd9Sstevel@tonic-gate fmd_serd_eng_t *sgp; 11367c478bd9Sstevel@tonic-gate 11377c478bd9Sstevel@tonic-gate if ((sgp = fmd_serd_eng_lookup(&mp->mod_serds, name)) == NULL) { 11387c478bd9Sstevel@tonic-gate fmd_api_error(mp, EFMD_SERD_NAME, 11397c478bd9Sstevel@tonic-gate "failed to add events from serd engine '%s'", name); 11407c478bd9Sstevel@tonic-gate } 11417c478bd9Sstevel@tonic-gate 11427c478bd9Sstevel@tonic-gate (void) fmd_api_case_impl(mp, cp); /* validate 'cp' */ 11437c478bd9Sstevel@tonic-gate 11447c478bd9Sstevel@tonic-gate for (sep = fmd_list_next(&sgp->sg_list); 1145*7aec1d6eScindi sep != NULL; sep = fmd_list_next(sep)) { 1146*7aec1d6eScindi if (fmd_case_insert_event(cp, sep->se_event)) 1147*7aec1d6eScindi mp->mod_stats->ms_accepted.fmds_value.ui64++; 1148*7aec1d6eScindi } 11497c478bd9Sstevel@tonic-gate 11507c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 11517c478bd9Sstevel@tonic-gate } 11527c478bd9Sstevel@tonic-gate 11537c478bd9Sstevel@tonic-gate void 11547c478bd9Sstevel@tonic-gate fmd_case_add_suspect(fmd_hdl_t *hdl, fmd_case_t *cp, nvlist_t *nvl) 11557c478bd9Sstevel@tonic-gate { 11567c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 11577c478bd9Sstevel@tonic-gate fmd_case_impl_t *cip = fmd_api_case_impl(mp, cp); 11587c478bd9Sstevel@tonic-gate char *class; 11597c478bd9Sstevel@tonic-gate 11607c478bd9Sstevel@tonic-gate if (cip->ci_state >= FMD_CASE_SOLVED) { 11617c478bd9Sstevel@tonic-gate fmd_api_error(mp, EFMD_CASE_STATE, "cannot add suspect to " 11627c478bd9Sstevel@tonic-gate "%s: case is already solved or closed\n", cip->ci_uuid); 11637c478bd9Sstevel@tonic-gate } 11647c478bd9Sstevel@tonic-gate 11657c478bd9Sstevel@tonic-gate if (nvlist_lookup_string(nvl, FM_CLASS, &class) != 0 || 11667c478bd9Sstevel@tonic-gate class == NULL || *class == '\0') { 11677c478bd9Sstevel@tonic-gate fmd_api_error(mp, EFMD_CASE_EVENT, "cannot add suspect to " 11687c478bd9Sstevel@tonic-gate "%s: suspect event is missing a class\n", cip->ci_uuid); 11697c478bd9Sstevel@tonic-gate } 11707c478bd9Sstevel@tonic-gate 11717c478bd9Sstevel@tonic-gate fmd_case_insert_suspect(cp, nvl); 11727c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 11737c478bd9Sstevel@tonic-gate } 11747c478bd9Sstevel@tonic-gate 11757c478bd9Sstevel@tonic-gate void 11767c478bd9Sstevel@tonic-gate fmd_case_setspecific(fmd_hdl_t *hdl, fmd_case_t *cp, void *data) 11777c478bd9Sstevel@tonic-gate { 11787c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 11797c478bd9Sstevel@tonic-gate fmd_case_impl_t *cip = fmd_api_case_impl(mp, cp); 11807c478bd9Sstevel@tonic-gate 11817c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cip->ci_lock); 11827c478bd9Sstevel@tonic-gate cip->ci_data = data; 11837c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cip->ci_lock); 11847c478bd9Sstevel@tonic-gate 11857c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 11867c478bd9Sstevel@tonic-gate } 11877c478bd9Sstevel@tonic-gate 11887c478bd9Sstevel@tonic-gate void * 11897c478bd9Sstevel@tonic-gate fmd_case_getspecific(fmd_hdl_t *hdl, fmd_case_t *cp) 11907c478bd9Sstevel@tonic-gate { 11917c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 11927c478bd9Sstevel@tonic-gate fmd_case_impl_t *cip = fmd_api_case_impl(mp, cp); 11937c478bd9Sstevel@tonic-gate void *data; 11947c478bd9Sstevel@tonic-gate 11957c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cip->ci_lock); 11967c478bd9Sstevel@tonic-gate data = cip->ci_data; 11977c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cip->ci_lock); 11987c478bd9Sstevel@tonic-gate 11997c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 12007c478bd9Sstevel@tonic-gate return (data); 12017c478bd9Sstevel@tonic-gate } 12027c478bd9Sstevel@tonic-gate 12037c478bd9Sstevel@tonic-gate void 12047c478bd9Sstevel@tonic-gate fmd_case_setprincipal(fmd_hdl_t *hdl, fmd_case_t *cp, fmd_event_t *ep) 12057c478bd9Sstevel@tonic-gate { 12067c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 12077c478bd9Sstevel@tonic-gate 12087c478bd9Sstevel@tonic-gate (void) fmd_api_case_impl(mp, cp); /* validate 'cp' */ 1209*7aec1d6eScindi 1210*7aec1d6eScindi if (fmd_case_insert_principal(cp, ep)) 12117c478bd9Sstevel@tonic-gate mp->mod_stats->ms_accepted.fmds_value.ui64++; 12127c478bd9Sstevel@tonic-gate 12137c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 12147c478bd9Sstevel@tonic-gate } 12157c478bd9Sstevel@tonic-gate 12167c478bd9Sstevel@tonic-gate fmd_event_t * 12177c478bd9Sstevel@tonic-gate fmd_case_getprincipal(fmd_hdl_t *hdl, fmd_case_t *cp) 12187c478bd9Sstevel@tonic-gate { 12197c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 12207c478bd9Sstevel@tonic-gate fmd_case_impl_t *cip = fmd_api_case_impl(mp, cp); 12217c478bd9Sstevel@tonic-gate fmd_event_t *ep; 12227c478bd9Sstevel@tonic-gate 12237c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cip->ci_lock); 12247c478bd9Sstevel@tonic-gate ep = cip->ci_principal; 12257c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cip->ci_lock); 12267c478bd9Sstevel@tonic-gate 12277c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 12287c478bd9Sstevel@tonic-gate return (ep); 12297c478bd9Sstevel@tonic-gate } 12307c478bd9Sstevel@tonic-gate 12317c478bd9Sstevel@tonic-gate fmd_case_t * 12327c478bd9Sstevel@tonic-gate fmd_case_next(fmd_hdl_t *hdl, fmd_case_t *cp) 12337c478bd9Sstevel@tonic-gate { 12347c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 12357c478bd9Sstevel@tonic-gate 12367c478bd9Sstevel@tonic-gate if (cp != NULL) 12377c478bd9Sstevel@tonic-gate cp = fmd_list_next(fmd_api_case_impl(mp, cp)); 12387c478bd9Sstevel@tonic-gate else 12397c478bd9Sstevel@tonic-gate cp = fmd_list_next(&mp->mod_cases); 12407c478bd9Sstevel@tonic-gate 12417c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 12427c478bd9Sstevel@tonic-gate return (cp); 12437c478bd9Sstevel@tonic-gate } 12447c478bd9Sstevel@tonic-gate 12457c478bd9Sstevel@tonic-gate fmd_case_t * 12467c478bd9Sstevel@tonic-gate fmd_case_prev(fmd_hdl_t *hdl, fmd_case_t *cp) 12477c478bd9Sstevel@tonic-gate { 12487c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 12497c478bd9Sstevel@tonic-gate 12507c478bd9Sstevel@tonic-gate if (cp != NULL) 12517c478bd9Sstevel@tonic-gate cp = fmd_list_prev(fmd_api_case_impl(mp, cp)); 12527c478bd9Sstevel@tonic-gate else 12537c478bd9Sstevel@tonic-gate cp = fmd_list_prev(&mp->mod_cases); 12547c478bd9Sstevel@tonic-gate 12557c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 12567c478bd9Sstevel@tonic-gate return (cp); 12577c478bd9Sstevel@tonic-gate } 12587c478bd9Sstevel@tonic-gate 12597c478bd9Sstevel@tonic-gate /* 12607c478bd9Sstevel@tonic-gate * Utility function for fmd_buf_* routines. If a case is specified, use the 12617c478bd9Sstevel@tonic-gate * case's ci_bufs hash; otherwise use the module's global mod_bufs hash. 12627c478bd9Sstevel@tonic-gate */ 12637c478bd9Sstevel@tonic-gate static fmd_buf_hash_t * 12647c478bd9Sstevel@tonic-gate fmd_buf_gethash(fmd_module_t *mp, fmd_case_t *cp) 12657c478bd9Sstevel@tonic-gate { 12667c478bd9Sstevel@tonic-gate return (cp ? &fmd_api_case_impl(mp, cp)->ci_bufs : &mp->mod_bufs); 12677c478bd9Sstevel@tonic-gate } 12687c478bd9Sstevel@tonic-gate 12697c478bd9Sstevel@tonic-gate void 12707c478bd9Sstevel@tonic-gate fmd_buf_create(fmd_hdl_t *hdl, fmd_case_t *cp, const char *name, size_t size) 12717c478bd9Sstevel@tonic-gate { 12727c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 12737c478bd9Sstevel@tonic-gate fmd_buf_hash_t *bhp = fmd_buf_gethash(mp, cp); 12747c478bd9Sstevel@tonic-gate fmd_buf_t *bp = fmd_buf_lookup(bhp, name); 12757c478bd9Sstevel@tonic-gate 12767c478bd9Sstevel@tonic-gate if (bp == NULL) { 12777c478bd9Sstevel@tonic-gate if (fmd_strbadid(name, FMD_B_TRUE) != NULL || size == 0) { 12787c478bd9Sstevel@tonic-gate fmd_api_error(mp, EFMD_BUF_INVAL, "cannot create '%s' " 12797c478bd9Sstevel@tonic-gate "(size %lu): %s\n", name, (ulong_t)size, 12807c478bd9Sstevel@tonic-gate fmd_strerror(EFMD_BUF_INVAL)); 12817c478bd9Sstevel@tonic-gate } 12827c478bd9Sstevel@tonic-gate 12837c478bd9Sstevel@tonic-gate if (mp->mod_stats->ms_buflimit.fmds_value.ui64 - 12847c478bd9Sstevel@tonic-gate mp->mod_stats->ms_buftotal.fmds_value.ui64 < size) { 12857c478bd9Sstevel@tonic-gate fmd_api_error(mp, EFMD_BUF_LIMIT, "cannot create '%s': " 12867c478bd9Sstevel@tonic-gate "buf limit exceeded (%llu)\n", name, (u_longlong_t) 12877c478bd9Sstevel@tonic-gate mp->mod_stats->ms_buflimit.fmds_value.ui64); 12887c478bd9Sstevel@tonic-gate } 12897c478bd9Sstevel@tonic-gate 12907c478bd9Sstevel@tonic-gate mp->mod_stats->ms_buftotal.fmds_value.ui64 += size; 12917c478bd9Sstevel@tonic-gate bp = fmd_buf_insert(bhp, name, size); 12927c478bd9Sstevel@tonic-gate 12937c478bd9Sstevel@tonic-gate } else { 12947c478bd9Sstevel@tonic-gate fmd_api_error(mp, EFMD_BUF_EXISTS, 12957c478bd9Sstevel@tonic-gate "cannot create '%s': buffer already exists\n", name); 12967c478bd9Sstevel@tonic-gate } 12977c478bd9Sstevel@tonic-gate 12987c478bd9Sstevel@tonic-gate if (cp != NULL) 12997c478bd9Sstevel@tonic-gate fmd_case_setdirty(cp); 13007c478bd9Sstevel@tonic-gate else 13017c478bd9Sstevel@tonic-gate fmd_module_setdirty(mp); 13027c478bd9Sstevel@tonic-gate 13037c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 13047c478bd9Sstevel@tonic-gate } 13057c478bd9Sstevel@tonic-gate 13067c478bd9Sstevel@tonic-gate void 13077c478bd9Sstevel@tonic-gate fmd_buf_destroy(fmd_hdl_t *hdl, fmd_case_t *cp, const char *name) 13087c478bd9Sstevel@tonic-gate { 13097c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 13107c478bd9Sstevel@tonic-gate fmd_buf_hash_t *bhp = fmd_buf_gethash(mp, cp); 13117c478bd9Sstevel@tonic-gate fmd_buf_t *bp = fmd_buf_lookup(bhp, name); 13127c478bd9Sstevel@tonic-gate 13137c478bd9Sstevel@tonic-gate if (bp != NULL) { 13147c478bd9Sstevel@tonic-gate mp->mod_stats->ms_buftotal.fmds_value.ui64 -= bp->buf_size; 13157c478bd9Sstevel@tonic-gate fmd_buf_delete(bhp, name); 13167c478bd9Sstevel@tonic-gate 13177c478bd9Sstevel@tonic-gate if (cp != NULL) 13187c478bd9Sstevel@tonic-gate fmd_case_setdirty(cp); 13197c478bd9Sstevel@tonic-gate else 13207c478bd9Sstevel@tonic-gate fmd_module_setdirty(mp); 13217c478bd9Sstevel@tonic-gate } 13227c478bd9Sstevel@tonic-gate 13237c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 13247c478bd9Sstevel@tonic-gate } 13257c478bd9Sstevel@tonic-gate 13267c478bd9Sstevel@tonic-gate void 13277c478bd9Sstevel@tonic-gate fmd_buf_read(fmd_hdl_t *hdl, fmd_case_t *cp, 13287c478bd9Sstevel@tonic-gate const char *name, void *buf, size_t size) 13297c478bd9Sstevel@tonic-gate { 13307c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 13317c478bd9Sstevel@tonic-gate fmd_buf_t *bp = fmd_buf_lookup(fmd_buf_gethash(mp, cp), name); 13327c478bd9Sstevel@tonic-gate 13337c478bd9Sstevel@tonic-gate if (bp == NULL) { 13347c478bd9Sstevel@tonic-gate fmd_api_error(mp, EFMD_BUF_NOENT, "no buf named '%s' is " 13357c478bd9Sstevel@tonic-gate "associated with %s\n", name, cp ? "case" : "module"); 13367c478bd9Sstevel@tonic-gate } 13377c478bd9Sstevel@tonic-gate 13387c478bd9Sstevel@tonic-gate bcopy(bp->buf_data, buf, MIN(bp->buf_size, size)); 13397c478bd9Sstevel@tonic-gate if (size > bp->buf_size) 13407c478bd9Sstevel@tonic-gate bzero((char *)buf + bp->buf_size, size - bp->buf_size); 13417c478bd9Sstevel@tonic-gate 13427c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 13437c478bd9Sstevel@tonic-gate } 13447c478bd9Sstevel@tonic-gate 13457c478bd9Sstevel@tonic-gate void 13467c478bd9Sstevel@tonic-gate fmd_buf_write(fmd_hdl_t *hdl, fmd_case_t *cp, 13477c478bd9Sstevel@tonic-gate const char *name, const void *buf, size_t size) 13487c478bd9Sstevel@tonic-gate { 13497c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 13507c478bd9Sstevel@tonic-gate fmd_buf_hash_t *bhp = fmd_buf_gethash(mp, cp); 13517c478bd9Sstevel@tonic-gate fmd_buf_t *bp = fmd_buf_lookup(bhp, name); 13527c478bd9Sstevel@tonic-gate 13537c478bd9Sstevel@tonic-gate if (bp == NULL) { 13547c478bd9Sstevel@tonic-gate if (fmd_strbadid(name, FMD_B_TRUE) != NULL || size == 0) { 13557c478bd9Sstevel@tonic-gate fmd_api_error(mp, EFMD_BUF_INVAL, "cannot write '%s' " 13567c478bd9Sstevel@tonic-gate "(size %lu): %s\n", name, (ulong_t)size, 13577c478bd9Sstevel@tonic-gate fmd_strerror(EFMD_BUF_INVAL)); 13587c478bd9Sstevel@tonic-gate } 13597c478bd9Sstevel@tonic-gate 13607c478bd9Sstevel@tonic-gate if (mp->mod_stats->ms_buflimit.fmds_value.ui64 - 13617c478bd9Sstevel@tonic-gate mp->mod_stats->ms_buftotal.fmds_value.ui64 < size) { 13627c478bd9Sstevel@tonic-gate fmd_api_error(mp, EFMD_BUF_LIMIT, "cannot write '%s': " 13637c478bd9Sstevel@tonic-gate "buf limit exceeded (%llu)\n", name, (u_longlong_t) 13647c478bd9Sstevel@tonic-gate mp->mod_stats->ms_buflimit.fmds_value.ui64); 13657c478bd9Sstevel@tonic-gate } 13667c478bd9Sstevel@tonic-gate 13677c478bd9Sstevel@tonic-gate mp->mod_stats->ms_buftotal.fmds_value.ui64 += size; 13687c478bd9Sstevel@tonic-gate bp = fmd_buf_insert(bhp, name, size); 13697c478bd9Sstevel@tonic-gate 13707c478bd9Sstevel@tonic-gate } else if (size > bp->buf_size) { 13717c478bd9Sstevel@tonic-gate fmd_api_error(mp, EFMD_BUF_OFLOW, 13727c478bd9Sstevel@tonic-gate "write to buf '%s' overflows buf size (%lu > %lu)\n", 13737c478bd9Sstevel@tonic-gate name, (ulong_t)size, (ulong_t)bp->buf_size); 13747c478bd9Sstevel@tonic-gate } 13757c478bd9Sstevel@tonic-gate 13767c478bd9Sstevel@tonic-gate bcopy(buf, bp->buf_data, MIN(bp->buf_size, size)); 13777c478bd9Sstevel@tonic-gate bp->buf_flags |= FMD_BUF_DIRTY; 13787c478bd9Sstevel@tonic-gate 13797c478bd9Sstevel@tonic-gate if (cp != NULL) 13807c478bd9Sstevel@tonic-gate fmd_case_setdirty(cp); 13817c478bd9Sstevel@tonic-gate else 13827c478bd9Sstevel@tonic-gate fmd_module_setdirty(mp); 13837c478bd9Sstevel@tonic-gate 13847c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 13857c478bd9Sstevel@tonic-gate } 13867c478bd9Sstevel@tonic-gate 13877c478bd9Sstevel@tonic-gate size_t 13887c478bd9Sstevel@tonic-gate fmd_buf_size(fmd_hdl_t *hdl, fmd_case_t *cp, const char *name) 13897c478bd9Sstevel@tonic-gate { 13907c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 13917c478bd9Sstevel@tonic-gate fmd_buf_hash_t *bhp = fmd_buf_gethash(mp, cp); 13927c478bd9Sstevel@tonic-gate 13937c478bd9Sstevel@tonic-gate fmd_buf_t *bp; 13947c478bd9Sstevel@tonic-gate size_t size; 13957c478bd9Sstevel@tonic-gate 13967c478bd9Sstevel@tonic-gate if ((bp = fmd_buf_lookup(bhp, name)) != NULL) 13977c478bd9Sstevel@tonic-gate size = bp->buf_size; 13987c478bd9Sstevel@tonic-gate else 13997c478bd9Sstevel@tonic-gate size = 0; 14007c478bd9Sstevel@tonic-gate 14017c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 14027c478bd9Sstevel@tonic-gate return (size); 14037c478bd9Sstevel@tonic-gate } 14047c478bd9Sstevel@tonic-gate 14057c478bd9Sstevel@tonic-gate void 14067c478bd9Sstevel@tonic-gate fmd_serd_create(fmd_hdl_t *hdl, const char *name, uint_t n, hrtime_t t) 14077c478bd9Sstevel@tonic-gate { 14087c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 14097c478bd9Sstevel@tonic-gate 14107c478bd9Sstevel@tonic-gate if (fmd_serd_eng_lookup(&mp->mod_serds, name) != NULL) { 14117c478bd9Sstevel@tonic-gate fmd_api_error(mp, EFMD_SERD_EXISTS, 14127c478bd9Sstevel@tonic-gate "failed to create serd engine '%s': %s\n", 14137c478bd9Sstevel@tonic-gate name, fmd_strerror(EFMD_SERD_EXISTS)); 14147c478bd9Sstevel@tonic-gate } 14157c478bd9Sstevel@tonic-gate 14167c478bd9Sstevel@tonic-gate (void) fmd_serd_eng_insert(&mp->mod_serds, name, n, t); 14177c478bd9Sstevel@tonic-gate fmd_module_setdirty(mp); 14187c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 14197c478bd9Sstevel@tonic-gate } 14207c478bd9Sstevel@tonic-gate 14217c478bd9Sstevel@tonic-gate void 14227c478bd9Sstevel@tonic-gate fmd_serd_destroy(fmd_hdl_t *hdl, const char *name) 14237c478bd9Sstevel@tonic-gate { 14247c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 14257c478bd9Sstevel@tonic-gate 14267c478bd9Sstevel@tonic-gate fmd_serd_eng_delete(&mp->mod_serds, name); 14277c478bd9Sstevel@tonic-gate fmd_module_setdirty(mp); 14287c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 14297c478bd9Sstevel@tonic-gate } 14307c478bd9Sstevel@tonic-gate 14317c478bd9Sstevel@tonic-gate int 14327c478bd9Sstevel@tonic-gate fmd_serd_exists(fmd_hdl_t *hdl, const char *name) 14337c478bd9Sstevel@tonic-gate { 14347c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 14357c478bd9Sstevel@tonic-gate int rv = (fmd_serd_eng_lookup(&mp->mod_serds, name) != NULL); 14367c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 14377c478bd9Sstevel@tonic-gate 14387c478bd9Sstevel@tonic-gate return (rv); 14397c478bd9Sstevel@tonic-gate } 14407c478bd9Sstevel@tonic-gate 14417c478bd9Sstevel@tonic-gate void 14427c478bd9Sstevel@tonic-gate fmd_serd_reset(fmd_hdl_t *hdl, const char *name) 14437c478bd9Sstevel@tonic-gate { 14447c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 14457c478bd9Sstevel@tonic-gate fmd_serd_eng_t *sgp; 14467c478bd9Sstevel@tonic-gate 14477c478bd9Sstevel@tonic-gate if ((sgp = fmd_serd_eng_lookup(&mp->mod_serds, name)) == NULL) { 14487c478bd9Sstevel@tonic-gate fmd_api_error(mp, EFMD_SERD_NAME, 14497c478bd9Sstevel@tonic-gate "serd engine '%s' does not exist\n", name); 14507c478bd9Sstevel@tonic-gate } 14517c478bd9Sstevel@tonic-gate 14527c478bd9Sstevel@tonic-gate fmd_serd_eng_reset(sgp); 14537c478bd9Sstevel@tonic-gate fmd_module_setdirty(mp); 14547c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 14557c478bd9Sstevel@tonic-gate } 14567c478bd9Sstevel@tonic-gate 14577c478bd9Sstevel@tonic-gate int 14587c478bd9Sstevel@tonic-gate fmd_serd_record(fmd_hdl_t *hdl, const char *name, fmd_event_t *ep) 14597c478bd9Sstevel@tonic-gate { 14607c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 14617c478bd9Sstevel@tonic-gate fmd_serd_eng_t *sgp; 14627c478bd9Sstevel@tonic-gate int err; 14637c478bd9Sstevel@tonic-gate 14647c478bd9Sstevel@tonic-gate if ((sgp = fmd_serd_eng_lookup(&mp->mod_serds, name)) == NULL) { 14657c478bd9Sstevel@tonic-gate fmd_api_error(mp, EFMD_SERD_NAME, 14667c478bd9Sstevel@tonic-gate "failed to add record to serd engine '%s'", name); 14677c478bd9Sstevel@tonic-gate } 14687c478bd9Sstevel@tonic-gate 14697c478bd9Sstevel@tonic-gate err = fmd_serd_eng_record(sgp, ep); 14707c478bd9Sstevel@tonic-gate 14717c478bd9Sstevel@tonic-gate if (sgp->sg_flags & FMD_SERD_DIRTY) 14727c478bd9Sstevel@tonic-gate fmd_module_setdirty(mp); 14737c478bd9Sstevel@tonic-gate 14747c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 14757c478bd9Sstevel@tonic-gate return (err); 14767c478bd9Sstevel@tonic-gate } 14777c478bd9Sstevel@tonic-gate 14787c478bd9Sstevel@tonic-gate int 14797c478bd9Sstevel@tonic-gate fmd_serd_fired(fmd_hdl_t *hdl, const char *name) 14807c478bd9Sstevel@tonic-gate { 14817c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 14827c478bd9Sstevel@tonic-gate fmd_serd_eng_t *sgp; 14837c478bd9Sstevel@tonic-gate int err; 14847c478bd9Sstevel@tonic-gate 14857c478bd9Sstevel@tonic-gate if ((sgp = fmd_serd_eng_lookup(&mp->mod_serds, name)) == NULL) { 14867c478bd9Sstevel@tonic-gate fmd_api_error(mp, EFMD_SERD_NAME, 14877c478bd9Sstevel@tonic-gate "serd engine '%s' does not exist\n", name); 14887c478bd9Sstevel@tonic-gate } 14897c478bd9Sstevel@tonic-gate 14907c478bd9Sstevel@tonic-gate err = fmd_serd_eng_fired(sgp); 14917c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 14927c478bd9Sstevel@tonic-gate return (err); 14937c478bd9Sstevel@tonic-gate } 14947c478bd9Sstevel@tonic-gate 14957c478bd9Sstevel@tonic-gate int 14967c478bd9Sstevel@tonic-gate fmd_serd_empty(fmd_hdl_t *hdl, const char *name) 14977c478bd9Sstevel@tonic-gate { 14987c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 14997c478bd9Sstevel@tonic-gate fmd_serd_eng_t *sgp; 15007c478bd9Sstevel@tonic-gate int empty; 15017c478bd9Sstevel@tonic-gate 15027c478bd9Sstevel@tonic-gate if ((sgp = fmd_serd_eng_lookup(&mp->mod_serds, name)) == NULL) { 15037c478bd9Sstevel@tonic-gate fmd_api_error(mp, EFMD_SERD_NAME, 15047c478bd9Sstevel@tonic-gate "serd engine '%s' does not exist\n", name); 15057c478bd9Sstevel@tonic-gate } 15067c478bd9Sstevel@tonic-gate 15077c478bd9Sstevel@tonic-gate empty = fmd_serd_eng_empty(sgp); 15087c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 15097c478bd9Sstevel@tonic-gate return (empty); 15107c478bd9Sstevel@tonic-gate } 15117c478bd9Sstevel@tonic-gate 15127c478bd9Sstevel@tonic-gate pthread_t 15137c478bd9Sstevel@tonic-gate fmd_thr_create(fmd_hdl_t *hdl, void (*func)(void *), void *arg) 15147c478bd9Sstevel@tonic-gate { 15157c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 15167c478bd9Sstevel@tonic-gate fmd_thread_t *tp; 15177c478bd9Sstevel@tonic-gate pthread_t tid; 15187c478bd9Sstevel@tonic-gate 15197c478bd9Sstevel@tonic-gate if (mp->mod_stats->ms_thrtotal.fmds_value.ui32 >= 15207c478bd9Sstevel@tonic-gate mp->mod_stats->ms_thrlimit.fmds_value.ui32) { 15217c478bd9Sstevel@tonic-gate fmd_api_error(mp, EFMD_THR_LIMIT, "%s request to create an " 15227c478bd9Sstevel@tonic-gate "auxiliary thread exceeds module thread limit (%u)\n", 15237c478bd9Sstevel@tonic-gate mp->mod_name, mp->mod_stats->ms_thrlimit.fmds_value.ui32); 15247c478bd9Sstevel@tonic-gate } 15257c478bd9Sstevel@tonic-gate 15267c478bd9Sstevel@tonic-gate if ((tp = fmd_thread_create(mp, func, arg)) == NULL) { 15277c478bd9Sstevel@tonic-gate fmd_api_error(mp, EFMD_THR_CREATE, 15287c478bd9Sstevel@tonic-gate "failed to create auxiliary thread"); 15297c478bd9Sstevel@tonic-gate } 15307c478bd9Sstevel@tonic-gate 15317c478bd9Sstevel@tonic-gate tid = tp->thr_tid; 15327c478bd9Sstevel@tonic-gate mp->mod_stats->ms_thrtotal.fmds_value.ui32++; 15337c478bd9Sstevel@tonic-gate (void) fmd_idspace_xalloc(mp->mod_threads, tid, tp); 15347c478bd9Sstevel@tonic-gate 15357c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 15367c478bd9Sstevel@tonic-gate return (tid); 15377c478bd9Sstevel@tonic-gate } 15387c478bd9Sstevel@tonic-gate 15397c478bd9Sstevel@tonic-gate void 15407c478bd9Sstevel@tonic-gate fmd_thr_destroy(fmd_hdl_t *hdl, pthread_t tid) 15417c478bd9Sstevel@tonic-gate { 15427c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 15437c478bd9Sstevel@tonic-gate fmd_thread_t *tp; 15447c478bd9Sstevel@tonic-gate int err; 15457c478bd9Sstevel@tonic-gate 15467c478bd9Sstevel@tonic-gate if (pthread_self() == tid) { 15477c478bd9Sstevel@tonic-gate fmd_api_error(mp, EFMD_THR_INVAL, "auxiliary thread tried to " 15487c478bd9Sstevel@tonic-gate "destroy itself (tid %u)\n", tid); 15497c478bd9Sstevel@tonic-gate } 15507c478bd9Sstevel@tonic-gate 15517c478bd9Sstevel@tonic-gate if ((tp = fmd_idspace_getspecific(mp->mod_threads, tid)) == NULL) { 15527c478bd9Sstevel@tonic-gate fmd_api_error(mp, EFMD_THR_INVAL, "auxiliary thread tried to " 15537c478bd9Sstevel@tonic-gate "destroy an invalid thread (tid %u)\n", tid); 15547c478bd9Sstevel@tonic-gate } 15557c478bd9Sstevel@tonic-gate 15567c478bd9Sstevel@tonic-gate /* 15577c478bd9Sstevel@tonic-gate * Wait for the specified thread to exit and then join with it. Since 15587c478bd9Sstevel@tonic-gate * the thread may need to make API calls in order to complete its work 15597c478bd9Sstevel@tonic-gate * we must sleep with the module lock unheld, and then reacquire it. 15607c478bd9Sstevel@tonic-gate */ 15617c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 15627c478bd9Sstevel@tonic-gate err = pthread_join(tid, NULL); 15637c478bd9Sstevel@tonic-gate mp = fmd_api_module_lock(hdl); 15647c478bd9Sstevel@tonic-gate 15657c478bd9Sstevel@tonic-gate /* 15667c478bd9Sstevel@tonic-gate * Since pthread_join() was called without the module lock held, if 15677c478bd9Sstevel@tonic-gate * multiple callers attempted to destroy the same auxiliary thread 15687c478bd9Sstevel@tonic-gate * simultaneously, one will succeed and the others will get ESRCH. 15697c478bd9Sstevel@tonic-gate * Therefore we silently ignore ESRCH but only allow the caller who 15707c478bd9Sstevel@tonic-gate * succeessfully joined with the auxiliary thread to destroy it. 15717c478bd9Sstevel@tonic-gate */ 15727c478bd9Sstevel@tonic-gate if (err != 0 && err != ESRCH) { 15737c478bd9Sstevel@tonic-gate fmd_api_error(mp, EFMD_THR_JOIN, 15747c478bd9Sstevel@tonic-gate "failed to join with auxiliary thread %u\n", tid); 15757c478bd9Sstevel@tonic-gate } 15767c478bd9Sstevel@tonic-gate 15777c478bd9Sstevel@tonic-gate if (err == 0) { 15787c478bd9Sstevel@tonic-gate fmd_thread_destroy(tp, FMD_THREAD_NOJOIN); 15797c478bd9Sstevel@tonic-gate mp->mod_stats->ms_thrtotal.fmds_value.ui32--; 15807c478bd9Sstevel@tonic-gate (void) fmd_idspace_free(mp->mod_threads, tid); 15817c478bd9Sstevel@tonic-gate } 15827c478bd9Sstevel@tonic-gate 15837c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 15847c478bd9Sstevel@tonic-gate } 15857c478bd9Sstevel@tonic-gate 15867c478bd9Sstevel@tonic-gate void 15877c478bd9Sstevel@tonic-gate fmd_thr_signal(fmd_hdl_t *hdl, pthread_t tid) 15887c478bd9Sstevel@tonic-gate { 15897c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 15907c478bd9Sstevel@tonic-gate 15917c478bd9Sstevel@tonic-gate if (tid != mp->mod_thread->thr_tid && 15927c478bd9Sstevel@tonic-gate fmd_idspace_getspecific(mp->mod_threads, tid) == NULL) { 15937c478bd9Sstevel@tonic-gate fmd_api_error(mp, EFMD_THR_INVAL, "tid %u is not a valid " 15947c478bd9Sstevel@tonic-gate "thread id for module %s\n", tid, mp->mod_name); 15957c478bd9Sstevel@tonic-gate } 15967c478bd9Sstevel@tonic-gate 15977c478bd9Sstevel@tonic-gate (void) pthread_kill(tid, fmd.d_thr_sig); 15987c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 15997c478bd9Sstevel@tonic-gate } 16007c478bd9Sstevel@tonic-gate 16017c478bd9Sstevel@tonic-gate id_t 16027c478bd9Sstevel@tonic-gate fmd_timer_install(fmd_hdl_t *hdl, void *arg, fmd_event_t *ep, hrtime_t delta) 16037c478bd9Sstevel@tonic-gate { 16047c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 16057c478bd9Sstevel@tonic-gate fmd_modtimer_t *t; 16067c478bd9Sstevel@tonic-gate id_t id; 16077c478bd9Sstevel@tonic-gate 16087c478bd9Sstevel@tonic-gate if (delta < 0) { 16097c478bd9Sstevel@tonic-gate fmd_api_error(mp, EFMD_TIMER_INVAL, 16107c478bd9Sstevel@tonic-gate "timer delta %lld is not a valid interval\n", delta); 16117c478bd9Sstevel@tonic-gate } 16127c478bd9Sstevel@tonic-gate 16137c478bd9Sstevel@tonic-gate t = fmd_alloc(sizeof (fmd_modtimer_t), FMD_SLEEP); 16147c478bd9Sstevel@tonic-gate t->mt_mod = mp; 16157c478bd9Sstevel@tonic-gate t->mt_arg = arg; 16167c478bd9Sstevel@tonic-gate t->mt_id = -1; 16177c478bd9Sstevel@tonic-gate 16187c478bd9Sstevel@tonic-gate if ((id = fmd_timerq_install(fmd.d_timers, mp->mod_timerids, 16197c478bd9Sstevel@tonic-gate (fmd_timer_f *)fmd_module_timeout, t, ep, delta)) == -1) { 16207c478bd9Sstevel@tonic-gate fmd_free(t, sizeof (fmd_modtimer_t)); 16217c478bd9Sstevel@tonic-gate fmd_api_error(mp, EFMD_TIMER_LIMIT, 16227c478bd9Sstevel@tonic-gate "failed to install timer +%lld", delta); 16237c478bd9Sstevel@tonic-gate } 16247c478bd9Sstevel@tonic-gate 16257c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 16267c478bd9Sstevel@tonic-gate return (id); 16277c478bd9Sstevel@tonic-gate } 16287c478bd9Sstevel@tonic-gate 16297c478bd9Sstevel@tonic-gate void 16307c478bd9Sstevel@tonic-gate fmd_timer_remove(fmd_hdl_t *hdl, id_t id) 16317c478bd9Sstevel@tonic-gate { 16327c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 16337c478bd9Sstevel@tonic-gate fmd_modtimer_t *t; 16347c478bd9Sstevel@tonic-gate 16357c478bd9Sstevel@tonic-gate if (!fmd_idspace_valid(mp->mod_timerids, id)) { 16367c478bd9Sstevel@tonic-gate fmd_api_error(mp, EFMD_TIMER_INVAL, 16377c478bd9Sstevel@tonic-gate "id %ld is not a valid timer id\n", id); 16387c478bd9Sstevel@tonic-gate } 16397c478bd9Sstevel@tonic-gate 16407c478bd9Sstevel@tonic-gate t = fmd_timerq_remove(fmd.d_timers, mp->mod_timerids, id); 16417c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 16427c478bd9Sstevel@tonic-gate 16437c478bd9Sstevel@tonic-gate if (t != NULL) { 16447c478bd9Sstevel@tonic-gate fmd_eventq_cancel(mp->mod_queue, FMD_EVT_TIMEOUT, t); 16457c478bd9Sstevel@tonic-gate fmd_free(t, sizeof (fmd_modtimer_t)); 16467c478bd9Sstevel@tonic-gate } 16477c478bd9Sstevel@tonic-gate } 16487c478bd9Sstevel@tonic-gate 16497c478bd9Sstevel@tonic-gate nvlist_t * 16507c478bd9Sstevel@tonic-gate fmd_nvl_create_fault(fmd_hdl_t *hdl, const char *class, 16517c478bd9Sstevel@tonic-gate uint8_t certainty, nvlist_t *asru, nvlist_t *fru, nvlist_t *rsrc) 16527c478bd9Sstevel@tonic-gate { 16537c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 16547c478bd9Sstevel@tonic-gate nvlist_t *nvl; 16557c478bd9Sstevel@tonic-gate 16567c478bd9Sstevel@tonic-gate if (class == NULL || class[0] == '\0') 16577c478bd9Sstevel@tonic-gate fmd_api_error(mp, EFMD_NVL_INVAL, "invalid fault class\n"); 16587c478bd9Sstevel@tonic-gate 16597c478bd9Sstevel@tonic-gate nvl = fmd_protocol_fault(class, certainty, asru, fru, rsrc); 16607c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 16617c478bd9Sstevel@tonic-gate return (nvl); 16627c478bd9Sstevel@tonic-gate } 16637c478bd9Sstevel@tonic-gate 16647c478bd9Sstevel@tonic-gate int 16657c478bd9Sstevel@tonic-gate fmd_nvl_class_match(fmd_hdl_t *hdl, nvlist_t *nvl, const char *pattern) 16667c478bd9Sstevel@tonic-gate { 16677c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 16687c478bd9Sstevel@tonic-gate char *class; 16697c478bd9Sstevel@tonic-gate int rv; 16707c478bd9Sstevel@tonic-gate 16717c478bd9Sstevel@tonic-gate rv = (nvl != NULL && nvlist_lookup_string(nvl, 16727c478bd9Sstevel@tonic-gate FM_CLASS, &class) == 0 && fmd_strmatch(class, pattern)); 16737c478bd9Sstevel@tonic-gate 16747c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 16757c478bd9Sstevel@tonic-gate return (rv); 16767c478bd9Sstevel@tonic-gate } 16777c478bd9Sstevel@tonic-gate 16787c478bd9Sstevel@tonic-gate int 16797c478bd9Sstevel@tonic-gate fmd_nvl_fmri_expand(fmd_hdl_t *hdl, nvlist_t *nvl) 16807c478bd9Sstevel@tonic-gate { 16817c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 16827c478bd9Sstevel@tonic-gate int rv; 16837c478bd9Sstevel@tonic-gate 16847c478bd9Sstevel@tonic-gate if (nvl == NULL) { 16857c478bd9Sstevel@tonic-gate fmd_api_error(mp, EFMD_NVL_INVAL, 16867c478bd9Sstevel@tonic-gate "invalid nvlist %p\n", (void *)nvl); 16877c478bd9Sstevel@tonic-gate } 16887c478bd9Sstevel@tonic-gate 16897c478bd9Sstevel@tonic-gate rv = fmd_fmri_expand(nvl); 16907c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 16917c478bd9Sstevel@tonic-gate return (rv); 16927c478bd9Sstevel@tonic-gate } 16937c478bd9Sstevel@tonic-gate 16947c478bd9Sstevel@tonic-gate int 16957c478bd9Sstevel@tonic-gate fmd_nvl_fmri_present(fmd_hdl_t *hdl, nvlist_t *nvl) 16967c478bd9Sstevel@tonic-gate { 16977c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 16987c478bd9Sstevel@tonic-gate int rv; 16997c478bd9Sstevel@tonic-gate 17007c478bd9Sstevel@tonic-gate if (nvl == NULL) { 17017c478bd9Sstevel@tonic-gate fmd_api_error(mp, EFMD_NVL_INVAL, 17027c478bd9Sstevel@tonic-gate "invalid nvlist %p\n", (void *)nvl); 17037c478bd9Sstevel@tonic-gate } 17047c478bd9Sstevel@tonic-gate 17057c478bd9Sstevel@tonic-gate rv = fmd_fmri_present(nvl); 17067c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 17077c478bd9Sstevel@tonic-gate 17087c478bd9Sstevel@tonic-gate if (rv < 0) { 17097c478bd9Sstevel@tonic-gate fmd_api_error(mp, EFMD_FMRI_OP, "invalid fmri for " 17107c478bd9Sstevel@tonic-gate "fmd_nvl_fmri_present\n"); 17117c478bd9Sstevel@tonic-gate } 17127c478bd9Sstevel@tonic-gate 17137c478bd9Sstevel@tonic-gate return (rv); 17147c478bd9Sstevel@tonic-gate } 17157c478bd9Sstevel@tonic-gate 17167c478bd9Sstevel@tonic-gate int 17177c478bd9Sstevel@tonic-gate fmd_nvl_fmri_unusable(fmd_hdl_t *hdl, nvlist_t *nvl) 17187c478bd9Sstevel@tonic-gate { 17197c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 17207c478bd9Sstevel@tonic-gate int rv; 17217c478bd9Sstevel@tonic-gate 17227c478bd9Sstevel@tonic-gate if (nvl == NULL) { 17237c478bd9Sstevel@tonic-gate fmd_api_error(mp, EFMD_NVL_INVAL, 17247c478bd9Sstevel@tonic-gate "invalid nvlist %p\n", (void *)nvl); 17257c478bd9Sstevel@tonic-gate } 17267c478bd9Sstevel@tonic-gate 17277c478bd9Sstevel@tonic-gate rv = fmd_fmri_unusable(nvl); 17287c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 17297c478bd9Sstevel@tonic-gate 17307c478bd9Sstevel@tonic-gate if (rv < 0) { 17317c478bd9Sstevel@tonic-gate fmd_api_error(mp, EFMD_FMRI_OP, "invalid fmri for " 17327c478bd9Sstevel@tonic-gate "fmd_nvl_fmri_unusable\n"); 17337c478bd9Sstevel@tonic-gate } 17347c478bd9Sstevel@tonic-gate 17357c478bd9Sstevel@tonic-gate return (rv); 17367c478bd9Sstevel@tonic-gate } 17377c478bd9Sstevel@tonic-gate 17387c478bd9Sstevel@tonic-gate int 1739*7aec1d6eScindi fmd_nvl_fmri_faulty(fmd_hdl_t *hdl, nvlist_t *nvl) 1740*7aec1d6eScindi { 1741*7aec1d6eScindi fmd_module_t *mp = fmd_api_module_lock(hdl); 1742*7aec1d6eScindi fmd_asru_hash_t *ahp = fmd.d_asrus; 1743*7aec1d6eScindi fmd_asru_t *ap; 1744*7aec1d6eScindi int rv = 0; 1745*7aec1d6eScindi 1746*7aec1d6eScindi if (nvl == NULL) { 1747*7aec1d6eScindi fmd_api_error(mp, EFMD_NVL_INVAL, 1748*7aec1d6eScindi "invalid nvlist %p\n", (void *)nvl); 1749*7aec1d6eScindi } 1750*7aec1d6eScindi 1751*7aec1d6eScindi if ((ap = fmd_asru_hash_lookup_nvl(ahp, nvl, FMD_B_FALSE)) != NULL) { 1752*7aec1d6eScindi rv = (ap->asru_flags & FMD_ASRU_FAULTY) != 0; 1753*7aec1d6eScindi fmd_asru_hash_release(ahp, ap); 1754*7aec1d6eScindi } 1755*7aec1d6eScindi 1756*7aec1d6eScindi fmd_module_unlock(mp); 1757*7aec1d6eScindi return (rv); 1758*7aec1d6eScindi } 1759*7aec1d6eScindi 1760*7aec1d6eScindi int 17617c478bd9Sstevel@tonic-gate fmd_nvl_fmri_contains(fmd_hdl_t *hdl, nvlist_t *n1, nvlist_t *n2) 17627c478bd9Sstevel@tonic-gate { 17637c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_api_module_lock(hdl); 17647c478bd9Sstevel@tonic-gate int rv; 17657c478bd9Sstevel@tonic-gate 17667c478bd9Sstevel@tonic-gate if (n1 == NULL || n2 == NULL) { 17677c478bd9Sstevel@tonic-gate fmd_api_error(mp, EFMD_NVL_INVAL, 17687c478bd9Sstevel@tonic-gate "invalid nvlist(s): %p, %p\n", (void *)n1, (void *)n2); 17697c478bd9Sstevel@tonic-gate } 17707c478bd9Sstevel@tonic-gate 17717c478bd9Sstevel@tonic-gate rv = fmd_fmri_contains(n1, n2); 17727c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 17737c478bd9Sstevel@tonic-gate 17747c478bd9Sstevel@tonic-gate if (rv < 0) { 17757c478bd9Sstevel@tonic-gate fmd_api_error(mp, EFMD_FMRI_OP, "invalid fmri for " 17767c478bd9Sstevel@tonic-gate "fmd_nvl_fmri_contains\n"); 17777c478bd9Sstevel@tonic-gate } 17787c478bd9Sstevel@tonic-gate 17797c478bd9Sstevel@tonic-gate return (rv); 17807c478bd9Sstevel@tonic-gate } 1781d9638e54Smws 1782d9638e54Smws nvlist_t * 1783d9638e54Smws fmd_nvl_fmri_translate(fmd_hdl_t *hdl, nvlist_t *fmri, nvlist_t *auth) 1784d9638e54Smws { 1785d9638e54Smws fmd_module_t *mp = fmd_api_module_lock(hdl); 1786d9638e54Smws nvlist_t *xfmri; 1787d9638e54Smws 1788d9638e54Smws if (fmri == NULL || auth == NULL) { 1789d9638e54Smws fmd_api_error(mp, EFMD_NVL_INVAL, 1790d9638e54Smws "invalid nvlist(s): %p, %p\n", (void *)fmri, (void *)auth); 1791d9638e54Smws } 1792d9638e54Smws 1793d9638e54Smws xfmri = fmd_fmri_translate(fmri, auth); 1794d9638e54Smws fmd_module_unlock(mp); 1795d9638e54Smws return (xfmri); 1796d9638e54Smws } 1797d9638e54Smws 1798d9638e54Smws int 1799d9638e54Smws fmd_event_local(fmd_hdl_t *hdl, fmd_event_t *ep) 1800d9638e54Smws { 1801d9638e54Smws if (hdl == NULL || ep == NULL) { 1802d9638e54Smws fmd_api_error(fmd_api_module_lock(hdl), EFMD_EVENT_INVAL, 1803d9638e54Smws "NULL parameter specified to fmd_event_local\n"); 1804d9638e54Smws } 1805d9638e54Smws 1806d9638e54Smws return (((fmd_event_impl_t *)ep)->ev_flags & FMD_EVF_LOCAL); 1807d9638e54Smws } 1808d9638e54Smws 1809d9638e54Smws fmd_xprt_t * 1810d9638e54Smws fmd_xprt_open(fmd_hdl_t *hdl, uint_t flags, nvlist_t *auth, void *data) 1811d9638e54Smws { 1812d9638e54Smws fmd_module_t *mp = fmd_api_module_lock(hdl); 1813d9638e54Smws fmd_xprt_t *xp; 1814d9638e54Smws 1815d9638e54Smws if (flags & ~FMD_XPRT_CMASK) { 1816d9638e54Smws fmd_api_error(mp, EFMD_XPRT_INVAL, 1817d9638e54Smws "invalid transport flags 0x%x\n", flags); 1818d9638e54Smws } 1819d9638e54Smws 1820d9638e54Smws if ((flags & FMD_XPRT_RDWR) != FMD_XPRT_RDWR && 1821d9638e54Smws (flags & FMD_XPRT_RDWR) != FMD_XPRT_RDONLY) { 1822d9638e54Smws fmd_api_error(mp, EFMD_XPRT_INVAL, 1823d9638e54Smws "cannot open write-only transport\n"); 1824d9638e54Smws } 1825d9638e54Smws 1826d9638e54Smws if (mp->mod_stats->ms_xprtopen.fmds_value.ui32 >= 1827d9638e54Smws mp->mod_stats->ms_xprtlimit.fmds_value.ui32) { 1828d9638e54Smws fmd_api_error(mp, EFMD_XPRT_LIMIT, "%s request to create a " 1829d9638e54Smws "transport exceeds module transport limit (%u)\n", 1830d9638e54Smws mp->mod_name, mp->mod_stats->ms_xprtlimit.fmds_value.ui32); 1831d9638e54Smws } 1832d9638e54Smws 1833d9638e54Smws if ((xp = fmd_xprt_create(mp, flags, auth, data)) == NULL) 1834d9638e54Smws fmd_api_error(mp, errno, "cannot create transport"); 1835d9638e54Smws 1836d9638e54Smws fmd_module_unlock(mp); 1837d9638e54Smws return (xp); 1838d9638e54Smws } 1839d9638e54Smws 1840d9638e54Smws void 1841d9638e54Smws fmd_xprt_close(fmd_hdl_t *hdl, fmd_xprt_t *xp) 1842d9638e54Smws { 1843d9638e54Smws fmd_module_t *mp = fmd_api_module_lock(hdl); 1844d9638e54Smws fmd_xprt_impl_t *xip = fmd_api_transport_impl(hdl, xp); 1845d9638e54Smws 1846d9638e54Smws /* 1847d9638e54Smws * Although this could be supported, it doesn't seem necessary or worth 1848d9638e54Smws * the trouble. For now, just detect this and trigger a module abort. 1849d9638e54Smws * If it is needed, transports should grow reference counts and a new 1850d9638e54Smws * event type will need to be enqueued for the main thread to reap it. 1851d9638e54Smws */ 1852d9638e54Smws if (xip->xi_thread != NULL && 1853d9638e54Smws xip->xi_thread->thr_tid == pthread_self()) { 1854d9638e54Smws fmd_api_error(mp, EFMD_XPRT_INVAL, 1855d9638e54Smws "fmd_xprt_close() cannot be called from fmdo_send()\n"); 1856d9638e54Smws } 1857d9638e54Smws 1858d9638e54Smws fmd_xprt_destroy(xp); 1859d9638e54Smws fmd_module_unlock(mp); 1860d9638e54Smws } 1861d9638e54Smws 1862d9638e54Smws void 1863d9638e54Smws fmd_xprt_post(fmd_hdl_t *hdl, fmd_xprt_t *xp, nvlist_t *nvl, hrtime_t hrt) 1864d9638e54Smws { 1865d9638e54Smws fmd_xprt_impl_t *xip = fmd_api_transport_impl(hdl, xp); 1866d9638e54Smws 1867d9638e54Smws /* 1868d9638e54Smws * fmd_xprt_recv() must block during startup waiting for fmd to globally 1869d9638e54Smws * clear FMD_XPRT_DSUSPENDED. As such, we can't allow it to be called 1870d9638e54Smws * from a module's _fmd_init() routine, because that would block 1871d9638e54Smws * fmd from completing initial module loading, resulting in a deadlock. 1872d9638e54Smws */ 1873d9638e54Smws if ((xip->xi_flags & FMD_XPRT_ISUSPENDED) && 1874d9638e54Smws (pthread_self() == xip->xi_queue->eq_mod->mod_thread->thr_tid)) { 1875d9638e54Smws fmd_api_error(fmd_api_module_lock(hdl), EFMD_XPRT_INVAL, 1876d9638e54Smws "fmd_xprt_post() cannot be called from _fmd_init()\n"); 1877d9638e54Smws } 1878d9638e54Smws 1879d9638e54Smws fmd_xprt_recv(xp, nvl, hrt); 1880d9638e54Smws } 1881d9638e54Smws 1882d9638e54Smws void 1883d9638e54Smws fmd_xprt_suspend(fmd_hdl_t *hdl, fmd_xprt_t *xp) 1884d9638e54Smws { 1885d9638e54Smws (void) fmd_api_transport_impl(hdl, xp); /* validate 'xp' */ 1886d9638e54Smws fmd_xprt_xsuspend(xp, FMD_XPRT_SUSPENDED); 1887d9638e54Smws } 1888d9638e54Smws 1889d9638e54Smws void 1890d9638e54Smws fmd_xprt_resume(fmd_hdl_t *hdl, fmd_xprt_t *xp) 1891d9638e54Smws { 1892d9638e54Smws (void) fmd_api_transport_impl(hdl, xp); /* validate 'xp' */ 1893d9638e54Smws fmd_xprt_xresume(xp, FMD_XPRT_SUSPENDED); 1894d9638e54Smws } 1895d9638e54Smws 1896d9638e54Smws int 1897d9638e54Smws fmd_xprt_error(fmd_hdl_t *hdl, fmd_xprt_t *xp) 1898d9638e54Smws { 1899d9638e54Smws fmd_xprt_impl_t *xip = fmd_api_transport_impl(hdl, xp); 1900d9638e54Smws return (xip->xi_state == _fmd_xprt_state_err); 1901d9638e54Smws } 1902d9638e54Smws 1903d9638e54Smws /* 1904d9638e54Smws * Translate all FMRIs in the specified name-value pair list for the specified 1905d9638e54Smws * FMRI authority, and return a new name-value pair list for the translation. 1906d9638e54Smws * This function is the recursive engine used by fmd_xprt_translate(), below. 1907d9638e54Smws */ 1908d9638e54Smws static nvlist_t * 1909d9638e54Smws fmd_xprt_xtranslate(nvlist_t *nvl, nvlist_t *auth) 1910d9638e54Smws { 1911d9638e54Smws uint_t i, j, n; 1912d9638e54Smws nvpair_t *nvp, **nvps; 1913d9638e54Smws uint_t nvpslen = 0; 1914d9638e54Smws char *name; 1915d9638e54Smws size_t namelen = 0; 1916d9638e54Smws 1917d9638e54Smws nvlist_t **a, **b; 1918d9638e54Smws nvlist_t *l, *r; 1919d9638e54Smws data_type_t type; 1920d9638e54Smws char *s; 1921d9638e54Smws int err; 1922d9638e54Smws 1923d9638e54Smws (void) nvlist_xdup(nvl, &nvl, &fmd.d_nva); 1924d9638e54Smws 1925d9638e54Smws /* 1926d9638e54Smws * Count up the number of name-value pairs in 'nvl' and compute the 1927d9638e54Smws * maximum length of a name used in this list for use below. 1928d9638e54Smws */ 1929d9638e54Smws for (nvp = nvlist_next_nvpair(nvl, NULL); 1930d9638e54Smws nvp != NULL; nvp = nvlist_next_nvpair(nvl, nvp), nvpslen++) { 1931d9638e54Smws size_t len = strlen(nvpair_name(nvp)); 1932d9638e54Smws namelen = MAX(namelen, len); 1933d9638e54Smws } 1934d9638e54Smws 1935d9638e54Smws nvps = alloca(sizeof (nvpair_t *) * nvpslen); 1936d9638e54Smws name = alloca(namelen + 1); 1937d9638e54Smws 1938d9638e54Smws /* 1939d9638e54Smws * Store a snapshot of the name-value pairs in 'nvl' into nvps[] so 1940d9638e54Smws * that we can iterate over the original pairs in the loop below while 1941d9638e54Smws * performing arbitrary insert and delete operations on 'nvl' itself. 1942d9638e54Smws */ 1943d9638e54Smws for (i = 0, nvp = nvlist_next_nvpair(nvl, NULL); 1944d9638e54Smws nvp != NULL; nvp = nvlist_next_nvpair(nvl, nvp)) 1945d9638e54Smws nvps[i++] = nvp; 1946d9638e54Smws 1947d9638e54Smws /* 1948d9638e54Smws * Now iterate over the snapshot of the name-value pairs. If we find a 1949d9638e54Smws * value that is of type NVLIST or NVLIST_ARRAY, we translate that 1950d9638e54Smws * object by either calling ourself recursively on it, or calling into 1951d9638e54Smws * fmd_fmri_translate() if the object is an FMRI. We then rip out the 1952d9638e54Smws * original name-value pair and replace it with the translated one. 1953d9638e54Smws */ 1954d9638e54Smws for (i = 0; i < nvpslen; i++) { 1955d9638e54Smws nvp = nvps[i]; 1956d9638e54Smws type = nvpair_type(nvp); 1957d9638e54Smws 1958d9638e54Smws switch (type) { 1959d9638e54Smws case DATA_TYPE_NVLIST_ARRAY: 1960d9638e54Smws if (nvpair_value_nvlist_array(nvp, &a, &n) != 0 || 1961d9638e54Smws a == NULL || n == 0) 1962d9638e54Smws continue; /* array is zero-sized; skip it */ 1963d9638e54Smws 1964d9638e54Smws b = fmd_alloc(sizeof (nvlist_t *) * n, FMD_SLEEP); 1965d9638e54Smws 1966d9638e54Smws /* 1967d9638e54Smws * If the first array nvlist element looks like an FMRI 1968d9638e54Smws * then assume the other elements are FMRIs as well. 1969d9638e54Smws * If any b[j]'s can't be translated, then EINVAL will 1970d9638e54Smws * be returned from nvlist_add_nvlist_array() below. 1971d9638e54Smws */ 1972d9638e54Smws if (nvlist_lookup_string(*a, FM_FMRI_SCHEME, &s) == 0) { 1973d9638e54Smws for (j = 0; j < n; j++) 1974d9638e54Smws b[j] = fmd_fmri_translate(a[j], auth); 1975d9638e54Smws } else { 1976d9638e54Smws for (j = 0; j < n; j++) 1977d9638e54Smws b[j] = fmd_xprt_xtranslate(a[j], auth); 1978d9638e54Smws } 1979d9638e54Smws 1980d9638e54Smws (void) strcpy(name, nvpair_name(nvp)); 1981d9638e54Smws (void) nvlist_remove(nvl, name, type); 1982d9638e54Smws err = nvlist_add_nvlist_array(nvl, name, b, n); 1983d9638e54Smws 1984d9638e54Smws for (j = 0; j < n; j++) 1985d9638e54Smws nvlist_free(b[j]); 1986d9638e54Smws 1987d9638e54Smws fmd_free(b, sizeof (nvlist_t *) * n); 1988d9638e54Smws 1989d9638e54Smws if (err != 0) { 1990d9638e54Smws nvlist_free(nvl); 1991d9638e54Smws errno = err; 1992d9638e54Smws return (NULL); 1993d9638e54Smws } 1994d9638e54Smws break; 1995d9638e54Smws 1996d9638e54Smws case DATA_TYPE_NVLIST: 1997d9638e54Smws if (nvpair_value_nvlist(nvp, &l) == 0 && 1998d9638e54Smws nvlist_lookup_string(l, FM_FMRI_SCHEME, &s) == 0) 1999d9638e54Smws r = fmd_fmri_translate(l, auth); 2000d9638e54Smws else 2001d9638e54Smws r = fmd_xprt_xtranslate(l, auth); 2002d9638e54Smws 2003d9638e54Smws if (r == NULL) { 2004d9638e54Smws nvlist_free(nvl); 2005d9638e54Smws return (NULL); 2006d9638e54Smws } 2007d9638e54Smws 2008d9638e54Smws (void) strcpy(name, nvpair_name(nvp)); 2009d9638e54Smws (void) nvlist_remove(nvl, name, type); 2010d9638e54Smws (void) nvlist_add_nvlist(nvl, name, r); 2011d9638e54Smws 2012d9638e54Smws nvlist_free(r); 2013d9638e54Smws break; 2014d9638e54Smws } 2015d9638e54Smws } 2016d9638e54Smws 2017d9638e54Smws return (nvl); 2018d9638e54Smws } 2019d9638e54Smws 2020d9638e54Smws nvlist_t * 2021d9638e54Smws fmd_xprt_translate(fmd_hdl_t *hdl, fmd_xprt_t *xp, fmd_event_t *ep) 2022d9638e54Smws { 2023d9638e54Smws fmd_xprt_impl_t *xip = fmd_api_transport_impl(hdl, xp); 2024d9638e54Smws 2025d9638e54Smws if (xip->xi_auth == NULL) { 2026d9638e54Smws fmd_api_error(fmd_api_module_lock(hdl), EFMD_XPRT_INVAL, 2027d9638e54Smws "no authority defined for transport %p\n", (void *)xp); 2028d9638e54Smws } 2029d9638e54Smws 2030d9638e54Smws return (fmd_xprt_xtranslate(FMD_EVENT_NVL(ep), xip->xi_auth)); 2031d9638e54Smws } 2032d9638e54Smws 2033d9638e54Smws void 2034d9638e54Smws fmd_xprt_setspecific(fmd_hdl_t *hdl, fmd_xprt_t *xp, void *data) 2035d9638e54Smws { 2036d9638e54Smws fmd_api_transport_impl(hdl, xp)->xi_data = data; 2037d9638e54Smws } 2038d9638e54Smws 2039d9638e54Smws void * 2040d9638e54Smws fmd_xprt_getspecific(fmd_hdl_t *hdl, fmd_xprt_t *xp) 2041d9638e54Smws { 2042d9638e54Smws return (fmd_api_transport_impl(hdl, xp)->xi_data); 2043d9638e54Smws } 2044