diff --git a/bin/gsh/tests/Makefile b/bin/gsh/tests/Makefile new file mode 100644 index 0000000..9168d9c --- /dev/null +++ b/bin/gsh/tests/Makefile @@ -0,0 +1,40 @@ +# +# This makefile is intended for use with dmake(1) on Apple IIGS +# $Id: Makefile,v 1.1 1999/11/30 20:28:24 tribby Exp $ +# +# Created by Dave Tribby (beginning June 1998) + +# This makefile creates the simple test programs used for gsh testing. +# These two programs are used directly by the dotests command script: +# echoparams echo parameters passed from command line; +# uses reparse.asm assembly language subroutine +# callsystem call the system() library subroutine +# +# The remaining two programs can be run to verify the system +# shellenv print information on the shell environment +# testfork use fork/_execve/wait/kill the way gsh does + + +# Make sure lint is turned on +CFLAGS += -w + +all: echoparams callsystem shellenv testfork + +# echoparams has a helper subroutine named reparse. +echoparams.o: echoparams.c + +reparse.o: reparse.asm + +echoparams: echoparams.c reparse.asm + 17/occ -o echoparams.o -i -w -a0 -c echoparams.c + 17/occ -o reparse.o -i -w -a0 -c reparse.asm + 17/occ -o echoparams echoparams.o reparse.o + rm -f echoparams.root echoparams.o reparse.root reparse.o + +clean: + rm -f *.o + rm -f *.root + +clobber: clean + rm -f echoparams callsystem shellenv testfork + diff --git a/bin/gsh/tests/callsystem.c b/bin/gsh/tests/callsystem.c new file mode 100644 index 0000000..3770376 --- /dev/null +++ b/bin/gsh/tests/callsystem.c @@ -0,0 +1,26 @@ +/* + * callsystem.c: see what happens when system() is called + * + * Written by Dave Tribby to test gsh * June 1998 + * $Id: callsystem.c,v 1.1 1999/11/30 20:28:24 tribby Exp $ + */ + +#include +#include + +int main(int argc, char *argv[]) +{ + int i, rtnval; + printf("Test of system() function\n"); + *argv++; + if (argc == 1) { + rtnval = system((char *)0L); + printf(" Null parameter returns value of %d\n", rtnval); + } + else for (i = 1; i < argc; i++) { + rtnval = system(*argv); + printf(" `%s` returns value = %d\n", *argv,rtnval); + *argv++; + } + return rtnval; +} diff --git a/bin/gsh/tests/dotests b/bin/gsh/tests/dotests new file mode 100644 index 0000000..f942556 --- /dev/null +++ b/bin/gsh/tests/dotests @@ -0,0 +1,596 @@ +# Test gsh built-in commands +# Written by Dave Tribby beginning June 1998 +# $Id: dotests,v 1.1 1999/11/30 20:28:24 tribby Exp $ +# ----------------------------------------------------------------------- +# Support commands that must be available (usually in tests directory) +# echoparams echo parameters passed from command line; +# uses reparse.asm assembly language subroutine +# callsystem call the system() library subroutine +# Support exec files that must be available (usually in tests directory) +# prin10params prints $0 through $10 +# singletc execute a single test and compare results +# releasemem releases most gsh memory; use with debug mem mgr +# +# Additional job control tests that cannot be part of this file are +# found in testjobs and testjobs2. +# +# Output comparison files are read from the directory specified within this +# script by variable $cmpout (/src/gno/bin/gsh/tests/bi.out/). NOTE: the +# hash.list file needs updating when contents of /bin and /usr/bin changes. +# ----------------------------------------------------------------------- + +# NOTE: $PATH might be messed up, so use full path for sed +set SED=/usr/bin/sed + +# Clean up the alias environment, so results are consistent +# A. Generate the cleanup aliases command file +set tmpcmd=/tmp/cleanalias +alias | $SED -e 's/:.*//' -e 's/^/unalias /' > $tmpcmd +# B. Run the cleanup command +echo -n "Removing all aliases..." +source $tmpcmd +echo + +# Clean up the variable environment, so results are consistent +# A. Generate the cleanup variables command file +set tmpcmd=/tmp/cleanenv +set | $SED -e '/TERM/d' -e 's/ = .*//' -e 's/^/unset /' > $tmpcmd +# B. Run the cleanup command +echo -n "Removing environment variables..." +source $tmpcmd +echo + +# Add back a few environment variables + +# Location of shell to be tested +set objdir /obj/gno/bin/gsh +setenv SHELL=$objdir/gsh + +setenv USER=test + +set testdir=/src/gno/bin/gsh/tests +setenv HOME=$testdir + +setenv PATH "$objdir" +set PATH "$testdir $PATH /bin /usr/bin" +export PATH +rehash + +# Directories for holding test output and comparison output +setenv cmpdir=$testdir/bi.out +setenv outdir=/tmp/bi.out + +# Use either cmp or diff for comparing files +setenv compare="diff" +setenv compare="cmp" + +# Create directory under /tmp to hold results +# GNO's rm command is no longer implemented under the cp command +set RM="/bin/rm" + +# Create directory under /tmp to hold results +echo -n "Removing output directory $outdir..." +$RM -rf $outdir/* +rmdir $outdir +echo +mkdir $outdir + + +echo " = = = = = Start of $SHELL built-in tests = = = = =" +echo "" + +# Use clear at beginning +setenv testcmd="clear" +echo "Test: $testcmd" +$testcmd +echo " Completion status for $testcmd = $status" +echo "" + +# There should be no aliases at this point +setenv testcmd="alias" +setenv listfile="$testcmd.0.list" +singletc + +# Add a few aliases back in +echo "Adding aliases for ls and mv" +alias ls 'ls -l' +alias mv 'cp -p mv' + +setenv testcmd="alias" +setenv listfile="$testcmd.list" +singletc + +setenv testcmd="alias" +setenv testarg="newcmd date" +echo "Test: $testcmd $testarg" +$testcmd $testarg +echo " Completion status = $status" +unset testarg + +setenv testcmd="unalias" +setenv testarg="newcmd" +echo "Test: $testcmd $testarg" +$testcmd $testarg +echo " Completion status = $status" +unset testarg + +setenv testcmd="which" +setenv testarg="ls" +setenv listfile="$testcmd.0.list" +singletc + +setenv testcmd="unalias" +echo "Test: $testcmd $testarg" +$testcmd $testarg +echo " Completion status = $status" + +setenv testcmd="which" +setenv listfile="$testcmd.list" +singletc +unset testarg + + +setenv testcmd="echo" +echo "Test: $testcmd" +setenv listfile="$testcmd.list" +echo '\- - - - - - - - - - E C H O T E S T S - - - - - - - - - -' > $outdir/$listfile +echo >> $outdir/$listfile +echo Testing whether the echo command inserts an extra space: >> $outdir/$listfile +echo -n "There should be no space between ->" >> $outdir/$listfile +echo "<- the '->' and '<-'" >> $outdir/$listfile +echo " Completion status = $status" +echo "Checking results against control file (no differences expected)" +$compare $cmpdir/$listfile $outdir/$listfile +echo " comparison status = $status for $listfile" +echo "" + +set testcmd=sed +echo "Test: $testcmd and redirected stdin/stdout" +setenv infile="${testcmd}0.in" +setenv listfile1="${testcmd}1.list" +echo "This is a test" > $outdir/$infile +echo "This is another test" >> $outdir/$infile +$testcmd -e's/test/success/' < $outdir/$infile > $outdir/$listfile1 +$compare $cmpdir/$listfile1 $outdir/$listfile1 +echo " comparison status = $status for $listfile1" +echo "" + +setenv listfile2="${testcmd}2.list" +echo "Test: $testcmd and pipes" +cat $outdir/$infile | $testcmd -e's/test/success/' | cat > $outdir/$listfile2 +$compare $cmpdir/$listfile1 $outdir/$listfile2 +echo " comparison status = $status for $listfile2" +echo "" + + +setenv testcmd="commands" +setenv listfile="$testcmd.list" +singletc + + +setenv testcmd="export" + +setenv testcmd="set" +setenv listfile="$testcmd.list" +singletc + + +## NOTE: need to clean up prefixes so results are consistent + +# NOTE: since prefix is a non-forked built-in command, it must be +# executed from a new shell to capture its output +setenv testcmd="$SHELL" +setenv testarg="-f prefix" +setenv listfile="prefix.list" +singletc +unset testarg + + +setenv testcmd="pushd" +setenv testarg="$cmpdir" +echo "Test: $testcmd $testarg" +$testcmd $testarg +echo " Completion status = $status" +unset testarg + +setenv testcmd="dirs" +echo "Test: $testcmd $testarg" +$testcmd $testarg +echo " Completion status = $status" +unset testarg + +setenv testcmd="cd" +setenv testarg="$outdir" +echo "Test: $testcmd $testarg" +$testcmd $testarg +echo " Completion status = $status" +unset testarg + +# NOTE: since pwd is a non-forked built-in command, it must be +# executed from a new shell to capture its output +setenv testcmd="$SHELL" +setenv testarg="-f pwd" +setenv listfile="pwd.list" +singletc +unset testarg + +setenv testcmd="chdir" +setenv testarg="/bin" +echo "Test: $testcmd $testarg" +$testcmd $testarg +echo " Completion status = $status" +unset testarg + +setenv testcmd="$SHELL" +setenv testarg="-f pwd" +setenv listfile="pwd.2.list" +singletc +unset testarg + +setenv testcmd="popd" +echo "Test: $testcmd $testarg" +$testcmd $testarg +echo " Completion status = $status" +unset testarg + + +## NOTE: may need shorter path so results are consistent, +## but also need access to /bin and /usr/bin commands. +setenv testcmd="rehash" +echo "Test: $testcmd $testarg" +$testcmd $testarg +echo " Completion status = $status" + +## Comparison file hash.list may need to be replaced, depending upon +## changes to contents of /bin/ and /usr/bin/ directories. +setenv testcmd="hash" +setenv listfile="$testcmd.list" +singletc + +# Create two commands by the same name in different directories +setenv testcmd="pathtst" +echo "echo This is test command number 1" > /tmp/$testcmd +chtyp -l exec /tmp/$testcmd +echo "echo This is test command number 2" > $outdir/$testcmd +chtyp -l exec $outdir/$testcmd + +# Add those directories to $PATH (holding onto the old $PATH) +setenv holdpath="$PATH" +setenv PATH="/tmp $outdir $PATH" +rehash +setenv listfile="$testcmd.1.list" +singletc + +# Reorder the search of $PATH and try again +setenv OLDPATHMODE=1 +rehash +setenv testarg="with OLDPATHMODE set" +setenv listfile="$testcmd.2.list" +singletc +unset testarg + +# Reset environment so $PATH acts in the expected way +setenv PATH="$holdpath" +unset OLDPATHMODE +unset holdpath +rehash +$RM /tmp/$testcmd $outdir/$testcmd + + +setenv testcmd="unhash" + + +# Job control: see separate file "testjobs", which must be sourced. + +setenv testcmd="bg" + +setenv testcmd="fg" + +setenv testcmd="kill" + +setenv testcmd="stop" + +setenv testcmd="jobs" + + + +# Cannot test output from these...just status + +setenv testcmd="tset" +echo "Test: $testcmd" +$testcmd +echo " Completion status = $status" +echo "" + +setenv testcmd="setdebug" +setenv testarg="-pathtrace" +echo "Test: $testcmd" +$testcmd $testarg +echo " Completion status = $status" +echo "" +unset testarg + +setenv testcmd="bindkey" + + +setenv testcmd="history" +echo "Test: $testcmd" +$testcmd +echo " Completion status = $status" + +setenv testcmd="ps" +echo "Test: $testcmd" +$testcmd +echo " Completion status = $status" +echo "" + + +# These have been tested enough through other uses + +setenv testcmd="source" + +setenv testcmd="unset" + +setenv testcmd="setenv" + + + +# Cannot figure how to test these... + +setenv testcmd="exit" + +setenv testcmd="edit" + + +# Create a gsh execution file with a forked command in it and execute +# it two different ways. (From "cmdtest") +echo +echo "= = Testing execution file with forked commands = = = = = = = " + +set tmpcmd=/tmp/testcmds +echo -n > $tmpcmd +chtyp -l exec $tmpcmd + +set echo_cmd="/bin/echo" +set ps_cmd="/bin/ps -l" +echo "$echo_cmd $ps_cmd" >> $tmpcmd +echo "$ps_cmd" >> $tmpcmd + +# Execute the command +echo -n "= = Executing as a command: " +$tmpcmd + +# Source the command +echo -n "= = Sourcing the command: " +source $tmpcmd + +echo "= = Execution files did not hang: test successful! = = = = = =" + + +echo +echo " = = = = = Start of $SHELL commandline expansion tests = = = =" +echo + +setenv home=/src/gno/bin/gsh/tests + +setenv listfile="tilde.list" +echo 'Test: echo ~/ ~:' +echo ~/ ~: > $outdir/$listfile +echo " Completion status = $status" +echo "Checking results against control file (no differences expected)" +$compare $cmpdir/$listfile $outdir/$listfile +echo " comparison status = $status for $listfile" +echo "" + +setenv listfile="glob.list" +echo 'ls *.c bad*name dot*' +ls *.c bad*name dot* > $outdir/$listfile +echo " Completion status = $status" +echo "Checking results against control file (no differences expected)" +$compare $cmpdir/$listfile $outdir/$listfile +echo " comparison status = $status for $listfile" +echo "" + +setenv listfile="multi.list" +echo 'Test: multiple commands separated by ";"' +set t_num=0 +set t_num=1 ; echo "Test variable has been set to $t_num" > $outdir/$listfile +echo " Completion status = $status" +echo "Checking results against control file (no differences expected)" +$compare $cmpdir/$listfile $outdir/$listfile +echo " comparison status = $status for $listfile" +echo "" +unset t_num + +setenv listfile="semi.list" +echo 'Test: semicolons within quoted parameters' +echoparams "This ; will" 'see if ; are confusing' > $outdir/$listfile +echo " Completion status = $status" +echo "Checking results against control file (no differences expected)" +$compare $cmpdir/$listfile $outdir/$listfile +echo " comparison status = $status for $listfile" +echo "" + +setenv listfile="null.list" +echo 'Test: null parameters' +echoparams "Parameter #1" "" p3 '' "Last param" > $outdir/$listfile +echo " Completion status = $status" +echo "Checking results against control file (no differences expected)" +$compare $cmpdir/$listfile $outdir/$listfile +echo " comparison status = $status for $listfile" +echo "" + +# Next two commands operate with KEEPQUOTE environment variable set + +setenv listfile=keep.list +echo 'Test: keep single quotes around parameters' +setenv KEEPQUOTE=1 +echoparams 'Parameter #1' "" p3 '' "Last param" > $outdir/$listfile +echo " Completion status = $status" +unset KEEPQUOTE +echo "Checking results against control file (no differences expected)" +$compare $cmpdir/$listfile $outdir/$listfile +echo " comparison status = $status for $listfile" +echo "" + +setenv listfile=keep2.list +echo 'Test: keep single quotes around parameters, again' +setenv KEEPQUOTE=1 +echoparams '{ print "Hello, world" }' filename > $outdir/$listfile +echo " Completion status = $status" +unset KEEPQUOTE +echo "Checking results against control file (no differences expected)" +$compare $cmpdir/$listfile $outdir/$listfile +echo " comparison status = $status for $listfile" +echo "" + + +# Ensure that $0 - $10 are created appropriately +setenv testcmd="print10params" +setenv listfile="print10.list" +echo "Test: $testcmd" +$testcmd p1 p2 p3 p4 p5 p6 p7 p8 p9 p10 > $outdir/$listfile +echo " Completion status = $status" +echo "Checking results against control file (no differences expected)" +$compare $cmpdir/$listfile $outdir/$listfile +echo " comparison status = $status for $listfile" +echo + +echo +echo " = = = = = = Start of $SHELL system() interface tests = = = = =" +echo + +setenv listfile="nullsys.list" +echo 'Test: call system() with null parameter' +callsystem "" > $outdir/$listfile +echo " Completion status = $status" +echo "Checking results against control file (no differences expected)" +$compare $cmpdir/$listfile $outdir/$listfile +echo " comparison status = $status for $listfile" +echo "" + +set sys_cmd "ps" +echo "Test: concurrent execution of $sys_cmd" +callsystem "$sys_cmd" & ; callsystem "$sys_cmd" +echo +set sys_cmd "/bin/ps -l" +echo "Test: concurrent execution of $sys_cmd" +callsystem "$sys_cmd" & ; callsystem "$sys_cmd" +echo +set sys_cmd "pwd" +echo "Test: concurrent execution of $sys_cmd" +callsystem "$sys_cmd" & ; callsystem "$sys_cmd" +echo +set sys_cmd "rehash" +echo "Test: concurrent execution of $sys_cmd" +callsystem "$sys_cmd" & ; callsystem "$sys_cmd" +echo +set sys_cmd "hash" +echo "Test: concurrent execution of $sys_cmd" +callsystem "$sys_cmd" & ; callsystem "$sys_cmd" +echo +echo "= = = Execution did not hang: test successful! = = = = =" + +echo +echo " = = = = = $SHELL commands' usage strings and status test = = = =" +echo + +# Non-forked commands + +bg a b c +echo " Completion status = $status (expected 1)" + +chdir a b c +echo " Completion status = $status (expected 1)" + +cd a b c +echo " Completion status = $status (expected 1)" + +clear a b c +echo " Completion status = $status (expected 1)" + +export +echo " Completion status = $status (expected 1)" + +fg a b c +echo " Completion status = $status (expected 1)" + +jobs a b c +echo " Completion status = $status (expected 1)" + +kill a b c +echo " Completion status = $status (expected 1)" + +popd a b c +echo " Completion status = $status (expected 1)" + +prefix a b c +echo " Completion status = $status (expected 1)" + +pushd a b c +echo " Completion status = $status (expected 1)" + +pwd a b c +echo " Completion status = $status (expected 1)" + +rehash a b c +echo " Completion status = $status (expected 1)" + +stop a b c +echo " Completion status = $status (expected 1)" + +tset a b c +echo " Completion status = $status (expected 1)" + +unalias +echo " Completion status = $status (expected 1)" + +unhash a b c +echo " Completion status = $status (expected 1)" + +unset +echo " Completion status = $status (expected 1)" + + +# Forked commands + +commands a b b +echo " Completion status = $status (expected 1)" + +setdebug a b c +echo " Completion status = $status (expected 1)" + +dirs a b c +echo " Completion status = $status (expected 1)" + +hash a b c +echo " Completion status = $status (expected 1)" + +ps a b c +echo " Completion status = $status (expected 1)" + +set -x +echo " Completion status = $status (expected 1)" + +setenv -x +echo " Completion status = $status (expected 1)" + +bindkey a b c +echo " Completion status = $status (expected 1)" + +echo -x +echo " Completion status = $status (expected 1)" + +history a b c +echo " Completion status = $status (expected 1)" + +which +echo " Completion status = $status (expected 1)" + +edit +echo " Completion status = $status (expected 1)" + +echo +echo " = = = = = End of $SHELL tests = = = = =" +echo +echo "Note: To test job control commands, source testjobs and testjobs2." diff --git a/bin/gsh/tests/echoparams.c b/bin/gsh/tests/echoparams.c new file mode 100644 index 0000000..579ca5e --- /dev/null +++ b/bin/gsh/tests/echoparams.c @@ -0,0 +1,30 @@ +/* + * echoparams: echo the arguments passed as parameters + * + * Written by Dave Tribby to test gsh * June 1998 + * $Id: echoparams.c,v 1.1 1999/11/30 20:28:24 tribby Exp $ + */ + +#include +#include + +/* Interface to subroutine that re-parses parameters */ +extern int reparse(char *argv[], char *commandline); + +int main(int argc, char *argv[]) +{ + int i; + int argc1; + char **argv1; + + printf("Command line: %s\n", commandline()); + for (i = 0; i < argc; i++) + printf(" parameter %2d: '%s'\n", i,*argv++); + + printf("Reparsing...\n"); + argc1 = reparse(&argv1, commandline()); + for (i = 0; i < argc1; i++) + printf(" parameter %2d: '%s'\n", i,*argv1++); + + return 0; +} diff --git a/bin/gsh/tests/print10params b/bin/gsh/tests/print10params new file mode 100644 index 0000000..21a7a0e --- /dev/null +++ b/bin/gsh/tests/print10params @@ -0,0 +1,11 @@ +echo "p0 = $0" +echo "p1 = $1" +echo "p2 = $2" +echo "p3 = $3" +echo "p4 = $4" +echo "p5 = $5" +echo "p6 = $6" +echo "p7 = $7" +echo "p8 = $8" +echo "p9 = $9" +echo "p10 = $10" diff --git a/bin/gsh/tests/releasemem b/bin/gsh/tests/releasemem new file mode 100644 index 0000000..9c96a85 --- /dev/null +++ b/bin/gsh/tests/releasemem @@ -0,0 +1,49 @@ +# Release as much memory as possible from current invocation of gsh. +# This is only useful when using the debug version of memory routines +# found in mmdebug.asm, because the normal memory routines hold on to +# allocated memory for reuse. The steps for using this to check for +# memory leaks: +# - link gsh with debug memory management routines +# - execute that version (it will be much slower than normal) +# - perform activities with the debug gsh +# - source this file +# - get memory manager ID of the debug gsh (via ps, for example) +# - using the NiftyList NDA, list memory allocated by MMID+$0D00; +# for example, if MMID=1009 enter the NiftyList command +# 1D09id +# There should be several blocks of size $400, plus blocks for +# strings holding the current directory, the current command, +# and the name of the history file. All other allocated memory +# is suspicious. (If a gsh command is killed, its memory will +# probably be left allocated.) +# Written by Dave Tribby (November 1998) +# $Id: releasemem,v 1.1 1999/11/30 20:28:24 tribby Exp $ + +echo " = = = = = Releasing gsh allocated memory = = = = =" +echo " Note: This command should be sourced, not executed" +echo + +# NOTE: $PATH might be messed up, so use full path for sed and cat +set SED=/usr/bin/sed +set CAT=/bin/cat + +echo -n "Removing all aliases..." +# A. Generate the cleanup aliases command file +set tmpcmd=/tmp/cleanalias +alias | $SED -e 's/:.*//' -e 's/^/unalias /' > $tmpcmd +# B. Run the cleanup command +source $tmpcmd +echo + +echo -n "Releasing hash table memory..." +unhash +echo + +echo -n "Removing directory stack..." +dirs | $SED -e's/[^ ]* [^ ]*/popd; /' > $tmpcmd +source $tmpcmd + +echo -n "Reduce the history to 1 (minimum)" +setenv HISTORY=1 +echo +echo "=> Manually enter any command for final release of history memory" diff --git a/bin/gsh/tests/reparse.asm b/bin/gsh/tests/reparse.asm new file mode 100644 index 0000000..eef4ea9 --- /dev/null +++ b/bin/gsh/tests/reparse.asm @@ -0,0 +1,34 @@ +* ------------------------------------------------------------------- +* +* Example of routine to re-parse the commandline arguments to +* recognize both " and ' as quote characters. +* +* Written by Dave Tribby beginning November 1999 +* +* Summary: extern int reparse(char *argv[], char *commandline); +* +* Method: call the GNO routine ~GNO_PARSEARG. +* +* ------------------------------------------------------------------- + +dummy START ; This segment ends up in .root + END + + case on +reparse START + +; NOTE: ~GNO_PARSEARG expects commandline parameter to be the "raw" +; value passed by the shell, so it skips the first 8 characters. +; Need to adjust pointer back 8 bytes. + + lda $8,s ; Get commandline parameter, low-order word. + sec + sbc #8 ; Subtract 8. + sta $8,s + lda $a,s ; Adjust high-order word, if necessary. + sbc #0 + sta $a,s + + jml >~GNO_PARSEARG ; Let ~GNO_PARSEARG handle the rest. + + END diff --git a/bin/gsh/tests/shellenv.c b/bin/gsh/tests/shellenv.c new file mode 100644 index 0000000..6586f0e --- /dev/null +++ b/bin/gsh/tests/shellenv.c @@ -0,0 +1,155 @@ +/* + * shellenv: print information on the shell environment + * + * Written by Dave Tribby to test gsh * June 1998 + * $Id: shellenv.c,v 1.1 1999/11/30 20:28:24 tribby Exp $ + */ + +#include +#include +#include +#include + +/* VersionGS parameter block */ +VersionGSPB vers_pb = {1}; + +/* GetLInfoGS parameter block */ +ResultBuf255Ptr sFilePtr = NULL; +ResultBuf255Ptr dFilePtr = NULL; +ResultBuf255Ptr paramsPtr = NULL; +ResultBuf255Ptr iStringPtr = NULL; +GetLInfoGSPB get_li_pb = {11}; + +/* GetLangGS paramater block */ +GetLangGSPB get_l_pb = {1}; + +/* DirectionGS parameter block */ +DirectionGSPB dir_pb = {2}; +char *devnm[3]={"stdin ", "stdout", "stderr"}; +char *devdir[3]={"Console", "Printer", "Disk file"}; + + +/* Cleanup routine at end: deallocate buffers */ +void cleanup(void) +{ + if (get_li_pb.sFile) { + free(get_li_pb.sFile); + get_li_pb.sFile = NULL; + } + if (get_li_pb.dFile) { + free(get_li_pb.dFile); + get_li_pb.dFile = NULL; + } + if (get_li_pb.parms) { + free(get_li_pb.parms); + get_li_pb.parms = NULL; + } + if (get_li_pb.iString) { + free(get_li_pb.iString); + get_li_pb.iString = NULL; + } +} + +/* Allocate memory for a GS/OS result buffer */ +ResultBuf255Ptr allocate_buf(Word numbytes) +{ + ResultBuf255Ptr hold_ptr; + if ( (hold_ptr = (ResultBuf255Ptr) malloc(numbytes+1)) == 0) { + printf("Error allocating %u bytes of memory\n"); + exit (1); + } + hold_ptr->bufSize = 1024; + return hold_ptr; +} + +/* Print information about a buffer */ +void print_buf_info(char *title, ResultBuf255Ptr buf_ptr) +{ + char *end_str; + /* Calculate address beyond end of string */ + end_str = buf_ptr->bufString.text + buf_ptr->bufString.length; + /* Terminate the string with a null character */ + *end_str = '\0'; + printf("Buffer for %s: size = %u\n%s\n\n", + title, buf_ptr->bufString.length, buf_ptr->bufString.text); +} + +/* Print information about option flags */ +void print_flag_info(unsigned long flags) +{ + char ch='A'; + unsigned long testpos=0x80000000; + + printf("%08lX:", flags); + while (ch <= 'Z') { + if (testpos & flags) printf(" %c",ch); + ch++; + testpos = testpos >> 1; + } +} + + +int main(int argc, char *argv[]) +{ + int i; + + printf("=< S H E L L E N V I R O N M E N T R E P O R T >=\n"); + + atexit(cleanup); + + VersionGS(&vers_pb); + printf("Shell version: "); + for (i=0; i<4; i++) putchar(vers_pb.version[i]); + putchar('\n'); + + printf("Edit/Compile/Link environment:\n"); + get_li_pb.sFile = allocate_buf(1024); + get_li_pb.dFile = allocate_buf(255); + get_li_pb.parms = allocate_buf(255); + get_li_pb.iString = allocate_buf(1024); + GetLInfoGS(&get_li_pb); + + print_buf_info("Source file", (ResultBuf255Ptr) get_li_pb.sFile); + print_buf_info("Destination file", (ResultBuf255Ptr) get_li_pb.dFile); + print_buf_info("Parameter List", (ResultBuf255Ptr) get_li_pb.parms); + print_buf_info("Command specific", (ResultBuf255Ptr) get_li_pb.iString); + printf("Error level: Maximum = %d, Found = %d\n", + get_li_pb.merr, get_li_pb.merrf); + printf("Operations flag = %08X Keep flag = %d\n", + get_li_pb.lops, get_li_pb.kflag); + printf("Flags: -"); + print_flag_info(get_li_pb.mFlags); + printf(" +"); + print_flag_info(get_li_pb.pFlags); + putchar('\n'); + printf("Displacement into file: %ld\n", get_li_pb.org); + + GetLangGS(&get_l_pb); + printf("Current language number = %d (", get_l_pb.lang); + switch(get_l_pb.lang) { + case 0: printf("ProDOS"); + break; + case 1: printf("text"); + break; + case 3: printf("ASM65816"); + break; + case 5: printf("ORCA/Pascal"); + break; + case 6: printf("EXEC"); + break; + case 8: printf("ORCA/C"); + break; + default: printf("?"); + } + printf(")\n"); + + printf("I/O Redirection:\n"); + for (i=0; i<3; i++) { + dir_pb.device = i; + DirectionGS(&dir_pb); + printf(" %d: %s direction = %d", i,devnm[i],dir_pb.direct); + if (dir_pb.direct < 3) printf(" (%s)", devdir[dir_pb.direct]); + putchar('\n'); + } + return 0; +} diff --git a/bin/gsh/tests/singletc b/bin/gsh/tests/singletc new file mode 100644 index 0000000..079606f --- /dev/null +++ b/bin/gsh/tests/singletc @@ -0,0 +1,10 @@ +# Run one test and compare results. +# Before calling, set $testcmd, $testarg, $listfile + +echo "Test: $testcmd $testarg" +$testcmd $testarg > $outdir/$listfile +echo " Completion status = $status" +echo "Checking results against control file (no differences expected)" +$compare $cmpdir/$listfile $outdir/$listfile +echo " comparison status = $status for $listfile" +echo "" diff --git a/bin/gsh/tests/test.list b/bin/gsh/tests/test.list new file mode 100644 index 0000000..515cfb5 --- /dev/null +++ b/bin/gsh/tests/test.list @@ -0,0 +1,446 @@ +Script started on: Fri Nov 26 21:55:46 1999 +Executing gshrc from directory /H2/NewDev +[61] tests=> dotests ; exit +Removing all aliases... +Removing environment variables... +hashed 118 files +Removing output directory /tmp/bi.out... + = = = = = Start of /obj/gno/bin/gsh/gsh built-in tests = = = = = +Test: clear + Completion status for clear = 0 +Test: alias + Completion status = 0 +Checking results against control file (no differences expected) + comparison status = 0 for alias.0.list +Adding aliases for ls and mv +Test: alias + Completion status = 0 +Checking results against control file (no differences expected) + comparison status = 0 for alias.list +Test: alias newcmd date + Completion status = 0 +Test: unalias newcmd + Completion status = 0 +Test: which ls + Completion status = 0 +Checking results against control file (no differences expected) + comparison status = 0 for which.0.list +Test: unalias ls + Completion status = 0 +Test: which ls + Completion status = 0 +Checking results against control file (no differences expected) + comparison status = 0 for which.list +Test: echo + Completion status = 0 +Checking results against control file (no differences expected) + comparison status = 0 for echo.list +Test: sed and redirected stdin/stdout + comparison status = 0 for sed1.list +Test: sed and pipes + comparison status = 0 for sed2.list +Test: commands + Completion status = 0 +Checking results against control file (no differences expected) + comparison status = 0 for commands.list +Test: set + Completion status = 0 +Checking results against control file (no differences expected) + comparison status = 0 for set.list +Test: /obj/gno/bin/gsh/gsh -f prefix + Completion status = 0 +Checking results against control file (no differences expected) + comparison status = 0 for prefix.list +Test: pushd /src/gno/bin/gsh/tests/bi.out +~/bi.out ~ + Completion status = 0 +Test: dirs +~/bi.out ~ + Completion status = 0 +Test: cd /tmp/bi.out + Completion status = 0 +Test: /obj/gno/bin/gsh/gsh -f pwd + Completion status = 0 +Checking results against control file (no differences expected) + comparison status = 0 for pwd.list +Test: chdir /bin + Completion status = 0 +Test: /obj/gno/bin/gsh/gsh -f pwd + Completion status = 0 +Checking results against control file (no differences expected) + comparison status = 0 for pwd.2.list +Test: popd +~ + Completion status = 0 +Test: rehash +hashed 118 files + Completion status = 0 +Test: hash + Completion status = 0 +Checking results against control file (no differences expected) +[datafork] /src/gno/bin/gsh/tests/bi.out/hash.list differ: /tmp/bi.out/hash.list char 18, line 1 + comparison status = 1 for hash.list +hashed 121 files +Test: pathtst + Completion status = 0 +Checking results against control file (no differences expected) + comparison status = 0 for pathtst.1.list +hashed 121 files +Test: pathtst with OLDPATHMODE set + Completion status = 0 +Checking results against control file (no differences expected) + comparison status = 0 for pathtst.2.list +hashed 118 files +Test: tset + Completion status = 0 +Test: setdebug + Completion status = 0 +Test: history + 1: less ../Makefile + 2: pushd /src/gno + 3: fgrep clean *.mk + 4: more binrules.mk + 5: popd + 6: edit Makefile + 7: dmake -u clean + 8: dmake -n clean + 9: dmake -n clobber + 10: ls + 11: dmake clobber + 12: ls + 13: ls *.c + 14: more testfork.c + 15: ls + 16: edit dotests + 17: more shellenv.c + 18: ls *.c + 19: ll calls* + 20: edit Makefile *.c + 21: ll + 22: more cmdtest4fr + 23: rm cmdtest4fr + 24: more cmdtestmul + 25: rm cmdtestmul + 26: ls + 27: more dotests + 28: ls + 29: edit dotests + 30: chtyp -l exec dotests + 31: edit dotests + 32: ll + 33: more fulltests.mul + 34: more /var/tmp/test.list + 35: edit /var/tmp/test.list + 36: ls + 37: more releasemem + 38: ls + 39: more singletc + 40: fgrep singletc dotests + 41: edit dotests + 42: ls + 43: more smallbi + 44: ls + 45: more testedit + 46: ll test* + 47: edit Makefile + 48: clrff + 49: clrff + 50: ls + 51: mkdir extra + 52: mv singletc testedit extra/ + 53: ls -n + 54: mv fulltests.mul extra/ + 55: more cmdtest + 56: mv cmdtest extra/ + 57: ls + 58: dmake clean + 59: dmake clobber + 60: exit + 61: dotests ; exit + Completion status = 0 +Test: ps + ID STATE TT MMID UID TIME COMMAND + 1 ready co 1002 0000 23:12 NullProcess + 2 paused nu 1004 0000 0:01 init + 3 blocked nu 1003 0000 0:00 syslogd + 382 paused co 1006 0000 0:22 -gsh + 539 waiting co 1005 0000 0:00 /src/gno/build.tools/fulltests + 548 paused 07 1011 0000 0:05 gsh + 547 waiting 06 1010 0000 0:00 script /tmp/rawlist + 549 ready 06 100F 0000 2:34 forked child of script /tmp/rawlist + 558 ready 07 1008 0000 0:14 dotests + 820 running 07 1012 0000 0:00 forked child of dotests + Completion status = 0 += = Testing execution file with forked commands = = = = = = = += = Executing as a command: /bin/ps -l + ID PPID PGRP STATE TT MMID USER TIME COMMAND + 1 1 00 ready co 1002 0000 23:12 NullProcess + 2 1 02 paused 00 1004 0000 00:01 init + 3 2 02 blocked 00 1003 0000 00:00 syslogd + 382 2 04 paused co 1006 0000 00:22 -gsh + 539 382 03 waitsigch co 1005 0000 00:00 /src/gno/build.tools/fullte... + 548 547 06 paused 07 1011 0000 00:05 gsh + 547 539 03 waitsigch 06 1010 0000 00:00 script /tmp/rawlist + 549 547 03 ready 06 100F 0000 02:38 forked child of process 547 + 558 548 05 waitsigch 07 1008 0000 00:14 dotests + 838 558 05 waitsigch 07 1012 0000 00:00 /tmp/testcmds + 840 838 05 running 07 100D 0000 00:00 /bin/ps -l += = Sourcing the command: /bin/ps -l + ID PPID PGRP STATE TT MMID USER TIME COMMAND + 1 1 00 ready co 1002 0000 23:12 NullProcess + 2 1 02 paused 00 1004 0000 00:01 init + 3 2 02 blocked 00 1003 0000 00:00 syslogd + 382 2 04 paused co 1006 0000 00:22 -gsh + 539 382 03 waitsigch co 1005 0000 00:00 /src/gno/build.tools/fullte... + 548 547 06 paused 07 1011 0000 00:05 gsh + 547 539 03 waitsigch 06 1010 0000 00:00 script /tmp/rawlist + 549 547 03 ready 06 100F 0000 02:39 forked child of process 547 + 558 548 05 paused 07 1008 0000 00:15 dotests + 843 558 07 running 07 100D 0000 00:00 /bin/ps -l += = Execution files did not hang: test successful! = = = = = = + = = = = = Start of /obj/gno/bin/gsh/gsh commandline expansion tests = = = = +Test: echo ~/ ~: + Completion status = 0 +Checking results against control file (no differences expected) + comparison status = 0 for tilde.list +ls *.c bad*name dot* + Completion status = 0 +Checking results against control file (no differences expected) + comparison status = 0 for glob.list +Test: multiple commands separated by ";" + Completion status = 0 +Checking results against control file (no differences expected) + comparison status = 0 for multi.list +Test: semicolons within quoted parameters + Completion status = 0 +Checking results against control file (no differences expected) + comparison status = 0 for semi.list +Test: null parameters + Completion status = 0 +Checking results against control file (no differences expected) + comparison status = 0 for null.list +Test: keep single quotes around parameters +" Completion status = 0" +Checking results against control file (no differences expected) + comparison status = 0 for keep.list +Test: keep single quotes around parameters, again +" Completion status = 0" +Checking results against control file (no differences expected) + comparison status = 0 for keep2.list +Test: print10params + Completion status = 0 +Checking results against control file (no differences expected) + comparison status = 0 for print10.list + = = = = = = Start of /obj/gno/bin/gsh/gsh system() interface tests = = = = = +Test: call system() with null parameter + Completion status = 0 +Checking results against control file (no differences expected) + comparison status = 0 for nullsys.list +Test: concurrent execution of ps +Test of system() function + ID STATE TT MMID UID TIME COMMAND + 1 ready co 1002 0000 23:12 NullProcess + 2 paused nu 1004 0000 0:01 init + 3 blocked nu 1003 0000 0:00 syslogd + 382 paused co 1006 0000 0:22 -gsh + 539 waiting co 1005 0000 0:00 /src/gno/build.tools/fulltests + 548 paused 07 1011 0000 0:05 gsh + 547 waiting 06 1010 0000 0:00 script /tmp/rawlist + 549 ready 06 100F 0000 2:58 forked child of script /tmp/rawlist + 558 ready 07 1008 0000 0:18 dotests + 942 ready 07 1013 0000 0:00 callsystem ps + 943 running 07 1012 0000 0:00 forked child of callsystem ps + 944 ready 07 1015 0000 0:00 callsystem ps +Test of system() function + `ps` returns value = 0 + ID STATE TT MMID UID TIME COMMAND + 1 ready co 1002 0000 23:12 NullProcess + 2 paused nu 1004 0000 0:01 init + 3 blocked nu 1003 0000 0:00 syslogd + 382 paused co 1006 0000 0:22 -gsh + 539 waiting co 1005 0000 0:00 /src/gno/build.tools/fulltests + 548 paused 07 1011 0000 0:05 gsh + 547 waiting 06 1010 0000 0:00 script /tmp/rawlist + 549 ready 06 100F 0000 2:59 forked child of script /tmp/rawlist + 558 waiting 07 1008 0000 0:18 dotests + 945 running 07 1012 0000 0:00 forked child of callsystem ps + 944 waiting 07 1015 0000 0:00 callsystem ps + `ps` returns value = 0 +Test: concurrent execution of /bin/ps -l +Test of system() function + ID PPID PGRP STATE TT MMID USER TIME COMMAND + 1 1 00 ready co 1002 0000 23:12 NullProcess + 2 1 02 paused 00 1004 0000 00:01 init + 3 2 02 blocked 00 1003 0000 00:00 syslogd +Test of system() function + 382 2 04 paused co 1006 0000 00:22 -gsh + 539 382 03 waitsigch co 1005 0000 00:00 /src/gno/build.tools/fullte... + 548 547 06 paused 07 1011 0000 00:05 gsh + 547 539 03 waitsigch 06 1010 0000 00:00 script /tmp/rawlist + 549 547 03 ready 06 100F 0000 03:00 forked child of process 547 + 558 548 05 waitsigch 07 1008 0000 00:19 dotests + 949 558 07 waitsigch 07 1013 0000 00:00 callsystem "/bin/ps -l" + 950 949 07 running 07 100D 0000 00:00 /bin/ps -l + 951 558 05 ready 07 1014 0000 00:00 callsystem "/bin/ps -l" + ID PPID PGRP STATE TT MMID USER TIME COMMAND + 1 1 00 ready co 1002 0000 23:12 NullProcess + 2 1 02 paused 00 1004 0000 00:01 init + 952 951 05 ready 07 1015 0000 00:00 /bin/ps -l + 3 2 02 blocked 00 1003 0000 00:00 syslogd + 382 2 04 paused co 1006 0000 00:22 -gsh + `/bin/ps -l` returns value = 0 + 539 382 03 waitsigch co 1005 0000 00:00 /src/gno/build.tools/fullte... + 548 547 06 paused 07 1011 0000 00:05 gsh + 547 539 03 waitsigch 06 1010 0000 00:00 script /tmp/rawlist + 549 547 03 ready 06 100F 0000 03:00 forked child of process 547 + 558 548 05 waitsigch 07 1008 0000 00:19 dotests + 951 558 05 waitsigch 07 1014 0000 00:00 callsystem "/bin/ps -l" + 952 951 05 running 07 1015 0000 00:00 /bin/ps -l + `/bin/ps -l` returns value = 0 +Test: concurrent execution of pwd +Test of system() function +:src:gno:bin:gsh:tests: + `pwd` returns value = 0 +Test of system() function +:src:gno:bin:gsh:tests: + `pwd` returns value = 0 +Test: concurrent execution of rehash +Test of system() function +hashed 118 files + `rehash` returns value = 0 +Test of system() function +hashed 118 files + `rehash` returns value = 0 +Test: concurrent execution of hash +Test of system() function +apropos ctags gsh.r pwd testjobs +aroff cut gsh0 rcp testjobs2 +asml date gsh10 releasemem time +assemble day head removerez touch +aw30 describe help rlogin tr +awk df hostname rm true +basename diff init rmdir udl +binprint dirname install rsh uname +callsystem dmake kill script uncompress +cat dotests last sed uniq +catrez du launch setvers unshar +center echo less shellenv uptime +chmod echoparams link singletc vi +chtyp egrep logger sleep wall +cksum false ls split wc +Test of system() function +cmp fgrep lseg strings whatis +cmpl fmt man stty whereis +coff freeze mkdir su who +colcrt ftp more sum whois +compile getvers nroff tail yankit +compress grep passwd tar yes +copycat gsh print10params tee +cp gsh.debug ps test +cpp gsh.nodebug purge testfork + `hash` returns value = 0 +apropos ctags gsh.r pwd testjobs +aroff cut gsh0 rcp testjobs2 +asml date gsh10 releasemem time +assemble day head removerez touch +aw30 describe help rlogin tr +awk df hostname rm true +basename diff init rmdir udl +binprint dirname install rsh uname +callsystem dmake kill script uncompress +cat dotests last sed uniq +catrez du launch setvers unshar +center echo less shellenv uptime +chmod echoparams link singletc vi +chtyp egrep logger sleep wall +cksum false ls split wc +cmp fgrep lseg strings whatis +cmpl fmt man stty whereis +coff freeze mkdir su who +colcrt ftp more sum whois +compile getvers nroff tail yankit +compress grep passwd tar yes +copycat gsh print10params tee +cp gsh.debug ps test +cpp gsh.nodebug purge testfork + `hash` returns value = 0 += = = Execution did not hang: test successful! = = = = = + = = = = = /obj/gno/bin/gsh/gsh commands' usage strings and status test = = = = +Usage: bg [%job | pid] + Completion status = 1 (expected 1) +Usage: chdir [pathname] + Completion status = 1 (expected 1) +Usage: cd [pathname] + Completion status = 1 (expected 1) +Usage: clear + Completion status = 1 (expected 1) +Usage: export var ... + Completion status = 1 (expected 1) +Usage: fg [%job | pid] + Completion status = 1 (expected 1) +Usage: jobs [-l] + Completion status = 1 (expected 1) +kill: No such job or pid. + Completion status = 1 (expected 1) +Usage: popd [+n] + Completion status = 1 (expected 1) +Usage: prefix prefixnum prefixname + Completion status = 1 (expected 1) +usage: pushd [+n | dir] + Completion status = 1 (expected 1) +Usage: pwd + Completion status = 1 (expected 1) +Usage: rehash + Completion status = 1 (expected 1) +Usage: stop [%job | pid] + Completion status = 1 (expected 1) +Usage: tset + Completion status = 1 (expected 1) +Usage: unalias name ... + Completion status = 1 (expected 1) +Usage: unhash + Completion status = 1 (expected 1) +Usage: unset var ... + Completion status = 1 (expected 1) +Usage: commands + Completion status = 1 (expected 1) +Usage: setdebug (value | [+|-]flag ... ) +Flags: gsostrace - Trace GS/OS calls + gsosblocks - Trace GS/OS parameter blocks + gsoserrors - Trace GS/OS errors + pathtrace - Trace GS/OS pathnames + sigtrace - Trace signals + systrace - Trace system calls + breakpoint - Coded brk instructions + Completion status = 1 (expected 1) +usage: dirs [-l] + Completion status = 1 (expected 1) +Usage: hash + Completion status = 1 (expected 1) +Usage: ps + Completion status = 1 (expected 1) +Usage: + set - displays all variables + set ... [var] - displays the value of var + set [var value]... - sets var to value + set [var=value]... - sets var to value + Completion status = 1 (expected 1) +Usage: + set - displays all variables + set ... [var] - displays the value of var + set [var value]... - sets var to value + set [var=value]... - sets var to value + Completion status = 1 (expected 1) +Usage: bindkey [-l] function string + Completion status = 1 (expected 1) +Usage: echo [-n] [strings...] + Completion status = 1 (expected 1) +Usage: history + Completion status = 1 (expected 1) +Usage: which [file ...] + Completion status = 1 (expected 1) +edit: no filename specified + Completion status = 1 (expected 1) + = = = = = End of /obj/gno/bin/gsh/gsh tests = = = = = +Note: To test job control commands, source testjobs and testjobs2. +Script done on: Fri Nov 26 22:04:34 1999 diff --git a/bin/gsh/tests/testfork.c b/bin/gsh/tests/testfork.c new file mode 100644 index 0000000..8a291db --- /dev/null +++ b/bin/gsh/tests/testfork.c @@ -0,0 +1,466 @@ +/* + * testfork: See how fork/_execve/wait/kill interact + * + * Written by Dave Tribby to test gsh * Oct 1998 + */ + +#define INCLUDE_WAIT +#define INCLUDE_PWAIT + +#include +#include +#include +#include +#include +#include +#include +#include + +int fork_mutex = 0; /* Mutual exclusion during fork */ +int event_mutex = 0; /* Mutual exclusion while adding an event */ +int wait_in_handler = 0; /* Should wait() be called in sig handler? */ +int root_pid; /* Root program's pid */ +int child1_pid; /* Child program's pid */ + +/* Values to be passed to _execve() */ +char *progname; +char *cmdline; + +/* Default values for _execve() if none are provided on command line */ +char *d_progname="/bin/ps"; +char *d_cmdline="/bin/ps -l"; + + + +/* ---------- Data and code for handling program events ----------*/ + +/* Structure for recording program events */ +typedef struct { + int pid; + int verb; + int v1,v2; + } EventRec; + +EventRec *prog_events; /* Pointer to array of events */ +int num_events=0, max_events; /* Current # of events and maximum */ + +/* Values for verb in event record */ +enum { e_start, e_fork, e_forkmc, e_exec, e_exfail, e_sigp0, e_sigp1, + e_wait, e_kill, e_getsig, e_noproc, e_end }; +char *e_name[] ={"Start", "Fork child pid =", "Fork mutex count =", + "_execve", "_execve failed", "Calling sigpause", + "Sigpause returned", "Wait returns child", + "Kill returns", "Receive signal", "Process not found!", "End"}; + + +/* + * Add a program event + */ +#pragma databank 1 +void add_event(int pid, int verb, int v1, int v2) +{ + EventRec *p; + + /* Lock the event mutual exclusion key */ +/* ------------------------------------------------- + asm { + phb + phk + plb + lda #1 + test: tsb event_mutex + beq alldone + cop 0x7f + bra test + alldone: plb + } +---------------------------------------------------- */ + + if (num_events >= max_events ) { + prog_events = realloc((char *)prog_events, 64*sizeof(EventRec)); + max_events += 64; + } + p = &(prog_events[num_events]); + p->pid = pid; + p->verb = verb; + p->v1 = v1; + p->v2 = v2; + num_events++; + + /* Unlock the event mutual exclusion key */ + event_mutex = 0; +} +#pragma databank 0 + + +/* + * Print program event records + */ +void print_events(void) +{ + int i; + EventRec *p; + + p = prog_events; + for (i=0; i < num_events; i++) { + printf("%3d: %4d %s", i, p->pid, e_name[p->verb]); + switch (p->verb) { + case e_getsig: + case e_fork: + case e_forkmc: + printf(" %d", p->v1); + break; + case e_wait: + case e_kill: + printf(" pid %d status = 0x%04X", + p->v1,p->v2); + break; + } + printf("\n"); + p++; + } +} + + + + +/* ---------- Data and code for handling process list ----------*/ + +#define MAX_SIG 33 + +/* Linked list for each invocation of this program sharing the same space */ +struct ProgListRec { + struct ProgListRec *next; + int pid; + int *sig_rcv; + } ProgListRec; +typedef struct ProgListRec ProgListRec; + +ProgListRec *plist_head = NULL; + +/* + * Clear the signal received array + */ +#pragma databank 1 +void clear_sig_flags(int *sig_array) +{ + int sig_num; + for (sig_num = 0; sig_num < MAX_SIG; sig_num++) { + sig_array[sig_num] = 0; + } +} +#pragma databank 0 + +/* + * Create a new entry in the process list + */ +#pragma databank 1 +void new_process_entry(int pid) +{ + ProgListRec *new; + + new = malloc(sizeof(ProgListRec)); + new->pid = pid; + new->sig_rcv = malloc(MAX_SIG*sizeof(int)); + clear_sig_flags(new->sig_rcv); + new->next = plist_head; + plist_head = new; +} +#pragma databank 0 + + +#pragma databank 1 +ProgListRec *find_process_entry(int my_pid) +{ + ProgListRec *plist; + + /* Find process list entry and set signal received bit */ + plist = plist_head; + while (plist && plist->pid != my_pid) { + plist = plist->next; + } + if (!plist) { + add_event(my_pid, e_noproc, 0, 0); + } + return plist; +} +#pragma databank 0 + +/* + * Print process list + */ +#pragma databank 1 +void print_proc_list(void) +{ + ProgListRec *plist; + int signum; + + plist = plist_head; + while (plist) { + printf("Process # %d received signals:", plist->pid); + for (signum = 1; signum < MAX_SIG; signum++) { + if (plist->sig_rcv[signum]) + printf(" %d", signum); + } + printf("\n"); + plist = plist->next; + } +} +#pragma databank 0 + + + +/* ---------------------------------------------------------------*/ + + +/* + * Entry point for forked process to schedule "progname" + */ +#pragma databank 1 +void prog_exec(void) +{ + int child_pid; + int my_pid; + + /* Get process id */ + my_pid = getpid(); + + fork_mutex = 0; + add_event(my_pid, e_exec, 0, 0); + child_pid = _execve(progname,cmdline); + add_event(my_pid, e_exfail, 0, 0); +} +#pragma databank 0 + + +/* + * Signal handler + */ +#pragma databank 1 +void SigHandler(int sig, int code) +{ + pid_t wpid; + union wait status; + int my_pid; + ProgListRec *pentry; + + + /* Get process id */ + my_pid = getpid(); + + add_event(my_pid, e_getsig, sig, code); + + /* Find process list entry and set signal received bit */ + if (pentry = find_process_entry(my_pid)) { + pentry->sig_rcv[sig] = 1; + } + + switch (sig) { + case SIGCHLD: + if (wait_in_handler) { + /* Get child's completion status */ + wpid = wait(&status); + add_event(my_pid, e_wait, wpid, status.w_status); + } + /* Make sure parent isn't waiting on mutex */ + fork_mutex = 0; + break; + case SIGUSR1: /* User-defined signal 1 */ + if (my_pid == root_pid) + kill(child1_pid,SIGUSR2); + break; + case SIGUSR2: /* User-defined signal 2 */ + break; + case SIGHUP: /* Hang-up */ + case SIGTERM: /* Kill or hang-up */ + fprintf(stderr, "...bye!...\n"); + exit(1); + } +} +#pragma databank 0 + + +/* + * Establish signal handlers + */ +#pragma databank 1 +void set_sig_handler(void) +{ + signal(SIGINT, SigHandler); + signal(SIGTERM, SigHandler); + signal(SIGHUP, SigHandler); + signal(SIGTSTP, SigHandler); + signal(SIGCHLD, SigHandler); + signal(SIGUSR1, SigHandler); + signal(SIGUSR2, SigHandler); +} +#pragma databank 0 + + +/* + * Wait for foreground process to finish up + */ +#pragma databank 1 +void pwait(void) +{ + long oldmask; + int my_pid; + ProgListRec *pentry; + + /* Get process id */ + my_pid = getpid(); + + /* Wait for signal */ + pentry = find_process_entry(my_pid); + while (!pentry->sig_rcv[SIGCHLD]) { + add_event(my_pid, e_sigp0, 0, 0); + sigpause(0); + add_event(my_pid, e_sigp1, 0, 0); + } +} +#pragma databank 0 + + +/* + * Invoke a child program + */ +#pragma databank 1 +int invoke(void *addr) +{ + int my_pid; + int child_pid; + int mutex_count = 0; + + my_pid = getpid(); + fork_mutex = 1; + child_pid = fork(addr); + add_event(my_pid, e_fork, child_pid, 0); + while (fork_mutex) { + asm { + cop 0x7f + } + mutex_count++; + } + add_event(my_pid, e_forkmc, mutex_count, 0); + return child_pid; +} +#pragma databank 0 + + + +/* + * Do process startup stuff, and invoke the proper child + */ +#pragma databank 1 +void command(int pid, void *addr) +{ + long oldmask; + int child_pid; + int kill_stat; + + /* Temporarially block reception of all signals */ + oldmask = sigblock(-1L); + + /* Invoke the appropriate child process */ + child_pid = invoke(addr); + + /* Enable the signal handlers for current process */ + set_sig_handler(); + + /* Create process entry for this process */ + new_process_entry(pid); + + /* Restore previous signal mask */ + sigsetmask(oldmask); + + /* If this is the child, let parent know we're here */ + if (pid != root_pid) + kill(root_pid,SIGUSR1); + + /* If child process is still running, wait for it to complete */ + kill_stat = kill(child_pid,0); + add_event(pid, e_kill, child_pid, kill_stat); + if (!kill_stat) { + pwait(); + } +} +#pragma databank 0 + + + +/* + * Forked child of root process starts here + */ +int process2(void) +#pragma databank 1 +{ + child1_pid = getpid(); + add_event(child1_pid, e_start, 0, 0); + + command(child1_pid,&prog_exec); + + add_event(child1_pid, e_end, 0, 0); + return 1; +} +#pragma databank 0 + + +/* + * Main program starts here + */ +int main(int argc, char *argv[]) +{ + pid_t wpid; + union wait status; + int argnum; + + root_pid = getpid(); + max_events = 64; + if (!(prog_events = malloc(64*sizeof(EventRec)))) { + fprintf(stderr, "ERROR: cannot malloc %d bytes\n", + 64*sizeof(EventRec)); + exit(1); + } + + /* Print listing of events and process list when program terminates */ + atexit(print_events); + atexit(print_proc_list); + + /* Set value of grandchild program to be executed */ + if (argc <= 1) { + /* Use default if nothing provided in arguments */ + progname = d_progname; + cmdline = d_cmdline; + } + else { + progname = argv[1]; + /* Command line for _execve() is root program's */ + /* cmd line without the original program name. */ + cmdline = commandline(); + while (*cmdline && *cmdline != ' ') cmdline++; + while (*cmdline && *cmdline == ' ') cmdline++; + } + + /* Record that we made it through startup */ + add_event(root_pid, e_start, 0, 0); + +#ifdef INCLUDE_WAIT + /* This section of code does a simple wait */ + wait_in_handler = 0; + signal(SIGCHLD, SigHandler); + invoke(&prog_exec); + wpid = wait(&status); + add_event(root_pid, e_wait, wpid, status.w_status); +#endif + +#ifdef INCLUDE_PWAIT + /* This section of code does a more complex wait two levels deep */ + wait_in_handler = 1; + + command(root_pid,&process2); +#endif + + add_event(root_pid, e_end, 0, 0); + + return 0; +} diff --git a/bin/gsh/tests/testjobs b/bin/gsh/tests/testjobs new file mode 100644 index 0000000..1579908 --- /dev/null +++ b/bin/gsh/tests/testjobs @@ -0,0 +1,28 @@ +# Test gsh built-in job commands +# Written by Dave Tribby (December 1998) +# $Id: testjobs,v 1.1 1999/11/30 20:28:24 tribby Exp $ +# This shell exec file must be sourced rather than run + +echo " = = = = = Test of $SHELL job control" +echo "" +echo "NOTE: $0 must be sourced rather than run; otherwise it kills itself!" +echo "" + +/bin/sleep 15 & +/bin/sleep 5 & + +echo +echo "Should show two jobs" +jobs + +echo +echo "Kill the first job" +kill %1 + +echo +echo "There should now only be one job" +jobs + +echo +echo "Wait on the final job" +fg diff --git a/bin/gsh/tests/testjobs2 b/bin/gsh/tests/testjobs2 new file mode 100644 index 0000000..4841e35 --- /dev/null +++ b/bin/gsh/tests/testjobs2 @@ -0,0 +1,29 @@ +# Test gsh built-in job commands +# Written by Dave Tribby (December 1998) +# $Id: testjobs2,v 1.1 1999/11/30 20:28:24 tribby Exp $ +# This shell exec file must be sourced rather than run + +echo " = = = = = Test of $SHELL job control" +echo "" +echo "NOTE: $0 must be sourced rather than run; otherwise it kills itself!" +echo "" + +/bin/sleep 15 & + +echo +echo "Should show one job" +jobs + +echo +echo "Kill the first job" +kill %1 + +/bin/sleep 5 & + +echo +echo "There should now be another job" +jobs + +echo +echo "Wait on the final job" +fg