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  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 #pragma ident   "%Z%%M% %I%     %E% SMI"        /* SVr3.2H      */
  27 
  28 /*
  29  * Dump STREAMS module.  Could be used anywhere on a stream to
  30  * print all message headers and data on to the console.
  31  */
  32 
  33 #include <sys/types.h>
  34 #include <sys/param.h>
  35 #include <sys/systm.h>
  36 #include <sys/stream.h>
  37 #include <sys/stropts.h>
  38 #include <sys/errno.h>
  39 #include <sys/cmn_err.h>
  40 #include <sys/ddi.h>
  41 #include <sys/strsun.h>
  42 
  43 #include <sys/conf.h>
  44 #include <sys/modctl.h>
  45 
  46 static char     hdr[100];       /* current message header */
  47 static char     hdrpad[100];    /* pad of same length as hdr[] */
  48 
  49 /*
  50  * Raw buffer dumping routine.  Displays the contents of the first message in
  51  * message chain `mp', using the "traditional" dump format.
  52  *
  53  * For instance, "Hello STREAMS, panicked lately?" would be displayed as:
  54  *
  55  * RD 30001dbb240 M_DATA 48656C6C 6F205354 5245414D 532C2070  Hello STREAMS, p
  56  *                       616E6963 6B656420 6C617465 6C793F    anicked lately?
  57  *
  58  * If the character being displayed is not printable, a '.' is shown.
  59  */
  60 
  61 #define DEDUMP_HEXPERBLK        4
  62 #define DEDUMP_HEXLEN           (sizeof ("11223344") * 4)
  63 #define DEDUMP_ASCLEN           (sizeof ("0123456789ABCDEF") - 1)
  64 
  65 static void
  66 dedump_raw(mblk_t *mp)
  67 {
  68         char    hex[DEDUMP_HEXLEN + 1], asc[DEDUMP_ASCLEN + 1];
  69         int     hexi = 0, asci = 0, i = 0;
  70         uchar_t c;
  71         char    *hdrp = hdr;
  72 
  73         hex[DEDUMP_HEXLEN] = '\0';
  74 
  75         for (;;) {
  76                 if (i == MBLKL(mp) || (i != 0 && (i % DEDUMP_ASCLEN) == 0)) {
  77                         /*
  78                          * We're either out of data or we've filled a complete
  79                          * line.  In either case, print out what we've got --
  80                          * but first NUL-terminate asc[] and pad out hex[]
  81                          * with spaces.
  82                          */
  83                         asc[asci] = '\0';
  84                         (void) memset(hex + hexi, ' ', DEDUMP_HEXLEN - hexi);
  85                         (void) printf("%s %s %s\n", hdrp, hex, asc);
  86 
  87                         /*
  88                          * If we're out of data, bail.  Otherwise, reset asci
  89                          * and hexi for another lap around.  Also, set hdrp to
  90                          * the pad since we only want to show the header once.
  91                          */
  92                         if (i == MBLKL(mp))
  93                                 break;
  94                         asci = 0;
  95                         hexi = 0;
  96                         hdrp = hdrpad;
  97                 }
  98 
  99                 c = mp->b_rptr[i++];
 100 
 101                 hexi += snprintf(hex + hexi, 3, "%02X", c);
 102                 if ((i % DEDUMP_HEXPERBLK) == 0)
 103                         hex[hexi++] = ' ';
 104                 asc[asci++] = (c >= 32 && c <= 126) ? c : '.';
 105         }
 106 }
 107 
 108 static void
 109 dedump_char(mblk_t *mp)
 110 {
 111         (void) printf("%s 0x%x\n", hdr, *(uchar_t *)mp->b_rptr);
 112 }
 113 
 114 static void
 115 dedump_int(mblk_t *mp)
 116 {
 117         (void) printf("%s %d\n", hdr, *(int *)mp->b_rptr);
 118 }
 119 
 120 static void
 121 dedump_ssize(mblk_t *mp)
 122 {
 123         (void) printf("%s %ld\n", hdr, *(ssize_t *)mp->b_rptr);
 124 }
 125 
 126 static void
 127 dedump_cmdblk(mblk_t *mp)
 128 {
 129         struct cmdblk *cbp = (struct cmdblk *)mp->b_rptr;
 130 
 131         (void) printf("%s cmd %x cred %p len %u error %d\n", hdr, cbp->cb_cmd,
 132             (void *)cbp->cb_cr, cbp->cb_len, cbp->cb_error);
 133 }
 134 
 135 static void
 136 dedump_iocblk(mblk_t *mp)
 137 {
 138         struct iocblk *ic = (struct iocblk *)mp->b_rptr;
 139 
 140         (void) printf("%s cmd %x cred %p id %u flag %x count %ld rval %d "
 141             "err %d\n", hdr, ic->ioc_cmd, (void *)ic->ioc_cr, ic->ioc_id,
 142             ic->ioc_flag, ic->ioc_count, ic->ioc_rval, ic->ioc_error);
 143 }
 144 
 145 static void
 146 dedump_stroptions(mblk_t *mp)
 147 {
 148         struct stroptions *so = (struct stroptions *)mp->b_rptr;
 149 
 150         (void) printf("%s flag %x readopt %d wroff %u\n", hdr,
 151             so->so_flags, so->so_readopt, so->so_wroff);
 152 
 153         (void) printf("%s minpsz %ld maxpsz %ld hiwat %lu lowat %lu\n", hdrpad,
 154             so->so_minpsz, so->so_maxpsz, so->so_hiwat, so->so_lowat);
 155 
 156         (void) printf("%s band %u erropt %u maxblk %ld copyopt %u\n", hdrpad,
 157             so->so_band, so->so_erropt, so->so_maxblk, so->so_copyopt);
 158 }
 159 
 160 static void
 161 dedump_copyreq(mblk_t *mp)
 162 {
 163         struct copyreq *cq = (struct copyreq *)mp->b_rptr;
 164 
 165         (void) printf("%s cmd %x cred %p id %u flag %x priv %p addr %p size "
 166             "%lu\n", hdr, cq->cq_cmd, (void *)cq->cq_cr, cq->cq_id, cq->cq_flag,
 167             (void *)cq->cq_private, (void *)cq->cq_addr, cq->cq_size);
 168 }
 169 
 170 static void
 171 dedump_copyresp(mblk_t *mp)
 172 {
 173         struct copyresp *cp = (struct copyresp *)mp->b_rptr;
 174 
 175         (void) printf("%s cmd %x cred %p id %u flag %x priv %p rval %p\n", hdr,
 176             cp->cp_cmd, (void *)cp->cp_cr, cp->cp_id, cp->cp_flag,
 177             (void *)cp->cp_private, (void *)cp->cp_rval);
 178 }
 179 
 180 typedef struct msgfmt {
 181         uchar_t m_type;
 182         char    m_desc[15];
 183         void    (*m_print)(mblk_t *);
 184 } msgfmt_t;
 185 
 186 static msgfmt_t msgfmt[256] = {
 187         {       M_DATA,         "M_DATA    ",   dedump_raw              },
 188         {       M_PROTO,        "M_PROTO   ",   dedump_raw              },
 189         {       M_BREAK,        "M_BREAK   ",   dedump_raw              },
 190         {       M_PASSFP,       "M_PASSFP  ",   dedump_raw              },
 191         {       M_EVENT,        "M_EVENT   ",   dedump_raw              },
 192         {       M_SIG,          "M_SIG     ",   dedump_char             },
 193         {       M_DELAY,        "M_DELAY   ",   dedump_int              },
 194         {       M_CTL,          "M_CTL     ",   dedump_raw              },
 195         {       M_IOCTL,        "M_IOCTL   ",   dedump_iocblk           },
 196         {       M_SETOPTS,      "M_SETOPTS ",   dedump_stroptions       },
 197         {       M_RSE,          "M_RSE     ",   dedump_raw              },
 198         {       M_IOCACK,       "M_IOCACK  ",   dedump_iocblk           },
 199         {       M_IOCNAK,       "M_IOCNAK  ",   dedump_iocblk           },
 200         {       M_PCPROTO,      "M_PCPROTO ",   dedump_raw              },
 201         {       M_PCSIG,        "M_PCSIG   ",   dedump_char             },
 202         {       M_READ,         "M_READ    ",   dedump_ssize            },
 203         {       M_FLUSH,        "M_FLUSH   ",   dedump_char             },
 204         {       M_STOP,         "M_STOP    ",   dedump_raw              },
 205         {       M_START,        "M_START   ",   dedump_raw              },
 206         {       M_HANGUP,       "M_HANGUP  ",   dedump_raw              },
 207         {       M_ERROR,        "M_ERROR   ",   dedump_char             },
 208         {       M_COPYIN,       "M_COPYIN  ",   dedump_copyreq          },
 209         {       M_COPYOUT,      "M_COPYOUT ",   dedump_copyreq          },
 210         {       M_IOCDATA,      "M_IOCDATA ",   dedump_copyresp         },
 211         {       M_PCRSE,        "M_PCRSE   ",   dedump_raw              },
 212         {       M_STOPI,        "M_STOPI   ",   dedump_raw              },
 213         {       M_STARTI,       "M_STARTI  ",   dedump_raw              },
 214         {       M_PCEVENT,      "M_PCEVENT ",   dedump_raw              },
 215         {       M_UNHANGUP,     "M_UNHANGUP",   dedump_raw              },
 216         {       M_CMD,          "M_CMD     ",   dedump_cmdblk           },
 217 };
 218 
 219 /*ARGSUSED1*/
 220 static int
 221 dedumpopen(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *crp)
 222 {
 223         if (!sflag)
 224                 return (ENXIO);
 225 
 226         if (q->q_ptr)
 227                 return (0);             /* already attached */
 228 
 229         qprocson(q);
 230         return (0);
 231 }
 232 
 233 /*ARGSUSED1*/
 234 static int
 235 dedumpclose(queue_t *q, int flag, cred_t *crp)
 236 {
 237         qprocsoff(q);
 238         return (0);
 239 }
 240 
 241 /*
 242  * Common put procedure for upstream and downstream.
 243  */
 244 static int
 245 dedumpput(queue_t *q, mblk_t *mp)
 246 {
 247         unsigned char type = DB_TYPE(mp);
 248         ssize_t hdrlen;
 249 
 250         hdrlen = snprintf(hdr, sizeof (hdr), "%s %p %10s ",
 251             (q->q_flag & QREADR) ? "RD" : "WR", (void *)q, msgfmt[type].m_desc);
 252 
 253         hdrpad[hdrlen] = '\0';
 254         msgfmt[type].m_print(mp);
 255         hdrpad[hdrlen] = ' ';
 256 
 257         putnext(q, mp);
 258         return (0);
 259 }
 260 
 261 struct module_info dedump_minfo = {
 262         0xaaa, "dedump", 0, INFPSZ, 0, 0
 263 };
 264 
 265 struct qinit dedumprinit = {
 266         dedumpput, NULL, dedumpopen, dedumpclose, NULL, &dedump_minfo, NULL
 267 };
 268 
 269 struct qinit dedumpwinit = {
 270         dedumpput, NULL, NULL, NULL, NULL, &dedump_minfo, NULL
 271 };
 272 
 273 struct streamtab dedumpinfo = {
 274         &dedumprinit, &dedumpwinit, NULL, NULL,
 275 };
 276 
 277 static struct fmodsw fsw = {
 278         "dedump",
 279         &dedumpinfo,
 280         D_MP | D_MTPERMOD       /* just to serialize printfs */
 281 };
 282 
 283 static struct modlstrmod modlstrmod = {
 284         &mod_strmodops, "dump streams module", &fsw
 285 };
 286 
 287 static struct modlinkage modlinkage = {
 288         MODREV_1, &modlstrmod, NULL
 289 };
 290 
 291 int
 292 _init(void)
 293 {
 294         int i;
 295         msgfmt_t mf;
 296 
 297         /*
 298          * Sort msgfmt[] so that msgfmt[n] describes message type n.
 299          */
 300         for (i = 255; i != 0; i--) {
 301                 mf = msgfmt[i];
 302                 msgfmt[i].m_type = i;
 303                 (void) sprintf(msgfmt[i].m_desc, "M_BOGUS_0x%x", i);
 304                 msgfmt[i].m_print = dedump_raw;
 305                 if (mf.m_desc[0] != 0)
 306                         msgfmt[mf.m_type] = mf;
 307         }
 308 
 309         /*
 310          * Fill hdrpad[] with as many spaces as will fit.
 311          */
 312         (void) memset(hdrpad, ' ', sizeof (hdrpad) - 1);
 313         hdrpad[sizeof (hdrpad) - 1] = '\0';
 314 
 315         return (mod_install(&modlinkage));
 316 }
 317 
 318 int
 319 _fini(void)
 320 {
 321         return (mod_remove(&modlinkage));
 322 }
 323 
 324 int
 325 _info(struct modinfo *modinfop)
 326 {
 327         return (mod_info(&modlinkage, modinfop));
 328 }