[comp.unix.wizards] tty watcher

root@ozdaltx.UUCP (08/30/87)

I know this is probably simple, but for the life of me I
can't figure out how to do it.

I need to be able to monitor, at will, a port or tty and be
able to see what the person using the tty is seeing and what
they are responding. I'm running SCO XENIX V5. You'd think
this would be simple to do... but... 

Any ideas?
-- 
************************************************
* Scotty                     *  Adapt          *
* ihnp4!killer!ozdaltx!sysop *     Enjoy       *
* "Ad Venerem Securiorem"    *        Survive  *

root@ozdaltx.UUCP (09/25/87)

First, let thank the 30 or so folks who responded in
reference of my looking for code for a tty watcher that
*might* run on a XENIX system.  Some of the names on the
responces looked like a who's who in *NIX.

However, after many "I wrote"s, "I have written"s , 
chest pounding and other self induced back slapping, forwarded
to this site, with four or five possible exceptions, I have yet
to see any genuine offers of help... either in the form of
actual code or logical suggestions. Also noted that many of
the responders obviously DID NOT read/understand the
original question as the referenced systems ranged from Sun
to MINIX (sp?) to whatever.. In other words referencing
specific "flavors" of *NIX... when generic was/is needed.

What has prompted this is, I have seen too many people in
the same situation as I'm in. Asking honest questions and
hoping for a legitimate responce. Instead I see (quite often
from the same people), something to the effect of, "YOU DUMB
S**T.. READ THE F***ING MANUAL... YOU SHOULD BE A GURU LIKE
THE REST OF US". etc., etc., ect. This seems to be a common
malady among programers. (I'm sure I've suffered the same on
occasion).

How about putting the ole egos out to pasture and cut
the **FLAMES** to the newcommers. I once had a professor
who's favorite saying was, "There is no such thing as a dumb
question, unless it is never asked".  To future posters,
at least tell what system/version you are running. *NIX IS
NOT STANDARD.... YET.

We ALL started out pretty DUMB.

-- 
============================================================
| Scotty                     |  Adapt - Enjoy - Survive    |
| ihnp4!killer!ozdaltx!sysop |  "Ad Venerem Securiorem"    |
============================================================

drears@ARDEC.arpa (10/03/87)

     I just started reading this discussion.  I am enclosing a program
soemone sent to me that will allow people with kmem read access to
watch the input of a tty.  It will not work if the user is in raw
mode.  I do not know the orginal author's name.  It was sent to me
unsolicited about two years ago.

Dennis

Disclaimer:   Opinions and statements are mine only. 
cut here
------------------------

#include <stdio.h>
#include <sys/param.h>
#include <sys/clist.h>
#include <nlist.h>
#include <ctype.h>
#include "tty.h"



#define	NDZ	1		/* should be gotten from /sys/dev/dz.h	*/
#define	NDH	3		/* should be gotten from /sys/dev/dh.h	*/
#define	DZ11	1		/* major device number of the dz11	*/
#define	DH11	12		/* major device number of the dh11	*/
#define	DZ_X	8		/* eight lines per dz11			*/
#define	DH_X	16		/* sixteen lines per dh11		*/

#undef	major()			/* need to do this because of kernel	*/
#undef	minor()			/* macros used to strip off device #'s  */

static struct nlist nl[2];

static char *name_list[] = {
	"_dz_tty" ,		/* base address of the dz tty structures*/
	"_dh11" ,		/* same for the dh's			*/
	0
};

main(argc , argv)
char **argv;
int  argc;
{
					/********************************/
	int major;			/* place to hold major #	*/
	int minor;			/* place to hold minor #	*/
	int board_type;			/* tells me which kind of tty   */
	int fd;				/* fd for memory		*/
	long offset;			/* how far into the above tables*/
	struct tty ttyb;		/* place to put the tty buffer	*/
	extern char *calloc();		/* our friend calloc		*/
	char *p;			/* destroy the argv's so noone  */
					/* can see what we are doing	*/
					/********************************/

	get_args(&major , &minor , argc , argv);
	check_args(major , minor , &board_type , argv);
	get_name_list(board_type , argv);
	open_memory(&fd , argv);
	for (p = argv[1]; *p != '\0'; p++) *p = '\0';
	for (p = argv[2]; *p != '\0'; p++) *p = '\0';
	offset = minor * sizeof(struct tty);
	fflush(stdout);
	fflush(stdout);
	while (1) {
		read_tty(fd , nl[0].n_value , offset , &ttyb);
		get_clist(fd , &ttyb.t_nu.t_t.T_rawq);
	}
}

/**
***	Much monkeying around was done before I settled on this
***	procedure. I attempted to follow the c_next pointers in
***	the individual cblocks. This is friutless since by  the
***	time we do the second seek and read the information has
***	been whisked away.
***
***	So - The LIMITATIONS of this routine are:
***
***		cannot read from any tty in RAW mode
***		can only snarf first 28 characters (ie
***			the first cblock)
***
***	Nice things about this routine:
***
***		only NEW  characters  are  echoed to the output
***		(eg characters  in the cblock which  have  been
***		seen before are swallowed).
**/

get_clist(fd , cl)
register struct clist *cl;
{
	static char c[CBSIZE];
	static char *old_start = 0 , *old_finish = 0;
	static int  old_i = 0;
	char *pntr;
	int tn , in;

	if ((cl->c_cc > 0) &&
	    ((old_start != cl->c_cf) || (old_finish != cl->c_cl))) {
		pntr = c;
		lseek(fd , (long) cl->c_cf , 0);
		read(fd , c ,(tn=in=cl->c_cc > CBSIZE ? CBSIZE : cl->c_cc));
		if (old_start == cl->c_cf) {
			in -= old_i;
			pntr += old_i;
		}
		if (in > 0) while (in--) putchar(*(pntr++));
		else if (in < 0) while (in++) putchar('\010');
		fflush(stdout);
		old_i = tn;
		old_start = cl->c_cf;
		old_finish = cl->c_cl;
	}
	if (cl->c_cc <= 0) {
		if (old_i != 0) putchar('\n');
		old_i = old_start = old_finish = NULL;
	}
}

/**
***	The rest of the routines are very strait forward and
***	Rick and Lory won't need comments.
**/

read_tty(fd , base , offset , buffer)
long base , offset;
register struct tty *buffer;
{
	register int i;

	lseek(fd , base + offset , 0);
	i = read(fd , buffer , sizeof(struct tty));
	if (i != sizeof(struct tty)) {
		printf("unexpected return from read\n");
		printf("should have been %d\n" , sizeof(struct tty));
		printf("was %d\n" , i);
		exit(0);
	}
}

open_memory(fd , argv)
int *fd;
char **argv;
{
	if ((*fd = open("/dev/kmem" , 0)) < 0) {
		perror(argv[0]);
		exit(0);
	}
}

get_name_list(index,argv)
char **argv;
{
	nl[0].n_name = name_list[index];
	nlist("/vmunix" , nl);
	if (! nl[0].n_type) {
		printf("%s: couldn't get name list\n" , argv[0]);
	}
	printf("%s starts at %08x\n" , nl[0].n_name , nl[0].n_value);
}

get_args(major , minor , argc , argv)
int *major , *minor , argc;
char **argv;
{
	if (argc != 3) {
		fprintf(stderr,"%s: arg count\n" , argv[0]);
		exit(0);
	}
	*major = atoi(argv[1]);
	*minor = atoi(argv[2]);
	printf("Major Device: %d -- Minor Device: %d\n" , *major , *minor);
}

check_args(major , minor , board , argv)
char **argv;
int *board;
{
	if (minor < 0) {
bad_minor:	printf("%s: bad minor device number\n" , argv[0]);
		exit(0);
	}
	switch (major) {

	case DZ11:
			if (minor >= NDZ * DZ_X) goto bad_minor;
			printf("DZ11 - Unit %d\n" , minor / DZ_X);
			*board = 0;
			break;

	case DH11:
			if (minor >= NDH * DH_X) goto bad_minor;
			printf("DH11 - Unit %d\n" , minor / DH_X);
			*board = 1;
			break;

	default:
			printf("%s: bad major device number\n" , argv[0]);
			exit(0);
	}
}