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