From dde8a05baa845591e418a5e69252e1baf17aaf8e Mon Sep 17 00:00:00 2001 From: "Ugen J.S. Antsilevich" Date: Tue, 14 Feb 1995 21:21:26 +0000 Subject: [PATCH] Here it came-the all-brand-new snoop device.. Users-beware.. It is tested and working for me but probably have some bugs i didn't noticed so test it and reply... It can: look at what's sent to the user from tty device snoop on pty's,vty's and serial tty's It (still) can't: write to tty see what user types in local echo mode It is probably bad styled and very dependant on tty_pty.c,sio.c and syscons.c I would be really happy if another ppl would make their changes because i am not sure this is the best snoop we can have..but it is good..:))))) --- sys/dev/snp/snp.c | 469 +++++++++++++++++++++++++++++++++++++++++++ sys/kern/tty.c | 20 +- sys/kern/tty_snoop.c | 469 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 954 insertions(+), 4 deletions(-) create mode 100644 sys/dev/snp/snp.c create mode 100644 sys/kern/tty_snoop.c diff --git a/sys/dev/snp/snp.c b/sys/dev/snp/snp.c new file mode 100644 index 000000000000..35ee6ea89ad7 --- /dev/null +++ b/sys/dev/snp/snp.c @@ -0,0 +1,469 @@ +/* + * Copyright (c) 1995 Ugen J.S.Antsilevich + * + * Redistribution and use in source forms, with and without modification, + * are permitted provided that this entire comment appears intact. + * + * Redistribution in binary form may occur without any restrictions. + * Obviously, it would be nice if you gave credit where credit is due + * but requiring it would be too onerous. + * + * This software is provided ``AS IS'' without any warranties of any kind. + * + * Snoop stuff. + */ + +#include "snp.h" + +#if (defined NSNP) && (NSNP > 0) + +#include +#include +#include +#include /* Oooh..We need O/NTTYDISC */ +#include +#define TTYDEFCHARS +#include +#undef TTYDEFCHARS +#include +#include +#include +#include +#include + +#include + + + +#ifdef ST_PTY +/* + * This should be same as in "kern/tty_pty.c" + */ +#include "pty.h" + +#if NPTY == 1 +#undef NPTY +#define NPTY 32 +#endif + +extern struct tty pt_tty[]; +#endif /* ST_PTY */ + + +#ifdef ST_SIO +/* + * This should be same as "i386/isa/sio.c" + */ +#include "sio.h" + +extern struct tty sio_tty[]; +#endif /* ST_SIO */ + + +#ifdef ST_VTY +/* + * This should match "i386/isa/sc.c" + */ + +#if !defined(MAXCONS) +#define MAXCONS 16 +#endif + +extern struct tty sccons[]; +#endif /* ST_VTY */ + + +/* + * This is local structure to hold + * data for all tty arrays we serve. + */ +typedef struct tty tty_arr[]; +struct tty_tab { + int lt_max; + tty_arr *lt_tab; +}; + +static struct tty_tab tty_tabs[]={ +#ifdef ST_PTY + { NPTY , &pt_tty }, +#else + { -1 , NULL }, +#endif +#ifdef ST_VTY + { MAXCONS, &sccons }, +#else + { -1 , NULL }, +#endif +#ifdef ST_SIO + { NSIO , &sio_tty } +#else + { -1 , NULL } +#endif +}; + + +#ifndef MIN +#define MIN(a,b) (((a)<(b))?(a):(b)) +#endif + + +static struct snoop snoopsw[NSNP]; + +int +snpread(dev, uio, flag) + dev_t dev; + struct uio *uio; + int flag; +{ + int unit = minor(dev),s; + struct snoop *snp = &snoopsw[unit]; + int len,n,nblen,error = 0; + caddr_t from; + char *nbuf; + +#ifdef DIAGNOSTIC + if ((snp->snp_len+snp->snp_base)>snp->snp_blen) + panic("snoop buffer error"); +#endif + if (snp->snp_unit==-1) + return (EIO); + + snp->snp_flags &= ~SNOOP_RWAIT; + + do { + if (snp->snp_len == 0) { + if (snp->snp_flags & SNOOP_NBIO) { + return EWOULDBLOCK; + } + snp->snp_flags|=SNOOP_RWAIT; + tsleep((caddr_t)snp,(PZERO+1)|PCATCH,"snoopread",0); + } + } while (snp->snp_len == 0); + + n = uio->uio_resid; + + while (snp->snp_len > 0 && uio->uio_resid > 0 && error == 0) { + len = MIN(uio->uio_resid,snp->snp_len); + from = (caddr_t)(snp->snp_buf+snp->snp_base); + if (len == 0) + break; + + error = uiomove(from,len,uio); + snp->snp_base+=len; + snp->snp_len-=len; + } + if (n) + snp->snp_flags &= ~SNOOP_OFLOW; + + s=spltty(); + nblen=snp->snp_blen; + if (((nblen/2)>=SNOOP_MINLEN) && (nblen/2)>=snp->snp_len) { + while (((nblen/2)>=snp->snp_len) && ((nblen/2)>=SNOOP_MINLEN)) + nblen=nblen/2; + if (nbuf=malloc(nblen,M_TTYS,M_NOWAIT)) { + bcopy(snp->snp_buf+snp->snp_base,nbuf,snp->snp_len); + free(snp->snp_buf,M_TTYS); + snp->snp_buf=nbuf; + snp->snp_blen=nblen; + snp->snp_base=0; + } + } + splx(s); + + return error; +} + + +int +snpin(snp,buf,n) +struct snoop *snp; +char *buf; +int n; +{ + int s_free,s_tail; + int s,len,nblen; + caddr_t from,to; + char *nbuf; + struct tty_tab *l_tty; + struct tty *tp; + + + if (n == 0) + return 0; + +#ifdef DIAGNOSTIC + if (n < 0) + panic("bad snoop char count"); +#endif + if (snp->snp_flags&SNOOP_OFLOW) { + printf("Snoop: buffer overflow \n"); + /* + * On overflow we just repeat the standart + * close procedure...yes , this is waste of space but.. + * Then next read from device will fail if one would + * recall he is snooping and retry... + */ + snp->snp_flags &= ~SNOOP_OPEN; + snp->snp_base = 0; + snp->snp_len = 0; + snp->snp_blen=0; + free(snp->snp_buf,M_TTYS); + + /* + * If line disc. changed we do not touch + * this pointer,SLIP/PPP will change it anyway. + */ + + if (snp->snp_unit==-1) + goto oflow_notty; + + l_tty=&(tty_tabs[snp->snp_type]); + tp=&((*l_tty->lt_tab)[snp->snp_unit]); + + if (tp->t_sc == snp && (tp->t_state&TS_SNOOP) && + (tp->t_line == OTTYDISC || tp->t_line == NTTYDISC)) { + tp->t_sc = NULL; + tp->t_state &=~TS_SNOOP; + }; + snp->snp_unit=-1; + +oflow_notty: + selwakeup(&snp->snp_sel); + snp->snp_sel.si_pid = 0; + + return (0); +} + + s_free = snp->snp_blen - ( snp->snp_len + snp->snp_base ); + s_tail = snp->snp_blen - snp->snp_len; + + + if (n > s_free) { + s=spltty(); + nblen=snp->snp_blen; + while ((n > s_free) && ((nblen*2)<=SNOOP_MAXLEN)) { + nblen=snp->snp_blen*2; + s_free = nblen - ( snp->snp_len + snp->snp_base ); + } + if ((n<=s_free) && (nbuf=malloc(nblen,M_TTYS,M_NOWAIT))) { + bcopy(snp->snp_buf+snp->snp_base,nbuf,snp->snp_len); + free(snp->snp_buf,M_TTYS); + snp->snp_buf=nbuf; + snp->snp_blen=nblen; + snp->snp_base=0; + } else { + snp->snp_flags|=SNOOP_OFLOW; + if (snp->snp_flags & SNOOP_RWAIT) { + snp->snp_flags &= ~SNOOP_RWAIT; + wakeup((caddr_t)snp); + } + splx(s); + return 0; + } + splx(s); + } + + if (n > s_tail) { + from=(caddr_t)(snp->snp_buf+snp->snp_base); + to=(caddr_t)(snp->snp_buf); + len=snp->snp_len; + bcopy(from,to,len); + snp->snp_base=0; + } + + + to=(caddr_t)(snp->snp_buf+snp->snp_base+snp->snp_len); + bcopy(buf,to,n); + snp->snp_len+=n; + + if (snp->snp_flags & SNOOP_RWAIT) { + snp->snp_flags &= ~SNOOP_RWAIT; + wakeup((caddr_t)snp); + } + + selwakeup(&snp->snp_sel); + snp->snp_sel.si_pid = 0; + + return n; +} + +int +snpopen(dev, flag, mode, p) + dev_t dev; + int flag, mode; + struct proc *p; +{ + struct snoop *snp; + register int unit, error; + + if (error = suser(p->p_ucred, &p->p_acflag)) + return (error); + + if ((unit = minor(dev)) >= NSNP) + return (ENXIO); + snp = &snoopsw[unit]; + if (snp->snp_flags & SNOOP_OPEN) + return (ENXIO); + snp->snp_flags |= SNOOP_OPEN; + + snp->snp_buf=malloc(SNOOP_MINLEN,M_TTYS,M_WAITOK); + snp->snp_blen=SNOOP_MINLEN; + snp->snp_base=0; + snp->snp_len=0; + + /* + * unit == -1 is for inactive snoop + * devices. + */ + snp->snp_unit=-1; + + return (0); +} + +int +snpclose(dev, flag) + dev_t dev; + int flag; +{ + register int unit = minor(dev); + struct snoop *snp = &snoopsw[unit]; + struct tty *tp; + struct tty_tab *l_tty; + + snp->snp_flags &= ~SNOOP_OPEN; + snp->snp_base = 0; + snp->snp_len = 0; + snp->snp_blen=0; + free(snp->snp_buf,M_TTYS); + + /* + * If line disc. changed we do not touch + * this pointer,SLIP/PPP will change it anyway. + */ + + if (snp->snp_unit==-1) + goto close_notty; + + l_tty=&tty_tabs[snp->snp_type]; + tp=&((*l_tty->lt_tab)[snp->snp_unit]); + + if (tp->t_sc == snp && (tp->t_state&TS_SNOOP) && + (tp->t_line == OTTYDISC || tp->t_line == NTTYDISC)) { + tp->t_sc = NULL; + tp->t_state &=~TS_SNOOP; + }; + snp->snp_unit=-1; + +close_notty: + selwakeup(&snp->snp_sel); + snp->snp_sel.si_pid = 0; + + return (0); +} + + + + +int +snpioctl(dev, cmd, data, flag) + dev_t dev; + int cmd; + caddr_t data; + int flag; +{ + int unit = minor(dev),s; + int tunit,ttype; + struct snoop *snp = &snoopsw[unit]; + struct tty *tp,*tpo; + struct tty_tab *l_tty,*l_otty; + + switch (cmd) { + case SNPSTTY: + tunit=((struct snptty *)data)->st_unit; + ttype=((struct snptty *)data)->st_type; + + if (ttype < 0 || ttype > ST_MAXTYPE) + return (EINVAL); + + l_tty = &tty_tabs[ttype]; + if (l_tty->lt_tab == NULL) + return (EINVAL); + + if (tunit < 0 || tunit >= l_tty->lt_max) + return (EINVAL); + + tp=&((*l_tty->lt_tab)[tunit]); + + if (tp->t_sc!=(caddr_t)snp && (tp->t_state&TS_SNOOP)) + return (EBUSY); + + if (tp->t_line!=OTTYDISC && tp->t_line!=NTTYDISC) + return (EBUSY); + + s=spltty(); + if (snp->snp_unit != -1) { + l_otty=&tty_tabs[snp->snp_type]; + tpo=&((*l_otty->lt_tab)[snp->snp_unit]); + tpo->t_state &=~TS_SNOOP; + } + + tp->t_sc=(caddr_t)snp; + tp->t_state |= TS_SNOOP; + snp->snp_unit = tunit; + splx(s); + + break; + case SNPGTTY: + ((struct snptty *)data)->st_unit = snp->snp_unit; + ((struct snptty *)data)->st_type = snp->snp_type; + break; + + case FIONBIO: + if (*(int *)data) + snp->snp_flags |= SNOOP_NBIO; + else + snp->snp_flags &= ~SNOOP_NBIO; + break; + case FIOASYNC: + if (*(int *)data) + snp->snp_flags |= SNOOP_ASYNC; + else + snp->snp_flags &= ~SNOOP_ASYNC; + break; + case FIONREAD: + s = spltty(); + if (snp->snp_unit!=-1) + *(int *)data = snp->snp_len; + else + *(int *)data = 0; + splx(s); + break; + default: + return (ENOTTY); + } + return (0); +} + + +int +snpselect(dev, rw, p) + dev_t dev; + int rw; + struct proc *p; +{ + int unit = minor(dev), s; + struct snoop *snp = &snoopsw[unit]; + + if (rw != FREAD) { + return 0; + } + + if (snp->snp_len > 0) { + return 1; + } + + selrecord(p, &snp->snp_sel); + return 0; +} + +#endif diff --git a/sys/kern/tty.c b/sys/kern/tty.c index 0d5e9d604680..aaa15729dba5 100644 --- a/sys/kern/tty.c +++ b/sys/kern/tty.c @@ -36,9 +36,11 @@ * SUCH DAMAGE. * * @(#)tty.c 8.8 (Berkeley) 1/21/94 - * $Id: tty.c,v 1.23 1995/02/13 02:03:57 ache Exp $ + * $Id: tty.c,v 1.21 1995/02/09 11:13:30 jkh Exp $ */ +#include "snp.h" + #include #include #include @@ -57,8 +59,13 @@ #include #include +#if (defined NSNP) && (NSNP > 0) +#include +#endif + #include + static int proc_compare __P((struct proc *p1, struct proc *p2)); static void ttyblock __P((struct tty *tp)); static void ttyecho __P((int, struct tty *tp)); @@ -1005,8 +1012,6 @@ ttywait(tp) break; } } - if (!error && (tp->t_outq.c_cc || ISSET(tp->t_state, TS_BUSY))) - error = EIO; splx(s); return (error); } @@ -1138,8 +1143,10 @@ ttylclose(tp, flag) int flag; { - if ((flag & IO_NDELAY) || ttywflush(tp)) + if (flag & IO_NDELAY) ttyflush(tp, FREAD | FWRITE); + else + ttywflush(tp); return (0); } @@ -1594,6 +1601,11 @@ ttwrite(tp, uio, flag) cc = 0; break; } +#if (defined NSNP) && (NSNP > 0) + if (tp->t_state&TS_SNOOP && tp->t_sc!=NULL) { + snpin((struct snoop *)tp->t_sc,cp,cc); + } +#endif } /* * If nothing fancy need be done, grab those characters we diff --git a/sys/kern/tty_snoop.c b/sys/kern/tty_snoop.c new file mode 100644 index 000000000000..35ee6ea89ad7 --- /dev/null +++ b/sys/kern/tty_snoop.c @@ -0,0 +1,469 @@ +/* + * Copyright (c) 1995 Ugen J.S.Antsilevich + * + * Redistribution and use in source forms, with and without modification, + * are permitted provided that this entire comment appears intact. + * + * Redistribution in binary form may occur without any restrictions. + * Obviously, it would be nice if you gave credit where credit is due + * but requiring it would be too onerous. + * + * This software is provided ``AS IS'' without any warranties of any kind. + * + * Snoop stuff. + */ + +#include "snp.h" + +#if (defined NSNP) && (NSNP > 0) + +#include +#include +#include +#include /* Oooh..We need O/NTTYDISC */ +#include +#define TTYDEFCHARS +#include +#undef TTYDEFCHARS +#include +#include +#include +#include +#include + +#include + + + +#ifdef ST_PTY +/* + * This should be same as in "kern/tty_pty.c" + */ +#include "pty.h" + +#if NPTY == 1 +#undef NPTY +#define NPTY 32 +#endif + +extern struct tty pt_tty[]; +#endif /* ST_PTY */ + + +#ifdef ST_SIO +/* + * This should be same as "i386/isa/sio.c" + */ +#include "sio.h" + +extern struct tty sio_tty[]; +#endif /* ST_SIO */ + + +#ifdef ST_VTY +/* + * This should match "i386/isa/sc.c" + */ + +#if !defined(MAXCONS) +#define MAXCONS 16 +#endif + +extern struct tty sccons[]; +#endif /* ST_VTY */ + + +/* + * This is local structure to hold + * data for all tty arrays we serve. + */ +typedef struct tty tty_arr[]; +struct tty_tab { + int lt_max; + tty_arr *lt_tab; +}; + +static struct tty_tab tty_tabs[]={ +#ifdef ST_PTY + { NPTY , &pt_tty }, +#else + { -1 , NULL }, +#endif +#ifdef ST_VTY + { MAXCONS, &sccons }, +#else + { -1 , NULL }, +#endif +#ifdef ST_SIO + { NSIO , &sio_tty } +#else + { -1 , NULL } +#endif +}; + + +#ifndef MIN +#define MIN(a,b) (((a)<(b))?(a):(b)) +#endif + + +static struct snoop snoopsw[NSNP]; + +int +snpread(dev, uio, flag) + dev_t dev; + struct uio *uio; + int flag; +{ + int unit = minor(dev),s; + struct snoop *snp = &snoopsw[unit]; + int len,n,nblen,error = 0; + caddr_t from; + char *nbuf; + +#ifdef DIAGNOSTIC + if ((snp->snp_len+snp->snp_base)>snp->snp_blen) + panic("snoop buffer error"); +#endif + if (snp->snp_unit==-1) + return (EIO); + + snp->snp_flags &= ~SNOOP_RWAIT; + + do { + if (snp->snp_len == 0) { + if (snp->snp_flags & SNOOP_NBIO) { + return EWOULDBLOCK; + } + snp->snp_flags|=SNOOP_RWAIT; + tsleep((caddr_t)snp,(PZERO+1)|PCATCH,"snoopread",0); + } + } while (snp->snp_len == 0); + + n = uio->uio_resid; + + while (snp->snp_len > 0 && uio->uio_resid > 0 && error == 0) { + len = MIN(uio->uio_resid,snp->snp_len); + from = (caddr_t)(snp->snp_buf+snp->snp_base); + if (len == 0) + break; + + error = uiomove(from,len,uio); + snp->snp_base+=len; + snp->snp_len-=len; + } + if (n) + snp->snp_flags &= ~SNOOP_OFLOW; + + s=spltty(); + nblen=snp->snp_blen; + if (((nblen/2)>=SNOOP_MINLEN) && (nblen/2)>=snp->snp_len) { + while (((nblen/2)>=snp->snp_len) && ((nblen/2)>=SNOOP_MINLEN)) + nblen=nblen/2; + if (nbuf=malloc(nblen,M_TTYS,M_NOWAIT)) { + bcopy(snp->snp_buf+snp->snp_base,nbuf,snp->snp_len); + free(snp->snp_buf,M_TTYS); + snp->snp_buf=nbuf; + snp->snp_blen=nblen; + snp->snp_base=0; + } + } + splx(s); + + return error; +} + + +int +snpin(snp,buf,n) +struct snoop *snp; +char *buf; +int n; +{ + int s_free,s_tail; + int s,len,nblen; + caddr_t from,to; + char *nbuf; + struct tty_tab *l_tty; + struct tty *tp; + + + if (n == 0) + return 0; + +#ifdef DIAGNOSTIC + if (n < 0) + panic("bad snoop char count"); +#endif + if (snp->snp_flags&SNOOP_OFLOW) { + printf("Snoop: buffer overflow \n"); + /* + * On overflow we just repeat the standart + * close procedure...yes , this is waste of space but.. + * Then next read from device will fail if one would + * recall he is snooping and retry... + */ + snp->snp_flags &= ~SNOOP_OPEN; + snp->snp_base = 0; + snp->snp_len = 0; + snp->snp_blen=0; + free(snp->snp_buf,M_TTYS); + + /* + * If line disc. changed we do not touch + * this pointer,SLIP/PPP will change it anyway. + */ + + if (snp->snp_unit==-1) + goto oflow_notty; + + l_tty=&(tty_tabs[snp->snp_type]); + tp=&((*l_tty->lt_tab)[snp->snp_unit]); + + if (tp->t_sc == snp && (tp->t_state&TS_SNOOP) && + (tp->t_line == OTTYDISC || tp->t_line == NTTYDISC)) { + tp->t_sc = NULL; + tp->t_state &=~TS_SNOOP; + }; + snp->snp_unit=-1; + +oflow_notty: + selwakeup(&snp->snp_sel); + snp->snp_sel.si_pid = 0; + + return (0); +} + + s_free = snp->snp_blen - ( snp->snp_len + snp->snp_base ); + s_tail = snp->snp_blen - snp->snp_len; + + + if (n > s_free) { + s=spltty(); + nblen=snp->snp_blen; + while ((n > s_free) && ((nblen*2)<=SNOOP_MAXLEN)) { + nblen=snp->snp_blen*2; + s_free = nblen - ( snp->snp_len + snp->snp_base ); + } + if ((n<=s_free) && (nbuf=malloc(nblen,M_TTYS,M_NOWAIT))) { + bcopy(snp->snp_buf+snp->snp_base,nbuf,snp->snp_len); + free(snp->snp_buf,M_TTYS); + snp->snp_buf=nbuf; + snp->snp_blen=nblen; + snp->snp_base=0; + } else { + snp->snp_flags|=SNOOP_OFLOW; + if (snp->snp_flags & SNOOP_RWAIT) { + snp->snp_flags &= ~SNOOP_RWAIT; + wakeup((caddr_t)snp); + } + splx(s); + return 0; + } + splx(s); + } + + if (n > s_tail) { + from=(caddr_t)(snp->snp_buf+snp->snp_base); + to=(caddr_t)(snp->snp_buf); + len=snp->snp_len; + bcopy(from,to,len); + snp->snp_base=0; + } + + + to=(caddr_t)(snp->snp_buf+snp->snp_base+snp->snp_len); + bcopy(buf,to,n); + snp->snp_len+=n; + + if (snp->snp_flags & SNOOP_RWAIT) { + snp->snp_flags &= ~SNOOP_RWAIT; + wakeup((caddr_t)snp); + } + + selwakeup(&snp->snp_sel); + snp->snp_sel.si_pid = 0; + + return n; +} + +int +snpopen(dev, flag, mode, p) + dev_t dev; + int flag, mode; + struct proc *p; +{ + struct snoop *snp; + register int unit, error; + + if (error = suser(p->p_ucred, &p->p_acflag)) + return (error); + + if ((unit = minor(dev)) >= NSNP) + return (ENXIO); + snp = &snoopsw[unit]; + if (snp->snp_flags & SNOOP_OPEN) + return (ENXIO); + snp->snp_flags |= SNOOP_OPEN; + + snp->snp_buf=malloc(SNOOP_MINLEN,M_TTYS,M_WAITOK); + snp->snp_blen=SNOOP_MINLEN; + snp->snp_base=0; + snp->snp_len=0; + + /* + * unit == -1 is for inactive snoop + * devices. + */ + snp->snp_unit=-1; + + return (0); +} + +int +snpclose(dev, flag) + dev_t dev; + int flag; +{ + register int unit = minor(dev); + struct snoop *snp = &snoopsw[unit]; + struct tty *tp; + struct tty_tab *l_tty; + + snp->snp_flags &= ~SNOOP_OPEN; + snp->snp_base = 0; + snp->snp_len = 0; + snp->snp_blen=0; + free(snp->snp_buf,M_TTYS); + + /* + * If line disc. changed we do not touch + * this pointer,SLIP/PPP will change it anyway. + */ + + if (snp->snp_unit==-1) + goto close_notty; + + l_tty=&tty_tabs[snp->snp_type]; + tp=&((*l_tty->lt_tab)[snp->snp_unit]); + + if (tp->t_sc == snp && (tp->t_state&TS_SNOOP) && + (tp->t_line == OTTYDISC || tp->t_line == NTTYDISC)) { + tp->t_sc = NULL; + tp->t_state &=~TS_SNOOP; + }; + snp->snp_unit=-1; + +close_notty: + selwakeup(&snp->snp_sel); + snp->snp_sel.si_pid = 0; + + return (0); +} + + + + +int +snpioctl(dev, cmd, data, flag) + dev_t dev; + int cmd; + caddr_t data; + int flag; +{ + int unit = minor(dev),s; + int tunit,ttype; + struct snoop *snp = &snoopsw[unit]; + struct tty *tp,*tpo; + struct tty_tab *l_tty,*l_otty; + + switch (cmd) { + case SNPSTTY: + tunit=((struct snptty *)data)->st_unit; + ttype=((struct snptty *)data)->st_type; + + if (ttype < 0 || ttype > ST_MAXTYPE) + return (EINVAL); + + l_tty = &tty_tabs[ttype]; + if (l_tty->lt_tab == NULL) + return (EINVAL); + + if (tunit < 0 || tunit >= l_tty->lt_max) + return (EINVAL); + + tp=&((*l_tty->lt_tab)[tunit]); + + if (tp->t_sc!=(caddr_t)snp && (tp->t_state&TS_SNOOP)) + return (EBUSY); + + if (tp->t_line!=OTTYDISC && tp->t_line!=NTTYDISC) + return (EBUSY); + + s=spltty(); + if (snp->snp_unit != -1) { + l_otty=&tty_tabs[snp->snp_type]; + tpo=&((*l_otty->lt_tab)[snp->snp_unit]); + tpo->t_state &=~TS_SNOOP; + } + + tp->t_sc=(caddr_t)snp; + tp->t_state |= TS_SNOOP; + snp->snp_unit = tunit; + splx(s); + + break; + case SNPGTTY: + ((struct snptty *)data)->st_unit = snp->snp_unit; + ((struct snptty *)data)->st_type = snp->snp_type; + break; + + case FIONBIO: + if (*(int *)data) + snp->snp_flags |= SNOOP_NBIO; + else + snp->snp_flags &= ~SNOOP_NBIO; + break; + case FIOASYNC: + if (*(int *)data) + snp->snp_flags |= SNOOP_ASYNC; + else + snp->snp_flags &= ~SNOOP_ASYNC; + break; + case FIONREAD: + s = spltty(); + if (snp->snp_unit!=-1) + *(int *)data = snp->snp_len; + else + *(int *)data = 0; + splx(s); + break; + default: + return (ENOTTY); + } + return (0); +} + + +int +snpselect(dev, rw, p) + dev_t dev; + int rw; + struct proc *p; +{ + int unit = minor(dev), s; + struct snoop *snp = &snoopsw[unit]; + + if (rw != FREAD) { + return 0; + } + + if (snp->snp_len > 0) { + return 1; + } + + selrecord(p, &snp->snp_sel); + return 0; +} + +#endif