ZJOB ;ISF/RWF - GT.M Job Exam ;8/15/07  16:28
 ;;8.0;KERNEL;**349**;Jul 10, 1995;Build 2
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ; Various edits between Wally, Dave Whitten, Bhaskar,           ;
 ; and Chris Richardson over a period of time.                   ;
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;
 ;PID is decimal job number.
 I $ZV'["GT.M" W !,"This is for GT.M only" Q
 N PID,HEXPID,DTIME
 S DTIME=600
RPID ; Request the PID
 F  D   Q:"^"[PID
 . S PID=$$ASKJOB
 . D:PID>0
 . . N ACTION
 . . S ACTION="L"
 . . D DOIT
 . . F  D ASK Q:ACTION="^"  D DOIT Q:ACTION="^"
 . .Q
 .Q
 ; Single Exit
 W !!
 Q
 ;
ASK ; Ask for user input
 R !,"Job Exam Action: L//",ACTION:DTIME
 S:'$T ACTION="^"
 S:ACTION="" ACTION="L"
 I ACTION["^" Q  ;Exit
 ;
 ;first non-space, UPPER character
 S ACTION=$TR($E($TR(ACTION," ")),"klsv","KLSV")
 Q
 ;
DOIT ; Action Prompt
 I ACTION="S" D ^ZSY  S ACTION="L" ;FALLTHRU
 I ACTION="L"!(ACTION="V") D DISPLAY(PID,ACTION) Q
 I ACTION="*" D LOAD^ZJOB1 S ACTION="^" Q
 I ACTION="K" W !,"Sorry Kill Job not supported yet" Q  ;G ACTION
 ; All Else
 W:ACTION'="?" !,"Unknown Action received"
 ;ACTION["?"
 W !,"Enter '^' to choose another JOB "
 W !,"Enter 'L' to display status information about other Job"
 W !,"Enter 'S' to display current System Status"
 W !,"Enter 'V' to display local variables of other job"
 W !,"Enter '*' to load other job's symbol table into current job and Q"
 W !,"Enter 'K' to send a Kill Job command to other job"
 Q
 ;
ASKJOB() ;Ask for Job PID/Commands
 N PID
 W !!,"Examine Another JOB Utility "
 F   S PID=$$RDJNUM  Q:PID="^"  Q:PID=+PID
 Q PID
 ;
RDJNUM() ;
 N INP,PID
 S INP=""
 R !,"Enter JOB number: ",INP:DTIME S:'$T INP="^"
 S INP=$TR(INP,"hlsv","HLSV")
 I "^"[INP Q "^"  ;abend
 ;
 I INP["?" D  Q " "
 . W !,"To display information about another Job"
 . W !,"   enter JOB number in Hexidecimal or Decimal"
 . W !,"   Enter Hexadecimal with a leading/trailing 'h' "
 . W !,"To display current System Status enter S"
 . W !,"To exit enter ^"
 .Q
 I INP["S" D ^ZSY Q " " ;
 ;
 ; good hex or decimal number
 S PID=$TR(INP,"abcdefh","ABCDEFH")
 I $L($TR(PID,"0123456789ABCDEFH","")) D  Q " "
 . W !,"Invalid character in JOB number."
 .Q
 ;
 ;If in Hex, Convert PID to decimal
 I PID["H" S PID=$$DEC($TR(PID,"H")) ; ...and continue
 ; good job number but it is your own job.  Don't go there...
 I PID=$JOB D  Q " "
 . W !,"Can't EXAMINE your own process."
 .Q
 ;
 ; VA check to see if a GTM job exists.
 I $L($T(XUSCNT)),'$$CHECK^XUSCNT(PID) W !,"Not running thru VA kernel." ;decimal job
 ;
 ;W !,"JOB #",PID," does not exist"
 ;Q " " ; bad job number so re-ask
 Q PID
 ;
INTRPT(JOB) ;Send MUPIP intrpt
 N $ET,$ES S $ET="D IRTERR^ZJOB"
 ; shouldn't interrupt ourself
 I JOB=$JOB Q 0
 ;We need a LOCK to guarantee commands from two processes don't conflict
 N X,OLDINTRPT,TMP,ZSYSCMD,ZPATH,%J
 L +^XUTL("XUSYS","COMMAND"):10 Q:'$T 0
 ;
 S ^XUTL("XUSYS","COMMAND")="EXAM",^("COMMAND",0)=$J_":"_$H
 K ^XUTL("XUSYS",JOB,"JE")
 S OLDINTRP=$ZINTERRUPT,%J=$J
 S TMP=0,$ZINTERRUPT="S TMP=1"
 ;
 I $ZV["VMS" S JOB=$$HEX(JOB),%J=$$HEX(%J)
 S ZSYSCMD="mupip intrpt "_JOB ; interrupt other job
 I $ZV["VMS" S ZPATH="@gtm$dist:"  ; VMS path
 ;E  S ZPATH="sudo $gtm_dist" ;$ztrnlnm("gtm_dist") ;Unix path
 E  S ZPATH="$gtm_dist/" ;Unix path
 W !,"Send intrp to job. Any error means you don't have the privilege to intrpt.",!
 ZSYSTEM ZPATH_ZSYSCMD ; System Request
 ;Now send to self
 ;
 ;ZSYSTEM ZPATH_"mupip intrpt "_%J
 ; wait is too long 60>>30
 H 1 S TMP=1
 ; wait for interrupt, will set TMP=1
 ;F X=1:1:30 H 1 Q:TMP=1  ;ZINTERRUPT does not stop a HANG
 ; Restore old $ZINTERRPT
 S $ZINTERRUPT=OLDINTRP
 K ^XUTL("XUSYS","COMMAND") ;Cleanup
 L -^XUTL("XUSYS","COMMAND")
 Q TMP  ;Report if we received interrupt
 ;
ITRERR ;Handle error during Interrupt
 U $P W !,"Error: ",$ES
 S $ET="Q:($ES&$Q) 0 Q:$ES  S $EC="""" Q 0"
 Q
 ;
DISPLAY(JOB,ACTION) ;Display Job info, L is always the default.  No need to test for it.
 ; The "L" header is part of the "V" Option
 ;Send the interupt
 I '$$INTRPT(JOB) W !,"Unable to Examine JOB, please retry later" Q
 D DISPL ;Show Header
 I ACTION="V" D DISPV ;Show symbol table
 Q
 ;
DISPL ; ACTION="L" means single page info
 ; Show short job info
 ; Current Routine and Line Number  ;Current Line Executing
 D GETINFO
 S HEXJOB="" I $ZV["VMS" S HEXJOB=$$HEX(JOB)
 W !,"JOB #: "_JOB W:$L(HEXJOB) " ("_HEXJOB_")" W ?40,"Process Name: "_$G(^XUTL("XUSYS",JOB,"NM"))
 W !,"Device: "_$P($G(^XUTL("XUSYS",JOB,"JE","D",1))," ")
 W !,"Process State: "_PS W:$L(IMAGE) ?40,"IMAGE: "_IMAGE_" ("_INAME_")"
 W !,"JOB Type: "_JTYPE,?25,"CPU Time: "_CTIME,?50,"Login time: "_LTIME
 W !!,"Routine line: <"_$G(^XUTL("XUSYS",JOB,"INTERRUPT"))_">"
 W !,CODELINE
 Q
 ;
 ; No Symbol Residue from this module.  The following are ephemeral
 ; S - Information Type
 ; I - Variable
DISPV ; ACTION="V"  ; lookup how XTER is doing variable handling...
 ; print $ZGBLDIR and $ZROUTINES
 N C,I,S
 F S="Stack","Locks","Devices","Intrinsic Variables","Variables"    D
 . S C=$E(S),I=""
 . D:$D(^XUTL("XUSYS",JOB,"JE",C))  W !
 . . W !,"Section "_S
 . . F  S I=$O(^XUTL("XUSYS",JOB,"JE",C,I)) Q:I=""  W !,^(I)
 . . Q
 . Q
 Q
 ;  ==============
GETINFO ; Identify the Target Process's state.
 ; Setup, process state > ps, Image name > iname, CPU time > ctime, Login time > ltime
 S (PS,INAME,CTIME,LTIME,JTYPE,IMAGE,CODELINE)=""
 S CODELINE=$G(^XUTL("XUSYS",JOB,"codeline"))
 I $zv["VMS" D VSTATE  Q
 ; Assume Unix as default
 D USTATE
 Q
 ;
VSTATE ; VMS get Process state
 S TNAME=$ZGETJPI(JOB,"TERMINAL"),NM=$ZGETJPI(JOB,"prcnam")
 S JTYPE=$ZGETJPI(JOB,"jobtype"),PS=$ZGETJPI(JOB,"state")
 S LTIME=$$DATETIME($ZGETJPI(PID,"LOGINTIM")),CTIME=$$CPUTIME($ZGETJPI(JOB,"cputim"))
 Q
 ;
DATETIME(HOROLOG) ;
 Q $ZDATE(HOROLOG,"DD-MON-YY 24:60:SS","Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec")
 ;
CPUTIME(S) ; Calculate the VMS CPU time from first argument, S
 N T,SS,M,H,D
 S T=S#100,S=S\100 S:$L(T)=1 T="0"_T
 S SS=S#60,S=S\60 S:$L(SS)=1 SS="0"_SS
 S M=S#60,S=S\60 S:$L(M)=1 M="0"_M
 S H=S#24,D=S\24 S:$L(H)=1 H="0"_H
 Q D_" "_H_":"_M_":"_SS_"."_T
 ;
BLINDPID ;
 N ZE S ZE=$ZS,$EC=""
 I ZE["NOPRIV" S NOPRIV=1
 Q
 ; MAY BE REDUNDANT OR WRONG
USTATE ;UNIX Process state.
 N %FILE,%TEXT,U,%J,ZCMD,$ET,$ES
 S $ET="D UERR^ZJOB",STATE="",U="^"
 S %FILE="/tmp/_gtm_sy_"_$J_".tmp"
 ;S ZCMD="ps ef -C mumps >"_%FILE ;| grep "_JOB_">"_%FILE
 S ZCMD="ps eo pid,tty,stat,time,etime,cmd -C mumps >"_%FILE ;| grep "_JOB_">"_%FILE
 ;W !,ZCMD
 ZSYSTEM ZCMD
 O %FILE:(readonly)
 ; Get only line of text from temp file
 U %FILE
 F EXIT=0:0 R %TEXT Q:%TEXT=""  D  Q:EXIT
 . Q:+%TEXT'=JOB
 . S %TEXT=$$VPE(%TEXT," ",U) ; parse each line of the ps output
 . S TNAME=$P(%TEXT,U,2),PS=$P(%TEXT,U,3),CTIME=$P(%TEXT,U,4),LTIME=$P(%TEXT,U,5),JTYPE=$P(%TEXT,U,7)
 . S EXIT=1
 .Q
 ;
 U $P C %FILE:DELETE
 S PS=$S(PS="S":"hib",PS="D":"lef",PS="R":"run",1:PS)
 Q
 ;  ================
UERR ;Error
 S $EC=""
 U $P W !,"Error: "_$ZS
 Q:$Q -9
 Q
 ;
HEX(D) ;Decimal to Hex
 Q $$FUNC^%DH(D,8)
DEC(H) ;Hex to Decimal
 Q $$FUNC^%HD(H)
 ;
VPE(%OLDSTR,%OLDDEL,%NEWDEL) ; $PIECE extract based on variable length delimiter
 N %LEN,%PIECE,%NEWSTR
 S %STRING=$G(%STRING)
 S %OLDDEL=$G(%OLDDEL) I %OLDDEL="" S %OLDDEL=" "
 S %LEN=$L(%OLDDEL)
 ; each %OLDDEL-sized chunk of %OLDSTR that might be delimiter
 S %NEWDEL=$G(%NEWDEL) I %NEWDEL="" S %NEWDEL="^"
 ; each piece of the old string
 S %NEWSTR="" ; new reformatted string to return
 F  Q:%OLDSTR=""  D
 . S %PIECE=$P(%OLDSTR,%OLDDEL)
 . S $P(%OLDSTR,%OLDDEL)=""
 . S %NEWSTR=%NEWSTR_$S(%NEWSTR="":"",1:%NEWDEL)_%PIECE
 . F  Q:%OLDDEL'=$E(%OLDSTR,1,%LEN)  S $E(%OLDSTR,1,%LEN)=""
 .Q
 Q %NEWSTR
 ;
