예제 #1
0
/*
 * 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);
}
예제 #2
0
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);
    }
예제 #3
0
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);
}