Access another jobs QTEMP
From an email by Larry Ducie available in the rpg400 archives at: http://archive.midrange.com/rpg400-l/200505/msg00297.html
Chaps,
I've just reviewed the code and it's more simple than I remembered - 4 CLLE programs and three commands. They're all very small so I'll post all 7 at the foot of this mail. (I hope you don't mind David - and apologies to all, but there's nothing worse than looking for something in the archives and all you find are references of source passed off-list)
First - an overview of how it works: To get started quickly all objects must be compiled into library JOBCMDLIB. This is because it's hard-coded. But as you now have the source, you can do what you want. :-)
Basically, it works by starting a job trace on the job you are investigating. When starting a trace you can specify an exit program. As this exit program is invoked WITHIN the environment of the job being traced it can be used as a hook within the job. Every time a traceable event occurs within the job it will call this program. By default this program marks the trace as processed and discards it - so an actual trace is not generated. You can optionally specify whether you wish to service this job - good for debugging.
When you issue command STRJOBCMD it starts a trace, and registers program EXITTRC. It also creates a message queue in library JOBCMDLIB that uniquely references that job. Every time the exit program is called it looks for entries on that mesage queue and passes the command on it directly to QCMDEXC. This allows you to run commands within that job - using the job's user profile!
When you issue command SNDJOBCMD it lets you create a command string and then passes it to the message queue created for the job you're tracing. Next time it generates a traceable event it executes your command. It's as simple as that!
When you issue command ENDJOBCMD it ends the trace. You can specify whether you wish to end the service of the job too - good if you're servicing and debugging the job and wish to keep debugging.
That's it.
To create the commands:
- create a library called JOBCMDLIB
- compile the four CLLE programs into library JOBCMDLIB.
- compile the three commands into library JOBCMDLIB, specify the CLLE of the same name as the processing program.
You will also need to create a message queue called CMDLOG in library JOBCMDLIB. This will log all commands sent to jobs via this route. This is important as there is practically no way of knowing somebody is doing this. You can piggyback one job after another and then it'd be almost impossible to trace the fact that actions invoked within one job was actually caused by another user running another job.
Finally, here's a good test:
- Start two sessions.
- Leave session 1 on a command line.
- Add JOBCMDLIB to the library list of session 2 and issue command STRJOBCMD - enter the job details of session 1, and opt to service the job.
- In session 2 issue command SNDJOBCMD and place the job details of session 1 again. This time type a call command to your favourite interactive screen program.
- Simply press Enter in session 1.
The program should be called, and the screen should appear.
Have fun! (I've copy 'n' pasted the source into the mail so I hope it formats OK).
I'll try and set up a savf to download on my website.
Cheers
Larry Ducie
Source:
Contents
STRJOBCMD - CLLE
/* **************************************************************** */ PGM PARM(&JOB &SRVJOB) DCL VAR(&JOB) TYPE(*CHAR) LEN(26) DCL VAR(&NAME) TYPE(*CHAR) LEN(10) DCL VAR(&USER) TYPE(*CHAR) LEN(10) DCL VAR(&NUMBER) TYPE(*CHAR) LEN(6) DCL VAR(&SRVJOB) TYPE(*CHAR) LEN(1) DCL VAR(&MSGQ) TYPE(*CHAR) LEN(10) /* Extract job details... */ CHGVAR VAR(&NAME) VALUE(%SST(&JOB 1 10)) CHGVAR VAR(&USER) VALUE(%SST(&JOB 11 10)) CHGVAR VAR(&NUMBER) VALUE(%SST(&JOB 21 6)) /* Service job..? */ IF COND(&SRVJOB *EQ 'Y') THEN(DO) STRSRVJOB JOB(&NUMBER/&USER/&NAME) /* Job does not exist... */ MONMSG MSGID(CPF3520) EXEC(DO) SNDPGMMSG MSG('The job you are trying to send a + command to does not exist') TOPGMQ(*PRV) GOTO CMDLBL(END) ENDDO /* Job already being serviced... */ MONMSG MSGID(CPF3501) EXEC(DO) SNDPGMMSG MSG('Job is already being serviced, traced + or debugged') TOPGMQ(*PRV) GOTO CMDLBL(END) ENDDO /* Already servicing another job... */ MONMSG MSGID(CPF3938) EXEC(DO) SNDPGMMSG MSG('You are already servicing another job') + TOPGMQ(*PRV) GOTO CMDLBL(END) ENDDO /* General errors... */ MONMSG MSGID(CPF3500) EXEC(DO) SNDPGMMSG MSG('An error occurred when trying to + service the job. See joblog for + details.') TOPGMQ(*PRV) GOTO CMDLBL(END) ENDDO ENDDO /* Create message queue... */ CHGVAR VAR(&MSGQ) VALUE('SRVJ' *CAT &NUMBER) CRTMSGQ MSGQ(JOBCMDLIB/&MSGQ) MONMSG CPF9999 /* Set trace... */ TRCJOB EXITPGM(JOBCMDLIB/EXITTRC) MONMSG CPF9999 EXEC(DO) SNDPGMMSG MSG('An error occurred when trying to + trace the job. See joblog for + details.') TOPGMQ(*PRV) IF COND(&SRVJOB *EQ 'Y') THEN(DO) ENDSRVJOB MONMSG MSGID(CPF9999) ENDDO DLTMSGQ MSGQ(JOBCMDLIB/&MSGQ) MONMSG CPF9999 GOTO CMDLBL(END) ENDDO END: ENDPGM
SNDJOBCMD - CLLE
/* **************************************************************** */ PGM PARM(&JOB &CMD) DCL VAR(&JOB) TYPE(*CHAR) LEN(26) DCL VAR(&NAME) TYPE(*CHAR) LEN(10) DCL VAR(&USER) TYPE(*CHAR) LEN(10) DCL VAR(&NUMBER) TYPE(*CHAR) LEN(6) DCL VAR(&CMD) TYPE(*CHAR) LEN(512) DCL VAR(&MSGQ) TYPE(*CHAR) LEN(10) /* Extract job details... */ CHGVAR VAR(&NAME) VALUE(%SST(&JOB 1 10)) CHGVAR VAR(&USER) VALUE(%SST(&JOB 11 10)) CHGVAR VAR(&NUMBER) VALUE(%SST(&JOB 21 6)) /* Send command to message queue... */ CHGVAR VAR(&MSGQ) VALUE('SRVJ' *CAT &NUMBER) SNDPGMMSG MSG(&CMD) TOMSGQ(JOBCMDLIB/&MSGQ) MONMSG MSGID(CPF2469) EXEC(DO) SNDPGMMSG MSG('An error occured while sending the + command. Please re-enter the details.') GOTO CMDLBL(END) ENDDO END: ENDPGM
ENDJOBCMD - CLLE
/* **************************************************************** */ PGM PARM(&JOB &SRVJOB) DCL VAR(&JOB) TYPE(*CHAR) LEN(26) DCL VAR(&NAME) TYPE(*CHAR) LEN(10) DCL VAR(&USER) TYPE(*CHAR) LEN(10) DCL VAR(&NUMBER) TYPE(*CHAR) LEN(6) DCL VAR(&SRVJOB) TYPE(*CHAR) LEN(1) DCL VAR(&MSGQ) TYPE(*CHAR) LEN(10) /* Extract job details... */ CHGVAR VAR(&NAME) VALUE(%SST(&JOB 1 10)) CHGVAR VAR(&USER) VALUE(%SST(&JOB 11 10)) CHGVAR VAR(&NUMBER) VALUE(%SST(&JOB 21 6)) /* End trace... */ TRCJOB SET(*END) MONMSG CPF9999 /* End service job... */ IF COND(&SRVJOB *EQ 'Y') THEN(DO) ENDSRVJOB MONMSG CPF9999 ENDDO /* Delete message queue... */ CHGVAR VAR(&MSGQ) VALUE('SRVJ' *CAT &NUMBER) DLTMSGQ MSGQ(JOBCMDLIB/&MSGQ) MONMSG CPF9999 ENDPGM
EXITTRC - CLLE
PGM PARM(&TRCDTA) DCL VAR(&TRCDTA) TYPE(*CHAR) LEN(1024) DCL VAR(&CMD) TYPE(*CHAR) LEN(1024) DCL VAR(&LEN) TYPE(*DEC) LEN(15 5) VALUE(512) DCL VAR(&MSGTXT) TYPE(*CHAR) LEN(512) DCL VAR(&NAME) TYPE(*CHAR) LEN(10) DCL VAR(&USER) TYPE(*CHAR) LEN(10) DCL VAR(&NUMBER) TYPE(*CHAR) LEN(6) DCL VAR(&MSGQ) TYPE(*CHAR) LEN(10) DCL VAR(&SENDER) TYPE(*CHAR) LEN(80) DCL VAR(&LOG) TYPE(*CHAR) LEN(512) /* Set trace record as processed... */ CHGVAR VAR(&TRCDTA) VALUE(' ') /* Retrieve job attributes... */ RTVJOBA JOB(&NAME) USER(&USER) NBR(&NUMBER) /* Receive message from queue... */ CHGVAR VAR(&MSGQ) VALUE('SRVJ' *CAT &NUMBER) RCVMSG MSGQ(JOBCMDLIB/&MSGQ) MSG(&MSGTXT) + SENDER(&SENDER) MONMSG MSGID(CPF9999) EXEC(GOTO CMDLBL(END)) /* Set command... */ CHGVAR %SST(&CMD 1 1024) %SST(&MSGTXT 1 &LEN) /* Send log messages, if message received... */ IF COND(&MSGTXT *NE ' ') THEN(DO) CHGVAR VAR(&LOG) VALUE(&SENDER *CAT &NAME *CAT + &USER *CAT &NUMBER) SNDPGMMSG MSG(&LOG) TOMSGQ(JOBCMDLIB/CMDLOG) CHGVAR VAR(&LOG) VALUE(&CMD) SNDPGMMSG MSG(&LOG) TOMSGQ(JOBCMDLIB/CMDLOG) MONMSG CPF0000 /* Call QCMDEXC to process command... */ CALL PGM(QCMDEXC) PARM(&CMD &LEN) MONMSG CPF0000 ENDDO END: ENDPGM
STRJOBCMD - CMD
CMD PROMPT('Start Job Command Processing') PARM KWD(JOB) TYPE(Q1) MIN(1) PROMPT('Job name . + . . . . . . . . . .') PARM KWD(SRVJOB) TYPE(*CHAR) LEN(1) RSTD(*YES) + DFT(Y) VALUES(Y N) CHOICE('(Y/N)') + PROMPT('Service Job . . . . . . . . .') /*********************************************************************/ Q1: QUAL TYPE(*NAME) LEN(10) MIN(1) CHOICE('Name') QUAL TYPE(*NAME) LEN(10) MIN(1) CHOICE('User') + PROMPT('User . . . . . . . . . . . . .') QUAL TYPE(*CHAR) LEN(6) RANGE(000000 999999) + MIN(1) CHOICE('000000-999999') + PROMPT('Number . . . . . . . . . . . .')
SNDJOBCMD - CMD
CMD PROMPT('Send Job Command') PARM KWD(JOB) TYPE(Q1) MIN(1) PROMPT('Job name . + . . . . . . . . . .') PARM KWD(CMD) TYPE(*CMDSTR) LEN(512) MIN(1) + CHOICE('Command') + PROMPT('Command . . . . . . . . . . .') /*********************************************************************/ Q1: QUAL TYPE(*NAME) LEN(10) MIN(1) CHOICE('Name') QUAL TYPE(*NAME) LEN(10) MIN(1) CHOICE('Name') + PROMPT('User . . . . . . . . . . . . .') QUAL TYPE(*CHAR) LEN(6) RANGE(000000 999999) + MIN(1) CHOICE('000000-999999') + PROMPT('Number . . . . . . . . . . . .')
ENDJOBCMD - CMD
CMD PROMPT('End Job Command Processing') PARM KWD(JOB) TYPE(Q1) MIN(1) PROMPT('Job name . + . . . . . . . . . .') PARM KWD(SRVJOB) TYPE(*CHAR) LEN(1) RSTD(*YES) + DFT(Y) VALUES(Y N) CHOICE('(Y/N)') + PROMPT('End service job . . . . . . .') /*********************************************************************/ Q1: QUAL TYPE(*NAME) LEN(10) MIN(1) CHOICE('Name') QUAL TYPE(*NAME) LEN(10) MIN(1) CHOICE('User') + PROMPT('User . . . . . . . . . . . . .') QUAL TYPE(*CHAR) LEN(6) RANGE(000000 999999) + MIN(1) CHOICE('000000-999999') + PROMPT('Number . . . . . . . . . . . .')