[comp.sources.unix] v10i018: Diffs for SystemV /bin/sh job control with sxt's, Part01/02

rs@uunet.UU.NET (Rich Salz) (06/24/87)

Submitted by: Simon Brown <simon@its63b.ed.ac.uk>
Archive-name: sxt-sh-jobs/Part01
Mod.sources: Volume 10, Number 18

	This is a set of context-diffs to implement job-control in the
	System-V Bourne Shell using sxt (layer) devices.

	It includes the additional files
		proc.c
		job.h
		README
		Makefile
		sxtalloc.c
		sxtalloc.8

	See README for installation details.

	To apply the diffs, its easiest to use Larry Wall's "patch" program,
	if you have it; otherwise its pretty hard work.

				Simon Brown
				Department of Computer Science
				University of Edinburgh
				Scotland, UK.

				UUCP: seismo!mcvax!ukc!its63b!simon
				    (or seismo!mcvax!ukc!cstvax!simon)
				ARPA: simon@its63b.ed.ac.uk
				    (or simon@cstvax.ed.ac.uk)
				JANET: simon@uk.ac.ed.its63b
				    (or simon@uk.ac.ed.cstvax)	


------------- cut here -------------- cut here ---------------- cut here ------
#!/bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	README
#	Makefile
#	args.c.Diff
#	cmd.c.Diff
#	defs.c.Diff
#	defs.h.Diff
#	error.c.Diff
#	fault.c.Diff
#	io.c.Diff
#	job.h
#	macro.c.Diff
#	main.c.Diff
#	msg.c.Diff
#	name.c.Diff
# This archive created: Fri Feb 20 17:42:58 1987
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'README'" '(4879 characters)'
if test -f 'README'
then
	echo shar: "will not over-write existing file 'README'"
else
cat << \SHAR_EOF > 'README'
System V Bourne Shell with additional sxt job-control features:

There are several pre-processor flags that you can set at the top of "defs.h".
These are:
	JOB		If you have this defined, then the shell will use
			clever job-oriented data-structures. It doesn't produce
			code that manipulates them - but it means that the
			commands that look at job-stuff will work better -
			things like "jobs" or "kill %job", etc...
	JOBSXT		If you have this defined, in addition to JOB, then
			you have access to sxt drivers to manipulate job
			control. 
	JOBSXT_HUP	If this is defined, then the shell will do lots
			of cleaning up if it should ever receive a SIGHUP
			signal. This is sometimes necessary because the
			kernel can get very confused about what processes
			belong to what groups.
	SXT_SUSPEND	If this is defined, then the shell will leave the
			file-descriptor to the controlling sxt device open
			in its children, so they can do "suspend()" calls
			to suspend themselves - this is the only way that
			programs that use RAW (ie, ~ICANON) mode can be
			subject to job-control. The environment variable
			"SXT_CONTROL" will contain the numeric value of
			this descriptor. To suspend yourself, just do
				fd = atoi(getenv("SXT_CONTROL"));
				ioctl(fd,SXTIOCSWTCH,0);
			(see <sys/sxt.h> for details).
	ERCC_SIGCONT	Usually it is not possible for programs to know
			if they have been suspended (unless they did it
			to themselves). If ERCC_SIGCONT is defined, then
			the shell will send SIGCONT to jobs whenever they
			are resumed. This assumes that you have SIGCONT
			defined in <signal.h> (SIGUSR2 is quite good for
			this). It will set SIGCONT to be ignored by
			children unless they explicitly trap it, so any
			programs that use SIGCONT for any other purpose
			will stop working if you have this.
	BLK_BOTTOM	This causes the cursor to be moved to the bottom
			of your screen whenever a foreground process becomes
			suspended. In fact, it uses termcap/terminfo in my
			full-modifications version of the shell, but that's
			not available here, so it does it in a stupid way.
			You might well not want this.
	SSHLIBRARY	This should be the directory-name for the place
			where the "sxtalloc" program is to be kept. Since
			these modifications to the shell are just a subset
			of a larger set of modifications forming the "ssh"
			shell, the directory "/usr/lib/ssh" is normal.
			Note that this must be given with unmatched quotes -
			one at the start but NOT at the end; ie,
				"/usr/lib/ssh
	sysV		You will almost certainly have this already
			pre-defined by cpp, but define it if you don't. This
			is pretty important.


Sxtalloc:
	In order to guarentee availability (and security) of sxt terminals,
	a setuid-root allocator is provided - "sxtalloc". This should be
	placed in the SSHLIBRARY directory. This is used for two purposes:
	    1. to chown groups of sxt terminals so that they can be used
	       solely by the intended user and not hijacked midway by
	       someone else, and
	    2. to stamp a new entry into /etc/utmp to reflect the fact
	       that the user's controlling terminal has changed into an sxt.
	       The old terminal is put back again when the shell has finished
	       with the sxt.
	On allocation, it returns the real tty-name on the standard output, and
	this is stored in the shell-parameter $REALTTY, which is automatically
	exported if set in this way. Subshells check to see if it is set and
	don't bother trying to inititate job-control if it is. It is then
	passed back to sxtalloc when the shell de-allocates the sxt.
	See the manual entry for details.


DISCLAIMER:
	I am fully aware that most of the code to implement this is 
	incredibly badly written. This reflects the fact that it consists
	of little pieces hacked out of a larger shell in a very simple-minded
	way (the larger shell also not being exactly the most beautifully-
	written program ever). But it seems to work, sort-of'ish ....

	If you find any important bugs, please send a summary (and a bug-fix
	would be nice) to me at
		ARPA: simon@its63b.ed.ac.uk
		ARPA: simon@cstvax.ed.ac.uk	(alternative address)
		UUCP: seismo!mcvax!ukc!{its63b,cstvax}!simon
		JANET: simno@uk.ac.ed.{its63b,cstvax}

	Finally, I'd better copyright this so some bastard doesn't sell it
	for thousands of dollars :-) so:

		These modifications are Copyright (c) Simon Brown, 
		February 1987.
		You may use or change them for personal use as much as you
		like, but don't try to sell them or pretend that they're
		yours ('cos that's not too impressive).


FURTHER DISCLAIMER:
	This has only been tested on a GEC 63/40 super-mini, running UX63.
	It is *not* guarenteed to work properly on anything else (though it'd
	be quite nice if it did).


AUTHOR:
		Simon Brown

			Department of Computer Science
			University of Edinburgh,
			Scotland,
			UK.

SHAR_EOF
fi
echo shar: "extracting 'Makefile'" '(521 characters)'
if test -f 'Makefile'
then
	echo shar: "will not over-write existing file 'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
#	Makefile	4.5	83/07/01
#
CFLAGS = -O

all:	sh

cp:	sh
	cp sh /bin/sh
	rm sh *.o

cmp:	sh
	cmp sh /bin/sh
	rm sh *.o

sh:	setbrk.o
sh:	blok.o stak.o defs.o
sh:	cmd.o fault.o main.o proc.o
sh:	word.o string.o name.o args.o
sh:	xec.o service.o error.o io.o
sh:	print.o macro.o expand.o
sh:	ctype.o msg.o
sh:	hash.o hashserv.o profile.o echo.o test.o
sh:	pwd.o func.o
blok.o:		brkincr.h
fault.o:	brkincr.h
main.o:		brkincr.h
stak.o:		brkincr.h

sh:
	cc -o sh *.o

install:
	install -s sh $(DESTDIR)/bin
clean:
	rm -f sh *.o
SHAR_EOF
fi
echo shar: "extracting 'args.c.Diff'" '(715 characters)'
if test -f 'args.c.Diff'
then
	echo shar: "will not over-write existing file 'args.c.Diff'"
else
cat << \SHAR_EOF > 'args.c.Diff'
*** args.c	Mon Nov 24 17:49:17 1986
--- /cs/simon/c/shdiff-sources/args.c	Thu Feb 19 19:16:31 1987
***************
*** 276,281
  
  clearup()
  {
  	/*
  	 * force `for' $* lists to go away
  	 */

--- 276,285 -----
  
  clearup()
  {
+ #ifdef JOB
+ 	extern int fgjobs;
+ #endif JOB
+ 
  	/*
  	 * force `for' $* lists to go away
  	 */
***************
*** 292,297
  	*/
  	while (poptemp())
  		;
  }
  
  struct dolnod *

--- 296,312 -----
  	*/
  	while (poptemp())
  		;
+ 
+ #ifdef JOB
+ 	/* reset job */
+ # ifdef JOBSXT
+ 	restore_sxt();
+ # endif
+ 	setjob(0);
+ 	fgjobs = 0;	/* so the next `await()' won't hang */
+ 	iflags =0;  	/* they're all temporary states */
+ #endif JOB
+ 
  }
  
  struct dolnod *
SHAR_EOF
fi
echo shar: "extracting 'cmd.c.Diff'" '(747 characters)'
if test -f 'cmd.c.Diff'
then
	echo shar: "will not over-write existing file 'cmd.c.Diff'"
else
cat << \SHAR_EOF > 'cmd.c.Diff'
*** cmd.c	Mon Nov 24 17:49:19 1986
--- /cs/simon/c/shdiff-sources/cmd.c	Wed Feb 18 14:06:30 1987
***************
*** 102,107
  	switch (wdval)
  	{
  	case '&':
  		if (i)
  			i = makefork(FINT | FPRS | FAMP, i);
  		else

--- 102,119 -----
  	switch (wdval)
  	{
  	case '&':
+ #ifdef JOB
+ 		/* prepend "bg" to convert "%x &" to "bg %x" */
+ 		if (i && i->tretyp==TCOM && ((struct comnod *)i)->comarg->argval[0]=='%'){
+ 			register struct comnod *ip;
+ 			register struct argnod *ap;
+ 			ip = (struct comnod *)i;
+ 			ap = (struct argnod *)getstor(sizeof(struct argnod)+3);
+ 			movstr("bg",ap->argval);
+ 			ap->argnxt = ip->comarg;
+ 			ip->comarg = ap;
+ 		} else
+ #endif JOB
  		if (i)
  			i = makefork(FINT | FPRS | FAMP, i);
  		else
SHAR_EOF
fi
echo shar: "extracting 'defs.c.Diff'" '(425 characters)'
if test -f 'defs.c.Diff'
then
	echo shar: "will not over-write existing file 'defs.c.Diff'"
else
cat << \SHAR_EOF > 'defs.c.Diff'
*** defs.c	Mon Nov 24 17:49:19 1986
--- /cs/simon/c/shdiff-sources/defs.c	Wed Feb 18 19:00:28 1987
***************
*** 47,52
  
  long			flags;
  int				rwait;	/* flags read waiting */
  
  /* error exits from various parts of shell */
  jmp_buf			subshell;

--- 47,53 -----
  
  long			flags;
  int				rwait;	/* flags read waiting */
+ long			iflags;
  
  /* error exits from various parts of shell */
  jmp_buf			subshell;
SHAR_EOF
fi
echo shar: "extracting 'defs.h.Diff'" '(3844 characters)'
if test -f 'defs.h.Diff'
then
	echo shar: "will not over-write existing file 'defs.h.Diff'"
else
cat << \SHAR_EOF > 'defs.h.Diff'
*** defs.h	Mon Nov 24 17:49:35 1986
--- /cs/simon/c/shdiff-sources/defs.h	Thu Feb 19 19:01:28 1987
***************
*** 3,8
   *	UNIX shell
   */
  
  
  /* error exits from various parts of shell */
  #define 	ERROR		1

--- 3,15 -----
   *	UNIX shell
   */
  
+ #define JOB			/* use job-control data structures */
+ #define JOBSXT			/* ... and use sxt's to implement it */
+ #define SSHLIBRARY "/usr/lib/ssh
+ #define JOBSXT_HUP		/* clever cleaning-up if it goes wrong */
+ #define SXT_SUSPEND		/* export the file-descriptor for job stuff */
+ /*#define ERCC_SIGCONT*/	/* use SIGUSR2 to simulate SIGCONT */
+ /*#define BLK_BOTTOM*/		/* move cursor to bottom of screen if blocked */
  
  /* error exits from various parts of shell */
  #define 	ERROR		1
***************
*** 74,79
  #define		SYSMEM		27
  #define		SYSTYPE  	28
  
  /* used for input and output of shell */
  #define 	INIO 		19
  

--- 81,99 -----
  #define		SYSMEM		27
  #define		SYSTYPE  	28
  
+ #ifdef JOB
+ #define		SYSJOBS		29
+ #define		SYSFG		30
+ #define 	SYSBG		31
+ #define		SYSKILL		32
+ #define		SYSSTOP		33
+ #define		SYSNOTIFY	34
+ # ifdef JOBSXT
+ # define	SYSSXT1		35
+ # endif
+ #endif JOB
+ 
+ 
  /* used for input and output of shell */
  #define 	INIO 		19
  
***************
*** 131,137
  extern char				**setenv();
  extern long				time();
  
! #define 	attrib(n,f)		(n->namflg |= f)
  #define 	round(a,b)		(((int)(((char *)(a)+b)-1))&~((b)-1))
  #define 	closepipe(x)	(close(x[INPIPE]), close(x[OTPIPE]))
  #define 	eq(a,b)			(cf(a,b)==0)

--- 151,158 -----
  extern char				**setenv();
  extern long				time();
  
! #define 	attrib(n,f)		((n)->namflg |= (f))
! #define 	nattrib(n,f)		((n)->namflg &= ~(f))
  #define 	round(a,b)		(((int)(((char *)(a)+b)-1))&~((b)-1))
  #define 	closepipe(x)	(close(x[INPIPE]), close(x[OTPIPE]))
  #define 	eq(a,b)			(cf(a,b)==0)
***************
*** 199,204
  extern struct namnod	mchknod;
  extern struct namnod	acctnod;
  extern struct namnod	mailpnod;
  
  /* special names */
  extern char				flagadr[];

--- 220,227 -----
  extern struct namnod	mchknod;
  extern struct namnod	acctnod;
  extern struct namnod	mailpnod;
+ extern struct namnod	ntfynod;
+ extern struct namnod	TTYnod;
  
  /* special names */
  extern char				flagadr[];
***************
*** 219,224
  extern char				mchkname[];
  extern char				acctname[];
  extern char				mailpname[];
  
  /* transput */
  extern char				tmpout[];

--- 242,249 -----
  extern char				mchkname[];
  extern char				acctname[];
  extern char				mailpname[];
+ extern char				ntfyname[];
+ extern char				TTYname[];
  
  /* transput */
  extern char				tmpout[];
***************
*** 261,266
  extern long				flags;
  extern int				rwait;	/* flags read waiting */
  
  /* error exits from various parts of shell */
  #include	<setjmp.h>
  extern jmp_buf			subshell;

--- 286,297 -----
  extern long				flags;
  extern int				rwait;	/* flags read waiting */
  
+ #ifdef JOB
+ extern long				iflags;
+ #define		jobflg		01
+ #define		sxtwaiting	02
+ #endif JOB
+ 
  /* error exits from various parts of shell */
  #include	<setjmp.h>
  extern jmp_buf			subshell;
***************
*** 277,282
  #define 	SIGSET		4
  #define 	SIGMOD		8
  #define 	SIGCAUGHT	16
  
  extern int				fault();
  extern BOOL				trapnote;

--- 308,314 -----
  #define 	SIGSET		4
  #define 	SIGMOD		8
  #define 	SIGCAUGHT	16
+ #define		DEVINTERRUPT	32
  
  extern int				fault();
  extern BOOL				trapnote;
***************
*** 362,364
  							exitsh(exitval ? exitval : SIGFAIL)
  
  #define 	exitset()	retval = exitval

--- 394,408 -----
  							exitsh(exitval ? exitval : SIGFAIL)
  
  #define 	exitset()	retval = exitval
+ 
+ 
+ #ifdef JOB
+ # ifdef sysV
+ #  define TTYNOD struct termio
+ #  include <termio.h>
+ # else
+ #  define TTYNOD struct sgttyb
+ #  include <sgtty.h>
+ # endif
+ #endif
+ 
SHAR_EOF
fi
echo shar: "extracting 'error.c.Diff'" '(378 characters)'
if test -f 'error.c.Diff'
then
	echo shar: "will not over-write existing file 'error.c.Diff'"
else
cat << \SHAR_EOF > 'error.c.Diff'
*** error.c	Mon Nov 24 17:49:20 1986
--- /cs/simon/c/shdiff-sources/error.c	Wed Feb 18 14:07:55 1987
***************
*** 75,80
  #ifdef ACCT
  	doacct();
  #endif
  	exit(exitval);
  }
  

--- 75,89 -----
  #ifdef ACCT
  	doacct();
  #endif
+ 
+ #ifdef JOB
+         zapjobs();
+ 	setjob(0);
+ # ifdef JOBSXT
+ 	sxtrelease(1);
+ # endif
+ #endif JOB
+ 
  	exit(exitval);
  }
  
SHAR_EOF
fi
echo shar: "extracting 'fault.c.Diff'" '(3967 characters)'
if test -f 'fault.c.Diff'
then
	echo shar: "will not over-write existing file 'fault.c.Diff'"
else
cat << \SHAR_EOF > 'fault.c.Diff'
*** fault.c	Mon Nov 24 17:49:21 1986
--- /cs/simon/c/shdiff-sources/fault.c	Thu Feb 19 18:21:00 1987
***************
*** 38,43
  int 	(*(sigval[]))() = 
  {
  	0,
  	done,
  	fault,
  	fault,

--- 38,46 -----
  int 	(*(sigval[]))() = 
  {
  	0,
+ #ifdef JOBSXT_HUP
+ 	fault,
+ #else
  	done,
  #endif
  	fault,
***************
*** 39,44
  {
  	0,
  	done,
  	fault,
  	fault,
  	done,

--- 42,48 -----
  	fault,
  #else
  	done,
+ #endif
  	fault,
  	fault,
  	done,
***************
*** 54,59
  	fault,
  	fault,
  	done,
  	done,
  	done,
  	done

--- 58,67 -----
  	fault,
  	fault,
  	done,
+ #ifdef JOB
+ # ifdef ERCC_SIGCONT
+ 	fault,		/* SIGUSR2 == SIGCONT? */
+ # else
  	done,
  # endif
  	fault,		/* SIGCLD */
***************
*** 55,60
  	fault,
  	done,
  	done,
  	done,
  	done
  };

--- 63,71 -----
  	fault,		/* SIGUSR2 == SIGCONT? */
  # else
  	done,
+ # endif
+ 	fault,		/* SIGCLD */
+ #else !JOB
  	done,
  	done,
  #endif
***************
*** 56,61
  	done,
  	done,
  	done,
  	done
  };
  

--- 67,74 -----
  	fault,		/* SIGCLD */
  #else !JOB
  	done,
+ 	done,
+ #endif
  	done
  };
  
***************
*** 67,73
  {
  	register int	flag;
  
! 	signal(sig, fault);
  	if (sig == SIGSEGV)
  	{
  		if (setbrk(brkincr) == -1)

--- 80,90 -----
  {
  	register int	flag;
  
! #ifdef JOB
! 	if (sig!=SIGCLD)
! #endif JOB
! 		signal(sig,fault);
! 
  	if (sig == SIGSEGV)
  	{
  		if (setbrk(brkincr) == -1)
***************
*** 78,83
  		if (flags & waiting)
  			done();
  	}
  	else
  	{
  		flag = (trapcom[sig] ? TRAPSET : SIGSET);

--- 95,119 -----
  		if (flags & waiting)
  			done();
  	}
+ #ifdef JOB
+ 	else if (sig==SIGCLD){
+ 		job_fault();
+ 		trapnote |= DEVINTERRUPT;
+ 		signal(SIGCLD,fault);	/* do this AFTER waiting */
+ 	}
+ # ifdef JOBSXT_HUP
+ 	else if (sig==SIGHUP){
+ 		if (flags&ttyflg) hupmail();
+ 		done();
+ 	}
+ # endif JOBSXT_HUP
+ # ifdef ERCC_SIGCONT
+ 	else if (sig==SIGCONT){
+ 		trapnote |= DEVINTERRUPT;
+ 	}
+ # endif ERCC_SIGCONT
+ #endif JOB
+ 
  	else
  	{
  		flag = (trapcom[sig] ? TRAPSET : SIGSET);
***************
*** 106,111
  	setsig(SIGTERM);
  	setsig(SIGUSR1);
  	setsig(SIGUSR2);
  }
  
  ignsig(n)

--- 142,150 -----
  	setsig(SIGTERM);
  	setsig(SIGUSR1);
  	setsig(SIGUSR2);
+ #ifdef JOB
+ 	setsig(SIGCLD);
+ #endif JOB
  }
  
  #ifdef JOB
***************
*** 108,113
  	setsig(SIGUSR2);
  }
  
  ignsig(n)
  {
  	register int	s, i;

--- 147,171 -----
  #endif JOB
  }
  
+ #ifdef JOB
+ /*
+  *	mask of signals that MUST be caught
+  */
+ #define X_CHILD 0
+ #define X_CONT 0
+ #define X_SEG (1L<<SIGSEGV)
+ #define X_ALRM (1L<<SIGALRM)
+ #ifdef JOB
+ # undef X_CHILD
+ # define X_CHILD (1L<<SIGCLD)
+ #endif JOB
+ #if defined(JOBSXT) && defined(ERCC_SIGCONT)
+ # undef X_CONT
+ # define X_CONT (1L<<SIGCONT)
+ #endif (JOBSXT and ERCC_SIGCONT)
+ long realsigs = X_CHILD | X_SEG | X_CONT | X_ALRM;
+ 
+ 
  ignsig(n)
  {
          register int    i;
***************
*** 110,115
  
  ignsig(n)
  {
  	register int	s, i;
  
  	if ((i = n) == SIGSEGV)

--- 168,188 -----
  
  ignsig(n)
  {
+         register int    i;
+ 
+         if (signal(i=n,SIG_IGN) != SIG_IGN){
+ 		trapflg[i] |= SIGMOD;
+ 		return(0);
+ 	} else if (realsigs&(1L<<n)){
+ 		trapflg[i] |= SIGMOD;
+ 		return(0);
+ 	} else return(1);
+ }
+ 
+ #else !JOB
+ 
+ ignsig(n)
+ {
  	register int	s, i;
  
  	if ((i = n) == SIGSEGV)
***************
*** 123,128
  	}
  	return(s);
  }
  
  getsig(n)
  {

--- 196,202 -----
  	}
  	return(s);
  }
+ #endif JOB
  
  getsig(n)
  {
***************
*** 194,196
  		}
  	}
  }

--- 268,290 -----
  		}
  	}
  }
+ 
+ 
+ 
+ #ifdef JOB
+ /*
+  *	fix up signals in child.
+  *	this is pretty kludgy, I suppose.
+  */
+ fixsigs()
+ {
+ 	signal(SIGTERM,SIG_DFL);
+ 	signal(SIGQUIT,SIG_DFL);
+ #ifdef ERCC_SIGCONT
+ 	signal(SIGCONT, SIG_IGN);	/* in case kid is stupid */
+ #endif ERCC_SIGCONT
+ 	trapflg[SIGTERM] &= ~SIGMOD;
+ 	trapflg[SIGQUIT] &= ~SIGMOD;
+ 	trapflg[SIGCONT] &= ~SIGMOD;
+ }
+ #endif JOB
SHAR_EOF
fi
echo shar: "extracting 'io.c.Diff'" '(4489 characters)'
if test -f 'io.c.Diff'
then
	echo shar: "will not over-write existing file 'io.c.Diff'"
else
cat << \SHAR_EOF > 'io.c.Diff'
*** io.c	Mon Nov 24 17:49:24 1986
--- /cs/simon/c/shdiff-sources/io.c	Fri Feb 20 12:51:13 1987
***************
*** 313,315
  	}
  	topfd = last;
  }

--- 313,529 -----
  	}
  	topfd = last;
  }
+ 
+ 
+ 
+ #ifdef JOB
+ 
+ /*
+  *	fetch current tty characteristics.
+  */
+ terminal(tp)
+ TTYNOD *tp;
+ {
+ # ifdef sysV
+ 	return(ioctl(0,TCGETA,tp));
+ # else
+ 	return(ioctl(0,TIOCGETP,tp));
+ # endif sysV
+ }
+ 
+ 
+ #ifdef JOBSXT
+ /*
+  *	sxt virtual-terminal stuff for SystemV Job-Control (layers)
+  */
+ #undef input
+ #include 	"job.h"
+ #include	<sys/types.h>
+ #include	<sys/tty.h>
+ #include	<sys/sxt.h>
+ #include	<errno.h>
+ 
+ #define SXTIO	  13
+ #define CONSTTYIO 14
+ 
+ /* this is a bit naughty: still... its only declared for sgtty, not termio! */
+ #define TIOCEXCL (('t'<<8)|13)
+ 
+ static char sxt[] = "/dev/sxt/000";
+ static char no_jobs[] = "; thus no job-control\n";
+ #define SXT_CHAN 11
+ extern int sxtchan;
+ extern int savsxtchan;
+ extern struct jobnod *jobs[];
+ 
+ 
+ 
+ /*
+  *	open a new channel
+  */
+ sxtopen(chan)
+ {
+ 	int rc;
+ 	struct termio tb;
+ 
+ 	if (chan>SXTMAX) return(-1);
+ 	sxt[SXT_CHAN] = chan+'0';
+ 	if ((rc=open(sxt,2)) < 0){
+ 		failed(sxt,errno);
+ 		/*NOTREACHED*/
+ 	}
+ 	tb = realtty;
+ 	if (chan>1){
+ 		tb.c_cc[VSWTCH] = '\032';	/* sorry! - only ^Z allowed */
+ 		tb.c_cflag |= LOBLK;		/* blocking allowed */
+ 	} else 	{
+ 		tb.c_cflag &= ~LOBLK;	    /* shell is immune to blocking */
+ 	}
+ 	ioctl(rc,TCSETA,&tb);
+ 	return(rc);
+ }
+ 
+ char *sxtstr[] = { SSHLIBRARY/sxtalloc`", 0 };
+ 
+ 
+ /*
+  *	initialize sxt
+  */
+ sxtinit()
+ {
+ 	int fd;
+ #ifdef SXT_SUSPEND
+ 	struct namnod *np;
+ #endif
+ 
+ 	iflags &= ~jobflg;
+ 	if (TTYnod.namval) goto nomesg;	/* its a subshell! */
+ 	if (setjmp(errshell)) goto bad;
+ 	execexp("REALTTY=`", sxtstr);
+ 	attrib(&TTYnod, (N_RDONLY|N_EXPORT));
+ 	sxtchan = 0;
+ 	if (exitval) goto bad;
+ 
+ 	while ((fd=open(sxt,O_RDWR)) == -1)
+ 		switch(errno){
+ 		    case ENOENT:
+ 			prs_buff("No sxt channels available");
+ 			prs_buff(no_jobs);
+ 			flushb();
+ 			sxtchan = -1;
+ 			return;
+ 		    case EBUSY:
+ 		    case EACCES:
+ 			sxtchan++;
+ 			if (sxtchan>9)
+ 				sxt[SXT_CHAN-2] = (sxtchan/10)+'0';
+ 			sxt[SXT_CHAN-1] = (sxtchan%10)+'0';
+ 			break;
+ 		    default:
+ 			prs_buff("sxt error\n");
+ 			flushb();
+ 			exit(1);
+ 		}
+ 	if (ioctl(fd,SXTIOCLINK,MAXPCHAN) != 0){
+ 	    	if (errno==ENOTTY || errno==EBUSY){
+ 			prs_buff("Controlling terminal not a real device");
+ 			prs_buff(no_jobs);
+ 			flushb();
+ 			sxtchan = -1;
+ 			close(fd);
+ 			return;
+ 		} else {
+ 			prs_buff("sxt ioctl error\n");
+ 			flushb();
+ 			exit(1);
+ 		}
+ 	}
+ 	ioctl(fd,SXTIOCUBLK,0);		/* controller mustn't block on output */
+ 	ioctl(fd,TIOCEXCL,0);
+ 	ioctl(fd,TCSETA,&realtty);
+ #ifdef SXT_SUSPEND
+ 	rename(fd,sxt_fd=SXTIO);	/* so subprocesses can "suspend..." */
+ 	itos(SXTIO);
+ 	np=lookup("SXT_CONTROL");
+ 	assign(np,numbuf);
+ 	attrib(np,N_EXPORT);
+ #else
+ 	Ldup(fd,sxt_fd=SXTIO);
+ #endif SXT_SUSPEND
+ 	if (getppid() == 1){		/* kernel bug; so just use sxt 0 */
+ 		Ldup(dup(0),CONSTTYIO);
+ #ifdef notdef
+ 		sxtkludge = 0;
+ 		fd = sxt_fd;
+ #else
+ 		fd = sxtopen(1);
+ #endif notdef
+ 	} else {
+ 		setpgrp();		/* setpgrp will work */
+ 		fd = sxtopen(1);	/* BETTER work! */
+ 	}
+ 	close(0);
+ 	close(1); close(2);		/* forget real tty */
+ 	dup(fd);			/* input is channel 0 or 1 */
+ 	dup(0); dup(0);			/* stdout/stderr channel 0 or 1 too*/
+ 	close(fd);
+ 	iflags |= jobflg;
+ 	return;
+ 
+     bad:
+ 	prs_buff("cannot initialize sxt");
+ 	prs_buff(no_jobs);
+ 	flushb();
+     nomesg:
+ 	sxtchan = -1;
+ 	iflags &= ~jobflg;
+ 	return;
+ }
+ 
+ 
+ /*
+  *	release sxt
+  */
+ sxtrelease(suicide)
+ {
+ 	if (sxtchan != -1){
+ 		exitset();
+ 		if (suicide) 
+ 			flags &= ~rshflg;	/* late enough now */
+ 		sxtchan = -1;		/* no more! */
+ 		close(sxt_fd);		/* really!  */
+ 		execexp(SSHLIBRARY/sxtalloc \"$REALTTY\" $?",(char * *)0);
+ 		if (suicide) done();
+ 		close(0); close(1); close(2);
+ 		dup(CONSTTYIO); dup(0); dup(1); 	/* restore old tty */
+ 	}
+ }
+ 
+ 
+ /* temporarily forget about sxt's */
+ hide_sxt()
+ {
+ 	if (sxtchan!=-1){
+ 		savsxtchan = sxtchan;
+ 		sxtchan = -1;
+ 		iflags &= ~jobflg;
+ 		return(1);
+ 	} else return(0);
+ }
+ 
+ 
+ /* ... and remember them again */
+ restore_sxt()
+ {
+ 	if (sxtchan==-1){
+ 		sxtchan = savsxtchan;
+ 		savsxtchan = -1;
+ 		iflags |= jobflg;
+ 	}
+ }
+ 
+ #endif JOBSXT
+ 
+ #endif JOB
+ 
+ 
SHAR_EOF
fi
echo shar: "extracting 'job.h'" '(1981 characters)'
if test -f 'job.h'
then
	echo shar: "will not over-write existing file 'job.h'"
else
cat << \SHAR_EOF > 'job.h'
#
/*
 *	SSH job-control structure (one for each job).
 *	Copyright (c) S. Brown, 1987
 */

#ifdef JOB

/* Because of the algorithm used for parsing, only the first and last
   processes of a pipeline are posted to the job-table, so set PPERJ=2.	*/


#define JOB_MAX	30	/* maximum number of jobs allowed */
#define PPERJ	2	/* processes known per job */
#define EXTRAPROCS JOB_MAX	/* size of "extra proc" table */

struct jobnod {
	union {
		struct {
			unsigned run : 1;	/* running */
			unsigned stop : 1;	/* stopped */
			unsigned back : 1;	/* background */
			unsigned notify : 1;	/* to be notified of termination */
			unsigned deaths : PPERJ;/* processes which have died */
			unsigned lifes : PPERJ;	/* processes associated with job */
			unsigned knowtty : 1;	/* have fetched tty status for this job */
			unsigned stopstate : 2;	/* stop states */
		} singlebits;	/* for referencing single bits */
		short totalbits;/* for making global assignments */
 	} jb_flags;		/* is this not perhaps a bit unpleasant altogether? */
	char *jb_dir;		/* current directory of job */
	int jb_pgrp;		/* process group (useful only for BSD) */
	char *jb_cmd;		/* name of command */
	int jb_pri;		/* priority (stack for %+ and %-) */
	struct {
		int proc_pid;		/* process id */
		int proc_status;	/* exit status */
		short proc_flags;	/* flags? not used, anyway */
	} jb_proc[PPERJ];	/* processes associated with job */
#ifdef JOBSXT
	int jb_sxtfg;		/* file descriptor for job's sxt */
#endif JOBSXT
};


#define SS_STOP	0
#define SS_TSTP	1
#define SS_TTIN	2
#define SS_TTOU	3


#ifdef PROCESS_DOT_C

struct extrawait {
	int pid;
	int status;
};

#endif PROCESS_DOT_C


#ifdef JOBSXT
#define SXTMAX (MAXPCHAN-1)
#define SXT(n) ((n)?(n)+1:sxtkludge)
extern int sxtchan;
extern int sxtkludge;
extern int sxt_fd;
extern TTYNOD realtty;
#endif JOBSXT

#define WAIT_FG		1
#define WAIT_BG		2
#define WAIT_NOPAUSE	4
#define WAIT_JOB	8

extern struct jobnod *jobs[];
extern int currentjob;

#endif JOB
SHAR_EOF
fi
echo shar: "extracting 'macro.c.Diff'" '(1965 characters)'
if test -f 'macro.c.Diff'
then
	echo shar: "will not over-write existing file 'macro.c.Diff'"
else
cat << \SHAR_EOF > 'macro.c.Diff'
*** macro.c	Mon Nov 24 17:49:25 1986
--- /cs/simon/c/shdiff-sources/macro.c	Wed Feb 18 18:13:05 1987
***************
*** 253,258
  	return(fixstak());
  }
  
  static
  comsubst()
  {

--- 253,262 -----
  	return(fixstak());
  }
  
+ #ifdef JOB
+ #include "job.h"
+ #endif
+ 
  static
  comsubst()
  {
***************
*** 262,267
  	struct fileblk	cb;
  	register char	d;
  	register char *savptr = fixstak();
  
  	usestak();
  	while ((d = readc()) != SQUOTE && d)

--- 266,274 -----
  	struct fileblk	cb;
  	register char	d;
  	register char *savptr = fixstak();
+ #ifdef JOBSXT
+ 	BOOL chsxt = FALSE;
+ #endif JOBSXT
  
  	usestak();
  	while ((d = readc()) != SQUOTE && d)
***************
*** 283,288
  		 */
  		chkpipe(pv);
  		initf(pv[INPIPE]);
  		execute(t, 0, (int)(flags & errflg), 0, pv);
  		close(pv[OTPIPE]);
  	}

--- 290,298 -----
  		 */
  		chkpipe(pv);
  		initf(pv[INPIPE]);
+ #ifdef JOBSXT
+ 	   	chsxt = hide_sxt();
+ #endif JOBSXT
  		execute(t, 0, (int)(flags & errflg), 0, pv);
  		close(pv[OTPIPE]);
  	}
***************
*** 290,295
  	staktop = movstr(savptr, stakbot);
  	while (d = readc())
  		pushstak(d | quote);
  	await(0, 0);
  	while (stakbot != staktop)
  	{

--- 300,312 -----
  	staktop = movstr(savptr, stakbot);
  	while (d = readc())
  		pushstak(d | quote);
+ #ifdef JOB
+ 	await(0,WAIT_FG);	/* a process, in the forground */
+ # ifdef JOBSXT
+ 	if (chsxt)
+ 		restore_sxt();
+ # endif JOBSXT
+ #else !JOB
  	await(0, 0);
  #endif JOB
  	while (stakbot != staktop)
***************
*** 291,296
  	while (d = readc())
  		pushstak(d | quote);
  	await(0, 0);
  	while (stakbot != staktop)
  	{
  		if ((*--staktop & STRIP) != NL)

--- 308,314 -----
  # endif JOBSXT
  #else !JOB
  	await(0, 0);
+ #endif JOB
  	while (stakbot != staktop)
  	{
  		if ((*--staktop & STRIP) != NL)
***************
*** 301,306
  	}
  	pop();
  }
  
  #define CPYSIZ	512
  

--- 319,325 -----
  	}
  	pop();
  }
+ 
  
  #define CPYSIZ	512
  
SHAR_EOF
fi
echo shar: "extracting 'main.c.Diff'" '(2410 characters)'
if test -f 'main.c.Diff'
then
	echo shar: "will not over-write existing file 'main.c.Diff'"
else
cat << \SHAR_EOF > 'main.c.Diff'
*** main.c	Mon Nov 24 17:49:25 1986
--- /cs/simon/c/shdiff-sources/main.c	Fri Feb 20 12:48:19 1987
***************
*** 147,152
  	dfault(&mchknod, MAILCHECK);
  	mailchk = stoi(mchknod.namval);
  
  	if ((beenhere++) == FALSE)	/* ? profile */
  	{
  		if (*(simple(cmdadr)) == '-')

--- 147,156 -----
  	dfault(&mchknod, MAILCHECK);
  	mailchk = stoi(mchknod.namval);
  
+ #ifdef JOB
+ 	initjobs();
+ #endif JOB
+ 
  	if ((beenhere++) == FALSE)	/* ? profile */
  	{
  		if (*(simple(cmdadr)) == '-')
***************
*** 186,191
  			comdiv--;
  		}
  	}
  #ifdef pdp11
  	else
  		*execargs = (char *)dolv;	/* for `ps' cmd */

--- 190,200 -----
  			comdiv--;
  		}
  	}
+ 	else {
+ #ifdef JOBSXT
+ 		extern int sxtchan;
+ 		sxtchan = -1;
+ #endif JOBSXT
  #ifdef pdp11
  		*execargs = (char *)dolv;	/* for `ps' cmd */
  #endif
***************
*** 187,193
  		}
  	}
  #ifdef pdp11
- 	else
  		*execargs = (char *)dolv;	/* for `ps' cmd */
  #endif
  		

--- 196,201 -----
  		sxtchan = -1;
  #endif JOBSXT
  #ifdef pdp11
  		*execargs = (char *)dolv;	/* for `ps' cmd */
  #endif
  	}
***************
*** 190,195
  	else
  		*execargs = (char *)dolv;	/* for `ps' cmd */
  #endif
  		
  	exfile(0);
  	done();

--- 198,204 -----
  #ifdef pdp11
  		*execargs = (char *)dolv;	/* for `ps' cmd */
  #endif
+ 	}
  		
  	exfile(0);
  	done();
***************
*** 262,267
  
  	if (input >= 0)
  		initf(input);
  	/*
  	 * command loop
  	 */

--- 271,281 -----
  
  	if (input >= 0)
  		initf(input);
+ 
+ #ifdef JOB
+ 	if (flags&ttyflg) setjob(0);
+ #endif
+ 
  	/*
  	 * command loop
  	 */
***************
*** 265,270
  	/*
  	 * command loop
  	 */
  	for (;;)
  	{
  		tdystak(0);

--- 279,285 -----
  	/*
  	 * command loop
  	 */
+ 
  	for (;;)
  	{
  		tdystak(0);
***************
*** 304,310
  
  		trapnote = 0;
  		peekc = readc();
! 		if (eof)
  			return;
  
  #ifdef TIME_OUT

--- 319,337 -----
  
  		trapnote = 0;
  		peekc = readc();
! 		if (eof){
! #ifdef JOBSXT
! 			if ((flags&ttyflg) && stpjobs()){
! 				int fd;
! 				prs("\nThere are blocked jobs\n");
! 				fd = sxtopen(1);
! 				if (fd>=0){
! 					initf(fd);
! 					continue;
! 				}
! 			}
! 				
! #endif JOBSXT
  			return;
  		}
  
***************
*** 306,311
  		peekc = readc();
  		if (eof)
  			return;
  
  #ifdef TIME_OUT
  		alarm(0);

--- 333,339 -----
  				
  #endif JOBSXT
  			return;
+ 		}
  
  #ifdef TIME_OUT
  		alarm(0);
SHAR_EOF
fi
echo shar: "extracting 'msg.c.Diff'" '(3167 characters)'
if test -f 'msg.c.Diff'
then
	echo shar: "will not over-write existing file 'msg.c.Diff'"
else
cat << \SHAR_EOF > 'msg.c.Diff'
*** msg.c	Mon Nov 24 17:49:26 1986
--- /cs/simon/c/shdiff-sources/msg.c	Wed Feb 18 20:30:56 1987
***************
*** 66,71
  char	mchkname[]	= "MAILCHECK";
  char	acctname[]  	= "SHACCT";
  char	mailpname[]	= "MAILPATH";
  
  /*
   * string constants

--- 66,73 -----
  char	mchkname[]	= "MAILCHECK";
  char	acctname[]  	= "SHACCT";
  char	mailpname[]	= "MAILPATH";
+ char	ntfyname[] 	= "NOTIFY";
+ char	TTYname[] 	= "REALTTY";
  
  /*
   * string constants
***************
*** 149,154
  	{ "[",		SYSTST },
  #endif
  
  	{ "break",	SYSBREAK },
  	{ "cd",		SYSCD	},
  	{ "continue",	SYSCONT	},

--- 151,159 -----
  	{ "[",		SYSTST },
  #endif
  
+ #ifdef JOB
+ 	{ "bg",		SYSBG },
+ #endif JOB
  	{ "break",	SYSBREAK },
  	{ "cd",		SYSCD	},
  	{ "continue",	SYSCONT	},
***************
*** 157,162
  	{ "exec",	SYSEXEC	},
  	{ "exit",	SYSEXIT	},
  	{ "export",	SYSXPORT },
  	{ "hash",	SYSHASH	},
  
  #ifdef RES

--- 162,170 -----
  	{ "exec",	SYSEXEC	},
  	{ "exit",	SYSEXIT	},
  	{ "export",	SYSXPORT },
+ #ifdef JOB
+ 	{ "fg",		SYSFG },
+ #endif JOB
  	{ "hash",	SYSHASH	},
  
  #ifdef JOB
***************
*** 159,164
  	{ "export",	SYSXPORT },
  	{ "hash",	SYSHASH	},
  
  #ifdef RES
  	{ "login",	SYSLOGIN },
  	{ "newgrp",	SYSLOGIN },

--- 167,177 -----
  #endif JOB
  	{ "hash",	SYSHASH	},
  
+ #ifdef JOB
+ 	{ "jobs",	SYSJOBS },
+ 	{ "kill",	SYSKILL },
+ #endif JOB
+ 
  #ifdef RES
  	{ "login",	SYSLOGIN },
  	{ "newgrp",	SYSLOGIN },
***************
*** 166,171
  	{ "newgrp",	SYSNEWGRP },
  #endif
  
  	{ "pwd",	SYSPWD },
  	{ "read",	SYSREAD	},
  	{ "readonly",	SYSRDONLY },

--- 179,188 -----
  	{ "newgrp",	SYSNEWGRP },
  #endif
  
+ #ifdef JOB
+ 	{ "notify",	SYSNOTIFY },
+ #endif JOB
+ 
  	{ "pwd",	SYSPWD },
  	{ "read",	SYSREAD	},
  	{ "readonly",	SYSRDONLY },
***************
*** 172,177
  	{ "return",	SYSRETURN },
  	{ "set",	SYSSET	},
  	{ "shift",	SYSSHFT	},
  	{ "test",	SYSTST },
  	{ "times",	SYSTIMES },
  	{ "trap",	SYSTRAP	},

--- 189,200 -----
  	{ "return",	SYSRETURN },
  	{ "set",	SYSSET	},
  	{ "shift",	SYSSHFT	},
+ #ifdef JOB
+ 	{ "stop",	SYSSTOP },
+ # ifdef JOBSXT
+ 	{ "sxt1",	SYSSXT1 },
+ # endif JOBSXT
+ #endif JOB
  	{ "test",	SYSTST },
  	{ "times",	SYSTIMES },
  	{ "trap",	SYSTRAP	},
***************
*** 188,193
  };
  
  #ifdef RES
  	int no_commands = 26;
  #else
  	int no_commands = 27;

--- 211,219 -----
  };
  
  #ifdef RES
+ # ifdef JOB
+ 	int no_commands = 33;
+ # else
  	int no_commands = 26;
  # endif
  #else
***************
*** 189,194
  
  #ifdef RES
  	int no_commands = 26;
  #else
  	int no_commands = 27;
  #endif

--- 215,221 -----
  	int no_commands = 33;
  # else
  	int no_commands = 26;
+ # endif
  #else
  # ifdef JOB
  	int no_commands = 34;
***************
*** 190,194
  #ifdef RES
  	int no_commands = 26;
  #else
  	int no_commands = 27;
  #endif

--- 217,225 -----
  	int no_commands = 26;
  # endif
  #else
+ # ifdef JOB
+ 	int no_commands = 34;
+ # else
  	int no_commands = 27;
  # endif
  #endif
***************
*** 191,194
  	int no_commands = 26;
  #else
  	int no_commands = 27;
  #endif

--- 221,225 -----
  	int no_commands = 34;
  # else
  	int no_commands = 27;
+ # endif
  #endif
SHAR_EOF
fi
echo shar: "extracting 'name.c.Diff'" '(1211 characters)'
if test -f 'name.c.Diff'
then
	echo shar: "will not over-write existing file 'name.c.Diff'"
else
cat << \SHAR_EOF > 'name.c.Diff'
*** name.c	Mon Nov 24 17:49:26 1986
--- /cs/simon/c/shdiff-sources/name.c	Wed Feb 18 18:23:31 1987
***************
*** 54,59
  	(struct namnod *)NIL,
  	mailname
  };
  struct namnod mchknod =
  {
  	&ifsnod,

--- 54,65 -----
  	(struct namnod *)NIL,
  	mailname
  };
+ struct namnod ntfynod =
+ {
+ 	(struct namnod *)NIL,
+ 	&ps1nod,
+ 	ntfyname
+ };
  struct namnod mchknod =
  {
  	&ifsnod,
***************
*** 57,63
  struct namnod mchknod =
  {
  	&ifsnod,
! 	&ps1nod,
  	mchkname
  };
  struct namnod acctnod =

--- 63,69 -----
  struct namnod mchknod =
  {
  	&ifsnod,
! 	&ntfynod,
  	mchkname
  };
  struct namnod TTYnod =
***************
*** 60,66
  	&ps1nod,
  	mchkname
  };
! struct namnod acctnod =
  {
  	(struct namnod *)NIL,
  	(struct namnod *)NIL,

--- 66,72 -----
  	&ntfynod,
  	mchkname
  };
! struct namnod TTYnod =
  {
  	(struct namnod *)NIL,
  	(struct namnod *)NIL,
***************
*** 63,68
  struct namnod acctnod =
  {
  	(struct namnod *)NIL,
  	(struct namnod *)NIL,
  	acctname
  };

--- 69,80 -----
  struct namnod TTYnod =
  {
  	(struct namnod *)NIL,
+ 	(struct namnod *)NIL,
+ 	TTYname
+ };
+ struct namnod acctnod =
+ {
+ 	&TTYnod,
  	(struct namnod *)NIL,
  	acctname
  };
SHAR_EOF
fi
exit 0
#	End of shell archive