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