v01i009: Latest version of uipc code, Part02/05
Bradley E. Smith
brad at bradley.bradley.edu
Wed Feb 20 12:29:01 AEST 1991
Submitted-by: brad at 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 at ms.uky.edu, eric at 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 at 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 at 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 at 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 at galaxia.newport.ri.us; Work: dhb at quahog.ssd.ray.com
Send comp.sources.3b1 submissions to comp-sources-3b1 at galaxia.newport.ri.us
%% Can I be excused, my brain is full. **
More information about the Comp.sources.3b1
mailing list