date and time created 82/07/15 20:12:50 by root
authorBill Joy <root@ucbvax.Berkeley.EDU>
Fri, 16 Jul 1982 11:12:50 +0000 (03:12 -0800)
committerBill Joy <root@ucbvax.Berkeley.EDU>
Fri, 16 Jul 1982 11:12:50 +0000 (03:12 -0800)
SCCS-vsn: sys/kern/kern_sig.c 5.1

usr/src/sys/kern/kern_sig.c [new file with mode: 0644]

diff --git a/usr/src/sys/kern/kern_sig.c b/usr/src/sys/kern/kern_sig.c
new file mode 100644 (file)
index 0000000..3a89c2c
--- /dev/null
@@ -0,0 +1,899 @@
+/*     kern_sig.c      5.1     82/07/15        */
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/reg.h"
+#include "../h/inode.h"
+#include "../h/proc.h"
+#include "../h/clock.h"
+#include "../h/mtpr.h"
+#include "../h/timeb.h"
+#include "../h/times.h"
+#include "../h/conf.h"
+#include "../h/buf.h"
+#include "../h/mount.h"
+#include "../h/text.h"
+#include "../h/seg.h"
+#include "../h/pte.h"
+#include "../h/psl.h"
+#include "../h/vm.h"
+#include "../h/vlimit.h"
+#include "../h/acct.h"
+
+ssig()
+{
+       register int (*f)();
+       struct a {
+               int     signo;
+               int     (*fun)();
+       } *uap;
+       register struct proc *p = u.u_procp;
+       register a;
+       long sigmask;
+
+       uap = (struct a *)u.u_ap;
+       a = uap->signo & SIGNUMMASK;
+       f = uap->fun;
+       if (a<=0 || a>=NSIG || a==SIGKILL || a==SIGSTOP ||
+           a==SIGCONT && (f == SIG_IGN || f == SIG_HOLD)) {
+               u.u_error = EINVAL;
+               return;
+       }
+       if ((uap->signo &~ SIGNUMMASK) || (f != SIG_DFL && f != SIG_IGN &&
+           SIGISDEFER(f)))
+               u.u_procp->p_flag |= SNUSIG;
+       /* 
+        * Don't clobber registers if we are to simulate
+        * a ret+rti.
+        */
+       if ((uap->signo&SIGDORTI) == 0)
+               u.u_r.r_val1 = (int)u.u_signal[a];
+       /*
+        * Change setting atomically.
+        */
+       (void) spl6();
+       sigmask = 1L << (a-1);
+       if (u.u_signal[a] == SIG_IGN)
+               p->p_sig &= ~sigmask;           /* never to be seen again */
+       u.u_signal[a] = f;
+       if (f != SIG_DFL && f != SIG_IGN && f != SIG_HOLD)
+               f = SIG_CATCH;
+       if ((int)f & 1)
+               p->p_siga0 |= sigmask;
+       else
+               p->p_siga0 &= ~sigmask;
+       if ((int)f & 2)
+               p->p_siga1 |= sigmask;
+       else
+               p->p_siga1 &= ~sigmask;
+       (void) spl0();
+       /*
+        * Now handle options.
+        */
+       if (uap->signo & SIGDOPAUSE) {
+               /*
+                * Simulate a PDP11 style wait instrution which
+                * atomically lowers priority, enables interrupts
+                * and hangs.
+                */
+               pause();
+               /*NOTREACHED*/
+       }
+       if (uap->signo & SIGDORTI)
+               u.u_eosys = SIMULATERTI;
+}
+
+kill()
+{
+       register struct proc *p;
+       register a, sig;
+       register struct a {
+               int     pid;
+               int     signo;
+       } *uap;
+       int f, priv;
+
+       uap = (struct a *)u.u_ap;
+       f = 0;
+       a = uap->pid;
+       priv = 0;
+       sig = uap->signo;
+       if (sig < 0)
+               /*
+                * A negative signal means send to process group.
+                */
+               uap->signo = -uap->signo;
+       if (uap->signo == 0 || uap->signo > NSIG) {
+               u.u_error = EINVAL;
+               return;
+       }
+       if (a > 0 && sig > 0) {
+               p = pfind(a);
+               if (p == 0 || u.u_uid && u.u_uid != p->p_uid) {
+                       u.u_error = ESRCH;
+                       return;
+               }
+               psignal(p, uap->signo);
+               return;
+       }
+       if (a==-1 && u.u_uid==0) {
+               priv++;
+               a = 0;
+               sig = -1;               /* like sending to pgrp */
+       } else if (a==0) {
+               /*
+                * Zero process id means send to my process group.
+                */
+               sig = -1;
+               a = u.u_procp->p_pgrp;
+               if (a == 0) {
+                       u.u_error = EINVAL;
+                       return;
+               }
+       }
+       for(p = proc; p < procNPROC; p++) {
+               if (p->p_stat == NULL)
+                       continue;
+               if (sig > 0) {
+                       if (p->p_pid != a)
+                               continue;
+               } else if (p->p_pgrp!=a && priv==0 || p->p_ppid==0 ||
+                   (p->p_flag&SSYS) || (priv && p==u.u_procp))
+                       continue;
+               if (u.u_uid != 0 && u.u_uid != p->p_uid &&
+                   (uap->signo != SIGCONT || !inferior(p)))
+                       continue;
+               f++;
+               psignal(p, uap->signo);
+       }
+       if (f == 0)
+               u.u_error = ESRCH;
+}
+
+/*
+ * Priority for tracing
+ */
+#define        IPCPRI  PZERO
+
+/*
+ * Tracing variables.
+ * Used to pass trace command from
+ * parent to child being traced.
+ * This data base cannot be
+ * shared and is locked
+ * per user.
+ */
+struct {
+       int     ip_lock;
+       int     ip_req;
+       int     *ip_addr;
+       int     ip_data;
+} ipc;
+
+/*
+ * Send the specified signal to
+ * all processes with 'pgrp' as
+ * process group.
+ * Called by tty.c for quits and
+ * interrupts.
+ */
+gsignal(pgrp, sig)
+       register int pgrp;
+{
+       register struct proc *p;
+
+       if (pgrp == 0)
+               return;
+       for(p = proc; p < procNPROC; p++)
+               if (p->p_pgrp == pgrp)
+                       psignal(p, sig);
+}
+
+/*
+ * Send the specified signal to
+ * the specified process.
+ */
+psignal(p, sig)
+       register struct proc *p;
+       register int sig;
+{
+       register int s;
+       register int (*action)();
+       long sigmask;
+
+       if ((unsigned)sig >= NSIG)
+               return;
+       sigmask = (1L << (sig-1));
+
+       /*
+        * If proc is traced, always give parent a chance.
+        * Otherwise get the signal action from the bits in the proc table.
+        */
+       if (p->p_flag & STRC)
+               action = SIG_DFL;
+       else {
+               s = (p->p_siga1&sigmask) != 0;
+               s <<= 1;
+               s |= (p->p_siga0&sigmask) != 0;
+               action = (int(*)())s;
+               /*
+                * If the signal is ignored, we forget about it immediately.
+                */
+               if (action == SIG_IGN)
+                       return;
+       }
+#define mask(sig)      (1<<(sig-1))
+#define        stops   (mask(SIGSTOP)|mask(SIGTSTP)|mask(SIGTTIN)|mask(SIGTTOU))
+       if (sig) {
+               p->p_sig |= sigmask;
+               switch (sig) {
+
+               case SIGTERM:
+                       if ((p->p_flag&STRC) != 0 || action != SIG_DFL)
+                               break;
+                       /* fall into ... */
+
+               case SIGKILL:
+                       if (p->p_nice > NZERO)
+                               p->p_nice = NZERO;
+                       break;
+
+               case SIGCONT:
+                       p->p_sig &= ~stops;
+                       break;
+
+               case SIGSTOP:
+               case SIGTSTP:
+               case SIGTTIN:
+               case SIGTTOU:
+                       p->p_sig &= ~mask(SIGCONT);
+                       break;
+               }
+       }
+#undef mask
+#undef stops
+       /*
+        * Defer further processing for signals which are held.
+        */
+       if (action == SIG_HOLD)
+               return;
+       s = spl6();
+       switch (p->p_stat) {
+
+       case SSLEEP:
+               /*
+                * If process is sleeping at negative priority
+                * we can't interrupt the sleep... the signal will
+                * be noticed when the process returns through
+                * trap() or syscall().
+                */
+               if (p->p_pri <= PZERO)
+                       goto out;
+               /*
+                * Process is sleeping and traced... make it runnable
+                * so it can discover the signal in issig() and stop
+                * for the parent.
+                */
+               if (p->p_flag&STRC)
+                       goto run;
+               switch (sig) {
+
+               case SIGSTOP:
+               case SIGTSTP:
+               case SIGTTIN:
+               case SIGTTOU:
+                       /*
+                        * These are the signals which by default
+                        * stop a process.
+                        */
+                       if (action != SIG_DFL)
+                               goto run;
+                       /*
+                        * Don't clog system with children of init
+                        * stopped from the keyboard.
+                        */
+                       if (sig != SIGSTOP && p->p_pptr == &proc[1]) {
+                               psignal(p, SIGKILL);
+                               p->p_sig &= ~sigmask;
+                               splx(s);
+                               return;
+                       }
+                       /*
+                        * If a child in vfork(), stopping could
+                        * cause deadlock.
+                        */
+                       if (p->p_flag&SVFORK)
+                               goto out;
+                       p->p_sig &= ~sigmask;
+                       p->p_cursig = sig;
+                       stop(p);
+                       goto out;
+
+               case SIGIO:
+               case SIGURG:
+               case SIGCHLD:
+                       /*
+                        * These signals are special in that they
+                        * don't get propogated... if the process
+                        * isn't interested, forget it.
+                        */
+                       if (action != SIG_DFL)
+                               goto run;
+                       p->p_sig &= ~sigmask;           /* take it away */
+                       goto out;
+
+               default:
+                       /*
+                        * All other signals cause the process to run
+                        */
+                       goto run;
+               }
+               /*NOTREACHED*/
+
+       case SSTOP:
+               /*
+                * If traced process is already stopped,
+                * then no further action is necessary.
+                */
+               if (p->p_flag&STRC)
+                       goto out;
+               switch (sig) {
+
+               case SIGKILL:
+                       /*
+                        * Kill signal always sets processes running.
+                        */
+                       goto run;
+
+               case SIGCONT:
+                       /*
+                        * If the process catches SIGCONT, let it handle
+                        * the signal itself.  If it isn't waiting on
+                        * an event, then it goes back to run state.
+                        * Otherwise, process goes back to sleep state.
+                        */
+                       if (action != SIG_DFL || p->p_wchan == 0)
+                               goto run;
+                       p->p_stat = SSLEEP;
+                       goto out;
+
+               case SIGSTOP:
+               case SIGTSTP:
+               case SIGTTIN:
+               case SIGTTOU:
+                       /*
+                        * Already stopped, don't need to stop again.
+                        * (If we did the shell could get confused.)
+                        */
+                       p->p_sig &= ~sigmask;           /* take it away */
+                       goto out;
+
+               default:
+                       /*
+                        * If process is sleeping interruptibly, then
+                        * unstick it so that when it is continued
+                        * it can look at the signal.
+                        * But don't setrun the process as its not to
+                        * be unstopped by the signal alone.
+                        */
+                       if (p->p_wchan && p->p_pri > PZERO)
+                               unsleep(p);
+                       goto out;
+               }
+               /*NOTREACHED*/
+
+       default:
+               /*
+                * SRUN, SIDL, SZOMB do nothing with the signal,
+                * other than kicking ourselves if we are running.
+                * It will either never be noticed, or noticed very soon.
+                */
+               if (p == u.u_procp && !noproc)
+                       aston();
+               goto out;
+       }
+       /*NOTREACHED*/
+run:
+       /*
+        * Raise priority to at least PUSER.
+        */
+       if (p->p_pri > PUSER)
+               if ((p != u.u_procp || noproc) && p->p_stat == SRUN &&
+                   (p->p_flag & SLOAD)) {
+                       remrq(p);
+                       p->p_pri = PUSER;
+                       setrq(p);
+               } else
+                       p->p_pri = PUSER;
+       setrun(p);
+out:
+       splx(s);
+}
+
+/*
+ * Returns true if the current
+ * process has a signal to process.
+ * The signal to process is put in p_cursig.
+ * This is asked at least once each time a process enters the
+ * system (though this can usually be done without actually
+ * calling issig by checking the pending signal masks.)
+ * A signal does not do anything
+ * directly to a process; it sets
+ * a flag that asks the process to
+ * do something to itself.
+ */
+issig()
+{
+       register struct proc *p;
+       register int sig;
+       long sigbits;
+       long sigmask;
+
+       p = u.u_procp;
+       for (;;) {
+               sigbits = p->p_sig;
+               if ((p->p_flag&STRC) == 0)
+                       sigbits &= ~p->p_ignsig;
+               if (p->p_flag&SVFORK)
+#define bit(a) (1<<(a-1))
+                       sigbits &= ~(bit(SIGSTOP)|bit(SIGTSTP)|bit(SIGTTIN)|bit(SIGTTOU));
+               if (sigbits == 0)
+                       break;
+               sig = ffs((int)sigbits);
+               sigmask = 1L << (sig-1);
+               p->p_sig &= ~sigmask;           /* take the signal! */
+               p->p_cursig = sig;
+               if (p->p_flag&STRC && (p->p_flag&SVFORK)==0) {
+                       /*
+                        * If traced, always stop, and stay
+                        * stopped until released by the parent.
+                        */
+                       do {
+                               stop(p);
+                               swtch();
+                       } while (!procxmt() && p->p_flag&STRC);
+
+                       /*
+                        * If the traced bit got turned off,
+                        * then put the signal taken above back into p_sig
+                        * and go back up to the top to rescan signals.
+                        * This ensures that siga0 and u_signal are consistent.
+                        */
+                       if ((p->p_flag&STRC) == 0) {
+                               p->p_sig |= sigmask;
+                               continue;
+                       }
+
+                       /*
+                        * If parent wants us to take the signal,
+                        * then it will leave it in p->p_cursig;
+                        * otherwise we just look for signals again.
+                        */
+                       sig = p->p_cursig;
+                       if (sig == 0)
+                               continue;
+               }
+               switch (u.u_signal[sig]) {
+
+               case SIG_DFL:
+                       /*
+                        * Don't take default actions on system processes.
+                        */
+                       if (p->p_ppid == 0)
+                               break;
+                       switch (sig) {
+
+                       case SIGTSTP:
+                       case SIGTTIN:
+                       case SIGTTOU:
+                               /*
+                                * Children of init aren't allowed to stop
+                                * on signals from the keyboard.
+                                */
+                               if (p->p_pptr == &proc[1]) {
+                                       psignal(p, SIGKILL);
+                                       continue;
+                               }
+                               /* fall into ... */
+
+                       case SIGSTOP:
+                               if (p->p_flag&STRC)
+                                       continue;
+                               stop(p);
+                               swtch();
+                               continue;
+
+                       case SIGCONT:
+                       case SIGCHLD:
+                               /*
+                                * These signals are normally not
+                                * sent if the action is the default.
+                                */
+                               continue;               /* == ignore */
+
+                       default:
+                               goto send;
+                       }
+                       /*NOTREACHED*/
+
+               case SIG_HOLD:
+               case SIG_IGN:
+                       /*
+                        * Masking above should prevent us
+                        * ever trying to take action on a held
+                        * or ignored signal, unless process is traced.
+                        */
+                       if ((p->p_flag&STRC) == 0)
+                               printf("issig\n");
+                       continue;
+
+               default:
+                       /*
+                        * This signal has an action, let
+                        * psig process it.
+                        */
+                       goto send;
+               }
+               /*NOTREACHED*/
+       }
+       /*
+        * Didn't find a signal to send.
+        */
+       p->p_cursig = 0;
+       return (0);
+
+send:
+       /*
+        * Let psig process the signal.
+        */
+       return (sig);
+}
+
+#ifndef vax
+ffs(mask)
+       register long mask;
+{
+       register int i;
+
+       for(i=1; i<NSIG; i++) {
+               if (mask & 1)
+                       return (i);
+               mask >>= 1;
+       }
+       return (0);
+}
+#endif
+
+/*
+ * Put the argument process into the stopped
+ * state and notify the parent via wakeup and/or signal.
+ */
+stop(p)
+       register struct proc *p;
+{
+
+       p->p_stat = SSTOP;
+       p->p_flag &= ~SWTED;
+       wakeup((caddr_t)p->p_pptr);
+       /*
+        * Avoid sending signal to parent if process is traced
+        */
+       if (p->p_flag&STRC)
+               return;
+       psignal(p->p_pptr, SIGCHLD);
+}
+
+/*
+ * Perform the action specified by
+ * the current signal.
+ * The usual sequence is:
+ *     if (issig())
+ *             psig();
+ * The signal bit has already been cleared by issig,
+ * and the current signal number stored in p->p_cursig.
+ */
+psig()
+{
+       register struct proc *rp = u.u_procp;
+       register int n = rp->p_cursig;
+       long sigmask = 1L << (n-1);
+       register int (*action)();
+
+       if (rp->p_cursig == 0)
+               panic("psig");
+       action = u.u_signal[n];
+       if (action != SIG_DFL) {
+               if (action == SIG_IGN || action == SIG_HOLD)
+                       panic("psig action");
+               u.u_error = 0;
+               if (n != SIGILL && n != SIGTRAP)
+                       u.u_signal[n] = 0;
+               /*
+                * If this catch value indicates automatic holding of
+                * subsequent signals, set the hold value.
+                */
+               if (SIGISDEFER(action)) {
+                       (void) spl6();
+                       if ((int)SIG_HOLD & 1)
+                               rp->p_siga0 |= sigmask;
+                       else
+                               rp->p_siga0 &= ~sigmask;
+                       if ((int)SIG_HOLD & 2)
+                               rp->p_siga1 |= sigmask;
+                       else
+                               rp->p_siga1 &= ~sigmask;
+                       u.u_signal[n] = SIG_HOLD;
+                       (void) spl0();
+                       action = SIGUNDEFER(action);
+               }
+               sendsig(action, n);
+               rp->p_cursig = 0;
+               return;
+       }
+       u.u_acflag |= AXSIG;
+       switch (n) {
+
+       case SIGILL:
+       case SIGIOT:
+       case SIGBUS:
+       case SIGQUIT:
+       case SIGTRAP:
+       case SIGEMT:
+       case SIGFPE:
+       case SIGSEGV:
+       case SIGSYS:
+               u.u_arg[0] = n;
+               if (core())
+                       n += 0200;
+       }
+       exit(n);
+}
+
+#ifdef unneeded
+int    corestop = 0;
+#endif
+/*
+ * Create a core image on the file "core"
+ * If you are looking for protection glitches,
+ * there are probably a wealth of them here
+ * when this occurs to a suid command.
+ *
+ * It writes UPAGES block of the
+ * user.h area followed by the entire
+ * data+stack segments.
+ */
+core()
+{
+       register struct inode *ip;
+       extern schar();
+
+#ifdef unneeded
+       if (corestop) {
+               int i;
+               for (i = 0; i < 10; i++)
+                       if (u.u_comm[i])
+                               putchar(u.u_comm[i], 0);
+               printf(", uid %d\n", u.u_uid);
+               if (corestop&2)
+                       asm("halt");
+       }
+#endif
+       if (u.u_uid != u.u_ruid)
+               return;
+       if (ctob(UPAGES+u.u_dsize+u.u_ssize) >= u.u_limit[LIM_CORE])
+               return (0);
+       u.u_error = 0;
+       u.u_dirp = "core";
+       ip = namei(schar, 1, 1);
+       if (ip == NULL) {
+               if (u.u_error)
+                       return (0);
+               ip = maknode(0666);
+               if (ip==NULL)
+                       return (0);
+       }
+       if (!access(ip, IWRITE) &&
+          (ip->i_mode&IFMT) == IFREG &&
+          ip->i_nlink == 1) {
+               itrunc(ip);
+               u.u_acflag |= ACORE;
+               u.u_offset = 0;
+               u.u_base = (caddr_t)&u;
+               u.u_count = ctob(UPAGES);
+               u.u_segflg = 1;
+               writei(ip);
+               u.u_base = (char *)ctob(u.u_tsize);
+               u.u_count = ctob(u.u_dsize);
+               u.u_segflg = 0;
+               writei(ip);
+               u.u_base = (char *)(USRSTACK - ctob(u.u_ssize));
+               u.u_count = ctob(u.u_ssize);
+               writei(ip);
+       } else
+               u.u_error = EFAULT;
+       iput(ip);
+       return (u.u_error==0);
+}
+
+/*
+ * grow the stack to include the SP
+ * true return if successful.
+ */
+grow(sp)
+       unsigned sp;
+{
+       register si;
+
+       if (sp >= USRSTACK-ctob(u.u_ssize))
+               return (0);
+       si = clrnd(btoc((USRSTACK-sp)) - u.u_ssize + SINCR);
+       if (ctob(u.u_ssize+si) > u.u_limit[LIM_STACK])
+               return (0);
+       if (chksize(u.u_tsize, u.u_dsize, u.u_ssize+si))
+               return (0);
+       if (swpexpand(u.u_dsize, u.u_ssize+si, &u.u_dmap, &u.u_smap)==0)
+               return (0);
+       
+       expand(si, P1BR);
+       return (1);
+}
+
+/*
+ * sys-trace system call.
+ */
+ptrace()
+{
+       register struct proc *p;
+       register struct a {
+               int     req;
+               int     pid;
+               int     *addr;
+               int     data;
+       } *uap;
+
+       uap = (struct a *)u.u_ap;
+       if (uap->req <= 0) {
+               u.u_procp->p_flag |= STRC;
+               return;
+       }
+       p = pfind(uap->pid);
+       if (p == 0 || p->p_stat != SSTOP || p->p_ppid != u.u_procp->p_pid) {
+               u.u_error = ESRCH;
+               return;
+       }
+       while (ipc.ip_lock)
+               sleep((caddr_t)&ipc, IPCPRI);
+       ipc.ip_lock = p->p_pid;
+       ipc.ip_data = uap->data;
+       ipc.ip_addr = uap->addr;
+       ipc.ip_req = uap->req;
+       p->p_flag &= ~SWTED;
+       while (ipc.ip_req > 0) {
+               if (p->p_stat==SSTOP)
+                       setrun(p);
+               sleep((caddr_t)&ipc, IPCPRI);
+       }
+       u.u_r.r_val1 = ipc.ip_data;
+       if (ipc.ip_req < 0)
+               u.u_error = EIO;
+       ipc.ip_lock = 0;
+       wakeup((caddr_t)&ipc);
+}
+
+int ipcreg[] = {R0,R1,R2,R3,R4,R5,R6,R7,R8,R9,R10,R11,AP,FP,SP,PC};
+/*
+ * Code that the child process
+ * executes to implement the command
+ * of the parent process in tracing.
+ */
+procxmt()
+{
+       register int i;
+       register *p;
+       register struct text *xp;
+
+       if (ipc.ip_lock != u.u_procp->p_pid)
+               return (0);
+       u.u_procp->p_slptime = 0;
+       i = ipc.ip_req;
+       ipc.ip_req = 0;
+       switch (i) {
+
+       /* read user I */
+       case 1:
+               if (!useracc((caddr_t)ipc.ip_addr, 4, B_READ))
+                       goto error;
+               ipc.ip_data = fuiword((caddr_t)ipc.ip_addr);
+               break;
+
+       /* read user D */
+       case 2:
+               if (!useracc((caddr_t)ipc.ip_addr, 4, B_READ))
+                       goto error;
+               ipc.ip_data = fuword((caddr_t)ipc.ip_addr);
+               break;
+
+       /* read u */
+       case 3:
+               i = (int)ipc.ip_addr;
+               if (i<0 || i >= ctob(UPAGES))
+                       goto error;
+               ipc.ip_data = ((physadr)&u)->r[i>>2];
+               break;
+
+       /* write user I */
+       /* Must set up to allow writing */
+       case 4:
+               /*
+                * If text, must assure exclusive use
+                */
+               if (xp = u.u_procp->p_textp) {
+                       if (xp->x_count!=1 || xp->x_iptr->i_mode&ISVTX)
+                               goto error;
+                       xp->x_iptr->i_flag &= ~ITEXT;
+               }
+               i = -1;
+               if (chgprot((caddr_t)ipc.ip_addr, RW) &&
+                   chgprot((caddr_t)ipc.ip_addr+(sizeof(int)-1), RW))
+                       i = suiword((caddr_t)ipc.ip_addr, ipc.ip_data);
+               (void) chgprot((caddr_t)ipc.ip_addr, RO);
+               (void) chgprot((caddr_t)ipc.ip_addr+(sizeof(int)-1), RO);
+               if (i < 0)
+                       goto error;
+               if (xp)
+                       xp->x_flag |= XWRIT;
+               break;
+
+       /* write user D */
+       case 5:
+               if (suword((caddr_t)ipc.ip_addr, 0) < 0)
+                       goto error;
+               (void) suword((caddr_t)ipc.ip_addr, ipc.ip_data);
+               break;
+
+       /* write u */
+       case 6:
+               i = (int)ipc.ip_addr;
+               p = (int *)&((physadr)&u)->r[i>>2];
+               for (i=0; i<16; i++)
+                       if (p == &u.u_ar0[ipcreg[i]])
+                               goto ok;
+               if (p == &u.u_ar0[PS]) {
+                       ipc.ip_data |= PSL_CURMOD|PSL_PRVMOD;
+                       ipc.ip_data &=  ~PSL_USERCLR;
+                       goto ok;
+               }
+               goto error;
+
+       ok:
+               *p = ipc.ip_data;
+               break;
+
+       /* set signal and continue */
+       /* one version causes a trace-trap */
+       case 9:
+       case 7:
+               if ((int)ipc.ip_addr != 1)
+                       u.u_ar0[PC] = (int)ipc.ip_addr;
+               if ((unsigned)ipc.ip_data > NSIG)
+                       goto error;
+               u.u_procp->p_cursig = ipc.ip_data;      /* see issig */
+               if (i == 9)
+                       u.u_ar0[PS] |= PSL_T;
+               wakeup((caddr_t)&ipc);
+               return (1);
+
+       /* force exit */
+       case 8:
+               wakeup((caddr_t)&ipc);
+               exit(u.u_procp->p_cursig);
+
+       default:
+       error:
+               ipc.ip_req = -1;
+       }
+       wakeup((caddr_t)&ipc);
+       return (0);
+}