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 (c) 2013 Gary Mills
24 * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
27 #include <sys/types.h>
28 #include <sys/param.h>
29 #include <sys/varargs.h>
30 #include <sys/systm.h>
31 #include <sys/cmn_err.h>
32 #include <sys/stream.h>
33 #include <sys/strsubr.h>
34 #include <sys/strsun.h>
35 #include <sys/sysmacros.h>
39 #include <sys/syslog.h>
40 #include <sys/console.h>
41 #include <sys/debug.h>
42 #include <sys/utsname.h>
43 #include <sys/id_space.h>
46 log_zone_t log_global
;
48 queue_t
*log_backlogq
;
51 #define LOG_PRISIZE 8 /* max priority size: 7 characters + null */
52 #define LOG_FACSIZE 9 /* max priority size: 8 characters + null */
54 static krwlock_t log_rwlock
;
55 static int log_rwlock_depth
;
56 static int log_seq_no
[SL_CONSOLE
+ 1];
57 static stdata_t log_fakestr
;
58 static id_space_t
*log_minorspace
;
59 static log_t log_backlog
;
60 static struct kmem_cache
*log_cons_cache
; /* log_t cache */
62 static queue_t
*log_recentq
;
63 static queue_t
*log_freeq
;
65 static zone_key_t log_zone_key
;
67 static char log_overflow_msg
[] = "message overflow on /dev/log minor #%d%s\n";
69 static char log_pri
[LOG_PRIMASK
+ 1][LOG_PRISIZE
] = {
70 "emerg", "alert", "crit", "error",
71 "warning", "notice", "info", "debug"
74 static char log_fac
[LOG_NFACILITIES
+ 1][LOG_FACSIZE
] = {
75 "kern", "user", "mail", "daemon",
76 "auth", "syslog", "lpr", "news",
77 "uucp", "altcron", "authpriv", "ftp",
78 "ntp", "audit", "console", "cron",
79 "local0", "local1", "local2", "local3",
80 "local4", "local5", "local6", "local7",
83 static int log_cons_constructor(void *, void *, int);
84 static void log_cons_destructor(void *, void *);
87 * Get exclusive access to the logging system; this includes all minor
88 * devices. We use an rwlock rather than a mutex because hold times
89 * are potentially long, so we don't want to waste cycles in adaptive mutex
90 * spin (rwlocks always block when contended). Note that we explicitly
91 * support recursive calls (e.g. printf() calls foo() calls printf()).
93 * Clients may use log_enter() / log_exit() to guarantee that a group
94 * of messages is treated atomically (i.e. they appear in order and are
95 * not interspersed with any other messages), e.g. for multiline printf().
97 * This could probably be changed to a per-zone lock if contention becomes
103 if (rw_owner(&log_rwlock
) != curthread
)
104 rw_enter(&log_rwlock
, RW_WRITER
);
111 if (--log_rwlock_depth
== 0)
112 rw_exit(&log_rwlock
);
116 log_flushq(queue_t
*q
)
119 log_t
*lp
= (log_t
*)q
->q_ptr
;
121 /* lp will be NULL if the queue was created via log_makeq */
122 while ((mp
= getq_noenab(q
, 0)) != NULL
)
123 log_sendmsg(mp
, lp
== NULL
? GLOBAL_ZONEID
: lp
->log_zoneid
);
127 * Create a minimal queue with just enough fields filled in to support
128 * canput(9F), putq(9F), and getq_noenab(9F). We set QNOENB to ensure
129 * that the queue will never be enabled.
132 log_makeq(size_t lowat
, size_t hiwat
, void *ibc
)
136 q
= kmem_zalloc(sizeof (queue_t
), KM_SLEEP
);
137 q
->q_stream
= &log_fakestr
;
138 q
->q_flag
= QISDRV
| QMTSAFE
| QNOENB
| QREADR
| QUSE
;
142 mutex_init(QLOCK(q
), NULL
, MUTEX_DRIVER
, ibc
);
148 * Initialize the log structure for a new zone.
151 log_zoneinit(zoneid_t zoneid
)
156 if (zoneid
== GLOBAL_ZONEID
)
157 lzp
= &log_global
; /* use statically allocated struct */
159 lzp
= kmem_zalloc(sizeof (log_zone_t
), KM_SLEEP
);
161 for (i
= 0; i
< LOG_NUMCLONES
; i
++) {
162 lzp
->lz_clones
[i
].log_minor
=
163 (minor_t
)id_alloc(log_minorspace
);
164 lzp
->lz_clones
[i
].log_zoneid
= zoneid
;
171 log_zonefree(zoneid_t zoneid
, void *arg
)
173 log_zone_t
*lzp
= arg
;
176 ASSERT(lzp
!= &log_global
&& zoneid
!= GLOBAL_ZONEID
);
179 for (i
= 0; i
< LOG_NUMCLONES
; i
++)
180 id_free(log_minorspace
, lzp
->lz_clones
[i
].log_minor
);
181 kmem_free(lzp
, sizeof (log_zone_t
));
190 * Create a backlog queue to consume console messages during periods
191 * when there is no console reader (e.g. before syslogd(1M) starts).
193 log_backlogq
= log_consq
= log_makeq(0, LOG_HIWAT
, NULL
);
196 * Create a queue to hold free message of size <= LOG_MSGSIZE.
197 * Calls from high-level interrupt handlers will do a getq_noenab()
198 * from this queue, so its q_lock must be a maximum SPL spin lock.
200 log_freeq
= log_makeq(LOG_MINFREE
, LOG_MAXFREE
, (void *)ipltospl(SPL8
));
203 * Create a queue for messages from high-level interrupt context.
204 * These messages are drained via softcall, or explicitly by panic().
206 log_intrq
= log_makeq(0, LOG_HIWAT
, (void *)ipltospl(SPL8
));
209 * Create a queue to hold the most recent 8K of console messages.
210 * Useful for debugging. Required by the "$<msgbuf" adb macro.
212 log_recentq
= log_makeq(0, LOG_RECENTSIZE
, NULL
);
215 * Create an id space for clone devices opened via /dev/log.
216 * Need to limit the number of zones to avoid exceeding the
217 * available minor number space.
219 log_maxzones
= (L_MAXMIN32
- LOG_LOGMIN
) / LOG_NUMCLONES
- 1;
220 if (log_maxzones
< maxzones
)
221 maxzones
= log_maxzones
;
222 log_minorspace
= id_space_create("logminor_space", LOG_LOGMIN
+ 1,
225 * Put ourselves on the ZSD list. Note that zones have not been
226 * initialized yet, but our constructor will be called on the global
227 * zone when they are.
229 zone_key_create(&log_zone_key
, log_zoneinit
, NULL
, log_zonefree
);
232 * Initialize backlog structure.
234 log_backlog
.log_zoneid
= GLOBAL_ZONEID
;
235 log_backlog
.log_minor
= LOG_BACKLOG
;
237 /* Allocate kmem cache for conslog's log structures */
238 log_cons_cache
= kmem_cache_create("log_cons_cache",
239 sizeof (struct log
), 0, log_cons_constructor
, log_cons_destructor
,
240 NULL
, NULL
, NULL
, 0);
243 * Let the logging begin.
245 log_update(&log_backlog
, log_backlogq
, SL_CONSOLE
, log_console
);
248 * Now that logging is enabled, emit the SunOS banner.
250 printf("\rSunOS Release %s Version %s %u-bit\n",
251 utsname
.release
, utsname
.version
, NBBY
* (uint_t
)sizeof (void *));
252 printf("Copyright (c) 1983, 2010, Oracle and/or its affiliates. "
253 "All rights reserved.\n");
255 printf("DEBUG enabled\n");
260 * Allocate a log device corresponding to supplied device type.
261 * Both devices are clonable. /dev/log devices are allocated per zone.
262 * /dev/conslog devices are allocated from kmem cache.
265 log_alloc(minor_t type
)
267 zone_t
*zptr
= curproc
->p_zone
;
273 if (type
== LOG_CONSMIN
) {
276 * Return a write-only /dev/conslog device.
277 * No point allocating log_t until there's a free minor number.
279 minor
= (minor_t
)id_alloc(log_minorspace
);
280 lp
= kmem_cache_alloc(log_cons_cache
, KM_SLEEP
);
281 lp
->log_minor
= minor
;
284 ASSERT(type
== LOG_LOGMIN
);
286 lzp
= zone_getspecific(log_zone_key
, zptr
);
289 /* search for an available /dev/log device for the zone */
290 for (i
= LOG_LOGMINIDX
; i
<= LOG_LOGMAXIDX
; i
++) {
291 lp
= &lzp
->lz_clones
[i
];
292 if (lp
->log_inuse
== 0)
295 if (i
> LOG_LOGMAXIDX
)
298 /* Indicate which device type */
299 lp
->log_major
= LOG_LOGMIN
;
307 id_free(log_minorspace
, lp
->log_minor
);
308 kmem_cache_free(log_cons_cache
, lp
);
312 * Move console messages from src to dst. The time of day isn't known
313 * early in boot, so fix up the message timestamps if necessary.
316 log_conswitch(log_t
*src
, log_t
*dst
)
323 while ((mp
= getq_noenab(src
->log_q
, 0)) != NULL
) {
324 log_ctl_t
*lc
= (log_ctl_t
*)mp
->b_rptr
;
325 lc
->flags
|= SL_LOGONLY
;
328 * The ttime is written with 0 in log_sensmsg() only when
329 * good gethrestime_sec() data is not available to store in
330 * the log_ctl_t in the early boot phase.
332 if (lc
->ttime
== 0) {
334 * Look ahead to first early boot message with time.
347 hlc
= (log_ctl_t
*)hmp
->b_rptr
;
349 * Calculate hrestime for an early log message with
350 * an invalid time stamp. We know:
351 * - the lbolt of the invalid time stamp.
352 * - the hrestime and lbolt of the first valid
355 hlc
->ttime
= lc
->ttime
- (lc
->ltime
- hlc
->ltime
) / hz
;
356 (void) putq(dst
->log_q
, hmp
);
359 (void) putq(dst
->log_q
, mp
);
364 hlc
= (log_ctl_t
*)hmp
->b_rptr
;
365 hlc
->ttime
= gethrestime_sec() -
366 (ddi_get_lbolt() - hlc
->ltime
) / hz
;
367 (void) putq(dst
->log_q
, hmp
);
370 dst
->log_overflow
= src
->log_overflow
;
372 dst
->log_flags
= SL_CONSOLE
;
373 log_consq
= dst
->log_q
;
377 * Set the fields in the 'target' clone to the specified values.
378 * Then, look at all clones to determine which message types are
379 * currently active and which clone is the primary console queue.
380 * If the primary console queue changes to or from the backlog
381 * queue, copy all messages from backlog to primary or vice versa.
384 log_update(log_t
*target
, queue_t
*q
, short flags
, log_filter_t
*filter
)
387 short active
= SL_CONSOLE
;
390 zoneid_t zoneid
= target
->log_zoneid
;
397 target
->log_wanted
= filter
;
398 target
->log_flags
= flags
;
399 target
->log_overflow
= 0;
402 * Need to special case the global zone here since this may be
403 * called before zone_init.
405 if (zoneid
== GLOBAL_ZONEID
) {
407 } else if ((zptr
= zone_find_by_id(zoneid
)) == NULL
) {
409 return; /* zone is being destroyed, ignore update */
411 lzp
= zone_getspecific(log_zone_key
, zptr
);
414 for (i
= LOG_LOGMAXIDX
; i
>= LOG_LOGMINIDX
; i
--) {
415 lp
= &lzp
->lz_clones
[i
];
416 if (zoneid
== GLOBAL_ZONEID
&& (lp
->log_flags
& SL_CONSOLE
))
417 log_consq
= lp
->log_q
;
418 active
|= lp
->log_flags
;
420 lzp
->lz_active
= active
;
425 if (log_consq
== target
->log_q
) {
426 if (flags
& SL_CONSOLE
)
427 log_conswitch(&log_backlog
, target
);
429 log_conswitch(target
, &log_backlog
);
438 log_error(log_t
*lp
, log_ctl_t
*lc
)
440 if ((lc
->pri
& LOG_FACMASK
) == LOG_KERN
)
441 lc
->pri
= LOG_KERN
| LOG_ERR
;
446 log_trace(log_t
*lp
, log_ctl_t
*lc
)
448 trace_ids_t
*tid
= (trace_ids_t
*)lp
->log_data
->b_rptr
;
449 trace_ids_t
*tidend
= (trace_ids_t
*)lp
->log_data
->b_wptr
;
452 * We use `tid + 1 <= tidend' here rather than the more traditional
453 * `tid < tidend', since the former ensures that there's at least
454 * `sizeof (trace_ids_t)' bytes available before executing the
455 * loop, whereas the latter only ensures that there's a single byte.
457 for (; tid
+ 1 <= tidend
; tid
++) {
458 if (tid
->ti_level
< lc
->level
&& tid
->ti_level
>= 0)
460 if (tid
->ti_mid
!= lc
->mid
&& tid
->ti_mid
>= 0)
462 if (tid
->ti_sid
!= lc
->sid
&& tid
->ti_sid
>= 0)
464 if ((lc
->pri
& LOG_FACMASK
) == LOG_KERN
)
465 lc
->pri
= LOG_KERN
| LOG_DEBUG
;
473 log_console(log_t
*lp
, log_ctl_t
*lc
)
475 if ((lc
->pri
& LOG_FACMASK
) == LOG_KERN
) {
476 if (lc
->flags
& SL_FATAL
)
477 lc
->pri
= LOG_KERN
| LOG_CRIT
;
478 else if (lc
->flags
& SL_ERROR
)
479 lc
->pri
= LOG_KERN
| LOG_ERR
;
480 else if (lc
->flags
& SL_WARN
)
481 lc
->pri
= LOG_KERN
| LOG_WARNING
;
482 else if (lc
->flags
& SL_NOTE
)
483 lc
->pri
= LOG_KERN
| LOG_NOTICE
;
484 else if (lc
->flags
& SL_TRACE
)
485 lc
->pri
= LOG_KERN
| LOG_DEBUG
;
487 lc
->pri
= LOG_KERN
| LOG_INFO
;
493 log_makemsg(int mid
, int sid
, int level
, int sl
, int pri
, void *msg
,
494 size_t size
, int on_intr
)
500 if (size
<= LOG_MSGSIZE
&&
501 (on_intr
|| log_freeq
->q_count
> log_freeq
->q_lowat
))
502 mp
= getq_noenab(log_freeq
, 0);
506 (mp
= allocb(sizeof (log_ctl_t
), BPRI_HI
)) == NULL
||
507 (mp2
= allocb(MAX(size
, LOG_MSGSIZE
), BPRI_HI
)) == NULL
) {
511 DB_TYPE(mp
) = M_PROTO
;
512 mp
->b_wptr
+= sizeof (log_ctl_t
);
516 mp2
->b_wptr
= mp2
->b_rptr
;
519 lc
= (log_ctl_t
*)mp
->b_rptr
;
526 bcopy(msg
, mp2
->b_wptr
, size
- 1);
527 mp2
->b_wptr
[size
- 1] = '\0';
528 mp2
->b_wptr
+= strlen((char *)mp2
->b_wptr
) + 1;
534 log_freemsg(mblk_t
*mp
)
536 mblk_t
*mp2
= mp
->b_cont
;
538 ASSERT(MBLKL(mp
) == sizeof (log_ctl_t
));
539 ASSERT(mp2
->b_rptr
== mp2
->b_datap
->db_base
);
541 if ((log_freeq
->q_flag
& QFULL
) == 0 &&
542 MBLKL(mp2
) <= LOG_MSGSIZE
&& MBLKSIZE(mp2
) >= LOG_MSGSIZE
)
543 (void) putq(log_freeq
, mp
);
549 log_sendmsg(mblk_t
*mp
, zoneid_t zoneid
)
553 mblk_t
*mp2
= mp
->b_cont
;
554 log_ctl_t
*lc
= (log_ctl_t
*)mp
->b_rptr
;
564 * Need to special case the global zone here since this may be
565 * called before zone_init.
567 if (zoneid
== GLOBAL_ZONEID
) {
569 } else if ((zptr
= zone_find_by_id(zoneid
)) == NULL
) {
570 /* specified zone doesn't exist, free message and return */
574 lzp
= zone_getspecific(log_zone_key
, zptr
);
578 if ((lc
->flags
& lzp
->lz_active
) == 0) {
587 * Raise the console queue's q_hiwat to ensure that we
588 * capture all panic messages.
590 log_consq
->q_hiwat
= 2 * LOG_HIWAT
;
591 log_consq
->q_flag
&= ~QFULL
;
593 /* Message was created while panicking. */
594 lc
->flags
|= SL_PANICMSG
;
597 src
= (char *)mp2
->b_rptr
;
598 dst
= strstr(src
, "FACILITY_AND_PRIORITY] ");
600 facility
= dst
- src
;
601 body
= facility
+ 23; /* strlen("FACILITY_AND_PRIORITY] ") */
607 * In the early boot phase hrestime is invalid, then timechanged is 0.
608 * If hrestime is not valid, the ttime is set to 0 here and the correct
609 * ttime is calculated in log_conswitch() later. The log_conswitch()
610 * calculation to determine the correct ttime does not use ttime data
611 * from these log_ctl_t structures; it only uses ttime from log_ctl_t's
612 * that contain good data.
615 lc
->ltime
= ddi_get_lbolt();
617 lc
->ttime
= gethrestime_sec();
622 flags
= lc
->flags
& lzp
->lz_active
;
623 log_seq_no
[flags
& SL_ERROR
]++;
624 log_seq_no
[flags
& SL_TRACE
]++;
625 log_seq_no
[flags
& SL_CONSOLE
]++;
628 * If this is in the global zone, start with the backlog, then
629 * walk through the clone logs. If not, just do the clone logs.
631 backlog
= (zoneid
== GLOBAL_ZONEID
);
633 while (i
<= LOG_LOGMAXIDX
) {
636 * Do the backlog this time, then start on the
642 lp
= &lzp
->lz_clones
[i
++];
645 if ((lp
->log_flags
& flags
) && lp
->log_wanted(lp
, lc
)) {
646 if (canput(lp
->log_q
)) {
647 lp
->log_overflow
= 0;
648 lc
->seq_no
= log_seq_no
[lp
->log_flags
];
649 if ((mp2
= copymsg(mp
)) == NULL
)
652 src
= (char *)mp2
->b_cont
->b_rptr
;
653 dst
= src
+ facility
;
654 fac
= (lc
->pri
& LOG_FACMASK
) >> 3;
656 LOG_FACSIZE
+ LOG_PRISIZE
, "%s.%s",
657 log_fac
[MIN(fac
, LOG_NFACILITIES
)],
658 log_pri
[lc
->pri
& LOG_PRIMASK
]);
659 src
+= body
- 2; /* copy "] " too */
663 mp2
->b_cont
->b_wptr
= (uchar_t
*)dst
;
665 (void) putq(lp
->log_q
, mp2
);
666 } else if (++lp
->log_overflow
== 1) {
667 if (lp
->log_q
== log_consq
) {
668 console_printf(log_overflow_msg
,
670 " -- is syslogd(1M) running?");
672 printf(log_overflow_msg
,
682 if ((flags
& SL_CONSOLE
) && (lc
->pri
& LOG_FACMASK
) == LOG_KERN
) {
683 if ((mp2
== NULL
|| log_consq
== log_backlogq
|| panicstr
) &&
684 (lc
->flags
& SL_LOGONLY
) == 0)
685 console_printf("%s", (char *)mp
->b_cont
->b_rptr
+ body
);
686 if ((lc
->flags
& SL_CONSONLY
) == 0 &&
687 (mp2
= copymsg(mp
)) != NULL
) {
688 mp2
->b_cont
->b_rptr
+= body
;
689 if (log_recentq
->q_flag
& QFULL
)
690 freemsg(getq_noenab(log_recentq
, 0));
691 (void) putq(log_recentq
, mp2
);
701 * Print queued messages to console.
704 log_printq(queue_t
*qfirst
)
712 * Look ahead to first queued message in the stream.
716 for (q
= qfirst
; q
->q_next
!= qlast
; q
= q
->q_next
)
718 for (mp
= q
->q_first
; mp
!= NULL
; mp
= mp
->b_next
) {
719 lc
= (log_ctl_t
*)mp
->b_rptr
;
721 * Check if message is already displayed at
724 if (lc
->flags
& SL_PANICMSG
)
727 cp
= (char *)mp
->b_cont
->b_rptr
;
729 /* Strip off the message ID. */
730 if ((msgp
= strstr(cp
, "[ID ")) != NULL
&&
731 (msgp
= strstr(msgp
, "] ")) != NULL
) {
736 * Using console_printf instead of printf to avoid
737 * queueing messages to log_consq.
739 console_printf("%s", cp
);
741 } while ((qlast
= q
) != qfirst
);
746 log_cons_constructor(void *buf
, void *cdrarg
, int kmflags
)
748 struct log
*lp
= buf
;
750 lp
->log_zoneid
= GLOBAL_ZONEID
;
751 lp
->log_major
= LOG_CONSMIN
; /* Indicate which device type */
758 log_cons_destructor(void *buf
, void *cdrarg
)
760 struct log
*lp
= buf
;
762 ASSERT(lp
->log_zoneid
== GLOBAL_ZONEID
);
763 ASSERT(lp
->log_major
== LOG_CONSMIN
);
764 ASSERT(lp
->log_data
== NULL
);