1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/types.h> 30 #include <sys/param.h> 31 #include <sys/varargs.h> 32 #include <sys/systm.h> 33 #include <sys/cmn_err.h> 34 #include <sys/stream.h> 35 #include <sys/strsubr.h> 36 #include <sys/strsun.h> 37 #include <sys/sysmacros.h> 38 #include <sys/kmem.h> 39 #include <sys/log.h> 40 #include <sys/spl.h> 41 #include <sys/syslog.h> 42 #include <sys/console.h> 43 #include <sys/debug.h> 44 #include <sys/utsname.h> 45 #include <sys/id_space.h> 46 #include <sys/zone.h> 47 48 log_zone_t log_global; 49 queue_t *log_consq; 50 queue_t *log_backlogq; 51 queue_t *log_intrq; 52 53 #define LOG_PRISIZE 8 /* max priority size: 7 characters + null */ 54 #define LOG_FACSIZE 9 /* max priority size: 8 characters + null */ 55 56 static krwlock_t log_rwlock; 57 static int log_rwlock_depth; 58 static int log_seq_no[SL_CONSOLE + 1]; 59 static stdata_t log_fakestr; 60 static id_space_t *log_minorspace; 61 static log_t log_backlog; 62 static struct kmem_cache *log_cons_cache; /* log_t cache */ 63 static vmem_t *log_cons_minor_arena; /* Arena for device minors */ 64 65 static queue_t *log_recentq; 66 static queue_t *log_freeq; 67 68 static zone_key_t log_zone_key; 69 70 static char log_overflow_msg[] = "message overflow on /dev/log minor #%d%s\n"; 71 72 static char log_pri[LOG_PRIMASK + 1][LOG_PRISIZE] = { 73 "emerg", "alert", "crit", "error", 74 "warning", "notice", "info", "debug" 75 }; 76 77 static char log_fac[LOG_NFACILITIES + 1][LOG_FACSIZE] = { 78 "kern", "user", "mail", "daemon", 79 "auth", "syslog", "lpr", "news", 80 "uucp", "resv9", "resv10", "resv11", 81 "resv12", "audit", "resv14", "cron", 82 "local0", "local1", "local2", "local3", 83 "local4", "local5", "local6", "local7", 84 "unknown" 85 }; 86 static int log_cons_constructor(void *, void *, int); 87 static void log_cons_destructor(void *, void *); 88 89 /* 90 * Get exclusive access to the logging system; this includes all minor 91 * devices. We use an rwlock rather than a mutex because hold times 92 * are potentially long, so we don't want to waste cycles in adaptive mutex 93 * spin (rwlocks always block when contended). Note that we explicitly 94 * support recursive calls (e.g. printf() calls foo() calls printf()). 95 * 96 * Clients may use log_enter() / log_exit() to guarantee that a group 97 * of messages is treated atomically (i.e. they appear in order and are 98 * not interspersed with any other messages), e.g. for multiline printf(). 99 * 100 * This could probably be changed to a per-zone lock if contention becomes 101 * an issue. 102 */ 103 void 104 log_enter(void) 105 { 106 if (rw_owner(&log_rwlock) != curthread) 107 rw_enter(&log_rwlock, RW_WRITER); 108 log_rwlock_depth++; 109 } 110 111 void 112 log_exit(void) 113 { 114 if (--log_rwlock_depth == 0) 115 rw_exit(&log_rwlock); 116 } 117 118 void 119 log_flushq(queue_t *q) 120 { 121 mblk_t *mp; 122 log_t *lp = (log_t *)q->q_ptr; 123 124 /* lp will be NULL if the queue was created via log_makeq */ 125 while ((mp = getq_noenab(q)) != NULL) 126 log_sendmsg(mp, lp == NULL ? GLOBAL_ZONEID : lp->log_zoneid); 127 } 128 129 /* 130 * Create a minimal queue with just enough fields filled in to support 131 * canput(9F), putq(9F), and getq_noenab(9F). We set QNOENB to ensure 132 * that the queue will never be enabled. 133 */ 134 static queue_t * 135 log_makeq(size_t lowat, size_t hiwat, void *ibc) 136 { 137 queue_t *q; 138 139 q = kmem_zalloc(sizeof (queue_t), KM_SLEEP); 140 q->q_stream = &log_fakestr; 141 q->q_flag = QISDRV | QMTSAFE | QNOENB | QREADR | QUSE; 142 q->q_nfsrv = q; 143 q->q_lowat = lowat; 144 q->q_hiwat = hiwat; 145 mutex_init(QLOCK(q), NULL, MUTEX_DRIVER, ibc); 146 147 return (q); 148 } 149 150 /* 151 * Initialize the log structure for a new zone. 152 */ 153 static void * 154 log_zoneinit(zoneid_t zoneid) 155 { 156 int i; 157 log_zone_t *lzp; 158 159 if (zoneid == GLOBAL_ZONEID) 160 lzp = &log_global; /* use statically allocated struct */ 161 else 162 lzp = kmem_zalloc(sizeof (log_zone_t), KM_SLEEP); 163 164 for (i = 0; i < LOG_NUMCLONES; i++) { 165 lzp->lz_clones[i].log_minor = 166 (minor_t)id_alloc(log_minorspace); 167 lzp->lz_clones[i].log_zoneid = zoneid; 168 } 169 return (lzp); 170 } 171 172 /*ARGSUSED*/ 173 static void 174 log_zonefree(zoneid_t zoneid, void *arg) 175 { 176 log_zone_t *lzp = arg; 177 int i; 178 179 ASSERT(lzp != &log_global && zoneid != GLOBAL_ZONEID); 180 if (lzp == NULL) 181 return; 182 for (i = 0; i < LOG_NUMCLONES; i++) 183 id_free(log_minorspace, lzp->lz_clones[i].log_minor); 184 kmem_free(lzp, sizeof (log_zone_t)); 185 } 186 187 void 188 log_init(void) 189 { 190 int log_maxzones; 191 192 /* 193 * Create a backlog queue to consume console messages during periods 194 * when there is no console reader (e.g. before syslogd(1M) starts). 195 */ 196 log_backlogq = log_consq = log_makeq(0, LOG_HIWAT, NULL); 197 198 /* 199 * Create a queue to hold free message of size <= LOG_MSGSIZE. 200 * Calls from high-level interrupt handlers will do a getq_noenab() 201 * from this queue, so its q_lock must be a maximum SPL spin lock. 202 */ 203 log_freeq = log_makeq(LOG_MINFREE, LOG_MAXFREE, (void *)ipltospl(SPL8)); 204 205 /* 206 * Create a queue for messages from high-level interrupt context. 207 * These messages are drained via softcall, or explicitly by panic(). 208 */ 209 log_intrq = log_makeq(0, LOG_HIWAT, (void *)ipltospl(SPL8)); 210 211 /* 212 * Create a queue to hold the most recent 8K of console messages. 213 * Useful for debugging. Required by the "$<msgbuf" adb macro. 214 */ 215 log_recentq = log_makeq(0, LOG_RECENTSIZE, NULL); 216 217 /* 218 * Create an id space for clone devices opened via /dev/log. 219 * Need to limit the number of zones to avoid exceeding the 220 * available minor number space. 221 */ 222 log_maxzones = (L_MAXMIN32 - LOG_LOGMIN) / LOG_NUMCLONES - 1; 223 if (log_maxzones < maxzones) 224 maxzones = log_maxzones; 225 log_minorspace = id_space_create("logminor_space", LOG_LOGMIN + 1, 226 L_MAXMIN32); 227 /* 228 * Put ourselves on the ZSD list. Note that zones have not been 229 * initialized yet, but our constructor will be called on the global 230 * zone when they are. 231 */ 232 zone_key_create(&log_zone_key, log_zoneinit, NULL, log_zonefree); 233 234 /* 235 * Initialize backlog structure. 236 */ 237 log_backlog.log_zoneid = GLOBAL_ZONEID; 238 log_backlog.log_minor = LOG_BACKLOG; 239 240 /* Allocate integer space for conslog's minor numbers */ 241 log_cons_minor_arena = vmem_create("log_cons_minor", (void *)1, 242 LOG_NUMCONS, 1, NULL, NULL, NULL, 0, 243 VM_SLEEP | VMC_IDENTIFIER); 244 245 /* Allocate kmem cache for conslog's log structures */ 246 log_cons_cache = kmem_cache_create("log_cons_cache", 247 sizeof (struct log), 0, log_cons_constructor, log_cons_destructor, 248 NULL, NULL, NULL, 0); 249 250 /* 251 * Let the logging begin. 252 */ 253 log_update(&log_backlog, log_backlogq, SL_CONSOLE, log_console); 254 255 /* 256 * Now that logging is enabled, emit the SunOS banner. 257 */ 258 printf("\rSunOS Release %s Version %s %u-bit\n", 259 utsname.release, utsname.version, NBBY * (uint_t)sizeof (void *)); 260 printf("Copyright 1983-2005 Sun Microsystems, Inc. " 261 "All rights reserved.\nUse is subject to license terms.\n"); 262 #ifdef DEBUG 263 printf("DEBUG enabled\n"); 264 #endif 265 } 266 267 /* 268 * Allocate a log device corresponding to supplied device type. 269 * Both devices are clonable. /dev/log devices are allocated per zone. 270 * /dev/conslog devices are allocated from kmem cache, with minor numbers 271 * supplied from a vmem arena. 272 */ 273 log_t * 274 log_alloc(minor_t type) 275 { 276 zone_t *zptr = curproc->p_zone; 277 log_zone_t *lzp; 278 log_t *lp; 279 int i; 280 minor_t minor; 281 282 if (type == LOG_CONSMIN) { 283 284 /* 285 * Return a write-only /dev/conslog device. 286 * No point allocating log_t until there's a free minor number. 287 */ 288 minor = (minor_t)(uintptr_t) 289 vmem_alloc(log_cons_minor_arena, 1, VM_SLEEP); 290 lp = kmem_cache_alloc(log_cons_cache, KM_SLEEP); 291 lp->log_minor = minor; 292 return (lp); 293 } else { 294 ASSERT(type == LOG_LOGMIN); 295 296 lzp = zone_getspecific(log_zone_key, zptr); 297 ASSERT(lzp != NULL); 298 299 /* search for an available /dev/log device for the zone */ 300 for (i = LOG_LOGMINIDX; i <= LOG_LOGMAXIDX; i++) { 301 lp = &lzp->lz_clones[i]; 302 if (lp->log_inuse == 0) 303 break; 304 } 305 if (i > LOG_LOGMAXIDX) 306 lp = NULL; 307 lp->log_major = LOG_LOGMIN; 308 return (lp); 309 } 310 } 311 312 void 313 log_free(log_t *lp) 314 { 315 /* Return minor number to the pool */ 316 vmem_free(log_cons_minor_arena, (void *)(uintptr_t)lp->log_minor, 1); 317 /* Return log to the cache */ 318 kmem_cache_free(log_cons_cache, lp); 319 } 320 321 /* 322 * Move console messages from src to dst. The time of day isn't known 323 * early in boot, so fix up the message timestamps if necessary. 324 */ 325 static void 326 log_conswitch(log_t *src, log_t *dst) 327 { 328 mblk_t *mp; 329 mblk_t *hmp = NULL; 330 mblk_t *tmp = NULL; 331 log_ctl_t *hlc; 332 333 while ((mp = getq_noenab(src->log_q)) != NULL) { 334 log_ctl_t *lc = (log_ctl_t *)mp->b_rptr; 335 lc->flags |= SL_LOGONLY; 336 337 /* 338 * In the early boot phase hrestime is invalid. 339 * hrestime becomes valid when clock() runs for the first time. 340 * At this time is lbolt == 1. log_sendmsg() saves the lbolt 341 * value in ltime. 342 */ 343 if (lc->ltime < 2) { 344 /* 345 * Look ahead to first early boot message with time. 346 */ 347 if (hmp) { 348 tmp->b_next = mp; 349 tmp = mp; 350 } else 351 hmp = tmp = mp; 352 continue; 353 } 354 355 while (hmp) { 356 tmp = hmp->b_next; 357 hmp->b_next = NULL; 358 hlc = (log_ctl_t *)hmp->b_rptr; 359 /* 360 * Calculate hrestime for an early log message with 361 * an invalid time stamp. We know: 362 * - the lbolt of the invalid time stamp. 363 * - the hrestime and lbolt of the first valid 364 * time stamp. 365 */ 366 hlc->ttime = lc->ttime - (lc->ltime - hlc->ltime) / hz; 367 (void) putq(dst->log_q, hmp); 368 hmp = tmp; 369 } 370 (void) putq(dst->log_q, mp); 371 } 372 while (hmp) { 373 tmp = hmp->b_next; 374 hmp->b_next = NULL; 375 hlc = (log_ctl_t *)hmp->b_rptr; 376 hlc->ttime = gethrestime_sec() - (lbolt - hlc->ltime) / hz; 377 (void) putq(dst->log_q, hmp); 378 hmp = tmp; 379 } 380 dst->log_overflow = src->log_overflow; 381 src->log_flags = 0; 382 dst->log_flags = SL_CONSOLE; 383 log_consq = dst->log_q; 384 } 385 386 /* 387 * Set the fields in the 'target' clone to the specified values. 388 * Then, look at all clones to determine which message types are 389 * currently active and which clone is the primary console queue. 390 * If the primary console queue changes to or from the backlog 391 * queue, copy all messages from backlog to primary or vice versa. 392 */ 393 void 394 log_update(log_t *target, queue_t *q, short flags, log_filter_t *filter) 395 { 396 log_t *lp; 397 short active = SL_CONSOLE; 398 zone_t *zptr = NULL; 399 log_zone_t *lzp; 400 zoneid_t zoneid = target->log_zoneid; 401 int i; 402 403 log_enter(); 404 405 if (q != NULL) 406 target->log_q = q; 407 target->log_wanted = filter; 408 target->log_flags = flags; 409 target->log_overflow = 0; 410 411 /* 412 * Need to special case the global zone here since this may be 413 * called before zone_init. 414 */ 415 if (zoneid == GLOBAL_ZONEID) { 416 lzp = &log_global; 417 } else if ((zptr = zone_find_by_id(zoneid)) == NULL) { 418 log_exit(); 419 return; /* zone is being destroyed, ignore update */ 420 } else { 421 lzp = zone_getspecific(log_zone_key, zptr); 422 } 423 ASSERT(lzp != NULL); 424 for (i = LOG_LOGMAXIDX; i >= LOG_LOGMINIDX; i--) { 425 lp = &lzp->lz_clones[i]; 426 if (zoneid == GLOBAL_ZONEID && (lp->log_flags & SL_CONSOLE)) 427 log_consq = lp->log_q; 428 active |= lp->log_flags; 429 } 430 lzp->lz_active = active; 431 432 if (zptr) 433 zone_rele(zptr); 434 435 if (log_consq == target->log_q) { 436 if (flags & SL_CONSOLE) 437 log_conswitch(&log_backlog, target); 438 else 439 log_conswitch(target, &log_backlog); 440 } 441 target->log_q = q; 442 443 log_exit(); 444 } 445 446 /*ARGSUSED*/ 447 int 448 log_error(log_t *lp, log_ctl_t *lc) 449 { 450 if ((lc->pri & LOG_FACMASK) == LOG_KERN) 451 lc->pri = LOG_KERN | LOG_ERR; 452 return (1); 453 } 454 455 int 456 log_trace(log_t *lp, log_ctl_t *lc) 457 { 458 trace_ids_t *tid = (trace_ids_t *)lp->log_data->b_rptr; 459 trace_ids_t *tidend = (trace_ids_t *)lp->log_data->b_wptr; 460 461 /* 462 * We use `tid + 1 <= tidend' here rather than the more traditional 463 * `tid < tidend', since the former ensures that there's at least 464 * `sizeof (trace_ids_t)' bytes available before executing the 465 * loop, whereas the latter only ensures that there's a single byte. 466 */ 467 for (; tid + 1 <= tidend; tid++) { 468 if (tid->ti_level < lc->level && tid->ti_level >= 0) 469 continue; 470 if (tid->ti_mid != lc->mid && tid->ti_mid >= 0) 471 continue; 472 if (tid->ti_sid != lc->sid && tid->ti_sid >= 0) 473 continue; 474 if ((lc->pri & LOG_FACMASK) == LOG_KERN) 475 lc->pri = LOG_KERN | LOG_DEBUG; 476 return (1); 477 } 478 return (0); 479 } 480 481 /*ARGSUSED*/ 482 int 483 log_console(log_t *lp, log_ctl_t *lc) 484 { 485 if ((lc->pri & LOG_FACMASK) == LOG_KERN) { 486 if (lc->flags & SL_FATAL) 487 lc->pri = LOG_KERN | LOG_CRIT; 488 else if (lc->flags & SL_ERROR) 489 lc->pri = LOG_KERN | LOG_ERR; 490 else if (lc->flags & SL_WARN) 491 lc->pri = LOG_KERN | LOG_WARNING; 492 else if (lc->flags & SL_NOTE) 493 lc->pri = LOG_KERN | LOG_NOTICE; 494 else if (lc->flags & SL_TRACE) 495 lc->pri = LOG_KERN | LOG_DEBUG; 496 else 497 lc->pri = LOG_KERN | LOG_INFO; 498 } 499 return (1); 500 } 501 502 mblk_t * 503 log_makemsg(int mid, int sid, int level, int sl, int pri, void *msg, 504 size_t size, int on_intr) 505 { 506 mblk_t *mp = NULL; 507 mblk_t *mp2; 508 log_ctl_t *lc; 509 510 if (size <= LOG_MSGSIZE && 511 (on_intr || log_freeq->q_count > log_freeq->q_lowat)) 512 mp = getq_noenab(log_freeq); 513 514 if (mp == NULL) { 515 if (on_intr || 516 (mp = allocb(sizeof (log_ctl_t), BPRI_HI)) == NULL || 517 (mp2 = allocb(MAX(size, LOG_MSGSIZE), BPRI_HI)) == NULL) { 518 freemsg(mp); 519 return (NULL); 520 } 521 DB_TYPE(mp) = M_PROTO; 522 mp->b_wptr += sizeof (log_ctl_t); 523 mp->b_cont = mp2; 524 } else { 525 mp2 = mp->b_cont; 526 mp2->b_wptr = mp2->b_rptr; 527 } 528 529 lc = (log_ctl_t *)mp->b_rptr; 530 lc->mid = mid; 531 lc->sid = sid; 532 lc->level = level; 533 lc->flags = sl; 534 lc->pri = pri; 535 536 bcopy(msg, mp2->b_wptr, size - 1); 537 mp2->b_wptr[size - 1] = '\0'; 538 mp2->b_wptr += strlen((char *)mp2->b_wptr) + 1; 539 540 return (mp); 541 } 542 543 void 544 log_freemsg(mblk_t *mp) 545 { 546 mblk_t *mp2 = mp->b_cont; 547 548 ASSERT(MBLKL(mp) == sizeof (log_ctl_t)); 549 ASSERT(mp2->b_rptr == mp2->b_datap->db_base); 550 551 if ((log_freeq->q_flag & QFULL) == 0 && 552 MBLKL(mp2) <= LOG_MSGSIZE && MBLKSIZE(mp2) >= LOG_MSGSIZE) 553 (void) putq(log_freeq, mp); 554 else 555 freemsg(mp); 556 } 557 558 void 559 log_sendmsg(mblk_t *mp, zoneid_t zoneid) 560 { 561 log_t *lp; 562 char *src, *dst; 563 mblk_t *mp2 = mp->b_cont; 564 log_ctl_t *lc = (log_ctl_t *)mp->b_rptr; 565 int flags, fac; 566 off_t facility = 0; 567 off_t body = 0; 568 zone_t *zptr = NULL; 569 log_zone_t *lzp; 570 int i; 571 int backlog; 572 573 /* 574 * Need to special case the global zone here since this may be 575 * called before zone_init. 576 */ 577 if (zoneid == GLOBAL_ZONEID) { 578 lzp = &log_global; 579 } else if ((zptr = zone_find_by_id(zoneid)) == NULL) { 580 /* specified zone doesn't exist, free message and return */ 581 log_freemsg(mp); 582 return; 583 } else { 584 lzp = zone_getspecific(log_zone_key, zptr); 585 } 586 ASSERT(lzp != NULL); 587 588 if ((lc->flags & lzp->lz_active) == 0) { 589 if (zptr) 590 zone_rele(zptr); 591 log_freemsg(mp); 592 return; 593 } 594 595 if (panicstr) { 596 /* 597 * Raise the console queue's q_hiwat to ensure that we 598 * capture all panic messages. 599 */ 600 log_consq->q_hiwat = 2 * LOG_HIWAT; 601 log_consq->q_flag &= ~QFULL; 602 603 /* Message was created while panicking. */ 604 lc->flags |= SL_PANICMSG; 605 } 606 607 src = (char *)mp2->b_rptr; 608 dst = strstr(src, "FACILITY_AND_PRIORITY] "); 609 if (dst != NULL) { 610 facility = dst - src; 611 body = facility + 23; /* strlen("FACILITY_AND_PRIORITY] ") */ 612 } 613 614 log_enter(); 615 616 lc->ltime = lbolt; 617 lc->ttime = gethrestime_sec(); 618 619 flags = lc->flags & lzp->lz_active; 620 log_seq_no[flags & SL_ERROR]++; 621 log_seq_no[flags & SL_TRACE]++; 622 log_seq_no[flags & SL_CONSOLE]++; 623 624 /* 625 * If this is in the global zone, start with the backlog, then 626 * walk through the clone logs. If not, just do the clone logs. 627 */ 628 backlog = (zoneid == GLOBAL_ZONEID); 629 i = LOG_LOGMINIDX; 630 while (i <= LOG_LOGMAXIDX) { 631 if (backlog) { 632 /* 633 * Do the backlog this time, then start on the 634 * others. 635 */ 636 backlog = 0; 637 lp = &log_backlog; 638 } else { 639 lp = &lzp->lz_clones[i++]; 640 } 641 642 if ((lp->log_flags & flags) && lp->log_wanted(lp, lc)) { 643 if (canput(lp->log_q)) { 644 lp->log_overflow = 0; 645 lc->seq_no = log_seq_no[lp->log_flags]; 646 if ((mp2 = copymsg(mp)) == NULL) 647 break; 648 if (facility != 0) { 649 src = (char *)mp2->b_cont->b_rptr; 650 dst = src + facility; 651 fac = (lc->pri & LOG_FACMASK) >> 3; 652 dst += snprintf(dst, 653 LOG_FACSIZE + LOG_PRISIZE, "%s.%s", 654 log_fac[MIN(fac, LOG_NFACILITIES)], 655 log_pri[lc->pri & LOG_PRIMASK]); 656 src += body - 2; /* copy "] " too */ 657 while (*src != '\0') 658 *dst++ = *src++; 659 *dst++ = '\0'; 660 mp2->b_cont->b_wptr = (uchar_t *)dst; 661 } 662 (void) putq(lp->log_q, mp2); 663 } else if (++lp->log_overflow == 1) { 664 if (lp->log_q == log_consq) { 665 console_printf(log_overflow_msg, 666 lp->log_minor, 667 " -- is syslogd(1M) running?"); 668 } else { 669 printf(log_overflow_msg, 670 lp->log_minor, ""); 671 } 672 } 673 } 674 } 675 676 if (zptr) 677 zone_rele(zptr); 678 679 if ((flags & SL_CONSOLE) && (lc->pri & LOG_FACMASK) == LOG_KERN) { 680 if ((mp2 == NULL || log_consq == log_backlogq || panicstr) && 681 (lc->flags & SL_LOGONLY) == 0) 682 console_printf("%s", (char *)mp->b_cont->b_rptr + body); 683 if ((lc->flags & SL_CONSONLY) == 0 && 684 (mp2 = copymsg(mp)) != NULL) { 685 mp2->b_cont->b_rptr += body; 686 if (log_recentq->q_flag & QFULL) 687 freemsg(getq_noenab(log_recentq)); 688 (void) putq(log_recentq, mp2); 689 } 690 } 691 692 log_freemsg(mp); 693 694 log_exit(); 695 } 696 697 /* 698 * Print queued messages to console. 699 */ 700 void 701 log_printq(queue_t *qfirst) 702 { 703 mblk_t *mp; 704 queue_t *q, *qlast; 705 char *cp, *msgp; 706 log_ctl_t *lc; 707 708 /* 709 * Look ahead to first queued message in the stream. 710 */ 711 qlast = NULL; 712 do { 713 for (q = qfirst; q->q_next != qlast; q = q->q_next) 714 continue; 715 for (mp = q->q_first; mp != NULL; mp = mp->b_next) { 716 lc = (log_ctl_t *)mp->b_rptr; 717 /* 718 * Check if message is already displayed at 719 * /dev/console. 720 */ 721 if (lc->flags & SL_PANICMSG) 722 continue; 723 724 cp = (char *)mp->b_cont->b_rptr; 725 726 /* Strip off the message ID. */ 727 if ((msgp = strstr(cp, "[ID ")) != NULL && 728 (msgp = strstr(msgp, "] ")) != NULL) { 729 cp = msgp + 2; 730 } 731 732 /* 733 * Using console_printf instead of printf to avoid 734 * queueing messages to log_consq. 735 */ 736 console_printf("%s", cp); 737 } 738 } while ((qlast = q) != qfirst); 739 } 740 741 /* ARGSUSED */ 742 static int 743 log_cons_constructor(void *buf, void *cdrarg, int kmflags) 744 { 745 struct log *lp = buf; 746 lp->log_zoneid = GLOBAL_ZONEID; 747 lp->log_major = LOG_CONSMIN; 748 lp->log_data = NULL; 749 return (0); 750 } 751 752 /* ARGSUSED */ 753 static void 754 log_cons_destructor(void *buf, void *cdrarg) 755 { 756 struct log *lp = buf; 757 ASSERT(lp->log_zoneid == GLOBAL_ZONEID); 758 ASSERT(lp->log_major == LOG_CONSMIN); 759 ASSERT(lp->log_data == NULL); 760 } 761