[comp.unix.xenix] SVR3 signal functions on SCO XENIX 2.3.1

ag@elgar.UUCP (Keith Gabryelski) (02/09/89)

[It looks as if this one was lost somewhere along the line.  So, I
repost.  Apologies to those that have seen this before. --kmg]

From: ag@elgar.UUCP (Keith Gabryelski)
Subject: How to get SVR3 sigset(), sigignore(), sighold(), sigrelse(),
	 and sigpause() system calls on a 386 SCO XENIX 2.3.1 system.
Date: 29 Jan 89 22:12:10 GMT

This readme file documents how to get the System V Release 3 system
calls sighold(), sigignore(), sigpause(), and sigrelse() on a 386 SCO
XENIX 2.3.1 system running dev sys 2.2.0/2.2.1 (with fix LNG060).

If you do not have the LNG060 fix for your dev sys this stuff probably
will not work.  LN6060 is a free fix supplied by SCO.  Their Technical
Support Number is 1-800-626-4381.  Ask for `Media'.

In any case, sighold.o, sigrelse.o, sigignore.o, sigpause.o, and
sigset.o should all be in your 386 libc.a.  To check this, try:

	ar t /lib/386/Slibc.a

You should see the above mention .o files listed (probably near the
end).  If you do not, you probably need fix LNG060.

The sigset() system call works as supplied by SCO, but sighold() and
company require a function _sigcomm() not in libc.a.  This function is
supplied in this distribution as sigcomm.c.  Whenever you use the new
signal routines (except for sigset()) you must link in sigcomm.o and
agsig.o.  agsig() [in agsig.o] is an assembly language routine that
calls the real agsig() system call in the kernel.

You may want to put both these routines in /lib/386/Slibc.a.

I should mention that sigpause() doesn't really work.  That is, it is
pretty much equivalent to doing a "sigrelse(SIG); pause();" in that it
does not reset the hold mask for the argument it is given.  It seems
that the kernel resets u.u_procp->p_hold when it returns from a
handler.  Why?  I don't know, but to fixing it is beyond the scope of
my resources (ie, binary only).  Maybe somebody at SCO could explain?

newsig.c holds agsig(), the kernel system call, and agsiginit().
agsiginit() will automatically initialize agsig() in the sysent struct
at the entry number SYSNUM.  SYSNUM is defined in agsig.s and
newsig.c.  If you wish to change its value to something besides 0x42
you must change SYSNUM is BOTH files.  The number is also used in
`adbhack'

	[[[[ Here is how to install this on your System ]]]]

Obligatory warning: This is not supported by SCO.  I doubt they
intended this type of hack on their system.  Your mileage may vary.
This is public domain.

Unshar the following file and the read README.

The installation should be done while in single user mode.

#! /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 the files:
#	Makefile
#	README
#	adbhack
#	agsig.s
#	entry
#	manual_stuff
#	newsig.c
#	sigcomm.c
#	testing
# This archive created: Sun Jan 29 14:04:56 1989
export PATH; PATH=/bin:$PATH
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
SHELL= /bin/sh
CFLAGS= -g
LIBS=

all:	newsig.o agsig.o sigcomm.o
SHAR_EOF
fi # end of overwriting check
if test -f 'README'
then
	echo shar: will not over-write existing file "'README'"
else
cat << \SHAR_EOF > 'README'
	By Keith Gabryelski (ag@elgar.UUCP)

This readme file documents how to get the System V Release 3 system
calls sighold(), sigignore(), sigpause(), and sigrelse() on a 386 SCO
XENIX 2.3.1 system running dev sys 2.2.0/2.2.1 (with fix LNG060).

If you do not have the LNG060 fix for your dev sys this stuff probably
will not work.  LN6060 is a free fix supplied by SCO.  Their Technical
Support Number is 1-800-626-4381.  Ask for `Media'.

In any case, sighold.o, sigrelse.o, sigignore.o, sigpause.o, and
sigset.o should all be in your 386 libc.a.  To check this, try:

	ar t /lib/386/Slibc.a

You should see the above mention .o files listed (probably near the
end).  If you do not, you probably need fix LNG060.

The sigset() system call works as supplied by SCO, but sighold() and
company require a function _sigcomm() not in libc.a.  This function is
supplied in this distribution as sigcomm.c.  Whenever you use the new
signal routines (except for sigset()) you must link in sigcomm.o and
agsig.o.  agsig() [in agsig.o] is an assembly language routine that
calls the real agsig() system call in the kernel.

You may want to put both these routines in /lib/386/Slibc.a.

I should mention that sigpause() doesn't really work.  That is, it is
pretty much equivalent to doing a "sigrelse(SIG); pause();" in that it
does not reset the hold mask for the argument it is given.  It seems
that kernel resets u.u_procp->p_hold when it returns from a handler.
Why, I don't know, but to fixing it is beyond the scope of my
resources (ie, binary only).  Maybe somebody at SCO could explain?

newsig.c holds agsig(), the kernel system call, and agsiginit().
agsiginit() will automatically initialize agsig() in the sysent struct
at the entry number SYSNUM.  SYSNUM is defined in agsig.s and
newsig.c.  If you wish to change its value to something besides 0x42
you must change SYSNUM is BOTH files.  The number is also used in
`adbhack'

	[[[[ Here is how to install this on your System ]]]]

Obligatory warning: This is not supported by SCO.  I doubt they
intended this type of hack on their system.  Your mileage may vary.
This is public domain.

Unshar the following file and the read README.

The installation should be done while in single user mode.

SYSNUM (in agsig.s and newsig.c) is the index into the sysent array in
the kernel where _agsig() will be referenced.  The 0x42nd sysent entry
is not used on my system, to check your system read my earlier article
on select() and the sysent structure.  briefly:
	[
		nm /xenix | grep _nosys
			# The resulting number is the number placed in
			# empty systent structs.

		adb /xenix
		* $x
		* _systent,80/XXX
			# This will list all the sysent entries
			# find one entry where the last field is the
			# the number you received from grepping /xenix
			# for _nosys.
			# divide the address by 0x0C and that is the
			# index into the array you will use.


	# I used 0x42 on my system.

		adb xenix
		* $x
		* _sysent+(c*42)/XXX
		_sysent+0x318:	0x0	0x0	0x68f0    ;; 0x68f0 = _nosys

	]
	
Type `make'.  This will compile the necessary files that are supplied
in this distribution.

As `root' copy newsig.o /usr/sys/conf.

Modify /usr/sys/conf/link_xenix to link in newsig.o.  My link_xenix
looks like:

	[ -f xenix ] && mv xenix xenix-
	ld -Rd 1000 -D 18 -B 20 -A 0 -i -u start -o xenix \
		start.o c.o ../io/ctconf.o uts.o oem.o space.o tab.o kid.o \
		../ml/libml.a ../mdep/libmdep.a ../sys/libsys.a \
		../xnet/libxnstub.a ../io/libio.a ../io/libiostub.a newsig.o
	exit $?

If you want this to be a temporary hack you can modify the sysent
table by hand using the shell script `adbhack'.  You must modify the
kernel AFTER you remake it.

If you want this to be semi-permanent you must modify the init_tbl
array in /usr/include/sys/init.h to call agsiginit().  Here are the
diffs from my system:

	 [first `mv /usr/sys/conf/space.o /usr/sys/conf/OLDspace.o'
		so you won't be too hosed if things go wrong.]

---------------------- /usr/include/sys/init.h ----------------
    28a29
    > extern agsiginit();
    61a63
    > 	agsiginit,	/* new sig stuff */
----------------------------------------------------------------

Now, type `make' in /usr/sys/conf.  This will remake the kernel making
a new space.o and linking in newsig.o.

	[If you decided to use `adbhack' instead of modifying init.h
	 do `adbhack' now].

You should be all set.

cp /xenix /xenix.good
mv /usr/sys/conf/xenix /xenix

reboot your machine.

	** If your system does not boot (or panics while booting) you
	** did something wrong!  Reboot and type `xenix.good' at the
	** `:' boot prompt and try again.

To test the new system calls try the programs in the testing
directory.

If you have problems or comments, send them to me.  If I can help, I
will:

	Keith Gabryelski (ag@elgar.UUCP)

Elgar does not support this distribution.
SHAR_EOF
fi # end of overwriting check
if test -f 'adbhack'
then
	echo shar: will not over-write existing file "'adbhack'"
else
cat << \SHAR_EOF > 'adbhack'
:
#
# Bourne shell script that will modify the sysent structure if you
# don't do the init_tbl hack.
#
# Remember to `42' in (c*42) below to SYSUM if you change its value
# in agsig.s or (and) newsig.c
#

adb -w xenix << ADB_EOF
\$x
_sysent+(c*42)/W20203
_sysent+(c*42)+4/W33
_sysent+(c*42)+8/W_agsig
_sysent+(c*42)/XXX
ADB_EOF
SHAR_EOF
chmod +x 'adbhack'
fi # end of overwriting check
if test -f 'agsig.s'
then
	echo shar: will not over-write existing file "'agsig.s'"
else
cat << \SHAR_EOF > 'agsig.s'
; agsig
;
;	Supplemental libc sig routine.
;
; By Keith Gabryelski (ag@elgar.UUCP)
; Public Domain
;

	title	agsig

	.386

SYSNUM	equ 	42h

extrn	_errno:dword

public  _agsig

_TEXT	segment  dword use32 public 'CODE'
	assume   cs: _TEXT
_agsig	proc near
	mov	eax, SYSNUM		; Get system call number.

	;
	; I don't even pretend to understand masm syntax.  I tried
	; the following line (and variations) without any success.
	;

;	call    far 7:0			; Switch to kernel and call SYSNUM.

	;
	; Don't laugh, it works.
	;

	db 9ah
	dw 0,0
	dw 7

	jb	short _cerror		; below == error.

	ret				; done.

_cerror:
	mov	_errno, eax		; Save error code in _errno.
	mov	eax, -1			; Return -1 (as error).
	ret				; done.

_agsig	endp

_TEXT	ends

	end
SHAR_EOF
fi # end of overwriting check
if test -f 'entry'
then
	echo shar: will not over-write existing file "'entry'"
else
cat << \SHAR_EOF > 'entry'
    42     | 00 | 02 | 02 | 03 | 0 0 0 0 0 0 3 3 | _agsig



adb -w xenix
* $x
* _sysent+(c*42)/XXX
_sysent+0x318:	0x0		0x0		0x68f0    ;; 0x68f0 = _nosys
* _sysent+(c*42)/W20203
* _sysent+(c*42)+4/W33
* _sysent+(c*42)+8/W_agsig
* _sysent+(c*42)/XXX
_sysent+0x318:	0x020203	0x33		_agsig	  ;; _agsig = ??
SHAR_EOF
fi # end of overwriting check
if test -f 'manual_stuff'
then
	echo shar: will not over-write existing file "'manual_stuff'"
else
cat << \SHAR_EOF > 'manual_stuff'
Here is a brief description of the new system calls.

	#include <signal.h>

sigset(signum, func)
int signum;
int (*func)();
	Just like signal(S) except will defer any signals that are
	caught until after there handler is finished.  If you
	longjmp() out of a handler, use sigrelse().

	sigset(S) (and possibly signal(S)) have another argument
	for FUNC arg; SIG_HOLD.  sigset(signum, SIG_HOLD) is
	equivalent to doing a sighold(signum).  This defers the
	signal until a sigrelse(signum) is done.

sigignore(signum)
int signum;
	Equivalent to sigset(signum, SIG_IGN).  Ignore a signal.

sighold(signum)
int signum;
	Defer a signal until a sigrelse(S) is done.

sigrelse(signum)
int signum;
	Release a previously held signal.

sigpause(signum)
int signum;
	Like pause() except does an autonomous sigrelse(signum) before
	pausing and sighold(signum) afterwards.

		(Actually this doesn't really work.  See the readme file).



	
SHAR_EOF
fi # end of overwriting check
if test -f 'newsig.c'
then
	echo shar: will not over-write existing file "'newsig.c'"
else
cat << \SHAR_EOF > 'newsig.c'
/*
** newsig.c
**
**		Handle sigrelse() and sigpause() system calls
**		on a SCO XENIX 2.2.3 with dev system 2.2.1 with fix
**		LNG060.
**
** By: Keith Gabryelski (ag@elgar.UUCP)
**
** Public domain.
*/

#define M_KERNEL

#include <sys/types.h>
#include <sys/signal.h>
#include <sys/errno.h>
#include <sys/sysmacros.h>
#include <sys/page.h>
#include <sys/seg.h>
#include <sys/param.h>
#include <sys/proc.h>
#include <sys/dir.h>
#include <sys/user.h>
#include <sys/systm.h>

/*
** SYSNUM is the sysent number where agsig will be installed.  If you
** change it here, be sure to change it in agsig.s.
*/

#define SYSNUM 0x42		/* Found out that pipe() was 42 decimal
				   the hard way ... */

/*
** agsig() - handle sigpause() and sigrelse() system calls.
**
** agsig() takes two arguments; type (INT) defines what type of
** system call this is (defined in signal.h) and sig (INT) defines
** which signal we should handle.
*/

agsig()
{
    struct ap 
    {
	int type;
	int sig;
    } *ap = (struct ap *)u.u_ap;	/*
					** Args to system calls are actually
					** passed in u.u_ap in the kernel.
					*/
    
    switch(ap->type)
    {
    case SIGRELSE:
	if (ap->sig > NSIG || ap->sig < 1)	/* Bad signal? */
	    u.u_error = EINVAL;
	else
	    u.u_procp->p_hold &= ~(1<<(ap->sig-1));   /* Clear p_hold bit */
	return;
	
    case SIGPAUSE:
	if (ap->sig > NSIG || ap->sig < 1)	/* BADSIG? */
	    u.u_error = EINVAL;
	else
	{
	    u.u_procp->p_hold &= ~(1<<(ap->sig-1)); /* clear p_hold bit. */
	    sleep(&u, PSLEP|PCATCH);		/* sleep until signal */

	    if (issig())
		psig();				/* handle signal */

	    u.u_procp->p_hold |= (1<<(ap->sig-1)); /* hold signal */
	}
	return;
	
    case SIGHOLD:
    case SIGIGNORE:
    case SIGDEFER:
    default:
	u.u_error = EINVAL;
	return;
    }
}

/*
** agsiginit() - initialize the sysnet struct with the agsig system call
**		 as the SYSNUM entry.
*/

agsiginit()
{
    sysent[SYSNUM].sy_ret = 0;			/* return value INT */
    sysent[SYSNUM].sy_arg386 = 2;		/* 2 386 words */
    sysent[SYSNUM].sy_nlarg286 = 2;		/* 2 286 words */
    sysent[SYSNUM].sy_nmarg286 = 3;		/* something */
    sysent[SYSNUM].sy_argmask = MASK(CONST,CONST,0,0,0,0); /* types of args */
    sysent[SYSNUM].sy_call = agsig;		/* the system call routine */

    printf("sigrelse()/sigpause() installed in sysent entry 0x%x.\n", SYSNUM);
}
SHAR_EOF
fi # end of overwriting check
if test -f 'sigcomm.c'
then
	echo shar: will not over-write existing file "'sigcomm.c'"
else
cat << \SHAR_EOF > 'sigcomm.c'
/*
** sigcomm.c - interface routines for sighold() and company.
**	       This routine uses routines in agsig.s
**
** By: Keith Gabryelski (ag@elgar.UUCP)
** Public domain.
*/

#define M_KERNEL
#include <sys/signal.h>
#undef M_KERNEL

#include <sys/errno.h>

extern int errno;

_sigcomm(type)
int type;
{
    int sig;

    sig = type&SIGNO_MASK;

    switch(type&~(SIGNO_MASK))
    {
    case SIGHOLD:
	if (sigset(sig, SIG_HOLD) < 0)
	    return -1;
	return 0;

    case SIGIGNORE:
	if (sigset(sig, SIG_IGN) < 0)
	    return -1;
	return 0;

    case SIGRELSE:
	return agsig(SIGRELSE, sig);
	
    case SIGPAUSE:
	return agsig(SIGPAUSE, sig);
	
    case SIGDEFER:
    default:
	errno = EINVAL;
	return -1;
    }
}
SHAR_EOF
fi # end of overwriting check
if test ! -d 'testing'
then
	mkdir 'testing'
fi
cd 'testing'
if test -f 'sighr.c'
then
	echo shar: will not over-write existing file "'sighr.c'"
else
cat << \SHAR_EOF > 'sighr.c'
/*
** sighr.c - Test sighold() and sigrelse().
**
** By: Keith Gabryelski (ag@elgar.UUCP)
** Public domain.
*/

#include <stdio.h>
#include <signal.h>

handler(sig)
{
    printf("signal received %d.\n", sig);
    exit(1);
}

main()
{
    sigset(SIGINT, handler);

    if (sighold(SIGINT) < 0)
    {
	perror("sighold");
	exit(1);
    }

    puts("SIGINT is being held.  .<cr> to continue.");

    while(getchar() != '.')
	;

    puts("SIGINT is being release.");

    if (sigrelse(SIGINT) < 0)
	perror("sigrelse");

    puts("SIGINT has been release.");
}
SHAR_EOF
fi # end of overwriting check
if test -f 'spause.c'
then
	echo shar: will not over-write existing file "'spause.c'"
else
cat << \SHAR_EOF > 'spause.c'
/*
** spause.c - Test sigpause().
**
** By Keith Gabryelski (ag@elgar.UUCP)
** Public Domain
*/

#include <stdio.h>
#include <signal.h>

int foo;

handler(sig)
{
    printf("signal received %d.\n", sig);
    foo = 1;
}

main()
{
    foo = 0;

    sigset(SIGINT, handler);

    if (sighold(SIGINT) < 0)
    {
	perror("sighold");
	exit(1);
    }

    sleep(5);
    
    puts("SIGINT is being held, doing a sigpause(SIGINIT).\n");

    sigpause(SIGINT);

    /*    sighold(SIGINT); */
    /*
    ** sigpause() does not re-hold the signal when it exits.
    ** I think the kernel is intenionally doing this for some
    ** confused reason.
    */

    puts("SIGINT is being release.");

    sleep(5);
    
    sigrelse(SIGINT);
    
    puts("SIGINT has been release.");
}
SHAR_EOF
fi # end of overwriting check
if test -f 'settest.c'
then
	echo shar: will not over-write existing file "'settest.c'"
else
cat << \SHAR_EOF > 'settest.c'
/*
** settest.c - Test sigset().
**
** By: Keith Gabryelski (ag@elgar.UUCP)
** Public Domain.
*/

#include <stdio.h>
#include <signal.h>

handler(sig)
int sig;
{
    int i;
    
    printf("signal received %d.\n", sig);

    for (i=10; i > 0 ; --i)
    {
	printf("SIGINT being held in int handler. %d more seconds\n", i);
	sleep(1);
    }
}

doquit(sig)
int sig;
{
    exit(0);
}

main()
{
    sigset(SIGINT, handler);
    sigset(SIGQUIT, doquit);

    puts("sigset() done ... waiting");

    while(1)
    {
	puts("In main() looping for an interrupt.");
	sleep(1);
    }
}
SHAR_EOF
fi # end of overwriting check
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
#
# Makefile for testing new signal routines.
#
#	This ASSUMES that the new kernel has been booted and
#	sigcomm.o/agsig.o exist in ..
#
# By: Keith Gabyrelski
# Public Domain
#

SHELL= /bin/sh
CFLAGS= -g
LIBS=

all:	settest sighr spause

settest:	settest.c
	cc $(CFLAGS) settest.c ../sigcomm.o ../agsig.o -o settest

sighr:	sighr.c
	cc $(CFLAGS) sighr.c ../sigcomm.o ../agsig.o -o sighr

spause:	spause.c
	cc $(CFLAGS) spause.c ../sigcomm.o ../agsig.o -o spause
SHAR_EOF
fi # end of overwriting check
cd ..
#	End of shell archive
exit 0
-- 
ag@elgar.CTS.COM         Keith Gabryelski          ...!{ucsd, crash}!elgar!ag

-- 
ag@elgar.CTS.COM         Keith Gabryelski          ...!{ucsd, crash}!elgar!ag