gno/bin/gsh/jobs.asm

1722 lines
24 KiB
NASM

************************************************************************
*
* The GNO Shell Project
*
* Developed by:
* Jawaid Bazyar
* Tim Meekins
*
**************************************************************************
*
* JOBS.ASM
* By Tim Meekins
*
* Job control handling routines
*
**************************************************************************
mcopy m/jobs.mac
keep o/jobs
WSTOPPED gequ $7F
SIGINT gequ 2
SIGKILL gequ 9
SIGTERM gequ 15
SIGSTOP gequ 17
SIGTSTP gequ 18
SIGCONT gequ 19
SIGCHLD gequ 20
SIGTTIN gequ 21
SIGTTOU gequ 22
;
; process structure used in job control
;
p_next gequ 0 ;next in global proclist
p_friends gequ p_next+4 ;next in job list
p_flags gequ p_friends+4 ;various job status flags
p_reason gequ p_flags+2 ;reason for entering this state
p_index gequ p_reason+2 ;job index
p_pid gequ p_index+2 ;process id
p_jobid gequ p_pid+2 ;process id of job leader
p_command gequ p_jobid+2 ;command (how job invoked)
p_space gequ p_command+4 ;space for structure
;
; p_flags values
;
PRUNNING gequ %0000000000000001 ;running
PSTOPPED gequ %0000000000000010 ;stopped
PNEXITED gequ %0000000000000100 ;normally exited
PAEXITED gequ %0000000000001000 ;abnormally exited
PSIGNALED gequ %0000000000010000 ;terminated by signal != SIGINT
PNOTIFY gequ %0000000000100000 ;notify async when done
PTIME gequ %0000000001000000 ;job times should be printed
PAWAITED gequ %0000000010000000 ;top level is waiting for it
PFOREGND gequ %0000000100000000 ;started in shells pgrp
PDUMPED gequ %0000001000000000 ;process dumped core
PDIAG gequ %0000010000000000 ;diagnostic output also piped out
PPOU gequ %0000100000000000 ;piped output
PREPORTED gequ %0001000000000000 ;status has been reported
PINTERRUPTED gequ %0010000000000000 ;job stopped via interrupt signal
PPTIME gequ %0100000000000000 ;time individual process
PNEEDNOTE gequ %1000000000000000 ;notify as soon as practicle
;====================================================================
;
; pwait - wait for foreground processes to finish up.
;
;====================================================================
pwait START
using pdata
waitpid equ 1
oldsig equ waitpid+2
p equ oldsig+4
space equ p+4
end equ space+3
; subroutine (0:dummy),space
tsc
sec
sbc #space-1
tcs
phd
tcd
getpid
sta waitpid
waitloop ldx #%0000000000001010
lda #%0100000000000000
sigblock @xa
sta oldsig
stx oldsig+2
lda pjoblist
ldx pjoblist+2
loop sta p
stx p+2
ora p+2
beq done
ldy #p_flags
lda [p],y
and #PFOREGND+PRUNNING
cmp #PFOREGND+PRUNNING
bne loop2
ldy #p_pid
lda [p],y
cmp waitpid
beq loop2
; 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
lda [p],y
tax
ldy #p_next
lda [p],y
bra loop
done sigsetmask oldsig
pld
tsc
clc
adc #end-4
tcs
rtl
END
;====================================================================
;
; jobkiller - kills all jobs
;
;====================================================================
jobkiller START
using pdata
p equ 0
space equ p+4
subroutine (0:dummy),space
loop lda pjoblist
beq done
ldx pjoblist+2
beq done
sta p
stx p+2
ldy #p_pid
lda [p],y
kill (@a,#SIGKILL)
bra loop
done return
END
;====================================================================
;
; palloc - allocate a process structure and fill it up
;
;====================================================================
palloc START
using pdata
using global
pp equ 1
space equ pp+4
cmd equ space+3
bg equ cmd+4
pid equ bg+2
end equ pid+2
; subroutine (2:pid,2:bg,4:cmd),space
tsc
sec
sbc #space-1
tcs
phd
tcd
ldx #%0000000000001000
lda #%0000000000000000
sigblock @xa
phx
pha
ph4 #p_space
jsl ~NEW
sta pp
stx pp+2
ldy #p_pid ;set pid
lda pid
sta [pp],y
ldy #p_jobid
sta [pp],y
lda bg ;set running flags
bne bg00
lda #PRUNNING+PFOREGND
bra bg01
bg00 lda #PRUNNING
bg01 ldy #p_flags
sta [pp],y
ldy #p_next
lda pjoblist
sta [pp],y
ldy #p_next+2
lda pjoblist+2
sta [pp],y
ldx pp+2
ldy pp
stx pjoblist+2
sty pjoblist
lda pcurrent
ora pcurrent+2
bne in01
stx pcurrent+2
sty pcurrent
bra in02
in01 lda pprevious
ora pprevious+2
bne in02
stx pprevious+2
sty pprevious
in02 anop
ldy #p_friends
lda #0
sta [pp],y
ldy #p_friends+2
sta [pp],y
inc pmaxindex ;set job number
ldy #p_index
lda pmaxindex
sta [pp],y
pei (cmd+2)
pei (cmd)
jsr cstrlen
inc a
pea 0
pha
jsl ~NEW
pei (cmd+2)
pei (cmd)
phx
pha
ldy #p_command ;set command
sta [pp],y
txa
ldy #p_command+2
sta [pp],y
jsr copycstr
lda bg
beq noprint
pei (pp+2)
pei (pp)
pea 1
pea 0
jsl pprint
noprint anop
case on
jsl sigsetmask
case off
lda space
sta end-3
lda space+1
sta end-2
pld
tsc
clc
adc #end-4
tcs
rtl
END
;====================================================================
;
; pallocpipe - allocate a process structure and fill it up and append
; to previous command pipeline.
;
;====================================================================
pallocpipe START
using pdata
using global
p equ 1
pp equ p+4
space equ pp+4
cmd equ space+3
bg equ cmd+4
pid equ bg+2
end equ pid+2
; subroutine (2:pid,2:bg,4:cmd),space
tsc
sec
sbc #space-1
tcs
phd
tcd
ldx #%0000000000001000
lda #%0000000000000000
sigblock @xa
phx
pha
ph4 #p_space
jsl ~NEW
sta pp
stx pp+2
ldy #p_pid ;set pid
lda pid
sta [pp],y
ldy #p_jobid
sta [pp],y
lda bg ;set running flags
bne bg00
lda #PRUNNING+PFOREGND
bra bg01
bg00 lda #PRUNNING
bg01 ldy #p_flags
sta [pp],y
ldy #p_next
lda #0
sta [pp],y
ldy #p_next+2
sta [pp],y
ldy #p_friends
sta [pp],y
ldy #p_friends+2
sta [pp],y
pei (cmd+2)
pei (cmd)
jsr cstrlen
inc a
pea 0
pha
jsl ~NEW
pei (cmd+2)
pei (cmd)
phx
pha
ldy #p_command ;set command
sta [pp],y
txa
ldy #p_command+2
sta [pp],y
jsr copycstr
;
; update the current pipeline to know about the last pipe.
;
lda pjoblist
ldx pjoblist+2
loop sta p
stx p+2
ldy #p_flags
lda [pp],y
sta [p],y
ldy #p_jobid
lda [pp],y
sta [p],y
ldy #p_friends
lda [p],y
ldy #p_friends+2
ora [p],y
beq addit
lda [p],y
tax
ldy #p_friends
lda [p],y
bra loop
addit ldy #p_friends
lda pp
sta [p],y
ldy #p_friends+2
lda pp+2
sta [p],y
case on
jsl sigsetmask
case off
lda space
sta end-3
lda space+1
sta end-2
pld
tsc
clc
adc #end-4
tcs
rtl
END
;====================================================================
;
; handle a SIGCHLD signal
;
;====================================================================
pchild START
using pdata
using global
waitstatus equ 1
pid equ waitstatus+4 ;just in case
p equ pid+2
space equ p+4
signum equ space+3
code equ signum+2
end equ code+2
; subroutine (2:code,2:signum),space
tsc
sec
sbc #space-1
tcs
phd
tcd
phb
phk
plb
stz signum
;
; get status for the process that just died
;
ldx #0
clc
tdc
adc #waitstatus
wait @xa
sta pid
;
; search for the job that has finished.
;
search lda pjoblist
ldx pjoblist+2
lookloop sta p
stx p+2
ora p+2
jeq done
ldy #p_jobid
lda [p],y
cmp pid
beq lookfound
ldy #p_next+2
lda [p],y
tax
ldy #p_next
lda [p],y
bra lookloop
;
; see how wait was signaled.
;
lookfound anop
lda waitstatus
and #$FF
cmp #WSTOPPED
jne kill
lda waitstatus
xba
and #$FF ;<- signal number
sta signum
cmp #SIGTSTP
beq stop
cmp #SIGTERM
jeq zap
cmp #SIGINT
beq zap
cmp #SIGSTOP
beq stop
cmp #SIGTTIN
beq stop
cmp #SIGTTOU
bne zap
stop ldy #p_flags
lda [p],y
eor #PRUNNING
ora #PSTOPPED
sta [p],y
pei (p+2)
pei (p)
jsr mkjobcur
ldy #p_flags
lda [p],y
bit #PFOREGND
beq stop2
tctpgrp (gshtty,gshpid)
stop2 pei (p+2)
pei (p)
pea 0
pei (signum)
jsl pprint
bra done
kill ldy #p_flags
lda [p],y
bit #PFOREGND ;only set status variable if in
beq zap0 ; foreground
lda waitstatus
jsr setstatus
bra zap
zap0 inc signalled
zap ldy #p_index
lda [p],y
pha
jsl removejob
ldy #p_flags
lda [p],y
bit #PFOREGND
beq done
tctpgrp (gshtty,gshpid)
done anop
plb
lda space
sta end-3
lda space+1
sta end-2
pld
tsc
clc
adc #end-4
tcs
rtl
;
; set status return variable
;
setstatus ENTRY
xba
and #$FF
cmp #100
bcc set1
Int2Dec (@a,#valstat1+1,#3,#0)
lda #valstat1
ldx #^valstat1
bra set0
set1 cmp #10
bcc set2
Int2Dec (@a,#valstat2+1,#2,#0)
lda #valstat2
ldx #^valstat2
bra set0
set2 Int2Dec (@a,#valstat3+1,#1,#0)
lda #valstat3
ldx #^valstat3
set0 sta SetParm+4
stx SetParm+6
Set_Variable SetParm
rts
SetParm dc a4'name'
ds 4
name str 'status'
valstat1 str '000'
valstat2 str '00'
valstat3 str '0'
END
;====================================================================
;
; remove a job
;
;====================================================================
removejob START
using pdata
p equ 1
prev equ p+4
space equ prev+4
jobnum equ space+3
end equ jobnum+2
; subroutine (2:jobnum),space
tsc
sec
sbc #space-1
tcs
phd
tcd
stz prev
stz prev+2
lda pjoblist
ldx pjoblist+2
loop sta p
stx p+2
ora p+2
jeq done
ldy #p_index
lda [p],y
cmp jobnum
beq gotit
lda p
sta prev
stx prev+2
ldy #p_next+2
lda [p],y
tax
ldy #p_next
lda [p],y
bra loop
;
; adjust linked list pointers
;
gotit ora2 prev,prev+2,@a
beq gotit2
ldy #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
sta pjoblist
ldy #p_next+2
lda [p],y
sta pjoblist+2
;
; free the node (may want to check currjob and prevjob pointers)
;
gotit3 anop
ldy #p_flags
lda [p],y
and #PFOREGND
bne gotit3c
jsr newline
ldy #p_flags
lda #0
sta [p],y
pei (p+2)
pei (p)
pea 0
pea 0
jsl pprint
gotit3c anop
ldy #p_command+2
lda [p],y
pha
dey2
lda [p],y
pha
jsl nullfree
lda pcurrent
eor pcurrent+2
eor p
eor p+2
bne gotit3a
mv4 pprevious,pcurrent
stz pprevious
stz pprevious+2
lda prev
eor prev+2
eor pcurrent
eor pcurrent+2
beq gotit3a
mv4 prev,pprevious
gotit3a lda pprevious
eor pprevious+2
eor p
eor p+2
bne gotit3b
stz pprevious
stz pprevious+2
gotit3b anop
gotit4 ldy #p_friends
lda [p],y
pha
ldy #p_friends+2
lda [p],y
pha
pei (p+2)
pei (p)
jsl nullfree
pla
sta P+2
pla
sta p
ora p+2
beq gotit5
ldy #p_command+2
lda [p],y
pha
ldy #p_command
lda [p],y
pha
jsl nullfree
bra gotit4
gotit5 anop
;
; find maximum job number
;
stz prev
lda pjoblist
ldx pjoblist+2
fmaxloop sta p
stx p+2
ora p+2
beq gotmax
ldy #p_index
lda [p],y
cmp prev
bcc skipmax
sta prev
skipmax ldy #p_next+2
lda [p],y
tax
ldy #p_next
lda [p],y
bra fmaxloop
gotmax mv2 prev,pmaxindex
done anop
lda space+1
sta end-2
lda space
sta end-3
pld
tsc
clc
adc #end-4
tcs
rtl
END
;====================================================================
;
; mkjobcur
;
;====================================================================
mkjobcur START
using pdata
space equ 1
p equ space+2
end equ p+4
; subroutine (4:p),space
lda p,s
eor p+2,s
eor pcurrent
eor pcurrent+2
beq done
mv4 pcurrent,pprevious
lda p,s
sta pcurrent
lda p+2,s
sta pcurrent+2
done lda space,s
sta end-2,s
tsc
clc
adc #end-3
tcs
rts
END
**************************************************************************
*
* JOBS: builtin command
* syntax: exit
*
* displays jobs
*
**************************************************************************
jobs START
using pdata
pidflag equ 0
pp equ pidflag+2
count equ pp+4
space equ count+2
subroutine (4:argv,2:argc),space
stz pidflag
lda argc
dec a
beq cont
dec a
beq grab
shit ldx #^Usage
lda #Usage
jsr errputs
jmp done
grab ldy #4
lda [argv],y
sta pp
ldy #4+2
lda [argv],y
sta pp+2
lda [pp]
and #$FF
if2 @a,ne,#'-',shit
ldy #1
lda [pp],y
if2 @a,ne,#'l',shit
inc pidflag
cont ld2 1,count
loop lda pjoblist
ldx pjoblist+2
loop2 sta pp
stx pp+2
ora pp+2
beq next
ldy #p_index
lda [pp],y
cmp count
beq gotit
ldy #p_next+2
lda [pp],y
tax
ldy #p_next
lda [pp],y
bra loop2
gotit pei (pp+2)
pei (pp)
pei (pidflag)
pea 0
jsl pprint
next inc count
lda count
cmp pmaxindex
beq loop
bcc loop
done return
Usage dc c'Usage: jobs [-l]',h'0d00'
END
**************************************************************************
*
* KILL: builtin command
* syntax: kill [-sig] [pid ...]
*
* sends a [kill] signal to a process
*
**************************************************************************
kill START
ptr equ 1
arg equ ptr+4
signum equ arg+4
pid equ signum+2
space equ pid+2
argc equ space+3
argv equ argc+2
end equ argv+4
; subroutine (4:argv,2:argc),space
tsc
sec
sbc #space-1
tcs
phd
tcd
lda argc
dec a
bne init
ldx #^Usage
lda #Usage
jsr errputs
jmp done
init stz pid
ld2 SIGTERM,signum
dec argc
jeq dokill
add2 argv,#4,argv
ldy #2
lda [argv]
sta arg
lda [argv],y
sta arg+2
lda [arg]
and #$FF
cmp #'-'
jne getpid
inc arg
lda [arg]
and #$FF
cmp #'0'
bcc getname
cmp #'9'+1
bcs getname
pei (arg+2)
pei (arg)
jsr cstrlen
tax
Dec2Int (arg,@x,#0),signum
lda signum ;yeah, yeah, I know...
bmi ohshitnum
cmp #1
bcc ohshitnum
cmp #25
bcc next
cmp #30
beq next
cmp #31
beq next
ohshitnum ldx #^err1
lda #err1
jsr errputs
jmp done
getname lda [arg]
cmp #'l'
beq lister
pei (arg+2)
pei (arg)
jsr lowercstr
ld2 1,signum
ld4 names,ptr
nameloop pei (arg+2)
pei (arg)
pei (ptr+2)
pei (ptr)
jsr cmpcstr
cmp #0
beq next
inc signum
add2 ptr,#8,ptr
lda signum
cmp #32
bcc nameloop
ldx #^err3
lda #err3
jsr errputs
bra done
next dec argc
jeq dokill
add2 argv,#4,argv
ldy #2
lda [argv]
sta arg
lda [argv],y
sta arg+2
getpid pei (arg+2)
pei (arg)
jsl parsepid
sta pid
cmp #0
beq killnull
cmp #-1
bne dokill
ldx #^err2
lda #err2
jsr errputs
bra done
lister ldx #^liststr
lda #liststr
jsr puts
bra done
killnull ldx #^err4
lda #err4
jsr errputs
bra done
dokill kill (pid,signum)
cmp #0
beq done
ldx #^err2
lda #err2
jsr errputs
done lda space
sta end-3
lda space+1
sta end-2
pld
tsc
clc
adc #end-4
tcs
lda #0
rtl
Usage dc c'Usage: kill [-signum | -signame] [pid | %jobid] ...',h'0d00'
err1 dc c'kill: Invalid signal number.',h'0d00'
err2 dc c'kill: No such job or pid.',h'0d00'
err3 dc c'kill: Invalid signal name.',h'0d00'
err4 dc c'kill: Killing the kernel null process isn''t such a good idea.',h'0d00'
liststr dc c'sighup sigint sigquit sigill sigtrap sigabrt sigemt '
dc c'sigfpe sigkill sigbus sigsegv sigsys sigpipe sigalrm '
dc c'sigterm sigurg sigstop sigtstp sigcont sigchld sigttin '
dc c'sigttou sigio sigxcpu sigusr1 sigusr2',h'0d00'
names dc c'sighup',h'0000' ;1
dc c'sigint',h'0000' ;2
dc c'sigquit',h'00' ;3
dc c'sigill',h'0000' ;4
dc c'sigtrap',h'00' ;5
dc c'sigabrt',h'00' ;6
dc c'sigemt',h'0000' ;7
dc c'sigfpe',h'0000' ;8
dc c'sigkill',h'00' ;9
dc c'sigbus',h'0000' ;10
dc c'sigsegv',h'00' ;11
dc c'sigsys',h'0000' ;12
dc c'sigpipe',h'00' ;13
dc c'sigalrm',h'00' ;14
dc c'sigterm',h'00' ;15
dc c'sigurg',h'0000' ;16
dc c'sigstop',h'00' ;17
dc c'sigtstp',h'00' ;18
dc c'sigcont',h'00' ;19
dc c'sigchld',h'00' ;20
dc c'sigttin',h'00' ;21
dc c'sigttou',h'00' ;22
dc c'sigio',h'000000' ;23
dc c'sigxcpu',h'00' ;24
dc h'0000000000000000' ;25
dc h'0000000000000000' ;26
dc h'0000000000000000' ;27
dc h'0000000000000000' ;28
dc h'0000000000000000' ;29
dc c'sigusr1',h'00' ;30
dc c'sigusr2',h'00' ;31
END
**************************************************************************
*
* FG: builtin command
*
**************************************************************************
fg START
using pdata
using global
pid equ 0
p equ pid+2
space equ p+4
subroutine (4:argv,2:argc),space
lda argc
dec a
bne getit
ora2 pjoblist,pjoblist+2,@a
jeq whoashit
mv4 pjoblist,p
bra dofg
getit dec a
beq getit2
ldx #^usage
lda #usage
jmp puterr
getit2 ldy #4+2
lda [argv],y
pha
ldy #4
lda [argv],y
pha
jsl parsepid
sta pid
cmp #-1
jeq nojob
mv4 pjoblist,p
loop ora2 p,p+2,@a
jeq nojob
ldy #p_jobid
lda [p],y
cmp pid
beq dofg
ldy #p_next
lda [p],y
tax
ldy #p_next+2
lda [p],y
sta p+2
stx p
bra loop
dofg ldy #p_flags
lda [p],y
and #PFOREGND+PRUNNING
cmp #PFOREGND+PRUNNING
bne dofg1
ldx #^err02
lda #^err01
bra puterr
dofg1 lda [p],y
ora #PRUNNING+PFOREGND
sta [p],y
ldy #p_jobid
lda [p],y
tax
tctpgrp (gshtty,@x)
ldy #p_flags
lda [p],y
bit #PSTOPPED
beq dofg2
; lda [p],y
eor #PSTOPPED
sta [p],y
pei (p+2)
pei (p)
pea 0
pea 0
jsl pprint
ldy #p_jobid
lda [p],y
getpgrp @a
eor #$FFFF
inc a
kill (@a,#SIGCONT)
bra dofg3
dofg2 pei (p+2)
pei (p)
pea 0
pea 0
jsl pprint
dofg3 jsl pwait
bra done
whoashit ldx #^err01
lda #err01
bra puterr
nojob ldx #^err03
lda #err03
puterr jsr errputs
done return
usage dc c'Usage: fg [%job | pid]',h'0d00'
err01 dc c'fg: No job to foreground.',h'0d00'
err02 dc c'fg: Gee, this job is already in the foreground.',h'0d00'
err03 dc c'fg: No such job.',h'0d00'
END
**************************************************************************
*
* BG: builtin command
*
**************************************************************************
bg START
using pdata
using global
pid equ 0
p equ pid+2
space equ p+4
subroutine (4:argv,2:argc),space
lda argc
dec a
bne getit
ora2 pjoblist,pjoblist+2,@a
jeq whoashit
mv4 pjoblist,p
bra dofg
getit dec a
beq getit2
ldx #^usage
lda #usage
jmp puterr
getit2 ldy #4+2
lda [argv],y
pha
ldy #4
lda [argv],y
pha
jsl parsepid
sta pid
cmp #-1
jeq nojob
mv4 pjoblist,p
loop ora2 p,p+2,@a
jeq nojob
ldy #p_jobid
lda [p],y
cmp pid
beq dofg
ldy #p_next
lda [p],y
tax
ldy #p_next+2
lda [p],y
sta p+2
stx p
bra loop
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
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)
pei (p+2)
pei (p)
pea 0
pea 0
jsl pprint
ldy #p_jobid
lda [p],y
getpgrp @a
eor #$FFFF
inc a
kill (@a,#SIGCONT)
bra dofg3
dofg2 pei (p+2)
pei (p)
pea 0
pea 0
jsl pprint
dofg3 bra done
whoashit ldx #^err01
lda #err01
bra puterr
nojob ldx #^err03
lda #err03
puterr jsr errputs
done return
usage dc c'Usage: bg [%job | pid]',h'0d00'
err01 dc c'bg: No job to background.',h'0d00'
err02 dc c'bg: Gee, this job is already in the background.',h'0d00'
err03 dc c'bg: No such job.',h'0d00'
END
**************************************************************************
*
* STOP: builtin command
*
**************************************************************************
stop START
using pdata
using global
pid equ 0
p equ pid+2
space equ p+4
subroutine (4:argv,2:argc),space
lda argc
dec a
bne getit
ora2 pjoblist,pjoblist+2,@a
jeq whoashit
mv4 pjoblist,p
bra dofg
getit dec a
beq getit2
ldx #^usage
lda #usage
jmp puterr
getit2 ldy #4+2
lda [argv],y
pha
ldy #4
lda [argv],y
pha
jsl parsepid
sta pid
cmp #-1
jeq nojob
mv4 pjoblist,p
loop ora2 p,p+2,@a
jeq nojob
ldy #p_jobid
lda [p],y
cmp pid
beq dofg
ldy #p_next
lda [p],y
tax
ldy #p_next+2
lda [p],y
sta p+2
stx p
bra loop
dofg ldy #p_flags
lda [p],y
and #PSTOPPED
beq dofg1
ldx #^err02
lda #err02
bra puterr
dofg1 tctpgrp (gshtty,gshpid)
ldy #p_jobid
lda [p],y
getpgrp @a
eor #$FFFF
inc a
kill (@a,#SIGSTOP)
bra done
whoashit ldx #^err01
lda #err01
bra puterr
nojob ldx #^err03
lda #err03
puterr jsr errputs
done return
usage dc c'Usage: stop [%job | pid]',h'0d00'
err01 dc c'stop: No job to stop.',h'0d00'
err02 dc c'stop: Gee, this job is already stopped.',h'0d00'
err03 dc c'stop: No such job.',h'0d00'
END
;====================================================================
;
; print job
;
;====================================================================
pprint START
using pdata
p equ 0
count equ p+4
space equ count+2
subroutine (4:pp,2:idflag,2:signum),space
stz count
;
; display job number
;
lda #'['
jsr putchar
ldy #p_index
lda [pp],y
cmp #10
bcs id10
adc #'0'
jsr putchar
lda #']'
jsr putchar
lda #' '
jsr putchar
bra ida
id10 Int2Dec (@a,#dec10,#2,#0)
ldx #^dec10
lda #dec10
jsr puts
ida lda #' '
jsr putchar
;
; display '+' or '-'
;
if2 pp,ne,pcurrent,pcur1
if2 pp+2,ne,pcurrent+2,pcur1
lda #'+'
bra pcur3
pcur1 if2 pp,ne,pprevious,pcur2
if2 pp+2,ne,pprevious+2,pcur2
lda #'-'
bra pcur3
pcur2 lda #' '
pcur3 jsr putchar
lda #' '
jsr putchar
;
; display process id
;
lda idflag
beq stat
ldy #p_jobid
lda [pp],y
Int2Dec (@a,#pidstr,#5,#0)
ldx #^pidstr
lda #pidstr
jsr puts
ld2 6,count
;
; status
;
stat ldy #p_flags
lda [pp],y
bit #PRUNNING
beq stat2
ldx #^statrun
lda #statrun
bra stat0
stat2 bit #PSTOPPED
beq stat3
ldx #^statstop
lda #statstop
bra stat0
stat3 ldx #^statohshit
lda #statohshit
stat0 jsr puts
;
; show signal
;
lda signum
beq sig0
if2 @a,ne,#SIGTTIN,sig2
ldx #^sigttinstr
lda #sigttinstr
bra sig1
sig2 if2 @a,ne,#SIGTTOU,sig3
ldx #^sigttoustr
lda #sigttoustr
bra sig1
sig3 ldx #^sigotherstr
lda #sigotherstr
sig1 phx
pha
jsr puts
jsr cstrlen
clc
adc count
sta count
sig0 anop
;
; display command
;
showcmd ldy #p_command
lda [pp],y
sta p
ldy #p_command+2
lda [pp],y
sta p+2
ldy #0
chloop lda [p],y
and #$FF
beq next
phy
jsr putchar
ply
iny
inc count
if2 count,cc,#60,chloop
showell ldx #^ellipsis
lda #ellipsis
jsr puts
bra cmd01
next ldy #p_friends
lda [pp],y
pha
ldy #p_friends+2
lda [pp],y
ora 1,s
beq donename
lda [pp],y
sta pp+2
plx
stx pp
if2 count,cs,#57,showell
clc
adc #3
sta count
ldx #^pipestr
lda #pipestr
jsr puts
bra showcmd
donename pla
ldy #p_flags
lda [pp],y
and #PFOREGND
bne cmd01
ldx #^ampstr
lda #ampstr
jsr puts
cmd01 anop
jsr newline
return
dec10 dc c'00]',h'00'
pidstr dc c'00000 ',h'00'
statrun dc c'Running ',h'00'
statstop dc c'Stopped ',h'00'
statohshit dc c'Done ',h'00'
ampstr dc c' &',h'00'
ellipsis dc c'...',h'00'
pipestr dc c' | ',h'00'
sigttinstr dc c'(tty input) ',h'00'
sigttoustr dc c'(tty output) ',h'00'
sigotherstr dc c'(signal) ',h'00'
END
;====================================================================
;
; parse process id (if starts with '%', then parse job num and
; concert to process id).
;
;====================================================================
parsepid START
using pdata
p equ 0
len equ p+4
pid equ len+2
space equ pid+2
subroutine (4:str),space
pei (str+2)
pei (str)
jsr cstrlen
sta len
lda [str]
and #$FF
cmp #'%'
beq dojob
cmp #'0'
jcc nojob
cmp #'9'+1
jcs nojob
Dec2Int (str,len,#0),pid
jmp done
dojob ldy #1
lda [str],y
and #$FF
beq docurjob
if2 @a,eq,#'+',docurjob
if2 @a,eq,#'%',docurjob
if2 @a,ne,#'-',dojobnum
lda pprevious
ldx pprevious+2
bra gotjob
docurjob lda pcurrent
ldx pcurrent+2
bra gotjob
dojobnum ldy len
dey
ldx str+2
lda str
inc a
Dec2Int (@xa,@y,#0),pid
lda pjoblist
ldx pjoblist+2
sta p
stx p+2
loop ora2 p,p+2,@a
beq nojob
ldy #p_index
lda [p],y
cmp pid
beq gotjob2
ldy #p_next
lda [p],y
tax
ldy #p_next+2
lda [p],y
sta p+2
stx p
bra loop
gotjob sta p
stx p+2
gotjob2 ora2 p,p+2,@a
beq nojob
ldy #p_jobid
lda [p],y
sta pid
bra done
nojob ld2 -1,pid
done return 2:pid
END
;====================================================================
;
; process data
;
;====================================================================
pdata DATA
pwaitsem dc i2'0'
pjoblist dc i4'0' ;job list
pcurrent dc i4'0' ;current job in table
pprevious dc i4'0' ;previous job in table
pmaxindex dc i2'0' ;current maximum job index
END