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