BSD 3 development
authorBill Joy <wnj@ucbvax.Berkeley.EDU>
Sat, 5 Jan 1980 13:51:23 +0000 (05:51 -0800)
committerBill Joy <wnj@ucbvax.Berkeley.EDU>
Sat, 5 Jan 1980 13:51:23 +0000 (05:51 -0800)
Work on file usr/src/sys/h/acct.h
Work on file usr/src/sys/h/buf.h
Work on file usr/src/sys/sys/Locore.c
Work on file usr/src/sys/sys/acct.c
Work on file usr/src/sys/sys/alloc.c
Work on file usr/src/sys/sys/clock.c
Work on file usr/src/sys/sys/conf.c
Work on file usr/src/sys/sys/cons.c
Work on file usr/src/sys/sys/dkleave.c
Work on file usr/src/sys/sys/dsort.c
Work on file usr/src/sys/sys/fio.c
Work on file usr/src/sys/sys/flp.c
Work on file usr/src/sys/sys/ht.c
Work on file usr/src/sys/sys/iget.c
Work on file usr/src/sys/sys/kl.c
Work on file usr/src/sys/sys/main.c
Work on file usr/src/sys/sys/malloc.c
Work on file usr/src/sys/sys/mba.c
Work on file usr/src/sys/sys/mx1.c
Work on file usr/src/sys/sys/mx2.c
Work on file usr/src/sys/sys/nami.c
Work on file usr/src/sys/sys/partab.c
Work on file usr/src/sys/sys/pipe.c
Work on file usr/src/sys/sys/prf.c
Work on file usr/src/sys/sys/prim.c
Work on file usr/src/sys/sys/rdwri.c

Synthesized-from: 3bsd

26 files changed:
usr/src/sys/h/acct.h [new file with mode: 0644]
usr/src/sys/h/buf.h [new file with mode: 0644]
usr/src/sys/sys/Locore.c [new file with mode: 0644]
usr/src/sys/sys/acct.c [new file with mode: 0644]
usr/src/sys/sys/alloc.c [new file with mode: 0644]
usr/src/sys/sys/clock.c [new file with mode: 0644]
usr/src/sys/sys/conf.c [new file with mode: 0644]
usr/src/sys/sys/cons.c [new file with mode: 0644]
usr/src/sys/sys/dkleave.c [new file with mode: 0644]
usr/src/sys/sys/dsort.c [new file with mode: 0644]
usr/src/sys/sys/fio.c [new file with mode: 0644]
usr/src/sys/sys/flp.c [new file with mode: 0644]
usr/src/sys/sys/ht.c [new file with mode: 0644]
usr/src/sys/sys/iget.c [new file with mode: 0644]
usr/src/sys/sys/kl.c [new file with mode: 0644]
usr/src/sys/sys/main.c [new file with mode: 0644]
usr/src/sys/sys/malloc.c [new file with mode: 0644]
usr/src/sys/sys/mba.c [new file with mode: 0644]
usr/src/sys/sys/mx1.c [new file with mode: 0644]
usr/src/sys/sys/mx2.c [new file with mode: 0644]
usr/src/sys/sys/nami.c [new file with mode: 0644]
usr/src/sys/sys/partab.c [new file with mode: 0644]
usr/src/sys/sys/pipe.c [new file with mode: 0644]
usr/src/sys/sys/prf.c [new file with mode: 0644]
usr/src/sys/sys/prim.c [new file with mode: 0644]
usr/src/sys/sys/rdwri.c [new file with mode: 0644]

diff --git a/usr/src/sys/h/acct.h b/usr/src/sys/h/acct.h
new file mode 100644 (file)
index 0000000..db5d500
--- /dev/null
@@ -0,0 +1,27 @@
+/*     acct.h  2.1     1/5/80 */
+
+/*
+ * Accounting structures
+ */
+
+typedef        unsigned short comp_t;  /* "floating pt": 3 bits base 8 exp, 13 bits fraction */
+struct acct
+{
+       char    ac_comm[10];            /* Accounting command name */
+       comp_t  ac_utime;               /* Accounting user time */
+       comp_t  ac_stime;               /* Accounting system time */
+       comp_t  ac_etime;               /* Accounting elapsed time */
+       time_t  ac_btime;               /* Beginning time */
+       short   ac_uid;                 /* Accounting user ID */
+       short   ac_gid;                 /* Accounting group ID */
+       short   ac_mem;                 /* average memory usage */
+       comp_t  ac_io;                  /* number of disk IO blocks */
+       dev_t   ac_tty;                 /* control typewriter */
+       char    ac_flag;                /* Accounting flag */
+};
+
+extern struct  acct    acctbuf;
+extern struct  inode   *acctp;         /* inode of accounting file */
+
+#define        AFORK   01              /* has executed fork, but no exec */
+#define        ASU     02              /* used super-user privileges */
diff --git a/usr/src/sys/h/buf.h b/usr/src/sys/h/buf.h
new file mode 100644 (file)
index 0000000..7361cf3
--- /dev/null
@@ -0,0 +1,93 @@
+/*     buf.h   2.1     1/5/80  */
+
+/*
+ * Each buffer in the pool is usually doubly linked into 2 lists:
+ * the device with which it is currently associated (always)
+ * and also on a list of blocks available for allocation
+ * for other use (usually).
+ * The latter list is kept in last-used order, and the two
+ * lists are doubly linked to make it easy to remove
+ * a buffer from one list when it was found by
+ * looking through the other.
+ * A buffer is on the available list, and is liable
+ * to be reassigned to another disk block, if and only
+ * if it is not marked BUSY.  When a buffer is busy, the
+ * available-list pointers can be used for other purposes.
+ * Most drivers use the forward ptr as a link in their I/O
+ * active queue.
+ * A buffer header contains all the information required
+ * to perform I/O.
+ * Most of the routines which manipulate these things
+ * are in bio.c.
+ */
+struct buf
+{
+       int     b_flags;                /* see defines below */
+       struct  buf *b_forw;            /* headed by d_tab of conf.c */
+       struct  buf *b_back;            /*  "  */
+       struct  buf *av_forw;           /* position on free list, */
+       struct  buf *av_back;           /*     if not BUSY*/
+       dev_t   b_dev;                  /* major+minor device name */
+       unsigned b_bcount;              /* transfer count */
+       union {
+           caddr_t b_addr;             /* low order core address */
+           int *b_words;               /* words for clearing */
+           struct filsys *b_filsys;    /* superblocks */
+           struct dinode *b_dino;      /* ilist */
+           daddr_t *b_daddr;           /* indirect block */
+       } b_un;
+       daddr_t b_blkno;                /* block # on device */
+       char    b_xmem;                 /* high order core address */
+       char    b_error;                /* returned after I/O */
+       unsigned int b_resid;           /* words not transferred after error */
+       struct  proc  *b_proc;          /* process doing physical or swap I/O */
+};
+
+#ifdef KERNEL
+extern struct buf buf[];               /* The buffer pool itself */
+extern struct buf swbuf[];             /* swap I/O headers */
+extern struct buf bfreelist;           /* head of available list */
+extern struct buf bswlist;             /* head of free swap header list */
+extern struct buf *bclnlist;           /* head of cleaned page list */
+
+struct buf *alloc();
+struct buf *baddr();
+struct buf *getblk();
+struct buf *geteblk();
+struct buf *bread();
+struct buf *breada();
+
+unsigned minphys();
+#endif
+
+#define        NSWBUF  32                      /* number of swap I/O headers */
+
+/*
+ * These flags are kept in b_flags.
+ */
+#define        B_WRITE  0x0000 /* non-read pseudo-flag */
+#define        B_READ   0x0001 /* read when I/O occurs */
+#define        B_DONE   0x0002 /* transaction finished */
+#define        B_ERROR  0x0004 /* transaction aborted */
+#define        B_BUSY   0x0008 /* not on av_forw/back list */
+#define        B_PHYS   0x0010 /* Physical IO potentially using UNIBUS map */
+#define        B_MAP    0x0020 /* This block has the UNIBUS map allocated */
+#define        B_WANTED 0x0040 /* issue wakeup when BUSY goes off */
+#define        B_AGE    0x0080 /* delayed write for correct aging */
+#define        B_ASYNC  0x0100 /* don't wait for I/O completion */
+#define        B_DELWRI 0x0200 /* don't write till block leaves available list */
+#define        B_TAPE   0x0400 /* this is a magtape (no bdwrite) */
+#define        B_UAREA  0x0800 /* add u-area to a swap operation */
+#define        B_PAGET  0x1000 /* page in/out of page table space */
+#define        B_DIRTY  0x2000 /* dirty page to be pushed out async */
+#define        B_PGIN   0x4000 /* page in flag to swap(), for counting */
+
+/*
+ * special redeclarations for
+ * the head of the queue per
+ * device driver.
+ */
+#define        b_actf          av_forw
+#define        b_actl          av_back
+#define        b_active        b_bcount
+#define        b_errcnt        b_resid
diff --git a/usr/src/sys/sys/Locore.c b/usr/src/sys/sys/Locore.c
new file mode 100644 (file)
index 0000000..cd5d2fb
--- /dev/null
@@ -0,0 +1,293 @@
+/*     Locore.c        2.1     1/5/80  */
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/pte.h"
+#include "../h/vm.h"
+#include "../h/tty.h"
+#include "../h/cmap.h"
+
+/*
+ * Pseudo file for lint to show what is used/defined in locore.s.
+ */
+
+int    printsw;
+int    coresw;
+struct cmap *cmap;
+struct cmap *ecmap;
+
+lowinit()
+{
+       extern  int (*UNIvec[BSIZE/NBPW])();
+
+       /*
+        * Pseudo-uses of globals.
+        */
+       lowinit();
+       intstack[0] = intstack[1];
+       Umap[0] = Umap[1];
+       Sysmap[0] = Sysmap[1];
+       maxmem = physmem = freemem = 0;
+       /* should reference _u */
+       main(0);
+
+       /*
+        * Routines called from interrupt vectors.
+        */
+       dump();
+       hpintr(0, 0);
+       htintr(0, 0);
+       (*UNIvec[0])();
+       printf("error!");
+       cnrint(0);
+       cnxint(0);
+       clock((caddr_t)0, 0);
+       if (runrun)
+               ;
+       trap((caddr_t)0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0, 0, 15, 0);
+}
+
+int    waitloc;
+int    ewaitloc;
+
+dzdma()
+{
+
+       dzxint((struct tty *)0);
+}
+
+/*ARGSUSED*/
+addupc(pc, prof, n)
+       caddr_t pc;
+       struct uprof *prof;
+{
+
+}
+
+/*ARGSUSED*/
+fubyte(base)
+       caddr_t base;
+{
+
+       return (0);
+}
+
+/*ARGSUSED*/
+fuibyte(base)
+       caddr_t base;
+{
+
+       return (0);
+}
+
+/*ARGSUSED*/
+subyte(base, i)
+       caddr_t base;
+{
+
+       return (0);
+}
+
+/*ARGSUSED*/
+suibyte(base, i)
+       caddr_t base;
+{
+
+       return (0);
+}
+
+/*ARGSUSED*/
+fuword(base)
+       caddr_t base;
+{
+
+       return (0);
+}
+
+/*ARGSUSED*/
+fuiword(base)
+       caddr_t base;
+{
+
+       return (0);
+}
+
+/*ARGSUSED*/
+suword(base, i)
+       caddr_t base;
+{
+
+       return (0);
+}
+
+/*ARGSUSED*/
+suiword(base, i)
+       caddr_t base;
+{
+
+       return (0);
+}
+
+/*ARGSUSED*/
+copyin(uaddr, kaddr, n)
+       caddr_t uaddr, kaddr;
+       unsigned n;
+{
+
+       return (0);
+}
+
+/*ARGSUSED*/
+copyout(kaddr, uaddr, n)
+       caddr_t kaddr, uaddr;
+       unsigned n;
+{
+
+       return (0);
+}
+
+idle()
+{
+
+}
+
+/*ARGSUSED*/
+save(svb)
+       label_t svb;
+{
+
+       return (0);
+}
+
+/*ARGSUSED*/
+resume(uaddr, svb)
+       short uaddr[UPAGES];
+       label_t svb;
+{
+
+       /*NOTREACHED*/
+}
+
+spl1()
+{
+
+       return (0);
+}
+
+spl4()
+{
+
+       return (0);
+}
+
+spl5()
+{
+
+       return (0);
+}
+
+spl6()
+{
+
+       return (0);
+}
+
+spl7()
+{
+
+       return (0);
+}
+
+spl0()
+{
+
+       return (0);
+}
+
+/*ARGSUSED*/
+splx(s)
+{
+
+}
+
+/*ARGSUSED*/
+copyseg(uaddr, pf)
+       caddr_t uaddr;
+       unsigned pf;
+{
+
+}
+
+/*ARGSUSED*/
+clearseg(pf)
+       unsigned pf;
+{
+
+}
+
+/*ARGSUSED*/
+useracc(uaddr, bcnt, rw)
+       caddr_t uaddr;
+       unsigned bcnt;
+{
+
+       return (0);
+}
+
+/*ARGSUSED*/
+kernacc(addr, bcnt, rw)
+       caddr_t addr;
+       unsigned bcnt;
+{
+
+       return (0);
+}
+
+/*ARGSUSED*/
+udiv(i, j)
+       int i, j;
+{
+
+       return (0);
+}
+
+#ifdef UNNEEDED
+/*ARGSUSED*/
+urem(i, j)
+       unsigned i, j;
+{
+
+       return (0);
+}
+#endif
+
+struct user u;
+struct user swaputl;
+struct user forkutl;
+struct user xswaputl;
+struct user xswap2utl;
+struct user pushutl;
+struct user vfutl;
+struct user pushutl;
+
+struct pte usrpt[USRPTSIZE*NPTEPG];
+
+struct pte Sysmap[4*NPTEPG];
+struct pte Umap[UPAGES];
+struct pte Swapmap[UPAGES];
+struct pte Forkmap[UPAGES];
+struct pte Xswapmap[UPAGES];
+struct pte Xswap2map[UPAGES];
+struct pte Pushmap[UPAGES];
+struct pte Vfmap[UPAGES];
+
+struct pte mmap[1];
+struct pte mcrmap[1];
+char   vmmap[NBPG];
+int    mcr[3];
+
+struct pte Usrptmap[USRPTSIZE];
+
+char   buffers[NBUF][BSIZE];
diff --git a/usr/src/sys/sys/acct.c b/usr/src/sys/sys/acct.c
new file mode 100644 (file)
index 0000000..6e98e3e
--- /dev/null
@@ -0,0 +1,129 @@
+/*     acct.c  2.1     1/5/80  */
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/acct.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/inode.h"
+#include "../h/proc.h"
+#include "../h/seg.h"
+
+/*
+ * Perform process accounting functions.
+ */
+
+sysacct()
+{
+       register struct inode *ip;
+       register struct a {
+               char    *fname;
+       } *uap;
+
+       uap = (struct a *)u.u_ap;
+       if (suser()) {
+               if (uap->fname==NULL) {
+                       if (acctp) {
+                               plock(acctp);
+                               iput(acctp);
+                               acctp = NULL;
+                       }
+                       return;
+               }
+               if (acctp) {
+                       u.u_error = EBUSY;
+                       return;
+               }
+               ip = namei(uchar, 0);
+               if(ip == NULL)
+                       return;
+               if((ip->i_mode & IFMT) != IFREG) {
+                       u.u_error = EACCES;
+                       iput(ip);
+                       return;
+               }
+               acctp = ip;
+               prele(ip);
+       }
+}
+
+/*
+ * On exit, write a record on the accounting file.
+ */
+acct()
+{
+       register i;
+       register struct inode *ip;
+       off_t siz;
+
+       if ((ip=acctp)==NULL)
+               return;
+       plock(ip);
+       for (i=0; i<sizeof(acctbuf.ac_comm); i++)
+               acctbuf.ac_comm[i] = u.u_comm[i];
+       acctbuf.ac_utime = compress(u.u_utime);
+       acctbuf.ac_stime = compress(u.u_stime);
+       acctbuf.ac_etime = compress(time - u.u_start);
+       acctbuf.ac_btime = u.u_start;
+       acctbuf.ac_uid = u.u_ruid;
+       acctbuf.ac_gid = u.u_rgid;
+       acctbuf.ac_mem = 0;
+       acctbuf.ac_io = 0;
+       acctbuf.ac_tty = u.u_ttyd;
+       acctbuf.ac_flag = u.u_acflag;
+       siz = ip->i_size;
+       u.u_offset = siz;
+       u.u_base = (caddr_t)&acctbuf;
+       u.u_count = sizeof(acctbuf);
+       u.u_segflg = 1;
+       u.u_error = 0;
+       writei(ip);
+       if(u.u_error)
+               ip->i_size = siz;
+       prele(ip);
+}
+
+/*
+ * Produce a pseudo-floating point representation
+ * with 3 bits base-8 exponent, 13 bits fraction.
+ */
+compress(t)
+register time_t t;
+{
+       register exp = 0, round = 0;
+
+       while (t >= 8192) {
+               exp++;
+               round = t&04;
+               t >>= 3;
+       }
+       if (round) {
+               t++;
+               if (t >= 8192) {
+                       t >>= 3;
+                       exp++;
+               }
+       }
+       return((exp<<13) + t);
+}
+
+/*
+ * lock user into core as much
+ * as possible. swapping may still
+ * occur if core grows.
+ */
+syslock()
+{
+       register struct proc *p;
+       register struct a {
+               int     flag;
+       } *uap;
+
+       uap = (struct a *)u.u_ap;
+       if(suser()) {
+               p = u.u_procp;
+               p->p_flag &= ~SULOCK;
+               if(uap->flag)
+                       p->p_flag |= SULOCK;
+       }
+}
diff --git a/usr/src/sys/sys/alloc.c b/usr/src/sys/sys/alloc.c
new file mode 100644 (file)
index 0000000..5ee54cb
--- /dev/null
@@ -0,0 +1,351 @@
+/*     alloc.c 2.1     1/5/80  */
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/mount.h"
+#include "../h/filsys.h"
+#include "../h/fblk.h"
+#include "../h/conf.h"
+#include "../h/buf.h"
+#include "../h/inode.h"
+#include "../h/ino.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+typedef        struct fblk *FBLKP;
+
+/*
+ * alloc will obtain the next available
+ * free disk block from the free list of
+ * the specified device.
+ * The super block has up to NICFREE remembered
+ * free blocks; the last of these is read to
+ * obtain NICFREE more . . .
+ *
+ * no space on dev x/y -- when
+ * the free list is exhausted.
+ */
+struct buf *
+alloc(dev)
+dev_t dev;
+{
+       daddr_t bno;
+       register struct filsys *fp;
+       register struct buf *bp;
+
+       fp = getfs(dev);
+       while(fp->s_flock)
+               sleep((caddr_t)&fp->s_flock, PINOD);
+       do {
+               if(fp->s_nfree <= 0)
+                       goto nospace;
+               if (fp->s_nfree > NICFREE) {
+                       prdev("Bad free count", dev);
+                       goto nospace;
+               }
+               bno = fp->s_free[--fp->s_nfree];
+               if(bno == 0)
+                       goto nospace;
+       } while (badblock(fp, bno, dev));
+       if(fp->s_nfree <= 0) {
+               fp->s_flock++;
+               bp = bread(dev, bno);
+               if ((bp->b_flags&B_ERROR) == 0) {
+                       fp->s_nfree = ((FBLKP)(bp->b_un.b_addr))->df_nfree;
+                       bcopy((caddr_t)((FBLKP)(bp->b_un.b_addr))->df_free,
+                           (caddr_t)fp->s_free, sizeof(fp->s_free));
+               }
+               brelse(bp);
+               fp->s_flock = 0;
+               wakeup((caddr_t)&fp->s_flock);
+               if (fp->s_nfree <=0)
+                       goto nospace;
+       }
+       bp = getblk(dev, bno);
+       clrbuf(bp);
+       fp->s_fmod = 1;
+       return(bp);
+
+nospace:
+       fp->s_nfree = 0;
+       prdev("no space", dev);
+       u.u_error = ENOSPC;
+       return(NULL);
+}
+
+/*
+ * place the specified disk block
+ * back on the free list of the
+ * specified device.
+ */
+free(dev, bno)
+dev_t dev;
+daddr_t bno;
+{
+       register struct filsys *fp;
+       register struct buf *bp;
+
+       fp = getfs(dev);
+       fp->s_fmod = 1;
+       while(fp->s_flock)
+               sleep((caddr_t)&fp->s_flock, PINOD);
+       if (badblock(fp, bno, dev))
+               return;
+       if(fp->s_nfree <= 0) {
+               fp->s_nfree = 1;
+               fp->s_free[0] = 0;
+       }
+       if(fp->s_nfree >= NICFREE) {
+               fp->s_flock++;
+               bp = getblk(dev, bno);
+               ((FBLKP)(bp->b_un.b_addr))->df_nfree = fp->s_nfree;
+               bcopy((caddr_t)fp->s_free,
+                       (caddr_t)((FBLKP)(bp->b_un.b_addr))->df_free,
+                       sizeof(fp->s_free));
+               fp->s_nfree = 0;
+               bwrite(bp);
+               fp->s_flock = 0;
+               wakeup((caddr_t)&fp->s_flock);
+       }
+       fp->s_free[fp->s_nfree++] = bno;
+       fp->s_fmod = 1;
+}
+
+/*
+ * Check that a block number is in the
+ * range between the I list and the size
+ * of the device.
+ * This is used mainly to check that a
+ * garbage file system has not been mounted.
+ *
+ * bad block on dev x/y -- not in range
+ */
+badblock(fp, bn, dev)
+register struct filsys *fp;
+daddr_t bn;
+dev_t dev;
+{
+
+       if (bn < fp->s_isize || bn >= fp->s_fsize) {
+               prdev("bad block", dev);
+               return(1);
+       }
+       return(0);
+}
+
+/*
+ * Allocate an unused I node
+ * on the specified device.
+ * Used with file creation.
+ * The algorithm keeps up to
+ * NICINOD spare I nodes in the
+ * super block. When this runs out,
+ * a linear search through the
+ * I list is instituted to pick
+ * up NICINOD more.
+ */
+struct inode *
+ialloc(dev)
+dev_t dev;
+{
+       register struct filsys *fp;
+       register struct buf *bp;
+       register struct inode *ip;
+       int i;
+       struct dinode *dp;
+       ino_t ino, inobas;
+       int first;
+       daddr_t adr;
+
+       fp = getfs(dev);
+       while(fp->s_ilock)
+               sleep((caddr_t)&fp->s_ilock, PINOD);
+loop:
+       if(fp->s_ninode > 0) {
+               ino = fp->s_inode[--fp->s_ninode];
+               ip = iget(dev, ino);
+               if(ip == NULL)
+                       return(NULL);
+               if(ip->i_mode == 0) {
+                       for (i=0; i<NADDR; i++)
+                               ip->i_un.i_addr[i] = 0;
+                       fp->s_fmod = 1;
+                       return(ip);
+               }
+               /*
+                * Inode was allocated after all.
+                * Look some more.
+                */
+               iput(ip);
+               goto loop;
+       }
+       fp->s_ilock++;
+       if (fp->s_nbehind < 4 * NICINOD) {
+               first = 1;
+               ino = fp->s_lasti;
+               if (itoo(ino))
+                       panic("ialloc");
+               adr = itod(ino);
+       } else {
+fromtop:
+               first = 0;
+               ino = 1;
+               adr = SUPERB+1;
+               fp->s_nbehind = 0;
+       }
+#ifdef ERNIE
+       printf("s_lasti %d, s_nbehind %d\n", fp->s_lasti, fp->s_nbehind);
+       printf("searching %x/%x from %d\n", major(dev), minor(dev), ino);
+#endif
+       for(; adr < fp->s_isize; adr++) {
+               inobas = ino;
+               bp = bread(dev, adr);
+               if (bp->b_flags & B_ERROR) {
+                       brelse(bp);
+                       ino += INOPB;
+                       continue;
+               }
+               dp = bp->b_un.b_dino;
+               for(i=0; i<INOPB; i++) {
+                       if(dp->di_mode != 0)
+                               goto cont;
+                       for(ip = &inode[0]; ip < &inode[NINODE]; ip++)
+                       if(dev==ip->i_dev && ino==ip->i_number)
+                               goto cont;
+                       fp->s_inode[fp->s_ninode++] = ino;
+                       if(fp->s_ninode >= NICINOD)
+                               break;
+               cont:
+                       ino++;
+                       dp++;
+               }
+               brelse(bp);
+               if(fp->s_ninode >= NICINOD)
+                       break;
+       }
+       if (fp->s_ninode < NICINOD && first) {
+#ifdef ERNIE
+               printf("found only %d inodes on dev %x/%x, looking from top\n",
+                   fp->s_ninode, major(dev), minor(dev));
+#endif
+               goto fromtop;
+       }
+#ifdef ERNIE
+       printf("search of %x/%x ended at %d\n", major(dev), minor(dev), ino);
+#endif
+       fp->s_lasti = inobas;
+       fp->s_ilock = 0;
+       wakeup((caddr_t)&fp->s_ilock);
+       if(fp->s_ninode > 0)
+               goto loop;
+       prdev("Out of inodes", dev);
+       u.u_error = ENOSPC;
+       return(NULL);
+}
+
+/*
+ * Free the specified I node
+ * on the specified device.
+ * The algorithm stores up
+ * to NICINOD I nodes in the super
+ * block and throws away any more.
+ */
+ifree(dev, ino)
+dev_t dev;
+ino_t ino;
+{
+       register struct filsys *fp;
+
+       fp = getfs(dev);
+       if(fp->s_ilock)
+               return;
+       if(fp->s_ninode >= NICINOD) {
+               if (fp->s_lasti > ino)
+                       fp->s_nbehind++;
+               return;
+       }
+       fp->s_inode[fp->s_ninode++] = ino;
+       fp->s_fmod = 1;
+}
+
+/*
+ * getfs maps a device number into
+ * a pointer to the incore super
+ * block.
+ * The algorithm is a linear
+ * search through the mount table.
+ * A consistency check of the
+ * in core free-block and i-node
+ * counts.
+ *
+ * bad count on dev x/y -- the count
+ *     check failed. At this point, all
+ *     the counts are zeroed which will
+ *     almost certainly lead to "no space"
+ *     diagnostic
+ * panic: no fs -- the device is not mounted.
+ *     this "cannot happen"
+ */
+struct filsys *
+getfs(dev)
+dev_t dev;
+{
+       register struct mount *mp;
+       register struct filsys *fp;
+
+       for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
+       if(mp->m_bufp != NULL && mp->m_dev == dev) {
+               fp = mp->m_bufp->b_un.b_filsys;
+               if(fp->s_nfree > NICFREE || fp->s_ninode > NICINOD) {
+                       prdev("bad count", dev);
+                       fp->s_nfree = 0;
+                       fp->s_ninode = 0;
+               }
+               return(fp);
+       }
+       panic("no fs");
+       return(NULL);
+}
+
+/*
+ * update is the internal name of
+ * 'sync'. It goes through the disk
+ * queues to initiate sandbagged IO;
+ * goes through the I nodes to write
+ * modified nodes; and it goes through
+ * the mount table to initiate modified
+ * super blocks.
+ */
+update()
+{
+       register struct inode *ip;
+       register struct mount *mp;
+       register struct buf *bp;
+       struct filsys *fp;
+
+       if(updlock)
+               return;
+       updlock++;
+       for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
+               if(mp->m_bufp != NULL) {
+                       fp = mp->m_bufp->b_un.b_filsys;
+                       if(fp->s_fmod==0 || fp->s_ilock!=0 ||
+                          fp->s_flock!=0 || fp->s_ronly!=0)
+                               continue;
+                       bp = getblk(mp->m_dev, SUPERB);
+                       if (bp->b_flags & B_ERROR)
+                               continue;
+                       fp->s_fmod = 0;
+                       fp->s_time = time;
+                       bcopy((caddr_t)fp, bp->b_un.b_addr, BSIZE);
+                       bwrite(bp);
+               }
+       for(ip = &inode[0]; ip < &inode[NINODE]; ip++)
+               if((ip->i_flag&ILOCK)==0 && ip->i_count) {
+                       ip->i_flag |= ILOCK;
+                       ip->i_count++;
+                       iupdat(ip, &time, &time);
+                       iput(ip);
+               }
+       updlock = 0;
+       bflush(NODEV);
+}
diff --git a/usr/src/sys/sys/clock.c b/usr/src/sys/sys/clock.c
new file mode 100644 (file)
index 0000000..60a670c
--- /dev/null
@@ -0,0 +1,215 @@
+/*     clock.c 2.1     1/5/80  */
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/callo.h"
+#include "../h/seg.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/proc.h"
+#include "../h/reg.h"
+#include "../h/psl.h"
+#include "../h/vm.h"
+#include "../h/buf.h"
+
+#define        SCHMAG  9/10
+
+
+/*
+ * clock is called straight from
+ * the real time clock interrupt.
+ *
+ * Functions:
+ *     implement callouts
+ *     maintain user/system times
+ *     maintain date
+ *     profile
+ *     lightning bolt wakeup (every second)
+ *     alarm clock signals
+ *     jab the scheduler
+ */
+
+clock(pc, ps)
+caddr_t pc;
+{
+       register struct callo *p1, *p2;
+       register struct proc *pp;
+       int a;
+       extern caddr_t waitloc, ewaitloc;
+
+       /*
+        * reprime clock
+        */
+       clkreld();
+
+       /*
+        * callouts
+        * else update first non-zero time
+        */
+
+       if(callout[0].c_func == NULL)
+               goto out;
+       p2 = &callout[0];
+       while(p2->c_time<=0 && p2->c_func!=NULL)
+               p2++;
+       p2->c_time--;
+
+       /*
+        * if ps is high, just return
+        */
+       if (BASEPRI(ps))
+               goto out;
+
+       /*
+        * callout
+        */
+
+       if(callout[0].c_time <= 0) {
+               p1 = &callout[0];
+               while(p1->c_func != 0 && p1->c_time <= 0) {
+                       (*p1->c_func)(p1->c_arg);
+                       p1++;
+               }
+               p2 = &callout[0];
+               while(p2->c_func = p1->c_func) {
+                       p2->c_time = p1->c_time;
+                       p2->c_arg = p1->c_arg;
+                       p1++;
+                       p2++;
+               }
+       }
+
+       /*
+        * lightning bolt time-out
+        * and time of day
+        */
+out:
+       a = dk_busy&07;
+       if (USERMODE(ps)) {
+               u.u_utime++;
+               if(u.u_procp->p_nice > NZERO)
+                       a += 8;
+       } else {
+               a += 16;
+               if (pc == waitloc || pc == ewaitloc )
+                       a += 8;
+               u.u_stime++;
+       }
+       dk_time[a]++;
+       pp = u.u_procp;
+       if(++pp->p_cpu == 0)
+               pp->p_cpu--;
+       if(++lbolt >= HZ) {
+               if (BASEPRI(ps))
+                       return;
+               lbolt -= HZ;
+               ++time;
+               VOID spl1();
+               runrun++;
+               wakeup((caddr_t)&lbolt);
+               rate.v_pgin = 0;
+               for(pp = &proc[0]; pp < &proc[NPROC]; pp++)
+               if (pp->p_stat && pp->p_stat<SZOMB) {
+                       if(pp->p_time != 127)
+                               pp->p_time++;
+                       if(pp->p_clktim)
+                               if(--pp->p_clktim == 0)
+                                       psignal(pp, SIGCLK);
+                       if(pp->p_stat==SSLEEP||pp->p_stat==SSTOP)
+                               if (pp->p_slptime != 127)
+                                       pp->p_slptime++;
+                       if(pp->p_stat&SLOAD) {
+                               ave(pp->p_aveflt, pp->p_faults, 5);
+                               pp->p_faults = 0;
+                               rate.v_pgin += pp->p_aveflt;
+                       }
+                       sum.v_pgin += cnt.v_pgin;
+                       cnt.v_pgin = 0;
+                       a = (pp->p_cpu & 0377)*SCHMAG + pp->p_nice - NZERO;
+                       if(a < 0)
+                               a = 0;
+                       if(a > 255)
+                               a = 255;
+                       pp->p_cpu = a;
+                       if(pp->p_pri >= PUSER)
+                               VOID setpri(pp);
+               }
+               vmmeter();
+               if(runin!=0) {
+                       runin = 0;
+                       wakeup((caddr_t)&runin);
+               }
+               /*
+                * If there are pages that have been cleaned, 
+                * jolt the pageout daemon to process them.
+                * We do this here so that these pages will be
+                * freed if there is an abundance of memory and the
+                * daemon would not be awakened otherwise.
+                */
+               if (bclnlist != NULL)
+                       wakeup((caddr_t)&proc[2]);
+#ifdef ERNIE
+               if (USERMODE(ps)) {
+                       pp = u.u_procp;
+                       if (pp->p_uid)
+                               if (pp->p_nice == NZERO && u.u_utime > 600 * HZ)
+                                       pp->p_nice = NZERO+4;
+                       VOID setpri(pp);
+               }
+#endif
+       }
+       if (USERMODE(ps))
+               /*
+                * We do this last since it
+                * may block on a page fault in user space.
+                */
+               if (u.u_prof.pr_scale)
+                       addupc(pc, &u.u_prof, 1);
+}
+
+/*
+ * timeout is called to arrange that
+ * fun(arg) is called in tim/HZ seconds.
+ * An entry is sorted into the callout
+ * structure. The time in each structure
+ * entry is the number of HZ's more
+ * than the previous entry.
+ * In this way, decrementing the
+ * first entry has the effect of
+ * updating all entries.
+ *
+ * The panic is there because there is nothing
+ * intelligent to be done if an entry won't fit.
+ */
+timeout(fun, arg, tim)
+int (*fun)();
+caddr_t arg;
+{
+       register struct callo *p1, *p2;
+       register int t;
+       int s;
+
+       t = tim;
+       p1 = &callout[0];
+       s = spl7();
+       while(p1->c_func != 0 && p1->c_time <= t) {
+               t -= p1->c_time;
+               p1++;
+       }
+       if (p1 >= &callout[NCALL-1])
+               panic("Timeout table overflow");
+       p1->c_time -= t;
+       p2 = p1;
+       while(p2->c_func != 0)
+               p2++;
+       while(p2 >= p1) {
+               (p2+1)->c_time = p2->c_time;
+               (p2+1)->c_func = p2->c_func;
+               (p2+1)->c_arg = p2->c_arg;
+               p2--;
+       }
+       p1->c_time = t;
+       p1->c_func = fun;
+       p1->c_arg = arg;
+       splx(s);
+}
diff --git a/usr/src/sys/sys/conf.c b/usr/src/sys/sys/conf.c
new file mode 100644 (file)
index 0000000..9171bc1
--- /dev/null
@@ -0,0 +1,141 @@
+/*     conf.c  2.1     1/5/80  */
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/buf.h"
+#include "../h/tty.h"
+#include "../h/conf.h"
+#include "../h/proc.h"
+#include "../h/text.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/file.h"
+#include "../h/inode.h"
+#include "../h/acct.h"
+#include "../h/mba.h"
+
+int    nulldev();
+int    nodev();
+
+int    hpstrategy(), hpread(), hpwrite(), hpintr();
+struct buf     hptab;
+int    htopen(), htclose(), htstrategy(), htread(), htwrite();
+struct buf     httab;
+
+#ifdef ERNIE
+int    uhpopen(), uhpstrategy(), uhpread(), uhpwrite();
+struct buf     uhptab;
+
+int    urpopen(), urpstrategy(), urpread(), urpwrite();
+struct buf     urptab;
+#endif
+
+struct bdevsw  bdevsw[] =
+{
+/* 0 */        nulldev,        nulldev,        hpstrategy,     &hptab,
+/* 1 */        htopen,         htclose,        htstrategy,     &httab,
+#ifdef ERNIE
+/* 2 */        uhpopen,        nulldev,        uhpstrategy,    &uhptab,
+/* 3 */        urpopen,        nulldev,        urpstrategy,    &urptab,
+#endif
+       0,
+};
+
+int    cnopen(), cnclose(), cnread(), cnwrite(), cnioctl();
+
+#ifdef ERNIE
+int    klopen(), klclose(), klread(), klwrite(), klioctl();
+struct tty kl_tty[];
+#endif
+
+int    flopen(), flclose(), flread(), flwrite();
+
+int    dzopen(), dzclose(), dzread(), dzwrite(), dzioctl(), dzstop();
+struct tty dz_tty[];
+
+int    syopen(), syread(), sywrite(), syioctl();
+
+int    mmread(), mmwrite();
+
+#ifdef ERNIE
+int    vpopen(), vpclose(), vpwrite(), vpioctl();
+#endif
+
+int    mxopen(), mxclose(), mxread(), mxwrite(), mxioctl();
+int    mcread();
+char   *mcwrite();
+
+struct cdevsw  cdevsw[] =
+{
+/* 0 */                cnopen, cnclose, cnread, cnwrite, cnioctl, nulldev, 0,
+/* 1 */                dzopen, dzclose, dzread, dzwrite, dzioctl, dzstop, dz_tty,
+/* 2 */                syopen, nulldev, syread, sywrite, syioctl, nulldev, 0,
+/* 3 */                nulldev, nulldev, mmread, mmwrite, nodev, nulldev, 0,
+/* 4 */                nulldev, nulldev, hpread, hpwrite, nodev, nodev, 0,
+/* 5 */                htopen,  htclose, htread, htwrite, nodev, nodev, 0,
+#ifdef ERNIE
+/* 6 */                vpopen, vpclose, nodev, vpwrite, vpioctl, nulldev, 0,
+/* 7 */                klopen, klclose, klread, klwrite, klioctl, nulldev, kl_tty,
+#else
+/* 6 */                nodev, nodev, nodev, nodev, nodev, nodev, 0,
+/* 7 */                nodev, nodev, nodev, nodev, nodev, nodev, 0,
+#endif
+/* 8 */                flopen, flclose, flread, flwrite, nodev, nodev, 0,
+/* 9 */                mxopen, mxclose, mxread, mxwrite, mxioctl, nulldev, 0,
+#ifdef ERNIE
+/* 10 */       uhpopen, nulldev, uhpread, uhpwrite, nodev, nodev, 0,
+/* 11 */       urpopen, nulldev, urpread, urpwrite, nodev, nodev, 0,
+#endif
+               0,
+};
+
+int    ttyopen(),ttread();
+char   *ttwrite();
+int    ttyinput(), ttyrend();
+struct linesw linesw[] =
+{
+       ttyopen, nulldev, ttread, ttwrite, nodev,
+       ttyinput, ttyrend, nulldev, nulldev, nulldev,   /* 0 */
+       mxopen, mxclose, mcread, mcwrite, mxioctl,
+       nulldev, nulldev, nulldev, nulldev, nulldev,    /* 1 */
+       0
+};
+int    nldisp = 1;
+dev_t  rootdev = makedev(0, 0);
+dev_t  swapdev = makedev(0, 1);
+dev_t  pipedev = makedev(0, 0);
+daddr_t swplo = 1;             /* (swplo-1) % CLSIZE must be 0 */
+int    nswap = 33439;
+struct buf     buf[NBUF];
+struct file    file[NFILE];
+struct inode   inode[NINODE];
+struct text    text[NTEXT];
+struct proc    proc[NPROC];
+struct buf     bfreelist;
+struct buf     bswlist;        /* free list of swap headers */
+struct buf     *bclnlist;      /* header for list of cleaned pages */
+struct acct    acctbuf;
+struct inode   *acctp;
+int    mem_no = 3;     /* major device number of memory special file */
+
+
+extern struct user u;
+
+int mbanum[] = {       /* mba number of major device */
+       0,              /* disk */
+       1,              /* tape */
+       9999999,        /* unused */
+       9999999,        /* unused */
+       0,              /* disk, raw */
+       1,              /* tape, raw */
+};
+
+int *mbaloc[] = {      /* virtual location of mba */
+       (int *)MBA0,
+       (int *)MBA1,
+};
diff --git a/usr/src/sys/sys/cons.c b/usr/src/sys/sys/cons.c
new file mode 100644 (file)
index 0000000..9994b89
--- /dev/null
@@ -0,0 +1,194 @@
+/*     cons.c  2.1     1/5/80  */
+
+/*
+ *   Vax console driver and floppy interface
+ */
+#include "../h/param.h"
+#include "../h/conf.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/tty.h"
+#include "../h/systm.h"
+#include "../h/cons.h"
+#include "../h/mtpr.h"
+
+#define        NL1     000400
+#define        NL2     001000
+#define        CR2     020000
+#define        FF1     040000
+#define        TAB1    002000
+
+struct tty cons;
+int    cnstart();
+int    ttrstrt();
+char   partab[];
+
+/*ARGSUSED*/
+cnopen(dev, flag)
+dev_t dev;
+{
+       register struct tty *tp;
+
+       tp = &cons;
+       tp->t_oproc = cnstart;
+       tp->t_iproc = NULL;
+       if ((tp->t_state&ISOPEN) == 0) {
+               ttychars(tp);
+               tp->t_state = ISOPEN|CARR_ON;
+               tp->t_flags = EVENP|ECHO|XTABS|CRMOD;
+       }
+       mtpr(RXCS, mfpr(RXCS)|RXCS_IE);
+       mtpr(TXCS, mfpr(TXCS)|TXCS_IE);
+       ttyopen(dev, tp);
+}
+
+/*ARGSUSED*/
+cnclose(dev)
+dev_t dev;
+{
+       register struct tty *tp;
+
+       tp = &cons;
+       wflushtty(tp);
+       tp->t_state = 0;
+}
+
+/*ARGSUSED*/
+cnread(dev)
+dev_t dev;
+{
+
+       ttread(&cons);
+}
+
+/*ARGSUSED*/
+cnwrite(dev)
+dev_t dev;
+{
+
+       ttwrite(&cons);
+}
+
+/*
+ * Got a level-20 transmission interrupt -
+ * the LSI wants another character.  First,
+ * see if we can send something to the typewriter.
+ * If not, try the floppy.
+ */
+/*ARGSUSED*/
+cnxint(dev)
+dev_t dev;
+{
+
+       if (cnxtty() == 0)
+               conxfl();
+}
+
+/*
+ * Formerly cnxint -
+ * called by new cnxint to see if there are
+ * any characters to write to the console, and,
+ * if there are, to do it.
+ */
+cnxtty()
+{
+       register struct tty *tp;
+
+       tp = &cons;
+       if (tp->t_outq.c_cc == 0)
+               return(0);
+       ttstart(tp);
+       if (tp->t_outq.c_cc == 0 || tp->t_outq.c_cc == TTLOWAT)
+               wakeup((caddr_t)&tp->t_outq);
+       return(1);
+}
+
+/*
+ * Got a level-20 receive interrupt -
+ * the LSI wants to give us a character.
+ * Catch the character, and see who it goes to.
+ */
+/*ARGSUSED*/
+cnrint(dev)
+dev_t dev;
+{
+       register int c;
+
+       c = mfpr(RXDB);
+       if ((c&RXDB_ID)==0)             /* look at source byte */
+               ttyinput(c, &cons);     /* character from typewriter */
+       else
+               cnrfl(c);               /* character from floppy */
+}
+
+/*ARGSUSED*/
+cnioctl(dev, cmd, addr, flag)
+dev_t dev;
+caddr_t addr;
+{
+       register struct tty *tp;
+       tp = &cons;
+       if (ttioccom(cmd, tp, addr, dev) ==0)
+               u.u_error = ENOTTY;
+}
+
+cnstart(tp)
+register struct tty *tp;
+{
+       register c;
+
+       if ((mfpr(TXCS)&TXCS_RDY) == 0)
+               return;
+       if ((c=getc(&tp->t_outq)) >= 0) {
+               if (tp->t_flags&RAW)
+                       mtpr(TXDB, c&0xff);
+               else if (c<=0177)
+                       mtpr(TXDB, (c | (partab[c]&0200))&0xff);
+               else {
+                       timeout(ttrstrt, (caddr_t)tp, (c&0177));
+                       tp->t_state |= TIMEOUT;
+               }
+       }
+}
+
+char   *msgbufp = msgbuf;      /* Next saved printf character */
+/*
+ * Print a character on console.
+ * Attempts to save and restore device
+ * status.
+ * If the switches are 0, all
+ * printing is inhibited.
+ *
+ * Whether or not printing is inhibited,
+ * the last MSGBUFS characters
+ * are saved in msgbuf for inspection later.
+ */
+putchar(c)
+register c;
+{
+       register s, timo;
+
+       if (c != '\0' && c != '\r' && c != 0177) {
+               *msgbufp++ = c;
+               if(msgbufp >= &msgbuf[MSGBUFS])
+                       msgbufp = msgbuf;
+       }
+       timo = 30000;
+       /*
+        * Try waiting for the console tty to come ready,
+        * otherwise give up after a reasonable time.
+        */
+       while((mfpr(TXCS)&TXCS_RDY) == 0)
+               if(--timo == 0)
+                       break;
+       if(c == 0)
+               return;
+       s = mfpr(TXCS);
+       mtpr(TXCS,0);
+       mtpr(TXDB, c&0xff);
+       if(c == '\n')
+               putchar('\r');
+       putchar(0);
+       mtpr(TXCS, s);
+}
diff --git a/usr/src/sys/sys/dkleave.c b/usr/src/sys/sys/dkleave.c
new file mode 100644 (file)
index 0000000..d171416
--- /dev/null
@@ -0,0 +1,31 @@
+/*     dkleave.c       2.1     1/5/80  */
+
+#include "../h/param.h"
+#include "../h/buf.h"
+
+daddr_t
+dkblock(bp)
+register struct buf *bp;
+{
+       register int dminor;
+
+       if (((dminor=minor(bp->b_dev))&0100) == 0)
+               return(bp->b_blkno);
+       dminor >>= 3;
+       dminor &= 07;
+       dminor++;
+       return(bp->b_blkno/dminor);
+}
+
+dkunit(bp)
+register struct buf *bp;
+{
+       register int dminor;
+
+       dminor = minor(bp->b_dev) >> 3;
+       if ((dminor&010) == 0)
+               return(dminor);
+       dminor &= 07;
+       dminor++;
+       return(bp->b_blkno%dminor);
+}
diff --git a/usr/src/sys/sys/dsort.c b/usr/src/sys/sys/dsort.c
new file mode 100644 (file)
index 0000000..1fa9465
--- /dev/null
@@ -0,0 +1,45 @@
+/*     dsort.c 2.1     1/5/80  */
+
+/*
+ * generalized seek sort for disk
+ */
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/buf.h"
+
+#define        b_cylin b_resid
+
+disksort(dp, bp)
+register struct buf *dp, *bp;
+{
+       register struct buf *ap;
+       struct buf *tp;
+
+       ap = dp->b_actf;
+       if(ap == NULL) {
+               dp->b_actf = bp;
+               dp->b_actl = bp;
+               bp->av_forw = NULL;
+               return;
+       }
+       tp = NULL;
+       for(; ap != NULL; ap = ap->av_forw) {
+               if ((bp->b_flags&B_READ) && (ap->b_flags&B_READ) == 0) {
+                       if (tp == NULL)
+                               tp = ap;
+                       break;
+               }
+               if ((bp->b_flags&B_READ) == 0 && (ap->b_flags&B_READ))
+                       continue;
+               if(ap->b_cylin <= bp->b_cylin)
+                       if(tp == NULL || ap->b_cylin >= tp->b_cylin)
+                               tp = ap;
+       }
+       if(tp == NULL)
+               tp = dp->b_actl;
+       bp->av_forw = tp->av_forw;
+       tp->av_forw = bp;
+       if(tp == dp->b_actl)
+               dp->b_actl = bp;
+}
diff --git a/usr/src/sys/sys/fio.c b/usr/src/sys/sys/fio.c
new file mode 100644 (file)
index 0000000..010d93c
--- /dev/null
@@ -0,0 +1,266 @@
+/*     fio.c   2.1     1/5/80  */
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/filsys.h"
+#include "../h/file.h"
+#include "../h/conf.h"
+#include "../h/inode.h"
+#include "../h/reg.h"
+#include "../h/acct.h"
+
+/*
+ * Convert a user supplied
+ * file descriptor into a pointer
+ * to a file structure.
+ * Only task is to check range
+ * of the descriptor.
+ */
+struct file *
+getf(f)
+register int f;
+{
+       register struct file *fp;
+
+       if(0 <= f && f < NOFILE) {
+               fp = u.u_ofile[f];
+               if(fp != NULL)
+                       return(fp);
+       }
+       u.u_error = EBADF;
+       return(NULL);
+}
+
+/*
+ * Internal form of close.
+ * Decrement reference count on
+ * file structure.
+ * Also make sure the pipe protocol
+ * does not constipate.
+ *
+ * Decrement reference count on the inode following
+ * removal to the referencing file structure.
+ * Call device handler on last close.
+ */
+closef(fp)
+register struct file *fp;
+{
+       register struct inode *ip;
+       int flag, mode;
+       dev_t dev;
+       register int (*cfunc)();
+       struct chan *cp;
+
+       if(fp == NULL)
+               return;
+       if (fp->f_count > 1) {
+               fp->f_count--;
+               return;
+       }
+       ip = fp->f_inode;
+       flag = fp->f_flag;
+       cp = fp->f_un.f_chan;
+       dev = (dev_t)ip->i_un.i_rdev;
+       mode = ip->i_mode;
+
+       plock(ip);
+       fp->f_count = 0;
+       if(flag & FPIPE) {
+               ip->i_mode &= ~(IREAD|IWRITE);
+               wakeup((caddr_t)ip+1);
+               wakeup((caddr_t)ip+2);
+       }
+       iput(ip);
+
+       switch(mode&IFMT) {
+
+       case IFCHR:
+       case IFMPC:
+               cfunc = cdevsw[major(dev)].d_close;
+               break;
+
+       case IFBLK:
+       case IFMPB:
+               cfunc = bdevsw[major(dev)].d_close;
+               break;
+       default:
+               return;
+       }
+
+       if (flag & FMP)
+               goto call;
+
+       for(fp=file; fp < &file[NFILE]; fp++)
+               if (fp->f_count && fp->f_inode==ip)
+                       return;
+
+call:
+       (*cfunc)(dev, flag, cp);
+}
+
+/*
+ * openi called to allow handler
+ * of special files to initialize and
+ * validate before actual IO.
+ */
+openi(ip, rw)
+register struct inode *ip;
+{
+       dev_t dev;
+       register unsigned int maj;
+
+       dev = (dev_t)ip->i_un.i_rdev;
+       maj = major(dev);
+       switch(ip->i_mode&IFMT) {
+
+       case IFCHR:
+       case IFMPC:
+               if(maj >= nchrdev)
+                       goto bad;
+               (*cdevsw[maj].d_open)(dev, rw);
+               break;
+
+       case IFBLK:
+       case IFMPB:
+               if(maj >= nblkdev)
+                       goto bad;
+               (*bdevsw[maj].d_open)(dev, rw);
+       }
+       return;
+
+bad:
+       u.u_error = ENXIO;
+}
+
+/*
+ * Check mode permission on inode pointer.
+ * Mode is READ, WRITE or EXEC.
+ * In the case of WRITE, the
+ * read-only status of the file
+ * system is checked.
+ * Also in WRITE, prototype text
+ * segments cannot be written.
+ * The mode is shifted to select
+ * the owner/group/other fields.
+ * The super user is granted all
+ * permissions.
+ */
+access(ip, mode)
+register struct inode *ip;
+{
+       register m;
+
+       m = mode;
+       if(m == IWRITE) {
+               if(getfs(ip->i_dev)->s_ronly != 0) {
+                       u.u_error = EROFS;
+                       return(1);
+               }
+               if (ip->i_flag&ITEXT)           /* try to free text */
+                       xrele(ip);
+               if(ip->i_flag & ITEXT) {
+                       u.u_error = ETXTBSY;
+                       return(1);
+               }
+       }
+       if(u.u_uid == 0)
+               return(0);
+       if(u.u_uid != ip->i_uid) {
+               m >>= 3;
+               if(u.u_gid != ip->i_gid)
+                       m >>= 3;
+       }
+       if((ip->i_mode&m) != 0)
+               return(0);
+
+       u.u_error = EACCES;
+       return(1);
+}
+
+/*
+ * Look up a pathname and test if
+ * the resultant inode is owned by the
+ * current user.
+ * If not, try for super-user.
+ * If permission is granted,
+ * return inode pointer.
+ */
+struct inode *
+owner()
+{
+       register struct inode *ip;
+
+       ip = namei(uchar, 0);
+       if(ip == NULL)
+               return(NULL);
+       if(u.u_uid == ip->i_uid)
+               return(ip);
+       if(suser())
+               return(ip);
+       iput(ip);
+       return(NULL);
+}
+
+/*
+ * Test if the current user is the
+ * super user.
+ */
+suser()
+{
+
+       if(u.u_uid == 0) {
+               u.u_acflag |= ASU;
+               return(1);
+       }
+       u.u_error = EPERM;
+       return(0);
+}
+
+/*
+ * Allocate a user file descriptor.
+ */
+ufalloc()
+{
+       register i;
+
+       for(i=0; i<NOFILE; i++)
+               if(u.u_ofile[i] == NULL) {
+                       u.u_r.r_val1 = i;
+                       u.u_pofile[i] = 0;
+                       return(i);
+               }
+       u.u_error = EMFILE;
+       return(-1);
+}
+
+/*
+ * Allocate a user file descriptor
+ * and a file structure.
+ * Initialize the descriptor
+ * to point at the file structure.
+ *
+ * no file -- if there are no available
+ *     file structures.
+ */
+struct file *
+falloc()
+{
+       register struct file *fp;
+       register i;
+
+       i = ufalloc();
+       if(i < 0)
+               return(NULL);
+       for(fp = &file[0]; fp < &file[NFILE]; fp++)
+               if(fp->f_count == 0) {
+                       u.u_ofile[i] = fp;
+                       fp->f_count++;
+                       fp->f_un.f_offset = 0;
+                       return(fp);
+               }
+       printf("no file\n");
+       u.u_error = ENFILE;
+       return(NULL);
+}
diff --git a/usr/src/sys/sys/flp.c b/usr/src/sys/sys/flp.c
new file mode 100644 (file)
index 0000000..7cf6730
--- /dev/null
@@ -0,0 +1,258 @@
+/*     flp.c   2.1     1/5/80  */
+
+#include "../h/flp.h"
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/conf.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/mtpr.h"
+#include "../h/buf.h"
+#include "../h/cons.h"
+
+struct {
+       short   fl_state;               /* open and busy flags */
+       short   fl_active;              /* driver state flag */
+       struct  buf *fl_buf;            /* buffer we're using */
+       unsigned char *fl_xaddr;        /* transfer address */
+       short   fl_errcnt;
+} fltab;
+
+/*ARGSUSED*/
+flopen(dev, flag)
+       dev_t dev;
+       int flag;
+{
+       struct buf *geteblk();
+
+       if (fltab.fl_state != 0) {
+               u.u_error = ENXIO;
+               return;
+       }
+       fltab.fl_state = FL_OPEN;
+       fltab.fl_buf = geteblk();
+       fltab.fl_active = FL_IDLE;
+}
+
+/*ARGSUSED*/
+flclose(dev, flag)
+       dev_t dev;
+       int flag;
+{
+
+       brelse(fltab.fl_buf);
+       fltab.fl_state = 0;
+}
+
+flstrategy(rw)
+       int rw;
+{
+       register struct buf *bp;
+       register unsigned i;
+
+       /*
+        * Assume one block read/written for each call - 
+        * and enforce this by checking for block size of 128.
+        * Use the b_blkno field to address
+        * physical, 128-byte blocks (u.u_offset/128).
+        * This is checked for validity, and is further interpreted as:
+        *
+        *      track# * (sectors/track) + sector #
+        */
+       if (u.u_count == 0) 
+               return;
+       VOID spl4();
+       while (fltab.fl_state & FL_BUSY)
+               sleep((caddr_t)&fltab, PRIBIO);
+       fltab.fl_state |= FL_BUSY;
+       VOID spl0();
+
+       bp = fltab.fl_buf;
+       while ((i = min(RXBYSEC, u.u_count)) != 0) {
+               bp->b_blkno = u.u_offset>>7;
+               if (bp->b_blkno >= MAXSEC || (u.u_offset & 0177) != 0) {
+                       /* block number out of range */
+                       /* or offset in middle of block */
+                       u.u_error = ENXIO;
+                       break;  
+               }
+               if (rw == B_WRITE) {
+                       iomove(bp->b_un.b_addr, i, B_WRITE);
+                       if (u.u_error != 0)
+                               break;
+               }
+               bp->b_flags = rw;
+               VOID spl4(); 
+               flstart();
+               while ((bp->b_flags & B_DONE) == 0)
+                       sleep((caddr_t)bp, PRIBIO);     
+               VOID spl0();
+               if (bp->b_flags & B_ERROR) {
+                       u.u_error = EIO;
+                       break;
+               }
+               if (rw == B_READ) {
+                       iomove(bp->b_un.b_addr, i, B_READ);
+                       if (u.u_error != 0)
+                               break;
+               }
+       }
+       u.u_count = bp->b_resid;
+       fltab.fl_state &= ~FL_BUSY;
+       wakeup((caddr_t)&fltab);
+}
+
+/*ARGSUSED*/
+flread(dev)
+       dev_t dev;
+{
+
+       flstrategy(B_READ);
+}
+
+/*ARGSUSED*/
+flwrite(dev)
+       dev_t dev;
+{
+
+       flstrategy(B_WRITE);
+}
+
+flstart()
+{
+       register struct buf *bp;
+
+       bp = fltab.fl_buf;
+       fltab.fl_active = FL_MAND;
+       fltab.fl_errcnt = 0;
+       fltab.fl_xaddr = (unsigned char *) bp->b_un.b_addr;
+       bp->b_resid = 0;
+       bp->b_bcount = RXBYSEC; /* always transfer a full sector */
+
+       if ((mfpr(TXCS) & TXCS_RDY) == 0)
+               /* not ready to receive order */
+               return;
+       /*
+        * Wake up floppy LSI software with command
+        */
+       fltab.fl_active = FL_SEC;
+       if ((bp->b_flags&B_READ) == B_READ)
+               mtpr(TXDB, FL_RS);
+       else
+               mtpr(TXDB, FL_WS);
+}
+
+/*
+ * See if we want to transmit something
+ * to the floppy - and do it
+ */
+conxfl()
+{
+       register int databyte;
+       register struct buf *bp;
+
+       bp = fltab.fl_buf;
+       switch (fltab.fl_active) {
+
+       case FL_MAND:           /* send command */
+               if ((bp->b_flags&B_READ) == B_READ)
+                       mtpr(TXDB,FL_RS);
+               else
+                       mtpr(TXDB,  FL_WS);
+               fltab.fl_active = FL_SEC;
+               break;
+
+       case FL_SEC:            /* send sector address */
+               databyte = (int)bp->b_blkno % RXSTRK + 1;
+               mtpr(TXDB, FL_DATA | databyte);
+               fltab.fl_active = FL_TRACK;
+               break;
+
+       case FL_TRACK:          /* send track address */
+               databyte = (int)bp->b_blkno / RXSTRK;
+               mtpr(TXDB , FL_DATA | databyte);
+               if ((bp->b_flags&B_READ) == B_READ)
+                       /* prepare to receive complete */
+                       fltab.fl_active = FL_COM;
+               else
+                       /* prepare to send data */
+                       fltab.fl_active = FL_DAX;
+               break;
+
+       case FL_DAX:
+               databyte = *(fltab.fl_xaddr++);
+               mtpr(TXDB, FL_DATA | databyte);
+               if (--bp->b_bcount == 0)
+                       fltab.fl_active = FL_COM;
+               break;
+
+       case FL_CAN:            /* give cancel order */
+               mtpr(TXDB, FL_CANCEL);
+               if (++fltab.fl_errcnt <= FLERRS) {
+                       /* If error count permits, retry order */
+                       fltab.fl_active = FL_MAND;
+                       bp->b_bcount = RXBYSEC;
+                       fltab.fl_xaddr = (unsigned char *) bp->b_un.b_addr;
+               } else {
+                       /*
+                        * We're really stupid today - call it an
+                        * error and give up
+                        */
+                       bp->b_flags |= B_ERROR | B_DONE;
+                       bp->b_resid = -RXBYSEC;
+                       fltab.fl_active = FL_IDLE;
+                       wakeup((caddr_t)bp);
+               }
+       }
+}
+
+cnrfl(c)
+       int c;
+{
+       register int datum;
+       register struct buf *bp;
+
+       datum = c;
+       bp = fltab.fl_buf;
+       if (datum == FL_PERR) {
+               /*
+                * Got a protocol error - cancel the
+                * current function and try again if error count isn't
+                * too great.  First, though, make sure that an actual
+                * transaction is in progress (so a spurious error from
+                * the LSI won't screw us up too much!
+                */
+               if (fltab.fl_active != FL_IDLE)
+                       fltab.fl_active = FL_CAN;
+       } else switch(fltab.fl_active ) {
+
+       case FL_DAR:            /* expecting a datum */
+               if ((c&RXDB_ID) != FL_DATA)
+                       goto error;
+               *(fltab.fl_xaddr++) = (c & RXDB_DATA);
+               if (--bp->b_bcount==0) {
+                       fltab.fl_active = FL_IDLE;
+                       bp->b_flags |= B_DONE;
+                       wakeup((caddr_t)bp);
+               }
+               break;
+
+       case FL_COM:            /* expecting a "function complete" */
+               if ((c&RXDB_ID)!= FL_FFC || (c&FL_ERR) == FL_ERR){
+error:
+                       bp->b_flags |= B_ERROR | B_DONE;
+                       bp->b_resid = -bp->b_bcount;
+                       fltab.fl_active = FL_IDLE;
+                       wakeup((caddr_t)bp);
+               } else if ((bp->b_flags&B_READ) == B_READ)
+                       /* got function complete, now get data */
+                       fltab.fl_active = FL_DAR;
+               else {
+                       /* got function complete on write - finish up */
+                       fltab.fl_active = FL_IDLE;
+                       bp->b_flags |= B_DONE;
+                               wakeup((caddr_t)bp);
+               }
+               break;
+       }
+}
diff --git a/usr/src/sys/sys/ht.c b/usr/src/sys/sys/ht.c
new file mode 100644 (file)
index 0000000..1c93ead
--- /dev/null
@@ -0,0 +1,351 @@
+/*     ht.c    2.1     1/5/80  */
+
+/*
+ * TJU16 tape driver
+ */
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/buf.h"
+#include "../h/conf.h"
+#include "../h/dir.h"
+#include "../h/file.h"
+#include "../h/user.h"
+#include "../h/map.h"
+#include "../h/mba.h"
+
+struct device
+{
+       int     htcs1;
+       int     htds;
+       int     hter;
+       int     htmr;
+       int     htas;
+       int     htfc;
+       int     htdt;
+       int     htck;
+       int     htsn;
+       int     httc;
+};
+
+struct buf     httab;
+struct buf     rhtbuf;
+struct buf     chtbuf;
+
+#define        NUNIT   1
+#define        BUNIT   2
+#define        INF     1000000
+
+char   h_openf[NUNIT];
+daddr_t        h_blkno[NUNIT];
+char   h_flags[NUNIT];
+daddr_t        h_nxrec[NUNIT];
+
+#define        HTADDR  ((struct device *)(MBA1 + MBA_ERB))
+
+#define        GO      01
+#define        WCOM    060
+#define        RCOM    070
+#define        NOP     0
+#define        WEOF    026
+#define        SFORW   030
+#define        SREV    032
+#define        ERASE   024
+#define        REW     06
+#define        DCLR    010
+#define        P800    01700           /* 800 + pdp11 mode */
+#define        P1600   02300           /* 1600 + pdp11 mode */
+#define        IENABLE 0100
+#define        RDY     0200
+#define        TM      04
+#define        DRY     0200
+#define        EOT     02000
+#define        CS      02000
+#define        COR     0100000
+#define        PES     040
+#define        WRL     04000
+#define        MOL     010000
+#define        ERR     040000
+#define        FCE     01000
+#define        TRE     040000
+#define        HARD    064023  /* UNS|OPI|NEF|FMT|RMR|ILR|ILF */
+
+#define        SIO     1
+#define        SSFOR   2
+#define        SSREV   3
+#define        SRETRY  4
+#define        SCOM    5
+#define        SOK     6
+
+#define        H_WRITTEN 1
+
+htopen(dev, flag)
+{
+       register unit, ds;
+
+       httab.b_flags |= B_TAPE;
+       unit = minor(dev) & 03;
+       if (unit >= NUNIT || h_openf[unit]) {
+               u.u_error = ENXIO;
+               return;
+       }
+       h_blkno[unit] = 0;
+       h_nxrec[unit] = INF;
+       h_flags[unit] = 0;
+       ds = hcommand(dev, NOP);
+       if ((ds&MOL)==0 || (flag && (ds&WRL)))
+               u.u_error = ENXIO;
+       if (u.u_error==0)
+               h_openf[unit]++;
+}
+
+htclose(dev, flag)
+{
+       register int unit;
+
+       unit = minor(dev) & 03;
+       if (flag == FWRITE || ((flag&FWRITE) && (h_flags[unit]&H_WRITTEN))) {
+               VOID hcommand(dev, WEOF);
+               VOID hcommand(dev, WEOF);
+               VOID hcommand(dev, SREV);
+       }
+/*     VOID hcommand(dev, REW);        */
+/* for 'mtm' file positioning */
+       if((minor(dev)&4) == 0) /* no 4 -> rewind */
+               VOID hcommand(dev, REW);
+       h_openf[unit] = 0;
+}
+
+hcommand(dev, com)
+{
+       register struct buf *bp;
+
+       bp = &chtbuf;
+       VOID spl5();
+       while(bp->b_flags&B_BUSY) {
+               bp->b_flags |= B_WANTED;
+               sleep((caddr_t)bp, PRIBIO);
+       }
+       VOID spl0();
+       bp->b_dev = dev;
+       bp->b_resid = com;
+       bp->b_blkno = 0;
+       bp->b_flags = B_BUSY|B_READ;
+       htstrategy(bp);
+       iowait(bp);
+       if(bp->b_flags&B_WANTED)
+               wakeup((caddr_t)bp);
+       bp->b_flags = 0;
+       return(bp->b_resid);
+}
+
+htstrategy(bp)
+register struct buf *bp;
+{
+       register daddr_t *p;
+
+       if(bp != &chtbuf) {
+               p = &h_nxrec[minor(bp->b_dev)&03];
+               if(dbtofsb(bp->b_blkno) > *p) {
+                       bp->b_flags |= B_ERROR;
+                       bp->b_error = ENXIO;
+                       iodone(bp);
+                       return;
+               }
+               if(dbtofsb(bp->b_blkno) == *p && bp->b_flags&B_READ) {
+                       bp->b_resid = bp->b_bcount;
+                       clrbuf(bp);
+                       iodone(bp);
+                       return;
+               }
+               if ((bp->b_flags&B_READ)==0) {
+                       *p = dbtofsb(bp->b_blkno) + 1;
+                       h_flags[minor(bp->b_dev)&03] |=  H_WRITTEN;
+               }
+       }
+       bp->av_forw = NULL;
+       VOID spl5();
+       if (httab.b_actf == NULL)
+               httab.b_actf = bp;
+       else
+               httab.b_actl->av_forw = bp;
+       httab.b_actl = bp;
+       if (httab.b_active==0)
+               htstart();
+       VOID spl0();
+}
+
+htstart()
+{
+       register struct buf *bp;
+       register unit, den;
+       daddr_t blkno;
+
+    loop:
+       if ((bp = httab.b_actf) == NULL)
+               return;
+       unit = minor(bp->b_dev);
+       den = P800 | (unit&03);
+       if(unit >= 8)
+               den = P1600 | (unit&03);
+       if((HTADDR->httc&03777) != den)
+               HTADDR->httc = den;
+       unit &= 03;
+       blkno = h_blkno[unit];
+       if (bp == &chtbuf) {
+               if (bp->b_resid==NOP) {
+                       bp->b_resid = HTADDR->htds & 0xffff;
+                       goto next;
+               }
+               httab.b_active = SCOM;
+               HTADDR->htfc = 0;
+               HTADDR->htcs1 = bp->b_resid|GO;
+               return;
+       }
+       if (h_openf[unit] < 0 || dbtofsb(bp->b_blkno) > h_nxrec[unit])
+               goto abort;
+       if (blkno == dbtofsb(bp->b_blkno)) {
+               httab.b_active = SIO;
+               HTADDR->htfc = -bp->b_bcount;
+               mbastart(bp, (int *)HTADDR);
+       } else {
+               if (blkno < dbtofsb(bp->b_blkno)) {
+                       httab.b_active = SSFOR;
+                       HTADDR->htfc = blkno - dbtofsb(bp->b_blkno);
+                       HTADDR->htcs1 = SFORW|GO;
+               } else {
+                       httab.b_active = SSREV;
+                       HTADDR->htfc = dbtofsb(bp->b_blkno) - blkno;
+                       HTADDR->htcs1 = SREV|GO;
+               }
+       }
+       return;
+
+    abort:
+       bp->b_flags |= B_ERROR;
+
+    next:
+       httab.b_actf = bp->av_forw;
+       iodone(bp);
+       goto loop;
+}
+
+/*ARGSUSED*/
+htintr(mbastat, as)
+{
+       register struct buf *bp;
+       register int unit, state;
+       int err;
+
+       if ((bp = httab.b_actf)==NULL)
+               return;
+       unit = minor(bp->b_dev) & 03;
+       state = httab.b_active;
+       httab.b_active = 0;
+       if (HTADDR->htds&(ERR|EOT|TM) || mbastat & MBAEBITS) {
+               err = HTADDR->hter & 0xffff;
+               if ((mbastat & MBAEBITS) || (err&HARD))
+                       state = 0;
+               if (bp == &rhtbuf)
+                       err &= ~FCE;
+               if ((bp->b_flags&B_READ) && (HTADDR->htds&PES))
+                       err &= ~(CS|COR);
+               if(HTADDR->htds&EOT || (HTADDR->htds&MOL)==0) {
+                       if(h_openf[unit])
+                               h_openf[unit] = -1;
+               }
+               else if(HTADDR->htds&TM) {
+                       HTADDR->htfc = 0;
+                       h_nxrec[unit] = dbtofsb(bp->b_blkno);
+                       state = SOK;
+               }
+               else if(state && err == 0)
+                       state = SOK;
+               if(httab.b_errcnt > 4)
+                       deverror(bp, HTADDR->hter, mbastat);
+               ((struct mba_regs *)MBA1)->mba_cr &= ~MBAIE;
+               HTADDR->htcs1 = DCLR|GO;
+               ((struct mba_regs *)MBA1)->mba_cr |= MBAIE;
+               if (state==SIO && ++httab.b_errcnt < 10) {
+                       httab.b_active = SRETRY;
+                       h_blkno[unit]++;
+                       HTADDR->htfc = -1;
+                       HTADDR->htcs1 = SREV|GO;
+                       return;
+               }
+               if (state!=SOK) {
+                       bp->b_flags |= B_ERROR;
+                       state = SIO;
+               }
+       } else if (HTADDR->htcs1 < 0) { /* SC */
+               if(HTADDR->htds & ERR) {
+                       ((struct mba_regs *)MBA1)->mba_cr &= ~MBAIE;
+                       HTADDR->htcs1 = DCLR|GO;
+                       ((struct mba_regs *)MBA1)->mba_cr |= MBAIE;
+               }
+       }
+       switch(state) {
+       case SIO:
+       case SOK:
+               h_blkno[unit]++;
+
+       case SCOM:
+               httab.b_errcnt = 0;
+               httab.b_actf = bp->av_forw;
+               bp->b_resid = - (HTADDR->htfc & 0xffff);
+               if (bp->b_flags & B_READ)
+                       bp->b_resid += bp->b_bcount;
+               iodone(bp);
+               break;
+
+       case SRETRY:
+               if((bp->b_flags&B_READ)==0) {
+                       httab.b_active = SSFOR;
+                       HTADDR->htcs1 = ERASE|GO;
+                       return;
+               }
+
+       case SSFOR:
+       case SSREV:
+               if(HTADDR->htds & TM) {
+                       if(state == SSREV) {
+                               h_nxrec[unit] = dbtofsb(bp->b_blkno) - (HTADDR->htfc&0xffff);
+                               h_blkno[unit] = h_nxrec[unit];
+                       } else {
+                               h_nxrec[unit] = dbtofsb(bp->b_blkno) + (HTADDR->htfc & 0xffff) - 1;
+                               h_blkno[unit] = dbtofsb(bp->b_blkno) + (HTADDR->htfc & 0xffff);
+                       }
+               } else
+                       h_blkno[unit] = dbtofsb(bp->b_blkno);
+               break;
+
+       default:
+               return;
+       }
+       htstart();
+}
+
+htread(dev)
+{
+       htphys(dev);
+       physio(htstrategy, &rhtbuf, dev, B_READ, minphys);
+}
+
+htwrite(dev)
+{
+       htphys(dev);
+       physio(htstrategy, &rhtbuf, dev, B_WRITE, minphys);
+}
+
+htphys(dev)
+{
+       register unit;
+       daddr_t a;
+
+       unit = minor(dev) & 03;
+       if(unit < NUNIT) {
+               a = u.u_offset >> 9;
+               h_blkno[unit] = dbtofsb(a);
+               h_nxrec[unit] = dbtofsb(a)+1;
+       }
+}
diff --git a/usr/src/sys/sys/iget.c b/usr/src/sys/sys/iget.c
new file mode 100644 (file)
index 0000000..54b47d5
--- /dev/null
@@ -0,0 +1,320 @@
+/*     iget.c  2.1     1/5/80  */
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/mount.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/inode.h"
+#include "../h/ino.h"
+#include "../h/filsys.h"
+#include "../h/conf.h"
+#include "../h/buf.h"
+
+/*
+ * Look up an inode by device,inumber.
+ * If it is in core (in the inode structure),
+ * honor the locking protocol.
+ * If it is not in core, read it in from the
+ * specified device.
+ * If the inode is mounted on, perform
+ * the indicated indirection.
+ * In all cases, a pointer to a locked
+ * inode structure is returned.
+ *
+ * printf warning: no inodes -- if the inode
+ *     structure is full
+ * panic: no imt -- if the mounted file
+ *     system is not in the mount table.
+ *     "cannot happen"
+ */
+struct inode *
+iget(dev, ino)
+dev_t dev;
+ino_t ino;
+{
+       register struct inode *ip;
+       register struct mount *mp;
+       register struct inode *oip;
+       register struct buf *bp;
+       register struct dinode *dp;
+
+loop:
+       oip = NULL;
+       for(ip = &inode[0]; ip < &inode[NINODE]; ip++) {
+               if(ino == ip->i_number && dev == ip->i_dev) {
+                       if((ip->i_flag&ILOCK) != 0) {
+                               ip->i_flag |= IWANT;
+                               sleep((caddr_t)ip, PINOD);
+                               goto loop;
+                       }
+                       if((ip->i_flag&IMOUNT) != 0) {
+                               for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
+                               if(mp->m_inodp == ip) {
+                                       dev = mp->m_dev;
+                                       ino = ROOTINO;
+                                       goto loop;
+                               }
+                               panic("no imt");
+                       }
+                       ip->i_count++;
+                       ip->i_flag |= ILOCK;
+                       return(ip);
+               }
+               if(oip==NULL && ip->i_count==0)
+                       oip = ip;
+       }
+       ip = oip;
+       if(ip == NULL) {
+               printf("Inode table overflow\n");
+               u.u_error = ENFILE;
+               return(NULL);
+       }
+       ip->i_dev = dev;
+       ip->i_number = ino;
+       ip->i_flag = ILOCK;
+       ip->i_count++;
+       ip->i_un.i_lastr = 0;
+       bp = bread(dev, itod(ino));
+       /*
+        * Check I/O errors
+        */
+       if((bp->b_flags&B_ERROR) != 0) {
+               brelse(bp);
+               iput(ip);
+               return(NULL);
+       }
+       dp = bp->b_un.b_dino;
+       dp += itoo(ino);
+       iexpand(ip, dp);
+       brelse(bp);
+       return(ip);
+}
+
+iexpand(ip, dp)
+register struct inode *ip;
+register struct dinode *dp;
+{
+       register char *p1;
+       char *p2;
+       int i;
+
+       ip->i_mode = dp->di_mode;
+       ip->i_nlink = dp->di_nlink;
+       ip->i_uid = dp->di_uid;
+       ip->i_gid = dp->di_gid;
+       ip->i_size = dp->di_size;
+       p1 = (char *)ip->i_un.i_addr;
+       p2 = (char *)dp->di_addr;
+       for(i=0; i<NADDR; i++) {
+               *p1++ = *p2++;
+               *p1++ = *p2++;
+               *p1++ = *p2++;
+               *p1++ = 0;
+       }
+}
+
+/*
+ * Decrement reference count of
+ * an inode structure.
+ * On the last reference,
+ * write the inode out and if necessary,
+ * truncate and deallocate the file.
+ */
+iput(ip)
+register struct inode *ip;
+{
+
+       if(ip->i_count == 1) {
+               ip->i_flag |= ILOCK;
+               if(ip->i_nlink <= 0) {
+                       itrunc(ip);
+                       ip->i_mode = 0;
+                       ip->i_flag |= IUPD|ICHG;
+                       ifree(ip->i_dev, ip->i_number);
+               }
+               iupdat(ip, &time, &time);
+               prele(ip);
+               ip->i_flag = 0;
+               ip->i_number = 0;
+       }
+       ip->i_count--;
+       prele(ip);
+}
+
+/*
+ * Check accessed and update flags on
+ * an inode structure.
+ * If any is on, update the inode
+ * with the current time.
+ */
+iupdat(ip, ta, tm)
+register struct inode *ip;
+time_t *ta, *tm;
+{
+       register struct buf *bp;
+       struct dinode *dp;
+       register char *p1;
+       char *p2;
+       int i;
+
+       if((ip->i_flag&(IUPD|IACC|ICHG)) != 0) {
+               if(getfs(ip->i_dev)->s_ronly)
+                       return;
+               bp = bread(ip->i_dev, itod(ip->i_number));
+               if (bp->b_flags & B_ERROR) {
+                       brelse(bp);
+                       return;
+               }
+               dp = bp->b_un.b_dino;
+               dp += itoo(ip->i_number);
+               dp->di_mode = ip->i_mode;
+               dp->di_nlink = ip->i_nlink;
+               dp->di_uid = ip->i_uid;
+               dp->di_gid = ip->i_gid;
+               dp->di_size = ip->i_size;
+               p1 = (char *)dp->di_addr;
+               p2 = (char *)ip->i_un.i_addr;
+               for(i=0; i<NADDR; i++) {
+                       *p1++ = *p2++;
+                       *p1++ = *p2++;
+                       *p1++ = *p2++;
+                       if(*p2++ != 0 && (ip->i_mode&IFMT)!=IFMPC
+                          && (ip->i_mode&IFMT)!=IFMPB)
+                               printf("iaddress > 2^24\n");
+               }
+               if(ip->i_flag&IACC)
+                       dp->di_atime = *ta;
+               if(ip->i_flag&IUPD)
+                       dp->di_mtime = *tm;
+               if(ip->i_flag&ICHG)
+                       dp->di_ctime = time;
+               ip->i_flag &= ~(IUPD|IACC|ICHG);
+               bdwrite(bp);
+       }
+}
+
+/*
+ * Free all the disk blocks associated
+ * with the specified inode structure.
+ * The blocks of the file are removed
+ * in reverse order. This FILO
+ * algorithm will tend to maintain
+ * a contiguous free list much longer
+ * than FIFO.
+ */
+itrunc(ip)
+register struct inode *ip;
+{
+       register i;
+       dev_t dev;
+       daddr_t bn;
+
+       if (ip->i_vfdcnt)
+               panic("itrunc");
+       i = ip->i_mode & IFMT;
+       if (i!=IFREG && i!=IFDIR)
+               return;
+       dev = ip->i_dev;
+       for(i=NADDR-1; i>=0; i--) {
+               bn = ip->i_un.i_addr[i];
+               if(bn == (daddr_t)0)
+                       continue;
+               ip->i_un.i_addr[i] = (daddr_t)0;
+               switch(i) {
+
+               default:
+                       free(dev, bn);
+                       break;
+
+               case NADDR-3:
+                       tloop(dev, bn, 0, 0);
+                       break;
+
+               case NADDR-2:
+                       tloop(dev, bn, 1, 0);
+                       break;
+
+               case NADDR-1:
+                       tloop(dev, bn, 1, 1);
+               }
+       }
+       ip->i_size = 0;
+       ip->i_flag |= ICHG|IUPD;
+}
+
+tloop(dev, bn, f1, f2)
+dev_t dev;
+daddr_t bn;
+{
+       register i;
+       register struct buf *bp;
+       register daddr_t *bap;
+       daddr_t nb;
+
+       bp = NULL;
+       for(i=NINDIR-1; i>=0; i--) {
+               if(bp == NULL) {
+                       bp = bread(dev, bn);
+                       if (bp->b_flags & B_ERROR) {
+                               brelse(bp);
+                               return;
+                       }
+                       bap = bp->b_un.b_daddr;
+               }
+               nb = bap[i];
+               if(nb == (daddr_t)0)
+                       continue;
+               if(f1) {
+                       brelse(bp);
+                       bp = NULL;
+                       tloop(dev, nb, f2, 0);
+               } else
+                       free(dev, nb);
+       }
+       if(bp != NULL)
+               brelse(bp);
+       free(dev, bn);
+}
+
+/*
+ * Make a new file.
+ */
+struct inode *
+maknode(mode)
+{
+       register struct inode *ip;
+
+       ip = ialloc(u.u_pdir->i_dev);
+       if(ip == NULL) {
+               iput(u.u_pdir);
+               return(NULL);
+       }
+       ip->i_flag |= IACC|IUPD|ICHG;
+       if((mode&IFMT) == 0)
+               mode |= IFREG;
+       ip->i_mode = mode & ~u.u_cmask;
+       ip->i_nlink = 1;
+       ip->i_uid = u.u_uid;
+       ip->i_gid = u.u_gid;
+       wdir(ip);
+       return(ip);
+}
+
+/*
+ * Write a directory entry with
+ * parameters left as side effects
+ * to a call to namei.
+ */
+wdir(ip)
+struct inode *ip;
+{
+
+       u.u_dent.d_ino = ip->i_number;
+       bcopy((caddr_t)u.u_dbuf, (caddr_t)u.u_dent.d_name, DIRSIZ);
+       u.u_count = sizeof(struct direct);
+       u.u_segflg = 1;
+       u.u_base = (caddr_t)&u.u_dent;
+       writei(u.u_pdir);
+       iput(u.u_pdir);
+}
diff --git a/usr/src/sys/sys/kl.c b/usr/src/sys/sys/kl.c
new file mode 100644 (file)
index 0000000..51d992d
--- /dev/null
@@ -0,0 +1,166 @@
+/*     kl.c    2.1     1/5/80  */
+
+#ifdef ERNIE
+/*
+ *   KL/DL-11 driver
+ */
+#include "../h/param.h"
+#include "../h/conf.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/tty.h"
+#include "../h/systm.h"
+#include "../h/map.h"
+#include "../h/pte.h"
+#include "../h/uba.h"
+
+/* base address */
+#define        KLBASE  ((struct device *)(UBA0_DEV+0176500))   /* kl and dl11-a */
+#define        DLBASE  ((struct device *)(UBA0_DEV+0175610))   /* dl-e */
+#define        NKL11   8
+#define        NDL11   0
+#define        DSRDY   02
+#define        RDRENB  01
+#define        DLDELAY 4       /* Extra delay for DL's (double buff) */
+
+#define        NL1     000400
+#define        NL2     001000
+#define        CR2     020000
+#define        FF1     040000
+#define        TAB1    002000
+
+struct tty kl_tty[NKL11+NDL11];
+int    klstart();
+int    ttrstrt();
+char   partab[];
+
+struct device {
+       short   rcsr;
+       short   rbuf;
+       short   tcsr;
+       short   tbuf;
+};
+
+/*ARGSUSED*/
+klopen(dev, flag)
+dev_t dev;
+{
+       register struct device *addr;
+       register struct tty *tp;
+       register d;
+
+       d = minor(dev);
+       if(d >= NKL11+NDL11) {
+               u.u_error = ENXIO;
+               return;
+       }
+       tp = &kl_tty[d];
+       /*
+        * set up minor 0 thru NKL11-1 to address from KLBASE
+        * set up minor NKL11 on to address from DLBASE
+        */
+       if(d<NKL11)
+               addr = KLBASE + d;
+       else
+               addr = DLBASE + (d-NKL11);
+       tp->t_addr = (caddr_t)addr;
+       tp->t_oproc = klstart;
+       if ((tp->t_state&ISOPEN) == 0) {
+               tp->t_state = ISOPEN|CARR_ON;
+               tp->t_flags = EVENP|LCASE|ECHO|XTABS|CRMOD|CR2;
+               ttychars(tp);
+       }
+       addr->rcsr |= IENABLE|DSRDY|RDRENB;
+       addr->tcsr |= IENABLE;
+       (*linesw[tp->t_line].l_open)(dev, tp);
+}
+
+klclose(dev)
+dev_t dev;
+{
+       register struct tty *tp;
+
+       tp = &kl_tty[minor(dev)];
+       (*linesw[tp->t_line].l_close)(tp);
+       ttyclose(tp);
+}
+
+klread(dev)
+dev_t dev;
+{
+       register struct tty *tp;
+
+       tp = &kl_tty[minor(dev)];
+       (*linesw[tp->t_line].l_read)(tp);
+}
+
+klwrite(dev)
+dev_t dev;
+{
+       register struct tty *tp;
+
+       tp = &kl_tty[minor(dev)];
+       (*linesw[tp->t_line].l_write)(tp);
+}
+
+klxint(dev)
+dev_t dev;
+{
+       register struct tty *tp;
+
+       tp = &kl_tty[minor(dev)];
+       if (tp->t_line)
+               (*linesw[tp->t_line].l_start)(tp);
+       else
+               ttstart(tp);
+       if ((tp->t_state&ASLEEP) && tp->t_outq.c_cc<=TTLOWAT)
+               if (tp->t_chan)
+                       mcstart(tp->t_chan, (caddr_t)&tp->t_outq);
+               else
+                       wakeup((caddr_t)&tp->t_outq);
+}
+
+klrint(dev)
+dev_t dev;
+{
+       register int c;
+       register struct device *addr;
+       register struct tty *tp;
+
+       tp = &kl_tty[minor(dev)];
+       addr = (struct device *)tp->t_addr;
+       c = addr->rbuf;
+       addr->rcsr |= RDRENB;
+       (*linesw[tp->t_line].l_rint)(c, tp);
+}
+
+/*ARGSUSED*/
+klioctl(dev, cmd, addr, flag)
+caddr_t addr;
+dev_t dev;
+{
+       if (ttioccom(cmd, &kl_tty[minor(dev)], addr, dev)==0)
+               u.u_error = ENOTTY;
+}
+
+klstart(tp)
+register struct tty *tp;
+{
+       register c;
+       register struct device *addr;
+
+       addr = (struct device *)tp->t_addr;
+       if ((addr->tcsr&DONE) == 0)
+               return;
+       if ((c=getc(&tp->t_outq)) >= 0) {
+               if (tp->t_flags&RAW)
+                       addr->tbuf = c;
+               else if (c<=0177)
+                       addr->tbuf = c | (partab[c]&0200);
+               else {
+                       timeout(ttrstrt, (caddr_t)tp, (c&0177) + DLDELAY);
+                       tp->t_state |= TIMEOUT;
+               }
+       }
+}
+#endif
diff --git a/usr/src/sys/sys/main.c b/usr/src/sys/sys/main.c
new file mode 100644 (file)
index 0000000..35e80b7
--- /dev/null
@@ -0,0 +1,214 @@
+/*     main.c  2.1     1/5/80  */
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/filsys.h"
+#include "../h/mount.h"
+#include "../h/map.h"
+#include "../h/proc.h"
+#include "../h/inode.h"
+#include "../h/seg.h"
+#include "../h/conf.h"
+#include "../h/buf.h"
+#include "../h/mtpr.h"
+#include "../h/pte.h"
+#include "../h/clock.h"
+#include "../h/vm.h"
+#include "../h/cmap.h"
+
+/*
+ * Initialization code.
+ * Called from cold start routine as
+ * soon as a stack and segmentation
+ * have been established.
+ * Functions:
+ *     clear and free user core
+ *     turn on clock
+ *     hand craft 0th process
+ *     call all initialization routines
+ *     fork - process 0 to schedule
+ *          - process 2 to page out
+ *          - process 1 execute bootstrap
+ *
+ * loop at loc 13 (0xd) in user mode -- /etc/init
+ *     cannot be executed.
+ */
+main(firstaddr)
+{
+       int i;
+
+       cpusid = mfpr(SID);             /* get system identification */
+
+       startup(firstaddr);
+       lotsfree = LOTSFREE;
+
+       /*
+        * set up system process 0 (swapper)
+        */
+
+       for(i=0; i<UPAGES; i++)
+               proc[0].p_addr[i] = firstaddr + i;
+       proc[0].p_stat = SRUN;
+       proc[0].p_flag |= SLOAD|SSYS;
+       proc[0].p_nice = NZERO;
+       u.u_procp = &proc[0];
+       u.u_cmask = CMASK;
+       clkstart();
+
+       /*
+        * Initialize devices and
+        * set up 'known' i-nodes
+        */
+
+       cinit();
+       binit();
+       bswinit();
+       iinit();
+       rootdir = iget(rootdev, (ino_t)ROOTINO);
+       rootdir->i_flag &= ~ILOCK;
+       u.u_cdir = iget(rootdev, (ino_t)ROOTINO);
+       u.u_cdir->i_flag &= ~ILOCK;
+       u.u_rdir = NULL;
+       u.u_dmap = zdmap;
+       u.u_smap = zdmap;
+
+       /*
+        * make page-out daemon (process 2)
+        * the daemon has ctopt(NSWBUF*CLSIZE) pages of page
+        * table so that it can map dirty pages into
+        * its address space during asychronuous pushes.
+        */
+
+       mpid = 1;
+       proc[0].p_szpt = clrnd(ctopt(NSWBUF*CLSIZE));
+       proc[1].p_stat = SZOMB;         /* force it to be in proc slot 2 */
+       if (newproc(0)) {
+               proc[2].p_flag |= SLOAD|SSYS;
+               proc[2].p_dsize = u.u_dsize = NSWBUF; 
+               pageout();
+       }
+
+       /*
+        * make init process and
+        * enter scheduling loop
+        */
+
+       mpid = 0;
+       proc[1].p_stat = 0;
+       proc[0].p_szpt = CLSIZE;
+       if (newproc(0)) {
+               expand(clrnd((int)btoc(szicode)), P0BR);
+               VOID copyout((caddr_t)icode, (caddr_t)0, (unsigned)szicode);
+               /*
+                * Return goes to loc. 0 of user init
+                * code just copied out.
+                */
+               return;
+       }
+       sched();
+}
+
+/*
+ * iinit is called once (from main)
+ * very early in initialization.
+ * It reads the root's super block
+ * and initializes the current date
+ * from the last modified date.
+ *
+ * panic: iinit -- cannot read the super
+ * block. Usually because of an IO error.
+ */
+iinit()
+{
+       register struct buf *cp, *bp;
+       register struct filsys *fp;
+       register unsigned i, j;
+
+       (*bdevsw[major(rootdev)].d_open)(rootdev, 1);
+       bp = bread(rootdev, SUPERB);
+       cp = geteblk();
+       if(u.u_error)
+               panic("iinit");
+       bcopy(bp->b_un.b_addr, cp->b_un.b_addr, sizeof(struct filsys));
+       brelse(bp);
+       mount[0].m_bufp = cp;
+       mount[0].m_dev = rootdev;
+       fp = cp->b_un.b_filsys;
+       fp->s_flock = 0;
+       fp->s_ilock = 0;
+       fp->s_ronly = 0;
+       fp->s_lasti = 1;
+       fp->s_nbehind = 0;
+       /* on boot, read VAX TODR register (GMT 10 ms.
+       *       clicks into current year) and set software time
+       *       in 'int time' (GMT seconds since year YRREF)
+       */
+       for (i = 0 , j = YRREF ; j < YRCURR ; j++)
+               i += (SECYR + (j%4?0:SECDAY)) ;
+       time = udiv(mfpr(TODR),100) + i ;
+       bootime = time;
+}
+
+/*
+ * This is the set of buffers proper, whose heads
+ * were declared in buf.h.  There can exist buffer
+ * headers not pointing here that are used purely
+ * as arguments to the I/O routines to describe
+ * I/O to be done-- e.g. swap headers swbuf[] for
+ * swapping.
+ */
+char   buffers[NBUF][BSIZE+BSLOP];
+
+/*
+ * Initialize the buffer I/O system by freeing
+ * all buffers and setting all device buffer lists to empty.
+ *
+ * MUST USE MEMALL HERE!!!
+ */
+binit()
+{
+       register struct buf *bp;
+       register struct buf *dp;
+       register int i;
+       struct bdevsw *bdp;
+
+       bfreelist.b_forw = bfreelist.b_back =
+           bfreelist.av_forw = bfreelist.av_back = &bfreelist;
+       for (i=0; i<NBUF; i++) {
+               bp = &buf[i];
+               bp->b_dev = NODEV;
+               bp->b_un.b_addr = buffers[i];
+               bp->b_back = &bfreelist;
+               bp->b_forw = bfreelist.b_forw;
+               bfreelist.b_forw->b_back = bp;
+               bfreelist.b_forw = bp;
+               bp->b_flags = B_BUSY;
+               brelse(bp);
+       }
+       for (bdp = bdevsw; bdp->d_open; bdp++) {
+               dp = bdp->d_tab;
+               if(dp) {
+                       dp->b_forw = dp;
+                       dp->b_back = dp;
+               }
+               nblkdev++;
+       }
+}
+
+/*
+ * Initialize linked list of free swap
+ * headers. These do not actually point
+ * to buffers, but rather to pages that
+ * are being swapped in and out.
+ */
+bswinit()
+{
+       register int i;
+
+       bswlist.av_forw = &swbuf[0];
+       for (i=0; i<NSWBUF-1; i++)
+               swbuf[i].av_forw = &swbuf[i+1];
+       swbuf[NSWBUF-1].av_forw = NULL;
+}
diff --git a/usr/src/sys/sys/malloc.c b/usr/src/sys/sys/malloc.c
new file mode 100644 (file)
index 0000000..22021ac
--- /dev/null
@@ -0,0 +1,100 @@
+/*     malloc.c        2.1     1/5/80  */
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/map.h"
+#include "../h/proc.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/mtpr.h"
+#include "../h/text.h"
+
+/*
+ * Allocate 'size' units from the given
+ * map. Return the base of the allocated
+ * space.
+ * In a map, the addresses are increasing and the
+ * list is terminated by a 0 size.
+ * The swap map unit is 512 bytes.
+ * Algorithm is first-fit.
+ */
+malloc(mp, size)
+struct map *mp;
+{
+       register int a;
+       register struct map *bp;
+
+       if (size <= 0)
+               panic("malloc");
+       for (bp=mp; bp->m_size; bp++) {
+               if (bp->m_size >= size) {
+                       a = bp->m_addr;
+                       bp->m_addr += size;
+                       if ((bp->m_size -= size) == 0) {
+                               do {
+                                       bp++;
+                                       (bp-1)->m_addr = bp->m_addr;
+                               } while ((bp-1)->m_size = bp->m_size);
+                       }
+                       if (mp == swapmap && a % CLSIZE)
+                               panic("malloc swapmap");
+                       return(a);
+               }
+       }
+       return(0);
+}
+
+/*
+ * Free the previously allocated space aa
+ * of size units into the specified map.
+ * Sort aa into map and combine on
+ * one or both ends if possible.
+ */
+mfree(mp, size, a)
+struct map *mp;
+register int size, a;
+{
+       register struct map *bp;
+       register int t;
+
+       if (a <= 0)
+               panic("mfree addr");
+       if (size <= 0)
+               panic("mfree size");
+       bp = mp;
+       for (; bp->m_addr<=a && bp->m_size!=0; bp++)
+               continue;
+       if (bp>mp && (bp-1)->m_addr+(bp-1)->m_size > a)
+               panic("mfree begov");
+       if (a+size > bp->m_addr && bp->m_size)
+               panic("mfree endov");
+       if (bp>mp && (bp-1)->m_addr+(bp-1)->m_size == a) {
+               (bp-1)->m_size += size;
+               if (a+size == bp->m_addr) {
+                       (bp-1)->m_size += bp->m_size;
+                       while (bp->m_size) {
+                               bp++;
+                               (bp-1)->m_addr = bp->m_addr;
+                               (bp-1)->m_size = bp->m_size;
+                       }
+               }
+       } else {
+               if (a+size == bp->m_addr && bp->m_size) {
+                       bp->m_addr -= size;
+                       bp->m_size += size;
+               } else if (size) {
+                       do {
+                               t = bp->m_addr;
+                               bp->m_addr = a;
+                               a = t;
+                               t = bp->m_size;
+                               bp->m_size = size;
+                               bp++;
+                       } while (size = t);
+               }
+       }
+       if ((mp == kernelmap) && kmapwnt) {
+               kmapwnt = 0;
+               wakeup((caddr_t)kernelmap);
+       }
+}
diff --git a/usr/src/sys/sys/mba.c b/usr/src/sys/sys/mba.c
new file mode 100644 (file)
index 0000000..3744aee
--- /dev/null
@@ -0,0 +1,101 @@
+/*     mba.c   2.1     1/5/80  */
+
+#include "../h/param.h"
+#include "../h/buf.h"
+#include "../h/conf.h"
+#include "../h/systm.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/proc.h"
+#include "../h/seg.h"
+#include "../h/pte.h"
+#include "../h/map.h"
+#include "../h/mba.h"
+#include "../h/mtpr.h"
+#include "../h/vm.h"
+
+/*
+ * startup routine for MBA controllers.
+ */
+#define        MBAWCOM 0x30
+#define        MBARCOM 0x38
+#define        GO      01
+
+int mbaboff;
+
+mbastart(bp, adcr)
+register struct buf *bp;
+int *adcr;
+{
+       register int i;
+       int npf;
+       unsigned v;
+       register struct pte *pte, *io;
+       int o;
+       int vaddr;
+       register struct mba_regs *mbap;
+       struct proc *rp;
+       extern int mbanum[], *mbaloc[];
+       extern char buffers[][];
+
+       mbap = (struct mba_regs *)mbaloc[mbanum[major(bp->b_dev)]];
+       if ((bp->b_flags & B_PHYS) == 0)
+               vaddr = (bp->b_un.b_addr - (char *)buffers) + mbaboff;
+       else {
+               io = (struct pte *)mbap;
+               io += (MBA_MAP + 128*4)/4;
+               v = btop(bp->b_un.b_addr);
+               o = (int)bp->b_un.b_addr & PGOFSET;
+               npf = btoc(bp->b_bcount + o);
+               rp = bp->b_flags&B_DIRTY ? &proc[2] : bp->b_proc;
+               vaddr = (128 << 9) | o;
+               if (bp->b_flags & B_UAREA) {
+                       for (i = 0; i < UPAGES; i++) {
+                               if (rp->p_addr[i] == 0)
+                                       panic("mba: zero upage");
+                               *(int *)io++ = rp->p_addr[i] | PG_V;
+                       }
+               } else if ((bp->b_flags & B_PHYS) == 0) {
+                       v &= 0x1fffff;          /* drop to physical addr */
+                       while (--npf >= 0)
+                               *(int *)io++ = v++ | PG_V;
+               } else {
+                       if (bp->b_flags & B_PAGET)
+                               pte = &Usrptmap[btokmx((struct pte *)bp->b_un.b_addr)];
+                       else
+                               pte = vtopte(rp, v);
+                       while (--npf >= 0) {
+                               if (pte->pg_pfnum == 0)
+                                       panic("mba, zero entry");
+                               *(int *)io++ = pte++->pg_pfnum | PG_V;
+                       }
+               }
+       }
+       mbap->mba_sr = -1;      /* clear status (error) bits */
+       mbap->mba_bcr = -bp->b_bcount;
+       mbap->mba_var = vaddr;
+       if (bp->b_flags & B_READ)
+               *adcr = MBARCOM | GO;
+       else
+               *adcr = MBAWCOM | GO;
+}
+
+mbainit()
+{
+       register int *io0, *io1, *b, t, j;
+       extern int *mbaloc[];
+       extern char buffers[][];
+
+       io0 = mbaloc[0] + (MBA_MAP/4);
+       io1 = mbaloc[1] + (MBA_MAP/4);
+       b = (int *)Sysmap + ((((int) buffers)>>9)&PG_PFNUM);
+       j = NBUF * CLSIZE + ((int)buffers & 0x1ff ? 1 : 0);
+       do {
+               t = PG_V | (*b++ & PG_PFNUM);
+               *io0++ = t;
+               *io1++ = t;
+       } while (--j>0);
+       *io0 = 0;               /* invalidate next entry */
+       *io1 = 0;
+       mbaboff = (int)buffers & 0x1ff;
+}
diff --git a/usr/src/sys/sys/mx1.c b/usr/src/sys/sys/mx1.c
new file mode 100644 (file)
index 0000000..388a823
--- /dev/null
@@ -0,0 +1,580 @@
+/*     mx1.c   2.1     1/5/80  */
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/reg.h"
+#include "../h/proc.h"
+#include "../h/tty.h"
+#include "../h/inode.h"
+#include "../h/mx.h"
+#include "../h/file.h"
+#include "../h/conf.h"
+
+/*
+ * Multiplexor:   clist version
+ *
+ * installation:
+ *     requires a line in cdevsw -
+ *             mxopen, mxclose, mxread, mxwrite, mxioctl, 0,
+ *
+ *     also requires a line in linesw -
+ *             mxopen, mxclose, mcread, mcwrite, mxioctl, nulldev, nulldev,
+ *
+ *     The linesw entry for mpx should be the last one in the table.
+ *     'nldisp' (number of line disciplines) should not include the
+ *     mpx line.  This is to prevent mpx from being enabled by an ioctl.
+
+ *     mxtty.c must be loaded instead of tty.c so that certain
+ *     sleeps will not be done if a typewriter is connected to
+ *     a channel and so that sdata will be called from ttyinput.
+ *     
+ */
+struct chan    chans[NCHANS];
+struct schan   schans[NPORTS];
+struct group   *groups[NGROUPS];
+int    mpxline;
+struct chan *xcp();
+dev_t  mpxdev  = -1;
+
+
+char   mcdebugs[NDEBUGS];
+
+
+/*
+ * Allocate a channel, set c_index to index.
+ */
+struct chan *
+challoc(index, isport)
+{
+register s,i;
+register struct chan *cp;
+
+       s = spl6();
+       for(i=0;i<((isport)?NPORTS:NCHANS);i++) {
+               cp = (isport)? (struct chan *)(schans+i): chans+i;
+               if(cp->c_group == NULL) {
+                       cp->c_index = index;
+                       cp->c_pgrp = 0;
+                       cp->c_flags = 0;
+                       splx(s);
+                       return(cp);
+               }
+       }
+       splx(s);
+       return(NULL);
+}
+
+
+
+/*
+ * Allocate a group table cell.
+ */
+gpalloc()
+{
+       register i;
+
+       for (i=NGROUPS-1; i>=0; i--)
+               if (groups[i]==NULL) {
+                       groups[i]++;
+                       return(i);
+               }
+       u.u_error = ENXIO;
+       return(i);
+}
+
+
+/*
+ * Add a channel to the group in
+ * inode ip.
+ */
+struct chan *
+addch(ip, isport)
+struct inode *ip;
+{
+register struct chan *cp;
+register struct group *gp;
+register i;
+
+       plock(ip);
+       gp = &ip->i_un.i_group;
+       for(i=0;i<NINDEX;i++) {
+               cp = (struct chan *)gp->g_chans[i];
+               if (cp == NULL) {
+                       if ((cp=challoc(i, isport)) != NULL) {
+                               gp->g_chans[i] = cp;
+                               cp->c_group = gp;
+                       }
+                       break;
+               }
+               cp = NULL;
+       }
+       prele(ip);
+       return(cp);
+}
+
+/*
+ * Mpxchan system call.
+ */
+
+mpxchan()
+{
+       extern  mxopen(), mcread(), sdata(), scontrol();
+       struct  inode   *ip, *gip;
+       struct  tty     *tp;
+       struct  file    *fp, *chfp, *gfp;
+       struct  chan    *cp;
+       struct  group   *gp, *ngp;
+       struct  mx_args vec;
+       struct  a       {
+               int     cmd;
+               int     *argvec;
+       } *uap;
+       dev_t   dev;
+       register int i;
+
+       /*
+        * Common setup code.
+        */
+
+       uap = (struct a *)u.u_ap;
+       VOID copyin((caddr_t)uap->argvec, (caddr_t)&vec, sizeof vec);
+       gp = NULL; gfp = NULL; cp = NULL;
+
+       switch(uap->cmd) {
+
+       case NPGRP:
+               if (vec.m_arg[1] < 0)
+                       break;
+       case CHAN:
+       case JOIN:
+       case EXTR:
+       case ATTACH:
+       case DETACH:
+       case CSIG:
+               gfp = getf(vec.m_arg[1]);
+               if (gfp==NULL)
+                       return;
+               gip = gfp->f_inode;
+               gp = &gip->i_un.i_group;
+               if (gp->g_inode != gip) {
+                       u.u_error = ENXIO;
+                       return;
+               }
+       }
+
+       switch(uap->cmd) {
+
+       /*
+        * Create an MPX file.
+        */
+
+       case MPX:
+       case MPXN:
+               if (mpxdev < 0) {
+                       for (i=0; linesw[i].l_open; i++) {
+                               if (linesw[i].l_read==mcread) {
+                                       mpxline = i;
+                                       for (i=0; cdevsw[i].d_open; i++) {
+                                               if (cdevsw[i].d_open==mxopen) {
+                                                       mpxdev = (dev_t)(i<<8);
+                                               }
+                                       }
+                               }
+                       }
+                       if (mpxdev < 0) {
+                               u.u_error = ENXIO;
+                               return;
+                       }
+               }
+               if (uap->cmd==MPXN) {
+                       if ((ip=ialloc(pipedev))==NULL)
+                               return;
+                       ip->i_mode = ((vec.m_arg[1]&0777)+IFMPC) & ~u.u_cmask;
+                       ip->i_flag = IACC|IUPD|ICHG;
+               } else {
+                       u.u_dirp = vec.m_name;
+                       ip = namei(uchar,1);
+                       if (ip != NULL) {
+                               i = ip->i_mode&IFMT;
+                               u.u_error = EEXIST;
+                               if (i==IFMPC || i==IFMPB) {
+                                       i = minor(ip->i_un.i_rdev);
+                                       gp = groups[i];
+                                       if (gp && gp->g_inode==ip)
+                                               u.u_error = EBUSY;
+                               }
+                               iput(ip);
+                               return;
+                       }
+                       if (u.u_error)
+                               return;
+                       ip = maknode((vec.m_arg[1]&0777)+IFMPC);
+                       if (ip == NULL)
+                               return;
+               }
+               if ((i=gpalloc()) < 0) {
+                       iput(ip);
+                       return;
+               }
+               if ((fp=falloc()) == NULL) {
+                       iput(ip);
+                       groups[i] = NULL;
+                       return;
+               }
+               ip->i_un.i_rdev = (daddr_t)(mpxdev+i);
+               ip->i_count++;
+               prele(ip);
+
+               gp = &ip->i_un.i_group;
+               groups[i] = gp;
+               gp->g_inode = ip;
+               gp->g_state = INUSE|ISGRP;
+               gp->g_group = NULL;
+               gp->g_file = fp;
+               gp->g_index = 0;
+               gp->g_rotmask = 1;
+               gp->g_rot = 0;
+               gp->g_datq = 0;
+               for(i=0;i<NINDEX;)
+                       gp->g_chans[i++] = NULL;
+
+               fp->f_flag = FREAD|FWRITE|FMP;
+               fp->f_inode = ip;
+               fp->f_un.f_chan = NULL;
+               return;
+
+       /*
+        * join file descriptor (arg 0) to group (arg 1)
+        * return channel number
+        */
+
+       case JOIN:
+               if ((fp=getf(vec.m_arg[0]))==NULL)
+                       return;
+               ip = fp->f_inode;
+               switch (ip->i_mode & IFMT) {
+
+               case IFMPC:
+                       if ((fp->f_flag&FMP) != FMP) {
+                               u.u_error = ENXIO;
+                               return;
+                       }
+                       ngp = &ip->i_un.i_group;
+                       if (mtree(ngp, gp) == NULL)
+                               return;
+                       fp->f_count++;
+                       u.u_r.r_val1 = cpx(ngp);
+                       return;
+
+               case IFCHR:
+                       dev = (dev_t)ip->i_un.i_rdev;
+                       tp = cdevsw[major(dev)].d_ttys;
+                       if (tp==NULL) {
+                               u.u_error = ENXIO;
+                               return;
+                       }
+                       tp = &tp[minor(dev)];
+                       if (tp->t_chan) {
+                               u.u_error = ENXIO;
+                               return;
+                       }
+                       if ((cp=addch(gip, 1))==NULL) {
+                               u.u_error = ENXIO;
+                               return;
+                       }
+                       tp->t_chan = cp;
+                       cp->c_fy = fp;
+                       fp->f_count++;
+                       cp->c_ttyp = tp;
+                       cp->c_line = tp->t_line;
+                       cp->c_flags = XGRP+PORT;
+                       u.u_r.r_val1 = cpx(cp);
+                       return;
+
+               default:
+                       u.u_error = ENXIO;
+                       return;
+
+               }
+
+       /*
+        * Attach channel (arg 0) to group (arg 1).
+        */
+
+       case ATTACH:
+               cp = xcp(gp, vec.m_arg[0]);
+               if (cp==NULL || cp->c_flags&ISGRP) {
+                       u.u_error = ENXIO;
+                       return;
+               }
+               u.u_r.r_val1 = cpx(cp);
+               wakeup((caddr_t)cp);
+               return;
+
+       case DETACH:
+               cp = xcp(gp, vec.m_arg[0]);
+               if (cp==NULL) {
+                       u.u_error = ENXIO;
+                       return;
+               }
+               detach(cp);
+               return;
+
+       /*
+        * Extract channel (arg 0) from group (arg 1).
+        */
+
+       case EXTR:
+               cp = xcp(gp, vec.m_arg[0]);
+               if (cp==NULL) {
+                       u.u_error = ENXIO;
+                       return;
+               }
+               if (cp->c_flags & ISGRP) {
+                       VOID mxfalloc(((struct group *)cp)->g_file);
+                       return;
+               }
+               if ((fp=cp->c_fy) != NULL) {
+                       VOID mxfalloc(fp);
+                       return;
+               }
+               if ((fp=falloc()) == NULL)
+                       return;
+               fp->f_inode = gip;
+               gip->i_count++;
+               fp->f_un.f_chan = cp;
+               fp->f_flag = (vec.m_arg[2]) ?
+                               (FREAD|FWRITE|FMPY) : (FREAD|FWRITE|FMPX);
+               cp->c_fy = fp;
+               return;
+
+       /*
+        * Make new chan on group (arg 1).
+        */
+
+       case CHAN:
+               if((gfp->f_flag&FMP)==FMP)cp = addch(gip, 0);
+                       if(cp == NULL){
+                       u.u_error = ENXIO;
+                       return;
+                       }
+               cp->c_flags = XGRP;
+               cp->c_fy = NULL;
+               cp->c_ttyp = cp->c_ottyp = (struct tty *)cp;
+               cp->c_line = cp->c_oline = mpxline;
+               u.u_r.r_val1 = cpx(cp);
+               return;
+
+       /*
+        * Connect fd (arg 0) to channel fd (arg 1).
+        * (arg 2 <  0) => fd to chan only
+        * (arg 2 >  0) => chan to fd only
+        * (arg 2 == 0) => both directions
+        */
+
+       case CONNECT:
+               if ((fp=getf(vec.m_arg[0]))==NULL)
+                       return;
+               if ((chfp=getf(vec.m_arg[1]))==NULL)
+                       return;
+               ip = fp->f_inode;
+               i = ip->i_mode&IFMT;
+               if (i!=IFCHR) {
+                       u.u_error = ENXIO;
+                       return;
+               }
+               dev = (dev_t)ip->i_un.i_rdev;
+               tp = cdevsw[major(dev)].d_ttys;
+               if (tp==NULL) {
+                       u.u_error = ENXIO;
+                       return;
+               }
+               tp = &tp[minor(dev)];
+               if (!(chfp->f_flag&FMPY)) {
+                       u.u_error = ENXIO;
+                       return;
+               }
+               cp = chfp->f_un.f_chan;
+               if (cp==NULL || cp->c_flags&PORT) {
+                       u.u_error = ENXIO;
+                       return;
+               }
+               i = vec.m_arg[2];
+               if (i>=0) {
+                       cp->c_ottyp = tp;
+                       cp->c_oline = tp->t_line;
+               }
+               if (i<=0)  {
+                       tp->t_chan = cp;
+                       cp->c_ttyp = tp;
+                       cp->c_line = tp->t_line;
+               }
+               u.u_r.r_val1 = 0;
+               return;
+
+       case NPGRP: {
+               register struct proc *pp;
+
+               if (gp != NULL) {
+                       cp = xcp(gp, vec.m_arg[0]);
+                       if (cp==NULL) {
+                               u.u_error = ENXIO;
+                               return;
+                       }
+               }
+               pp = u.u_procp;
+               pp->p_pgrp = pp->p_pid;
+               if (vec.m_arg[2])
+                       pp->p_pgrp = vec.m_arg[2];
+               if (gp != NULL)
+                       cp->c_pgrp = pp->p_pgrp;
+               u.u_r.r_val1 = pp->p_pgrp;
+               return;
+       }
+
+       case CSIG:
+               cp = xcp(gp, vec.m_arg[0]);
+               if (cp==NULL) {
+                       u.u_error = ENXIO;
+                       return;
+               }
+               signal(cp->c_pgrp, vec.m_arg[2]);
+               u.u_r.r_val1 = vec.m_arg[2];
+               return;
+
+       case DEBUG:
+               i = vec.m_arg[0];
+               if (i<0 || i>NDEBUGS)
+                       return;
+               mcdebugs[i] = vec.m_arg[1];
+               if (i==ALL)
+                       for(i=0;i<NDEBUGS;i++)
+                               mcdebugs[i] = vec.m_arg[1];
+               return;
+
+       default:
+               u.u_error = ENXIO;
+               return;
+       }
+
+}
+detach(cp)
+register struct chan *cp;
+{
+       register struct group *master,*sub;
+       register index;
+
+       if (cp->c_flags&ISGRP) {
+               sub = (struct group *)cp;
+               master = sub->g_group;  index = sub->g_index;
+               closef(sub->g_file);
+               master->g_chans[index] = NULL;
+               return;
+       } else if (cp->c_flags&PORT && cp->c_ttyp != NULL) {
+               closef(cp->c_fy);
+               chdrain(cp);
+               chfree(cp);
+               return;
+       }
+       if (cp->c_fy && (cp->c_flags&WCLOSE)==0) {
+               cp->c_flags |= WCLOSE;
+               chwake(cp);
+       } else {
+               chdrain(cp);
+               chfree(cp);
+       }
+}
+
+
+mxfalloc(fp)
+register struct file *fp;
+{
+register i;
+
+       if (fp==NULL) {
+               u.u_error = ENXIO;
+               return(-1);
+       }
+       i = ufalloc();
+       if (i < 0)
+               return(i);
+       u.u_ofile[i] = fp;
+       fp->f_count++;
+       u.u_r.r_val1 = i;
+       return(i);
+}
+
+/*
+ * Grow a branch on a tree.
+ */
+
+mtree(sub,master)
+register struct group *sub, *master;
+{
+       register i;
+       int mtresiz, stresiz;
+
+       if ((mtresiz=mup(master,sub)) == NULL) {
+               u.u_error = ENXIO;
+               return(NULL);
+       }
+       if ((stresiz=mdown(sub,master)) <= 0) {
+               u.u_error = ENXIO;
+               return(NULL);
+       }
+       if (sub->g_group != NULL) {
+               u.u_error = ENXIO;
+               return(NULL);
+       }
+       if (stresiz+mtresiz > NLEVELS) {
+               u.u_error = ENXIO;
+               return(NULL);
+       }
+       for (i=0;i<NINDEX;i++) {
+               if (master->g_chans[i] != NULL)
+                       continue;
+               master->g_chans[i] = (struct chan *)sub;
+               sub->g_group = master;
+               sub->g_index = i;
+               return(1);
+       }
+       u.u_error = ENXIO;
+       return(NULL);
+}
+
+mup(master,sub)
+struct group *master, *sub;
+{
+       register struct group *top;
+       register int depth;
+
+       depth = 1;  top = master;
+       while (top->g_group) {
+               depth++;
+               top = top->g_group;
+       }
+       if(top == sub)
+               return(NULL);
+       return(depth);
+}
+
+
+mdown(sub,master)
+struct group *sub, *master;
+{
+       register int maxdepth, i, depth;
+
+       if(sub == (struct group *)NULL || (sub->g_state&ISGRP) == 0)
+               return(0);
+       if(sub == master)
+               return(-1);
+       maxdepth = 0;
+       for(i=0; i<NINDEX; i++) {
+               if((depth=mdown(sub->g_chans[i],master)) == -1)
+                       return(-1);
+               maxdepth = (depth>maxdepth) ? depth: maxdepth;
+       }
+       return(maxdepth+1);
+}
diff --git a/usr/src/sys/sys/mx2.c b/usr/src/sys/sys/mx2.c
new file mode 100644 (file)
index 0000000..482ea87
--- /dev/null
@@ -0,0 +1,906 @@
+/*     mx2.c   2.1     1/5/80  */
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/proc.h"
+#include "../h/tty.h"
+#include "../h/inode.h"
+#include "../h/mx.h"
+#include "../h/file.h"
+#include "../h/conf.h"
+#include "../h/buf.h"
+/*
+ * multiplexor driver
+ */
+struct chan    chans[NCHANS];
+struct group   *groups[NGROUPS];
+int    mpxline;
+
+short  cmask[16]       ={
+       01,     02,     04,
+       010,    020,    040,
+       0100,   0200,   0400,
+       01000,  02000,  04000,
+       010000, 020000, 040000, 0100000
+};
+
+#define        IOMOVE  iomove
+#define        FPEND   &file[NFILE]
+struct chan *xcp(),*addch(),*nextcp();
+
+#define        HIQ     100
+#define        LOQ     20
+#define        MIN(a,b)        ((a<b)?a:b)
+#define        FP      ((struct file *)cp)
+
+char mcdebugs[NDEBUGS];
+
+struct group *
+getmpx(dev)
+dev_t dev;
+{
+       register d;
+
+       d = minor(dev);
+       if (d >= NGROUPS) {
+               u.u_error = ENXIO;
+               return(NULL);
+       }
+       return(groups[d]);
+}
+
+
+/*ARGSUSED*/
+mxopen(dev, flag)
+{
+       register struct group *gp;
+       register struct file *fp;
+       register struct chan *cp;
+       int     msg;
+
+       if ((gp=getmpx(dev)) == NULL) {
+               return;
+       }
+       if (!(gp->g_state&INUSE)) {
+               u.u_error = ENXIO;
+               return;
+       }
+       fp = u.u_ofile[u.u_r.r_val1];
+       if (fp->f_inode != gp->g_inode) {
+               u.u_error = ENXIO;
+               return;
+       }
+       if ((cp=addch(gp->g_inode,0)) == NULL) {
+               u.u_error = ENXIO;
+               return;
+       }
+
+       cp->c_flags = XGRP;
+       cp->c_ottyp = cp->c_ttyp = (struct tty *)cp;
+       cp->c_line = cp->c_oline = mpxline;
+
+       fp->f_flag |= FMPY;
+       fp->f_flag |= FREAD+FWRITE;
+       fp->f_un.f_chan = cp;
+
+       if (gp->g_inode == mpxip) {
+               plock(mpxip);
+               mpxname(cp);
+               msg = M_OPEN;
+       } else
+               msg = M_WATCH;
+
+       scontrol(cp, msg+(cp->c_index<<8), u.u_uid);
+       sleep((caddr_t)cp,TTIPRI);
+       if (cp->c_flags&NMBUF)
+               prele(mpxip);
+       if (cp->c_flags & WCLOSE) {
+               chdrain(cp);
+               chfree(cp);
+               u.u_error = ENXIO;
+               return;
+       }
+       cp->c_fy = fp;
+       cp->c_pgrp = u.u_procp->p_pgrp;
+}
+
+
+char   mxnmbuf[NMSIZE];
+int    nmsize;
+
+mpxname(cp)
+register struct chan *cp;
+{
+       register char *np;
+       register c;
+
+       np = mxnmbuf;
+       u.u_dirp = (caddr_t)u.u_arg[0];
+       
+       while (np < &mxnmbuf[NMSIZE]) {
+               c = uchar();
+               if (c <= 0)
+                       break;
+               *np++ = c;
+       }
+       *np++ = '\0';
+       nmsize = np - mxnmbuf;
+
+       cp->c_flags |= NMBUF;
+}
+
+
+mxclose(dev, flag, cp)
+dev_t  dev;
+register struct chan *cp;
+{
+register struct group *gp;
+register struct inode *ip;
+register struct file *fp;
+int    i, fmp;
+
+       fmp = flag&FMP;
+
+       /*
+        * close a channel
+        */
+       if (cp!=NULL && fmp && fmp!=FMP) {
+               for(fp=file; fp< FPEND; fp++)
+                   if(fp->f_count && fp->f_flag&FMP && fp->f_un.f_chan==cp){
+                               return;
+                       }
+               chdrain(cp);
+               if ((cp->c_flags&WCLOSE)==0) {
+                       scontrol(cp, M_CLOSE, 0);
+                       cp->c_flags |= WCLOSE;
+               } else {
+                       chfree(cp);
+               }
+               return;
+       }
+
+       if ((gp=getmpx(dev)) == NULL)
+               return;
+
+       ip = gp->g_inode;
+       if (ip==NULL || (ip->i_mode&IFMT)!=IFMPC) {
+               return;
+       }
+
+       for(fp=file; fp < FPEND; fp++) {
+               if (fp->f_count && (fp->f_flag&FMP)==FMP && fp->f_inode==ip) {
+                       return;
+               }
+       }
+
+       if (ip == mpxip) {
+               mpxip = NULL;
+               prele(ip);
+       }
+
+       for(i=0;i<NINDEX;i++)
+               if ((cp=gp->g_chans[i])!=NULL)
+                       detach(cp);
+
+       groups[minor(dev)] = NULL;
+       plock(ip);
+       zero((caddr_t)gp, sizeof (struct group));
+       ip->i_mode = IFREG + 0666;
+       ip->i_un.i_rdev = 0;
+       ip->i_flag |= IUPD|ICHG;
+       iput(ip);
+}
+
+zero(s, cc)
+register char *s;
+register cc;
+{
+       while (cc--)
+               *s++ = 0;
+}
+
+char   m_eot[] ={ M_EOT, 0, 0, 0};
+
+/*
+ * Mxread + mxwrite are entered from cdevsw
+ * for all read/write calls.  Operations on
+ * an mpx file are handled here.
+ * Calls are made through linesw to handle actual
+ * data movement.
+ */
+mxread(dev)
+{
+       register struct group *gp;
+       register struct chan *cp;
+       register esc;
+       struct rh h;
+       caddr_t base;
+       unsigned count;
+       int s, xfr, more, fmp;
+
+       if ((gp=getmpx(dev))==NULL || (FP=getf(u.u_arg[0]))==NULL) {
+               return;
+       }
+
+       fmp = FP->f_flag & FMP;
+       if (fmp != FMP) {
+               msread(fmp, FP->f_un.f_chan);
+               return;
+       }
+
+       if ((int)u.u_base & 1) {
+               u.u_error = ENXIO;
+               return;
+       }
+
+       s = spl6();
+       while (gp->g_datq == 0) {
+               sleep((caddr_t)&gp->g_datq, TTIPRI);
+       }
+       splx(s);
+
+       while (gp->g_datq && u.u_count >= CNTLSIZ + 2) {
+               esc = 0;
+               cp = nextcp(gp);
+               if (cp==NULL) {
+                       continue;
+               }
+               h.index = cpx(cp);
+               if (count = cp->c_ctlx.c_cc) {
+                       count += CNTLSIZ;
+                       if (cp->c_flags&NMBUF)
+                               count += nmsize;
+                       if (count > u.u_count) {
+                               VOID sdata(cp);
+                               return;
+                       }
+                       esc++;
+               }
+               base = u.u_base;
+               count = u.u_count;
+               u.u_base += sizeof h;
+               u.u_count -= sizeof h;
+               xfr = u.u_count;
+               if (esc) {
+                       more = mcread(cp);
+               } else {
+                       more = (*linesw[cp->c_line].l_read)(cp->c_ttyp);
+               }
+               if (more > 0)
+                       VOID sdata(cp);
+               if (more < 0)
+                       scontrol(cp, M_CLOSE, 0);
+               VOID spl0();
+               if (xfr == u.u_count) {
+                       esc++;
+                       IOMOVE((caddr_t)m_eot, sizeof m_eot, B_READ);
+               }
+               xfr -= u.u_count;
+               if (esc) {
+                       h.count = 0;
+                       h.ccount = xfr;
+               } else {
+                       h.count = xfr;
+                       h.ccount = 0;
+                       mxrstrt(cp, &cp->cx.datq, BLOCK|ALT);
+               }
+               if (u.u_count && (xfr&1)) {
+                       u.u_base++;
+                       u.u_count--;
+               }
+               VOID copyout((caddr_t)&h, base, sizeof h);
+
+       }
+}
+
+
+mxwrite(dev)
+{
+register struct chan *cp;
+struct wh h;
+struct group *gp;
+int    ucount, esc, fmp, burpcount;
+caddr_t        ubase, hbase;
+
+       if ((gp=getmpx(dev))==NULL || (FP=getf(u.u_arg[0]))==NULL) {
+               return;
+       }
+       fmp = FP->f_flag & FMP;
+       if (fmp != FMP) {
+               mswrite(fmp, FP->f_un.f_chan);
+               return;
+       }
+
+       burpcount = 0;
+       while (u.u_count >= sizeof h) {
+               hbase = u.u_base;
+               IOMOVE((caddr_t)&h, sizeof h, B_WRITE);
+               if (u.u_error)
+                       return;
+               esc = 0;
+               if (h.count==0) {
+                       esc++;
+                       h.count = h.ccount;
+               }
+               cp = xcp(gp, h.index);
+               if (cp==NULL || cp->c_flags&ISGRP) {
+                       u.u_error = ENXIO;
+                       return;
+               }
+               ucount = u.u_count;
+               ubase = u.u_base;
+               u.u_count = h.count;
+               u.u_base = h.data;
+
+               if (esc==0) {
+                       struct tty *tp;
+                       caddr_t waddr;
+                       int line;
+
+                       if (cp->c_flags&PORT) {
+                               line = cp->c_line;
+                               tp = cp->c_ttyp;
+                       } else {
+                               line = cp->c_oline;
+                               tp = cp->c_ottyp;
+                       }
+               loop:
+                       waddr = (caddr_t)(*linesw[line].l_write)(tp);
+                       if (u.u_count) {
+                               if (gp->g_state&ENAMSG) {
+                                       burpcount++;
+                                       cp->c_flags |= BLKMSG;
+/*
+                                       scontrol(cp, M_BLK, u.u_count);
+*/
+                                       h.ccount = -1;
+                                       h.count = u.u_count;
+                                       h.data = u.u_base;
+                                       VOID copyout((caddr_t)&h, hbase, sizeof h);
+                               } else {
+                                       if(waddr == 0) {
+                                               u.u_error = ENXIO;
+                                               return;
+                                       }
+                                       sleep(waddr, TTOPRI);
+                                       goto loop;
+                               }
+                       }
+               } else {
+                       mxwcontrol(cp); 
+               }
+               u.u_count = ucount;
+               u.u_base = ubase;
+       }
+       u.u_count = burpcount;
+}
+
+
+
+/*
+ * Mcread and mcwrite move data on an mpx file.
+ * Transfer addr and length is controlled by mxread/mxwrite.
+ * Kernel-to-Kernel and other special transfers are not
+ * yet in.
+ */
+mcread(cp)
+register struct chan *cp;
+{
+register struct clist *q;
+register char *np;
+
+
+       q = (cp->c_ctlx.c_cc) ? &cp->c_ctlx : &cp->cx.datq;
+       VOID mxmove(q, B_READ);
+
+       if (cp->c_flags&NMBUF && q == &cp->c_ctlx) {
+               np = mxnmbuf;
+               while (nmsize--)
+                       VOID passc(*np++);
+               cp->c_flags &= ~NMBUF;
+               prele(mpxip);
+       }
+       if (cp->c_flags&PORT)
+               return(cp->c_ctlx.c_cc + cp->c_ttyp->t_rawq.c_cc); else
+               return(cp->c_ctlx.c_cc + cp->cx.datq.c_cc);
+
+}
+
+
+caddr_t
+mcwrite(cp)
+register struct chan *cp;
+{
+register struct clist *q;
+int    s;
+
+       q = &cp->cy.datq;
+       while (u.u_count) {
+               s = spl6();
+               if (q->c_cc > HIQ || (cp->c_flags&EOTMARK)) {
+                       cp->c_flags |= SIGBLK;
+                       splx(s);
+                       break;
+               }
+               splx(s);
+               VOID mxmove(q, B_WRITE);
+       }
+       wakeup((caddr_t)q);
+       return((caddr_t)q);
+}
+
+
+/*
+ * Msread and mswrite move bytes
+ * between user and non-multiplexed channel.
+ */
+msread(fmp, cp)
+register struct chan *cp;
+{
+register struct clist *q;
+int s;
+
+       q = (fmp&FMPX) ? &cp->cx.datq : &cp->cy.datq;
+       s = spl6();
+       while (q->c_cc == 0) {
+               if (cp->c_flags & EOTMARK) {
+                       cp->c_flags &= ~EOTMARK;
+                       if(msgenab(cp))
+                               scontrol(cp, M_UBLK, 0);
+                       else {
+                               wakeup((caddr_t)cp);
+                               wakeup((caddr_t)q);
+                       }
+                       goto out;
+               }
+               if (cp->c_flags&WCLOSE) {
+                       u.u_error = ENXIO;
+                       goto out;
+               }
+               sleep((caddr_t)q,TTIPRI);
+       }
+       splx(s);
+       while (mxmove(q, B_READ) > 0)
+               ;
+       mxrstrt(cp, q, SIGBLK);
+       return;
+out:
+       splx(s);
+}
+
+
+mswrite(fmp, cp)
+register struct chan *cp;
+{
+       register struct clist *q;
+       register int cc;
+
+       q = (fmp&FMPX) ? &cp->cy.datq : &cp->cx.datq;
+       while (u.u_count) {
+               VOID spl6();
+               if (cp->c_flags&WCLOSE) {
+                       signal(cp->c_pgrp, SIGPIPE);
+                       VOID spl0();
+                       return;
+               }
+               if (q->c_cc>= HIQ || cp->c_flags&FBLOCK) {
+                       if (cp->c_flags&WCLOSE) {
+                               signal(cp->c_pgrp, SIGPIPE);
+                               VOID spl0();
+                               return;
+                       }
+                       VOID sdata(cp);
+                       cp->c_flags |= BLOCK;
+                       sleep((caddr_t)q+1,TTOPRI);
+                       VOID spl0();
+                       continue;
+               }
+               VOID spl0();
+               cc = mxmove(q, B_WRITE);
+               if (cc < 0)
+                       break;
+       }
+       if (fmp&FMPX) {
+               if (cp->c_flags&YGRP)  VOID sdata(cp);
+               else                   wakeup((caddr_t)q);
+       } else {
+               if (cp->c_flags&XGRP)  VOID sdata(cp);
+               else                   wakeup((caddr_t)q);
+       }
+}
+
+
+/*
+ * move chars between clist and user space.
+ */
+
+mxmove(q, dir)
+register struct clist *q;
+register dir;
+{
+register cc;
+char cbuf[HIQ];
+
+       cc = MIN(u.u_count, sizeof cbuf);
+       if (dir == B_READ) 
+               cc = q_to_b(q, cbuf, cc);
+       if (cc <= 0)
+               return(cc);
+       IOMOVE((caddr_t)cbuf, (unsigned)cc, dir);
+       if (dir == B_WRITE)
+               cc = b_to_q(cbuf, cc, q);
+       return(cc);
+}
+
+
+
+mxrstrt(cp, q, b)
+register struct chan *cp;
+register struct clist *q;
+register b;
+{
+int s;
+
+       s = spl6();
+       if (cp->c_flags&b && q->c_cc<LOQ) {
+               cp->c_flags &= ~b;
+               if (b&ALT)
+                       wakeup((caddr_t)q+1); else
+                       mcstart(cp, (caddr_t)q);
+       }
+       if (cp->c_flags&WFLUSH)
+               wakeup((caddr_t)q+2);
+       splx(s);
+}
+
+
+
+/*
+ * called from driver start or xint routines
+ * to wakeup output sleeper.
+ */
+mcstart(cp, q)
+register struct chan *cp;
+register caddr_t q;
+{
+
+       if (cp->c_flags&(BLKMSG)) {
+               cp->c_flags &= ~BLKMSG;
+               scontrol(cp, M_UBLK, 0);
+       } else
+               wakeup((caddr_t)q);
+}
+
+
+mxwcontrol(cp)
+register struct chan *cp;
+{
+short cmd;
+struct ttiocb vec;
+int    s;
+
+       IOMOVE((caddr_t)&cmd, sizeof cmd, B_WRITE);
+       if (u.u_error)
+               return;
+       switch(cmd) {
+       /*
+        * not ready to queue this up yet.
+        */
+       case M_EOT:
+               s = spl6();
+               while (cp->c_flags & EOTMARK)
+                       if(msgenab(cp)){
+                               scontrol(cp, M_BLK, 0);
+                               goto out;
+                       } else
+                               sleep((caddr_t)cp, TTOPRI);
+                               cp->c_flags |= EOTMARK;
+       out:
+               wakeup((caddr_t)&cp->cy.datq);
+               splx(s);
+               break;
+       case M_IOCTL:
+               break;
+       case M_IOANS:
+               if (cp->c_flags&SIOCTL) {
+                       IOMOVE((caddr_t)&vec, sizeof vec, B_WRITE);
+                       VOID b_to_q((caddr_t)&vec, sizeof vec, &cp->c_ctly);
+                       cp->c_flags &= ~SIOCTL;
+                       wakeup((caddr_t)cp);
+               }
+               break;
+       case M_BLK:
+               cp->c_flags |= FBLOCK;
+               break;
+       case M_UBLK:
+               cp->c_flags &= ~FBLOCK;
+               chwake(cp);
+               break;
+       default:
+               u.u_error = ENXIO;
+       }
+}
+
+
+
+/*ARGSUSED*/
+mxioctl(dev, cmd, addr, flag)
+caddr_t addr;
+{
+struct group *gp;
+int fmp;
+struct file *fp;
+struct {
+       short c_ctl;
+       short c_cmd;
+       struct ttiocb c_vec;
+} ctlbuf;
+
+       if ((gp=getmpx(dev))==NULL || (fp=getf(u.u_arg[0]))==NULL) {
+               return;
+       }
+
+       fmp = fp->f_flag & FMP;
+       if (fmp == FMP) {
+               switch(cmd) {
+
+               case MXLSTN:
+                       if (mpxip == NULL) {
+                               mpxip = gp->g_inode;
+                       } else {
+                               u.u_error = ENXIO;
+                               return;
+                       }
+                       break;
+
+               case MXNBLK:
+                       gp->g_state |= ENAMSG;
+                       break;
+
+               default:
+                       u.u_error = ENXIO;
+                       return;
+               }
+       } else {
+               ctlbuf.c_ctl = M_IOCTL;
+               ctlbuf.c_cmd = cmd;
+               VOID copyin(addr, (caddr_t)&ctlbuf.c_vec, sizeof (struct ttiocb));
+               sioctl(fp->f_un.f_chan, (char *)&ctlbuf, sizeof ctlbuf);
+               VOID copyout((caddr_t)&ctlbuf, addr, sizeof (struct ttiocb));
+       }
+}
+
+
+chdrain(cp)
+register struct chan *cp;
+{
+register struct tty *tp;
+int wflag;
+
+       chwake(cp);
+
+       wflag = (cp->c_flags&WCLOSE)==0;
+       tp = cp->c_ttyp;
+       if (tp == NULL)         /* prob not required */
+               return;
+       if (cp->c_flags&PORT && tp->t_chan == cp) {
+               cp->c_ttyp = NULL;
+               tp->t_chan = NULL;
+               return;
+       }
+       if (wflag) 
+               wflush(cp,&cp->cx.datq); else
+               flush(&cp->cx.datq);
+       if (!(cp->c_flags&YGRP)) {
+               flush(&cp->cy.datq);
+       }
+}
+
+chwake(cp)
+register struct chan *cp;
+{
+register char *p;
+
+       wakeup((caddr_t)cp);
+       flush(&cp->c_ctlx);
+       p = (char *)&cp->cx.datq;
+       wakeup((caddr_t)p); wakeup((caddr_t)++p); wakeup((caddr_t)++p);
+       p = (char *)&cp->cy.datq;
+       wakeup((caddr_t)p); wakeup((caddr_t)++p); wakeup((caddr_t)++p);
+}
+
+
+chfree(cp)
+register struct chan *cp;
+{
+register struct group *gp;
+register i;
+
+       gp = cp->c_group;
+       if (gp==NULL)
+               return;
+       i = cp->c_index;
+       if (cp == gp->g_chans[i]) {
+               gp->g_chans[i] = NULL;
+       }
+       cp->c_group = NULL;
+}
+
+
+flush(q)
+register struct clist *q;
+{
+
+       while(q->c_cc)
+               VOID getc(q);
+}
+
+
+wflush(cp,q)
+register struct chan *cp;
+register struct clist *q;
+{
+register s;
+
+       s = spl6();
+       while(q->c_cc) {
+               if (cp->c_flags & WCLOSE) {
+                       flush(q);
+                       goto out;
+               }
+               cp->c_flags |= WFLUSH;
+               VOID sdata(cp);
+               sleep((caddr_t)q+2,TTOPRI);
+       }
+out:
+       cp->c_flags &= ~WFLUSH;
+       splx(s);
+}
+
+
+scontrol(cp,event,value)
+register struct chan *cp;
+short event,value;
+{
+register struct clist *q;
+int s;
+
+       q = &cp->c_ctlx;
+       s = spl6();
+       if (sdata(cp) == NULL)
+               return;
+       VOID putw(event,q);
+       VOID putw(value,q);
+       splx(s);
+}
+
+
+
+sioctl(cp, vec, cc)
+register struct chan *cp;
+char *vec;
+{
+register s;
+register struct clist *q;
+
+       s = spl6();
+       q = &cp->cx.datq;
+       while (q->c_cc) {
+               cp->c_flags |= BLOCK;
+               if (sdata(cp)==NULL) {
+                       u.u_error = ENXIO;
+                       return;
+               }
+               sleep((caddr_t)q+1, TTOPRI);
+       }
+       VOID b_to_q(vec, cc, &cp->c_ctlx);
+       cp->c_flags |= SIOCTL;
+       while (cp->c_flags&SIOCTL) {
+               if (cp->c_ctlx.c_cc)
+                       if (sdata(cp)==NULL) {
+                               u.u_error = ENXIO;
+                               return;
+                       }
+               sleep((caddr_t)cp, TTOPRI);
+       }
+       VOID q_to_b(&cp->c_ctly, vec, cp->c_ctly.c_cc);
+       splx(s);
+}
+
+sdata(gp)
+register struct group *gp;
+{
+       register struct group *ngp;
+       register int    s;
+
+       ngp = gp->g_group;
+       if (ngp==NULL || (ngp->g_state&ISGRP)==0)
+               return(NULL);
+
+       s = spl6();
+       do {
+               ngp->g_datq |= cmask[gp->g_index];
+               wakeup((caddr_t)&ngp->g_datq);
+               gp = ngp;
+       } while(ngp=ngp->g_group);
+       splx(s);
+       return((int)gp);
+}
+
+
+
+struct chan *
+xcp(gp, x)
+register struct group *gp;
+register short x;
+{
+       register int i;
+
+       while (gp->g_group) gp=gp->g_group;
+       for (i=0;i<NLEVELS;i++) {
+               if ((x&017) >= NINDEX)
+                       break;
+               if (gp==NULL || (gp->g_state&ISGRP)==0)
+                       return((struct chan *)NULL);
+               gp = (struct group *)gp->g_chans[x&017];
+               x >>= 4;
+       }
+       return((struct chan *)gp);
+}
+
+cpx(cp)
+register struct chan *cp;
+{
+       register x;
+       register struct group *gp;
+
+       x = (-1<<4) + cp->c_index;
+       gp = cp->c_group;
+       while (gp->g_group) {
+               x <<= 4;
+               x |= gp->g_index;
+               gp = gp->g_group;
+       }
+       return(x);
+}
+
+
+struct chan *
+nextcp(gp)
+register struct group *gp;
+{
+       register struct group *lgp, *ngp;
+
+       do {
+               while ((gp->g_datq & cmask[gp->g_rot]) == 0) {
+                       gp->g_rot = (gp->g_rot+1)%NINDEX;
+               }
+               lgp = gp;
+               gp = (struct group *)gp->g_chans[gp->g_rot];
+       } while (gp!=NULL && gp->g_state&ISGRP);
+
+       lgp->g_datq &= ~cmask[lgp->g_rot];
+       lgp->g_rot  =  (lgp->g_rot+1)%NINDEX;
+
+       while (ngp=lgp->g_group) {
+               ngp->g_datq &= ~cmask[lgp->g_index];
+               if (ngp->g_datq)
+                       break;
+               lgp = ngp;
+       }
+       return((struct chan *)gp);
+}
+
+
+
+msgenab(cp)
+register struct chan *cp;
+{
+       register struct group *gp;
+
+       for(gp=cp->c_group;gp;gp=gp->g_group)
+               if(gp->g_state & ENAMSG)return(1);
+       return(0);
+}
diff --git a/usr/src/sys/sys/nami.c b/usr/src/sys/sys/nami.c
new file mode 100644 (file)
index 0000000..33f6bd7
--- /dev/null
@@ -0,0 +1,229 @@
+/*     nami.c  2.1     1/5/80  */
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/inode.h"
+#include "../h/mount.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/buf.h"
+
+/*
+ * Convert a pathname into a pointer to
+ * an inode. Note that the inode is locked.
+ *
+ * func = function called to get next char of name
+ *     &uchar if name is in user space
+ *     &schar if name is in system space
+ * flag = 0 if name is sought
+ *     1 if name is to be created
+ *     2 if name is to be deleted
+ */
+struct inode *
+namei(func, flag)
+int (*func)();
+{
+       register struct inode *dp;
+       register c;
+       register char *cp;
+       struct buf *bp;
+       int i;
+       dev_t d;
+       off_t eo;
+
+       /*
+        * If name starts with '/' start from
+        * root; otherwise start from current dir.
+        */
+
+       dp = u.u_cdir;
+       if((c=(*func)()) == '/')
+               if ((dp = u.u_rdir) == NULL)
+                       dp = rootdir;
+       VOID iget(dp->i_dev, dp->i_number);
+       while(c == '/')
+               c = (*func)();
+       if(c == '\0' && flag != 0)
+               u.u_error = ENOENT;
+
+cloop:
+       /*
+        * Here dp contains pointer
+        * to last component matched.
+        */
+
+       if(u.u_error)
+               goto out;
+       if(c == '\0')
+               return(dp);
+
+       /*
+        * If there is another component,
+        * Gather up name into
+        * users' dir buffer.
+        */
+
+       cp = &u.u_dbuf[0];
+       while (c != '/' && c != '\0' && u.u_error == 0 ) {
+               if (mpxip!=NULL && c=='!')
+                       break;
+               if(cp < &u.u_dbuf[DIRSIZ])
+                       *cp++ = c;
+               c = (*func)();
+       }
+       while(cp < &u.u_dbuf[DIRSIZ])
+               *cp++ = '\0';
+       while(c == '/')
+               c = (*func)();
+       if (c == '!' && mpxip != NULL) {
+               iput(dp);
+               plock(mpxip);
+               mpxip->i_count++;
+               return(mpxip);
+       }
+
+seloop:
+       /*
+        * dp must be a directory and
+        * must have X permission.
+        */
+
+       if((dp->i_mode&IFMT) != IFDIR)
+               u.u_error = ENOTDIR;
+       VOID access(dp, IEXEC);
+       if(u.u_error)
+               goto out;
+
+       /*
+        * set up to search a directory
+        */
+       u.u_offset = 0;
+       u.u_segflg = 1;
+       eo = 0;
+       bp = NULL;
+
+eloop:
+
+       /*
+        * If at the end of the directory,
+        * the search failed. Report what
+        * is appropriate as per flag.
+        */
+
+       if(u.u_offset >= dp->i_size) {
+               if(bp != NULL)
+                       brelse(bp);
+               if(flag==1 && c=='\0') {
+                       if(access(dp, IWRITE))
+                               goto out;
+                       u.u_pdir = dp;
+                       if(eo)
+                               u.u_offset = eo-sizeof(struct direct);
+                       else
+                               dp->i_flag |= IUPD|ICHG;
+                       return(NULL);
+               }
+               u.u_error = ENOENT;
+               goto out;
+       }
+
+       /*
+        * If offset is on a block boundary,
+        * read the next directory block.
+        * Release previous if it exists.
+        */
+
+       if((u.u_offset&BMASK) == 0) {
+               if(bp != NULL)
+                       brelse(bp);
+               bp = bread(dp->i_dev,
+                       bmap(dp, (daddr_t)(u.u_offset>>BSHIFT), B_READ));
+               if (bp->b_flags & B_ERROR) {
+                       brelse(bp);
+                       goto out;
+               }
+       }
+
+       /*
+        * Note first empty directory slot
+        * in eo for possible creat.
+        * String compare the directory entry
+        * and the current component.
+        * If they do not match, go back to eloop.
+        */
+
+       bcopy(bp->b_un.b_addr+(u.u_offset&BMASK), (caddr_t)&u.u_dent,
+               sizeof(struct direct));
+       u.u_offset += sizeof(struct direct);
+       if(u.u_dent.d_ino == 0) {
+               if(eo == 0)
+                       eo = u.u_offset;
+               goto eloop;
+       }
+       for(i=0; i<DIRSIZ; i++) {
+               if(u.u_dbuf[i] != u.u_dent.d_name[i])
+                       goto eloop;
+               if(u.u_dbuf[i] == 0)
+                       break;
+       }
+
+       /*
+        * Here a component matched in a directory.
+        * If there is more pathname, go back to
+        * cloop, otherwise return.
+        */
+
+       if(bp != NULL)
+               brelse(bp);
+       if(flag==2 && c=='\0') {
+               if(access(dp, IWRITE))
+                       goto out;
+               return(dp);
+       }
+       d = dp->i_dev;
+       if(u.u_dent.d_ino == ROOTINO)
+       if(dp->i_number == ROOTINO)
+       if(u.u_dent.d_name[1] == '.')
+               for(i=1; i<NMOUNT; i++)
+                       if(mount[i].m_bufp != NULL)
+                       if(mount[i].m_dev == d) {
+                               iput(dp);
+                               dp = mount[i].m_inodp;
+                               dp->i_count++;
+                               plock(dp);
+                               goto seloop;
+                       }
+       iput(dp);
+       dp = iget(d, u.u_dent.d_ino);
+       if(dp == NULL)
+               return(NULL);
+       goto cloop;
+
+out:
+       iput(dp);
+       return(NULL);
+}
+
+/*
+ * Return the next character from the
+ * kernel string pointed at by dirp.
+ */
+schar()
+{
+
+       return(*u.u_dirp++ & 0377);
+}
+
+/*
+ * Return the next character from the
+ * user string pointed at by dirp.
+ */
+uchar()
+{
+       register c;
+
+       c = fubyte(u.u_dirp++);
+       if(c == -1)
+               u.u_error = EFAULT;
+       return(c);
+}
diff --git a/usr/src/sys/sys/partab.c b/usr/src/sys/sys/partab.c
new file mode 100644 (file)
index 0000000..f26959a
--- /dev/null
@@ -0,0 +1,23 @@
+/*     partab.c        2.1     1/5/80  */
+
+/*
+ */
+
+char partab[] = {
+       0001,0201,0201,0001,0201,0001,0001,0201,
+       0202,0004,0003,0201,0005,0206,0201,0001,
+       0201,0001,0001,0201,0001,0201,0201,0001,
+       0001,0201,0201,0001,0201,0001,0001,0201,
+       0200,0000,0000,0200,0000,0200,0200,0000,
+       0000,0200,0200,0000,0200,0000,0000,0200,
+       0000,0200,0200,0000,0200,0000,0000,0200,
+       0200,0000,0000,0200,0000,0200,0200,0000,
+       0200,0000,0000,0200,0000,0200,0200,0000,
+       0000,0200,0200,0000,0200,0000,0000,0200,
+       0000,0200,0200,0000,0200,0000,0000,0200,
+       0200,0000,0000,0200,0000,0200,0200,0000,
+       0000,0200,0200,0000,0200,0000,0000,0200,
+       0200,0000,0000,0200,0000,0200,0200,0000,
+       0200,0000,0000,0200,0000,0200,0200,0000,
+       0000,0200,0200,0000,0200,0000,0000,0201
+};
diff --git a/usr/src/sys/sys/pipe.c b/usr/src/sys/sys/pipe.c
new file mode 100644 (file)
index 0000000..6a6fbc2
--- /dev/null
@@ -0,0 +1,220 @@
+/*     pipe.c  2.1     1/5/80  */
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/inode.h"
+#include "../h/file.h"
+#include "../h/reg.h"
+
+/*
+ * Max allowable buffering per pipe.
+ * This is also the max size of the
+ * file created to implement the pipe.
+ * If this size is bigger than 5120,
+ * pipes will be implemented with large
+ * files, which is probably not good.
+ */
+#define        PIPSIZ  4096
+
+/*
+ * The sys-pipe entry.
+ * Allocate an inode on the root device.
+ * Allocate 2 file structures.
+ * Put it all together with flags.
+ */
+pipe()
+{
+       register struct inode *ip;
+       register struct file *rf, *wf;
+       int r;
+
+       ip = ialloc(pipedev);
+       if(ip == NULL)
+               return;
+       rf = falloc();
+       if(rf == NULL) {
+               iput(ip);
+               return;
+       }
+       r = u.u_r.r_val1;
+       wf = falloc();
+       if(wf == NULL) {
+               rf->f_count = 0;
+               u.u_ofile[r] = NULL;
+               iput(ip);
+               return;
+       }
+       u.u_r.r_val2 = u.u_r.r_val1;
+       u.u_r.r_val1 = r;
+       wf->f_flag = FWRITE|FPIPE;
+       wf->f_inode = ip;
+       rf->f_flag = FREAD|FPIPE;
+       rf->f_inode = ip;
+       ip->i_count = 2;
+       ip->i_mode = IFREG;
+       ip->i_flag = IACC|IUPD|ICHG;
+}
+
+/*
+ * Read call directed to a pipe.
+ */
+readp(fp)
+register struct file *fp;
+{
+       register struct inode *ip;
+
+       ip = fp->f_inode;
+
+loop:
+       /*
+        * Very conservative locking.
+        */
+
+       plock(ip);
+       /*
+        * If nothing in the pipe, wait.
+        */
+       if (ip->i_size == 0) {
+               /*
+                * If there are not both reader and
+                * writer active, return without
+                * satisfying read.
+                */
+               prele(ip);
+               if(ip->i_count < 2)
+                       return;
+               ip->i_mode |= IREAD;
+               sleep((caddr_t)ip+2, PPIPE);
+               goto loop;
+       }
+
+       /*
+        * Read and return
+        */
+
+       u.u_offset = fp->f_un.f_offset;
+       readi(ip);
+       fp->f_un.f_offset = u.u_offset;
+       /*
+        * If reader has caught up with writer, reset
+        * offset and size to 0.
+        */
+       if (fp->f_un.f_offset == ip->i_size) {
+               fp->f_un.f_offset = 0;
+               ip->i_size = 0;
+               if(ip->i_mode & IWRITE) {
+                       ip->i_mode &= ~IWRITE;
+                       wakeup((caddr_t)ip+1);
+               }
+       }
+       prele(ip);
+}
+
+/*
+ * Write call directed to a pipe.
+ */
+writep(fp)
+register struct file *fp;
+{
+       register unsigned c;
+       register struct inode *ip;
+
+       ip = fp->f_inode;
+       c = u.u_count;
+
+loop:
+
+       /*
+        * If error or all done, return.
+        */
+
+       if (u.u_error)
+               return;
+       plock(ip);
+       if(c == 0) {
+               prele(ip);
+               u.u_count = 0;
+               return;
+       }
+
+       /*
+        * If there are not both read and
+        * write sides of the pipe active,
+        * return error and signal too.
+        */
+
+       if(ip->i_count < 2) {
+               prele(ip);
+               u.u_error = EPIPE;
+               psignal(u.u_procp, SIGPIPE);
+               return;
+       }
+
+       /*
+        * If the pipe is full,
+        * wait for reads to deplete
+        * and truncate it.
+        */
+
+       if(ip->i_size >= PIPSIZ) {
+               ip->i_mode |= IWRITE;
+               prele(ip);
+               sleep((caddr_t)ip+1, PPIPE);
+               goto loop;
+       }
+
+       /*
+        * Write what is possible and
+        * loop back.
+        * If writing less than PIPSIZ, it always goes.
+        * One can therefore get a file > PIPSIZ if write
+        * sizes do not divide PIPSIZ.
+        */
+
+       u.u_offset = ip->i_size;
+       u.u_count = min(c, PIPSIZ);
+       c -= u.u_count;
+       writei(ip);
+       prele(ip);
+       if(ip->i_mode&IREAD) {
+               ip->i_mode &= ~IREAD;
+               wakeup((caddr_t)ip+2);
+       }
+       goto loop;
+}
+
+/*
+ * Lock a pipe.
+ * If its already locked,
+ * set the WANT bit and sleep.
+ */
+plock(ip)
+register struct inode *ip;
+{
+
+       while(ip->i_flag&ILOCK) {
+               ip->i_flag |= IWANT;
+               sleep((caddr_t)ip, PINOD);
+       }
+       ip->i_flag |= ILOCK;
+}
+
+/*
+ * Unlock a pipe.
+ * If WANT bit is on,
+ * wakeup.
+ * This routine is also used
+ * to unlock inodes in general.
+ */
+prele(ip)
+register struct inode *ip;
+{
+
+       ip->i_flag &= ~ILOCK;
+       if(ip->i_flag&IWANT) {
+               ip->i_flag &= ~IWANT;
+               wakeup((caddr_t)ip);
+       }
+}
diff --git a/usr/src/sys/sys/prf.c b/usr/src/sys/sys/prf.c
new file mode 100644 (file)
index 0000000..4537672
--- /dev/null
@@ -0,0 +1,129 @@
+/*     prf.c   2.1     1/5/80  */
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/seg.h"
+#include "../h/buf.h"
+#include "../h/conf.h"
+
+/*
+ * In case console is off,
+ * panicstr contains argument to last
+ * call to panic.
+ */
+
+char   *panicstr;
+
+/*
+ * Scaled down version of C Library printf.
+ * Only %s %u %d (==%u) %o %x %D are recognized.
+ * Used to print diagnostic information
+ * directly on console tty.
+ * Since it is not interrupt driven,
+ * all system activities are pretty much
+ * suspended.
+ * Printf should not be used for chit-chat.
+ */
+/*VARARGS1*/
+printf(fmt, x1)
+register char *fmt;
+unsigned x1;
+{
+       register c;
+       register unsigned int *adx;
+       char *s;
+
+       adx = &x1;
+loop:
+       while((c = *fmt++) != '%') {
+               if(c == '\0')
+                       return;
+               putchar(c);
+       }
+       c = *fmt++;
+       if(c == 'X')
+               printx((long)*adx);
+       else if(c == 'd' || c == 'u' || c == 'o' || c == 'x')
+               printn((long)*adx, c=='o'? 8: (c=='x'? 16:10));
+       else if(c == 's') {
+               s = (char *)*adx;
+               while(c = *s++)
+                       putchar(c);
+       } else if (c == 'D') {
+               printn(*(long *)adx, 10);
+               adx += (sizeof(long) / sizeof(int)) - 1;
+       }
+       adx++;
+       goto loop;
+}
+
+printx(x)
+long x;
+{
+       int i;
+
+       for (i = 0; i < 8; i++)
+               putchar("0123456789ABCDEF"[(x>>((7-i)*4))&0xf]);
+}
+
+/*
+ * Print an unsigned integer in base b.
+ */
+printn(n, b)
+long n;
+{
+       register long a;
+
+       if (n<0) {      /* shouldn't happen */
+               putchar('-');
+               n = -n;
+       }
+       if(a = n/b)
+               printn(a, b);
+       putchar("0123456789ABCDEF"[(int)(n%b)]);
+}
+
+/*
+ * Panic is called on unresolvable
+ * fatal errors.
+ * It syncs, prints "panic: mesg" and
+ * then loops.
+ */
+panic(s)
+char *s;
+{
+       panicstr = s;
+       update();
+       printf("panic: %s\n", s);
+       for(;;)
+               idle();
+}
+
+/*
+ * prdev prints a warning message of the
+ * form "mesg on dev x/y".
+ * x and y are the major and minor parts of
+ * the device argument.
+ */
+prdev(str, dev)
+char *str;
+dev_t dev;
+{
+
+       printf("%s on dev %u/%u\n", str, major(dev), minor(dev));
+}
+
+/*
+ * deverr prints a diagnostic from
+ * a device driver.
+ * It prints the device, block number,
+ * and an octal word (usually some error
+ * status register) passed as argument.
+ */
+deverror(bp, o1, o2)
+register struct buf *bp;
+{
+
+       prdev("err", bp->b_dev);
+       printf("bn=%d er=%x,%x\n", bp->b_blkno, o1,o2);
+}
diff --git a/usr/src/sys/sys/prim.c b/usr/src/sys/sys/prim.c
new file mode 100644 (file)
index 0000000..3977d2f
--- /dev/null
@@ -0,0 +1,323 @@
+/*     prim.c  2.1     1/5/80  */
+
+#include "../h/param.h"
+#include "../h/tty.h"
+#include "../h/systm.h"
+#include "../h/conf.h"
+#include "../h/buf.h"
+
+struct cblock {
+       struct cblock *c_next;
+       char    c_info[CBSIZE];
+};
+
+struct cblock  cfree[NCLIST];
+struct cblock  *cfreelist;
+
+/*
+ * Character list get/put
+ */
+getc(p)
+register struct clist *p;
+{
+       register struct cblock *bp;
+       register int c, s;
+
+       s = spl6();
+       if (p->c_cc <= 0) {
+               c = -1;
+               p->c_cc = 0;
+               p->c_cf = p->c_cl = NULL;
+       } else {
+               c = *p->c_cf++ & 0377;
+               if (--p->c_cc<=0) {
+                       bp = (struct cblock *)(p->c_cf-1);
+                       bp = (struct cblock *) ((int)bp & ~CROUND);
+                       p->c_cf = NULL;
+                       p->c_cl = NULL;
+                       bp->c_next = cfreelist;
+                       cfreelist = bp;
+               } else if (((int)p->c_cf & CROUND) == 0){
+                       bp = (struct cblock *)(p->c_cf);
+                       bp--;
+                       p->c_cf = bp->c_next->c_info;
+                       bp->c_next = cfreelist;
+                       cfreelist = bp;
+               }
+       }
+       splx(s);
+       return(c);
+}
+
+/*
+ * copy clist to buffer.
+ * return number of bytes moved.
+ */
+q_to_b(q, cp, cc)
+register struct clist *q;
+register char *cp;
+{
+       register struct cblock *bp;
+       register int s;
+       char *acp;
+
+       if (cc <= 0)
+               return(0);
+       s = spl6();
+       if (q->c_cc <= 0) {
+               q->c_cc = 0;
+               q->c_cf = q->c_cl = NULL;
+               return(0);
+       }
+       acp = cp;
+       cc++;
+
+       while (--cc) {
+               *cp++ = *q->c_cf++;
+               if (--q->c_cc <= 0) {
+                       bp = (struct cblock *)(q->c_cf-1);
+                       bp = (struct cblock *)((int)bp & ~CROUND);
+                       q->c_cf = q->c_cl = NULL;
+                       bp->c_next = cfreelist;
+                       cfreelist = bp;
+                       break;
+               }
+               if (((int)q->c_cf & CROUND) == 0) {
+                       bp = (struct cblock *)(q->c_cf);
+                       bp--;
+                       q->c_cf = bp->c_next->c_info;
+                       bp->c_next = cfreelist;
+                       cfreelist = bp;
+               }
+       }
+       splx(s);
+       return(cp-acp);
+}
+
+
+/*
+ * Return count of contiguous characters
+ * in clist starting at q->c_cf.
+ * Stop counting if flag&character is non-null.
+ */
+ndqb(q, flag)
+register struct clist *q;
+{
+register cc;
+int s;
+
+       s = spl6();
+       if (q->c_cc <= 0) {
+               cc = -q->c_cc;
+               goto out;
+       }
+       cc = ((int)q->c_cf + CBSIZE) & ~CROUND;
+       cc -= (int)q->c_cf;
+       if (q->c_cc < cc)
+               cc = q->c_cc;
+       if (flag) {
+               register char *p, *end;
+
+               p = q->c_cf;
+               end = p;
+               end += cc;
+               while (p < end) {
+                       if (*p & flag) {
+                               cc = (int)p - (int)q->c_cf;
+                               break;
+                       }
+                       p++;
+               }
+       }
+out:
+       splx(s);
+       return(cc);
+}
+
+
+
+/*
+ * Update clist to show that cc characters
+ * were removed.  It is assumed that cc < CBSIZE.
+ */
+ndflush(q, cc)
+register struct clist *q;
+register cc;
+{
+register s;
+
+       if (cc == 0)
+               return;
+       s = spl6();
+       if (q->c_cc < 0) {
+               if (q->c_cf != NULL) {
+                       q->c_cc += cc;
+                       q->c_cf += cc;
+                       goto out;
+               }
+               q->c_cc = 0;
+               goto out;
+       }
+       if (q->c_cc == 0) {
+               goto out;
+       }
+       q->c_cc -= cc;
+       q->c_cf += cc;
+       if (((int)q->c_cf & CROUND) == 0) {
+               register struct cblock *bp;
+
+               bp = (struct cblock *)(q->c_cf) -1;
+               if (bp->c_next) {
+                       q->c_cf = bp->c_next->c_info;
+               } else {
+                       q->c_cf = q->c_cl = NULL;
+               }
+               bp->c_next = cfreelist;
+               cfreelist = bp;
+       } else
+       if (q->c_cc == 0) {
+               register struct cblock *bp;
+               q->c_cf = (char *)((int)q->c_cf & ~CROUND);
+               bp = (struct cblock *)(q->c_cf);
+               bp->c_next = cfreelist;
+               cfreelist = bp;
+               q->c_cf = q->c_cl = NULL;
+       }
+out:
+       splx(s);
+}
+putc(c, p)
+register struct clist *p;
+{
+       register struct cblock *bp;
+       register char *cp;
+       register s;
+
+       s = spl6();
+       if ((cp = p->c_cl) == NULL || p->c_cc < 0 ) {
+               if ((bp = cfreelist) == NULL) {
+                       splx(s);
+                       return(-1);
+               }
+               cfreelist = bp->c_next;
+               bp->c_next = NULL;
+               p->c_cf = cp = bp->c_info;
+       } else if (((int)cp & CROUND) == 0) {
+               bp = (struct cblock *)cp - 1;
+               if ((bp->c_next = cfreelist) == NULL) {
+                       splx(s);
+                       return(-1);
+               }
+               bp = bp->c_next;
+               cfreelist = bp->c_next;
+               bp->c_next = NULL;
+               cp = bp->c_info;
+       }
+       *cp++ = c;
+       p->c_cc++;
+       p->c_cl = cp;
+       splx(s);
+       return(0);
+}
+
+
+
+/*
+ * copy buffer to clist.
+ * return number of bytes not transfered.
+ */
+b_to_q(cp, cc, q)
+register char *cp;
+struct clist *q;
+register int cc;
+{
+       register char *cq;
+       register struct cblock *bp;
+       register s, acc;
+
+       if (cc <= 0)
+               return(0);
+       acc = cc;
+       s = spl6();
+       if ((cq = q->c_cl) == NULL || q->c_cc < 0) {
+               if ((bp = cfreelist) == NULL) 
+                       goto out;
+               cfreelist = bp->c_next;
+               bp->c_next = NULL;
+               q->c_cf = cq = bp->c_info;
+       }
+
+       while (cc) {
+               if (((int)cq & CROUND) == 0) {
+                       bp = (struct cblock *) cq - 1;
+                       if ((bp->c_next = cfreelist) == NULL) 
+                               goto out;
+                       bp = bp->c_next;
+                       cfreelist = bp->c_next;
+                       bp->c_next = NULL;
+                       cq = bp->c_info;
+               }
+               *cq++ = *cp++;
+               cc--;
+       }
+out:
+       q->c_cl = cq;
+       q->c_cc += acc-cc;
+       splx(s);
+       return(cc);
+}
+
+/*
+ * Initialize clist by freeing all character blocks, then count
+ * number of character devices. (Once-only routine)
+ */
+cinit()
+{
+       register int ccp;
+       register struct cblock *cp;
+       register struct cdevsw *cdp;
+
+       ccp = (int)cfree;
+       ccp = (ccp+CROUND) & ~CROUND;
+       for(cp=(struct cblock *)ccp; cp <= &cfree[NCLIST-1]; cp++) {
+               cp->c_next = cfreelist;
+               cfreelist = cp;
+       }
+       ccp = 0;
+       for(cdp = cdevsw; cdp->d_open; cdp++)
+               ccp++;
+       nchrdev = ccp;
+}
+
+/*
+ * integer (2-byte) get/put
+ * using clists
+ */
+/*
+getw(p)
+register struct clist *p;
+{
+       register int s;
+
+       if (p->c_cc <= 1)
+               return(-1);
+       s = getc(p);
+       return(s | (getc(p)<<8));
+}
+*/
+
+putw(c, p)
+register struct clist *p;
+{
+       register s;
+
+       s = spl6();
+       if (cfreelist==NULL) {
+               splx(s);
+               return(-1);
+       }
+       VOID putc(c, p);
+       VOID putc(c>>8, p);
+       splx(s);
+       return(0);
+}
diff --git a/usr/src/sys/sys/rdwri.c b/usr/src/sys/sys/rdwri.c
new file mode 100644 (file)
index 0000000..154b5ad
--- /dev/null
@@ -0,0 +1,200 @@
+/*     rdwri.c 2.1     1/5/80  */
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/inode.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/buf.h"
+#include "../h/conf.h"
+
+/*
+ * Read the file corresponding to
+ * the inode pointed at by the argument.
+ * The actual read arguments are found
+ * in the variables:
+ *     u_base          core address for destination
+ *     u_offset        byte offset in file
+ *     u_count         number of bytes to read
+ *     u_segflg        read to kernel/user/user I
+ */
+readi(ip)
+register struct inode *ip;
+{
+       struct buf *bp;
+       dev_t dev;
+       daddr_t lbn, bn;
+       off_t diff;
+       register int on, type;
+       register unsigned n;
+       extern int mem_no;
+
+       if(u.u_count == 0)
+               return;
+       dev = (dev_t)ip->i_un.i_rdev;
+       if (u.u_offset < 0 && ((ip->i_mode&IFMT) != IFCHR || mem_no != major(dev))) {
+               u.u_error = EINVAL;
+               return;
+       }
+       ip->i_flag |= IACC;
+       type = ip->i_mode&IFMT;
+       if (type==IFCHR || type==IFMPC) {
+               (*cdevsw[major(dev)].d_read)(dev);
+               return;
+       }
+
+       do {
+               lbn = bn = u.u_offset >> BSHIFT;
+               on = u.u_offset & BMASK;
+               n = min((unsigned)(BSIZE-on), u.u_count);
+               if (type!=IFBLK && type!=IFMPB) {
+                       diff = ip->i_size - u.u_offset;
+                       if (diff <= 0)
+                               return;
+                       if (diff < n)
+                               n = diff;
+                       bn = bmap(ip, bn, B_READ);
+                       if (u.u_error)
+                               return;
+                       dev = ip->i_dev;
+               } else
+                       rablock = bn+1;
+               if ((long)bn<0) {
+                       bp = geteblk();
+                       clrbuf(bp);
+               } else if (ip->i_un.i_lastr+1==lbn)
+                       bp = breada(dev, bn, rablock);
+               else
+                       bp = bread(dev, bn);
+               ip->i_un.i_lastr = lbn;
+               n = min(n, BSIZE-bp->b_resid);
+               if (n!=0)
+                       iomove(bp->b_un.b_addr+on, n, B_READ);
+               brelse(bp);
+       } while(u.u_error==0 && u.u_count!=0 && n!=0);
+}
+
+/*
+ * Write the file corresponding to
+ * the inode pointed at by the argument.
+ * The actual write arguments are found
+ * in the variables:
+ *     u_base          core address for source
+ *     u_offset        byte offset in file
+ *     u_count         number of bytes to write
+ *     u_segflg        write to kernel/user/user I
+ */
+writei(ip)
+register struct inode *ip;
+{
+       struct buf *bp;
+       dev_t dev;
+       daddr_t bn;
+       register int on, type;
+       register unsigned n;
+       extern int mem_no;
+
+       dev = (dev_t)ip->i_un.i_rdev;
+       if(u.u_offset < 0 && ((ip->i_mode&IFMT) != IFCHR || mem_no != major(dev)) ) {
+               u.u_error = EINVAL;
+               return;
+       }
+       type = ip->i_mode&IFMT;
+       if (type==IFCHR || type==IFMPC) {
+               ip->i_flag |= IUPD|ICHG;
+               (*cdevsw[major(dev)].d_write)(dev);
+               return;
+       }
+       if (u.u_count == 0)
+               return;
+
+       do {
+               bn = u.u_offset >> BSHIFT;
+               on = u.u_offset & BMASK;
+               n = min((unsigned)(BSIZE-on), u.u_count);
+               if (type!=IFBLK && type!=IFMPB) {
+                       bn = bmap(ip, bn, B_WRITE);
+                       if((long)bn<0)
+                               return;
+                       dev = ip->i_dev;
+               }
+               if(n == BSIZE) 
+                       bp = getblk(dev, bn);
+               else
+                       bp = bread(dev, bn);
+               iomove(bp->b_un.b_addr+on, n, B_WRITE);
+               if(u.u_error != 0)
+                       brelse(bp);
+               else
+                       bdwrite(bp);
+               if(u.u_offset > ip->i_size &&
+                  (type==IFDIR || type==IFREG))
+                       ip->i_size = u.u_offset;
+               ip->i_flag |= IUPD|ICHG;
+#ifdef ERNIE
+               ip->i_mode &= ~(ISUID|ISGID);
+#endif
+       } while(u.u_error==0 && u.u_count!=0);
+}
+
+/*
+ * Return the logical maximum
+ * of the 2 arguments.
+ */
+unsigned
+max(a, b)
+unsigned a, b;
+{
+
+       if(a > b)
+               return(a);
+       return(b);
+}
+
+/*
+ * Return the logical minimum
+ * of the 2 arguments.
+ */
+unsigned
+min(a, b)
+unsigned a, b;
+{
+
+       if(a < b)
+               return(a);
+       return(b);
+}
+
+/*
+ * Move n bytes at byte location
+ * &bp->b_un.b_addr[o] to/from (flag) the
+ * user/kernel (u.segflg) area starting at u.base.
+ * Update all the arguments by the number
+ * of bytes moved.
+ */
+iomove(cp, n, flag)
+       register caddr_t cp;
+       register unsigned n;
+{
+       register int t;
+
+       if (n==0)
+               return;
+       if (u.u_segflg != 1) {
+               if (flag==B_WRITE)
+                       t = copyin(u.u_base, (caddr_t)cp, n);
+               else
+                       t = copyout((caddr_t)cp, u.u_base, n);
+               if (t) {
+                       u.u_error = EFAULT;
+                       return;
+               }
+       } else
+               if (flag == B_WRITE)
+                       bcopy(u.u_base, (caddr_t)cp, n);
+               else
+                       bcopy((caddr_t)cp, u.u_base, n);
+       u.u_base += n;
+       u.u_offset += n;
+       u.u_count -= n;
+}