4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
39 #include <fmd_error.h>
40 #include <fmd_thread.h>
41 #include <fmd_protocol.h>
42 #include <fmd_event.h>
43 #include <fmd_dispq.h>
49 fmd_assert(const char *expr
, const char *file
, int line
)
51 fmd_panic("\"%s\", line %d: assertion failed: %s\n", file
, line
, expr
);
57 * To implement a reasonable panic() equivalent for fmd, we atomically bump a
58 * global counter of calls to fmd_vpanic() and attempt to print a panic message
59 * to stderr and dump core as a result of raising SIGABRT. This function must
60 * not attempt to grab any locks so that it can be called from any fmd code.
63 fmd_vpanic(const char *format
, va_list ap
)
66 pthread_t tid
= pthread_self();
73 * If this is not the first call to fmd_vpanic(), then check d_panictid
74 * to see if we are the panic thread. If so, then proceed directly to
75 * abort() because we have recursively panicked. If not, then pause()
76 * indefinitely waiting for the panic thread to terminate the daemon.
78 if (atomic_add_32_nv(&fmd
.d_panicrefs
, 1) != 1) {
79 while (fmd
.d_panictid
!= tid
)
85 * Use fmd.d_pid != 0 as a cheap test to see if fmd.d_key is valid
86 * (i.e. we're after fmd_create() and before fmd_destroy()).
88 if (fmd
.d_pid
!= 0 && (tp
= pthread_getspecific(fmd
.d_key
)) != NULL
)
89 (void) tp
->thr_trfunc(tp
->thr_trdata
, FMD_DBG_ERR
, format
, ap
);
94 (void) snprintf(msg
, sizeof (msg
), "%s: ABORT: ",
95 fmd
.d_pname
? fmd
.d_pname
: "fmd");
98 (void) vsnprintf(msg
+ len
, sizeof (msg
) - len
, format
, ap
);
100 if (strchr(format
, '\n') == NULL
) {
102 (void) snprintf(msg
+ len
, sizeof (msg
) - len
, ": %s\n",
103 fmd_strerror(oserr
));
106 (void) write(STDERR_FILENO
, msg
, strlen(msg
));
110 _exit(FMD_EXIT_ERROR
);
115 fmd_panic(const char *format
, ...)
119 va_start(ap
, format
);
120 fmd_vpanic(format
, ap
);
125 fmd_verror(int err
, const char *format
, va_list ap
)
133 if ((tp
= pthread_getspecific(fmd
.d_key
)) != NULL
) {
134 (void) tp
->thr_trfunc(tp
->thr_trdata
, FMD_DBG_ERR
, format
, ap
);
138 (void) pthread_mutex_lock(&fmd
.d_err_lock
);
140 if (fmd
.d_errstats
!= NULL
&& err
>= EFMD_UNKNOWN
&& err
< EFMD_END
)
141 fmd
.d_errstats
[err
- EFMD_UNKNOWN
].fmds_value
.ui64
++;
143 if (fmd
.d_fg
|| !fmd
.d_running
) {
144 (void) fprintf(stderr
, "%s: ", fmd
.d_pname
);
145 (void) vfprintf(stderr
, format
, ap
);
147 if (strchr(format
, '\n') == NULL
)
148 (void) fprintf(stderr
, ": %s\n", fmd_strerror(oserr
));
151 (void) pthread_mutex_unlock(&fmd
.d_err_lock
);
154 * If we are at error nesting level one and running in the background,
155 * log the error as an ereport to our own log and dispatch it. If the
156 * FMD_LF_BUSY flag is set, we can't attempt to log the event because
157 * a replay is running and we will deadlock on ourself in log_append.
159 if (!fmd
.d_fg
&& fmd
.d_running
&&
160 tp
!= NULL
&& tp
->thr_errdepth
== 1 &&
161 (nvl
= fmd_protocol_fmderror(err
, format
, ap
)) != NULL
) {
163 (void) nvlist_lookup_string(nvl
, FM_CLASS
, &class);
164 e
= fmd_event_create(FMD_EVT_PROTOCOL
, FMD_HRT_NOW
, nvl
, class);
166 (void) pthread_rwlock_rdlock(&fmd
.d_log_lock
);
167 if (!(fmd
.d_errlog
->log_flags
& FMD_LF_BUSY
))
168 fmd_log_append(fmd
.d_errlog
, e
, NULL
);
169 (void) pthread_rwlock_unlock(&fmd
.d_log_lock
);
171 fmd_dispq_dispatch(fmd
.d_disp
, e
, class);
177 if (err
== EFMD_EXIT
) {
180 (void) fmd_conf_getprop(fmd
.d_conf
, "core", &core
);
182 fmd_panic("forcing core dump at user request\n");
184 exit(FMD_EXIT_ERROR
);
190 fmd_error(int err
, const char *format
, ...)
194 va_start(ap
, format
);
195 fmd_verror(err
, format
, ap
);
200 fmd_vdprintf(int mask
, const char *format
, va_list ap
)
207 if (!(fmd
.d_fmd_debug
& mask
))
208 return; /* none of the specified modes are enabled */
210 if ((tp
= pthread_getspecific(fmd
.d_key
)) != NULL
)
211 (void) tp
->thr_trfunc(tp
->thr_trdata
, mask
, format
, ap
);
213 if (fmd
.d_fmd_dbout
== 0)
214 return; /* no debugging output sinks are enabled */
216 len
= vsnprintf(&c
, 1, format
, ap
);
217 msg
= alloca(len
+ 2);
218 (void) vsnprintf(msg
, len
+ 1, format
, ap
);
220 if (msg
[len
- 1] != '\n')
221 (void) strcpy(&msg
[len
], "\n");
223 if (fmd
.d_fmd_dbout
& FMD_DBOUT_STDERR
) {
224 (void) pthread_mutex_lock(&fmd
.d_err_lock
);
225 (void) fprintf(stderr
, "%s DEBUG: %s", fmd
.d_pname
, msg
);
226 (void) pthread_mutex_unlock(&fmd
.d_err_lock
);
229 if (fmd
.d_fmd_dbout
& FMD_DBOUT_SYSLOG
) {
230 syslog(LOG_DEBUG
| LOG_DAEMON
,
231 "%s DEBUG: %s", fmd
.d_pname
, msg
);
237 fmd_dprintf(int mask
, const char *format
, ...)
241 va_start(ap
, format
);
242 fmd_vdprintf(mask
, format
, ap
);
247 * The fmd_trace.c routines set tr_file and tr_line to NULL and 0 respectively.
248 * If they are invoked from a macro (see <fmd_subr.h>) this tail function is
249 * called as part of the TRACE() macro to fill in these fields from the cpp
250 * macro values for __FILE__ and __LINE__. No locking is needed because all
251 * trace buffers are allocated separately for each fmd thread.
254 fmd_trace_cpp(void *ptr
, const char *file
, int line
)
256 fmd_tracerec_t
*trp
= ptr
;
265 * The fmd_trace() function is the wrapper for the tracing routines provided in
266 * fmd_trace.c. It is invoked by the TRACE() macro in <fmd_subr.h>, and uses
267 * the per-thread trace buffer set up in fmd_thread.c to trace debugging info.
271 fmd_trace(uint_t tag
, const char *format
, ...)
273 fmd_thread_t
*tp
= pthread_getspecific(fmd
.d_key
);
278 return (NULL
); /* drop trace record if not ready yet */
280 va_start(ap
, format
);
281 trp
= tp
->thr_trfunc(tp
->thr_trdata
, tag
, format
, ap
);
288 fmd_ea_strerror(int err
)
291 case EXR_OK
: return ("no exacct error");
292 case EXR_SYSCALL_FAIL
: return (fmd_strerror(errno
));
293 case EXR_CORRUPT_FILE
: return ("file corruption detected");
294 case EXR_EOF
: return ("end-of-file reached");
295 case EXR_NO_CREATOR
: return ("creator tag mismatch");
296 case EXR_INVALID_BUF
: return ("invalid unpack buffer");
297 case EXR_NOTSUPP
: return ("exacct operation not supported");
298 case EXR_UNKN_VERSION
: return ("unsupported exacct file version");
299 case EXR_INVALID_OBJ
: return ("invalid exacct object");
300 default: return ("unknown exacct error");
305 * Create a local ENA value for fmd-generated ereports. We use ENA Format 1
306 * with the low bits of gethrtime() and pthread_self() as the processor ID.
311 hrtime_t hrt
= fmd_time_gethrtime();
313 return ((uint64_t)((FM_ENA_FMT1
& ENA_FORMAT_MASK
) |
314 ((pthread_self() << ENA_FMT1_CPUID_SHFT
) & ENA_FMT1_CPUID_MASK
) |
315 ((hrt
<< ENA_FMT1_TIME_SHFT
) & ENA_FMT1_TIME_MASK
)));
319 * fmd_ntz32() computes the number of trailing zeroes. The algorithm here is
320 * from "Hacker's Delight" by Henry Warren, Jr.
323 fmd_ntz32(uint32_t x
)
330 if ((x
& 0xFFFF) == 0) {
335 if ((x
& 0xFF) == 0) {
340 if ((x
& 0xF) == 0) {
345 if ((x
& 0x3) == 0) {
350 return (n
- (x
& 1));