Joined: 28 Mar 2023 Posts: 9 Location: United Kingdom
Hi,
I am looking into how to use the TSO/E Service Facility Routine to invoke other programs in an assembly program. I've been successful in invoking another program without passing any parameters, however, I can't seem to figure out how to pass parameters.
I am aware that IKJEFTSR parameter 7 can be used to specify parameters that would usually be passed in the PARM field. However, I want to try to pass an argument that the program consumes.
This is what I've come up with for IDCAMS (I know you're not meant to put IDCAMS in AUTHTSF, but this is just for me to test temporarily).
Code:
IDCAMASM CSECT # Mark as executable.
STM 14,12,12(13) # Store stack contents.
BALR 12,0 # Establish addressability by
USING *,12 # storing base addr in base reg.
ST 13,SAVE+4 # save the CALLER save area
LA 13,SAVE # load pointer to THIS save area
*
* invoke IKJEFTSR which has been passed IDCAMS as an arg (PGM/PGMLEN)
*
L 15,=V(IKJEFTSR) # GET ADDRESS OF IKJEFTSR
CALL (15),(IKJPARM1,PGM,PGMLEN,RETCODE,REASONC,ABENDCD,PARMLST),VL
LTR 15,15 # check TSR return code
BNZ ERRORRTN # bad TSR return
CLC RETCODE,ZERO # check for IDCAMS error
BH ERRORPGM # bad IDCAMD program error
B CLEANUP # run cleanup code and return
*
* TSR SERVICE FACILITY ERROR BRANCH
*
ERRORRTN DS 0H
B CLEANUP
*
* IDCAMS ERROR BRANCH
*
ERRORPGM DS 0H
B CLEANUP
*
* COMMON CLEANUP CODE
*
CLEANUP DS 0H
L 13,4(,13) # restore CALLER save area
LM 14,12,12(13) # restore register contents
SLR 15,15
BR 14 # branch back to caller
*
* CUSTOM SUBROUTINE
*
IOROUTE STM 14,12,12(13)
BALR 12,0
USING *,12
*
* RETURN
*
L 13,SAVETWO+4
LM 14,12,12(13)
BR 14
*
* declarations
*
ZERO DC F'0' # zero constant
SAVE DS 18F # define save area storage
SAVETWO DS 18F # save area for subroutine
PGM DC C'IDCAMS' # name of program
PGMLEN DC F'6' # length of program name
RETCODE DS F # data area for return code
REASONC DS F # data area for abend reason code
ABENDCD DS F # ABEND code
IKJPARM1 DS 0F # align
DC XL2'0000' # invoke from unauth program
DC X'01' # take dump if abend
DC X'02' # invoke program
IDCMARG DS 1F # one full word
DC H'2' # OPTIONS param len
DC X'0000' # OPTIONS param content
OPTIONS DC H'0' # no basic parms for IDCAMS
DNAMES DC H'0' # no alt ddnames
PGNO DC H'0' # length of field
DDNAME DC C'DDINPUTDS ' # left-justified DD for IO
IOLIST DC F'1' # one I/O list entry
DC A(DDNAME) # address of DDNAME
DC A(IOROUTE) # address of subroutine
DC A(DDNAME) # required arg for subroutine
PARMLST CALL ,(IDCMARG,DNAMES,PGNO,IOLIST),VL,MF=L # set up PARMLIST
IDCAMASM AMODE 31
END
Here is how I am compiling and running the program:
But I don't get any output from the IDCAMS PRINT statement like I do when I run this with the same parameters with a CALL directly. There are no abends or anything, and I can't find documentation on passing arguments in the way I want to -- any tips?
Joined: 01 Sep 2006 Posts: 2589 Location: Silicon Valley
Code:
IOLIST DC F'1' # one I/O list entry
DC A(DDNAME) # address of DDNAME
DC A(IOROUTE) # address of subroutine
DC A(DDNAME) # required arg for subroutine
I have never called IDCAMS in this way...
I think the use of DDINPUTDS is correct, but you use the same parameter, DDNAME, both for the first and third parameters in the group. The third parameter is USER DATA and it seems to have a very specific format. (but your IOROUTE routine does not seem to do anything, so perhaps it does not matter now. It might matter in the future.)
Joined: 28 Mar 2023 Posts: 9 Location: United Kingdom
Thanks for the responses!
So the above way of calling IDCAMS worked well enough for me if I called it directly; it outputs the dataset to SYSPRINT. See the below output for the non-IKJEFTSR code.
Assembler that is basically the same as the above but calls IDCAMS directly rather than through IKJEFTSR:
Code:
IDCAMTST CSECT # Mark as executable.
STM 14,12,12(13) # Store stack contents.
BALR 12,0 # Establish addressability by
USING *,12 # storing base addr in base reg.
ST 13,SAVE+4 # save the CALLER save area
LA 13,SAVE # load pointer to THIS save area
*
* invoke IKJEFTSR which has been passed IDCAMS as an arg (PGM/PGMLEN)
*
LOAD EP=IDCAMS # Load IDCAMS into R0
LR 15,0 # Copy R0 to R15
CALL (15),(OPTIONS,DNAMES,PGNO,IOLIST),VL
LTR 15,15 # check TSR return code
BNZ ERRORRTN # bad IDCAMS error
B CLEANUP # run cleanup code and return
*
* IDCAMS ERROR BRANCH
*
ERRORRTN DS 0H
B CLEANUP
*
* OTHER ERROR BRANCH
*
* ERRORPGM DS 0H
* B CLEANUP
*
* COMMON CLEANUP CODE
*
CLEANUP DS 0H
L 13,4(,13) # restore CALLER save area
LM 14,12,12(13) # restore register contents
SLR 15,15
BR 14 # branch back to caller
*
* CUSTOM SUBROUTINE
*
IOROUTE STM 14,12,12(13)
BALR 12,0
USING *,12
ST 13,SAVETWO+4
LA 13,SAVETWO
*
* RETURN
*
L 13,SAVETWO+4
LM 14,12,12(13)
BR 14
*
* declarations
*
ZERO DC F'0' # zero constant
SAVE DS 18F # define save area storage
SAVETWO DS 18F # second save area
* PGM DC C'IDCAMS' # name of program
* PGMLEN DC F'6' # length of program name
* RETCODE DS F # data area for return code
* REASONC DS F # data area for abend reason code
* ABENDCD DS F # ABEND code
* IKJPARM1 DS 0F # align
* DC XL2'0000' # invoke from unauth program
* DC X'01' # take dump if abend
* DC X'02' # invoke program
*IDCMARG DS 1F # one full word
* DC H'2' # OPTIONS param len
* DC X'0000' # OPTIONS param content
OPTIONS DC H'0' # no basic parms for IDCAMS
DNAMES DC H'0' # no alt ddnames
PGNO DC H'0' # length of field
DDNAME DC CL8'INPUTDS' # left-justified DD for IO
IOLIST DC F'1' # one I/O list entry
DC A(DDNAME) # address of DDNAME
DC A(IOROUTE) # address of subroutine
DC A(DDNAME) # required arg for subroutine
* PARMLST CALL ,(IDCMARG,DNAMES,PGNO,IOLIST),VL,MF=L # set up PARM
IDCAMASM AMODE 31
END
SYSPRINT in RUNSTEP:
Code:
1IDCAMS SYSTEM SERVICES TIME: 05:08:12 07/28/23 PAGE 1
0
PRINT INFILE(INPUTDS)
1IDCAMS SYSTEM SERVICES TIME: 05:08:12 07/28/23 PAGE 2
-LISTING OF DATA SET -ALEXGAS.TEMP.PDS
0RECORD SEQUENCE NUMBER - 1
000000 E3C8C9E2 40C9E240 C140E3C5 E2E340C9 C4C3C1D4 E240D9C5 C3D6D9C4 *THIS IS A TEST IDCAMS RECORD *
0IDC0005I NUMBER OF RECORDS PROCESSED WAS 1
0IDC0001I FUNCTION COMPLETED, HIGHEST CONDITION CODE WAS 0
1IDCAMS SYSTEM SERVICES TIME: 05:08:12 07/28/23 PAGE 3
0
0IDC0002I IDCAMS PROCESSING COMPLETE. MAXIMUM CONDITION CODE WAS 0
But when I use IKJEFTSR, it doesn't seem to process the IDCAMS command I provide to print the dataset, which means that my custom subroutine isn't called.
Perhaps the more accurate question is: how can I pass commands to the program that IKJEFTSR invoked? (or is this even possible?)
I feel like there must be a way as it would be incredibly limiting to not allow such functionality, but perhaps this use-case is too niche...
Sidenote: I am happy to try and get some logs -- would the link-edit output be of use? I don't think we have the z/OS Debugger though
In your code, you are using the parameters to use INPUTDS instead of SYSIN. I agree that you should prefer not to use SYSIN to avoid collisions with other processes... but IMHO, the simplest way is to default to use SYSIN.