10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*1401Smjnelson * Common Development and Distribution License (the "License"). 6*1401Smjnelson * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 21*1401Smjnelson 220Sstevel@tonic-gate /* 231259Sns92644 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate #include <sys/types.h> 300Sstevel@tonic-gate #include <sys/param.h> 310Sstevel@tonic-gate #include <sys/varargs.h> 320Sstevel@tonic-gate #include <sys/systm.h> 330Sstevel@tonic-gate #include <sys/cmn_err.h> 340Sstevel@tonic-gate #include <sys/stream.h> 350Sstevel@tonic-gate #include <sys/strsubr.h> 360Sstevel@tonic-gate #include <sys/strsun.h> 370Sstevel@tonic-gate #include <sys/sysmacros.h> 380Sstevel@tonic-gate #include <sys/kmem.h> 390Sstevel@tonic-gate #include <sys/log.h> 400Sstevel@tonic-gate #include <sys/spl.h> 410Sstevel@tonic-gate #include <sys/syslog.h> 420Sstevel@tonic-gate #include <sys/console.h> 430Sstevel@tonic-gate #include <sys/debug.h> 440Sstevel@tonic-gate #include <sys/utsname.h> 450Sstevel@tonic-gate #include <sys/id_space.h> 460Sstevel@tonic-gate #include <sys/zone.h> 470Sstevel@tonic-gate 480Sstevel@tonic-gate log_zone_t log_global; 490Sstevel@tonic-gate queue_t *log_consq; 500Sstevel@tonic-gate queue_t *log_backlogq; 510Sstevel@tonic-gate queue_t *log_intrq; 520Sstevel@tonic-gate 530Sstevel@tonic-gate #define LOG_PRISIZE 8 /* max priority size: 7 characters + null */ 540Sstevel@tonic-gate #define LOG_FACSIZE 9 /* max priority size: 8 characters + null */ 550Sstevel@tonic-gate 560Sstevel@tonic-gate static krwlock_t log_rwlock; 570Sstevel@tonic-gate static int log_rwlock_depth; 580Sstevel@tonic-gate static int log_seq_no[SL_CONSOLE + 1]; 590Sstevel@tonic-gate static stdata_t log_fakestr; 600Sstevel@tonic-gate static id_space_t *log_minorspace; 610Sstevel@tonic-gate static log_t log_backlog; 621259Sns92644 static struct kmem_cache *log_cons_cache; /* log_t cache */ 630Sstevel@tonic-gate 640Sstevel@tonic-gate static queue_t *log_recentq; 650Sstevel@tonic-gate static queue_t *log_freeq; 660Sstevel@tonic-gate 670Sstevel@tonic-gate static zone_key_t log_zone_key; 680Sstevel@tonic-gate 690Sstevel@tonic-gate static char log_overflow_msg[] = "message overflow on /dev/log minor #%d%s\n"; 700Sstevel@tonic-gate 710Sstevel@tonic-gate static char log_pri[LOG_PRIMASK + 1][LOG_PRISIZE] = { 720Sstevel@tonic-gate "emerg", "alert", "crit", "error", 730Sstevel@tonic-gate "warning", "notice", "info", "debug" 740Sstevel@tonic-gate }; 750Sstevel@tonic-gate 760Sstevel@tonic-gate static char log_fac[LOG_NFACILITIES + 1][LOG_FACSIZE] = { 770Sstevel@tonic-gate "kern", "user", "mail", "daemon", 780Sstevel@tonic-gate "auth", "syslog", "lpr", "news", 790Sstevel@tonic-gate "uucp", "resv9", "resv10", "resv11", 800Sstevel@tonic-gate "resv12", "audit", "resv14", "cron", 810Sstevel@tonic-gate "local0", "local1", "local2", "local3", 820Sstevel@tonic-gate "local4", "local5", "local6", "local7", 830Sstevel@tonic-gate "unknown" 840Sstevel@tonic-gate }; 851259Sns92644 static int log_cons_constructor(void *, void *, int); 861259Sns92644 static void log_cons_destructor(void *, void *); 870Sstevel@tonic-gate 880Sstevel@tonic-gate /* 890Sstevel@tonic-gate * Get exclusive access to the logging system; this includes all minor 900Sstevel@tonic-gate * devices. We use an rwlock rather than a mutex because hold times 910Sstevel@tonic-gate * are potentially long, so we don't want to waste cycles in adaptive mutex 920Sstevel@tonic-gate * spin (rwlocks always block when contended). Note that we explicitly 930Sstevel@tonic-gate * support recursive calls (e.g. printf() calls foo() calls printf()). 940Sstevel@tonic-gate * 950Sstevel@tonic-gate * Clients may use log_enter() / log_exit() to guarantee that a group 960Sstevel@tonic-gate * of messages is treated atomically (i.e. they appear in order and are 970Sstevel@tonic-gate * not interspersed with any other messages), e.g. for multiline printf(). 980Sstevel@tonic-gate * 990Sstevel@tonic-gate * This could probably be changed to a per-zone lock if contention becomes 1000Sstevel@tonic-gate * an issue. 1010Sstevel@tonic-gate */ 1020Sstevel@tonic-gate void 1030Sstevel@tonic-gate log_enter(void) 1040Sstevel@tonic-gate { 1050Sstevel@tonic-gate if (rw_owner(&log_rwlock) != curthread) 1060Sstevel@tonic-gate rw_enter(&log_rwlock, RW_WRITER); 1070Sstevel@tonic-gate log_rwlock_depth++; 1080Sstevel@tonic-gate } 1090Sstevel@tonic-gate 1100Sstevel@tonic-gate void 1110Sstevel@tonic-gate log_exit(void) 1120Sstevel@tonic-gate { 1130Sstevel@tonic-gate if (--log_rwlock_depth == 0) 1140Sstevel@tonic-gate rw_exit(&log_rwlock); 1150Sstevel@tonic-gate } 1160Sstevel@tonic-gate 1170Sstevel@tonic-gate void 1180Sstevel@tonic-gate log_flushq(queue_t *q) 1190Sstevel@tonic-gate { 1200Sstevel@tonic-gate mblk_t *mp; 1210Sstevel@tonic-gate log_t *lp = (log_t *)q->q_ptr; 1220Sstevel@tonic-gate 1230Sstevel@tonic-gate /* lp will be NULL if the queue was created via log_makeq */ 1240Sstevel@tonic-gate while ((mp = getq_noenab(q)) != NULL) 1250Sstevel@tonic-gate log_sendmsg(mp, lp == NULL ? GLOBAL_ZONEID : lp->log_zoneid); 1260Sstevel@tonic-gate } 1270Sstevel@tonic-gate 1280Sstevel@tonic-gate /* 1290Sstevel@tonic-gate * Create a minimal queue with just enough fields filled in to support 1300Sstevel@tonic-gate * canput(9F), putq(9F), and getq_noenab(9F). We set QNOENB to ensure 1310Sstevel@tonic-gate * that the queue will never be enabled. 1320Sstevel@tonic-gate */ 1330Sstevel@tonic-gate static queue_t * 1340Sstevel@tonic-gate log_makeq(size_t lowat, size_t hiwat, void *ibc) 1350Sstevel@tonic-gate { 1360Sstevel@tonic-gate queue_t *q; 1370Sstevel@tonic-gate 1380Sstevel@tonic-gate q = kmem_zalloc(sizeof (queue_t), KM_SLEEP); 1390Sstevel@tonic-gate q->q_stream = &log_fakestr; 1400Sstevel@tonic-gate q->q_flag = QISDRV | QMTSAFE | QNOENB | QREADR | QUSE; 1410Sstevel@tonic-gate q->q_nfsrv = q; 1420Sstevel@tonic-gate q->q_lowat = lowat; 1430Sstevel@tonic-gate q->q_hiwat = hiwat; 1440Sstevel@tonic-gate mutex_init(QLOCK(q), NULL, MUTEX_DRIVER, ibc); 1450Sstevel@tonic-gate 1460Sstevel@tonic-gate return (q); 1470Sstevel@tonic-gate } 1480Sstevel@tonic-gate 1490Sstevel@tonic-gate /* 1500Sstevel@tonic-gate * Initialize the log structure for a new zone. 1510Sstevel@tonic-gate */ 1520Sstevel@tonic-gate static void * 1530Sstevel@tonic-gate log_zoneinit(zoneid_t zoneid) 1540Sstevel@tonic-gate { 1550Sstevel@tonic-gate int i; 1560Sstevel@tonic-gate log_zone_t *lzp; 1570Sstevel@tonic-gate 1580Sstevel@tonic-gate if (zoneid == GLOBAL_ZONEID) 1590Sstevel@tonic-gate lzp = &log_global; /* use statically allocated struct */ 1600Sstevel@tonic-gate else 1610Sstevel@tonic-gate lzp = kmem_zalloc(sizeof (log_zone_t), KM_SLEEP); 1620Sstevel@tonic-gate 1630Sstevel@tonic-gate for (i = 0; i < LOG_NUMCLONES; i++) { 1640Sstevel@tonic-gate lzp->lz_clones[i].log_minor = 1650Sstevel@tonic-gate (minor_t)id_alloc(log_minorspace); 1660Sstevel@tonic-gate lzp->lz_clones[i].log_zoneid = zoneid; 1670Sstevel@tonic-gate } 1680Sstevel@tonic-gate return (lzp); 1690Sstevel@tonic-gate } 1700Sstevel@tonic-gate 1710Sstevel@tonic-gate /*ARGSUSED*/ 1720Sstevel@tonic-gate static void 1730Sstevel@tonic-gate log_zonefree(zoneid_t zoneid, void *arg) 1740Sstevel@tonic-gate { 1750Sstevel@tonic-gate log_zone_t *lzp = arg; 1760Sstevel@tonic-gate int i; 1770Sstevel@tonic-gate 1780Sstevel@tonic-gate ASSERT(lzp != &log_global && zoneid != GLOBAL_ZONEID); 1790Sstevel@tonic-gate if (lzp == NULL) 1800Sstevel@tonic-gate return; 1810Sstevel@tonic-gate for (i = 0; i < LOG_NUMCLONES; i++) 1820Sstevel@tonic-gate id_free(log_minorspace, lzp->lz_clones[i].log_minor); 1830Sstevel@tonic-gate kmem_free(lzp, sizeof (log_zone_t)); 1840Sstevel@tonic-gate } 1850Sstevel@tonic-gate 1860Sstevel@tonic-gate void 1870Sstevel@tonic-gate log_init(void) 1880Sstevel@tonic-gate { 1890Sstevel@tonic-gate int log_maxzones; 1900Sstevel@tonic-gate 1910Sstevel@tonic-gate /* 1920Sstevel@tonic-gate * Create a backlog queue to consume console messages during periods 1930Sstevel@tonic-gate * when there is no console reader (e.g. before syslogd(1M) starts). 1940Sstevel@tonic-gate */ 1950Sstevel@tonic-gate log_backlogq = log_consq = log_makeq(0, LOG_HIWAT, NULL); 1960Sstevel@tonic-gate 1970Sstevel@tonic-gate /* 1980Sstevel@tonic-gate * Create a queue to hold free message of size <= LOG_MSGSIZE. 1990Sstevel@tonic-gate * Calls from high-level interrupt handlers will do a getq_noenab() 2000Sstevel@tonic-gate * from this queue, so its q_lock must be a maximum SPL spin lock. 2010Sstevel@tonic-gate */ 2020Sstevel@tonic-gate log_freeq = log_makeq(LOG_MINFREE, LOG_MAXFREE, (void *)ipltospl(SPL8)); 2030Sstevel@tonic-gate 2040Sstevel@tonic-gate /* 2050Sstevel@tonic-gate * Create a queue for messages from high-level interrupt context. 2060Sstevel@tonic-gate * These messages are drained via softcall, or explicitly by panic(). 2070Sstevel@tonic-gate */ 2080Sstevel@tonic-gate log_intrq = log_makeq(0, LOG_HIWAT, (void *)ipltospl(SPL8)); 2090Sstevel@tonic-gate 2100Sstevel@tonic-gate /* 2110Sstevel@tonic-gate * Create a queue to hold the most recent 8K of console messages. 2120Sstevel@tonic-gate * Useful for debugging. Required by the "$<msgbuf" adb macro. 2130Sstevel@tonic-gate */ 2140Sstevel@tonic-gate log_recentq = log_makeq(0, LOG_RECENTSIZE, NULL); 2150Sstevel@tonic-gate 2160Sstevel@tonic-gate /* 2170Sstevel@tonic-gate * Create an id space for clone devices opened via /dev/log. 2180Sstevel@tonic-gate * Need to limit the number of zones to avoid exceeding the 2190Sstevel@tonic-gate * available minor number space. 2200Sstevel@tonic-gate */ 2210Sstevel@tonic-gate log_maxzones = (L_MAXMIN32 - LOG_LOGMIN) / LOG_NUMCLONES - 1; 2220Sstevel@tonic-gate if (log_maxzones < maxzones) 2230Sstevel@tonic-gate maxzones = log_maxzones; 2240Sstevel@tonic-gate log_minorspace = id_space_create("logminor_space", LOG_LOGMIN + 1, 2250Sstevel@tonic-gate L_MAXMIN32); 2260Sstevel@tonic-gate /* 2270Sstevel@tonic-gate * Put ourselves on the ZSD list. Note that zones have not been 2280Sstevel@tonic-gate * initialized yet, but our constructor will be called on the global 2290Sstevel@tonic-gate * zone when they are. 2300Sstevel@tonic-gate */ 2310Sstevel@tonic-gate zone_key_create(&log_zone_key, log_zoneinit, NULL, log_zonefree); 2320Sstevel@tonic-gate 2330Sstevel@tonic-gate /* 2340Sstevel@tonic-gate * Initialize backlog structure. 2350Sstevel@tonic-gate */ 2360Sstevel@tonic-gate log_backlog.log_zoneid = GLOBAL_ZONEID; 2370Sstevel@tonic-gate log_backlog.log_minor = LOG_BACKLOG; 2380Sstevel@tonic-gate 2391259Sns92644 /* Allocate kmem cache for conslog's log structures */ 2401259Sns92644 log_cons_cache = kmem_cache_create("log_cons_cache", 2411259Sns92644 sizeof (struct log), 0, log_cons_constructor, log_cons_destructor, 2421259Sns92644 NULL, NULL, NULL, 0); 2430Sstevel@tonic-gate 2440Sstevel@tonic-gate /* 2450Sstevel@tonic-gate * Let the logging begin. 2460Sstevel@tonic-gate */ 2470Sstevel@tonic-gate log_update(&log_backlog, log_backlogq, SL_CONSOLE, log_console); 2480Sstevel@tonic-gate 2490Sstevel@tonic-gate /* 2500Sstevel@tonic-gate * Now that logging is enabled, emit the SunOS banner. 2510Sstevel@tonic-gate */ 2520Sstevel@tonic-gate printf("\rSunOS Release %s Version %s %u-bit\n", 2530Sstevel@tonic-gate utsname.release, utsname.version, NBBY * (uint_t)sizeof (void *)); 254*1401Smjnelson printf("Copyright 1983-2006 Sun Microsystems, Inc. " 2550Sstevel@tonic-gate "All rights reserved.\nUse is subject to license terms.\n"); 2560Sstevel@tonic-gate #ifdef DEBUG 2570Sstevel@tonic-gate printf("DEBUG enabled\n"); 2580Sstevel@tonic-gate #endif 2590Sstevel@tonic-gate } 2600Sstevel@tonic-gate 2610Sstevel@tonic-gate /* 2621259Sns92644 * Allocate a log device corresponding to supplied device type. 2631259Sns92644 * Both devices are clonable. /dev/log devices are allocated per zone. 2641259Sns92644 * /dev/conslog devices are allocated from kmem cache. 2650Sstevel@tonic-gate */ 2660Sstevel@tonic-gate log_t * 2670Sstevel@tonic-gate log_alloc(minor_t type) 2680Sstevel@tonic-gate { 2690Sstevel@tonic-gate zone_t *zptr = curproc->p_zone; 2700Sstevel@tonic-gate log_zone_t *lzp; 2710Sstevel@tonic-gate log_t *lp; 2720Sstevel@tonic-gate int i; 2731259Sns92644 minor_t minor; 2740Sstevel@tonic-gate 2750Sstevel@tonic-gate if (type == LOG_CONSMIN) { 2760Sstevel@tonic-gate 2771259Sns92644 /* 2781259Sns92644 * Return a write-only /dev/conslog device. 2791259Sns92644 * No point allocating log_t until there's a free minor number. 2801259Sns92644 */ 2811259Sns92644 minor = (minor_t)id_alloc(log_minorspace); 2821259Sns92644 lp = kmem_cache_alloc(log_cons_cache, KM_SLEEP); 2831259Sns92644 lp->log_minor = minor; 2841259Sns92644 return (lp); 2851259Sns92644 } else { 2861259Sns92644 ASSERT(type == LOG_LOGMIN); 2870Sstevel@tonic-gate 2881259Sns92644 lzp = zone_getspecific(log_zone_key, zptr); 2891259Sns92644 ASSERT(lzp != NULL); 2900Sstevel@tonic-gate 2911259Sns92644 /* search for an available /dev/log device for the zone */ 2921259Sns92644 for (i = LOG_LOGMINIDX; i <= LOG_LOGMAXIDX; i++) { 2931259Sns92644 lp = &lzp->lz_clones[i]; 2941259Sns92644 if (lp->log_inuse == 0) 2951259Sns92644 break; 2961259Sns92644 } 2971259Sns92644 if (i > LOG_LOGMAXIDX) 2981259Sns92644 lp = NULL; 2991259Sns92644 else 3001259Sns92644 /* Indicate which device type */ 3011259Sns92644 lp->log_major = LOG_LOGMIN; 3021259Sns92644 return (lp); 3030Sstevel@tonic-gate } 3041259Sns92644 } 3051259Sns92644 3061259Sns92644 void 3071259Sns92644 log_free(log_t *lp) 3081259Sns92644 { 3091259Sns92644 id_free(log_minorspace, lp->log_minor); 3101259Sns92644 kmem_cache_free(log_cons_cache, lp); 3110Sstevel@tonic-gate } 3120Sstevel@tonic-gate 3130Sstevel@tonic-gate /* 3140Sstevel@tonic-gate * Move console messages from src to dst. The time of day isn't known 3150Sstevel@tonic-gate * early in boot, so fix up the message timestamps if necessary. 3160Sstevel@tonic-gate */ 3170Sstevel@tonic-gate static void 3180Sstevel@tonic-gate log_conswitch(log_t *src, log_t *dst) 3190Sstevel@tonic-gate { 3200Sstevel@tonic-gate mblk_t *mp; 3210Sstevel@tonic-gate mblk_t *hmp = NULL; 3220Sstevel@tonic-gate mblk_t *tmp = NULL; 3230Sstevel@tonic-gate log_ctl_t *hlc; 3240Sstevel@tonic-gate 3250Sstevel@tonic-gate while ((mp = getq_noenab(src->log_q)) != NULL) { 3260Sstevel@tonic-gate log_ctl_t *lc = (log_ctl_t *)mp->b_rptr; 3270Sstevel@tonic-gate lc->flags |= SL_LOGONLY; 3280Sstevel@tonic-gate 3290Sstevel@tonic-gate /* 3300Sstevel@tonic-gate * In the early boot phase hrestime is invalid. 3310Sstevel@tonic-gate * hrestime becomes valid when clock() runs for the first time. 3320Sstevel@tonic-gate * At this time is lbolt == 1. log_sendmsg() saves the lbolt 3330Sstevel@tonic-gate * value in ltime. 3340Sstevel@tonic-gate */ 3350Sstevel@tonic-gate if (lc->ltime < 2) { 3360Sstevel@tonic-gate /* 3370Sstevel@tonic-gate * Look ahead to first early boot message with time. 3380Sstevel@tonic-gate */ 3390Sstevel@tonic-gate if (hmp) { 3400Sstevel@tonic-gate tmp->b_next = mp; 3410Sstevel@tonic-gate tmp = mp; 3420Sstevel@tonic-gate } else 3430Sstevel@tonic-gate hmp = tmp = mp; 3440Sstevel@tonic-gate continue; 3450Sstevel@tonic-gate } 3460Sstevel@tonic-gate 3470Sstevel@tonic-gate while (hmp) { 3480Sstevel@tonic-gate tmp = hmp->b_next; 3490Sstevel@tonic-gate hmp->b_next = NULL; 3500Sstevel@tonic-gate hlc = (log_ctl_t *)hmp->b_rptr; 3510Sstevel@tonic-gate /* 3520Sstevel@tonic-gate * Calculate hrestime for an early log message with 3530Sstevel@tonic-gate * an invalid time stamp. We know: 3540Sstevel@tonic-gate * - the lbolt of the invalid time stamp. 3550Sstevel@tonic-gate * - the hrestime and lbolt of the first valid 3560Sstevel@tonic-gate * time stamp. 3570Sstevel@tonic-gate */ 3580Sstevel@tonic-gate hlc->ttime = lc->ttime - (lc->ltime - hlc->ltime) / hz; 3590Sstevel@tonic-gate (void) putq(dst->log_q, hmp); 3600Sstevel@tonic-gate hmp = tmp; 3610Sstevel@tonic-gate } 3620Sstevel@tonic-gate (void) putq(dst->log_q, mp); 3630Sstevel@tonic-gate } 3640Sstevel@tonic-gate while (hmp) { 3650Sstevel@tonic-gate tmp = hmp->b_next; 3660Sstevel@tonic-gate hmp->b_next = NULL; 3670Sstevel@tonic-gate hlc = (log_ctl_t *)hmp->b_rptr; 3680Sstevel@tonic-gate hlc->ttime = gethrestime_sec() - (lbolt - hlc->ltime) / hz; 3690Sstevel@tonic-gate (void) putq(dst->log_q, hmp); 3700Sstevel@tonic-gate hmp = tmp; 3710Sstevel@tonic-gate } 3720Sstevel@tonic-gate dst->log_overflow = src->log_overflow; 3730Sstevel@tonic-gate src->log_flags = 0; 3740Sstevel@tonic-gate dst->log_flags = SL_CONSOLE; 3750Sstevel@tonic-gate log_consq = dst->log_q; 3760Sstevel@tonic-gate } 3770Sstevel@tonic-gate 3780Sstevel@tonic-gate /* 3790Sstevel@tonic-gate * Set the fields in the 'target' clone to the specified values. 3800Sstevel@tonic-gate * Then, look at all clones to determine which message types are 3810Sstevel@tonic-gate * currently active and which clone is the primary console queue. 3820Sstevel@tonic-gate * If the primary console queue changes to or from the backlog 3830Sstevel@tonic-gate * queue, copy all messages from backlog to primary or vice versa. 3840Sstevel@tonic-gate */ 3850Sstevel@tonic-gate void 3860Sstevel@tonic-gate log_update(log_t *target, queue_t *q, short flags, log_filter_t *filter) 3870Sstevel@tonic-gate { 3880Sstevel@tonic-gate log_t *lp; 3890Sstevel@tonic-gate short active = SL_CONSOLE; 3900Sstevel@tonic-gate zone_t *zptr = NULL; 3910Sstevel@tonic-gate log_zone_t *lzp; 3920Sstevel@tonic-gate zoneid_t zoneid = target->log_zoneid; 3930Sstevel@tonic-gate int i; 3940Sstevel@tonic-gate 3950Sstevel@tonic-gate log_enter(); 3960Sstevel@tonic-gate 3970Sstevel@tonic-gate if (q != NULL) 3980Sstevel@tonic-gate target->log_q = q; 3990Sstevel@tonic-gate target->log_wanted = filter; 4000Sstevel@tonic-gate target->log_flags = flags; 4010Sstevel@tonic-gate target->log_overflow = 0; 4020Sstevel@tonic-gate 4030Sstevel@tonic-gate /* 4040Sstevel@tonic-gate * Need to special case the global zone here since this may be 4050Sstevel@tonic-gate * called before zone_init. 4060Sstevel@tonic-gate */ 4070Sstevel@tonic-gate if (zoneid == GLOBAL_ZONEID) { 4080Sstevel@tonic-gate lzp = &log_global; 4090Sstevel@tonic-gate } else if ((zptr = zone_find_by_id(zoneid)) == NULL) { 4100Sstevel@tonic-gate log_exit(); 4110Sstevel@tonic-gate return; /* zone is being destroyed, ignore update */ 4120Sstevel@tonic-gate } else { 4130Sstevel@tonic-gate lzp = zone_getspecific(log_zone_key, zptr); 4140Sstevel@tonic-gate } 4150Sstevel@tonic-gate ASSERT(lzp != NULL); 4160Sstevel@tonic-gate for (i = LOG_LOGMAXIDX; i >= LOG_LOGMINIDX; i--) { 4170Sstevel@tonic-gate lp = &lzp->lz_clones[i]; 4180Sstevel@tonic-gate if (zoneid == GLOBAL_ZONEID && (lp->log_flags & SL_CONSOLE)) 4190Sstevel@tonic-gate log_consq = lp->log_q; 4200Sstevel@tonic-gate active |= lp->log_flags; 4210Sstevel@tonic-gate } 4220Sstevel@tonic-gate lzp->lz_active = active; 4230Sstevel@tonic-gate 4240Sstevel@tonic-gate if (zptr) 4250Sstevel@tonic-gate zone_rele(zptr); 4260Sstevel@tonic-gate 4270Sstevel@tonic-gate if (log_consq == target->log_q) { 4280Sstevel@tonic-gate if (flags & SL_CONSOLE) 4290Sstevel@tonic-gate log_conswitch(&log_backlog, target); 4300Sstevel@tonic-gate else 4310Sstevel@tonic-gate log_conswitch(target, &log_backlog); 4320Sstevel@tonic-gate } 4330Sstevel@tonic-gate target->log_q = q; 4340Sstevel@tonic-gate 4350Sstevel@tonic-gate log_exit(); 4360Sstevel@tonic-gate } 4370Sstevel@tonic-gate 4380Sstevel@tonic-gate /*ARGSUSED*/ 4390Sstevel@tonic-gate int 4400Sstevel@tonic-gate log_error(log_t *lp, log_ctl_t *lc) 4410Sstevel@tonic-gate { 4420Sstevel@tonic-gate if ((lc->pri & LOG_FACMASK) == LOG_KERN) 4430Sstevel@tonic-gate lc->pri = LOG_KERN | LOG_ERR; 4440Sstevel@tonic-gate return (1); 4450Sstevel@tonic-gate } 4460Sstevel@tonic-gate 4470Sstevel@tonic-gate int 4480Sstevel@tonic-gate log_trace(log_t *lp, log_ctl_t *lc) 4490Sstevel@tonic-gate { 4500Sstevel@tonic-gate trace_ids_t *tid = (trace_ids_t *)lp->log_data->b_rptr; 4510Sstevel@tonic-gate trace_ids_t *tidend = (trace_ids_t *)lp->log_data->b_wptr; 4520Sstevel@tonic-gate 4530Sstevel@tonic-gate /* 4540Sstevel@tonic-gate * We use `tid + 1 <= tidend' here rather than the more traditional 4550Sstevel@tonic-gate * `tid < tidend', since the former ensures that there's at least 4560Sstevel@tonic-gate * `sizeof (trace_ids_t)' bytes available before executing the 4570Sstevel@tonic-gate * loop, whereas the latter only ensures that there's a single byte. 4580Sstevel@tonic-gate */ 4590Sstevel@tonic-gate for (; tid + 1 <= tidend; tid++) { 4600Sstevel@tonic-gate if (tid->ti_level < lc->level && tid->ti_level >= 0) 4610Sstevel@tonic-gate continue; 4620Sstevel@tonic-gate if (tid->ti_mid != lc->mid && tid->ti_mid >= 0) 4630Sstevel@tonic-gate continue; 4640Sstevel@tonic-gate if (tid->ti_sid != lc->sid && tid->ti_sid >= 0) 4650Sstevel@tonic-gate continue; 4660Sstevel@tonic-gate if ((lc->pri & LOG_FACMASK) == LOG_KERN) 4670Sstevel@tonic-gate lc->pri = LOG_KERN | LOG_DEBUG; 4680Sstevel@tonic-gate return (1); 4690Sstevel@tonic-gate } 4700Sstevel@tonic-gate return (0); 4710Sstevel@tonic-gate } 4720Sstevel@tonic-gate 4730Sstevel@tonic-gate /*ARGSUSED*/ 4740Sstevel@tonic-gate int 4750Sstevel@tonic-gate log_console(log_t *lp, log_ctl_t *lc) 4760Sstevel@tonic-gate { 4770Sstevel@tonic-gate if ((lc->pri & LOG_FACMASK) == LOG_KERN) { 4780Sstevel@tonic-gate if (lc->flags & SL_FATAL) 4790Sstevel@tonic-gate lc->pri = LOG_KERN | LOG_CRIT; 4800Sstevel@tonic-gate else if (lc->flags & SL_ERROR) 4810Sstevel@tonic-gate lc->pri = LOG_KERN | LOG_ERR; 4820Sstevel@tonic-gate else if (lc->flags & SL_WARN) 4830Sstevel@tonic-gate lc->pri = LOG_KERN | LOG_WARNING; 4840Sstevel@tonic-gate else if (lc->flags & SL_NOTE) 4850Sstevel@tonic-gate lc->pri = LOG_KERN | LOG_NOTICE; 4860Sstevel@tonic-gate else if (lc->flags & SL_TRACE) 4870Sstevel@tonic-gate lc->pri = LOG_KERN | LOG_DEBUG; 4880Sstevel@tonic-gate else 4890Sstevel@tonic-gate lc->pri = LOG_KERN | LOG_INFO; 4900Sstevel@tonic-gate } 4910Sstevel@tonic-gate return (1); 4920Sstevel@tonic-gate } 4930Sstevel@tonic-gate 4940Sstevel@tonic-gate mblk_t * 4950Sstevel@tonic-gate log_makemsg(int mid, int sid, int level, int sl, int pri, void *msg, 4960Sstevel@tonic-gate size_t size, int on_intr) 4970Sstevel@tonic-gate { 4980Sstevel@tonic-gate mblk_t *mp = NULL; 4990Sstevel@tonic-gate mblk_t *mp2; 5000Sstevel@tonic-gate log_ctl_t *lc; 5010Sstevel@tonic-gate 5020Sstevel@tonic-gate if (size <= LOG_MSGSIZE && 5030Sstevel@tonic-gate (on_intr || log_freeq->q_count > log_freeq->q_lowat)) 5040Sstevel@tonic-gate mp = getq_noenab(log_freeq); 5050Sstevel@tonic-gate 5060Sstevel@tonic-gate if (mp == NULL) { 5070Sstevel@tonic-gate if (on_intr || 5080Sstevel@tonic-gate (mp = allocb(sizeof (log_ctl_t), BPRI_HI)) == NULL || 5090Sstevel@tonic-gate (mp2 = allocb(MAX(size, LOG_MSGSIZE), BPRI_HI)) == NULL) { 5100Sstevel@tonic-gate freemsg(mp); 5110Sstevel@tonic-gate return (NULL); 5120Sstevel@tonic-gate } 5130Sstevel@tonic-gate DB_TYPE(mp) = M_PROTO; 5140Sstevel@tonic-gate mp->b_wptr += sizeof (log_ctl_t); 5150Sstevel@tonic-gate mp->b_cont = mp2; 5160Sstevel@tonic-gate } else { 5170Sstevel@tonic-gate mp2 = mp->b_cont; 5180Sstevel@tonic-gate mp2->b_wptr = mp2->b_rptr; 5190Sstevel@tonic-gate } 5200Sstevel@tonic-gate 5210Sstevel@tonic-gate lc = (log_ctl_t *)mp->b_rptr; 5220Sstevel@tonic-gate lc->mid = mid; 5230Sstevel@tonic-gate lc->sid = sid; 5240Sstevel@tonic-gate lc->level = level; 5250Sstevel@tonic-gate lc->flags = sl; 5260Sstevel@tonic-gate lc->pri = pri; 5270Sstevel@tonic-gate 5280Sstevel@tonic-gate bcopy(msg, mp2->b_wptr, size - 1); 5290Sstevel@tonic-gate mp2->b_wptr[size - 1] = '\0'; 5300Sstevel@tonic-gate mp2->b_wptr += strlen((char *)mp2->b_wptr) + 1; 5310Sstevel@tonic-gate 5320Sstevel@tonic-gate return (mp); 5330Sstevel@tonic-gate } 5340Sstevel@tonic-gate 5350Sstevel@tonic-gate void 5360Sstevel@tonic-gate log_freemsg(mblk_t *mp) 5370Sstevel@tonic-gate { 5380Sstevel@tonic-gate mblk_t *mp2 = mp->b_cont; 5390Sstevel@tonic-gate 5400Sstevel@tonic-gate ASSERT(MBLKL(mp) == sizeof (log_ctl_t)); 5410Sstevel@tonic-gate ASSERT(mp2->b_rptr == mp2->b_datap->db_base); 5420Sstevel@tonic-gate 5430Sstevel@tonic-gate if ((log_freeq->q_flag & QFULL) == 0 && 5440Sstevel@tonic-gate MBLKL(mp2) <= LOG_MSGSIZE && MBLKSIZE(mp2) >= LOG_MSGSIZE) 5450Sstevel@tonic-gate (void) putq(log_freeq, mp); 5460Sstevel@tonic-gate else 5470Sstevel@tonic-gate freemsg(mp); 5480Sstevel@tonic-gate } 5490Sstevel@tonic-gate 5500Sstevel@tonic-gate void 5510Sstevel@tonic-gate log_sendmsg(mblk_t *mp, zoneid_t zoneid) 5520Sstevel@tonic-gate { 5530Sstevel@tonic-gate log_t *lp; 5540Sstevel@tonic-gate char *src, *dst; 5550Sstevel@tonic-gate mblk_t *mp2 = mp->b_cont; 5560Sstevel@tonic-gate log_ctl_t *lc = (log_ctl_t *)mp->b_rptr; 5570Sstevel@tonic-gate int flags, fac; 5580Sstevel@tonic-gate off_t facility = 0; 5590Sstevel@tonic-gate off_t body = 0; 5600Sstevel@tonic-gate zone_t *zptr = NULL; 5610Sstevel@tonic-gate log_zone_t *lzp; 5620Sstevel@tonic-gate int i; 5630Sstevel@tonic-gate int backlog; 5640Sstevel@tonic-gate 5650Sstevel@tonic-gate /* 5660Sstevel@tonic-gate * Need to special case the global zone here since this may be 5670Sstevel@tonic-gate * called before zone_init. 5680Sstevel@tonic-gate */ 5690Sstevel@tonic-gate if (zoneid == GLOBAL_ZONEID) { 5700Sstevel@tonic-gate lzp = &log_global; 5710Sstevel@tonic-gate } else if ((zptr = zone_find_by_id(zoneid)) == NULL) { 5720Sstevel@tonic-gate /* specified zone doesn't exist, free message and return */ 5730Sstevel@tonic-gate log_freemsg(mp); 5740Sstevel@tonic-gate return; 5750Sstevel@tonic-gate } else { 5760Sstevel@tonic-gate lzp = zone_getspecific(log_zone_key, zptr); 5770Sstevel@tonic-gate } 5780Sstevel@tonic-gate ASSERT(lzp != NULL); 5790Sstevel@tonic-gate 5800Sstevel@tonic-gate if ((lc->flags & lzp->lz_active) == 0) { 5810Sstevel@tonic-gate if (zptr) 5820Sstevel@tonic-gate zone_rele(zptr); 5830Sstevel@tonic-gate log_freemsg(mp); 5840Sstevel@tonic-gate return; 5850Sstevel@tonic-gate } 5860Sstevel@tonic-gate 5870Sstevel@tonic-gate if (panicstr) { 5880Sstevel@tonic-gate /* 5890Sstevel@tonic-gate * Raise the console queue's q_hiwat to ensure that we 5900Sstevel@tonic-gate * capture all panic messages. 5910Sstevel@tonic-gate */ 5920Sstevel@tonic-gate log_consq->q_hiwat = 2 * LOG_HIWAT; 5930Sstevel@tonic-gate log_consq->q_flag &= ~QFULL; 5940Sstevel@tonic-gate 5950Sstevel@tonic-gate /* Message was created while panicking. */ 5960Sstevel@tonic-gate lc->flags |= SL_PANICMSG; 5970Sstevel@tonic-gate } 5980Sstevel@tonic-gate 5990Sstevel@tonic-gate src = (char *)mp2->b_rptr; 6000Sstevel@tonic-gate dst = strstr(src, "FACILITY_AND_PRIORITY] "); 6010Sstevel@tonic-gate if (dst != NULL) { 6020Sstevel@tonic-gate facility = dst - src; 6030Sstevel@tonic-gate body = facility + 23; /* strlen("FACILITY_AND_PRIORITY] ") */ 6040Sstevel@tonic-gate } 6050Sstevel@tonic-gate 6060Sstevel@tonic-gate log_enter(); 6070Sstevel@tonic-gate 6080Sstevel@tonic-gate lc->ltime = lbolt; 6090Sstevel@tonic-gate lc->ttime = gethrestime_sec(); 6100Sstevel@tonic-gate 6110Sstevel@tonic-gate flags = lc->flags & lzp->lz_active; 6120Sstevel@tonic-gate log_seq_no[flags & SL_ERROR]++; 6130Sstevel@tonic-gate log_seq_no[flags & SL_TRACE]++; 6140Sstevel@tonic-gate log_seq_no[flags & SL_CONSOLE]++; 6150Sstevel@tonic-gate 6160Sstevel@tonic-gate /* 6170Sstevel@tonic-gate * If this is in the global zone, start with the backlog, then 6180Sstevel@tonic-gate * walk through the clone logs. If not, just do the clone logs. 6190Sstevel@tonic-gate */ 6200Sstevel@tonic-gate backlog = (zoneid == GLOBAL_ZONEID); 6210Sstevel@tonic-gate i = LOG_LOGMINIDX; 6220Sstevel@tonic-gate while (i <= LOG_LOGMAXIDX) { 6230Sstevel@tonic-gate if (backlog) { 6240Sstevel@tonic-gate /* 6250Sstevel@tonic-gate * Do the backlog this time, then start on the 6260Sstevel@tonic-gate * others. 6270Sstevel@tonic-gate */ 6280Sstevel@tonic-gate backlog = 0; 6290Sstevel@tonic-gate lp = &log_backlog; 6300Sstevel@tonic-gate } else { 6310Sstevel@tonic-gate lp = &lzp->lz_clones[i++]; 6320Sstevel@tonic-gate } 6330Sstevel@tonic-gate 6340Sstevel@tonic-gate if ((lp->log_flags & flags) && lp->log_wanted(lp, lc)) { 6350Sstevel@tonic-gate if (canput(lp->log_q)) { 6360Sstevel@tonic-gate lp->log_overflow = 0; 6370Sstevel@tonic-gate lc->seq_no = log_seq_no[lp->log_flags]; 6380Sstevel@tonic-gate if ((mp2 = copymsg(mp)) == NULL) 6390Sstevel@tonic-gate break; 6400Sstevel@tonic-gate if (facility != 0) { 6410Sstevel@tonic-gate src = (char *)mp2->b_cont->b_rptr; 6420Sstevel@tonic-gate dst = src + facility; 6430Sstevel@tonic-gate fac = (lc->pri & LOG_FACMASK) >> 3; 6440Sstevel@tonic-gate dst += snprintf(dst, 6450Sstevel@tonic-gate LOG_FACSIZE + LOG_PRISIZE, "%s.%s", 6460Sstevel@tonic-gate log_fac[MIN(fac, LOG_NFACILITIES)], 6470Sstevel@tonic-gate log_pri[lc->pri & LOG_PRIMASK]); 6480Sstevel@tonic-gate src += body - 2; /* copy "] " too */ 6490Sstevel@tonic-gate while (*src != '\0') 6500Sstevel@tonic-gate *dst++ = *src++; 6510Sstevel@tonic-gate *dst++ = '\0'; 6520Sstevel@tonic-gate mp2->b_cont->b_wptr = (uchar_t *)dst; 6530Sstevel@tonic-gate } 6540Sstevel@tonic-gate (void) putq(lp->log_q, mp2); 6550Sstevel@tonic-gate } else if (++lp->log_overflow == 1) { 6560Sstevel@tonic-gate if (lp->log_q == log_consq) { 6570Sstevel@tonic-gate console_printf(log_overflow_msg, 6580Sstevel@tonic-gate lp->log_minor, 6590Sstevel@tonic-gate " -- is syslogd(1M) running?"); 6600Sstevel@tonic-gate } else { 6610Sstevel@tonic-gate printf(log_overflow_msg, 6620Sstevel@tonic-gate lp->log_minor, ""); 6630Sstevel@tonic-gate } 6640Sstevel@tonic-gate } 6650Sstevel@tonic-gate } 6660Sstevel@tonic-gate } 6670Sstevel@tonic-gate 6680Sstevel@tonic-gate if (zptr) 6690Sstevel@tonic-gate zone_rele(zptr); 6700Sstevel@tonic-gate 6710Sstevel@tonic-gate if ((flags & SL_CONSOLE) && (lc->pri & LOG_FACMASK) == LOG_KERN) { 6720Sstevel@tonic-gate if ((mp2 == NULL || log_consq == log_backlogq || panicstr) && 6730Sstevel@tonic-gate (lc->flags & SL_LOGONLY) == 0) 6740Sstevel@tonic-gate console_printf("%s", (char *)mp->b_cont->b_rptr + body); 6750Sstevel@tonic-gate if ((lc->flags & SL_CONSONLY) == 0 && 6760Sstevel@tonic-gate (mp2 = copymsg(mp)) != NULL) { 6770Sstevel@tonic-gate mp2->b_cont->b_rptr += body; 6780Sstevel@tonic-gate if (log_recentq->q_flag & QFULL) 6790Sstevel@tonic-gate freemsg(getq_noenab(log_recentq)); 6800Sstevel@tonic-gate (void) putq(log_recentq, mp2); 6810Sstevel@tonic-gate } 6820Sstevel@tonic-gate } 6830Sstevel@tonic-gate 6840Sstevel@tonic-gate log_freemsg(mp); 6850Sstevel@tonic-gate 6860Sstevel@tonic-gate log_exit(); 6870Sstevel@tonic-gate } 6880Sstevel@tonic-gate 6890Sstevel@tonic-gate /* 6900Sstevel@tonic-gate * Print queued messages to console. 6910Sstevel@tonic-gate */ 6920Sstevel@tonic-gate void 6930Sstevel@tonic-gate log_printq(queue_t *qfirst) 6940Sstevel@tonic-gate { 6950Sstevel@tonic-gate mblk_t *mp; 6960Sstevel@tonic-gate queue_t *q, *qlast; 6970Sstevel@tonic-gate char *cp, *msgp; 6980Sstevel@tonic-gate log_ctl_t *lc; 6990Sstevel@tonic-gate 7000Sstevel@tonic-gate /* 7010Sstevel@tonic-gate * Look ahead to first queued message in the stream. 7020Sstevel@tonic-gate */ 7030Sstevel@tonic-gate qlast = NULL; 7040Sstevel@tonic-gate do { 7050Sstevel@tonic-gate for (q = qfirst; q->q_next != qlast; q = q->q_next) 7060Sstevel@tonic-gate continue; 7070Sstevel@tonic-gate for (mp = q->q_first; mp != NULL; mp = mp->b_next) { 7080Sstevel@tonic-gate lc = (log_ctl_t *)mp->b_rptr; 7090Sstevel@tonic-gate /* 7100Sstevel@tonic-gate * Check if message is already displayed at 7110Sstevel@tonic-gate * /dev/console. 7120Sstevel@tonic-gate */ 7130Sstevel@tonic-gate if (lc->flags & SL_PANICMSG) 7140Sstevel@tonic-gate continue; 7150Sstevel@tonic-gate 7160Sstevel@tonic-gate cp = (char *)mp->b_cont->b_rptr; 7170Sstevel@tonic-gate 7180Sstevel@tonic-gate /* Strip off the message ID. */ 7190Sstevel@tonic-gate if ((msgp = strstr(cp, "[ID ")) != NULL && 7200Sstevel@tonic-gate (msgp = strstr(msgp, "] ")) != NULL) { 7210Sstevel@tonic-gate cp = msgp + 2; 7220Sstevel@tonic-gate } 7230Sstevel@tonic-gate 7240Sstevel@tonic-gate /* 7250Sstevel@tonic-gate * Using console_printf instead of printf to avoid 7260Sstevel@tonic-gate * queueing messages to log_consq. 7270Sstevel@tonic-gate */ 7280Sstevel@tonic-gate console_printf("%s", cp); 7290Sstevel@tonic-gate } 7300Sstevel@tonic-gate } while ((qlast = q) != qfirst); 7310Sstevel@tonic-gate } 7321259Sns92644 7331259Sns92644 /* ARGSUSED */ 7341259Sns92644 static int 7351259Sns92644 log_cons_constructor(void *buf, void *cdrarg, int kmflags) 7361259Sns92644 { 7371259Sns92644 struct log *lp = buf; 7381259Sns92644 7391259Sns92644 lp->log_zoneid = GLOBAL_ZONEID; 7401259Sns92644 lp->log_major = LOG_CONSMIN; /* Indicate which device type */ 7411259Sns92644 lp->log_data = NULL; 7421259Sns92644 return (0); 7431259Sns92644 } 7441259Sns92644 7451259Sns92644 /* ARGSUSED */ 7461259Sns92644 static void 7471259Sns92644 log_cons_destructor(void *buf, void *cdrarg) 7481259Sns92644 { 7491259Sns92644 struct log *lp = buf; 7501259Sns92644 7511259Sns92644 ASSERT(lp->log_zoneid == GLOBAL_ZONEID); 7521259Sns92644 ASSERT(lp->log_major == LOG_CONSMIN); 7531259Sns92644 ASSERT(lp->log_data == NULL); 7541259Sns92644 } 755