Coherent4.2.10/conf/dump/src/dump.c

Compare this file to the similar file:
Show the results in this format:

/*
 * The code in this file is taken from the example dump module listing in
 * Appendix B of the STREAMS Programmer's Guide for System V, Release 4 Multi-
 * Processor (Intel Edition). The overall structure of the code has been
 * retained, with some editing to reflect local coding standards, additional
 * commentary, and to bring the code up to SVR4MP DDI/DKI standards.
 */

#define	_DDI_DKI	1
#define	_SYSV4		1

#include <common/ccompat.h>
#include <sys/inline.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/errno.h>
#include <sys/cred.h>
#include <stddef.h>

/*
 * DUMP Module. This module prints data and ioctls going to and from a device
 * in real time. Printout is on the console. Usage is to push it on a stream
 * between any other modules.
 *
 * It accepts two ioctls:
 *	DUMP_VERB	Verbose printing of M_DATA (default)
 *	DUMP_TERSE	Terse printing of data
 *
 * The messages it prints begin with "I:" for incoming, "O:" for outgoing
 * data. "Ci" or "Co" are for non-data (control) messages. Data is printed in
 * character or hexadecimal format delimited by {{ and }} at message
 * boundaries.
 */

#include <sys/stream.h>
#include <sys/cmn_err.h>
#include "dump.h"

static struct module_info dumprinfo = {
	0x6475, "dump", 0, INFPSZ, 0, 0
};
static struct module_info dumpwinfo = {
	0x6475, "dump", 0, INFPSZ, 0, 0
};


static	int	dumpopen	__PROTO ((queue_t * q, dev_t * devp, int flag,
					  int sflag, cred_t * credp));
static	int	dumpclose	__PROTO ((queue_t * q, int flag,
					  cred_t * credp));
static	void	dumpwput	__PROTO ((queue_t * q, mblk_t * mp));
static 	void	dumprput	__PROTO ((queue_t * q, mblk_t * mp));

static struct qinit rinit = {
	dumprput, NULL, dumpopen, dumpclose, NULL, & dumprinfo, NULL
};
static struct qinit winit = {
	dumpwput, NULL, NULL, NULL, NULL, & dumpwinfo, NULL
};

struct streamtab dumpinfo = {
	& rinit, & winit, NULL, NULL
};

int		dumpdevflag = 0;


/*
 * Gather information from this data message and print it. The caller deals
 * with actually forwarding the data message.
 */

#if	__USE_PROTO__
__LOCAL__ void (dumpgather) (queue_t * q, mblk_t * mp, dm_dir_t dir)
#else
__LOCAL__ void
dumpgather __ARGS ((q, mp, dir))
queue_t	      *	q;
mblk_t	      *	mp;
dm_dir_t	dir;
#endif
{
	struct dm_str *	d = (struct dm_str *) q->q_ptr;
	pl_t		prev_pl;
	mblk_t	      *	tmp;
	unsigned long	counter;
	char		junk [2];

	/*
	 * Check state and print direction indication when it changes.
	 */

	if (d->dm_dir != dir) {

		d->dm_dir = dir;
		cmn_err (CE_CONT, dir == D_IN ? "^\nIN:" : "^\nOUT:");
	}

	if (mp->b_datap == NULL ||
	    (mp->b_rptr == mp->b_wptr && mp->b_cont == NULL)) {
		/*
		 * Zero-length messages are treated specially in most streams,
		 * note them specially.
		 */

		cmn_err (CE_CONT, "^DUMP: Zero-length data message\n");
		return;
	}

	cmn_err (CE_CONT, "^ {{");

	tmp = mp;
	counter = 0;
	junk [1] = 0;

	prev_pl = splstr ();

	do {
		unsigned char *	readp;

		if ((d->dm_flags & D_VERB) == 0) {

			counter += tmp->b_wptr - tmp->b_rptr;
			continue;
		}

		for (readp = tmp->b_rptr ; readp < tmp->b_wptr ; readp ++)
			if ((junk [0] = * readp) >= ' ' && junk [0] <= '~')
				cmn_err (CE_CONT, "^ %s", junk);
			else
				cmn_err (CE_CONT, "^ 0x%x", junk [0]);

	} while ((tmp = tmp->b_cont) != NULL &&
		 tmp->b_datap->db_type == M_DATA);


	if ((d->dm_flags & D_VERB) == 0)
		cmn_err (CE_CONT, "^ %d", counter);

	cmn_err (CE_CONT, "^ }} ");

	if (tmp != NULL)
		cmn_err (CE_CONT, "^\nDUMP: non-data b_cont\n");

	splx (prev_pl);
}


/*
 * Completely handle one of our ioctl () calls, including the qreply () of the
 * message.
 */

#if	__USE_PROTO__
__LOCAL__ void (dumpioc) (queue_t * q, mblk_t * mp)
#else
__LOCAL__ void
dumpioc __ARGS ((q, mp))
queue_t	      *	q;
mblk_t	      *	mp;
#endif
{
	struct iocblk *	iocp = (struct iocblk *) mp->b_rptr;
	struct dm_str *	d = (struct dm_str *) q->q_ptr;

	cmn_err (CE_CONT, "^DUMP: own ioctl is ");

	switch (iocp->ioc_cmd) {

	case DUMP_VERB:
		d->dm_flags |= D_VERB;
		cmn_err (CE_CONT, "^DUMP_VERB\n");

		mp->b_datap->db_type = M_IOCACK;
		break;

	case DUMP_TERSE:
		d->dm_flags &= ~ D_VERB;
		cmn_err (CE_CONT, "^DUMP_TERSE\n");

		mp->b_datap->db_type = M_IOCACK;
		break;

	default:
		cmn_err (CE_CONT, "^ unknown, %x\n", iocp->ioc_cmd);

		mp->b_datap->db_type = M_IOCNAK;
		break;
	}

	iocp->ioc_count = 0;
	qreply (q, mp);
}


/*
 * Display information about control messages.
 */

#if	__USE_PROTO__
__LOCAL__ void (dumpctl) (queue_t * q, mblk_t * mp, dm_dir_t dir)
#else
__LOCAL__ void
dumpctl __ARGS ((q, mp, dir))
queue_t	      *	q;
mblk_t	      *	mp;
dm_dir_t	dir;
#endif
{
	__CONST__ char * tmp = NULL;

	cmn_err (CE_CONT, "^\nC%s: M_", dir == D_IN ? "i" : "o");

	switch (mp->b_datap->db_type) {

		/* just in case */
	case M_DATA:	tmp = "DATA";	break;

	case M_READ:	tmp = "READ";	break;

	case M_IOCTL:	tmp = "IOCTL";	break;

	case M_IOCACK:	tmp = "IOCACK";	break;

	case M_IOCNAK:	tmp = "IOCNAK";	break;

	case M_IOCDATA:	tmp = "IOCDATA"; break;

	case M_CTL:	tmp = "CTL";	break;

	case M_PROTO:	tmp = "PROTO";	break;

	case M_PCPROTO:	tmp = "PCPROTO"; break;

	case M_BREAK:	tmp = "BREAK";	break;

	case M_DELAY:	tmp = "DELAY";	break;

	case M_PASSFP:	tmp = "PASSFP";	break;

	case M_SETOPTS:	tmp = "SETOPTS"; break;

	case M_ERROR:	tmp = "ERROR";	break;

	case M_HANGUP:	tmp = "HANGUP";	break;

	case M_FLUSH:	tmp = "FLUSH";	break;

	case M_COPYOUT:	tmp = "COPYOUT"; break;

	case M_COPYIN:	tmp = "COPYIN";	break;

	case M_START:	tmp = "START";	break;

	case M_STOP:	tmp = "STOP";	break;

	case M_STARTI:	tmp = "STARTI";	break;

	case M_STOPI:	tmp = "STOPI";	break;

	case M_SIG:
		cmn_err (CE_CONT, "^SIG (%d) ", * mp->b_rptr);
		break;

	case M_PCSIG:
		cmn_err (CE_CONT, "^PCSIG (%d) ", * mp->b_rptr);
		break;

	default:
		cmn_err (CE_CONT, "^Unknown! (0x%x) ", mp->b_datap->db_type);
		break;
	}

	if (tmp != NULL)
		cmn_err (CE_CONT, "^%s", tmp);

	/*
	 * Reset the direction indicator so the next data message will print
	 * the direction it is headed in.
	 */

	((struct dm_str *) q->q_ptr)->dm_dir = D_NONE;
}


/*
 * Display information about generally-known ioctl ()s. Feel free to add more
 * knowledge to this to suit your application.
 */

#if	__USE_PROTO__
__LOCAL__ void (dumpshow) (mblk_t * __NOTUSED (mp), int cmd)
#else
__LOCAL__ void
dumpshow __ARGS ((mp, cmd))
mblk_t	      *	mp;
int		cmd;
#endif
{
	switch (cmd) {

	default:
        	return;
	}
}


/*
 * Open a dump filter.
 */

#if	__USE_PROTO__
int dumpopen (queue_t * q, dev_t * __NOTUSED (devp), int flag,
	      int __NOTUSED (sflag), cred_t * __NOTUSED (credp))
#else
int dumpopen (q, devp, flag, sflag, credp)
queue_t	      *	q;
dev_t	      *	devp;
int		flag;
int		sflag;
cred_t	      *	credp;
#endif
{
	int		i;

	if (q->q_ptr != NULL) {

		cmn_err (CE_CONT, "^DUMP: re-open slot %d\n",
			 (struct dm_str *) q->q_ptr - dm_users);

		if ((flag & FNDELAY) != 0)
			cmn_err (CE_CONT, "^DUMP: reopen, NDELAY set\n");
		if ((flag & FNONBLOCK) != 0)
			cmn_err (CE_CONT, "^DUMP: reopen, NONBLOCK set\n");

		qprocson (q);
		return 0;
	}

	/*
	 * Search for a slot to use. We depend on the single-threading of
	 * driver open routines to protect this code, and the complementary
	 * code in dumpclose ()
	 */

	for (i = 0 ; i < dm_ucnt ; i ++) {

		if (dm_users [i].dm_use == D_FREE) {

			dm_users [i].dm_use = D_USED;
			dm_users [i].dm_dir = D_NONE;
			dm_users [i].dm_flags = D_VERB;

			WR (q)->q_ptr = q->q_ptr = (_VOID *) & dm_users [i];

			cmn_err (CE_CONT, "^DUMP: flag = %d\n", flag);

			if ((flag & FNDELAY) != 0)
				cmn_err (CE_CONT, "^DUMP: open, NDELAY set\n");
			if ((flag & FNONBLOCK) != 0)
				cmn_err (CE_CONT, "^DUMP: open, NONBLOCK set\n");

			qprocson (q);
			return 0;
		}
	}

        return EAGAIN;
}


/*
 * Close an entry and deallocate the control slot.
 */

#if	__USE_PROTO__
int (dumpclose) (queue_t * q, int __NOTUSED (flag),
		 cred_t * __NOTUSED (credp))
#else
int
dumpclose (q, flag, credp)
queue_t	      *	q;
int		flag;
cred_t	      *	credp;
#endif
{
	struct dm_str *	d = (struct dm_str *) q->q_ptr;

	d->dm_use = D_FREE;
	d->dm_flags = 0;

	WR (q)->q_ptr = q->q_ptr = NULL;

	cmn_err (CE_CONT, "^\nDUMP: end trace\n");
	qprocsoff (q);
	return 0;
}


/*
 * Put procedure for write side of module. Gathers data from all passing
 * M_DATA messages. Calls routine to handle ioctl calls.
 */

#if	__USE_PROTO__
void dumpwput (queue_t * q, mblk_t * mp)
#else
void
dumpwput (q, mp)
queue_t	      *	q;
mblk_t	      *	mp;
#endif
{
	if (mp->b_datap->db_type == M_IOCTL) {
		struct iocblk *	iocp = (struct iocblk *) mp->b_rptr;
		struct dm_str *	d = (struct dm_str *) q->q_ptr;

		if ((iocp->ioc_cmd & DUMPIOC) == DUMPIOC) {

			dumpioc (q, mp);
			return;
		}

		cmn_err (CE_CONT, "^Co: M_IOCTL %x, cnt %d ",
			 iocp->ioc_cmd, iocp->ioc_count);

		if ((d->dm_flags & D_VERB) != 0 && mp->b_cont)
			dumpshow (mp->b_cont, iocp->ioc_count);

		d->dm_dir = D_NONE;

	} else if (mp->b_datap->db_type == M_DATA)
		dumpgather (q, mp, D_OUT);
	else
		dumpctl (q, mp, D_OUT);

	putnext (q, mp);
}


/*
 * Read side put procedure, simply discriminates between upwards-bound control
 * and data.
 */

#if	__USE_PROTO__
void dumprput (queue_t * q, mblk_t * mp)
#else
void
dumprput (q, mp)
queue_t	      *	q;
mblk_t	      *	mp;
#endif
{
	if (mp->b_datap->db_type == M_DATA)
		dumpgather (q, mp, D_IN);
	else
		dumpctl (q, mp, D_IN);

	putnext (q, mp);
}