From 963a33c4bf216b70ca13fa5fdfe526bcc2eede30 Mon Sep 17 00:00:00 2001 From: tribby Date: Mon, 26 Oct 1998 17:04:51 +0000 Subject: [PATCH] Changes for gsh version 2.0d5: Add quotes around null parameters from the command line so they will be parsed properly (resolves PR#84). Output piped to an unfound command caused gsh to terminate, due to an interface change to the GNO 2.0.6 version of getpgrp(2): it now returns the process group of the caller. To get the process group number for the pid passed as a parameter pid, the call has to be made to _getpgrp(2). In addition to fixing invoke.asm, updates were also made in jobs.asm. When directory stack is full, pushd, reports a new error message: 'pushd: Directory stack full'. (Previously, 50 pushds would cause a crash.) When parameter passed to "pushd +n" is <= 0, report a new error message: 'pushd: Invalid number'. (Previously, tried to chdir to the parameter.) When a command appends to stderr (e.g., echo test >>&/tmp/err), stdin was closed, due to errappend being defined as pipefds+2 rather than pipefds+4 in cmd.asm. When there was an error reading stdin, gsh went into an infinite loop of beeping and requesting more input. Changed getchar (in stdio.asm) and GetCmdLine (in edit.asm) to report the error and terminate. Code in cmd.asm set and reset handler for signal SIGSTOP (17). This makes no sense, since there cannot be a handler for SIGSTOP. This was changed to set and reset signal SIGTSTP (18) since that handler is used by gsh. The error message "specify a command before redirecting" was never caught by the invoke() subroutine because the next higher routine, command(), checked for argv==0 before calling invoke(). The error message was moved into command(). --- bin/gsh/To.Do | 29 +++- bin/gsh/UpdateLog | 47 ++++++ bin/gsh/builtin.asm | 28 +-- bin/gsh/cmd.asm | 404 +++++++++++++++++++++++++++----------------- bin/gsh/dir.asm | 197 ++++++++++++--------- bin/gsh/edit.asm | 29 +++- bin/gsh/gsh.mac | 6 +- bin/gsh/gsh.rez | 4 +- bin/gsh/invoke.asm | 378 ++++++++++++++++++++++++----------------- bin/gsh/jobs.asm | 187 +++++++++++--------- bin/gsh/shell.asm | 18 +- bin/gsh/stdio.asm | 10 +- bin/gsh/term.asm | 50 +++--- 13 files changed, 830 insertions(+), 557 deletions(-) diff --git a/bin/gsh/To.Do b/bin/gsh/To.Do index d3b2d36..1461c4e 100644 --- a/bin/gsh/To.Do +++ b/bin/gsh/To.Do @@ -1,27 +1,40 @@ -Last updated: July 5, 1998 By: Dave Tribby +Last updated: Oct. 25, 1998 By: Dave Tribby -For more bug reports, see also http://www.gno.org/~gno/bugs.html +For more bug reports, see http://www.gno.org/~gno/bugs.html Completed items are reported in file UpdateLog. -Gsh requires the v2.0.4 ltermcap to link. Termcap has changed in v2.0.6, -and gsh should be updated to reflect this. +Executing the following exec file often results in a hang: + # Create exec file + set tmpcmd=/tmp/testcmds + echo "echo Sourcing $tmpcmd" > $tmpcmd + echo "/bin/ps -l" >> $tmpcmd + chtyp -l exec $tmpcmd + # Source that file; usually doesn't return + source $tmpcmd + +Allow redirection of built-in commands' I/O even if they aren't forked. + +Rather than have each built-in command always be either forked or +non-forked, check dynamically and only fork when it's really necessary +(background or piped). Identify limits built into gsh and how they can be changed; for example, size of $PATH <= 256; max programs in hash table = 256. -Allow redirection of built-in commands' I/O even if they aren't forked. - When a background process finishes and there's text in the input buffer, the next keypress correctly reprints the edit line but the key itself does not get put in the buffer. -running a process in the background from inside a script (not 'source', +Running a process in the background from inside a script (not 'source', but executing the script as a command) causes the shell to wait for that background process to end - not exactly what we want. -usage for alias and hash +Usage for alias and hash + +Gsh requires the v2.0.4 ltermcap to link. A new version of the termcap +library is proposed for GNO v2.0.6, and gsh may require updates. job control monitor for defunct processes when waiting. diff --git a/bin/gsh/UpdateLog b/bin/gsh/UpdateLog index f9f54ac..ae6fcf9 100644 --- a/bin/gsh/UpdateLog +++ b/bin/gsh/UpdateLog @@ -1,7 +1,51 @@ GSH 2.0 UPDATES ^^^^^^^^^^^^^^^ +Oct 10 98 [dmt] Found race condition: when forked process completes + quickly, the parent process may not ever receive its completion + signal. Fix: ensure process exists by calling kill(pid,0) + and checking status before calling pwait (cmd.asm). + Change calls to set and reset handler for signal 17 (SIGSTOP) + to do it for signal 18 (SIGTSTP) (17 can't be caught; 18 is). + +Oct 7 98 [dmt] Check for directory stack full in pushd, and report + new error message: 'pushd: Directory stack full'. (Previously, + 50 pushds would cause a crash.) + Check for parameter in pushd "+n" <=0, and report a new error + message: 'pushd: Invalid number'. (Previously, tried to chdir + to the parameter.) + +Oct 6 98 [dmt] Before calling pwait (to wait for child process) in + cmd.asm, enable the child status signal handler; change it + back to its previous state after the pwait call. This partially + fixes the problem of the shell waiting forever when a shell + exec file sources another exec file that contains a command + that causes a fork. + command() checked for argv==0 before calling invoke(), but + invoke() also checks. Move invoke()'s error message ("specify + a command before redirecting.") into command(). + +Sep 27 98 [dmt] Add quotes around null parameters on the command line + so they are parsed by the target command (PR#84) + +Sep 25 98 [dmt] If a command appends to stdout (echo test >>&/tmp/err), + then stdin gets closed. This was due to errappend being + defined as pipefds+2 rather than pipefds+4 in cmd.asm. + +Sep 23 98 [dmt] If there is an error reading stdin, gsh would go into + an infinite loop of beeping and requesting more input. Changed + getchar (in stdio.asm) and GetCmdLine (in edit.asm) to report + the error and terminate. + +Sep 9 98 [dmt] Output piped to an unfound command caused gsh to + terminate. This was due to an interface change to getpgrp(2): + it now returns the process group of the caller. To get the + process group number of the parameter pid, the call has to + be made to _getpgrp(2). This change was made in invoke.asm to + fix the bug. Additional updates were made in jobs.asm. + Sep 7 98 [dmt] Changes to this point checked-in to master archive. + Released as version 2.0d4 Sep 7 98 [dmt] In "gettoken" (cmd.asm), decrement buf (pointer to command line) when EOL is reached; otherwise if the character @@ -37,6 +81,7 @@ Aug 4 98 [dmt] Fixed defects in wordmatch (edit.asm) related to Aug 3 98 [dmt] Entabbed all the asm files (saved >36,000 bytes). Aug 3 98 [dmt] Changes to this point checked-in to master archive. + Released as version 2.0d3 Aug 2 98 [dmt] Remove alloc256/free256 and associated data. Replace with fixed 64-byte buffer for command filename (hash.asm) @@ -74,6 +119,7 @@ Jul 20 98 [dmt] Changed expand.asm to use InitWildcardGS and NextWildcardGS instead of their obsolete counterparts. Jul 20 98 [dmt] Changes up to this point checked-in to master archive. + Released as version 2.0d3 Jul 19 98 [dmt] Changed edit.asm to use ReadIndexedGS, InitWildcardGS, NextWildcardGS, instead of their obsolete counterparts. @@ -133,6 +179,7 @@ Jul 5 98 [dmt] Changed default order for copying files in $PATH dirs pathname to ExpandPathGS. Jun 29 98 [dmt] Changes up to this point checked-in to master archive. + Released as version 2.0d2 Jun 28 98 [dmt] Added InitVar routine to shellvar.asm to read values of all environment variables tracked in vardata. diff --git a/bin/gsh/builtin.asm b/bin/gsh/builtin.asm index eedf670..f0331bf 100644 --- a/bin/gsh/builtin.asm +++ b/bin/gsh/builtin.asm @@ -6,7 +6,7 @@ * Jawaid Bazyar * Tim Meekins * -* $Id: builtin.asm,v 1.6 1998/09/08 16:53:05 tribby Exp $ +* $Id: builtin.asm,v 1.7 1998/10/26 17:04:49 tribby Exp $ * ************************************************************************** * @@ -1284,32 +1284,6 @@ Usage dc c'Usage: ',h'00' END -************************************************************************** -* -* FST descriptions -* -************************************************************************** - -FSTData DATA - -FSTtable dc a4'fst0,fst1,fst2,fst3,fst4,fst5,fst6,fst7,fst8' - dc a4'fst0,fsta,fstb,fstc,fstd' - -fst0 dc c'[Unknown]',h'00' -fst1 dc c'ProDOS',h'00' -fst2 dc c'DOS 3.3',h'00' -fst3 dc c'DOS 3.2',h'00' -fst4 dc c'Pascal',h'00' -fst5 dc c'MFS',h'00' -fst6 dc c'HFS',h'00' -fst7 dc c'Lisa (get real)',h'00' -fst8 dc c'CP/M',h'00' -fsta dc c'MS-DOS',h'00' -fstb dc c'High Sierra',h'00' -fstc dc c'ISO 9660',h'00' -fstd dc c'AppleShare',h'00' - - END ************************************************************************** * diff --git a/bin/gsh/cmd.asm b/bin/gsh/cmd.asm index e304a9b..23f84e1 100644 --- a/bin/gsh/cmd.asm +++ b/bin/gsh/cmd.asm @@ -6,7 +6,7 @@ * Jawaid Bazyar * Tim Meekins * -* $Id: cmd.asm,v 1.6 1998/09/08 16:53:07 tribby Exp $ +* $Id: cmd.asm,v 1.7 1998/10/26 17:04:49 tribby Exp $ * ************************************************************************** * @@ -28,17 +28,21 @@ * * command subroutine (4:waitpid,2:inpipe,2:jobflag,2:inpipe2, * 4:pipesem,4:stream) +* Called by execute to act on a single command * Returns next token in Accumulator * * argfree subroutine (2:argc,4:argv) * * ShellExec subroutine (4:path,2:argc,4:argv,2:jobflag) +* Reads and executes commands from an exec file. * Returns completion status in Accumulator * * execute subroutine (4:cmdline,2:jobflag) +* Interpret a command line. * Returns completion status in Accumulator * * system Defined for libc; interface in +* User interface to execute commands via shell * int system (char *command) * ************************************************************************** @@ -52,6 +56,8 @@ dummycmd start ; ends up in .root SIGINT gequ 2 SIGSTOP gequ 17 +SIGTSTP gequ 18 +SIGCHLD gequ 20 ; ; TOKENS used by the parser ; @@ -328,12 +334,12 @@ errstr2 dc c"gsh: Missing ending '.",h'0d00' command START pipefds equ 1 -errappend equ pipefds+2 +errappend equ pipefds+4 errfile equ errappend+2 srcfile equ errfile+4 dstfile equ srcfile+4 -count equ dstfile+4 -argv equ count+2 +needq equ dstfile+4 +argv equ needq+2 word equ argv+4 cmdline equ word+4 pid equ cmdline+4 @@ -366,33 +372,35 @@ end equ waitpid+4 lda #0 Initialize to null C string. sta [cmdline] - jsl alloc1024 + jsl alloc1024 Allocate memory for token. sta word stx word+2 - ph4 #MAXARG*4 + ph4 #MAXARG*4 Allocate argv parameter pointer array ~NEW sta argv stx argv+2 - stz srcfile + stz argc Argument count = 0 + + stz srcfile Clear I/O redirection pointers stz srcfile+2 stz dstfile stz dstfile+2 stz errfile stz errfile+2 - stz argc stz pipefds stz pipefds+2 + lda #-3 sta [waitpid] -loop pei (word+2) +loop pei (word+2) Get next token from input stream. pei (word) pei (stream+2) pei (stream) jsl gettoken - sta token + sta token Jump to appropriate token handler. asl a tax jmp (toktbl,x) @@ -443,23 +451,33 @@ word2 lda argc ;Copy word to argv[argc] pei (temp) jsr copycstr - stz count ;count illegal characters in word - ldy #0 -illword lda [word],y +; +; Determine whether parameter needs surrounding quotes +; + stz needq + lda [word] If this is a null parameter, and #$FF - beq appword - if2 @a,eq,#' ',incword - if2 @a,eq,#'&',incword - if2 @a,eq,#'|',incword - if2 @a,eq,#'<',incword - if2 @a,eq,#'>',incword - if2 @a,eq,#';',incword - bra nextword -incword inc count -nextword iny - bra illword + beq qneeded it needs to be quoted. + ldy #0 +chkchar if2 @a,eq,#' ',qneeded + if2 @a,eq,#'&',qneeded + if2 @a,eq,#'|',qneeded + if2 @a,eq,#'<',qneeded + if2 @a,eq,#'>',qneeded + if2 @a,eq,#';',qneeded + iny Not special character. + lda [word],y Get next character in parameter. + and #$FF + beq appword Done if null character. + bra chkchar -appword pei (word+2) ;append word to current command line +qneeded inc needq Quotes needed. + +; +; Append word to command line (optionally, with quotes) +; +appword anop + pei (word+2) pei (word) pei (cmdline+2) pei (cmdline) @@ -470,35 +488,35 @@ appword pei (word+2) ;append word to current command line lda #' ' sta [cmdline],y iny -nospace lda count +nospace lda needq If special char is in parameter, beq noquote lda [word] and #$FF - cmp #'"' + cmp #'"' and it doesn't start with '"', bne doquote - stz count + stz needq bra noquote -doquote lda #'"' +doquote lda #'"' add a '"' at start. sta [cmdline],y iny - inc count noquote pei (cmdline+2) add2 @y,cmdline,@a pha - jsr copycstr - lda count + jsr copycstr Copy the parameter. + lda needq If quote was added at start, beq noquote2 pei (cmdline+2) pei (cmdline) jsr cstrlen tay - lda #'"' + lda #'"' add another at end. sta [cmdline],y iny lda #0 sta [cmdline],y noquote2 inc argc ;increment argument count goloop jmp loop + ; ; Parse a '<' token ; @@ -579,76 +597,95 @@ tok_semi anop tok_nl anop tok_eof anop - lda argc + lda argc If number of arguments == 0, bne nonnull - lda #0 - sta [waitpid] - lda #T_NULL + + lda srcfile If any of the file pointers + ora srcfile+2 are != NULL, + ora dstfile + ora dstfile+2 + ora errfile + ora errfile+2 + beq nulldone + + ldx #^spcmdstr print error message: + lda #spcmdstr specify a command before redirecting. + jsr errputs + +nulldone lda #0 Clear the waitpid + sta [waitpid] and return as if + lda #T_NULL nothing were parsed. jmp exit -nonnull asl2 a ;terminate the argv list - tay +nonnull asl2 a Terminate the argv list + tay with a null poiner. lda #0 sta [argv],y iny2 sta [argv],y ; -; see if there is a conflict between >,>> with | +; See if there is a conflict between > or >> and | ; lda token if2 @a,ne,#T_BAR,runit lda dstfile ora dstfile+2 beq bar2 - lda #err08 ;> or >> conflicts with | + lda #err08 Yes: there is a conflict! jmp error -bar2 clc - tdc - adc #pipefds +bar2 clc Calculate 32-bit address + tdc of direct page variable + adc #pipefds pipefds in X and A. ldx #0 - pipe @xa -;what if pipes return errors? + pipe @xa Allocate 2 file descriptor pipe +; >> NOTE: what if pipes return errors? -runit pei (argc) - pei (argv+2) +; +; Call invoke param size:name +; +runit pei (argc) 2: argc + pei (argv+2) 4: argv pei (argv) - pei (srcfile+2) + pei (srcfile+2) 4: sfile pei (srcfile) - pei (dstfile+2) + pei (dstfile+2) 4: dfile pei (dstfile) - pei (errfile+2) + pei (errfile+2) 4: efile pei (errfile) - pei (append) - pei (errappend) + pei (append) 2: app + pei (errappend) 2: eapp ldx #0 if2 token,ne,#T_AMP,run2 - inx + inx 2: bg run2 phx - pei (cmdline+2) + pei (cmdline+2) 4: cline pei (cmdline) - pei (jobflag) - pei (inpipe) - pei (pipefds+2) - pei (inpipe2) - pei (pipefds) - pei (pipesem+2) + pei (jobflag) 2: jobflag + pei (inpipe) 2: pipein (param passed in) + pei (pipefds+2) 2: pipeout (allocated: read end) + pei (inpipe2) 2: pipein2 (param passed in) + pei (pipefds) 2: pipeout2 (allocated: write end) + pei (pipesem+2) 4: pipesem (param passed in) pei (pipesem) jsl invoke sta pid cmp #-1 beq exit - if2 token,ne,#T_BAR,run3 If next token is "|", - pei (waitpid+2) recursively call command. +; If next token is "|", recursively call command. + + if2 token,ne,#T_BAR,run3 + + pei (waitpid+2) 4: waitpid pei (waitpid) - pei (pipefds) - pei (jobflag) - pei (pipefds+2) - pei (pipesem+2) + pei (pipefds) 2: inpipe + pei (jobflag) 2: jobflag + pei (pipefds+2) 2: inpipe2 + pei (pipesem+2) 4: pipesem pei (pipesem) - pei (stream+2) + pei (stream+2) 4: stream pei (stream) jsl command bra exit @@ -728,6 +765,7 @@ err06 dc c'gsh: Extra ''>&'' or ''>>&'' encountered.',h'0d00' err07 dc c'gsh: No file specified for ''>&'' or ''>>&''.',h'0d00' err08 dc c'gsh: ''|'' conflicts with ''>'' or ''>>''.',h'0d00' err09 dc c'gsh: ''|'' conflicts with ''<''.',h'0d00' +spcmdstr dc c'gsh: Specify a command before redirecting.',h'0d00' END @@ -766,7 +804,7 @@ free2 pei (argv+2) ************************************************************************** * -* Interpret a shell script +* Read and execute commands from an exec file (shell script) * This is overly complicated so that it can be run concurrently. * ************************************************************************** @@ -802,7 +840,7 @@ end equ path+4 lock mutex ; -; Set the variables 0..argc +; Set the environment variables $0 ... argc ; lda argc Get number of variables. jeq vars_set If 0, there are none to set. @@ -853,39 +891,49 @@ set_value anop jcc parmloop stay in loop. ; -; Variables have all been set +; $0 ... $n environment variables have all been set ; vars_set unlock mutex - ph4 #4 ;Close parms +; +; Allocate memory for GS/OS calls +; + + ph4 #4 CloseGS parms ~NEW sta CRec stx CRec+2 - ph4 #10 ;Open parms + ph4 #10 OpenGS parameter block ~NEW sta ORec stx ORec+2 - ph4 #12 ;NewLine parms + ph4 #12 NewLineGS parameter block ~NEW sta NRec stx NRec+2 - ph4 #16 ;Read parms + ph4 #16 ReadGS parameter block ~NEW sta RRec stx RRec+2 - ph4 #1000 ;data buffer + ph4 #1000 Data buffer (1000 bytes) ~NEW sta data stx data+2 - pei (path+2) ;Convert filename to GS/OS string - pei (path) +; +; Set parameters in OpenGS parameter block +; + lda #3 Number of parameters = 3. + sta [ORec] + + pei (path+2) Convert exec file + pei (path) pathname to GS/OS string jsr c2gsstr - ldy #4 + ldy #4 Store in PB, offset bytes 4-7. sta [ORec],y sta ptr iny2 @@ -893,86 +941,105 @@ vars_set unlock mutex sta [ORec],y sta ptr+2 - ldy #8 - lda #1 ;Read access only + lda #1 Read access only + ldy #8 Store in PB, offset bytes 8-9. sta [ORec],y - lda #3 ;Open the file - sta [ORec] - pei (ORec+2) + pei (ORec+2) OpenGS(ORec) pei (ORec) - ph2 #$2010 ;OPEN + ph2 #$2010 jsl $E100B0 - bcc ok - sta ErrError + + bcc ok If there was an error, + sta ErrError print a message ErrorGS Err jmp done -awshit sta ErrError - ErrorGS Err - jmp almostdone +ok ldy #2 Copy file ref num + lda [ORec],y from OpenGS PB into + sta [NRec],y NewLineGS PB, + sta [RRec],y ReadGS PB, + sta [CRec],y and CloseGS PB. -ok ldy #2 ;Copy file ref num - lda [ORec],y - sta [NRec],y - sta [RRec],y - sta [CRec],y - - lda #4 ;Do NewLine +; +; Set parameters in NewLineGS parameter block +; + lda #4 Number of parameters = 4. sta [NRec] - ldy #4 - lda #$7F - sta [NRec],y - iny2 - lda #1 - sta [NRec],y - iny2 - lda #NLTable + + ldy #4 enableMask + lda #$7F = $7F (each input character + sta [NRec],y is ANDed with this mask) + + iny2 numChars + lda #1 = 1 (number of newline chars + sta [NRec],y contained in newline char table) + + iny2 newlineTable pointer + lda #NLTable = NLTable sta [NRec],y iny2 lda #^NLTable sta [NRec],y - pei (NRec+2) - pei (NRec) - ph2 #$2011 ;NEWLINE - jsl $E100B0 - bcs awshit - lda #4 ;Set up read parm + pei (NRec+2) NewLineGS(NRec) + pei (NRec) + ph2 #$2011 + jsl $E100B0 + + bcc ok2 If there was an error, + sta ErrError print a message + ErrorGS Err + jmp close_ex + +; +; Set up ReadGS parameter block +; +ok2 lda #4 Number of parameters = 4 sta [RRec] - tay - lda data + + tay dataBuffer (offset 4) + lda data = data sta [RRec],y iny2 lda data+2 sta [RRec],y - iny2 - lda #1000 + + iny2 requestCount (offset 4) + lda #999 = 999 (save 1 byte for \0) sta [RRec],y iny2 lda #0 sta [RRec],y +; +; Read lines from the exec file +; ReadLoop anop - pei (RRec+2) + pei (RRec+2) ReadGS(RRec) pei (RRec) - ph2 #$2012 ;READ + ph2 #$2012 jsl $E100B0 - bcs almostdone - ldy #12 + + bcs close_ex Check for error + + ldy #12 Get transferCount lda [RRec],y - tay - lda #0 + + tay Store null byte + lda #0 at end of buffer. sta [data],y - lda varecho - beq noecho + + lda varecho If $ECHO environment + beq noecho variable is set, ldx data+2 lda data - jsr puts - jsr newline -noecho lda [data] - and #$FF - if2 @a,eq,#'#',ReadLoop + jsr puts print the line + jsr newline and a newline. + +noecho lda [data] If first character + and #$FF in data buffer is + if2 @a,eq,#'#',ReadLoop "#", read next line. * call execute: subroutine (4:cmdline,2:jobflag) pei (data+2) @@ -981,20 +1048,23 @@ noecho lda [data] jsl execute sta status - lda exit_requested - bne almostdone - bra ReadLoop + lda exit_requested If exit not requested, + bne close_ex + bra ReadLoop stay in read loop. -almostdone anop - stz exit_requested - lda #1 +; +; Close the exec file +; +close_ex anop + lda #1 Number of parameters = 1. sta [CRec] - pei (CRec+2) + pei (CRec+2) CloseGS(CRec) pei (CRec) - ph2 #$2014 ;CLOSE + ph2 #$2014 jsl $E100B0 + stz exit_requested Clear the "exit gsh" flag. -done pei (CRec+2) +done pei (CRec+2) Free the parameter blocks, pei (CRec) jsl nullfree pei (NRec+2) @@ -1006,15 +1076,17 @@ done pei (CRec+2) pei (ORec+2) pei (ORec) jsl nullfree - pei (data+2) + pei (data+2) data buffer, pei (data) jsl nullfree - pei (ptr+2) + pei (ptr+2) and path name. pei (ptr) jsl nullfree +; +; Restore stack and return to caller +; exit1a anop - lda space+1 sta end-2 lda space @@ -1028,7 +1100,8 @@ exit1a anop lda status Pass back status value. rtl -NLTable dc h'0d' +NLTable dc h'0d' Newline Table + ; Parameter block for shell ErrorGS call (p 393 in ORCA/M manual) Err dc i2'1' pCount @@ -1135,7 +1208,7 @@ find_end anop lda [cmdstrt],y Get next character. and #$FF If at end of string, beq found_end all done looking. -; Check for special characters +; Check for special quote characters cmp #"'" beq s_quote cmp #'"' @@ -1267,9 +1340,9 @@ loop pea 0 ;Bank 0 waitpid (hi) clc adc #pid pha waitpid (low) - pea 0 inpipe + pea 0 inpipe = 0 pei (jobflag) jobflag - pea 0 inpipe2 + pea 0 inpipe2 = 0 pea 0 ;Bank 0 pipesem (hi) tdc clc @@ -1283,51 +1356,64 @@ loop pea 0 ;Bank 0 waitpid (hi) jsl command sta term - bmi noerrexit + jmi noerrexit lda pid - beq nowait + jeq donewait cmp #-1 - beq noerrexit + jeq noerrexit lda jobflag - beq jobwait + jeq jobwait signal (#SIGINT,#0) phx pha - signal (#SIGSTOP,#0) + signal (#SIGTSTP,#0) phx pha -otherwait ldx #0 +otherwait anop + ldx #0 clc tdc adc #waitstatus - wait @xa + wait @xa Wait for child completion. cmp pid bne otherwait lda waitstatus and #$FF - cmp #$7F + cmp #$7F Check for WSTOPPED status. beq otherwait lda waitstatus jsr setstatus pla plx - signal (#SIGSTOP,@xa) + signal (#SIGTSTP,@xa) pla plx signal (#SIGINT,@xa) - bra nowait + bra donewait -jobwait jsl pwait - sta waitstatus +jobwait anop + signal (#SIGCHLD,#pchild) Ensure child sig handler active. + phx Save address of previous sig handler. + pha + kill (pid,#0) If child no longer exists, + beq wait4job + pei pid + jsl removejentry Remove it from the list. + bra setwstat +wait4job jsl pwait Otherwise, wait for it. +setwstat stz waitstatus + pla Restore previous child completion + plx signal handler. + signal (#SIGCHLD,@xa) ; If command detected EOF terminator, all done -nowait if2 term,eq,#T_EOF,noerrexit +donewait if2 term,eq,#T_EOF,noerrexit lda [exebuf] If not at end of line, and #$FF beq exit @@ -1405,11 +1491,11 @@ space equ retval+2 ina return 1 to caller. ; -; Let execute(str) do the work +; Let execute(str,1) do the work ; makecall pei (str+2) pei (str) - ph2 #1 ;tells execute we're called by system + ph2 #1 jobflag=1 says we're called by system jsl execute ; ; Set status and go back to the caller diff --git a/bin/gsh/dir.asm b/bin/gsh/dir.asm index 1f39bf1..4f53707 100644 --- a/bin/gsh/dir.asm +++ b/bin/gsh/dir.asm @@ -6,7 +6,7 @@ * Jawaid Bazyar * Tim Meekins * -* $Id: dir.asm,v 1.6 1998/09/08 16:53:07 tribby Exp $ +* $Id: dir.asm,v 1.7 1998/10/26 17:04:50 tribby Exp $ * ************************************************************************** * @@ -25,11 +25,11 @@ * * InitDStack * -* dirs +* dirs built-in command * -* pushd +* pushd built-in command * -* popd +* popd built-in command * * path2tilde * @@ -88,6 +88,7 @@ space equ arg+4 beq showshort dec a bne using + ldy #4 lda [argv],y sta arg @@ -108,12 +109,12 @@ using ldx #^usingstr jsr errputs bra exit -showlong jsl dotods +showlong jsl dotods Set top of stack to current directory. pea 0 jsl showdir bra exit -showshort jsl dotods +showshort jsl dotods Set top of stack to current directory. pea 1 jsl showdir @@ -144,46 +145,52 @@ space equ arg+4 subroutine (4:argv,2:argc),space - lda argc - dec a - beq xchange - dec a - bne usage + lda argc Get number of arguments. + dec a If no parameters, + beq xchange exchange top two dirs on stack. + dec a If > 1 parameter, + bne usage print usage string. - ldy #4 - lda [argv],y - sta arg + ldy #4 Move parameter pointer from + lda [argv],y argv array to direct + sta arg page variable "arg". ldy #6 lda [argv],y sta arg+2 - lda [arg] - and #$FF - cmp #'+' - beq rotate - jmp godir + lda [arg] If first character + and #$FF of parameter is + cmp #'+' "+", + beq rotate do the rotate; + jmp godir else push the directory. + +; +; More than one parameter provided; print usage string and exit. +; usage ldx #^usagestr lda #usagestr - jsr errputs - jmp exit + jmp prerrmsg -xchange lda tods - bne xgoodie - ldx #^err1 - lda #err1 - jsr errputs - jmp exit -xgoodie jsl dotods +; +; Either no parameter or "+" provided; exchange directory stack entries. +; +xchange lda tods Get index to top of dir stack. + bne xgoodie If 0, + ldx #^err1 print error message + lda #err1 "No other directory" + jmp prerrmsg + +xgoodie jsl dotods Set top of stack to current directory. lda tods dec a asl a asl a - tax + tax X = offset to tos-1. lda tods asl a asl a - tay - lda dirstack,x + tay Y = offset to tos. + lda dirstack,x Swap tos-1 and tos. pha lda dirstack,y sta dirstack,x @@ -195,29 +202,36 @@ xgoodie jsl dotods sta dirstack+2,x pla sta dirstack+2,y - jmp gototop - + jmp gototop chdir to the new tos. + +; +; Parameter = +n; do the rotate +; rotate add4 arg,#1,p pei (p+2) pei (p) jsr cstrlen tax - Dec2Int (p,@x,#0),@a - sta count - cmp #0 - beq godir - lda tods - beq roterr - lda count - cmp tods + Dec2Int (p,@x,#0),@a Convert parameter to decimal + sta count and store in count. + cmp #0 If parameter is 0 + beq badnum or negative, + bmi badnum report "invalid number". + cmp tods If count >= tos, beq rotloop bcc rotloop -roterr ldx #^err2 - lda #err2 - jsr errputs - jmp exit +roterr ldx #^err2 Print error message: + lda #err2 Directory stack not that deep + jmp prerrmsg +badnum ldx #^errbadnum Print error message: + lda #errbadnum Invalid number + jmp prerrmsg + +; +; Loop to rotate entries in directory stack +; rotloop lda tods dec a asl a @@ -244,25 +258,9 @@ nextrot pla sta dirstack+2 dec count bne rotloop - bra gototop - -godir jsl dotods - pei (arg+2) - pei (arg) - jsl gotodir - bne exit - - inc tods - lda tods - asl a - asl a - tay - lda #0 - sta dirstack,y - sta dirstack+2,y - jsl dotods - bra done - +; +; chdir to the top-of-stack directory +; gototop lda tods asl a asl a @@ -272,17 +270,50 @@ gototop lda tods lda dirstack,y pha jsl gotodir + bra done All done. -done lda varpushdsil + +; +; Parameter = directory name; add it to the stack +; +godir anop + lda tods + cmp #MAXD-1 If index >= maximum, + bcc stackok + ldx #^errfull print error message. + lda #errfull +prerrmsg jsr errputs + bra exit +stackok anop + jsl dotods Set top of stack to current directory. + pei (arg+2) + pei (arg) + jsl gotodir chdir to the parameter directory. + bne exit + + inc tods Bump the top of stack pointer. + lda tods + asl a + asl a + tay + lda #0 + sta dirstack,y + sta dirstack+2,y + jsl dotods Set top of stack to current directory. + +done lda varpushdsil If $PUSHDSILENT not defined, bne exit pea 1 - jsl showdir + jsl showdir show the directory stack. exit return 2:#0 usagestr dc c'usage: pushd [+n | dir]',h'0d00' err1 dc c'pushd: No other directory',h'0d00' err2 dc c'pushd: Directory stack not that deep',h'0d00' +errfull dc c'pushd: Directory stack full',h'0d00' +errbadnum dc c'pushd: Invalid number',h'0d00' + END @@ -348,7 +379,7 @@ pluserr ldx #^err2 jsr errputs bra exit -doplus jsl dotods +doplus jsl dotods Set top of stack to current directory. sub2 tods,count,@a asl a asl a @@ -502,35 +533,39 @@ space equ idx+2 subroutine (2:flag),space - lda tods - asl a - asl a + lda tods Get directory stack index. + asl a Multiply by four to + asl a get byte offset (idx). sta idx -loop lda flag +loop lda flag If parameter == 1, beq long + ldy idx - lda dirstack+2,y + lda dirstack+2,y print entry pha lda dirstack,y pha - jsl path2tilde - phx + jsl path2tilde but first substitute "~" + phx for home directory. pha jsr puts jsl nullfree bra next -long ldy idx - lda dirstack+2,y + +long ldy idx else, + lda dirstack+2,y print full entry. tax lda dirstack,y jsr puts -next lda #' ' + +next lda #' ' Print a space. jsr putchar - lda idx + + lda idx If idx != 0, beq done - sub2 idx,#4,idx - bra loop + sub2 idx,#4,idx idx = idx -4 + bra loop handle next entry. done jsr newline @@ -555,7 +590,7 @@ space equ idx+2 subroutine (0:dummy),space lda tods Get index number. - asl a Multiply by four + asl a Multiply index by four asl a to get byte offset. sta idx Store in idx tay and Y-register. diff --git a/bin/gsh/edit.asm b/bin/gsh/edit.asm index 9b0abe2..6cdba09 100644 --- a/bin/gsh/edit.asm +++ b/bin/gsh/edit.asm @@ -6,7 +6,7 @@ * Jawaid Bazyar * Tim Meekins * -* $Id: edit.asm,v 1.6 1998/09/08 16:53:08 tribby Exp $ +* $Id: edit.asm,v 1.7 1998/10/26 17:04:50 tribby Exp $ * ************************************************************************** * @@ -121,23 +121,33 @@ nextchar jsr cursoron jsr flush jsr getchar sta 4 - ldx signalled + ldx signalled If signal was received, beq nextchar2 - jsr cmdsig -; bra cmdloop + jsr cmdsig acknowledge it. nextchar2 jsr cursoroff - lda 4 - cmp #-1 + lda 4 Get results of getchar. + cmp #-1 EOF? beq eof - cmp #4 ;CTL-D - bne findcmd + cmp #4 CTL-D? (treated same as EOF) + beq eof + cmp #$FF00 Error? + bcc findcmd + and #$00FF + sta ErrError + ErrorGS Err yes--print error code. + bra reterr +; +; Parameter block for shell ErrorGS call (p 393 in ORCA/M manual) +; +Err dc i2'1' pCount +ErrError ds 2 Error number eof ldx cmdlen bne findcmd lda varignore bne findcmd - jsr cursoron +reterr jsr cursoron ioctl (#1,#TIOCSETP,#oldsgtty) ioctl (#1,#TIOCSETK,#oldttyk) ioctl (#1,#TIOCSLTC,#oldltc) @@ -243,6 +253,7 @@ cmdov2 lda insertflag cmp #0 bne cmdov2a rts + cmdov2a ldx #0 cmdov3 if2 @y,eq,cmdlen,cmdov4 lda cmdline,y diff --git a/bin/gsh/gsh.mac b/bin/gsh/gsh.mac index 1ceca9f..fb7a2a1 100644 --- a/bin/gsh/gsh.mac +++ b/bin/gsh/gsh.mac @@ -66,13 +66,13 @@ MEND ******************** -* getpgrp +* _getpgrp ******************** MACRO -&lab getpgrp &a1 +&lab _getpgrp &a1 &lab ph2 &a1 case on - jsl getpgrp + jsl _getpgrp case off MEND diff --git a/bin/gsh/gsh.rez b/bin/gsh/gsh.rez index 2a6c3b5..6711a50 100644 --- a/bin/gsh/gsh.rez +++ b/bin/gsh/gsh.rez @@ -1,7 +1,7 @@ /* * Resources for version and comment * - * $Id: gsh.rez,v 1.5 1998/09/08 16:53:09 tribby Exp $ + * $Id: gsh.rez,v 1.6 1998/10/26 17:04:50 tribby Exp $ */ #define PROG "gsh" @@ -16,7 +16,7 @@ resource rVersion (1, purgeable3) { { 2, 0, 0, /* Version 2.0.0 */ development, /* development|alpha|beta|final|release */ - 4 }, /* non-final release number */ + 5 }, /* non-final release number */ verUS, /* Country */ PROG, /* Program name */ DESC diff --git a/bin/gsh/invoke.asm b/bin/gsh/invoke.asm index 1660c47..0c2fb42 100644 --- a/bin/gsh/invoke.asm +++ b/bin/gsh/invoke.asm @@ -6,7 +6,7 @@ * Jawaid Bazyar * Tim Meekins * -* $Id: invoke.asm,v 1.7 1998/09/08 16:53:10 tribby Exp $ +* $Id: invoke.asm,v 1.8 1998/10/26 17:04:50 tribby Exp $ * ************************************************************************** * @@ -28,7 +28,7 @@ * returns with carry set/clear to indicate failure/success * * invoke subroutine (2:argc,4:argv,4:sfile,4:dfile,4:efile,2:app, -* 2:eapp,2:bg,4:cmd,2:jobflag,2:pipein,2:pipeout, +* 2:eapp,2:bg,4:cline,2:jobflag,2:pipein,2:pipeout, * 2:pipein2,2:pipeout2,4:pipesem) * return 2:rtnval * @@ -225,117 +225,111 @@ p equ 0 biflag equ p+4 ptr equ biflag+2 rtnval equ ptr+4 Return pid, -1 (error), or 0 (no fork) -dir equ rtnval+2 -space equ dir+4 +cpath equ rtnval+2 +space equ cpath+4 - subroutine (2:argc,4:argv,4:sfile,4:dfile,4:efile,2:app,2:eapp,2:bg,4:cmd,2:jobflag,2:pipein,2:pipeout,2:pipein2,2:pipeout2,4:pipesem),space + subroutine (2:argc,4:argv,4:sfile,4:dfile,4:efile,2:app,2:eapp,2:bg,4:cline,2:jobflag,2:pipein,2:pipeout,2:pipein2,2:pipeout2,4:pipesem),space ld2 -1,rtnval - stz biflag ;not a built-in + stz biflag Clear built-in flag. - lda argc Get number of arguments. - bne chknull If != 0 continue with processing. - - lda sfile If any of the file pointers - ora sfile+2 are != NULL, - ora dfile - ora dfile+2 - ora efile - ora efile+2 - beq nulldone - - ldx #^spcmdstr print error message: - lda #spcmdstr ' specify a command before redirecting.' - jsr errputs - -nulldone jmp done + lda argc If number of arguments == 0, + bne chknull nothing to do. (Shouldn't happen +nulldone jmp done because invoke checks argc==0). ; ; Check for null command ; -chknull ldy #2 Move command line +chknull ldy #2 Move 1st argument lda [argv] pointer to - sta dir dir (4 bytes). + sta cpath cpath (4 bytes). lda [argv],y - sta dir+2 If pointer == NULL - ora dir + sta cpath+2 If pointer == NULL + ora cpath beq nulldone all done. - lda [dir] If first character == '\0', + lda [cpath] If first character == '\0', and #$FF beq nulldone all done. ; -; check for file +; Check command: is it builtin, in hash table, etc? ; -checkfile anop - - pei (dir+2) - pei (dir) - jsl IsBuiltin ;check builtin first - cmp #-1 + pei (cpath+2) IsBuiltin returns + pei (cpath) 0 if forked built-in + jsl IsBuiltin 1 if non-forked built-in + cmp #-1 -1 if not a built-in jne trybuiltin +; ; Command is not listed in the built-in table. See if it was hashed - - pei (dir+2) - pei (dir) +; + pei (cpath+2) + pei (cpath) ph4 hash_table ph4 #hash_paths jsl search cmp #0 bne changeit cpx #0 - beq skip + beq noentry -changeit sta dir - stx dir+2 +changeit sta cpath Use full path from + stx cpath+2 hash table. -skip lock mutex2 - pei (dir+2) - pei (dir) +; +; Get information about the command's filename +; +noentry lock info_mutex + + pei (cpath+2) + pei (cpath) jsr c2gsstr sta GRecPath sta ptr stx GRecPath+2 stx ptr+2 - GetFileInfo GRec - unlock mutex2 - jcs notfound -; File type $B5 is a GS/OS Shell application (EXE) + unlock info_mutex + jcs notfound If error getting info, print error. + +; Is file type $B5: GS/OS Shell application (EXE)? if2 GRecFileType,eq,#$B5,doExec -; File type $B3 is a GS/OS application (S16) +; Is file type $B3: GS/OS application (S16)? if2 @a,eq,#$B3,doExec - ldx vardirexec + ldx vardirexec If $NODIREXEC isn't set, and bne ft02 cmp #$0F - jeq doDir Target is a directory; change to it. + jeq doDir file is a directory: change to it. -; File type $B0 is a source code file (SRC) +; Is file type $B0: source code file (SRC)? ft02 if2 @a,ne,#$B0,badfile ; Type $B0, Aux $00000006 is a shell command file (EXEC) if2 GRecAuxType,ne,#6,badfile if2 GRecAuxType+2,ne,#0,badfile jmp doShell - -badfile ldx dir+2 - lda dir +; +; Command file is not an appropriate type +; +badfile ldx cpath+2 + lda cpath jsr errputs ldx #^err1 Print error message: lda #err1 'Not executable.' jsr errputs -free pei (ptr+2) - pei (ptr) +free pei (ptr+2) Free memory used to hold + pei (ptr) GS/OS string with path. jsl nullfree jmp done -; -; launch an executable -; +* +* --------------------------------------------------------------- +* +* Launch an executable (EXE or S16 file) + doExec pei (ptr+2) pei (ptr) jsl nullfree @@ -344,11 +338,13 @@ doExec pei (ptr+2) jsr postfork jmp done - -invoke0 phk - plb ; -; make a copy of cmd +; Forked shell starts here... +; +invoke0 phk Make sure data bank register + plb is the same as program bank. +; +; Make copies of command line (cline) and path (cpath) for child ; pha pha @@ -362,7 +358,7 @@ invoke0 phk lda [1],y ;This is the UserID! and #$F0FF pha - ph4 _cmd + ph4 _cline jsr cstrlen inc a ply @@ -371,7 +367,7 @@ invoke0 phk NewHandle (@xa,@y,#$4018,#0),1 ply ldx #0 - PtrToHand (_cmd,1,@xy) + PtrToHand (_cline,1,@xy) ldy #2 lda [1],y tax @@ -379,10 +375,8 @@ invoke0 phk pld ply ply - phx ;_cmd + phx ;_cline pha -; -; make a copy of dir ; pha pha @@ -396,7 +390,7 @@ invoke0 phk lda [1],y ;This is the UserID! and #$F0FF pha - ph4 _dir + ph4 _cpath jsr cstrlen inc a ply @@ -405,7 +399,7 @@ invoke0 phk NewHandle (@xa,@y,#$4018,#0),1 ply ldx #0 - PtrToHand (_dir,1,@xy) + PtrToHand (_cpath,1,@xy) ldy #2 lda [1],y tax @@ -413,24 +407,32 @@ invoke0 phk pld ply ply - phx ;_dir + phx ;_cpath pha jsl infork bcs invoke1 +; +; Call _execve(_cpath,_cline) to replace forked shell with executable file +; case on jsl _execve For 2.0.6: call _execve, not execve case off rtl +; +; Error reported by infork; clean up stack and return to caller +; invoke1 pla pla pla pla rtl -; -; Next command is a directory name, so change to that directory -; +* +* --------------------------------------------------------------- +* +* Next command is a directory name, so change to that directory + doDir lock cdmutex mv4 GRecPath,PRecPath SetPrefix PRec @@ -438,10 +440,13 @@ doDir lock cdmutex stz rtnval Return value: no fork done. jmp free -; -; Next command is a shell command file: fork a shell script -; -doShell inc biflag ;don't free argv... +* +* --------------------------------------------------------------- +* +* Next command is a shell command file: fork a shell script + +doShell anop + inc biflag ;don't free argv... jsr prefork * int fork2(void *subr, int stack, int prio, char *name, word argc, ...) @@ -458,26 +463,32 @@ doShell inc biflag ;don't free argv... jsl fork2 case off -* fork #exec0 jsr postfork jmp free -exec0 ph2 _argc ;for argfree +; +; Forked shell starts here... +; +exec0 anop + ph2 _argc ;for argfree ph4 _argv - ph4 _dir ;for shellexec + ph4 _cpath ShellExec parameters ph2 _argc ph4 _argv jsl infork bcs exec0c signal (#SIGCHLD,#0) PushVariablesGS NullPB - pea 1 + pea 1 jobflag = 1 jsl ShellExec jsl argfree PopVariablesGS NullPB rtl +; +; Error reported by infork; clean up stack and return to caller +; exec0c pla pla pla @@ -511,8 +522,8 @@ trybuiltin inc biflag It's a built-in. Which type? ; ; Control transfers here for a forked built-in command ; -forkbuiltin cop $7F Give palloc a chance - +forkbuiltin anop + cop $7F Give palloc a chance ph2 _argc ph4 _argv jsl infork @@ -520,12 +531,15 @@ forkbuiltin cop $7F Give palloc a chance jsl builtin rtl +; ; Error reported by infork; clean up stack and return to caller +; fork0c pla pla pla rtl +* --------------------------------------------------------------- ; ; It's a non-forked builtin @@ -558,46 +572,59 @@ notfound pei (ptr+2) lda pipein beq notfound0 +; Input being piped into a command that was not found. + ssignal _semaphore sdelete _semaphore + mv4 pjoblist,p ldy #16 ;p_jobid - lda [p],y - getpgrp @a + lda [p],y Get forked process's pid. + _getpgrp @a Get forked process's group number. eor #$FFFF inc a - kill (@a,#9) + kill (@a,#9) Kill all processes in that group. sigpause #0 notfound0 anop done cop $7F - lda biflag + lda biflag If built-in flag is clear, bne skipfrarg - pei (argc) + pei (argc) free arguments. pei (argv+2) pei (argv) jsl argfree -skipfrarg pei (cmd+2) - pei (cmd) +skipfrarg pei (cline+2) Free command-line. + pei (cline) jsl nullfree return 2:rtnval + + +* --------------------------------------------------------------- +* +* Support routines +* +* --------------------------------------------------------------- + ; +; Tasks to do just before forking ; -; stuff to do just before forking -; -prefork lock mutex +prefork lock fork_mutex Lock the fork mutual exclusion. SetInGlobals (#$FF,#00) +; +; Move essential parameters from stack to mutual-exclusion protected memory +; mv4 sfile,_sfile mv4 dfile,_dfile mv4 efile,_efile mv2 app,_app mv2 eapp,_eapp - mv4 cmd,_cmd - mv4 dir,_dir + mv4 cline,_cline + mv4 cpath,_cpath mv2 argc,_argc mv4 argv,_argv mv2 pipein,_pipein @@ -608,73 +635,87 @@ prefork lock mutex mv2 jobflag,_jobflag lda [pipesem] sta _semaphore - lda pipesem - sta putsem+1 - lda pipesem+1 + + lda pipesem Set address of + sta putsem+1 semaphone in + lda pipesem+1 LDA instruction. sta putsem+2 + rts +* --------------------------------------------------------------- + ; -; stuff to do right after forking +; Tasks the parent process does right after forking ; postfork sta rtnval - lda pipein + lda pipein If pipein != 0, beq postfork2 sta CloseRef - Close CloseParm -postfork2 lda pipeout + Close CloseParm close pipein. + +postfork2 lda pipeout If pipeout != 0, beq postfork3 sta CloseRef - Close CloseParm -postfork3 lda rtnval + Close CloseParm close pipeout. + +postfork3 lda rtnval If return value == -1, cmp #-1 bne postfork4 - ldx #^deadstr Print error message: - lda #deadstr 'Cannot fork (too many processes?)' + ldx #^deadstr Print error message: + lda #deadstr 'Cannot fork (too many processes?)' jsr errputs - unlock mutex - jmp done + unlock fork_mutex Unlock the fork mutual exclusion. + jmp postfork6 Return to caller. postfork4 ldx jobflag dex - beq postfork5 - pha + beq postfork5 If jobflag == 1, + pha pei (bg) - pei (cmd+2) - pei (cmd) - lda pipein + pei (cline+2) + pei (cline) + lda pipein if pipein == 0, bne postfork4a - jsl palloc - bra postfork5 -postfork4a jsl pallocpipe -postfork5 lda >mutex ;DANGER!!!!! Assumes knowledge of + jsl palloc palloc(0,cline) + bra postfork5 else +postfork4a jsl pallocpipe pallocpipe(0,cline) + +postfork5 anop +; +; Wait for fork mutual exclusion lock to clear (cleared by infork) +; + lda >fork_mutex ;DANGER!!!!! Assumes knowledge of beq postfork6 ;lock/unlock structure!!!!!!!! cop $7F bra postfork5 + postfork6 rts -; -; stuff to do in fork -; -infork phk - plb +* --------------------------------------------------------------- - lda _jobflag - bne invoke0b +; +; Startup tasks by forked process +; +infork phk Make sure data bank register + plb is the same as program bank. + + lda _jobflag If jobflag == 0, + bne infork0b Open ttyopen - jcs doneinfork + jcs errinfork lda _pipein - bne invoke0a - tcnewpgrp ttyref -invoke0a settpgrp ttyref - lda _bg ;if in background then reset tty to + bne infork0a If not in pipeline, + tcnewpgrp ttyref allocate new process group. +infork0a settpgrp ttyref Set current process to have proc group. + lda _bg If in background, and #$FF - beq invoke0b ;to the shell process group - tctpgrp (gshtty,gshpid) + beq infork0b + tctpgrp (gshtty,gshpid) reset tty to the shell process group. -invoke0b ph4 _sfile +infork0b ph4 _sfile Redirect I/O ph4 _dfile ph4 _efile ph2 _app @@ -684,40 +725,58 @@ invoke0b ph4 _sfile ph2 _pipein2 ph2 _pipeout2 jsl redirect - jcs doneinfork + jcs errinfork - unlock mutex + unlock fork_mutex +; +; Wait on appropriate pipe semaphores +; lda _pipein - bne invoke0c + bne infork0c lda _pipeout - beq invoke0d - screate #0 -putsem sta >$FFFFFF - swait @a - bra invoke0d -invoke0c lda _pipeout - bne invoke0d -waitsemy lda _semaphore + beq clean_exit + +; +; _pipein == 0 && _pipeout != 0 +; + screate #0 Create a semaphore with count=0. +putsem sta >$FFFFFF Store semaphore number in pipesem. + swait @a Block on semaphore until ssignal. + bra clean_exit + +infork0c lda _pipeout + bne clean_exit +; +; _pipein != 0 && _pipeout != 0 +; +waitsemy lda _semaphore While _semaphore == 0, bne goodsemy - cop $7F + cop $7F allow other processes to run. bra waitsemy -goodsemy ssignal _semaphore - sdelete _semaphore - -invoke0d anop +goodsemy ssignal _semaphore Release _semaphore + sdelete _semaphore and delete it. +clean_exit anop clc bra indone +; +; Arrive at "errinfork" if ttyopen or redirect didn't work. +; +errinfork unlock fork_mutex +; sec Note: carry already set -doneinfork unlock mutex - sec -indone rtl +indone rtl Return to caller; status in carry. -mutex key -mutex2 key -cdmutex key + +fork_mutex key Mutual exclusion for forking +info_mutex key Mutual exclusion for GetFileInfo +cdmutex key Mutual exclusion for SetPrefix + +; +; Variables protected by fork_mutex (set by parent, used by child process) +; _argc dc i2'0' _argv dc i4'0' _sfile dc i4'0' @@ -725,8 +784,8 @@ _dfile dc i4'0' _efile dc i4'0' _app dc i2'0' _eapp dc i2'0' -_cmd dc i4'0' -_dir dc i4'0' +_cline dc i4'0' +_cpath dc i4'0' _pipein dc i2'0' _pipeout dc i2'0' _pipein2 dc i2'0' @@ -735,10 +794,12 @@ _bg dc i2'0' _jobflag dc i2'0' _semaphore dc i2'0' +; +; String constants +; str dc c'[0]',h'0d00' err1 dc c': Not executable.',h'0d00' err2 dc c': Command not found.',h'0d00' -spcmdstr dc c'Specify a command before redirecting.',h'0d00' deadstr dc c'Cannot fork (too many processes?)',h'0d00' ;try a spoon @@ -759,6 +820,7 @@ CloseRef dc i2'0' Err dc i2'0' +; Parameter block for opening tty ttyopen dc i2'2' ttyref dc i2'0' dc i4'ttyname' diff --git a/bin/gsh/jobs.asm b/bin/gsh/jobs.asm index b120f24..84e2c62 100644 --- a/bin/gsh/jobs.asm +++ b/bin/gsh/jobs.asm @@ -6,7 +6,7 @@ * Jawaid Bazyar * Tim Meekins * -* $Id: jobs.asm,v 1.6 1998/09/08 16:53:10 tribby Exp $ +* $Id: jobs.asm,v 1.7 1998/10/26 17:04:50 tribby Exp $ * ************************************************************************** * @@ -96,55 +96,73 @@ end equ space+3 phd tcd - getpid + getpid Get process ID. sta waitpid -waitloop ldx #%0000000000001010 +; +; Start of loop that waits for child processes to complete +; +waitloop anop +; Block signals 15 (SIGTERM), 18 (SIGTSTP), and 20 (SIGCHLD): +; Bit 3 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 +; Num 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 +; X/A 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + ldx #%0000000000001010 lda #%0100000000000000 sigblock @xa - sta oldsig + sta oldsig Save the previous signal mask. stx oldsig+2 - lda pjoblist + lock plistmutex Ensure list doesn't change. + + lda pjoblist Start pointer at head of job list. ldx pjoblist+2 -loop sta p +loop sta p Save job entry pointer in p. stx p+2 - - ora p+2 - beq done - ldy #p_flags + ora p+2 If pointer is 0, + beq done all done. + ldy #p_flags Get entry's job status flags. lda [p],y and #PFOREGND+PRUNNING cmp #PFOREGND+PRUNNING - bne loop2 - ldy #p_pid + bne getnext + + ldy #p_pid Get entry's process ID. lda [p],y cmp waitpid - beq loop2 + beq getnext ; check if the process is actually running..if it is not, report to the ; user that a stale process was detected and remove it from job control. - sigsetmask oldsig - sigpause #0 - bra waitloop -loop2 ldy #p_next+2 + unlock plistmutex + + sigsetmask oldsig Restore previous signal mask. + sigpause #0 Wait for a signal to arrive. + bra waitloop Start searching the entire list. + + +getnext ldy #p_next+2 Get pointer to next entry lda [p],y tax ldy #p_next lda [p],y - bra loop + bra loop and stay in loop. -done sigsetmask oldsig +; +; Arrive here when p == 0 +; +done unlock plistmutex + sigsetmask oldsig Restore previous signal mask. - pld - tsc + pld Reset direct page and + tsc stack pointers. clc adc #end-4 tcs - rtl + rtl Return to caller. END @@ -205,7 +223,9 @@ end equ pid+2 phd tcd - ldx #%0000000000001000 + lock plistmutex Ensure list doesn't change. + + ldx #%0000000000001000 Block SIGCHILD signals. lda #%0000000000000000 sigblock @xa phx @@ -284,6 +304,8 @@ in02 anop sta [pp],y jsr copycstr + unlock plistmutex + lda bg beq noprint pei (pp+2) @@ -294,7 +316,7 @@ in02 anop noprint anop case on - jsl sigsetmask + jsl sigsetmask Restore signal mask. case off lda space @@ -340,6 +362,8 @@ end equ pid+2 phd tcd + lock plistmutex Ensure list doesn't change. + ldx #%0000000000001000 lda #%0000000000000000 sigblock @xa @@ -423,6 +447,8 @@ addit ldy #p_friends lda pp+2 sta [p],y + unlock plistmutex + case on jsl sigsetmask case off @@ -486,7 +512,7 @@ end equ code+2 ; ; search for the job that has finished. ; -search lda pjoblist + lda pjoblist ldx pjoblist+2 lookloop sta p stx p+2 @@ -554,10 +580,11 @@ kill ldy #p_flags jsr setstatus bra zap zap0 inc signalled -zap ldy #p_index - lda [p],y +zap ldy #p_pid Remove the job entry + lda [p],y by referring to its pid. pha - jsl removejob + jsl removejentry + ldy #p_flags lda [p],y bit #PFOREGND @@ -578,9 +605,11 @@ done anop rtl +;-------------------------------------------------------------------- ; ; Set $status return variable ; + setstatus ENTRY xba Isolate status @@ -631,21 +660,21 @@ valstat_text dc c'000' Text (up to three digits) ;==================================================================== ; -; remove a job +; remove an entry in the job list, based on process number ; ;==================================================================== -removejob START +removejentry START using pdata p equ 1 prev equ p+4 space equ prev+4 -jobnum equ space+3 -end equ jobnum+2 +pid equ space+3 process id +end equ pid+2 -; subroutine (2:jobnum),space +; subroutine (2:pid),space tsc sec @@ -656,40 +685,43 @@ end equ jobnum+2 stz prev stz prev+2 + lock plistmutex Ensure list doesn't change. lda pjoblist ldx pjoblist+2 -loop sta p +loop sta p Get next entry in job list. stx p+2 - ora p+2 - jeq done - ldy #p_index + ora p+2 If null pointer, + jeq done all done. + ldy #p_pid Get job/pid number in entry. lda [p],y - cmp jobnum + cmp pid If it's not the one we're looking for, beq gotit - lda p + lda p Set prev to this entry. sta prev stx prev+2 ldy #p_next+2 - lda [p],y + lda [p],y Set X/A to next entry. tax ldy #p_next lda [p],y - bra loop + bra loop Check next entry. + ; -; adjust linked list pointers +; Entry found: adjust linked list pointers ; -gotit ora2 prev,prev+2,@a +gotit ora2 prev,prev+2,@a If prev != NULL, beq gotit2 - ldy #p_next + ldy #p_next prev->next = p->next lda [p],y sta [prev],y ldy #p_next+2 lda [p],y sta [prev],y bra gotit3 -gotit2 ldy #p_next - lda [p],y + +gotit2 ldy #p_next else + lda [p],y pjoblist = p->next sta pjoblist ldy #p_next+2 lda [p],y @@ -698,12 +730,11 @@ gotit2 ldy #p_next ; free the node (may want to check currjob and prevjob pointers) ; gotit3 anop - - ldy #p_flags + ldy #p_flags If PFOREGND status bit is set, lda [p],y and #PFOREGND bne gotit3c - jsr newline + jsr newline Print the job entry ldy #p_flags lda #0 sta [p],y @@ -712,36 +743,37 @@ gotit3 anop pea 0 pea 0 jsl pprint -gotit3c anop - ldy #p_command+2 - lda [p],y +gotit3c anop + ldy #p_command+2 Free memory used to hold + lda [p],y command string. pha dey2 lda [p],y pha jsl nullfree - lda pcurrent + lda pcurrent If pcurrent != p eor pcurrent+2 eor p eor p+2 bne gotit3a - mv4 pprevious,pcurrent - stz pprevious + mv4 pprevious,pcurrent pcurrent = pprevious + stz pprevious pprevious = NULL stz pprevious+2 - lda prev + lda prev If prev != pcurrent, eor prev+2 eor pcurrent eor pcurrent+2 beq gotit3a - mv4 prev,pprevious -gotit3a lda pprevious + mv4 prev,pprevious pprevious = prev + +gotit3a lda pprevious If pprevious != p, eor pprevious+2 eor p eor p+2 bne gotit3b - stz pprevious + stz pprevious pprevious == NULL stz pprevious+2 gotit3b anop @@ -751,18 +783,19 @@ gotit4 ldy #p_friends ldy #p_friends+2 lda [p],y pha - pei (p+2) + + pei (p+2) Free memory used to hold entry. pei (p) jsl nullfree - pla - sta P+2 + + pla p = p->p_friends + sta p+2 pla sta p ora p+2 - beq gotit5 - - ldy #p_command+2 - lda [p],y + beq gotit5 If p != NULL, + ldy #p_command+2 Free memory used to + lda [p],y hold text of command pha ldy #p_command lda [p],y @@ -772,7 +805,7 @@ gotit4 ldy #p_friends gotit5 anop ; -; find maximum job number +; find maximum job number and set pmaxindex ; stz prev lda pjoblist @@ -792,9 +825,11 @@ skipmax ldy #p_next+2 ldy #p_next lda [p],y bra fmaxloop + gotmax mv2 prev,pmaxindex done anop + unlock plistmutex lda space+1 sta end-2 lda space @@ -1215,7 +1250,6 @@ dofg1 lda [p],y lda [p],y bit #PSTOPPED beq dofg2 -; lda [p],y eor #PSTOPPED sta [p],y pei (p+2) @@ -1225,7 +1259,7 @@ dofg1 lda [p],y jsl pprint ldy #p_jobid lda [p],y - getpgrp @a + _getpgrp @a eor #$FFFF inc a kill (@a,#SIGCONT) @@ -1313,26 +1347,20 @@ loop ora2 p,p+2,@a dofg ldy #p_flags lda [p],y bit #PRUNNING -; cmp #PRUNNING -; bne dofg1 beq dofg1 ldx #^err02 lda #err02 bra puterr -dofg1 anop -; lda [p],y +dofg1 anop note: Y = #p_flags, A = [p],y ora #PRUNNING sta [p],y bit #PFOREGND beq dobg0 -; lda [p],y eor #PFOREGND sta [p],y dobg0 anop -; lda [p],y bit #PSTOPPED beq dofg2 -; lda [p],y eor #PSTOPPED sta [p],y tctpgrp (gshtty,gshpid) @@ -1343,7 +1371,7 @@ dobg0 anop jsl pprint ldy #p_jobid lda [p],y - getpgrp @a + _getpgrp @a eor #$FFFF inc a kill (@a,#SIGCONT) @@ -1411,6 +1439,7 @@ getit2 ldy #4+2 sta pid cmp #-1 jeq nojob + mv4 pjoblist,p loop ora2 p,p+2,@a jeq nojob @@ -1437,7 +1466,7 @@ dofg ldy #p_flags dofg1 tctpgrp (gshtty,gshpid) ldy #p_jobid lda [p],y - getpgrp @a + _getpgrp @a eor #$FFFF inc a kill (@a,#SIGSTOP) @@ -1731,6 +1760,8 @@ done return 2:pid pdata DATA +plistmutex key Mutual exclusion for job list + pwaitsem dc i2'0' pjoblist dc i4'0' ;job list diff --git a/bin/gsh/shell.asm b/bin/gsh/shell.asm index 5ecfe28..7575ea9 100644 --- a/bin/gsh/shell.asm +++ b/bin/gsh/shell.asm @@ -6,7 +6,7 @@ * Jawaid Bazyar * Tim Meekins * -* $Id: shell.asm,v 1.6 1998/09/08 16:53:13 tribby Exp $ +* $Id: shell.asm,v 1.7 1998/10/26 17:04:51 tribby Exp $ * ************************************************************************** * @@ -225,10 +225,10 @@ didit anop pha lda [p] pha - ph2 CmdArgc - pei (p+2) + ph2 CmdArgc argc + pei (p+2) argv pei (p) - pea 0 + pea 0 jobflag = 0 jsl ShellExec jmp done1 @@ -238,9 +238,9 @@ cmdskip lda ExecFlag ; ; The -e flag is set: execute remaining arguments as a command and exit. ; - ph4 ExecCmd - ph2 #0 - jsl Execute + ph4 ExecCmd cmdline + ph2 #0 jobflag = 0 + jsl execute jmp done1 ; @@ -289,8 +289,8 @@ gnoloop entry jsr newlineX jsr flush - ph4 #cmdline - ph2 #0 + ph4 #cmdline execute(cmdline,0) + ph2 #0 jobflag = 0 jsl execute lda exit_requested diff --git a/bin/gsh/stdio.asm b/bin/gsh/stdio.asm index 1217191..1c31e7d 100644 --- a/bin/gsh/stdio.asm +++ b/bin/gsh/stdio.asm @@ -6,7 +6,7 @@ * Jawaid Bazyar * Tim Meekins * -* $Id: stdio.asm,v 1.5 1998/09/08 16:53:14 tribby Exp $ +* $Id: stdio.asm,v 1.6 1998/10/26 17:04:51 tribby Exp $ * ************************************************************************** * @@ -300,8 +300,12 @@ getchar START readloop Read inReadParm bcc okread - ldy #-1 ;return EOF on ALL errors - jmp done2 + ldy #-1 Return EOF if error code + cmp #$4C is "EOF encountered". + beq go_done2 + ora #$FF00 For all other errors, + tay hi-byte is $FF, low-byte is error. +go_done2 jmp done2 okread stz inindex lda insize diff --git a/bin/gsh/term.asm b/bin/gsh/term.asm index c2e0f47..2adf695 100644 --- a/bin/gsh/term.asm +++ b/bin/gsh/term.asm @@ -6,7 +6,7 @@ * Jawaid Bazyar * Tim Meekins * -* $Id: term.asm,v 1.6 1998/09/08 16:53:14 tribby Exp $ +* $Id: term.asm,v 1.7 1998/10/26 17:04:51 tribby Exp $ * ************************************************************************** * @@ -149,8 +149,11 @@ ok jsl nullfree Free buffer allocated by getenv. sta termok mv4 areabuf,area +; +; Get addresses of termcap strings +; tgetstr (#isid,#area) - jsr puts + jsr puts Send initialization string to term. tgetstr (#leid,#area) sta lecap stx lecap+2 @@ -187,7 +190,10 @@ ok jsl nullfree Free buffer allocated by getenv. tgetstr (#usid,#area) sta uscap stx uscap+2 - + +; +; Bind keyboard characters +; tgetstr (#klid,#area) phx pha @@ -223,23 +229,27 @@ ok jsl nullfree Free buffer allocated by getenv. termname gsstr 'term' error1 dc c'Error reading termcap file!',h'0d0d00' error2 dc c'Termcap entry not found for ',h'00' -isid dc c'is',h'00' -leid dc c'le',h'00' -ndid dc c'nd',h'00' -veid dc c've',h'00' -viid dc c'vi',h'00' -vsid dc c'vs',h'00' -blid dc c'bl',h'00' -clid dc c'cl',h'00' -soid dc c'so',h'00' -seid dc c'se',h'00' -klid dc c'kl',h'00' -krid dc c'kr',h'00' -kuid dc c'ku',h'00' -kdid dc c'kd',h'00' -cdid dc c'cd',h'00' -ueid dc c'ue',h'00' -usid dc c'us',h'00' + +; +; Termcap identification strings +; +isid dc c'is',h'00' Initialization +leid dc c'le',h'00' Out of keypad transmit mode +ndid dc c'nd',h'00' Non-destructive space +veid dc c've',h'00' Normal cursor visible +viid dc c'vi',h'00' Cursor unvisible +vsid dc c'vs',h'00' Standout cursor +blid dc c'bl',h'00' Bell +clid dc c'cl',h'00' Clear screen and home cursor +soid dc c'so',h'00' Begin standout mode +seid dc c'se',h'00' End standout mode +cdid dc c'cd',h'00' Clear to end of display +ueid dc c'ue',h'00' End underscore mode +usid dc c'us',h'00' Begin underscore mode +klid dc c'kl',h'00' Left arrow key +krid dc c'kr',h'00' Right arrow key +kuid dc c'ku',h'00' Up key +kdid dc c'kd',h'00' Down key sgtty anop dc i1'0'