brad@bradley.bradley.edu (Bradley E. Smith) (02/20/91)
Submitted-by: brad@bradley.bradley.edu (Bradley E. Smith) Posting-number: Volume 1, Issue 9 Archive-name: uipc/part02 # This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # # Wrapped by bradley!brad on Fri Feb 15 22:36:39 CST 1991 # Contents: uipc/src/ uipc/src/debug.c uipc/src/domain.c uipc/src/interface.c # uipc/src/linesw.c uipc/src/mbuf.c uipc/src/number-ptys.h # uipc/src/osel.c uipc/src/osyscalls.c uipc/src/proto.c uipc/src/pty.c # uipc/src/pty.h echo mkdir - uipc/src mkdir uipc/src chmod u=rwx,g=rx,o=rx uipc/src echo x - uipc/src/debug.c sed 's/^@//' > "uipc/src/debug.c" <<'@//E*O*F uipc/src/debug.c//' #ifndef LINT static char * sccsdef = "%W% %D%"; #endif #include <sys/types.h> #include <sys/param.h> #include <sys/systm.h> #include <sys/errno.h> #include <sys/proc.h> #include <uipc/mbuf.h> #include <uipc/socket.h> #include <uipc/socketvar.h> #include <uipc/protosw.h> #include <uipc/domain.h> #include <uipc/unpcb.h> #define PRINTF eprintf /* */ /* #define PRINTF printf /* */ void dump_mbuf (m, func) struct mbuf * m; char *func; { #ifdef OLDWAY (void) PRINTF ("MBUF DUMP [%x]\n", m); (void) PRINTF ("[m_next : %x] [m_off : %x] [m_len : %x] [m_type : %x]\n", m->m_next, m->m_off, m->m_len, m->m_type); if (m->m_type == MT_SOCKET) { struct socket * so = mtod (m, struct socket *); (void) PRINTF ("[so_type %x] [so_state %x]\n", so->so_type, so->so_state); } (void) PRINTF ("MBUF DUMP [done]\n"); #else if (m->m_type == MT_SOCKET) { struct socket * so = mtod (m, struct socket *); PRINTF ("FUNCTION %s: MBUF DUMP [%x]\n[m_next : %x] [m_off : %x] \ [m_len : %x] [m_type : %x]\n[so_type %x] [so_state %x]\n", func, m, m->m_next, m->m_off, m->m_len, m->m_type, so->so_type, so->so_state); } else { PRINTF ("FUNCTION %s: MBUF DUMP [%x]\n[m_next : %x] [m_off : %x] \ [m_len : %x] [m_type : %x]\n", func, m, m->m_next, m->m_off, m->m_len, m->m_type); } #endif } sodebug(so) struct socket *so; { struct unpcb *unp = sotounpcb(so); PRINTF("so_rcv.sb_cc=%u, so_snd.sb_cc=%u\nso_rcv.sb_mb(add)=%u, so_snd.sb_mb=%u\nso_rcv.sb_hiwat=%u, so_snd.sb_hiwat=%u\nunp_cc=%u\n", so->so_rcv.sb_cc, so->so_snd.sb_cc, so->so_rcv.sb_mb, so->so_rcv.sb_mb, so->so_rcv.sb_hiwat, so->so_rcv.sb_hiwat, unp->unp_conn->unp_cc ); }; @//E*O*F uipc/src/debug.c// chmod u=rw,g=r,o=r uipc/src/debug.c echo x - uipc/src/domain.c sed 's/^@//' > "uipc/src/domain.c" <<'@//E*O*F uipc/src/domain.c//' /* * domain.c - routines for handling domains * * Written by Alex Crain. * * This file is loosly based in the Berkeley file uipc_domain.c, * but is *not* guarenteed to be in any way compatable. It is * close enough to the Berkeley code that the following applies... * * Copyright (c) 1982, 1986, 1988 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and that due credit is given * to the University of California at Berkeley. The name of the University * may not be used to endorse or promote products derived from this * software without specific prior written permission. This software * is provided "as is" without express or implied warranty. * */ #include <sys/types.h> #include <sys/param.h> #include <sys/systm.h> #include <uipc/socketvar.h> #include <uipc/socket.h> #include <uipc/protosw.h> #include <uipc/domain.h> #include <uipc/mbuf.h> #include <uipc/fproto.h> #ifndef __STDC__ #define ADDDOMAIN(x) \ { extern struct domain x/**/domain; \ x/**/domain.dom_next = domains; \ domains = &x/**/domain; } #else #define ADDDOMAIN(x) \ { extern struct domain x ## domain; \ x ## domain.dom_next = domains; \ domains = &x ## domain; } #endif void domaininit () { register struct domain * dp; register struct protosw * pr; ADDDOMAIN (unix); #ifdef INET ADDDOMAIN (inet); #endif for (dp = domains; dp; dp = dp->dom_next) { if (dp->dom_init) (* dp->dom_init) (); for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) if (pr->pr_init) (* pr->pr_init) (); } } struct protosw * pffindtype (family, type) int family, type; { register struct domain * dp; register struct protosw * pr; for (dp = domains; dp; dp = dp->dom_next) if (dp->dom_family == family) goto found; return 0; found: for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) if (pr->pr_type && pr->pr_type == type) return pr; return 0; } struct protosw * pffindproto (family, protocol, type) int family, protocol, type; { register struct domain * dp; register struct protosw * pr; struct protosw * maybe = 0; for (dp = domains; dp; dp = dp->dom_next) if (dp->dom_family == family) goto found; return 0; found: for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) { if ((pr->pr_protocol == protocol) && (pr->pr_type == type)) return pr; #ifdef SOCK_RAW if ((type == SOCK_RAW && pr->pr_type == SOCK_RAW && pr->pr_protocol == 0 && maybe = (struct protosw *) 0)) maybe = pr; #endif } return maybe; } @//E*O*F uipc/src/domain.c// chmod u=rw,g=r,o=r uipc/src/domain.c echo x - uipc/src/interface.c sed 's/^@//' > "uipc/src/interface.c" <<'@//E*O*F uipc/src/interface.c//' /* * interface.c - extra system calls interface. * * This started life as a file written by Alex Crain. * */ #include "pty.h" #include <sys/types.h> #include <sys/systm.h> #include <sys/errno.h> #include <sys/user.h> #include <sys/conf.h> #include <uipc/socketvar.h> #include <uipc/mbuf.h> #include <uipc/protosw.h> #include <uipc/domain.h> #include <uipc/fproto.h> #include "sysent.h" void dosyscall(); /* stuff to wake up on */ extern int select_sleep; extern nulldev(); extern int se_register(); extern int ptyopen(); int (*old_locsys)(); /* saved value of sysent[SYSL_LOCSYS].sy_call */ int pty_major = 0; /* major number of pty device for use by select */ void ptyinit () { int i; /* * add our own system call processor. */ old_locsys = sysent[SYSL_LOCSYS].sy_call; sysent[SYSL_LOCSYS].sy_call = (int (*)()) dosyscall; /* * find out where the pty major device is */ for(i=0;i<cdevcnt;i++) { if(cdevsw[i].d_open == ptyopen) pty_major = i; /* got it */ } # ifdef DEBUGA eprintf("ptyinit: pty_major = %d\n", pty_major); # endif se_linesw_setup(); /* initalize line switch */ cdevsw[pty_major].d_ttys = pts_tty; /* tell gettty where to find us */ /* * tell other drivers how to register for select service (polling) */ ldmisc[SEL_REGISTER] = se_register; uipcinit(); } void dosyscall() { int index = u.u_ap[0] - SYSL_FIRST; /* * Intercept our calls */ if (index >= 0 && index <= (SYSL_LAST - SYSL_FIRST)) { /* * syscall arguments are available via the users %sp, at u.u_ar0[15]. * These arguments must be copied to the argument vector u.u_arg[] * for access by the kernal. Noting that the stack looks like: * %sp -> [ frame link, &68, arg1, arg2 ... ] */ int arg = 0; int * ap = (int *) (u.u_ar0[15]) + 2; while (arg < sysentries[index].sy_narg) u.u_arg[arg++] = fuword(ap++); /* * Perform the call. */ # ifdef DEBUGA eprintf("pty.select: calling sysentries[%d].sy_call", index); # endif (* sysentries[index].sy_call) (); } else (*old_locsys) (); } int serelease () { int s = spl5(); # ifdef DEBUGA eprintf("pty.select: in serelease\n"); # endif /* Did we get here without going through our system call interface? */ if (sysent[SYSL_LOCSYS].sy_call != old_locsys) { /* check if any other system call drivers were loaded after us but not * unloaded yet. Drivers which add system calls through SYSL_LOCSYS * must be uninstalled in the oposite order that they are installed */ if (sysent[SYSL_LOCSYS].sy_call != (int (*)()) dosyscall) { u.u_error = EBUSY; /* order of driver unloads must be wrong! */ return; } sysent[SYSL_LOCSYS].sy_call = old_locsys; ldmisc[SEL_REGISTER] = nulldev; # ifdef DEBUG eprintf("pty.select: calling se_linesw_release and setting error\n"); # endif se_linesw_release(); u.u_error = EAGAIN; /* we can't release our memory yet, since we still have stuff on the kernel return stack. The next call will succeed. */ } splx (s); uipcrelease(); return; } extern void (* sock_read)(); extern void (* sock_write)(); extern void (* sock_close)(); void uipcinit () { int i; /* * link to the existing hooks in the kernal. */ sock_read = uipc_read; sock_write = uipc_write; sock_close = uipc_close; /* * Initialize the system. */ mbinit (); domaininit (); } int uipcrelease () { int mbmem_ref; int s = spl5(); struct mbuf * m; for (m = mbmem; m < &mbmem[NMBUF+1]; m++) if (m->m_type == MT_SOCKET) if (soclose (mtod (m, struct socket *))) return EBUSY; for (mbmem_ref =0, m = mbmem; m < &mbmem[NMBUF+1]; m++, mbmem_ref++) if (m->m_type != MT_FREE) { int * i; (void) printf ("\n\n\nUIPC: Illegal mbuf type %d.\n", m->m_type); (void) printf ("m = ([*|%x] [m_next|%x] [m_len|%x] [m_type|%x])\n", m, m->m_next, m->m_len, m->m_type); (void) printf ("mbmem_ref=%d, NMBUF=%d\n", mbmem_ref, NMBUF); for (i = mtod (m, int *); i < ((int *) ((caddr_t) m + MSIZE - MTAIL)); i+=4) (void) printf ("%x %x %x %x\n", *i, *(i+1), *(i+2), *(i+3)); panic ("uipc_release"); } splx (s); return 0; } /* * rdwr() uses this for reading sockets. * * There are no arguments, pertinant info is available as: * u.u_ap[0] - The file descriptor number * u.u_base - IO buffer address * u.u_count - size of buffer. * u.u_segflg - IO buffer location * * Errors do not return, rather an error condition is handled with a longjmp * to u.u_qsav, with some non-zero argument. the call will return -1 to the * user, passing the error in errno (u.u_error). Since the jump returns * directly to trap(), we need to do any houskeeping here. */ void uipc_write () { struct file * fp = getf (u.u_ap[0]); u.u_error = sosend (filesock (fp), (struct mbuf *) 0, 0, (struct mbuf *) 0); /* * process errors */ if (u.u_error) longjmp (u.u_qsav, 1); } void uipc_read () { struct file * fp = getf (u.u_ap[0]); u.u_error = soreceive (filesock (fp), (struct mbuf **) 0, 0, (struct mbuf **) 0); /* * process errors */ if (u.u_error) longjmp (u.u_qsav, 1); } void uipc_close (sp) off_t sp; { u.u_error = soclose (mtod (ptom (sp), struct socket *)); #ifdef SELECT selwakeup(0); /* wake up any one waiting */ #endif /* * process errors */ if (u.u_error) longjmp (u.u_qsav, 1); } /* * General utilities for the BSD<->sysV mix. */ #ifdef unixpc asm(" global bzero "); asm("bzero: "); asm(" mov.l 4(%sp),%a0"); asm(" mov.w 10(%sp),%d0"); asm(" sub.w &1,%d0 "); asm(" bmi end "); asm("loop: "); asm(" mov.b &0,(%a0)+"); asm(" dbf %d0,loop"); asm("end: "); asm(" rts "); #else void bzero (s, n) char * s; int n; { while (n--) *s++ = '\0'; } #endif int ufavail () { int avail = 0, fd = 0; for (fd = 0; fd < 80; fd++) if (u.u_ofile[fd] == 0) avail++; return avail; } @//E*O*F uipc/src/interface.c// chmod u=rw,g=r,o=r uipc/src/interface.c echo x - uipc/src/linesw.c sed 's/^@//' > "uipc/src/linesw.c" <<'@//E*O*F uipc/src/linesw.c//' /* * This file contains hooks to intercept tty line input and notify selecting * processes to poll for fd's ready to read. */ #include <sys/types.h> #include <sys/sysmacros.h> #include <sys/conf.h> #include <sys/tty.h> #include "select.h" int (*real_linesw_l_input)(); /* extern int selecting; */ se_linesw_l_input(tp) struct tty *tp; { /* check for wakeup maybe? */ if((SELPROC(tp) & 0xffffffL) != 0xffffffL) { # ifdef DEBUGA eprintf("select: linesw: got input wakeing up select\n"); # endif selwakeup(SELPROC(tp) & 0xffffffL); SELPROC(tp) |= 0xffffffL; } /* call real input routine */ (*real_linesw_l_input)(tp); } se_linesw_setup() { /* setup to route tty input to here */ real_linesw_l_input = linesw[0].l_input; linesw[0].l_input = se_linesw_l_input; } se_linesw_release() { /* setup to route tty back to normal */ linesw[0].l_input = real_linesw_l_input; } @//E*O*F uipc/src/linesw.c// chmod u=rw,g=rw,o=rw uipc/src/linesw.c echo x - uipc/src/mbuf.c sed 's/^@//' > "uipc/src/mbuf.c" <<'@//E*O*F uipc/src/mbuf.c//' #ifndef LINT static char * sccsdef = "%W% %D%"; #endif /* * mbuf.c - high level socket routines * * Written by Alex Crain. * * This file is based in the Berkeley file uipc_mbuf.c, * but is *not* guarenteed to be in any way compatable. It is * close enough to the Berkeley code that the following applies... * * Copyright (c) 1982, 1986, 1988 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and that due credit is given * to the University of California at Berkeley. The name of the University * may not be used to endorse or promote products derived from this * software without specific prior written permission. This software * is provided "as is" without express or implied warranty. * */ #include <sys/types.h> #include <sys/param.h> #include <sys/systm.h> #include <uipc/socketvar.h> #include <uipc/protosw.h> #include <uipc/domain.h> #include <uipc/mbuf.h> #include <uipc/fproto.h> static char mbuf_data[sizeof (struct mbuf) * (NMBUF + 1)]; /* * Initialize the mbuf map; all free in a null terminated linked list. */ void mbinit() { register int i; mfree = mbmem = &(dtom (mbuf_data))[1]; mbmask = ((unsigned int) mbmem & 0xFF800000); for (i = 0; i < NMBUF; i++) { mbmem[i].m_type = MT_FREE; mbmem[i].m_next = &mbmem[i+1]; } mbmem[NMBUF-1].m_next = NULL; } /* * get one mbuf structure */ struct mbuf * m_get (canwait, type) int canwait, type; { struct mbuf * m; MGET (m, canwait, type); return m; } /* * get a clean mbuf (all zeros). */ struct mbuf * m_getclr (canwait, type) int canwait, type; { register struct mbuf * m; MGET (m, canwait, type); if (m == 0) return 0; bzero (mtod (m, caddr_t), MLEN); return m; } /* * free one mbuf structure. returns the next mbuf in the chain. */ struct mbuf * m_free (m) struct mbuf * m; { struct mbuf * n; MFREE (m, n); return n; } /* * get some more mbuf. * There is no more, so we wait until some comes back. */ struct mbuf * m_more (canwait, type) int canwait, type; { struct mbuf * m; if (canwait == M_WAIT) { m_want++; (void) sleep ((caddr_t) &mfree, PZERO - 1); MGET (m, canwait, type); return m; } else return NULL; } /* * free an mbuf chain. */ void m_freem (m) struct mbuf * m; { struct mbuf * n; int s = splimp (); if (m == NULL) goto done; do { MFREE(m, n); } while (m = n); done: splx (s); } /* * copy an mbuf chain, return 0 on failure. */ struct mbuf * m_copy (m, off, len) struct mbuf * m; int off, len; { struct mbuf * n, ** np; struct mbuf * top; if (len = 0) return NULL; if (off < 0 || len < 0) panic ("m_copy"); while (off > 0) { if (m == 0) panic ("m_copy"); if (off < m->m_len) break; off -= m->m_len; m = m->m_next; } np = ⊤ top = 0; while (len > 0) { if (m == 0) { if (len != M_COPYALL) panic ("m_copy"); break; } MGET (n, M_DONTWAIT, m->m_type); if ((*np = n) == 0) goto nospace; n->m_len = MIN (len, m->m_len - off); bcopy (mtod (m, caddr_t), mtod (n, caddr_t), (unsigned) n->m_len); if (len != M_COPYALL) len -= n->m_len; off = 0; m = m->m_next; np = &n->m_next; } return top; nospace: m_freem (top); return NULL; } @//E*O*F uipc/src/mbuf.c// chmod u=rw,g=r,o=r uipc/src/mbuf.c echo x - uipc/src/number-ptys.h sed 's/^@//' > "uipc/src/number-ptys.h" <<'@//E*O*F uipc/src/number-ptys.h//' /* number-ptys.h - Eric H. Herrin II * * define the number of ptys here so the actual number only has to be in * one place. * * Version 2.1 */ #define NUMBER_OF_PTYS 32 @//E*O*F uipc/src/number-ptys.h// chmod u=rw,g=rw,o=rw uipc/src/number-ptys.h echo x - uipc/src/osel.c sed 's/^@//' > "uipc/src/osel.c" <<'@//E*O*F uipc/src/osel.c//' rds = uap->readfds; wds = uap->writefds; tmout = uap->timeout; cnt = 0; /* initaize out to zero */ if(rds) { /* have readbitmask */ for(i=0;i < uap->nfds; i++) { u.u_error = 0; /* reset it */ mask = 1 << i; if(*rds & mask) { /* is this one? */ fp = getsock(i); if(fp != 0) { /* valid socket */ so = filesock(fp); j = (SS_CANTRCVMORE | SS_CANTSENDMORE); k = SS_ISCONNECTED; /* first check for closed sockets * closed sockets appear only to have j set */ if((so->so_state & j) == j) { /* socket is close. mark as having * data on it, so a read will fail */ cnt++; } /* next we check for a state of incomming ie * accept needs to be called */ else if ( so->so_qlen ) { cnt++; } /* and this is for regular sockets already * connected */ else if( (so->so_rcv.sb_mb != 0) && (so->so_rcv.sb_cc != 0)) { /* has buffer & has chars */ cnt++; } else { *rds &= ~mask; } } @//E*O*F uipc/src/osel.c// chmod u=rw,g=r,o=r uipc/src/osel.c echo x - uipc/src/osyscalls.c sed 's/^@//' > "uipc/src/osyscalls.c" <<'@//E*O*F uipc/src/osyscalls.c//' #ifndef LINT static char * sccsdef = "%W% %D%"; #endif /* * syscalls.c - system call kernal interface routines. * * Written by Alex Crain. * * This file is based in the Berkeley file uipc_syscalls.c, * but is *not* guarenteed to be in any way compatable. It is * close enough to the Berkeley code that the following applies... * * Copyright (c) 1982, 1986, 1988 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and that due credit is given * to the University of California at Berkeley. The name of the University * may not be used to endorse or promote products derived from this * software without specific prior written permission. This software * is provided "as is" without express or implied warranty. * */ #include <sys/types.h> #include <sys/param.h> #include <sys/systm.h> #include <sys/user.h> #include <sys/file.h> #include <sys/buf.h> #include <sys/errno.h> #include <sys/systm.h> #include <sys/tty.h> #include <uipc/mbuf.h> #include <uipc/socket.h> #include <uipc/socketvar.h> #include <uipc/domain.h> #include <uipc/protosw.h> #include <uipc/un.h> #include <uipc/fproto.h> #include <uipc/unpcb.h> #include <uipc/pty.h> struct file * getsock (); /* * socket (domain, type, protocol) * * Create a socket and add it to the processes open file table. This involves * some creativity, because the file structure is really too small for our * uses. The kernal only knows about inodes, so there is no f_type slot. * Instead, the kernal looks for a NULL f_inode, which means that we are a * socket. Unfortunately, this means that there is no room in the file * structure for the socket address, so we keep all of our sockets in a linear * table, and store the table offset in f_offset, which has no meaning here * anyway. (see the macros filesock() and sockoffet() in conf.h). */ int select_sleep; /* value to say if we need to wakeup */ int select_sleep_addr; /* address we select on if wait in select */ /* * this is hard coded righ now....for test only...soon it will be * loaded in at boot time so that it is not hard coded */ int so_win_major = 0; /* major device of window */ unsigned int so_win_tty = 0; /* address of wintty */ sosetup() /* setup variables */ { register struct a { int w_major; unsigned int w_tty; } * uap = (struct a *) u.u_ap; so_win_major = uap->w_major; so_win_tty = uap->w_tty; } soselect () { register struct a { int nfds; int *readfds; int *writefds; int *execptfds; long *timeout; } * uap = (struct a *) u.u_ap; int i,mask, cnt, *rds, *wds; int k,l, j; long *tmout; struct file *fp; struct inode *ip; struct tty *tp; struct socket *so; struct unpcb *unp; rds = uap->readfds; wds = uap->writefds; tmout = uap->timeout; cnt = 0; /* initaize out to zero */ if(rds) { /* have readbitmask */ for(i=0;i < uap->nfds; i++) { u.u_error = 0; /* reset it */ mask = 1 << i; if(*rds & mask) { /* is this one? */ fp = getsock(i); if(fp != 0) { /* valid socket */ so = filesock(fp); j = (SS_CANTRCVMORE | SS_CANTSENDMORE); k = SS_ISCONNECTED; /* first check for closed sockets * closed sockets appear only to have j set */ if((so->so_state & j) == j) { /* socket is close. mark as having * data on it, so a read will fail */ cnt++; } /* next we check for a state of incomming ie * accept needs to be called */ else if ( so->so_qlen ) { cnt++; } /* and this is for regular sockets already * connected */ else if( (so->so_rcv.sb_mb != 0) && (so->so_rcv.sb_cc != 0)) { /* has buffer & has chars */ cnt++; } else { *rds &= ~mask; } } else if((fp = getf(i)) != 0) { /* valid open file */ ip = fp->f_inode; /* are we a pty? */ if(major(ip->i_rdev) == pty_major) { /* got a pty file descriptor */ if(Master(ip->i_rdev) == True) { /* get slot in tty table */ k = minor(ip->i_rdev) - PTYCNT; tp = &pts_tty[k]; /* ok */ /* check buffer address */ if(tp->t_tbuf.c_count) { /* ok to read */ cnt++; }else { *rds &= ~mask; } }else { /* normal slot */ /* not sure this is right */ k = minor(ip->i_rdev); tp = &pts_tty[k]; /* ok */ /* first check if we need to * process any chars on the queue */ if((tp->t_rawq.c_cc > 0) && ( tp->t_canq.c_cc == 0)) canon(tp); /* should fix it */ /* check buffer address */ if(tp->t_canq.c_cc) { /* ok to read */ cnt++; }else { *rds &= ~mask; } } }else if(major(ip->i_rdev) == so_win_major) { /* got a window file descriptor */ /* take off 1 for aligment */ k = minor(ip->i_rdev) - 1; k *= sizeof(struct tty); tp = (struct tty *) (unsigned) (so_win_tty + k); /* check buffer */ k = tp->t_rawq.c_cc; if(k) cnt++; else *rds &= ~mask; } /* here we have named pipes */ else if(ip->i_mode & IFIFO) { /* if i_count == 1 no opens left * we notify select of this */ if (ip->i_count == 1) cnt++; else if (ip->i_fwptr) cnt++; else *rds &= ~mask; } else { *rds &= ~mask; } } else { *rds &= ~mask; } } } } if(wds) { /* have writebitmask */ for(i=0;i < uap->nfds; i++) { u.u_error = 0; /* reset it */ mask = 1 << i; if(*wds & mask) { /* is this one? */ fp = getsock(i); if(fp != 0) { /* valid socket */ so = filesock(fp); unp = sotounpcb(so); /* in debugging usrreq.c it appears that this * fills up with the # of chars that are ready * for the other end of the socket to read * * the problem lies in that the other my not * read but the write might not block, since * we don't know how big the next write will * be we assume that if there are any chars * then that is to much */ if(unp->unp_conn->unp_cc) { /* yup it has chars and we set the * bitmask off in this case */ *wds &= ~mask; } else { /* should be okay to right on */ cnt++; } } else if((fp = getf(i)) != 0) { /* valid open file */ ip = fp->f_inode; if(major(ip->i_rdev) == pty_major) { /* got a pty file descriptor */ if(Master(ip->i_rdev) == True) { /* get slot in tty table */ k = minor(ip->i_rdev) - PTYCNT; tp = &pts_tty[k]; /* ok */ /* check buffer address */ if(tp->t_rawq.c_cc) { /* has chars */ *wds &= ~mask; }else cnt++; }else /* slave */ { /* get slot in tty table */ k = minor(ip->i_rdev); tp = &pts_tty[k]; /* ok */ if(tp->t_outq.c_cc) /* not ok to write */ *wds &= ~mask; else cnt++; } } /* is it stdout or stderr? */ else if(major(ip->i_rdev) == so_win_major) { /* got a window file descriptor */ /* take off 1 for aligment */ k = minor(ip->i_rdev) - 1; k *= sizeof(struct tty); tp = (struct tty *) (unsigned) (so_win_tty + k); /* check buffer */ k = tp->t_outq.c_cc; if(k) { /* has chars and can't write to */ *wds &= ~mask; } else /* okay to write */ cnt++; } else if(ip->i_mode & IFIFO) { /* if i_count == 1 no opens left * we notify select of this */ if (ip->i_count == 1) cnt++; else if (ip->i_fwptr) *rds &= ~mask; /* has data no write */ else cnt++; /* no data ok to write */ } else { /* not sure what type of file so unmark it*/ *wds &= ~mask; } } else { *wds &= ~mask; } } } } if(cnt) { u.u_rval1 = cnt; return; } else if(tmout && (*tmout == 0L)) { /* only polling */ u.u_rval1 = cnt; return; } select_sleep = 1; /* sleep until worked up */ sleep( (caddr_t) &select_sleep_addr, PZERO+1 ); /* we are here so we let the user level know that we are ready */ u.u_rval1 = 0; return; } socket () { register struct a { int domain; int type; int proto; } * uap = (struct a *) u.u_ap; struct socket * so; struct file *fp; if ((fp = falloc ((struct inode *) 0, FREAD| FWRITE)) == NULL) return; if (u.u_error = socreate (uap->domain, &so, uap->type, uap->proto)) goto bad; fp->f_offset = sockoffset (so); return; bad: u.u_ofile[u.u_rval1] = 0; fp->f_count = 0; fp->f_next = ffreelist; ffreelist = fp; } bind () { struct a { int s; caddr_t name; int namelen; } * uap = (struct a *) u.u_ap; struct file * fp; struct mbuf * nam; if ((fp = getsock (uap->s)) == 0) return; if (u.u_error = sockargs (&nam, uap->name, uap->namelen, MT_SONAME)) return; u.u_error = sobind (filesock (fp), nam); m_freem (nam); } listen () { struct a { int s; int backlog; } * uap = (struct a *) u.u_ap; struct file * fp; if ((fp = getsock (uap->s)) == 0) return; u.u_error = solisten (filesock (fp), uap->backlog); } accept () { struct a { int s; caddr_t name; int * anamelen; } * uap = (struct a *) u.u_ap; struct file * fp; struct mbuf * nam; int namelen; int s; struct socket * so; if (uap->name == 0) goto noname; if (u.u_error = copyin ((caddr_t) uap->anamelen, (caddr_t) &namelen, sizeof (namelen))) return; if (useracc ((caddr_t) uap->name, (u_int) namelen, UACC_WRITE) == 0) { u.u_error = EFAULT; return; } noname: if ((fp = getsock (uap->s)) == 0) return; s = splnet (); so = filesock (fp); if ((so->so_options & SO_ACCEPTCONN) == 0) { u.u_error = EINVAL; goto bad; } if ((so->so_state & SS_NBIO) && so->so_qlen == 0) { u.u_error = EWOULDBLOCK; goto bad; } while (so->so_qlen == 0 && so->so_error == 0) { if (so->so_state & SS_CANTRCVMORE) { so->so_error = ECONNABORTED; break; } sleep ((caddr_t) &so->so_timeo, PZERO+1); } if (so->so_error) { u.u_error = so->so_error; so->so_error = 0; goto bad; } if ((fp = falloc ((struct inode *) 0, FREAD| FWRITE)) == 0) goto bad; else { struct socket * so2 = so->so_q; if (soqremque (so2, 1) == 0) panic ("accept"); so = so2; } fp->f_offset = sockoffset (so); nam = m_get (M_WAIT, MT_SONAME); (void) soaccept (so, nam); if (uap->name) { if (namelen > nam->m_len) namelen = nam->m_len; (void) copyout (mtod (nam, caddr_t), (caddr_t) uap->name, (u_int) namelen); (void) copyout ((caddr_t) &namelen, (caddr_t) uap->anamelen, sizeof (*uap->anamelen)); } m_freem (nam); bad: splx (s); return; } connect () { struct a { int s; caddr_t name; int namelen; } * uap = (struct a *) u.u_ap; struct file * fp; struct socket * so; struct mbuf * nam; int s; if ((fp = getsock (uap->s)) == 0) return; so = filesock (fp); if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) { u.u_error = EALREADY; return; } if (u.u_error = sockargs (&nam, uap->name, uap->namelen, MT_SONAME)) return; if (u.u_error = soconnect (so, nam)) goto bad; if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) { u.u_error = EINPROGRESS; m_freem (nam); return; } s = splnet (); if (setjmp (u.u_qsav)) { if (u.u_error == 0) u.u_error = EINTR; goto bad2; } while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) sleep ((caddr_t) &so->so_timeo, PZERO + 1); u.u_error = so->so_error; so->so_error = 0; bad2: splx (s); bad: so->so_state &= ~SS_ISCONNECTING; m_freem (nam); } socketpair () { struct a { int domain; int type; int proto; int * rsv; } * uap = (struct a *) u.u_ap; register struct file * fp1, * fp2; struct socket * so1, * so2; int sv[2]; /* * verify that uap->rsv is in the users address space & writeable. * UACC_READ and UACC_WRITE are defined in <uipc/conf.h>. */ if (useracc ((caddr_t) uap->rsv, sizeof (int) * 2, UACC_WRITE) == 0) { u.u_error = EFAULT; return; } /* * Create some sockets (2). */ if (u.u_error = socreate (uap->domain, &so1, uap->type, uap->proto)) return; if (u.u_error = socreate (uap->domain, &so2, uap->type, uap->proto)) goto free1; /* * assign them to file structures in the open file table. */ if ((fp1 = falloc ((struct inode *) 0, FREAD | FWRITE)) == NULL) goto free2; sv[0] = u.u_rval1; fp1->f_offset = sockoffset (so1); if ((fp2 = falloc ((struct inode *) 0, FREAD | FWRITE)) == NULL) goto free3; sv[1] = u.u_rval1; fp2->f_offset = sockoffset (so2); /* * Connect them together. */ if (u.u_error = soconnect2 (so1, so2)) goto free4; /* * DATAGRAMS need to be connected both ways */ if (uap->type == SOCK_DGRAM) if (u.u_error = soconnect2 (so2, so1)) goto free4; /* * done, return 0 and pass the file descriptors back. */ u.u_rval1 = 0; copyout ((caddr_t) sv, (caddr_t) uap->rsv, 2 * sizeof (int)); return; free4: fp2->f_count = 0; fp2->f_next = ffreelist; ffreelist = fp2; free3: fp1->f_count = 0; fp1->f_next = ffreelist; ffreelist = fp1; free2: (void) soclose (so2); free1: (void) soclose (so1); } sendto () { struct a { int s; caddr_t buf; int len; int flags; caddr_t to; int tolen; } * uap = (struct a *) u.u_ap; struct msghdr msg; msg.msg_name = uap->to; msg.msg_namelen = uap->tolen; msg.msg_accrights = (caddr_t) 0; msg.msg_accrightslen = 0; u.u_base = uap->buf; u.u_count = uap->len; u.u_segflg = 0; sendit (uap->s, &msg, uap->flags); } send () { struct a { int s; caddr_t buf; int len; int flags; } * uap = (struct a *) u.u_ap; struct msghdr msg; msg.msg_name = (caddr_t) 0; msg.msg_namelen = 0; msg.msg_accrights = (caddr_t) 0; msg.msg_accrightslen = 0; u.u_base = uap->buf; u.u_count = uap->len; u.u_segflg = 0; sendit (uap->s, &msg, uap->flags); } void sendit (s, mp, flags) int s; struct msghdr * mp; int flags; { struct file * fp; struct mbuf * to, * rights; if ((fp = getsock (s)) == 0) return; if (u.u_count != 0 && useracc (u.u_base, u.u_count, UACC_READ) == 0) { u.u_error = EFAULT; return; } if (mp->msg_name) { if (u.u_error = sockargs (&to, mp->msg_name, mp->msg_namelen,MT_SONAME)) return; } else to = (struct mbuf *) 0; if (mp->msg_accrights) { if (u.u_error = sockargs (&to, mp->msg_accrights, mp->msg_accrightslen, MT_SONAME)) goto bad; } else rights = (struct mbuf *) 0; u.u_error = sosend (filesock (fp), to, flags, rights); if (rights) m_freem (rights); bad: if (to) m_freem (to); } recvfrom () { struct a { int s; caddr_t buf; int len; int flags; caddr_t from; int * fromlenaddr; } * uap = (struct a *) u.u_ap; struct msghdr msg; msg.msg_name = uap->from; if (u.u_error = copyin ((caddr_t) uap->fromlenaddr, (caddr_t) &msg.msg_namelen, sizeof (msg.msg_namelen))) return; msg.msg_accrights = (caddr_t) 0; msg.msg_accrightslen = 0; u.u_base = uap->buf; u.u_count = uap->len; u.u_segflg = 0; recvit (uap->s, &msg, uap->flags, (caddr_t) uap->fromlenaddr, (caddr_t) 0); } recv () { struct a { int s; caddr_t buf; int len; int flags; } * uap = (struct a *) u.u_ap; struct msghdr msg; msg.msg_name = (caddr_t) 0; msg.msg_namelen = 0; msg.msg_accrights = (caddr_t) 0; msg.msg_accrightslen = 0; u.u_base = uap->buf; u.u_count = uap->len; u.u_segflg = 0; recvit (uap->s, &msg, uap->flags, (caddr_t) 0, (caddr_t) 0); } void recvit (s, mp, flags, namelenp, rightslenp) int s; struct msghdr * mp; int flags; caddr_t namelenp, rightslenp; { struct file * fp; struct mbuf * from, * rights; int len; if ((fp = getsock (s)) == 0) return; if (u.u_count != 0 && useracc (u.u_base, u.u_count, UACC_WRITE) == 0) { u.u_error = EFAULT; return; } u.u_error = soreceive (filesock (fp), &from, flags, &rights); if (mp->msg_name) { len = mp->msg_namelen; if (len <= 0 || from == (struct mbuf *) 0) len = 0; else { if (len > from->m_len) len = from->m_len; (void) copyout ((caddr_t) mtod (from, caddr_t), (caddr_t) mp->msg_name, (unsigned) len); } (void) copyout ((caddr_t) &len, namelenp, sizeof (int)); } if (mp->msg_accrights) { len = mp->msg_accrightslen; if (len <= 0 || rights == (struct mbuf *) 0) len = 0; else { if (len > rights->m_len) len = rights->m_len; (void) copyout ((caddr_t) mtod (rights, caddr_t), (caddr_t) mp->msg_accrights, (unsigned) len); } (void) copyout ((caddr_t) &len, rightslenp, sizeof (int)); } if (rights) m_freem (rights); if (from) m_freem (from); } setsockopt () { struct a { int s; int level; int name; caddr_t val; int valsize; } * uap = (struct a *) u.u_ap; struct file * fp; struct mbuf * m = (struct mbuf *) 0; if ((fp = getsock (uap->s)) == 0) return; if (uap->valsize > MLEN) { u.u_error = EINVAL; return; } if (uap->val) { m = m_get (M_WAIT, MT_SOOPTS); if (m == (struct mbuf *) 0) { u.u_error = ENOBUFS; return; } if (u.u_error = copyin (uap->val, mtod (m, caddr_t), (u_int) uap->valsize)) { (void) m_freem (m); return; } m->m_len = uap->valsize; } u.u_error = sosetopt (filesock (fp), uap->level, uap->name, m); } getsockopt () { struct a { int s; int level; int name; caddr_t val; int * avalsize; } * uap = (struct a *) u.u_ap; struct file * fp; struct mbuf * m = (struct mbuf *) 0; int valsize; if ((fp = getsock (uap->s)) == 0) return; if (uap->val) { if (u.u_error = copyin ((caddr_t) uap->avalsize, (caddr_t) &valsize, sizeof (valsize))) return; } else valsize = 0; if (u.u_error = sogetopt (filesock (fp), uap->level, uap->name, &m)) goto bad; if (uap->val && valsize && m != (struct mbuf *) 0) { if (valsize > m->m_len) valsize = m->m_len; if (u.u_error = copyout (mtod (m, caddr_t), uap->val, (u_int) valsize)) goto bad; u.u_error = copyout ((caddr_t) &valsize, (caddr_t) uap->avalsize, sizeof (valsize)); } bad: if (m != (struct mbuf *) 0) (void) m_freem (m); } sockpipe () { register struct file * fpr, * fpw; struct socket * sor, * sow; int r; /* * Create some sockets (2). */ if (u.u_error = socreate (AF_UNIX, &sor, SOCK_STREAM, 0)) return; if (u.u_error = socreate (AF_UNIX, &sow, SOCK_STREAM, 0)) goto free1; /* * assign them to file structures in the open file table. */ if ((fpr = falloc ((struct inode *) 0, FREAD | FWRITE)) == NULL) goto free2; fpr->f_offset = sockoffset (sor); r = u.u_rval1; if ((fpw = falloc ((struct inode *) 0, FREAD | FWRITE)) == NULL) goto free3; fpw->f_offset = sockoffset (sow); u.u_rval2 = u.u_rval1; u.u_rval1 = r; /* * Connect them together. */ if (u.u_error = unp_connect2 (sow, sor)) goto free4; /* * Close one direction. */ sor->so_state |= SS_CANTSENDMORE; sow->so_state |= SS_CANTRCVMORE; return; free4: fpw->f_count = 0; fpw->f_next = ffreelist; ffreelist = fpw; free3: fpr->f_count = 0; fpr->f_next = ffreelist; ffreelist = fpr; free2: (void) soclose (sow); free1: (void) soclose (sor); } void getsockname () { struct a { int fdes; caddr_t asa; int * alen; } * uap = (struct a *) u.u_ap; struct file * fp; struct socket * so; struct mbuf * m; int len; if ((fp = getsock (uap->fdes)) == 0) return; if (u.u_error = copyin ((caddr_t) uap->alen, (caddr_t) &len, sizeof (len))) return; so = filesock (fp); if ((m = m_getclr (M_WAIT, MT_SONAME)) == (struct mbuf *) 0) { u.u_error = ENOBUFS; return; } if (u.u_error = (* so->so_proto->pr_usrreq) (so, PRU_SOCKADDR, (struct mbuf *) 0, m, (struct mbuf *) 0)) goto bad; if (len > m->m_len) len = m->m_len; if (u.u_error = copyout (mtod (m, caddr_t), (caddr_t) uap->asa, (u_int) len)) goto bad; u.u_error = copyout ((caddr_t) &len, (caddr_t) uap->alen, sizeof (len)); bad: m_freem (m); } /* * System call helper functions */ int sockargs (aname, name, namelen, type) struct mbuf ** aname; caddr_t name; int namelen, type; { struct mbuf * m; int error; if (namelen > MLEN) return EINVAL; if ((m = m_get (M_WAIT, type)) == NULL) return ENOBUFS; m->m_len = namelen; if (error = copyin (name, mtod (m, caddr_t), (u_int) namelen)) (void) m_free (m); else * aname = m; return error; } /* given a file descriptor see if it is a socket file descriptor */ struct file * getsock (fd) int fd; { struct file * fp; /* given an fd, see if it is a valid fd, ie in file table*/ if ((fp = getf (fd)) == NULL) return 0; if (fp->f_inode) { u.u_error = ENOTSOCK; return 0; } return fp; } @//E*O*F uipc/src/osyscalls.c// chmod u=rw,g=r,o=r uipc/src/osyscalls.c echo x - uipc/src/proto.c sed 's/^@//' > "uipc/src/proto.c" <<'@//E*O*F uipc/src/proto.c//' /* * proto.c - protocol spec for the UNIX domain. * * Written by Alex Crain. * * This file is loosly based in the Berkeley file uipc_proto.c, * but is *not* guarenteed to be in any way compatable. It is * close enough to the Berkeley code that the following applies... * * Copyright (c) 1982, 1986, 1988 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and that due credit is given * to the University of California at Berkeley. The name of the University * may not be used to endorse or promote products derived from this * software without specific prior written permission. This software * is provided "as is" without express or implied warranty. * */ #include <sys/types.h> #include <sys/param.h> #include <sys/systm.h> #include <uipc/mbuf.h> #include <uipc/socket.h> #include <uipc/socketvar.h> #include <uipc/protosw.h> #include <uipc/domain.h> #include <uipc/fproto.h> /* * UNIX domain protocols */ int uipc_usrreq (); int raw_init (), raw_usrreq (), raw_input (), raw_ctlinput (); extern struct domain unixdomain; struct protosw unixsw[] = { { SOCK_STREAM, &unixdomain, 0, PR_CONNREQUIRED | PR_WANTRCVD | PR_RIGHTS, 0, 0, 0, 0, uipc_usrreq, 0, 0, 0, 0, }, { SOCK_DGRAM, &unixdomain, 0, PR_ATOMIC | PR_ADDR | PR_RIGHTS, 0, 0, 0, 0, uipc_usrreq, 0, 0, 0, 0, }, #ifdef SOCK_RAW { 0, 0, 0, 0, raw_input, 0, raw_ctlinput, 0, raw_usrreq, raw_init, 0, 0, 0, }, #endif }; struct domain unixdomain = { AF_UNIX, "unix", 0, unp_externalize, (int (*)()) unp_dispose, unixsw, &unixsw[sizeof (unixsw) / sizeof (unixsw[0])] }; @//E*O*F uipc/src/proto.c// chmod u=rw,g=r,o=r uipc/src/proto.c echo x - uipc/src/pty.c sed 's/^@//' > "uipc/src/pty.c" <<'@//E*O*F uipc/src/pty.c//' /* * pty.c - Berkeley style pseudo tty driver for system V * * Copyright (c) 1987, Jens-Uwe Mager, FOCUS Computer GmbH * Not derived from licensed software. * * Permission is granted to freely use, copy, modify, and redistribute * this software, provided that no attempt is made to gain profit from it, * the author is not construed to be liable for any results of using the * software, alterations are clearly marked as such, and this notice is * not modified. */ /* * Modified for use on the UnixPC by: * Eric H. Herrin II * University of Kentucky Mathematical Sciences Laboratories * eric@ms.uky.edu, eric@ms.uky.csnet, !cbosgd!ukma!eric * * See README.3b1 for details of port and installation. * Version 2.1 */ #include "pty.h" #include "sys/param.h" #include "sys/types.h" #include "sys/sysmacros.h" #include "sys/systm.h" #include "sys/file.h" #include "sys/conf.h" #include "sys/proc.h" #include "sys/dir.h" #include "sys/tty.h" #include "sys/signal.h" #include "sys/user.h" #include "sys/errno.h" #include "sys/termio.h" #include "sys/ttold.h" #ifdef SELECT struct proc *pty_proc[PTYCNT]; /* selecting process for each master */ #endif /* The tty structures must be local to this driver. One doesn't have * conf.c */ struct tty pts_tty[PTYCNT]; int pts_cnt = PTYCNT; int ptystate[PTYCNT]; ptyopen(dev, flag) register dev_t dev; register int flag; { register struct tty *tp; dev = minor(dev); if (Master(dev) == True) { # ifdef DEBUG eprintf("open(master): \n"); # endif dev -= PTYCNT; tp = &pts_tty[dev]; if (dev >= pts_cnt) { u.u_error = ENXIO; return; } /* * allow only one controlling process */ if (ptystate[dev] & MOPEN) { u.u_error = EBUSY; return; } pty_proc[dev] = (struct proc *) -1L; if (tp->t_state & WOPEN) wakeup((caddr_t)&tp->t_canq); tp->t_state |= CARR_ON; ptystate[dev] |= MOPEN; #ifdef SELECT ptystate[dev] &= ~(SCLOSED); #endif } else { # ifdef DEBUG eprintf("open(slave): \n"); # endif tp = &pts_tty[dev]; if (dev >= pts_cnt) { u.u_error = ENXIO; return; } if ((tp->t_state & (ISOPEN|WOPEN)) == 0) { ttinit(tp); tp->t_proc = ptsproc; } /* * if master is still open, don't wait for carrier */ if (ptystate[dev] & MOPEN) tp->t_state |= CARR_ON; if (!(flag & FNDELAY)) { while ((tp->t_state & CARR_ON) == 0) { tp->t_state |= WOPEN; sleep((caddr_t)&tp->t_canq, TTIPRI); } } (*linesw[tp->t_line].l_open)(tp); } } ptyclose(dev, flag) register dev_t dev; register int flag; { register struct tty *tp; dev = minor(dev); if (Master(dev) == True) { # ifdef DEBUG eprintf("close(master): \n"); # endif dev -= PTYCNT; tp = &pts_tty[dev]; if (tp->t_state & ISOPEN) { signal(tp->t_pgrp, SIGHUP); ttyflush(tp, FREAD|FWRITE); } else { /* must get rid of buffered output */ while (tp->t_tbuf.c_count) { # ifdef DEBUG eprintf("c_count = %d\n", tp->t_tbuf.c_count); # endif ptsproc(tp, T_WFLUSH); /* side effects? */ } } /* * virtual carrier gone */ tp->t_state &= ~(CARR_ON); ptystate[dev] &= ~MOPEN; } else { # ifdef DEBUG eprintf("close(slave): \n"); # endif tp = &pts_tty[dev]; (*linesw[tp->t_line].l_close)(tp); tp->t_state &= ~CARR_ON; # ifdef SELECT ptystate[dev] |= SCLOSED; { int indx = tp - pts_tty; /* * We just closed the slave device. The master won't block * on a read. Now Wake up any processes which might be * selecting so it can poll again. */ if (indx >= 0 && indx < PTYCNT && pty_proc[indx] != (struct proc *) -1L) { selwakeup(pty_proc[indx]); pty_proc[indx] = (struct proc *) -1L; } } # endif } } ptyread(dev) register dev_t dev; { register struct tty *tp; register n; dev = minor(dev); if (Master(dev) == True) { # ifdef DEBUG eprintf("read(master): \n"); # endif dev -= PTYCNT; tp = &pts_tty[dev]; /* added fix for hanging master side when the slave hangs * up too early. Fix by Michael Bloom (mb@ttidca.tti.com). */ /* if ((tp->t_state & (ISOPEN|TTIOW)) == 0) { */ if (ptystate[dev] & SCLOSED) { u.u_error = EIO; return; } while (u.u_count > 0) { ptsproc(tp, T_OUTPUT); if ((tp->t_state & (TTSTOP|TIMEOUT)) || tp->t_tbuf.c_ptr == NULL || tp->t_tbuf.c_count == 0) { if (u.u_fmode & FNDELAY) break; # ifdef DEBUG eprintf("read(master): master going to sleep\n"); # endif ptystate[dev] |= MRWAIT; sleep((caddr_t)&tp->t_rloc, TTIPRI); # ifdef DEBUG eprintf("read(master): master woke up\n"); # endif continue; } n = min(u.u_count, tp->t_tbuf.c_count); if (n) { # ifdef DEBUG eprintf("read(master): got some stuff\n"); # endif if (copyout(tp->t_tbuf.c_ptr, u.u_base, n)) { u.u_error = EFAULT; break; } tp->t_tbuf.c_count -= n; tp->t_tbuf.c_ptr += n; u.u_base += n; u.u_count -= n; } } } else { # ifdef DEBUG eprintf("read(slave): \n"); # endif tp = &pts_tty[dev]; # ifdef DEBUG eprintf("read(slave): got some stuff\n"); # endif (*linesw[tp->t_line].l_read)(tp); } } ptywrite(dev) register dev_t dev; { register struct tty *tp; register n; dev = minor(dev); if (Master(dev) == True) { # ifdef DEBUG eprintf("write(master): \n"); # endif dev -= PTYCNT; tp = &pts_tty[dev]; if ((tp->t_state & ISOPEN) == 0) { u.u_error = EIO; return; } while (u.u_count > 0) { if ((tp->t_state & TBLOCK) || tp->t_rbuf.c_ptr == NULL) { if (u.u_fmode & FNDELAY) break; ptystate[dev] |= MWWAIT; # ifdef DEBUG eprintf("write(master): going to sleep\n"); # endif sleep((caddr_t)&tp->t_wloc, TTOPRI); # ifdef DEBUG eprintf("write: waking up\n"); # endif continue; } n = min(u.u_count, tp->t_rbuf.c_count); if (n) { # ifdef DEBUG eprintf("write(master): sending some stuff\n"); # endif if (copyin(u.u_base,tp->t_rbuf.c_ptr, n)) { u.u_error = EFAULT; break; } if (tp->t_iflag & IXON) { /* check for flow control */ register char c; register int i; for (i = 0; i < n; i++) { c = tp->t_rbuf.c_ptr[i]; if (tp->t_state & TTSTOP) { if ((c == CSTART) || (tp->t_iflag & IXANY) ) { (*tp->t_proc)(tp, T_RESUME); } } else { if (c==CSTOP) { (*tp->t_proc)(tp, T_SUSPEND); } } if (c==CSTART || c==CSTOP) { /* through away this char and proc remaining on next while loop*/ n = i; u.u_count -= 1; if (u.u_count == 0) { return; } break; /* exit for loop */ } } } tp->t_rbuf.c_count -= n; u.u_base += n; u.u_count -= n; } (*linesw[tp->t_line].l_input)(tp); } } else { # ifdef DEBUG eprintf("write(slave): \n"); # endif tp = &pts_tty[dev]; # ifdef DEBUG eprintf("write(slave): sending some stuff\n"); # endif (*linesw[tp->t_line].l_write)(tp); } } ptyioctl(dev, cmd, arg, mode) dev_t dev; int cmd, arg, mode; { register struct tty *tp; dev = minor(dev); if (Master(dev) == True) { # ifdef DEBUG eprintf("ioctl(master): \n"); # endif dev -= PTYCNT; tp = &pts_tty[dev]; /* * sorry, but we can't fiddle with the tty struct without * having done LDOPEN */ if (tp->t_state & ISOPEN) { if (cmd == TCSBRK && arg == NULL) { signal(tp->t_pgrp, SIGINT); if ((tp->t_iflag & NOFLSH) == 0) ttyflush(tp, FREAD|FWRITE); } else { /* * we must flush output to avoid hang in ttywait */ if (cmd == TCSETAW || cmd == TCSETAF || cmd == TCSBRK || cmd == TIOCSETP) ttyflush(tp, FWRITE); ttiocom(tp, cmd, arg, mode); } } } else { # ifdef DEBUG eprintf("ioctl(slave): \n"); # endif tp = &pts_tty[dev]; ttiocom(tp, cmd, arg, mode); } } ptsproc(tp, cmd) register struct tty *tp; { register struct ccblock *tbuf; extern ttrstrt(); switch (cmd) { case T_TIME: # ifdef DEBUG eprintf("ptsproc: T_TIME:\n"); # endif tp->t_state &= ~TIMEOUT; goto start; case T_WFLUSH: # ifdef DEBUG eprintf("ptsproc: T_WFLUSH:\n"); # endif tp->t_tbuf.c_size -= tp->t_tbuf.c_count; tp->t_tbuf.c_count = 0; /* fall through */ case T_RESUME: # ifdef DEBUG eprintf("ptsproc: T_RESUME:\n"); # endif tp->t_state &= ~TTSTOP; /* fall through */ case T_OUTPUT: start: # ifdef DEBUG eprintf("ptsproc: T_OUTPUT:\n"); # endif if (tp->t_state & (TTSTOP|TIMEOUT)) break; # ifdef DEBUG eprintf("ptsproc: T_OUTPUT: past(TTSTOP|TIMEOUT)"); # endif tbuf = &tp->t_tbuf; if (tbuf->c_ptr == NULL || tbuf->c_count == 0) { # ifdef DEBUG eprintf("ptsproc: T_OUTPUT: tbuf empty, may break\n"); # endif if (tbuf->c_ptr) tbuf->c_ptr -= tbuf->c_size; if (!(CPRES & (*linesw[tp->t_line].l_output)(tp))) break; } # ifdef SELECT { int indx = tp - pts_tty; /* * We just got some stuff that the master device might want * to read. Now Wake up any processes which might be * selecting so it can poll again. */ if (indx >= 0 && indx < PTYCNT && pty_proc[indx] != (struct proc *) -1L) { selwakeup(pty_proc[indx]); pty_proc[indx] = (struct proc *) -1L; } } # endif if (tbuf->c_count && (ptystate[tp-pts_tty] & MRWAIT)) { # ifdef DEBUG eprintf("ptsproc: T_OUTPUT: waking up master\n"); # endif ptystate[tp-pts_tty] &= ~MRWAIT; wakeup((caddr_t)&tp->t_rloc); } # ifdef DEBUG eprintf("ptsproc: T_OUTPUT: leaving end\n"); # endif break; case T_SUSPEND: # ifdef DEBUG eprintf("ptsproc: T_SUSPEND:\n"); # endif tp->t_state |= TTSTOP; break; case T_BLOCK: # ifdef DEBUG eprintf("ptsproc: T_BLOCK:\n"); # endif /* * the check for ICANON appears to be neccessary * to avoid a hang when overflowing input */ if ((tp->t_iflag & ICANON) == 0) tp->t_state |= TBLOCK; break; case T_BREAK: # ifdef DEBUG eprintf("ptsproc: T_BREAK:\n"); # endif tp->t_state |= TIMEOUT; timeout(ttrstrt, tp, HZ/4); break; #ifdef T_LOG_FLUSH case T_LOG_FLUSH: #endif case T_RFLUSH: # ifdef DEBUG eprintf("ptsproc: T_RFLUSH:\n"); # endif if (!(tp->t_state & TBLOCK)) break; /* fall through */ case T_UNBLOCK: # ifdef DEBUG eprintf("ptsproc: T_UNBLOCK:\n"); # endif tp->t_state &= ~(TTXOFF|TBLOCK); /* fall through */ case T_INPUT: # ifdef DEBUG eprintf("ptsproc: T_INPUT:\n"); # endif if (ptystate[tp-pts_tty] & MWWAIT) { ptystate[tp-pts_tty] &= ~MWWAIT; # ifdef DEBUG eprintf("ptsproc: T_INPUT: waking up master\n"); # endif wakeup((caddr_t)&tp->t_wloc); } break; default: # ifdef DEBUG eprintf("ptsproc: default:\n"); # else ; # endif } } /* This routine used to be a stub, however, an industrious soul found * the release routine caused a panic whenever the driver is released * and some ptys are still open. The simple 'for' loop fixes this * problem. * * Credit should be given to: * Mike "Ford" Ditto * kenobi!ford@crash.CTS.COM, ...!crash!kenobi!ford * for finding the bug and writing the for loop. * * [Eric H. Herrin II, 10-7-87] */ ptyrelease() { register int i; # ifdef DEBUG eprintf("ptyrelease:\n"); # endif for (i=0; i<PTYCNT; i++) if ((ptystate[i] & (ISOPEN|MOPEN)) || (pts_tty[i].t_state & WOPEN)) { u.u_error = EBUSY; return; } # ifdef SELECT serelease(); # endif return; } @//E*O*F uipc/src/pty.c// chmod u=rw,g=rw,o=rw uipc/src/pty.c echo x - uipc/src/pty.h sed 's/^@//' > "uipc/src/pty.h" <<'@//E*O*F uipc/src/pty.h//' /* pty.h - Eric H. Herrin II (eric@ms.uky.edu) * * some elementary definitions for the pty driver (UnixPC version) * * Version 2.1 */ /* * the following are arbitrary 3 unused bits from t_state * in sys/tty.h */ /* The UnixPC does not have any extra bits in t_state, thus * one must provide other means of storing the state. */ #define MRWAIT 01 /* master waiting in read */ #define t_rloc t_cc[0] /* wchannel */ #define MWWAIT 02 /* master waiting in write */ #define t_wloc t_cc[1] /* wchannel */ #define MOPEN 04 /* master is open */ #ifdef SELECT #define SCLOSED 010 /* slave was opened and closed */ /* cleared in master open, set in slave close */ #endif int ptsproc(); extern struct tty pts_tty[]; #define True (1 == 1) #define False (0 == 1) /* This is the total number of ptys. Note the maximum number here is * currently 64 for the UnixPC (128 minor devices/2 minor devices per pty * yields 64 total ptys). I really don't see the need for more than 32 * on the 3B1, however, if someone does, then (s)he can change it. */ #include "number-ptys.h" #define PTYCNT (dev_t)NUMBER_OF_PTYS /* some definitions to include kernel info from system header files. */ #define KERNEL 1 #define defined_io 1 /* #define NOSTREAMS 1 Seems that this was not defined in 3.51 */ #define UNIXPC 1 /* This macro returns True if the parameter is a master minor device number, * False otherwise. */ #define Master( dev ) (minor(dev) >= PTYCNT) /* Index in ldmisc to use for pointer to se_register * se_register(poll_routine, maj_dev) is how other drivers tell us the * address of their select polling routine. */ #define SEL_REGISTER (LDMISCSLOTS - 1) /* This is the maximum major device number which can be used above */ #define NUM_SEL_DRIVERS 32 @//E*O*F uipc/src/pty.h// chmod u=rw,g=rw,o=rw uipc/src/pty.h exit 0 -- David H. Brierley Home: dave@galaxia.newport.ri.us; Work: dhb@quahog.ssd.ray.com Send comp.sources.3b1 submissions to comp-sources-3b1@galaxia.newport.ri.us %% Can I be excused, my brain is full. **