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