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