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