|
|
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.