/* * To implement a reasonable panic() equivalent for fmd, we atomically bump a * global counter of calls to fmd_vpanic() and attempt to print a panic message * to stderr and dump core as a result of raising SIGABRT. This function must * not attempt to grab any locks so that it can be called from any fmd code. */ void fmd_vpanic(const char *format, va_list ap) { int oserr = errno; pthread_t tid = pthread_self(); fmd_thread_t *tp; char msg[BUFSIZ]; size_t len; /* * If this is not the first call to fmd_vpanic(), then check d_panictid * to see if we are the panic thread. If so, then proceed directly to * abort() because we have recursively panicked. If not, then pause() * indefinitely waiting for the panic thread to terminate the daemon. */ if (atomic_add_32_nv(&fmd.d_panicrefs, 1) != 1) { while (fmd.d_panictid != tid) (void) pause(); goto abort; } /* * Use fmd.d_pid != 0 as a cheap test to see if fmd.d_key is valid * (i.e. we're after fmd_create() and before fmd_destroy()). */ if (fmd.d_pid != 0 && (tp = pthread_getspecific(fmd.d_key)) != NULL) (void) tp->thr_trfunc(tp->thr_trdata, FMD_DBG_ERR, format, ap); fmd.d_panicstr = msg; fmd.d_panictid = tid; (void) snprintf(msg, sizeof (msg), "%s: ABORT: ", fmd.d_pname ? fmd.d_pname : "fmd"); len = strlen(msg); (void) vsnprintf(msg + len, sizeof (msg) - len, format, ap); if (strchr(format, '\n') == NULL) { len = strlen(msg); (void) snprintf(msg + len, sizeof (msg) - len, ": %s\n", fmd_strerror(oserr)); } (void) write(STDERR_FILENO, msg, strlen(msg)); abort: abort(); _exit(FMD_EXIT_ERROR); }
void fmd_verror(int err, const char *format, va_list ap) { int oserr = errno; fmd_thread_t *tp; nvlist_t *nvl; fmd_event_t *e; char *class; if ((tp = pthread_getspecific(fmd.d_key)) != NULL) { (void) tp->thr_trfunc(tp->thr_trdata, FMD_DBG_ERR, format, ap); tp->thr_errdepth++; } (void) pthread_mutex_lock(&fmd.d_err_lock); if (fmd.d_errstats != NULL && err >= EFMD_UNKNOWN && err < EFMD_END) fmd.d_errstats[err - EFMD_UNKNOWN].fmds_value.ui64++; if (fmd.d_fg || !fmd.d_running) { (void) fprintf(stderr, "%s: ", fmd.d_pname); (void) vfprintf(stderr, format, ap); if (strchr(format, '\n') == NULL) (void) fprintf(stderr, ": %s\n", fmd_strerror(oserr)); } (void) pthread_mutex_unlock(&fmd.d_err_lock); /* * If we are at error nesting level one and running in the background, * log the error as an ereport to our own log and dispatch it. If the * FMD_LF_BUSY flag is set, we can't attempt to log the event because * a replay is running and we will deadlock on ourself in log_append. */ if (!fmd.d_fg && fmd.d_running && tp != NULL && tp->thr_errdepth == 1 && (nvl = fmd_protocol_fmderror(err, format, ap)) != NULL) { (void) nvlist_lookup_string(nvl, FM_CLASS, &class); e = fmd_event_create(FMD_EVT_PROTOCOL, FMD_HRT_NOW, nvl, class); (void) pthread_rwlock_rdlock(&fmd.d_log_lock); if (!(fmd.d_errlog->log_flags & FMD_LF_BUSY)) fmd_log_append(fmd.d_errlog, e, NULL); (void) pthread_rwlock_unlock(&fmd.d_log_lock); fmd_dispq_dispatch(fmd.d_disp, e, class); }
static int fmd_ckpt_restore_suspects(fmd_ckpt_t *ckp, fmd_case_t *cp, fcf_secidx_t sid) { const fcf_nvl_t *fcfn, *endn; const fcf_sec_t *sp; nvlist_t *nvl; int err, i; if ((sp = fmd_ckpt_secptr(ckp, sid, FCF_SECT_NVLISTS)) == NULL) { fmd_ckpt_error(ckp, EFMD_CKPT_INVAL, "invalid link to section %u: expected nvlists\n", sid); } fcfn = fmd_ckpt_dataptr(ckp, sp); endn = fmd_ckpt_datalim(ckp, sp); for (i = 0; fcfn < endn; i++) { char *data = (char *)fcfn + sp->fcfs_entsize; size_t size = (size_t)fcfn->fcfn_size; if (fcfn->fcfn_size > (size_t)((char *)endn - data)) { fmd_ckpt_error(ckp, EFMD_CKPT_INVAL, "nvlist %u [%d] " "size %u exceeds buffer\n", sid, i, size); } if ((err = nvlist_xunpack(data, size, &nvl, &fmd.d_nva)) != 0) { fmd_ckpt_error(ckp, EFMD_CKPT_INVAL, "failed to " "unpack nvlist %u [%d]: %s\n", sid, i, fmd_strerror(err)); } fmd_case_insert_suspect(cp, nvl); size = sp->fcfs_entsize + fcfn->fcfn_size; size = P2ROUNDUP(size, sizeof (uint64_t)); fcfn = (fcf_nvl_t *)((uintptr_t)fcfn + size); } return (i); }