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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 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. 12 * 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] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2026 Oxide Computer Company 24 * Copyright (c) 2013 Gary Mills 25 * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. 26 */ 27 28 #include <sys/types.h> 29 #include <sys/param.h> 30 #include <sys/varargs.h> 31 #include <sys/systm.h> 32 #include <sys/cmn_err.h> 33 #include <sys/panic.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 #include <sys/bootbanner.h> 48 49 log_zone_t log_global; 50 queue_t *log_consq; 51 queue_t *log_backlogq; 52 queue_t *log_intrq; 53 54 #define LOG_PRISIZE 8 /* max priority size: 7 characters + null */ 55 #define LOG_FACSIZE 9 /* max priority size: 8 characters + null */ 56 57 static krwlock_t log_rwlock; 58 static int log_rwlock_depth; 59 static int log_seq_no[SL_CONSOLE + 1]; 60 static stdata_t log_fakestr; 61 static id_space_t *log_minorspace; 62 static log_t log_backlog; 63 static struct kmem_cache *log_cons_cache; /* log_t cache */ 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", "altcron", "authpriv", "ftp", 81 "ntp", "audit", "console", "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 (panicstr != NULL) 107 return; 108 if (rw_owner(&log_rwlock) != curthread) 109 rw_enter(&log_rwlock, RW_WRITER); 110 log_rwlock_depth++; 111 } 112 113 void 114 log_exit(void) 115 { 116 if (panicstr != NULL) 117 return; 118 if (--log_rwlock_depth == 0) 119 rw_exit(&log_rwlock); 120 } 121 122 void 123 log_flushq(queue_t *q) 124 { 125 mblk_t *mp; 126 log_t *lp = (log_t *)q->q_ptr; 127 128 /* lp will be NULL if the queue was created via log_makeq */ 129 while ((mp = getq_noenab(q, 0)) != NULL) 130 log_sendmsg(mp, lp == NULL ? GLOBAL_ZONEID : lp->log_zoneid); 131 } 132 133 /* 134 * Create a minimal queue with just enough fields filled in to support 135 * canput(9F), putq(9F), and getq_noenab(9F). We set QNOENB to ensure 136 * that the queue will never be enabled. 137 */ 138 static queue_t * 139 log_makeq(size_t lowat, size_t hiwat, void *ibc) 140 { 141 queue_t *q; 142 143 q = kmem_zalloc(sizeof (queue_t), KM_SLEEP); 144 q->q_stream = &log_fakestr; 145 q->q_flag = QISDRV | QMTSAFE | QNOENB | QREADR | QUSE; 146 q->q_nfsrv = q; 147 q->q_lowat = lowat; 148 q->q_hiwat = hiwat; 149 mutex_init(QLOCK(q), NULL, MUTEX_DRIVER, ibc); 150 151 return (q); 152 } 153 154 /* 155 * Initialize the log structure for a new zone. 156 */ 157 static void * 158 log_zoneinit(zoneid_t zoneid) 159 { 160 int i; 161 log_zone_t *lzp; 162 163 if (zoneid == GLOBAL_ZONEID) 164 lzp = &log_global; /* use statically allocated struct */ 165 else 166 lzp = kmem_zalloc(sizeof (log_zone_t), KM_SLEEP); 167 168 for (i = 0; i < LOG_NUMCLONES; i++) { 169 lzp->lz_clones[i].log_minor = 170 (minor_t)id_alloc(log_minorspace); 171 lzp->lz_clones[i].log_zoneid = zoneid; 172 } 173 return (lzp); 174 } 175 176 /*ARGSUSED*/ 177 static void 178 log_zonefree(zoneid_t zoneid, void *arg) 179 { 180 log_zone_t *lzp = arg; 181 int i; 182 183 ASSERT(lzp != &log_global && zoneid != GLOBAL_ZONEID); 184 if (lzp == NULL) 185 return; 186 for (i = 0; i < LOG_NUMCLONES; i++) 187 id_free(log_minorspace, lzp->lz_clones[i].log_minor); 188 kmem_free(lzp, sizeof (log_zone_t)); 189 } 190 191 static void 192 log_bootbanner_print(const char *line, uint_t num) 193 { 194 const char *pfx = (num == 0) ? "\r" : ""; 195 196 printf("%s%s\n", pfx, line); 197 } 198 199 void 200 log_init(void) 201 { 202 int log_maxzones; 203 204 /* 205 * Create a backlog queue to consume console messages during periods 206 * when there is no console reader (e.g. before syslogd(8) starts). 207 */ 208 log_backlogq = log_consq = log_makeq(0, LOG_HIWAT, NULL); 209 210 /* 211 * Create a queue to hold free message of size <= LOG_MSGSIZE. 212 * Calls from high-level interrupt handlers will do a getq_noenab() 213 * from this queue, so its q_lock must be a maximum SPL spin lock. 214 */ 215 log_freeq = log_makeq(LOG_MINFREE, LOG_MAXFREE, (void *)ipltospl(SPL8)); 216 217 /* 218 * Create a queue for messages from high-level interrupt context. 219 * These messages are drained via softcall, or explicitly by panic(). 220 */ 221 log_intrq = log_makeq(0, LOG_HIWAT, (void *)ipltospl(SPL8)); 222 223 /* 224 * Create a queue to hold the most recent 64K of console messages. 225 * Useful for debugging. Required by the "$<msgbuf" adb macro. 226 */ 227 log_recentq = log_makeq(0, LOG_RECENTSIZE, NULL); 228 229 /* 230 * Create an id space for clone devices opened via /dev/log. 231 * Need to limit the number of zones to avoid exceeding the 232 * available minor number space. 233 */ 234 log_maxzones = (L_MAXMIN32 - LOG_LOGMIN) / LOG_NUMCLONES - 1; 235 if (log_maxzones < maxzones) 236 maxzones = log_maxzones; 237 log_minorspace = id_space_create("logminor_space", LOG_LOGMIN + 1, 238 L_MAXMIN32); 239 /* 240 * Put ourselves on the ZSD list. Note that zones have not been 241 * initialized yet, but our constructor will be called on the global 242 * zone when they are. 243 */ 244 zone_key_create(&log_zone_key, log_zoneinit, NULL, log_zonefree); 245 246 /* 247 * Initialize backlog structure. 248 */ 249 log_backlog.log_zoneid = GLOBAL_ZONEID; 250 log_backlog.log_minor = LOG_BACKLOG; 251 252 /* Allocate kmem cache for conslog's log structures */ 253 log_cons_cache = kmem_cache_create("log_cons_cache", 254 sizeof (struct log), 0, log_cons_constructor, log_cons_destructor, 255 NULL, NULL, NULL, 0); 256 257 /* 258 * Let the logging begin. 259 */ 260 log_update(&log_backlog, log_backlogq, SL_CONSOLE, log_console); 261 262 /* 263 * Now that logging is enabled, emit the boot banner. 264 */ 265 #ifdef LEGACY_BANNER 266 printf("\rSunOS Release %s Version %s %u-bit\n", 267 utsname.release, utsname.version, NBBY * (uint_t)sizeof (void *)); 268 printf("Copyright (c) 1983, 2010, Oracle and/or its affiliates. " 269 "All rights reserved.\n"); 270 #else 271 bootbanner_print(log_bootbanner_print); 272 #endif 273 #ifdef DEBUG 274 printf("DEBUG enabled\n"); 275 #endif 276 } 277 278 /* 279 * Allocate a log device corresponding to supplied device type. 280 * Both devices are clonable. /dev/log devices are allocated per zone. 281 * /dev/conslog devices are allocated from kmem cache. 282 */ 283 log_t * 284 log_alloc(minor_t type) 285 { 286 zone_t *zptr = curproc->p_zone; 287 log_zone_t *lzp; 288 log_t *lp; 289 int i; 290 minor_t minor; 291 292 if (type == LOG_CONSMIN) { 293 294 /* 295 * Return a write-only /dev/conslog device. 296 * No point allocating log_t until there's a free minor number. 297 */ 298 minor = (minor_t)id_alloc(log_minorspace); 299 lp = kmem_cache_alloc(log_cons_cache, KM_SLEEP); 300 lp->log_minor = minor; 301 return (lp); 302 } else { 303 ASSERT(type == LOG_LOGMIN); 304 305 lzp = zone_getspecific(log_zone_key, zptr); 306 ASSERT(lzp != NULL); 307 308 /* search for an available /dev/log device for the zone */ 309 for (i = LOG_LOGMINIDX; i <= LOG_LOGMAXIDX; i++) { 310 lp = &lzp->lz_clones[i]; 311 if (lp->log_inuse == 0) 312 break; 313 } 314 if (i > LOG_LOGMAXIDX) 315 lp = NULL; 316 else 317 /* Indicate which device type */ 318 lp->log_major = LOG_LOGMIN; 319 return (lp); 320 } 321 } 322 323 void 324 log_free(log_t *lp) 325 { 326 id_free(log_minorspace, lp->log_minor); 327 kmem_cache_free(log_cons_cache, lp); 328 } 329 330 /* 331 * Move console messages from src to dst. The time of day isn't known 332 * early in boot, so fix up the message timestamps if necessary. 333 */ 334 static void 335 log_conswitch(log_t *src, log_t *dst) 336 { 337 mblk_t *mp; 338 mblk_t *hmp = NULL; 339 mblk_t *tmp = NULL; 340 log_ctl_t *hlc; 341 342 while ((mp = getq_noenab(src->log_q, 0)) != NULL) { 343 log_ctl_t *lc = (log_ctl_t *)mp->b_rptr; 344 lc->flags |= SL_LOGONLY; 345 346 /* 347 * The ttime is written with 0 in log_sensmsg() only when 348 * good gethrestime_sec() data is not available to store in 349 * the log_ctl_t in the early boot phase. 350 */ 351 if (lc->ttime == 0) { 352 /* 353 * Look ahead to first early boot message with time. 354 */ 355 if (hmp) { 356 tmp->b_next = mp; 357 tmp = mp; 358 } else 359 hmp = tmp = mp; 360 continue; 361 } 362 363 while (hmp) { 364 tmp = hmp->b_next; 365 hmp->b_next = NULL; 366 hlc = (log_ctl_t *)hmp->b_rptr; 367 /* 368 * Calculate hrestime for an early log message with 369 * an invalid time stamp. We know: 370 * - the lbolt of the invalid time stamp. 371 * - the hrestime and lbolt of the first valid 372 * time stamp. 373 */ 374 hlc->ttime = lc->ttime - (lc->ltime - hlc->ltime) / hz; 375 (void) putq(dst->log_q, hmp); 376 hmp = tmp; 377 } 378 (void) putq(dst->log_q, mp); 379 } 380 while (hmp) { 381 tmp = hmp->b_next; 382 hmp->b_next = NULL; 383 hlc = (log_ctl_t *)hmp->b_rptr; 384 hlc->ttime = gethrestime_sec() - 385 (ddi_get_lbolt() - hlc->ltime) / hz; 386 (void) putq(dst->log_q, hmp); 387 hmp = tmp; 388 } 389 dst->log_overflow = src->log_overflow; 390 src->log_flags = 0; 391 dst->log_flags = SL_CONSOLE; 392 log_consq = dst->log_q; 393 } 394 395 /* 396 * Set the fields in the 'target' clone to the specified values. 397 * Then, look at all clones to determine which message types are 398 * currently active and which clone is the primary console queue. 399 * If the primary console queue changes to or from the backlog 400 * queue, copy all messages from backlog to primary or vice versa. 401 */ 402 void 403 log_update(log_t *target, queue_t *q, short flags, log_filter_t *filter) 404 { 405 log_t *lp; 406 short active = SL_CONSOLE; 407 zone_t *zptr = NULL; 408 log_zone_t *lzp; 409 zoneid_t zoneid = target->log_zoneid; 410 int i; 411 412 log_enter(); 413 414 if (q != NULL) 415 target->log_q = q; 416 target->log_wanted = filter; 417 target->log_flags = flags; 418 target->log_overflow = 0; 419 420 /* 421 * Need to special case the global zone here since this may be 422 * called before zone_init. 423 */ 424 if (zoneid == GLOBAL_ZONEID) { 425 lzp = &log_global; 426 } else if ((zptr = zone_find_by_id(zoneid)) == NULL) { 427 log_exit(); 428 return; /* zone is being destroyed, ignore update */ 429 } else { 430 lzp = zone_getspecific(log_zone_key, zptr); 431 } 432 ASSERT(lzp != NULL); 433 for (i = LOG_LOGMAXIDX; i >= LOG_LOGMINIDX; i--) { 434 lp = &lzp->lz_clones[i]; 435 if (zoneid == GLOBAL_ZONEID && (lp->log_flags & SL_CONSOLE)) 436 log_consq = lp->log_q; 437 active |= lp->log_flags; 438 } 439 lzp->lz_active = active; 440 441 if (zptr) 442 zone_rele(zptr); 443 444 if (log_consq == target->log_q) { 445 if (flags & SL_CONSOLE) 446 log_conswitch(&log_backlog, target); 447 else 448 log_conswitch(target, &log_backlog); 449 } 450 target->log_q = q; 451 452 log_exit(); 453 } 454 455 /*ARGSUSED*/ 456 int 457 log_error(log_t *lp, log_ctl_t *lc) 458 { 459 if ((lc->pri & LOG_FACMASK) == LOG_KERN) 460 lc->pri = LOG_KERN | LOG_ERR; 461 return (1); 462 } 463 464 int 465 log_trace(log_t *lp, log_ctl_t *lc) 466 { 467 trace_ids_t *tid = (trace_ids_t *)lp->log_data->b_rptr; 468 trace_ids_t *tidend = (trace_ids_t *)lp->log_data->b_wptr; 469 470 /* 471 * We use `tid + 1 <= tidend' here rather than the more traditional 472 * `tid < tidend', since the former ensures that there's at least 473 * `sizeof (trace_ids_t)' bytes available before executing the 474 * loop, whereas the latter only ensures that there's a single byte. 475 */ 476 for (; tid + 1 <= tidend; tid++) { 477 if (tid->ti_level < lc->level && tid->ti_level >= 0) 478 continue; 479 if (tid->ti_mid != lc->mid && tid->ti_mid >= 0) 480 continue; 481 if (tid->ti_sid != lc->sid && tid->ti_sid >= 0) 482 continue; 483 if ((lc->pri & LOG_FACMASK) == LOG_KERN) 484 lc->pri = LOG_KERN | LOG_DEBUG; 485 return (1); 486 } 487 return (0); 488 } 489 490 /*ARGSUSED*/ 491 int 492 log_console(log_t *lp, log_ctl_t *lc) 493 { 494 if ((lc->pri & LOG_FACMASK) == LOG_KERN) { 495 if (lc->flags & SL_FATAL) 496 lc->pri = LOG_KERN | LOG_CRIT; 497 else if (lc->flags & SL_ERROR) 498 lc->pri = LOG_KERN | LOG_ERR; 499 else if (lc->flags & SL_WARN) 500 lc->pri = LOG_KERN | LOG_WARNING; 501 else if (lc->flags & SL_NOTE) 502 lc->pri = LOG_KERN | LOG_NOTICE; 503 else if (lc->flags & SL_TRACE) 504 lc->pri = LOG_KERN | LOG_DEBUG; 505 else 506 lc->pri = LOG_KERN | LOG_INFO; 507 } 508 return (1); 509 } 510 511 mblk_t * 512 log_makemsg(int mid, int sid, int level, int sl, int pri, void *msg, 513 size_t size, int on_intr) 514 { 515 mblk_t *mp = NULL; 516 mblk_t *mp2; 517 log_ctl_t *lc; 518 519 if (size <= LOG_MSGSIZE && 520 (on_intr || log_freeq->q_count > log_freeq->q_lowat)) 521 mp = getq_noenab(log_freeq, 0); 522 523 if (mp == NULL) { 524 if (on_intr || 525 (mp = allocb(sizeof (log_ctl_t), BPRI_HI)) == NULL || 526 (mp2 = allocb(MAX(size, LOG_MSGSIZE), BPRI_HI)) == NULL) { 527 freemsg(mp); 528 return (NULL); 529 } 530 DB_TYPE(mp) = M_PROTO; 531 mp->b_wptr += sizeof (log_ctl_t); 532 mp->b_cont = mp2; 533 } else { 534 mp2 = mp->b_cont; 535 mp2->b_wptr = mp2->b_rptr; 536 } 537 538 lc = (log_ctl_t *)mp->b_rptr; 539 lc->mid = mid; 540 lc->sid = sid; 541 lc->level = level; 542 lc->flags = sl; 543 lc->pri = pri; 544 545 bcopy(msg, mp2->b_wptr, size - 1); 546 mp2->b_wptr[size - 1] = '\0'; 547 mp2->b_wptr += strlen((char *)mp2->b_wptr) + 1; 548 549 return (mp); 550 } 551 552 void 553 log_freemsg(mblk_t *mp) 554 { 555 mblk_t *mp2 = mp->b_cont; 556 557 ASSERT(MBLKL(mp) == sizeof (log_ctl_t)); 558 ASSERT(mp2->b_rptr == mp2->b_datap->db_base); 559 560 if ((log_freeq->q_flag & QFULL) == 0 && 561 MBLKL(mp2) <= LOG_MSGSIZE && MBLKSIZE(mp2) >= LOG_MSGSIZE) 562 (void) putq(log_freeq, mp); 563 else 564 freemsg(mp); 565 } 566 567 void 568 log_sendmsg(mblk_t *mp, zoneid_t zoneid) 569 { 570 log_t *lp; 571 char *src, *dst; 572 mblk_t *mp2 = mp->b_cont; 573 log_ctl_t *lc = (log_ctl_t *)mp->b_rptr; 574 int flags, fac; 575 off_t facility = 0; 576 off_t body = 0; 577 zone_t *zptr = NULL; 578 log_zone_t *lzp; 579 int i; 580 int backlog; 581 582 /* 583 * Need to special case the global zone here since this may be 584 * called before zone_init. 585 */ 586 if (zoneid == GLOBAL_ZONEID) { 587 lzp = &log_global; 588 } else if ((zptr = zone_find_by_id(zoneid)) == NULL) { 589 /* specified zone doesn't exist, free message and return */ 590 log_freemsg(mp); 591 return; 592 } else { 593 lzp = zone_getspecific(log_zone_key, zptr); 594 } 595 ASSERT(lzp != NULL); 596 597 if ((lc->flags & lzp->lz_active) == 0) { 598 if (zptr) 599 zone_rele(zptr); 600 log_freemsg(mp); 601 return; 602 } 603 604 if (panicstr) { 605 /* 606 * Raise the console queue's q_hiwat to ensure that we 607 * capture all panic messages. 608 */ 609 log_consq->q_hiwat = 2 * LOG_HIWAT; 610 log_consq->q_flag &= ~QFULL; 611 612 /* Message was created while panicking. */ 613 lc->flags |= SL_PANICMSG; 614 } 615 616 src = (char *)mp2->b_rptr; 617 dst = strstr(src, "FACILITY_AND_PRIORITY] "); 618 if (dst != NULL) { 619 facility = dst - src; 620 body = facility + 23; /* strlen("FACILITY_AND_PRIORITY] ") */ 621 } 622 623 log_enter(); 624 625 /* 626 * In the early boot phase hrestime is invalid, then timechanged is 0. 627 * If hrestime is not valid, the ttime is set to 0 here and the correct 628 * ttime is calculated in log_conswitch() later. The log_conswitch() 629 * calculation to determine the correct ttime does not use ttime data 630 * from these log_ctl_t structures; it only uses ttime from log_ctl_t's 631 * that contain good data. 632 * 633 * While panicking, use the timestamps that panicsys() captured once 634 * the other CPUs had been stopped and hres_lock released, rather than 635 * reading the clock again here. The clock readers are seqlock readers 636 * of hres_lock, and getting a panic message to the console should not 637 * depend on that lock. 638 */ 639 if (panicstr != NULL) { 640 lc->ltime = (clock_t)panic_lbolt64; 641 lc->ttime = panic_hrestime.tv_sec; 642 } else { 643 lc->ltime = ddi_get_lbolt(); 644 if (timechanged) { 645 lc->ttime = gethrestime_sec(); 646 } else { 647 lc->ttime = 0; 648 } 649 } 650 651 flags = lc->flags & lzp->lz_active; 652 log_seq_no[flags & SL_ERROR]++; 653 log_seq_no[flags & SL_TRACE]++; 654 log_seq_no[flags & SL_CONSOLE]++; 655 656 /* 657 * If this is in the global zone, start with the backlog, then 658 * walk through the clone logs. If not, just do the clone logs. 659 */ 660 backlog = (zoneid == GLOBAL_ZONEID); 661 i = LOG_LOGMINIDX; 662 while (i <= LOG_LOGMAXIDX) { 663 if (backlog) { 664 /* 665 * Do the backlog this time, then start on the 666 * others. 667 */ 668 backlog = 0; 669 lp = &log_backlog; 670 } else { 671 lp = &lzp->lz_clones[i++]; 672 } 673 674 if ((lp->log_flags & flags) && lp->log_wanted(lp, lc)) { 675 if (canput(lp->log_q)) { 676 lp->log_overflow = 0; 677 lc->seq_no = log_seq_no[lp->log_flags]; 678 if ((mp2 = copymsg(mp)) == NULL) 679 break; 680 if (facility != 0) { 681 src = (char *)mp2->b_cont->b_rptr; 682 dst = src + facility; 683 fac = (lc->pri & LOG_FACMASK) >> 3; 684 dst += snprintf(dst, 685 LOG_FACSIZE + LOG_PRISIZE, "%s.%s", 686 log_fac[MIN(fac, LOG_NFACILITIES)], 687 log_pri[lc->pri & LOG_PRIMASK]); 688 src += body - 2; /* copy "] " too */ 689 while (*src != '\0') 690 *dst++ = *src++; 691 *dst++ = '\0'; 692 mp2->b_cont->b_wptr = (uchar_t *)dst; 693 } 694 (void) putq(lp->log_q, mp2); 695 } else if (++lp->log_overflow == 1) { 696 if (lp->log_q == log_consq) { 697 console_printf(log_overflow_msg, 698 lp->log_minor, 699 " -- is syslogd(8) running?"); 700 } else { 701 printf(log_overflow_msg, 702 lp->log_minor, ""); 703 } 704 } 705 } 706 } 707 708 if (zptr) 709 zone_rele(zptr); 710 711 if ((flags & SL_CONSOLE) && (lc->pri & LOG_FACMASK) == LOG_KERN) { 712 if ((mp2 == NULL || log_consq == log_backlogq || panicstr) && 713 (lc->flags & SL_LOGONLY) == 0) 714 console_printf("%s", (char *)mp->b_cont->b_rptr + body); 715 if ((lc->flags & SL_CONSONLY) == 0 && 716 (mp2 = copymsg(mp)) != NULL) { 717 mp2->b_cont->b_rptr += body; 718 if (log_recentq->q_flag & QFULL) 719 freemsg(getq_noenab(log_recentq, 0)); 720 (void) putq(log_recentq, mp2); 721 } 722 } 723 724 log_freemsg(mp); 725 726 log_exit(); 727 } 728 729 /* 730 * Print queued messages to console. 731 */ 732 void 733 log_printq(queue_t *qfirst) 734 { 735 mblk_t *mp; 736 queue_t *q, *qlast; 737 char *cp, *msgp; 738 log_ctl_t *lc; 739 740 /* 741 * Look ahead to first queued message in the stream. 742 */ 743 qlast = NULL; 744 do { 745 for (q = qfirst; q->q_next != qlast; q = q->q_next) 746 continue; 747 for (mp = q->q_first; mp != NULL; mp = mp->b_next) { 748 lc = (log_ctl_t *)mp->b_rptr; 749 /* 750 * Check if message is already displayed at 751 * /dev/console. 752 */ 753 if (lc->flags & SL_PANICMSG) 754 continue; 755 756 cp = (char *)mp->b_cont->b_rptr; 757 758 /* Strip off the message ID. */ 759 if ((msgp = strstr(cp, "[ID ")) != NULL && 760 (msgp = strstr(msgp, "] ")) != NULL) { 761 cp = msgp + 2; 762 } 763 764 /* 765 * Using console_printf instead of printf to avoid 766 * queueing messages to log_consq. 767 */ 768 console_printf("%s", cp); 769 } 770 } while ((qlast = q) != qfirst); 771 } 772 773 /* ARGSUSED */ 774 static int 775 log_cons_constructor(void *buf, void *cdrarg, int kmflags) 776 { 777 struct log *lp = buf; 778 779 lp->log_zoneid = GLOBAL_ZONEID; 780 lp->log_major = LOG_CONSMIN; /* Indicate which device type */ 781 lp->log_data = NULL; 782 return (0); 783 } 784 785 /* ARGSUSED */ 786 static void 787 log_cons_destructor(void *buf, void *cdrarg) 788 { 789 struct log *lp = buf; 790 791 ASSERT(lp->log_zoneid == GLOBAL_ZONEID); 792 ASSERT(lp->log_major == LOG_CONSMIN); 793 ASSERT(lp->log_data == NULL); 794 } 795