MVS TOOLS AND TRICKS OF THE TRADE March 1999 Sam Golob MVS Systems Programmer P.O. Box 906 Tallman, New York 10982 Sam Golob is a Senior Systems Programmer. He also participates in library tours and book signings with his wife, author Courtney Taylor. Sam can be contacted at sbgolob@cbttape.org. Information about the CBT MVS Tapes can be found on the web, at http://www.cbttape.org. SMP/E Preprocessing This month we'll be talking about SMP/E Preprocessing, which I helped develop about fifteen years ago, and which is still useful today. SMP/E Preprocessing has to do with keeping track of your operating system maintenance PTFs. With the techniques we'll discuss today, you can have a great measure of power and control over the fixes that will go on to your system, even before SMP/E has ever "seen" them. The idea of SMP/E Preprocessing is to look at a tape file of maintenance PTFs or any SMPPTFIN file, before it goes on to your system. I've found it wise never to completely trust IBM's software packaging, and I always try and study how it is put together. On occasion, IBM will claim to have sent a certain PTF on a tape, and it really isn't there. You only find out about the error after you've attempted to RECEIVE the PTF from the tape, and SMP/E tells you there are no PTFs eligible to be RECEIVEd. SMP/E does not give you any actual knowledge or information about the contents of the SMPPTFIN tape file. All SMP/E tells you, is whether the desired PTF is there, or not. No other information is forthcoming, unless you're willing to risk RECEIVEing many other PTFs that you may not want. How, then, can you pre-screen an SMPPTFIN file? You can copy it to disk and attempt to BROWSE it with ISPF. Then you can do repeated FIND commands for the "++ PTF" keyword, starting in column 1, that indicates the presence of a new PTF. Having found a PTF, you can next look for the FMID keyword which denotes the system component that the PTF belongs to. However, since IBM-shipped PTF files can be very large, sometimes containing 20 million lines or more, this is not usually a practical way of finding out what is going on. However, I must say that the REVIEW program from File 134 of the CBT MVS Tape is considerably better than ISPF Browse for this purpose. We have a far better way to pre-examine PTF files. Almost 20 years ago, Jerry Lawson of the Hartford Insurance Group wrote an assembler program which reads an SMPPTFIN file, and which sorts all the PTFs on it, by the product id (FMID) to which they belong. The output of Jerry's program is a report. With this program, we can read a PTF tape and find out what products and PTF numbers are represented in it. Even a very large SMPPTFIN file can be processed very quickly by Jerry's program. At least this is a step in the right direction. We can pre-screen a PTF tape to find out what's on it. The only drawback is that we can't directly use the report data, as it stands, to feed input to an SMP/E job. For this reason, I was not fully satisfied with Jerry's report as it was. I wrote a COBOL post-processing program to read the report, and to format the PTF numbers, arranged by FMID, so they could be directly fed into a new SMP/E RECEIVE, APPLY, or ACCEPT job. This gave me full FORFMID control of the SMPPTFIN tape, before SMP/E ever "got its grubby paws" on it. Another problem we have with looking at an SMPPTFIN file, is that it's often very large. Wouldn't it be nice to break it up into a pds, with each PTF as a separate member? Then, you could BROWSE, EDIT, or otherwise pre-process each PTF as a separate entity, instead of being forced to look at it as a small part of a huge file. I solved this problem by writing another COBOL program to help me break up any SMPPTFIN file by PTFs, APARs, USERMODs, or FUNCTIONs. (Sorry to have used COBOL, but it was quick and dirty, and it worked.) By breaking up the original huge file into its component PTFs, seen separately, we can have access to much more initial information about a PTF if we want it. We'll see more about this, later on. Now, we'll look into some of the details of each of these techniques, so that you'll be able to add these "weapons" to your arsenal of system control tools. I'll show you a lot of the control over PTFs that you can gain, and you can use your own inventiveness and creativity to further exploit this additional knowledge. WHERE YOU CAN FIND THE SOFTWARE Jerry Lawson's report program, and my supporting programs, can be found on File 118 of the CBT MVS Utilities Tape, which is a huge collection of free MVS software that is independently produced. You can order physical tapes throgh NaSPA, or you can duplicate a tape if somebody else has one (a good tape duplication program can be found on File 229 of the CBT Tape). Most of the CBT Tape materials can be found on the NaSPA cd-rom. However, the best place to get to specific CBT Tape files is to download them from www.naspa.net, which points to the NaSPA-sponsored site at www.cbttape.org. Simply go to www.naspa.net and click on "Online CBT Tape". Then click on "Download CBT". When you go to the online home of the CBT Tape, you're assured of getting the latest versions of the files. On CBT Tape File 118, Jerry Lawson's program is called PUTXREF, and my post-processing program is called SMPFMUPV. A sample execution jobstream is included as member JCL2. I wrote my original COBOL programs in VS/COBOL, but I've included COBOL II versions of the source, and there are 3 compile and linkedit jobs, IGYWCL1, IGYWCL2, IGYWCL3, which compile the COBOL II source programs under LE/370. In my tests, these programs worked correctly. The latest software is scheduled to be loaded on Version 420 of the CBT Tape, File 118, but meanwhile, it can be found on the net at: ftp://ftp.cbttape.org/pub/cbttape/adhoc/file118.zip . When this file is downloaded to the pc, you can unzip it and then upload it in binary (i.e. no translation or crlf) to the MVS system. The dataset will be in TSO XMIT format, and to make it usable, you do a TSO RECEIVE INDATASET('yourid.FILE118.XMI'). You'll get a partitioned dataset that contains all the good stuff. In case you can't get the newest version of File 118, the source programs SMPFMU2V and SMPUPD2 are correct, except for one data name in SMPUPD2 called FUNCTION, which became a COBOL reserved word, and which has to be changed to FUNCTON. HOW TO USE THE SOFTWARE In Figure 1, I've included a sample of execution JCL for a jobstream to look at an SMPPTFIN file, which could be on tape or on disk, and to produce Jerry Lawson's PUTXREF report. This is followed by my post-processing, which produces a file like the one shown in Figure 2. You'll see that every SYSMOD on the SMPPTFIN file is reported according to its FMID, and you can feed the output into SELECT statements on an SMP/E RECEIVE, APPLY, or ACCEPT job. In practice, I maintain a partitioned dataset which records the contents of every input SMPPTFIN tape I have. I run each of them through this processing, and I write a new pds member corresponding to each tape. I call the partitioned dataset userid.PTFPDS or some similar name, and I keep it around permanently. If I need to find on which tape a particular PTF is, I do a dataset search with the FIND subcommand of the PDS program (from File 182 of the CBT Tape). If you're licensed for STARTOOL (from Serena Inc. in Burlingame, California), it performs the same function. The FIND subcommand can be used to globally scan across all members of the pds, and it will show every tape I have, which contains that particular PTF. With the PDS command pointed at my PTFPDS dataset, a sample search command might be: FIND : /ptfname/ where the colon (:) denotes a command to search all members of the PTFPDS partitioned dataset. In addition, I can do a FIND on a particular FMID, and the PDS program will show me every PTF I have in house on a tape, which belongs to that FMID. If you examine Figure 2, you'll see that the comment field next to each PTF number, contains the FMID that the PTF belongs to, and you can search on that FMID name. You can use whatever global search utility you have, against all or some of the members of this pds, and you can instantly see how useful this kind of processing can be. BREAKING A BIG SMPPTFIN FILE INTO SEPARATE PTFS My SMPUPD program from File 118 of the CBT Tape can be used to break up an SMPPTFIN file into a pds containing each PTF as a separate member. The COBOL II version of the SMPUPD source is called SMPUPD2. All that SMPUPD does is to make a copy of the SMPPTFIN file with a few subtle changes. Before each ++ PTF keyword (or ++ APAR or ++ USERMOD or ++ FUNCTION), SMPUPD inserts an IEBUPDTE-type ./ ADD NAME=ptfname card, containing the name of the PTF or other SYSMOD that's there. This serves to separate each SYSMOD in the SMPPTFIN file from its neighbor. SMPUPD also does one more thing. It changes any ./ string starting in column 1, which would denote an internal IEBUPDTE control card in the PTF, to a different string: ./. This allows for the correct IEBUPDTE or PDSLOAD post-processing of the copied (and changed) SMPUPD output file. I have to talk about our IEBUPDTE substitute program called PDSLOAD. PDSLOAD can be found on File 093 of the CBT Tape. Besides performing a member load of a partitioned dataset from an IEBUPDTE format sequential dataset (the equivalent of IEBUPDTE, PARM=NEW), PDSLOAD can be set up to automatically convert all of the imbedded ./ strings within each member, back to the original ./ strings they once were. Thus, if you use PDSLOAD instead of IEBUPDTE to load the SMPUPD-modified copy of the original SMPPTFIN dataset into a pds, you won't have to convert imbedded >< strings globally back to ./ as they originally were. If you use PDSLOAD to create your pds, the original PTFs will be separated and correct as they were shipped. Look at sample JCL member SMPUPDJ, in File 118 of the CBT Tape, or look at Figure 3, to see how to load a partitioned dataset with the separated PTFs. The value of being able to look at separate PTFs from a big SMPPTFIN file is obvious to most people. If you only care about one PTF, you don't have to look at other PTFs that you don't want to see. You might also want to RECEIVE the single PTF directly, and not as a part of a big file. But there's another, more subtle advantage, if you know how to read the object decks that are on each PTF. Sometimes you need to fit a system modification, such as a load module zap, to a new version of an IBM module. If IBM doesn't provide source code for the new version, or if you can't get to the source code display from IBMLINK, you've got another alternative. You can disassemble the code from the object deck that's shipped with the latest PTF. Normally, disassemblers don't read 80-byte format object decks directly. So you can use the ISPF editor to copy the object deck to a separate file, linkedit it, and then disassemble the resulting load module, so you can fit your mod. Free disassemblers can be found on Files 171, 217, 238-242, and 354 of the CBT Tape. However, if you're lucky enough to have the STARTOOL vendor product from Serena (mentioned above), STARTOOL has a disassembler that will directly disassemble code from an 80-byte object deck. The STARTOOL object code disassembler is invoked with the READOBJ subcommand. Using STARTOOL, you can point to the pds that contains the PTFs separated from the SMPPTFIN file, or an SMPPTS dataset for that matter. Get a member list under STARTOOL (ML subcommand), and then invoke the line command of READ against any PTF in the dataset. This will instantly disassemble all the object decks in the PTF. You can now look at the assembler code in the PTFs, to help in fitting your mods. I hope this month's talk was instructive. The techniques certainly are different than what you normally see as an MVS systems programmer. But their utility value is obvious, and in the long run you'll save a lot of maintenance time, if you make a regular practice of incorporating these methods in your everyday work. Good luck. See you next month. * * * * * * * * * * * * * * * * * * * * * * * * Figure 1. JOBSTREAM TO RUN BASIC SMP/E PREPROCESSING This jobstream takes an SMPPTFIN file (a PTF file on disk or on tape) and first runs Jerry Lawson's PUTXREF report against it. Then, the job runs postprocessing program SMPFMUPV against the report, to produce an 80-byte PTF list sorted by FMID, as shown in Figure 2. //SAGOLOBX JOB (ACCT#),S-GOLOB, // NOTIFY=&SYSUID, // CLASS=B,MSGCLASS=X //******************************************************************// //* //* PUTXREF PROGRAM FROM HARTFORD INSURANCE GROUP *// //* WITH MY EXTENSIONS - S.GOLOB *// //* *// //* THIS JOB *// //* Separates PTF numbers by FMID. *// //* *// //* INPUT is an SMPPTFIN file. *// //* *// //* OUTPUTS are: 1. A PDS member with ./ ADD NAME=FMID *// //* and all PTFS belonging to that *// //* FMID, listed underneath. *// //* *// //* 2. A step to load the members into *// //* a PDS. For example, if you *// //* look at member JBB1214, you'll *// //* find a list of all PTFs belonging *// //* to FMID JBB1214, in a format so *// //* they can be input into an SMP job. *// //* *// //******************************************************************// //* //STEP1 EXEC PGM=PUTXREF //STEPLIB DD DSN=SAGOLOB.LOAD,DISP=SHR //INPUT DD DISP=SHR,DSN=SAGOLOB.TEST.SEQ.PTS //SORTIN DD DSN=&&SORT,DISP=(NEW,PASS),UNIT=3380, // DCB=(RECFM=FB,LRECL=15,BLKSIZE=4095), // SPACE=(CYL,(25,20)) //SORTOUT DD DSN=&&SORT,DISP=(SHR,PASS),VOL=REF=*.SORTIN //TITLES DD DISP=SHR,DSN=SAGOLOB.FILE118.PDS(TITLES) //PRINTER DD DSN=&TEMP1,DISP=(NEW,PASS),UNIT=3380, // DCB=(RECFM=VBA,LRECL=137,BLKSIZE=141), // SPACE=(TRK,(15,15)) //SYSUDUMP DD SYSOUT=* //SYSPRINT DD SYSOUT=* //SYSOUT DD SYSOUT=* //SYSIN DD * SORT FIELDS=(9,7,CH,A,1,7,CH,A) /* //COPY EXEC PGM=IEBGENER //SYSPRINT DD SYSOUT=* //SYSUT1 DD DSN=&TEMP1,DISP=(OLD,PASS,KEEP) //SYSUT2 DD SYSOUT=* //SYSIN DD DUMMY //* //CLEAN EXEC PGM=IEFBR14 //IN DD DSN=&TEMP1,DISP=(OLD,PASS) //* //SMPFMUPD EXEC PGM=SMPFMUPV //STEPLIB DD DISP=SHR,DSN=SAGOLOB.LOAD //SYSPRINT DD SYSOUT=* //SYSUT1 DD DSN=&TEMP1,DISP=(OLD,DELETE,KEEP) //*YSUT2 DD DSN=&TEMP3,DISP=(NEW,PASS),UNIT=SYSDA, //* DCB=(RECFM=FB,LRECL=80,BLKSIZE=3120), //* SPACE=(TRK,(15,30)) //SYSUT2 DD DISP=SHR,DSN=SAGOLOB.PTFPDS(TESTSEQ1) //SYSABEND DD SYSOUT=L,HOLD=YES //* //* The following step is optional, and may be commented out. //* You'll determine if you want it or not. //* //S03UPDTE EXEC PGM=PDSLOAD,PARM='UPDTE(./)' /* CBT TAPE--FILE 093 */ //*03UPDTE EXEC PGM=IEBUPDTE,PARM=NEW /* not as good */ //STEPLIB DD DISP=SHR,DSN=SAGOLOB.LOAD //SYSPRINT DD SYSOUT=* //SYSUT1 DD DSN=SAGOLOB.PTFPDS(TESTSEQ1),DISP=SHR /* LRECL=80 */ //*YSUT1 DD DSN=&TEMP3,DISP=(OLD,DELETE) //SYSUT2 DD DSN=SAGOLOB.PTSXREF,DISP=SHR /* a PDS. LRECL=80 */ * * * * * * * * * * * * * * * * * * * * * * * * Figure 2. SAMPLE OUTPUT OF SMP/E PREPROCESSING. This is sample output from the jobstream shown in Figure 1. Notice the comments which program SMPFMUPV inserts next to each PTF number. This makes it easier to do global searches either by PTF number or by FMID number. ./ ADD NAME=EDU1G01 UN90869 /* FMID - EDU1G01 - FROM PUT TAPE - DONE 02/01/99 */ ./ ADD NAME=H0G2110 UN79279 /* FMID - H0G2110 - FROM PUT TAPE - DONE 02/01/99 */ UN87460 /* FMID - H0G2110 - FROM PUT TAPE - DONE 02/01/99 */ UN87499 /* FMID - H0G2110 - FROM PUT TAPE - DONE 02/01/99 */ UN99450 /* FMID - H0G2110 - FROM PUT TAPE - DONE 02/01/99 */ ./ ADD NAME=JBB66N1 UW25288 /* FMID - JBB66N1 - FROM PUT TAPE - DONE 02/01/99 */ ./ ADD NAME=JIF4210 UW27032 /* FMID - JIF4210 - FROM PUT TAPE - DONE 02/01/99 */ UW27036 /* FMID - JIF4210 - FROM PUT TAPE - DONE 02/01/99 */ ./ ADD NAME=JIF4230 UW26914 /* FMID - JIF4230 - FROM PUT TAPE - DONE 02/01/99 */ UW27404 /* FMID - JIF4230 - FROM PUT TAPE - DONE 02/01/99 */ UW27480 /* FMID - JIF4230 - FROM PUT TAPE - DONE 02/01/99 */ UW27514 /* FMID - JIF4230 - FROM PUT TAPE - DONE 02/01/99 */ UW27518 /* FMID - JIF4230 - FROM PUT TAPE - DONE 02/01/99 */ UW27846 /* FMID - JIF4230 - FROM PUT TAPE - DONE 02/01/99 */ ./ ADD NAME=JIF4270 UW27665 /* FMID - JIF4270 - FROM PUT TAPE - DONE 02/01/99 */ ./ ADD NAME=JPZ8136 UW35675 /* FMID - JPZ8136 - FROM PUT TAPE - DONE 02/01/99 */ * * * * * * * * * * * * * * * * * * * * * * * * Figure 3: Processing to break an SMPPTFIN file into its separate SYSMODS (usually PTFs). Each SYSMOD will be a different member of the pds. //SAGOLOBO JOB (ACCT#),S-GOLOB, // NOTIFY=&SYSUID, // CLASS=B,MSGCLASS=X //******************************************************************// //** JCL TO MAKE A PDS OUT OF AN SMPPTFIN SEQ INPUT FILE **// //******************************************************************// //* STEP 1 - CREATION OF TEMPORARY COPY OF SMPPTFIN FILE //* WHICH HAS ./ ADD CARDS INSERTED, //* AND WHICH CONVERTS OTHER "./" STRINGS //* IN COLUMNS 1-2 TO "><". //******************************************************************// //S1PTFADD EXEC PGM=SMPUPD //STEPLIB DD DISP=SHR,DSN=SAGOLOB.LOAD //SYSPRINT DD SYSOUT=* //SYSUT1 DD DISP=SHR,DSN=SAGOLOB.TEST.SEQ.PTS //SYSUT2 DD DISP=(,PASS),DSN=&&TEMP,UNIT=SYSDA, // DCB=(RECFM=FB,LRECL=80,BLKSIZE=6160),SPACE=(TRK,(300,120)) //SYSABEND DD SYSOUT=A,HOLD=YES //******************************************************************// //* STEP 2 - RELOAD OF ALL SYSMODS INTO A NEW OUTPUT PDS. //******************************************************************// //S2UPDTE EXEC PGM=PDSLOAD,PARM='UPDTE(><)' //STEPLIB DD DISP=SHR,DSN=SAGOLOB.LOAD //SYSPRINT DD SYSOUT=* //SYSUT1 DD DSN=&&TEMP,DISP=(OLD,PASS) //SYSUT2 DD DSN=SAGOLOB.TEST.PDS.PTS,DISP=SHR //*YSUT2 DD DSN=SAGOLOB.TEST.PDS.PTS,DISP=(NEW,CATLG,DELETE), //* UNIT=SYSDA,VOL=SER=PRIM10,SPACE=(TRK,(300,120,137)), //* DCB=(RECFM=FB,LRECL=80,BLKSIZE=3120) //******************************************************************// //* STEP 3 - CREATION OF ISPF STATISTICS AND RESTORE OF //* DUPLICATELY-NAMED SYSMODS SO THEY CAN //* BE EXAMINED. //* COMPARE TOTAL NUMBER OF RECORDS IN THE PDS //* USING THE AT : SHORT COMMAND //* WITH THE NUMBER OF RECORDS IN THE ORIGINAL //* FILE, TO MAKE SURE NO RECORDS GOT LOST IN //* THIS PROCESS. //******************************************************************// //S3STATS EXEC PGM=IKJEFT01,REGION=4096K,DYNAMNBR=50 //STEPLIB DD DISP=SHR,DSN=IBMUSER.PDSE530.LOAD /* PDS or STARTOOL */ //SYSPRINT DD SYSOUT=* //SYSTSPRT DD SYSOUT=* //SYSTERM DD SYSOUT=* //* ----- THIS SHOULD WORK WITH FREE PDS AS WELL AS STARTOOL ----- *// //SYSTSIN DD * PDS 'SAGOLOB.TEST.PDS.PTS' AT : ADDSTATS USERID(PTF9901) VER(01) RESTORE $PTF REPEAT NOPROMPT AT $PTF* ADDSTATS USERID(REP9901) VER(01) FIXPDS RELEASE AT : SHORT CHANGE 'SAGOLOB.TEST.SEQ.PTS' VER END /* //