|
|
1.1 ! root 1: /* ! 2: * The code in this file is taken from the example dump module listing in ! 3: * Appendix B of the STREAMS Programmer's Guide for System V, Release 4 Multi- ! 4: * Processor (Intel Edition). The overall structure of the code has been ! 5: * retained, with some editing to reflect local coding standards, additional ! 6: * commentary, and to bring the code up to SVR4MP DDI/DKI standards. ! 7: */ ! 8: ! 9: #define _DDI_DKI 1 ! 10: #define _SYSV4 1 ! 11: ! 12: #include <common/ccompat.h> ! 13: #include <sys/inline.h> ! 14: #include <sys/file.h> ! 15: #include <sys/errno.h> ! 16: #include <stddef.h> ! 17: ! 18: /* ! 19: * DUMP Module. This module prints data and ioctls going to and from a device ! 20: * in real time. Printout is on the console. Usage is to push it on a stream ! 21: * between any other modules. ! 22: * ! 23: * It accepts two ioctls: ! 24: * DUMP_VERB Verbose printing of M_DATA (default) ! 25: * DUMP_TERSE Terse printing of data ! 26: * ! 27: * The messages it prints begin with "I:" for incoming, "O:" for outgoing ! 28: * data. "Ci" or "Co" are for non-data (control) messages. Data is printed in ! 29: * character or hexadecimal format delimited by {{ and }} at message ! 30: * boundaries. ! 31: */ ! 32: ! 33: #include "sys/types.h" ! 34: #include "sys/stream.h" ! 35: #include "sys/cmn_err.h" ! 36: #include "dump.h" ! 37: ! 38: static struct module_info dumprinfo = { ! 39: 0x6475, "dump", 0, INFPSZ, 0, 0 ! 40: }; ! 41: static struct module_info dumpwinfo = { ! 42: 0x6475, "dump", 0, INFPSZ, 0, 0 ! 43: }; ! 44: ! 45: ! 46: static int dumpopen __PROTO ((queue_t * q, dev_t * devp, int flag, ! 47: int sflag, cred_t * credp)); ! 48: static int dumpclose __PROTO ((queue_t * q, int flag, ! 49: cred_t * credp)); ! 50: static void dumpwput __PROTO ((queue_t * q, mblk_t * mp)); ! 51: static void dumprput __PROTO ((queue_t * q, mblk_t * mp)); ! 52: ! 53: static struct qinit rinit = { ! 54: dumprput, NULL, dumpopen, dumpclose, NULL, & dumprinfo, NULL ! 55: }; ! 56: static struct qinit winit = { ! 57: dumpwput, NULL, NULL, NULL, NULL, & dumpwinfo, NULL ! 58: }; ! 59: ! 60: struct streamtab dumpinfo = { ! 61: & rinit, & winit, NULL, NULL ! 62: }; ! 63: ! 64: int dumpdevflag = 0; ! 65: ! 66: ! 67: /* ! 68: * Gather information from this data message and print it. The caller deals ! 69: * with actually forwarding the data message. ! 70: */ ! 71: ! 72: #if __USE_PROTO__ ! 73: __LOCAL__ void (dumpgather) (queue_t * q, mblk_t * mp, dm_dir_t dir) ! 74: #else ! 75: __LOCAL__ void ! 76: dumpgather __ARGS ((q, mp, dir)) ! 77: queue_t * q; ! 78: mblk_t * mp; ! 79: dm_dir_t dir; ! 80: #endif ! 81: { ! 82: struct dm_str * d = (struct dm_str *) q->q_ptr; ! 83: pl_t prev_pl; ! 84: mblk_t * tmp; ! 85: unsigned long counter; ! 86: char junk [2]; ! 87: ! 88: /* ! 89: * Check state and print direction indication when it changes. ! 90: */ ! 91: ! 92: if (d->dm_dir != dir) { ! 93: ! 94: d->dm_dir = dir; ! 95: cmn_err (CE_CONT, dir == D_IN ? "^\nIN:" : "^\nOUT:"); ! 96: } ! 97: ! 98: if (mp->b_datap == NULL || ! 99: (mp->b_rptr == mp->b_wptr && mp->b_cont == NULL)) { ! 100: /* ! 101: * Zero-length messages are treated specially in most streams, ! 102: * note them specially. ! 103: */ ! 104: ! 105: cmn_err (CE_CONT, "^DUMP: Zero-length data message\n"); ! 106: return; ! 107: } ! 108: ! 109: cmn_err (CE_CONT, "^ {{"); ! 110: ! 111: tmp = mp; ! 112: counter = 0; ! 113: junk [1] = 0; ! 114: ! 115: prev_pl = splstr (); ! 116: ! 117: do { ! 118: unsigned char * readp; ! 119: ! 120: if ((d->dm_flags & D_VERB) == 0) { ! 121: ! 122: counter += tmp->b_wptr - tmp->b_rptr; ! 123: continue; ! 124: } ! 125: ! 126: for (readp = tmp->b_rptr ; readp < tmp->b_wptr ; readp ++) ! 127: if ((junk [0] = * readp) >= ' ' && junk [0] <= '~') ! 128: cmn_err (CE_CONT, "^ %s", junk); ! 129: else ! 130: cmn_err (CE_CONT, "^ 0x%x", junk [0]); ! 131: ! 132: } while ((tmp = tmp->b_cont) != NULL && ! 133: tmp->b_datap->db_type == M_DATA); ! 134: ! 135: ! 136: if ((d->dm_flags & D_VERB) == 0) ! 137: cmn_err (CE_CONT, "^ %d", counter); ! 138: ! 139: cmn_err (CE_CONT, "^ }} "); ! 140: ! 141: if (tmp != NULL) ! 142: cmn_err (CE_CONT, "^\nDUMP: non-data b_cont\n"); ! 143: ! 144: splx (prev_pl); ! 145: } ! 146: ! 147: ! 148: /* ! 149: * Completely handle one of our ioctl () calls, including the qreply () of the ! 150: * message. ! 151: */ ! 152: ! 153: #if __USE_PROTO__ ! 154: __LOCAL__ void (dumpioc) (queue_t * q, mblk_t * mp) ! 155: #else ! 156: __LOCAL__ void ! 157: dumpioc __ARGS ((q, mp)) ! 158: queue_t * q; ! 159: mblk_t * mp; ! 160: #endif ! 161: { ! 162: struct iocblk * iocp = (struct iocblk *) mp->b_rptr; ! 163: struct dm_str * d = (struct dm_str *) q->q_ptr; ! 164: ! 165: cmn_err (CE_CONT, "^DUMP: own ioctl is "); ! 166: ! 167: switch (iocp->ioc_cmd) { ! 168: ! 169: case DUMP_VERB: ! 170: d->dm_flags |= D_VERB; ! 171: cmn_err (CE_CONT, "^DUMP_VERB\n"); ! 172: ! 173: mp->b_datap->db_type = M_IOCACK; ! 174: break; ! 175: ! 176: case DUMP_TERSE: ! 177: d->dm_flags &= ~ D_VERB; ! 178: cmn_err (CE_CONT, "^DUMP_TERSE\n"); ! 179: ! 180: mp->b_datap->db_type = M_IOCACK; ! 181: break; ! 182: ! 183: default: ! 184: cmn_err (CE_CONT, "^ unknown, %x\n", iocp->ioc_cmd); ! 185: ! 186: mp->b_datap->db_type = M_IOCNAK; ! 187: break; ! 188: } ! 189: ! 190: iocp->ioc_count = 0; ! 191: qreply (q, mp); ! 192: } ! 193: ! 194: ! 195: /* ! 196: * Display information about control messages. ! 197: */ ! 198: ! 199: #if __USE_PROTO__ ! 200: __LOCAL__ void (dumpctl) (queue_t * q, mblk_t * mp, dm_dir_t dir) ! 201: #else ! 202: __LOCAL__ void ! 203: dumpctl __ARGS ((q, mp, dir)) ! 204: queue_t * q; ! 205: mblk_t * mp; ! 206: dm_dir_t dir; ! 207: #endif ! 208: { ! 209: __CONST__ char * tmp = NULL; ! 210: ! 211: cmn_err (CE_CONT, "^\nC%s: M_", dir == D_IN ? "i" : "o"); ! 212: ! 213: switch (mp->b_datap->db_type) { ! 214: ! 215: /* just in case */ ! 216: case M_DATA: tmp = "DATA"; break; ! 217: ! 218: case M_READ: tmp = "READ"; break; ! 219: ! 220: case M_IOCTL: tmp = "IOCTL"; break; ! 221: ! 222: case M_IOCACK: tmp = "IOCACK"; break; ! 223: ! 224: case M_IOCNAK: tmp = "IOCNAK"; break; ! 225: ! 226: case M_IOCDATA: tmp = "IOCDATA"; break; ! 227: ! 228: case M_CTL: tmp = "CTL"; break; ! 229: ! 230: case M_PROTO: tmp = "PROTO"; break; ! 231: ! 232: case M_PCPROTO: tmp = "PCPROTO"; break; ! 233: ! 234: case M_BREAK: tmp = "BREAK"; break; ! 235: ! 236: case M_DELAY: tmp = "DELAY"; break; ! 237: ! 238: case M_PASSFP: tmp = "PASSFP"; break; ! 239: ! 240: case M_SETOPTS: tmp = "SETOPTS"; break; ! 241: ! 242: case M_ERROR: tmp = "ERROR"; break; ! 243: ! 244: case M_HANGUP: tmp = "HANGUP"; break; ! 245: ! 246: case M_FLUSH: tmp = "FLUSH"; break; ! 247: ! 248: case M_COPYOUT: tmp = "COPYOUT"; break; ! 249: ! 250: case M_COPYIN: tmp = "COPYIN"; break; ! 251: ! 252: case M_START: tmp = "START"; break; ! 253: ! 254: case M_STOP: tmp = "STOP"; break; ! 255: ! 256: case M_STARTI: tmp = "STARTI"; break; ! 257: ! 258: case M_STOPI: tmp = "STOPI"; break; ! 259: ! 260: case M_SIG: ! 261: cmn_err (CE_CONT, "^SIG (%d) ", * mp->b_rptr); ! 262: break; ! 263: ! 264: case M_PCSIG: ! 265: cmn_err (CE_CONT, "^PCSIG (%d) ", * mp->b_rptr); ! 266: break; ! 267: ! 268: default: ! 269: cmn_err (CE_CONT, "^Unknown! (0x%x) ", mp->b_datap->db_type); ! 270: break; ! 271: } ! 272: ! 273: if (tmp != NULL) ! 274: cmn_err (CE_CONT, "^%s", tmp); ! 275: ! 276: /* ! 277: * Reset the direction indicator so the next data message will print ! 278: * the direction it is headed in. ! 279: */ ! 280: ! 281: ((struct dm_str *) q->q_ptr)->dm_dir = D_NONE; ! 282: } ! 283: ! 284: ! 285: /* ! 286: * Display information about generally-known ioctl ()s. Feel free to add more ! 287: * knowledge to this to suit your application. ! 288: */ ! 289: ! 290: #if __USE_PROTO__ ! 291: __LOCAL__ void (dumpshow) (mblk_t * __NOTUSED (mp), int cmd) ! 292: #else ! 293: __LOCAL__ void ! 294: dumpshow __ARGS ((mp, cmd)) ! 295: mblk_t * mp; ! 296: int cmd; ! 297: #endif ! 298: { ! 299: switch (cmd) { ! 300: ! 301: default: ! 302: return; ! 303: } ! 304: } ! 305: ! 306: ! 307: /* ! 308: * Open a dump filter. ! 309: */ ! 310: ! 311: #if __USE_PROTO__ ! 312: int dumpopen (queue_t * q, dev_t * __NOTUSED (devp), int flag, ! 313: int __NOTUSED (sflag), cred_t * __NOTUSED (credp)) ! 314: #else ! 315: int dumpopen (q, devp, flag, sflag, credp) ! 316: queue_t * q; ! 317: dev_t * devp; ! 318: int flag; ! 319: int sflag; ! 320: cred_t * credp; ! 321: #endif ! 322: { ! 323: int i; ! 324: ! 325: if (q->q_ptr != NULL) { ! 326: ! 327: cmn_err (CE_CONT, "^DUMP: re-open slot %d\n", ! 328: (struct dm_str *) q->q_ptr - dm_users); ! 329: ! 330: if ((flag & FNDELAY) != 0) ! 331: cmn_err (CE_CONT, "^DUMP: reopen, NDELAY set\n"); ! 332: if ((flag & FNONBLOCK) != 0) ! 333: cmn_err (CE_CONT, "^DUMP: reopen, NONBLOCK set\n"); ! 334: ! 335: qprocson (q); ! 336: return 0; ! 337: } ! 338: ! 339: /* ! 340: * Search for a slot to use. We depend on the single-threading of ! 341: * driver open routines to protect this code, and the complementary ! 342: * code in dumpclose () ! 343: */ ! 344: ! 345: for (i = 0 ; i < dm_ucnt ; i ++) { ! 346: ! 347: if (dm_users [i].dm_use == D_FREE) { ! 348: ! 349: dm_users [i].dm_use = D_USED; ! 350: dm_users [i].dm_dir = D_NONE; ! 351: dm_users [i].dm_flags = D_VERB; ! 352: ! 353: WR (q)->q_ptr = q->q_ptr = (_VOID *) & dm_users [i]; ! 354: ! 355: cmn_err (CE_CONT, "^DUMP: flag = %d\n", flag); ! 356: ! 357: if ((flag & FNDELAY) != 0) ! 358: cmn_err (CE_CONT, "^DUMP: open, NDELAY set\n"); ! 359: if ((flag & FNONBLOCK) != 0) ! 360: cmn_err (CE_CONT, "^DUMP: open, NONBLOCK set\n"); ! 361: ! 362: qprocson (q); ! 363: return 0; ! 364: } ! 365: } ! 366: ! 367: return EAGAIN; ! 368: } ! 369: ! 370: ! 371: /* ! 372: * Close an entry and deallocate the control slot. ! 373: */ ! 374: ! 375: #if __USE_PROTO__ ! 376: int (dumpclose) (queue_t * q, int __NOTUSED (flag), ! 377: cred_t * __NOTUSED (credp)) ! 378: #else ! 379: int ! 380: dumpclose (q, flag, credp) ! 381: queue_t * q; ! 382: int flag; ! 383: cred_t * credp; ! 384: #endif ! 385: { ! 386: struct dm_str * d = (struct dm_str *) q->q_ptr; ! 387: ! 388: d->dm_use = D_FREE; ! 389: d->dm_flags = 0; ! 390: ! 391: WR (q)->q_ptr = q->q_ptr = NULL; ! 392: ! 393: cmn_err (CE_CONT, "^\nDUMP: end trace\n"); ! 394: qprocsoff (q); ! 395: return 0; ! 396: } ! 397: ! 398: ! 399: /* ! 400: * Put procedure for write side of module. Gathers data from all passing ! 401: * M_DATA messages. Calls routine to handle ioctl calls. ! 402: */ ! 403: ! 404: #if __USE_PROTO__ ! 405: void dumpwput (queue_t * q, mblk_t * mp) ! 406: #else ! 407: void ! 408: dumpwput (q, mp) ! 409: queue_t * q; ! 410: mblk_t * mp; ! 411: #endif ! 412: { ! 413: if (mp->b_datap->db_type == M_IOCTL) { ! 414: struct iocblk * iocp = (struct iocblk *) mp->b_rptr; ! 415: struct dm_str * d = (struct dm_str *) q->q_ptr; ! 416: ! 417: if ((iocp->ioc_cmd & DUMPIOC) == DUMPIOC) { ! 418: ! 419: dumpioc (q, mp); ! 420: return; ! 421: } ! 422: ! 423: cmn_err (CE_CONT, "^Co: M_IOCTL %x, cnt %d ", ! 424: iocp->ioc_cmd, iocp->ioc_count); ! 425: ! 426: if ((d->dm_flags & D_VERB) != 0 && mp->b_cont) ! 427: dumpshow (mp->b_cont, iocp->ioc_count); ! 428: ! 429: d->dm_dir = D_NONE; ! 430: ! 431: } else if (mp->b_datap->db_type == M_DATA) ! 432: dumpgather (q, mp, D_OUT); ! 433: else ! 434: dumpctl (q, mp, D_OUT); ! 435: ! 436: putnext (q, mp); ! 437: } ! 438: ! 439: ! 440: /* ! 441: * Read side put procedure, simply discriminates between upwards-bound control ! 442: * and data. ! 443: */ ! 444: ! 445: #if __USE_PROTO__ ! 446: void dumprput (queue_t * q, mblk_t * mp) ! 447: #else ! 448: void ! 449: dumprput (q, mp) ! 450: queue_t * q; ! 451: mblk_t * mp; ! 452: #endif ! 453: { ! 454: if (mp->b_datap->db_type == M_DATA) ! 455: dumpgather (q, mp, D_IN); ! 456: else ! 457: dumpctl (q, mp, D_IN); ! 458: ! 459: putnext (q, mp); ! 460: } ! 461:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.