Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!utgpu!water!watmath!clyde!rutgers!husc6!cmcl2!brl-adm!adm!drears@ARDEC.arpa From: drears@ARDEC.arpa Newsgroups: comp.unix.wizards Subject: Re: tty watcher Message-ID: <9596@brl-adm.ARPA> Date: Fri, 2-Oct-87 19:13:32 EDT Article-I.D.: brl-adm.9596 Posted: Fri Oct 2 19:13:32 1987 Date-Received: Sat, 3-Oct-87 11:42:20 EDT Sender: news@brl-adm.ARPA Lines: 204 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 #include #include #include #include #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); } }