IEBGENER
Introduction
IEBGENER is basic utility used for copying data and it's reorganization. It can work only on sequential data, so PS data sets, PDS members or UNIX files.
Tasks
1. Transmit following data to your z/OS system and name it 'userid.EU2015.STATS'. Those are population statistics in most European countries. You'll need that data for few Tasks in this category.
Rank Country Population Population[%] Annual growth Annual growth[%] Doubling rate [years] 1 Russia 144031000 16.91 278000 0.19 368 2 Germany 81459000 9.54 256000 0.32 220 3 Turkey 78214000 9.18 1035000 1.34 52 4 France 66484000 7.8 261022 0.39 177 5 United Kingdom 65081276 7.64 484000 0.75 92 6 Italy 60963000 7.16 298000 0.49 141 7 Spain 46423064 5.44 -28000 -0.06t - 8 Ukraine 42850000 5.03 -136000 -0.32 - 9 Poland 38494000 4.52 20000 0.05 1334 10 Romania 19822000 2.33 -81000 -0.41 - 11 Kazakhstan 17543000 2.06 251000 1.45 48 12 Netherlands 17003777 1.99 62000 0.37 189 13 Belgium 11259000 1.32 58000 0.52 134 14 Greece 10769000 1.26 -12000 -0.11 - 15 Czech Republic 10535000 1.24 -6000 -0.06 - 16 Portugal 10311000 1.21 -58000 -0.56 - 17 Sweden 9858794 1.15 100000 1.03 68 18 Hungary 9835000 1.15 -28000 -0.28 - 19 Azerbaijan 9651000 1.13 117000 1.23 57 20 Belarus 9481000 1.11 0 0 - 21 Austria 8608000 1.01 57000 0.67 104 22 Switzerland 8265000 0.97 71000 0.87 80 23 Bulgaria 7185000 0.84 -41000 -0.57 - 24 Serbia 7103000 0.83 -29000 -0.41 - 25 Denmark 5673000 0.67 27000 0.48 145 26 Finland 5475000 0.64 6000 0.11 632 27 Slovakia 5426000 0.64 7000 0.13 537 28 Norway 5194000 0.61 57000 1.11 63 29 Ireland 4630000 0.54 16000 0.35 200 30 Croatia 4230000 0.5 -13000 -0.31 - 31 Bosnia and Herzegovina 3750000 0.44 -24000 -0.64 - 32 Georgia 3707000 0.44 -46000 -1.23 - 33 Moldova 3564000 0.42 17000 0.48 145 34 Armenia 3010000 0.35 -1000 -0.03 - 35 Lithuania 2906000 0.34 -25000 -0.85 - 36 Albania 2887000 0.34 -12000 -0.41 - 37 Macedonia 2071000 0.24 3000 0.15 478 38 Slovenia 2065000 0.24 3000 0.15 477 39 Latvia 1979000 0.23 -18000 -0.9 - 40 Estonia 1315000 0.15 6000 0.46 152 41 Cyprus 876000 0.1 4000 0.46 151 42 Montenegro 620000 0.07 0 0 - 43 Luxembourg 570000 0.07 14000 2.52 28 44 Malta 425000 0.05 2000 0.47 147 45 Iceland 331000 0.04 4000 1.22 57 46 Andorra 78000 0.01 1000 1.3 54 47 Liechtenstein 37000 0 0 0 - 48 Monaco 37000 0 0 0 - 49 San Marino 33000 0 0 0 - 50 Vatican City 800 0 0 0 -
2. Copy any job in your JCL library into new PDS/E data set called 'userid.IEBGEN.LIB'. 3. Split EU2015 data set into three members and store them in 'userid.IEBGEN.EUSTATS': - Store first record as LABEL member. - Store 10 most populated countries as TOP10 member. - Store all other countries as OTHER40 member. 4. Join LABEL, TOP10 and OTHER40 members back together and save it as STATS member in 'userid.IEBGEN.EUSTATS'. 5. Reorganize EU2015 data so only following columns are copied in that order: - Country - Annual growth - Population - Use '|' Between columns to separate them additionally. - Process only first 25 countries. - Save result as PS data set 'userid.IEBGEN.STATS2' with appropriate LRECL.
Hint 1
Solution for this exercise is only valid for PCOMM users - most popular software for z/OS terminal emulation. Other emulators also allow simple file transfer between z/OS and you're PC. Alternatively you could use FTP.
Hint 2-5
IEBGENER control statements syntax may be a little bit tricky at first but after getting hang of it it's pretty easy to use. All you need in this Assignment is “JCL Reference” and “DFSMSdfp Utilities” documents.
Solution 1
You must be in panel 6 in ISPF since transmission will issue TSO command. Select 'Action' and then 'Send File To Host'. First you need to configure transmission characteristics - enter 'Options' and go to 'MVS/TSO' tab. Now it's time to select data set characteristics for z/OS. In this case: - Transfer Type: text – our file contains text data. - File options: ascii, crlf – this is standard coding format on PC. If you have different use Notepad++ to convert it. - Record Format: fixed. - Record Length: 120 – enough to store all data from text file. - Block size: 27840 - Space allocation appropriate to file size. File has less than 5000 bytes so one track is enough. Click 'Save', 'Apply' & 'OK'. Now you can select 'text' transmission and file names. Just like in TSO use quotes around file name: 'userid.EU2015.STATS'.' Note: Data is copied from Wikipedia article “List of European countries by population” and copyrights belong to Wikipedia.
Solution 2
JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID //STEP1 EXEC PGM=IEBGENER //SYSPRINT DD SYSOUT=* //SYSIN DD DUMMY //SYSUT1 DD DSN=&SYSUID..MY.CNTL(LISTVTOC),DISP=SHR //SYSUT2 DD DSN=&SYSUID..IEBGEN.LIB(LISTVTOC),DISP=(NEW,CATLG), // LIKE=&SYSUID..MY.CNTL
This is the most common use for IEBGENER – to copy sequential data. The first thing to remember here is that DCB of input and output data sets must be the same, 'LIKE' parameter ensures that in this example. You cannot copy entire PDS with use of IEBGENER but you can work on specific members like in this case.
Solution 3
JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID //STEP1 EXEC PGM=IEBGENER //SYSPRINT DD SYSOUT=* //SYSUT1 DD DSN=&SYSUID..EU2015.STATS,DISP=SHR //SYSUT2 DD DSN=&SYSUID..IEBGEN.EUSTATS,DISP=(NEW,CATLG), // DCB=*.SYSUT1,SPACE=(TRK,(1,1,10)),DSNTYPE=LIBRARY //SYSIN DD * GENERATE MAXNAME=3,MAXGPS=2 MEMBER NAME=LABEL RECORD IDENT=(4,'Rank',1) MEMBER NAME=TOP10 RECORD IDENT=(2,'10',1) MEMBER NAME=OTHER40
In previous example LIKE parameter was used to copy the data set, in here we want to allocate PDS/E with the same DCB as sequential data set to DCB keyword is better choice. - GENERATE – this statement does nothing. See it as variable definition. This job uses 3 MEMBER statements (MAXNAME=3) and 2 RECORD statements (MAXGPS=2). You simply need to communicate this information to IEBGENER. - MEMBER - defines PDS member to which data will be written. - RECORD – each record statement is connected to MEMBER above. There is no such statement for the last member so all unprocessed data will be moved there. - IDENT – this identifies last record that is processed by this statement. In this case last record that will be copied to member defined above. Note that values in there are case-sensitive.
Solution 4
JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID //STEP1 EXEC PGM=IEBGENER //SYSIN DD DUMMY //SYSPRINT DD SYSOUT=* //SYSUT1 DD DISP=SHR,DSN=&SYSUID..IEBGEN.EUSTATS(LABEL) // DD DISP=SHR,DSN=&SYSUID..IEBGEN.EUSTATS(TOP10) // DD DISP=SHR,DSN=&SYSUID..IEBGEN.EUSTATS(OTHER40) //SYSUT2 DD DISP=SHR,DSN=&SYSUID..IEBGEN.EUSTATS(STATS)
Fortunately no control statements needed here. Also remember that members in PDS or PDS/E are always created automatically when you refer them so using DISP=SHR and referencing non-existing member will actually create it. It's like in 3.4 – when you enter data set with 'E' option all you need to create member is to select non-existing name 'S NEWMEM' and it will be opened, but it's actually saved only if you write some data in it.
Solution 5
Before any operation on specific fields it's good practice to copy starting and ending location of the field and then calculate it's length (length=endloc-starloc+1): - Country: 6-28, 23 - Annual growth: 57-72, 16 - Population: 29-40, 12 - 2 more columns needed for '|' separators. So LRECL=53 and BLKSIZE=27984 JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID //STEPDEL EXEC PGM=IEFBR14 //DDDEL DD DSN=&SYSUID..IEBGEN.EUSTATS2, // DISP=(MOD,DELETE,DELETE),SPACE=(TRK,(1,1)) //STEP1 EXEC PGM=IEBGENER //SYSPRINT DD SYSOUT=* //SYSUT1 DD DSN=&SYSUID..EU2015.STATS,DISP=SHR //SYSUT2 DD DSN=&SYSUID..IEBGEN.EUSTATS2,DISP=(NEW,CATLG), // SPACE=(TRK,(1,1)),LRECL=53,BLKSIZE=27984,RECFM=FB //SYSIN DD * GENERATE MAXGPS=1,MAXFLDS=5,MAXLITS=2 RECORD IDENT=(2,'25',1),FIELD=(23,6,,1),FIELD=(1,'|',,24), FIELD=(16,57,,25),FIELD=(1,'|',,41),FIELD=(12,29,,42)
In this example there are also parameters with literals ('|') as separators. Literals also must be defined in GENERATE statement by MAXLITS parameter. If you'll forget to add some parameter in GENERATE statement you'll likely to get “IEB342I INVALID SPACE ALLOCATION” message. This is not data set allocation but rather internal IEBGENER allocation for parameters you use in control statements. In such case you should check parameters in GENERATE statements.
IEBCOPY
Introduction
While IEBGENER is used for working on sequential data IEBCOPY is an Utility focused on libraries – PDS and PDS/E data sets. With it you can copy, split or join libraries. Rename members, make copy in place and also load and unload PDS and PDS/E data sets (load means conversion to sequential format which is needed if you want to save PDS on tape).
Tasks
1. Copy your personal JCL library to PDS named 'userid.IEBCOPY.CNTL'. 2. Select 5 members from 'userid.IEBCOPY.CNTL' to PDS/E named 'userid.IEBCOPY.CNTL2' and rename two of them. 3. Join CNTL and CNTL2 libraries into the former one (CNTL): - Rename manually two members in CNTL2 and modify another one so you can test if copy and replace was done correctly. - Replace members with duplicated names. - Use LIST option to display all processed members. 4. Make copy in place of CNTL library: - Before operation modify few members few times to simulate space fragmentation. - Compare space utilization and extends before and after this operation.
Hint 1-4
Each Utility description in “DFSMSdfp Utilities” has also some examples – they're not always what you want, but analyzing them is the best way to understand Utility processing principles and control statements syntax.
Solution 1
JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID //STEP1 EXEC PGM=IEBCOPY //SYSPRINT DD SYSOUT=* //SYSIN DD DUMMY //SYSUT1 DD DSN=&SYSUID..MY.CNTL,DISP=SHR //SYSUT2 DD DSN=&SYSUID..IEBCOPY.CNTL,DISP=(NEW,CATLG), // DCB=*.SYSUT1,SPACE=(TRK,(3,3,10))
Simple copy operation looks the same way as with IEBGENER. This is also easiest way to convert PDS to PDS/E and the other way around. The difference is that SYSUT1 and SYSUT2 are optional in IEBCOPY and you could also reference those data sets in alternate way:
COPY OUTDD=OUT,INDD=IN
Where IN and OUT are DD names.
Solution 2
JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID //STEP1 EXEC PGM=IEBCOPY //SYSPRINT DD SYSOUT=* //IN DD DSN=&SYSUID..IEBCOPY.CNTL,DISP=SHR //OUT DD DSN=&SYSUID..IEBCOPY.CNTL2,DISP=(NEW,CATLG), // DCB=*.IN,SPACE=(TRK,(3,3,10)),DSNTYPE=LIBRARY //SYSIN DD * COPY OUTDD=OUT,INDD=IN SELECT MEMBER=(EXECMD01,EXECMD02, - INITDASD,LISTVTOC,DEL)
SELECT statement is used for member selection. You can use EXCLUDE statement to copy all of them except few selected ones. Notice how continuation must be specified with IEBCOPY. There must be non-blank character in 72 column and comma at the end of continued parameters. You can also specify few SELECT/EXCLUDE statements in succession, for example following statement would work the same way:
COPY OUTDD=OUT,INDD=IN SELECT MEMBER=(EXECMD01,EXECMD02) SELECT MEMBER=(INITDASD,LISTVTOC,DEL)
Solution 3
JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID //STEP1 EXEC PGM=IEBCOPY //SYSPRINT DD SYSOUT=* //CNTL DD DSN=&SYSUID..IEBCOPY.CNTL,DISP=SHR //CNTL2 DD DSN=&SYSUID..IEBCOPY.CNTL2,DISP=SHR //SYSIN DD * COPY OUTDD=CNTL,INDD=((CNTL2,R)),LIST=YES
Thanks to LIST keyword you can now see in SYSPRINT which members were copied and which were replaced.
Solution 4
JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID //STEP1 EXEC PGM=IEBCOPY //SYSPRINT DD SYSOUT=* //CNTL DD DSN=&SYSUID..IEBCOPY.CNTL,DISP=SHR //SYSIN DD * COPY OUTDD=CNTL,INDD=CNTL
Copy in place does the same thing as compression - it reorganizes place inside PDS data set. So it can fix only one space problem. For other problems you can use CONDENSE or RELEASE ISMF command. Here is how COMPRESS(or copy in place) operation works:
TRK % XT Before 48 100 16 After 48 14 16
IEHLIST
Introduction
IEHLIST is a simple Utility that allows you to read VTOC in both original and user-readable format.
Tasks
1. Display VTOC information about three selected data sets in readable format. Describe following fields in listing: - DIR.REM - EXT - EXTENDS - LOW(C-H) - HIGH(C-H) - SMS.IND - DSCB(C-H-R) - F2 OR F3(C-H-R) 2. Display all possible data about selected PDS/E data set. 3. List entire VTOC of selected volume in readable format. - Convert the job to JCL procedure that accepts Volser as Symbolic Parameter.
Hint 1-2
IEHLIST Utility is described in “DFSMSdfp Utilities”, “Appendix D. IEHLIST VTOC Listing” is also something worth looking at.
Hint 3
To use Symbolic parameters as part of Utility control statements you'll need to use EXPORT statement.
Solution 1
JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID //LISTVTOC EXEC PGM=IEHLIST //SYSPRINT DD SYSOUT=* //ALLOC1 DD DISP=OLD,UNIT=3390,VOL=SER=USRSG1 //ALLOC2 DD DISP=OLD,UNIT=3390,VOL=SER=SSMST1 //SYSIN DD * LISTVTOC FORMAT,VOL=3390=USRSG1,DSNAME=JSADEK.EU2015.STATS LISTVTOC FORMAT,VOL=3390=USRSG1,DSNAME=JSADEK.MY.REXX LISTVTOC FORMAT,VOL=3390=SSMST1,DSNAME=USER.PROCLIB
Before any VTOC listing you must manually allocate volumes you want to check. Also IEHLIST requires that UNIT type in DD statements matches the the one from LISTVTOC control statement (3390 in this example). - DIR.REM – value present only if last directory block in PDS is used. You can use this field to determine if PDS needs to be reallocated (compression doesn't free directory blocks). - EXT – number of data set extends allocated on this volume. If data set is multi-volume actual value can be higher. - EXTENDS – size of data set extends. - LOW(C-H) – start address of extend. - HIGH(C-H) – end address of extend. Example:
NO LOW(C-H) HIGH(C-H) 0 24 5 24 14
C(Cylinder) and H(Head) define extend address on the volume. In above example first extend (0) starts on cylinder 24 track 5 and ends at the same cylinder at track 14 so it has 10 Tracks (14 track is also included). - SMS.IND – SMS attributes, if empty data set is not SMS-managed. - DSCB(C-H-R) – DSCB(Data Set Control Block) is simply an VTOC entry that describes space on the volume. There are ten DSCB types. This field points to the VTOC record that describes main data set characteristic along with it's first three extends (DSCB Format 1 or 8). - F2 OR F3(C-H-R) – this is the address of the next data set extend in VTOC. If data set has more than 3 extends additional extends must be written in separate DSCBs (Format 3).
Solution 2
JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID //LISTVTOC EXEC PGM=IEHLIST //SYSPRINT DD SYSOUT=* //ALLOC1 DD DISP=OLD,UNIT=3390,VOL=SER=USRSG1 //SYSIN DD * LISTVTOC FORMAT,PDSESPACE,VOL=3390=USRSG1,DSNAME=JSADEK.MY.REXX LISTVTOC DUMP,VOL=3390=USRSG1,DSNAME=JSADEK.MY.REXX LISTPDS FORMAT,VOL=3390=USRSG1,DSNAME=JSADEK.MY.REXX LISTPDS DUMP,VOL=3390=USRSG1,DSNAME=JSADEK.MY.REXX
This Task demonstrates what kind of data you can extract with IEHLIST. To extract all possible information you need to use four statements on selected PDS data set.
Solution 3
IEHLIST control statement is very simple in this example. The difficulty lies in right use of EXPORT statement. To specify volser in job that executes the procedure you could simply write:
//STEP1 EXEC LISTVTOC,VOLID=USRSG1
But this method will substitute VOLID variable in JCL code only. In this task we also need to substitute in in IEHLIST control statements:
//LISTVTOC EXEC PGM=IEHLIST //SYSPRINT DD SYSOUT=* //ALLOC1 DD DISP=OLD,UNIT=3390,VOL=SER=&VOLID //SYSIN DD *,SYMBOLS=EXECSYS LISTVTOC FORMAT,VOL=3390=&VOLID
To be able to do that we need z/OS 2.1 later and the EXPORT statement. Here is example of how it is normally used:
//VAREXP EXPORT SYMLIST=(REPHLQ) //VARDEF SET USRHLQ=JSADEK //DELETE EXEC PGM=IDCAMS //SYSPRINT DD SYSOUT=* //SYSIN DD *,SYMBOLS=EXECSYS DEL &USRHLQ..TEST.PDSE1 DEL &USRHLQ..TEST.PDSE2 SET MAXCC=0
You need three things: - EXPORT statement. - SET statement that follows the EXPORT statement. - SYMBOLS=EXECSYS in DD statement where variable will be substituted. Using EXPORT statement in procedure complicates it's usage and it's not normally done but here is the way you can do that. “SYMBOLS=EXECSYS” need to stay in stored procedure but EXPORT and SET statements needs to be moved to the job that executes the procedure:
//JSADEK01 JOB NOTIFY=&SYSUID // JCLLIB ORDER=(&SYSUID..JCLUTIL.CNTL) // EXPORT SYMLIST=(VOLID) // SET VOLID=USRSG1 //STEP1 EXEC LISTVTOC
IEBDG
Introduction
IEBDG (Test Data Generator) is an utility used mainly for filling up data set with generic data that can be used for testing your programs/scripts. You can also reorganize data of existing data set and modify it.
Tasks
1. Generate data set with 2000 records: - First column (6 chars) should store record number (1-2000). - Second column (20 chars) should store string "Empty Record". - Third column (10 chars) should store 10 digits '0'. - Separate each column with ';'. 2. Copy use IEBDG to copy only first 4 columns from 'userid.EU2015.STATS'. In 'Population[%]' column replace all values with '00.00'.
Hint 1-2
IEBDG is another Utility with pretty tricky control statements syntax. So it's best to go straight for the examples presented in “DFSMSdfp Utilities”.
Solution 1
JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID //STEP1 EXEC PGM=IEBDG //SYSPRINT DD SYSOUT=* //GENDATA DD DSN=&SYSUID..IEBDG.TEMPLATE,DISP=(NEW,CATLG), // SPACE=(TRK,(30,30),RLSE),RECFM=FB,LRECL=38,BLKSIZE=7600 //SYSIN DD * DSD OUTPUT=(GENDATA) FD NAME=F1,LENGTH=6,STARTLOC=1,FORMAT=ZD,INDEX=1 FD NAME=F2,LENGTH=20,STARTLOC=8,FILL=X'40',PICTURE=12,'Empty Record' FD NAME=F3,LENGTH=10,STARTLOC=29,FILL='0' FD NAME=F4,LENGTH=1,STARTLOC=7,FILL=';' FD NAME=F5,LENGTH=1,STARTLOC=28,FILL=';' CREATE QUANTITY=2000,FILL=X'40',NAME=(F1,F2,F3,F4,F5) END
- INDEX – specifies that number in each record will be iterated by 1. - DSD – defines input and output data. - FILL – in CREATE statement it ensures that columns not generated by any FD statement will be filled with spaces. - NAME – you must define which FD statements will be used for particular set of record. You can use different FD definitions in different CREATE statements.
Solution 2
JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID //STEP1 EXEC PGM=IEBDG //SYSPRINT DD SYSOUT=* //STATS DD DSN=&SYSUID..EU2015.STATS,DISP=SHR //GENDATA DD DSN=&SYSUID..IEBDG.TEMPLATE,DISP=(NEW,CATLG), // SPACE=(TRK,(30,30),RLSE),RECFM=FB,LRECL=54,BLKSIZE=5400 //SYSIN DD * DSD OUTPUT=(GENDATA),INPUT=(STATS) FD NAME=F1,LENGTH=54,STARTLOC=1,INPUT=STATS,FROMLOC=1 FD NAME=F2,LENGTH=5,STARTLOC=41,PICTURE=5,'00.00' CREATE QUANTITY=1,FILL=X'40',NAME=(F1),INPUT=STATS CREATE QUANTITY=50,FILL=X'40',NAME=(F1,F2),INPUT=STATS END
Another use of IEBDG is simple data reorganization and modification. So if you also want to clear some values from file or replace them like in this example IEBDG is a good choice. If you need to work only on specific record ranges you need to use multiple CREATE statements. First line is simply copied and truncated, next 50 records are also modified by 'F2' FD statement.
IEBUPDTE
Introduction
IEBUPDTE is an Utility used for data set modification. With it you can insert, remove or replace records in sequential data sets and members. It can be also used from data set conversion between PDS, PDS/E and PS data sets.
Tasks
1. Copy two jobs from your JCL library to 'userid.IEBUPDTE.CNTL'. - Add third member - use IEBUPDTE 'Data Statement' to create DEL member containing:
//DEL EXEC PGM=IEFBR14 //DELDD DD DISP=(MOD,DELETE,DELETE),SPACE=(TRK,1), // DSN=...
2. Modify DEL member by: - Renumerate it so records numeration follow convention: 100, 200, 300... - Insert two lines of comments after EXEC statement. - Replace the last line so it refers to some existing data set.
Hint 1-2
IEBUPDTE control statement syntax is the least intuitive off all IEB* and IEH* Utilities so it's best to start with examples included in “DFSMSdfp Utilities”.
Solution 1
JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID //STEP1 EXEC PGM=IEBUPDTE //SYSPRINT DD SYSOUT=* //SYSUT1 DD DSN=&SYSUID..MY.CNTL,DISP=SHR //SYSUT2 DD DSN=&SYSUID..IEBUPDTE.CNTL,DISP=(NEW,CATLG), // LIKE=&SYSUID..MY.CNTL //SYSIN DD DATA,DLM=## ./ REPRO NAME=LISTVTOC ./ REPRO NAME=PROCTEST ./ ADD NAME=DEL,LIST=ALL //DEL EXEC PGM=IEFBR14 //DELDD DD DISP=(MOD,DELETE,DELETE),SPACE=(TRK,1), // DSN=... ##
IEBUPDTE has for main functions, each of them can work both on sequential data sets, PDS or PDS/E. Unfortunately it can process only data sets with LRECL=80. - ADD – adds new member. - REPRO – copies member/data set. - REPL – replaces member/data set. - CHANGE – modifies member/data set.
Solution 2
JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID 00010000 //STEP1 EXEC PGM=IEBUPDTE,PARM=MOD 00020002 //SYSPRINT DD SYSOUT=* 00030000 //SYSUT1 DD DSN=&SYSUID..IEBUPDTE.CNTL,DISP=SHR 00040001 //SYSUT2 DD DSN=&SYSUID..IEBUPDTE.CNTL,DISP=SHR 00041001 //SYSIN DD DATA,DLM=## 00050002 ./ CHANGE NAME=DEL ./ NUMBER SEQ1=ALL,NEW1=100,INCR=100 ./ CHANGE NAME=DEL ./ NUMBER SEQ1=100,NEW1=200,INCR=100,INSERT=YES //* SOME JCL COMMENT #1 //* SOME JCL COMMENT #2 ./ CHANGE NAME=DEL ./ NUMBER SEQ1=ALL,NEW1=100,INCR=100 // DSN=JSADEK.TEST.DATA 00000500 ##
When you add, update or remove records in existing data set or member you must be aware of record numeration of target data set – IEBUPDTE uses it to identify records. When you insert or remove records it's enough to specify record number in NUMBER/DELETE statement. But if you update it you need to additional supply record number at the end of the record as shown in the last line, before delimiter. First CHANGE/NUMBER statement renumerate records in DEL member. Thanks to it we ensured that each line has clearly defined record number. You can issue 'NUM OFF' command to display numeration of DEL member, most likely it's in different format or doesn't exist at all. INSERT=YES defines that records included in data section will be inserted after record with number 100. If you don't use this keyword IEBUPDTE will try to modify record with number defined in data section like in the last CHANGE/NUMBER statements.
IEBCOMPR
Introduction
IEBCOMPR Utility is used for data comparison between sequential, PDS and PDS/E data sets. It's mainly used for two purposes: - Verification if backup copy is identical on byte level. - Comparison data set for differences – for example what was modified between current data set and it's backup copy.
Tasks
1. Copy 'userid.EU2015.STATS' via 3.4 and use IEBCOMPR to compare two copies: - Without any modification. - With few modified characters in random lines. 2. Consider situation in which a job step can run only if specific string is present in member 'userid.IEBCOMPR.TEST(MEMX)'. Write a two step job where second step is executed only if desired string is found in 'MEMX' member.
Hint 1-2
IEBCOMPR Utility signalizes that compared data sets are different by ending with RC=8 so it's not actually an error in case of this Utility. It's described in “DFSMSdfp Utilities”.
Solution 1
JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID //STEP1 EXEC PGM=IEBCOMPR //SYSPRINT DD SYSOUT=* //SYSUT1 DD DISP=SHR,DSN=&SYSUID..EU2015.STATS //SYSUT2 DD DISP=SHR,DSN=&SYSUID..EU2015.STATS.COPY //SYSIN DD DUMMY
IEBCOMPR ends with return code 0 only if both data sets are identical. When you modify Copy data set Utility will end with RC=8 and in SYSPRINT you'll find which records vary from each other. Unfortunately IEBCOMPR lists record that vary from each other in hexadecimal format. So it's best to simply copy line number and then compare it viewing the original data. Note: In ISPF Editor you can issue 'HEX ON/OFF' command to display records in hexadecimal format.
Solution 2
JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID //COMP1 EXEC PGM=IEBCOMPR //SYSPRINT DD SYSOUT=* //SYSUT1 DD * Member X //SYSUT2 DD DISP=SHR,DSN=&SYSUID..IEBCOMPR.TEST(MEMX) //SYSIN DD DUMMY //STEP1 EXEC PGM=IEFBR14,COND=(0,NE)
JCL is pretty much the same, simple COND parameter ensures that STEP1 won't be executed if MEMX contents does not match in-stream data. When comparing data sets with In-Stream data you must remember about line numeration. Issue 'NUM OFF' command in ISPF Editor to display them. Usually numeration is not a problem but sometimes you may need to remove it, here is command that will do that in no time: - “C P'=' X'40' ALL 73 80” – it replaces all characters between columns 73 and 80 with spaces. When you issue 'NUM ON' or 'RENUM' command numeration will be defined again.
IEHPROGM
Introduction
IEHPROGM is small Utility that has three functions: - Scratching data sets and members. - Renaming data sets and members. - Maintaining data set passwords. Nowadays data set access is maintained by RACF or alternate security products so passwords are very rarely used so it's mainly useful for renaming and removing data sets and especially members since IEBCOPY lacks those operations.
Tasks
1. Use 3.2 panel to allocate PDS data set with three members - MEM1, MEM2 & MEM3: - Rename MEM1 and MEM2 to MEMX1 and MEMX2. - Remove MEM3. 2. Consider situation in which sequential data set has used all it's available space and you need to reallocate it with twice the original space. - Use IEHPROGM to rename current data set to 'dsname.BACKUP'. - Use IEBGENER to copy it's content to larger data set with it's original name. - Use IEBCOMPR to verify if both data sets are identical. - If yes, use IEHPROGM to remove 'dsname.BACKUP1' data set. - On z/OS 2.1 or later - use Symbolics and EXPORT statement to define data set name and volser.
Hint 2
If you use z/OS 2.1 it's good practice to take advantage of EXPROT statement and define both data set name and volser as symbolic parameter. This way you need to change JCL only in two places to rerun the job for different data set. See “JCL Reference” for more information about EXPORT statement. When using Symbolics in-stream you should remember about it's possible length. After substitution records will be longer and sometimes can overflow beyond 71 column.
Solution 1
JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID //STEP1 EXEC PGM=IEHPROGM //SYSPRINT DD SYSOUT=* //DD1 DD DISP=OLD,UNIT=3390,VOL=SER=USRSG1 //SYSIN DD * RENAME DSNAME=JSADEK.IEHPROGM.PDS,VOL=3390=USRSG1, X NEWNAME=MEMX1,MEMBER=MEM1 RENAME DSNAME=JSADEK.IEHPROGM.PDS,VOL=3390=USRSG1, X NEWNAME=MEMX2,MEMBER=MEM2 SCRATCH DSNAME=JSADEK.IEHPROGM.PDS,VOL=3390=USRSG1,MEMBER=MEM3
IEHPROGM still uses old fashioned continuation syntax. To continue it's control statements you need to put non-blank character in column 72 and parameters in next line must start in column 16.
Solution 2
JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID //VAREXP EXPORT SYMLIST=(DS,VS) //VARDEF SET VS=USRSG1, <--- SUPPLY VOLSER // DS=JSADEK.EU2015.STATS <--- SUPPLY DSNAME //BACKUP EXEC PGM=IEHPROGM //SYSPRINT DD SYSOUT=* //DD1 DD DISP=OLD,UNIT=3390,VOL=SER=&VS //SYSIN DD *,SYMBOLS=EXECSYS RENAME DSNAME=&DS,VOL=3390=&VS, X NEWNAME=&DS..BACKUP // IF (RC=0) THEN //COPY EXEC PGM=IEBGENER //SYSPRINT DD SYSOUT=* //SYSIN DD DUMMY //SYSUT1 DD DSN=&DS..BACKUP,DISP=SHR //SYSUT2 DD DSN=&DS,DISP=(NEW,CATLG),VOL=SER=&VS, // LIKE=&DS..BACKUP,SPACE=(CYL,(40,20)) <--- CHECK SPACE // ENDIF // IF (RC=0) THEN //VERIFY EXEC PGM=IEBCOMPR //SYSPRINT DD SYSOUT=* //SYSUT1 DD DISP=SHR,DSN=&DS //SYSUT2 DD DISP=SHR,DSN=&DS..BACKUP //SYSIN DD DUMMY // ENDIF // IF (RC=0) THEN //DELCOPY EXEC PGM=IEHPROGM //SYSPRINT DD SYSOUT=* //DD1 DD DISP=OLD,UNIT=3390,VOL=SER=&VS //SYSIN DD *,SYMBOLS=EXECSYS SCRATCH DSNAME=&DS..BACKUP,VOL=3390=&VS // ENDIF
It's a good practice to include comments in the lines that should be checked before job run. This type of commenting is very clear and ensures that you check/modify every parameter that may require modification.
ISRSUPC
Introduction
ISRSUPC is another compare Utility but unlike IEBCOMPR it's main purpose not verification of backup copies but rather visual comparison of changes between two copies of the same data set/member. It also provides more control statements that, for example, enable you to compare only specific areas/records/columns in data sets. Second and even more useful function is “Search For” program which you can use from 3.4 panel, batch job or dedicated ISPF panels.
Tasks
1. Use ISRSUPC Utility via ISPF to compare original 'userid.EU2015.STATS' with: - The exact copy. - Copy in which you've inserted one record, removed two and modified three other records. - Enter 'userid.EU2015.STATS' in ISPF Editor and use COMPARE command to compare it with modified copy. 2. Run ISRSUPC via batch to: - Compare exact copies. - Compare copies that differ from each other. - Compare only first 10 records. - Compare only 'Annual growth' column. 3. Use SRCHFOR command to search: - All data sets under your HLQ for your TSO user ID. - Your JCL library for 'IEBGENER' keyword. 4. Use ISRSUPC Utility via batch job to find: - VTAM startup procedure in your PROCLIB concatenation. - If one of the PROGxx members (choose any) is referenced anywhere in the PARMLIB concatenation.
Hint 1-2
SuperC Utility (ISRSUPC) can be used from ISPF panels (option 3.12 by default). It's documented in “Appendix A” of “ISPF User's Guide Volume II”. Similarly to IEBCOMPR if compared data sets are identical ISRSUPC will end with RC=0. If there are differences it will end with RC=1.
Hint 3-4
You can use Search-For function in three ways: - Batch job. - ISPF option 3.14 and 3.15. - SRCHFOR command.
Solution 1
ISRSUPC Utility is normally available vie ISPF panel 3.12 and 3.13. Basic option (3.12) is all that you need here and probably all that you'll ever use. It's good to specify latest copy in first panel since utility uses 'New' and 'Old' words to identify each data set. Produced reports show not only modified lines but also points out what lines were added or deleted which is something that IEBCOMPR cannot do. ISPF also offers COMPARE command you can issue from EDIT panel:
000001 Rank Country 000002 1 Russia ====== 2 Ger3any .OAAAA 2 Germany
After issuing it dialog appears when you can specify compare options and data set to compare. Now lines from second file are shown with '======' label so you can clearly see the differences. In the original data set labels '.OAAAA' are added. To get back to the original view simply issue 'RES' command. You can even compare it with UNIX files by using '/' instead of data set name.
Solution 2
JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID //STEP1 EXEC PGM=ISRSUPC,PARM=('LINECMP,DELTAL') //OLDDD DD DISP=SHR,DSN=&SYSUID..EU2015.STATS //NEWDD DD DISP=SHR,DSN=&SYSUID..EU2015.STATS.C2 //OUTDD DD SYSOUT=* //SYSIN DD DUMMY
This is basic version of data set compare. It's also default option for 3.12 panel. We compare entire lines 'LINECMP' but you can also test 'FILECMP', 'WORDCMP' or 'BYTECMP' options. Second option specifies listing type - 'DELTA' means that only lines that differ from each other will be shown in output. Comparison of the first 10 records:
//SYSIN DD * CMPLINE TOP 1 BTM 10
Comparison of 'Annual growth' column:
//SYSIN DD * CMPCOLM 57:72
Solution 3
This is the most useful function of ISRSUPC Utility. You can search list of data sets in 3.4 as well as members of specific PDS or PDS/E. If you're searching all data sets starting with your HLQ you are likely to encounter error. It's because full list also includes Alias of your TSO user. You can easily overcome that problem by using 'JSADEK.*' mask in 3.4. The command syntax is very simple: 'SRCHFOR JSADEK' It's especially useful when you need to find particular job but don't remember in which member it's stored. In such case you can search for Utility used in that job or particular data set name. Another common use is searching PARMLIBs and PROCLIBs for particular parameters, volumes or startup procedures. Note: SRCHFOR command searches for particular string in data sets/members. Often what you need is to simply find a member with specific name. In this case you 'M' command in 3.4 panel or ISRDDN utility.
Solution 4
SRCHFOR is usually used from 3.4 panel but running it via batch job has two advantages: - It runs significantly faster which is especially important when searching many large data sets. - In 3.4 panels you are restricted to using masks, in batch job you can concatenate any data sets you want. JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID //SEARCH EXEC PGM=ISRSUPC,PARM=('SRCHCMP,ANYC') //SYSIN DD * SRCHFOR '//VTAM ' //OUTDD DD SYSOUT=* //NEWDD DD DISP=SHR,DSN=USER.TEST.PROCLIB // DD DISP=SHR,DSN=USER.PROCLIB --- other PROCLIBs --- // DD DISP=SHR,DSN=SYS1.PROCLIB
If it ends with RC=1 it means that string was found. When searching for jobs or procedures it's worth using '//' so you'll get more accurate matches. In Utility output data sets in concatenation are not referenced directly but via 'CONCAT#(2)' keyword. It means that result was found in second data set in concatenation so in above example in 'USER.PROCLIB'. You can also search for many words at the same time:
SRCHFOR 'PROGX3' SRCHFOR 'X3',W
Members in PARMLIBs are often referenced by suffix so this is also what you should look for. 'W' means that ISRSUPC will look for WORD 'X3'. This means that space, comma, dot, braces etc. must separate it from other letters and numbers.
IKJEFT*
Introduction
TSO provides three Utilities that can be used for issuing TSO commands via batch job: IKJEFT01, IKJEFT1A and IKJEFT1B.
Tasks
1. What's the differece between IKJEFT01, IKJEFT1A and IKJEFT1B? 2. Use each of IKJEFT* Utility to execute two commands: - First should execute non existing command, for example 'C2LL'. - Second one should allocate 'userid.IKJEFT.TESTx' data set. 3. Use IKJEFT1B to execute following REXX:
/* REXX */ SAY "TEST REXX EXECUTION..." SAY "679 * 33 = "679 * 33
- Include REXX code in JCL code. - Save it's output in data set called 'userid.REXXOUT.Dyymmdd.Thhmmss'. 4. Execute IDCAMS via IKJEFT1B: - Allocate all DD statements required by IDCAMS in the same step you execute IKJEFT1B. - Use 'SET MAXCC' IDCAMS statement to set RC to 7. - Execute IDCAMS via TSO CALL command.
Hint 1-2
IKJEFT* Utilities are described in detail in “TSO/E Customization” document. The only real difference is how they handle error and abend codes from command execution. You'll also need few TSO commands which are documented in “TSO/E Command Reference”.
Hint 3
To execute REXX code via TSO you need to allocate data set containing the script to SYSEXEC DD statement or use fully qualified name in the 'EXEC' TSO command. To include REXX code in JCL you'll need to first copy it to temporary data set, for example with IEBGENER. If you're not able to use System Symbols check SYSSYM parameter in Job Class definition.
Hint 4
The command you're looking for is 'CALL *(IDCAMS)'. You can read more about this command in “TSO/E Command Reference”.
Solution 1
IKJEFT01: - Error - Utility continues processing and after all commands are processed in ends with RC equal to the return code of the last executed command. - System Abend – Utility ends with RC=12. - User Abend – Utility ends with RC=12. IKJEFT1A: - Error – Utility ends with the same error code as failed command. - System Abend - Utility ends with 'S04C' Abend. - User Abend – Utility ends with RC of the Abend. IKJEFT1B: - Error – Utility ends with the same error code as failed command. - System Abend - Utility ends with 'S04C' Abend. - User Abend – Utility ends with 'S04C' Abend. The difference between IKJEFT1A and IKJEFT1B is cosmetic. IKJEFT01 is usually the worst choice since it will execute all commands specified in SYSTSIN even if they end in error, this is rarely desired behavior. Knowing the differences it usually best to simply use IKJEFT1B.
Solution 2
JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID //STEP1 EXEC PGM=IKJEFT01 //SYSTSPRT DD SYSOUT=* //SYSTSIN DD * C2LL ALLOC DDNAME(SYSUT2) DSNAME('JSADEK.IKJEFT.TEST1') NEW CATALOG - BLKSIZE(8000) LRECL(80) RECFM(F,B) SPACE(1,1) TRACKS
Standard TSO commands continuation ('-' or '+') is also used while executing them via IKJEFT* Utilities. Data set was allocated only by IKJEFT01, this Utility processes all commands even if some of them end in error like in this example. IKJEFT1A and IKJEFT1B both ended with RC=12 and ALLOC command wasn't executed.
Solution 3
JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID //REXXDEF EXEC PGM=IEBGENER //SYSPRINT DD SYSOUT=* //SYSIN DD DUMMY //SYSUT1 DD * /* REXX */ SAY "TEST REXX EXECUTION..." SAY "679 * 33 = "679 * 33 //SYSUT2 DD DSN=&&TEMP(TEMPMEM),DISP=(NEW,PASS),SPACE=(TRK,(3,1,3)), // LRECL=80,RECFM=FB,BLKSIZE=8000 //REXXEXEC EXEC PGM=IKJEFT1B,COND=(0,NE) //SYSEXEC DD DISP=(OLD,DELETE),DSN=&&TEMP //SYSTSPRT DD DSN=&SYSUID..REXXOUT.D&YYMMDD..T&HHMMSS,DISP=(NEW,CATLG), // LRECL=80,RECFM=FB,BLKSIZE=27920,SPACE=(TRK,(5,5),RLSE) //SYSTSIN DD * %TEMPMEM
If you want to define REXX inside job you must still copy it to data set. You can use IEBGENER for this purpose. To execute REXX or CLIST via TSO you can simply use '%TEMPMEM'. It will search for member of that name in SYSEXEC and SYSPROC DD statements. Without '%' TSO would still execute the script but it would first search if there is TSO command called TEMPMEM. So '%' simply speeds up search order.
Solution 4
JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID //STEP1 EXEC PGM=IKJEFT1B //SYSPRINT DD SYSOUT=* //SYSIN DD * SET MAXCC=7 //SYSTSPRT DD SYSOUT=* //SYSTSIN DD * CALL *(IDCAMS)
You can see why DD statements for IKJEFT* doesn't follow standard SYSIN/SYSPRINT naming convention. See DD statements as pool of allocated data sets to a particular step – just like you TSO user session has pool of allocated DDs you can view with 'TSO LISTALC' command or ISRDDN. Executing IDCAMS from the same step is possible because it has access to all DDs allocated to the step and searches for the ones it needs (SYSIN and SYSPRINT). When IDCAMS Dds are allocated all you need is TSO CALL command. '*' char means that standard program search will be performed, so LPA & LINKLIST will be searched for program called IDCAMS.
SDSF
Introduction
SDSF is very powerful tool in z/OS. It not only allows easy JES2 and Spool interaction but also provides interface to master console and other system functions. Since z/OS 2.1 you can also view various System Concatenation via SDSF such as LPA, LINKLIST, APF and PARMLIB. Good news is that SDSF provides Utility that enables you to use SDSF function via batch job. REXX also has it's API for SDSF functions but in this exercise we'll focus on SDSF Utility.
Tasks
1. Use SDSF Utility to display: - When system was IPLed last time. - All users logged on the system. - Spool Utilization. - Status of SMF data sets. - Status of Page data sets. 2. Modify previous job to store commands output in User Log and then print it to 'userid.SDSF.CMDOUT' with SDSF 'PRT' command. 3. Print SYSLOG records for chosen two hour period from yesterday (or today if SYSLOG is offloaded daily). 4. Display all jobs having your ID as prefix. Also display JES2 Resources. Save output in spool. 5. Display all jobs having your ID as prefix: - Filter them so only older than three days are displayed. - After ensuring that only desired outputs are selected – modify job so it purges them.
Hint 1-5
All you need for this Assignment is “Using SDSF in batch” chapter in “SDSF Operation and Customization”.
Hint 3
You'll need to know full syntax of PRT command. SDSF doesn't have “Command Reference” manual. All it's commands are described in built-in help available via PF1.
Hint 5
Before playing with Purge command make sure only correct jobs are selected. You'll need to use block command to purge all selected outputs.
Solution 1
JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID //STEP1 EXEC PGM=SDSF //ISFOUT DD SYSOUT=* //ISFIN DD * /D IPLINFO /D TS,L /$DSPL /D SMF /D ASM
Job like this can be used to automate often performed tasks Usually REXX or CLIST is better solution but for simple tasks SDSF is also fine.
Solution 2
JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID //STEP1 EXEC PGM=SDSF //ISFOUT DD SYSOUT=* //ISFIN DD * U U CLOSE U /D IPLINFO /D TS,L /$DSPL /D SMF /D ASM PRT ODSN 'JSADEK.SDSF.CMDOUT' * N PRT * 999999999 PRT CLOSE
When printing User or System Log you must specify which records to print. If you want to print entire log you can simply use 'PRT * 999999999'.
Solution 3
JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID //STEP1 EXEC PGM=SDSF //ISFOUT DD SYSOUT=* //ISFIN DD * LOG S PRT ODSN 'JSADEK.SDSF.SYSLOG' * N PT 20.30.00 01/01/2017 22.30.00 01/01/2017 PRT CLOSE
SDSF Utility is the easiest way for printing SYSLOG to data set. Full PRINT command systax is available in SDSF built-in help. The fastest way to find command syntax: - PF1 – enters SDSF help. - I – enters alphabetical index of SDSF help. - P – jump to topics starting with 'P'. - Now you can scroll down (with enter, not PF8) and find PRINT command description.
Solution 4
JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID //STEP1 EXEC PGM=SDSF,PARM='++30,400' //ISFOUT DD SYSOUT=* //ISFIN DD * PRE JSADEK* ST ++ALL RM
This exercise shows how to ensure that all data in the panel is included in output: - PARM='++30,400' – sets record length to 400 so all columns in 'Job class' panel are printed. - ++ALL – this is command that ensures that all records are displayed. In case of RM it's not a problems but you can have hundreds of jobs in ST panel. ALL parameter ensures all of them are displayed in SDSF Utility output.
Solution 5
JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID //STEP1 EXEC PGM=SDSF //ISFOUT DD SYSOUT=* //ISFIN DD * PRE JSADEK* O FIL END-DATE LT 2017.001 SET CONFIRM OFF F JSADEK FIRST ++//P F JSADEK LAST ++//
This is not something you'll do often with SDSF Utility – it's done much easier with JES2 command: '$POJQ,JM=JSADEK*,A>3'. This exercise just demonstrates how to use work on specific entries and how to use block commands in SDSF Utility.
BPXBATCH
Introduction
BPXBATCH is an Utility used for executing UNIX commands and scripts via batch job or TSO/E session. On z/OS USS (UNIX System Services) are the integral part of the system and much of the software running under z/OS requires UNIX. BPXBATCH DD statements can be loosely compared to IEBGENER DDs. BPXBATCH is a program used for invoking other programs/commands/scripts so such comparison is not exactly accurate, but still you can map them in following way: - STDIN – SYSUT1: input data. - STDOUT – SYSUT2: output data. - STDERR – SYSPRINT: result of script/program execution. - STDPARM – SYSIN: control statements/parameters for Utility execution. - STDVAR – variable definitions. Unlike IEBGENER all of those DDs are optional so you don't need to code them if you don't use them.
Tasks
1. Execute UNIX 'sleep' command with BPXBATCH. - Set sleep to ten minutes and find it in DA and then in PS SDSF panels. What's the structure of the job? - Cancel the job from running. 2. Issue three UNIX commands: 'cat file', 'sleep 15', 'whoami'. - Issue them one after another. - Issue them one after another but only if previous one ends successfully. - Issue all of them at the same time. - Test each of those three versions with existing and non-existing file in 'cat' command so you can check your job behavior in case of error. 3. Display content of your UNIX user catalog: - Find appropriate commands in documentation. - Supply it via PARM keyword. - Supply it via PARMDD keyword. - Supply it via STDPARM statement as in-stream data set. - Supply it via STDPARM statement as MVS data set. - Supply it via STDPARM statement as UNIX file. 4. Use BPXPATCH to create following files/catalogs in your user catalog: - 'stdio' catalog - 'My Data' catalog - 'test.sh' file with 'rwxrwxrwx' rights. - 'Test Data.txt' in 'My Data' catalog with rw-rw-rw-' rights. 5. Perform following file operations: - Copy 'userid.EU2015.STATS' data set to 'Test Data.txt' file you've created in Task#4. - Change access rights to 'Test Data.txt' so it cannot be modified anymore. - Create new catalog 'Jobs' in your user catalog and copy members from your JCL Library in there.
Hint 1
UNIX commands are described in “UNIX System Services Command Reference” and BPXBATCH in “UNIX System Services User's Guide”. Remember that UNIX unlike z/OS is designed to be case-sensitive so make sure you have 'CAPS OFF' in your editor session and pay attention to command syntax.
Hint 2
Check “sh — Invoke a shell” chapter of “UNIX System Services Command Reference”.
Hint 3
In z/OS 2.1 you can display UNIX file system via 3.4 ISPF panel. Use '/' character instead of data set name. User catalogs are in '/u' catalog. If you don't have user catalog – contact your System Administrator to create it. You can also access UNIX directly via 'TSO OMVS' command. “exit” command is used to leave Shell. Remember that when you use in-stream data in STDPARM or STDIN statements you should ensure that numeration in ISPF editor is turned off. Issue 'NUM OFF' command and remove it or commands will fail.
Solution 1
JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID //UNIXSTEP EXEC PGM=BPXBATCH,PARM='SH sleep 300'
If your goal is to simply issue UNIX command you don't need any DD statement. You can simply pass the command via PARM keyword. After job start you'll notice that you've also started an STC:
JOBNAME StepName ProcStep JobID JSADEK01 *OMVSEX JOB05921 JSADEK01 STEP1 STC05913
And in PS panel you'll find:
JOBNAME JobID Status JSADEK01 STC05913 SWAPPED,SLEEPING JSADEK01 JOB05921 SWAPPED,WAITING FOR CHILD
PS panel shows UNIX processes. You can see that the job you've executed actually uses two address spaces. First in initiator address space in which BPXBATCH runs (JOB*). Second address space is it's child process. In this case it's simply “sleep 300” UNIX command (STC*). In PS panel you can see both of them along with their PIDs (UNIX Process ID). If you decide to cancel JOB address space BPXBATCH will end along with all it's child processes. If you cancel STC address space you'll only kill “sleep” command. And BPXBATCH will continue to execute (or end in error). You can see the difference while issuing many commands at the same time:
//JSADEK01 JOB NOTIFY=&SYSUID //UNIXSTEP EXEC PGM=BPXBATCH,PARM='SH sleep 10 && sleep 15 && sleep 20'
You'll notice that this time job starts three STCs. You can cancel any of those tasks and it will not affect other processes:
JOBNAME JobID Status PID PPID JSADEK01 STC05938 SWAPPED,SLEEPING 16842801 67174445 JSADEK01 STC05932 SWAPPED,SLEEPING 50397230 67174445 JSADEK01 STC05935 SWAPPED,SLEEPING 50397231 67174445 JSADEK01 JOB05941 SWAPPED,WAITING FOR CHILD 67174445 1
PID – Process ID – every command and BPXBATCH is a separate UNIX process. PPID – here you can see that all command are child JOB05941(BPXBATCH process) while BPXBATCH is a child of BPXOINIT task which runs with PID=1.
Solution 2
Issuing one command after another:
//JSADEK01 JOB NOTIFY=&SYSUID //UNIXSTEP EXEC PGM=BPXBATCH //STDOUT DD SYSOUT=* //STDERR DD SYSOUT=* //STDPARM DD * SH cat /u/jsadek/test.txt ; sleep 15 ; whoami
Issuing one command after another only if previous one ends successfully:
SH cat /u/jsadek/test.txt && sleep 15 && whoami
Issuing all commands at the same time:
SH cat /u/jsadek/test.txt & sleep 15 & whoami
Solution 3
Using PARM:
//JSADEK01 JOB NOTIFY=&SYSUID //UNIXSTEP EXEC PGM=BPXBATCH,PARM='SH cd /u/jsadek ; ls -l' //STDOUT DD SYSOUT=* //STDERR DD SYSOUT=*
Unlike 'sleep' command now we have some output so STDOUT needs to be defined. STDERR also can come in handy in case of errors. Using PARMDD:
//JSADEK01 JOB NOTIFY=&SYSUID //UNIXSTEP EXEC PGM=BPXBATCH,PARMDD=DDPARM //STDOUT DD SYSOUT=* //STDERR DD SYSOUT=* //DDPARM DD * SH cd /u/jsadek ; ls -l
Using STDPARM with in-stream data:
//JSADEK01 JOB NOTIFY=&SYSUID //UNIXSTEP EXEC PGM=BPXBATCH //STDOUT DD SYSOUT=* //STDERR DD SYSOUT=* //STDPARM DD * SH cd /u/jsadek ; ls -l
It's pretty much the same as job with PARMDD. The difference is that with STDPARM you can define 65k characters so you can even put UNIX scripts in here. Also remember that numeration will cause the problem, ensure that JCL code don't use it - 'NUM OFF' command. Using STDPARM with MVS file:
//JSADEK01 JOB NOTIFY=&SYSUID //UNIXSTEP EXEC PGM=BPXBATCH //STDOUT DD SYSOUT=* //STDERR DD SYSOUT=* //STDPARM DD DISP=SHR,DSN=&SYSUID..BPXBATCH.CMD1
Using STDPARM with UNIX file:
//JSADEK01 JOB NOTIFY=&SYSUID //UNIXSTEP EXEC PGM=BPXBATCH //STDOUT DD SYSOUT=* //STDERR DD SYSOUT=* //STDPARM DD PATH='/u/jsadek/test.txt',PATHOPTS=(ORDONLY)
With PATH DD parameter you can easily access any UNIX file via batch job.
Solution 4
JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID //UNIXSTEP EXEC PGM=BPXBATCH //STDOUT DD SYSOUT=* //STDERR DD SYSOUT=* //STDPARM DD * SH cd /u/jsadek && mkdir stdio && mkdir 'My Data' && touch test.sh && chmod 777 test.sh && touch 'My Data/Test Data.txt' && chmod 666 'My Data/Test Data.txt'
BPXBATCH is also great for for create simple command list like this one. Most activity in z/OS UNIX are pretty easy and can be easily automatized this way.
Solution 5
JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID //UNIXSTEP EXEC PGM=BPXBATCH //STDOUT DD SYSOUT=* //STDERR DD SYSOUT=* //STDPARM DD * SH cp "//'JSADEK.EU2015.STATS'" "/u/jsadek/My Data/Test Data.txt" && chmod 444 "/u/jsadek/My Data/Test Data.txt" && mkdir "/u/jsadek/Jobs" && cp "//'JSADEK.JCLUTIL.CNTL'" "/u/jsadek/Jobs"
You can also access z/OS files from UNIX level. '//' must be specified before fully qualified data set name. When copying PDS and PDS/E each members becomes one UNIX file.
IDCAMS
Introduction
IDCAMS is mainly used for operations on VSAM data sets and Catalogs but you can also use it for standard activities like data set copy. You can also define VSAM data sets via JCL DD statement but not all parameters can be specified that way so it's always better to use IDCAMS while working on VSAM data sets. It's worth remembering that some of the IDCAMS functionality can used via 3.2;V ISPF panel (VSAM Utilities).
Tasks
1. Create GDG: - Set limit to 5. - Only the oldest generation should be scratched after limit is reached. - In the next step use REPRO to add few generations of various data sets (PS, PDS & PDS/E) to the GDG. 2. Remove GDG: - Remove all Generation data sets first. - If Generation data sets removal was unsuccessful end IDCAMS with CC=10. - Remove GDG Base only if generation removal was successful. - If GDG Base deletion was unsuccessful end IDCAMS with CC=11. 3. Join all offloaded SMF logs from yesterday into single data set. 4. Define VSAM ESDS data set that will be used to store data from 'userid.EU2015.STATS'. - Name it 'userid.EU2015.STATS.ESDS'. - Set Control Interval to 2048 - All VSAM components should be removed if Cluster is removed. - Set appropriate record size. 5. Copy 'userid.EU2015.STATS' to the ESDS allocated in Task#4. - Use IDCAMS to print ESDS data set to Spool. - Copy ESDS back to PS data set named 'userid.EU2015.STATS.ESDSCOPY' 6. Define VSAM KSDS data set that will be used to store data from 'userid.EU2015.STATS'. - Use default Control Interval size. - All VSAM components should be removed if Cluster is removed. - Set free space percentage to 5% in both Control Area and Control Interval. - 'Rank' column should be set as key with Length=3. - Data set should be reusable. 7. Copy 'userid.EU2015.STATS.ESDSCOPY' to 'userid.EU2015.STATS.KSDS': - Use IEBDG to convert keys in 'Rank' column into 001, 002... format. - Copy 'userid.EU2015.STATS' to the 'userid.EU2015.STATS.KSDS'. - Copy records with keys 20-30 from 'userid.EU2015.STATS.KSDS' to the 'userid.EU2015.STATS.KSDSCOPY'. 8. Define alternate key (Country) to the KSDS from Task#6. - Use PRINT command to check AIX structure. - Copy records between 'Russia' and 'Poland' to PS data set. - Rerun job but this time copy only 'Finland' record.
Hint 1
IDCAMS is described in “DFSMS Access Method Services for Catalogs”.
Hint 2
Check “Chapter 2: Modal Commands” in “DFSMS Access Method Services for Catalogs”.
Hint 4-7
For more information about VSAM data sets structure check “VSAM Demystified” RedBook.
Hint 8
To create alternate key you need to performs three operations: - Create AIX component with Alternate Key definition. - Define PATH that connects AIX with Base Cluster. - Build Index with BLDINDEX control statement. To use Alternate Key you need to refer to the PATH component, not the Base Cluster.
Solution 1
JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID //DEFGDG EXEC PGM=IDCAMS //SYSPRINT DD SYSOUT=* //SYSIN DD * DEF GDG(NAME(JSADEK.GDG.TEST)- LIMIT(5) - SCRATCH) //COPY EXEC PGM=IDCAMS //IN1 DD DISP=SHR,DSN=&SYSUID..BPXBATCH.CMD1 //OUT1 DD DSN=&SYSUID..GDG.TEST(+1),DISP=(NEW,CATLG), // LIKE=&SYSUID..BPXBATCH.CMD1 //IN2 DD DISP=SHR,DSN=&SYSUID..EU2015.STATS //OUT2 DD DSN=&SYSUID..GDG.TEST(+2),DISP=(NEW,CATLG), // LIKE=&SYSUID..EU2015.STATS //IN3 DD DISP=SHR,DSN=&SYSUID..MY.CNTL //OUT3 DD DSN=&SYSUID..GDG.TEST(+3),DISP=(NEW,CATLG), // LIKE=&SYSUID..MY.CNTL //IN4 DD DISP=SHR,DSN=&SYSUID..MY.REXX //OUT4 DD DSN=&SYSUID..GDG.TEST(+4),DISP=(NEW,CATLG), // LIKE=&SYSUID..MY.REXX //IN5 DD DISP=SHR,DSN=&SYSUID..SUPERC.LIST //OUT5 DD DSN=&SYSUID..GDG.TEST(+5),DISP=(NEW,CATLG), // LIKE=&SYSUID..SUPERC.LIST //IN6 DD DISP=SHR,DSN=&SYSUID..IKJEFT.TEST1 //OUT6 DD DSN=&SYSUID..GDG.TEST(+6),DISP=(NEW,CATLG), // LIKE=&SYSUID..IKJEFT.TEST1 //SYSPRINT DD SYSOUT=* //SYSIN DD * REPRO INFILE(IN1) OUTFILE(OUT1) REPRO INFILE(IN2) OUTFILE(OUT2) REPRO INFILE(IN3) OUTFILE(OUT3) REPRO INFILE(IN4) OUTFILE(OUT4) REPRO INFILE(IN5) OUTFILE(OUT5) REPRO INFILE(IN6) OUTFILE(OUT6)
GDG are usually made up from PS data sets with the same DCB but it's not in any way technical requirement. You can put any concatenation of PS, PDS and PDS/E data sets. So if by any reason characteristics of data sets change – there is no problem with adding new data sets with completely different DCBs. Second thing you should notice is that PDS & PDS/E members were not copied. IDCAMS REPRO command doesn't support those data sets – and although they're are created no member is copied. So for PDS and PDS/E you need to use IEBCOPY or ADRDSSU.
Solution 2
JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID //DELGDG EXEC PGM=IDCAMS //SYSPRINT DD SYSOUT=* //SYSIN DD * DEL JSADEK.GDG.TEST.* IF LASTCC NE 0 THEN DO SET MAXCC=10 CANCEL END DEL JSADEK.GDG.TEST GDG IF LASTCC NE 0 THEN DO SET MAXCC=11 END
IDCAMS provides simple set of statements that help control IDCAMS execution. IF, DO/END and SET are the most common ones. It's useful to remember that IDCAMS DELETE control statement supports simple masks which can save you some time while removing data sets with the same naming convention.
Solution 3
JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID //STEP1 EXEC PGM=IDCAMS //INDD DD DISP=SHR,DSN=SMF.MVST.G0110V00 // DD DISP=SHR,DSN=SMF.MVST.G0111V00 // DD DISP=SHR,DSN=SMF.MVST.G0112V00 // DD DISP=SHR,DSN=SMF.MVST.G0113V00 // DD DISP=SHR,DSN=SMF.MVST.G0114V00 // DD DISP=SHR,DSN=SMF.MVST.G0115V00 // DD DISP=SHR,DSN=SMF.MVST.G0116V00 // DD DISP=SHR,DSN=SMF.MVST.G0117V00 // DD DISP=SHR,DSN=SMF.MVST.G0118V00 // DD DISP=SHR,DSN=SMF.MVST.G0119V00 //OUTDD DD DSN=&SYSUID..SMF.EXTRACT.D170107,DISP=(NEW,CATLG), // SPACE=(CYL,(100,100),RLSE),LIKE=SMF.MVST.G0110V00 //SYSPRINT DD SYSOUT=* //SYSIN DD * REPRO INFILE(INDD) OUTFILE(OUTDD)
IDCAMS can be also used for simple copy operation and joining them together as in this example. It also supports more data set types that IEB* Utilities. SMF Logs are stored in VBS record format. IEBGENER cannot process such records.
Solution 4
JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID //STEP1 EXEC PGM=IDCAMS //SYSPRINT DD SYSOUT=* //SYSIN DD * DEFINE CLUSTER( - NAME(JSADEK.EU2015.STATS.ESDS) - NONINDEXED - TRACKS(3 3) - CONTROLINTERVALSIZE(2048) - ERASE - RECORDSIZE(95 120) - )
VSAM data sets are mostly used by specific software such as CICS but your programs and scripts can also take advantage of them. VSAM structure and behavior is pretty complex and you should refer to “VSAM Demystified” RedBook for details.
Solution 5
PS to VSAM copy:
//JSADEK01 JOB NOTIFY=&SYSUID //STEP1 EXEC PGM=IDCAMS //INDD DD DISP=SHR,DSN=&SYSUID..EU2015.STATS //OUTDD DD DISP=OLD,DSN=&SYSUID..EU2015.STATS.ESDS //SYSPRINT DD SYSOUT=* //SYSIN DD * REPRO INFILE(INDD) OUTFILE(OUTDD)
VSAM Print:
//JSADEK01 JOB NOTIFY=&SYSUID //STEP1 EXEC PGM=IDCAMS //INDD DD DISP=SHR,DSN=&SYSUID..EU2015.STATS.ESDS //SYSPRINT DD SYSOUT=* //SYSIN DD * PRINT INFILE(INDD) CHARACTER
Notice that lower-letters are not printed, unfortunately this is how it works, maybe it will be improved in the future. Still you can recognize each record in the data set and you can also check RBA of each record. RBA is simply a record address in ESDS. VSAM copy to PS:
//JSADEK01 JOB NOTIFY=&SYSUID //STEP1 EXEC PGM=IDCAMS //INDD DD DISP=SHR,DSN=&SYSUID..EU2015.STATS.ESDS //OUTDD DD DSN=&SYSUID..EU2015.STATS.ESDSCOPY,DISP=(NEW,CATLG), // SPACE=(TRK,5),LRECL=120,BLKSIZE=12000,RECFM=FB //SYSPRINT DD SYSOUT=* //SYSIN DD * REPRO INFILE(INDD) OUTFILE(OUTDD)
Because of the limitations of the print command it's sometimes better to simply convert VSAM data set to the PS data set.
Solution 6
JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID //STEP1 EXEC PGM=IDCAMS //SYSPRINT DD SYSOUT=* //SYSIN DD * DEFINE CLUSTER( - NAME(JSADEK.EU2015.STATS.KSDS) - INDEXED - KEYS(3 0) - TRACKS(3 3) - FREESPACE(5 5) - ERASE - RECORDSIZE(95 120) - )
The only real difference here is Key definition. Key is the record ID. If you want to retrieve specific record in KSDS you need to know value of it's Key. This is the same concept as Primary Key in relational data bases.
Solution 7
Key conversion:
//JSADEK01 JOB NOTIFY=&SYSUID //STEP1 EXEC PGM=IEBDG //SYSPRINT DD SYSOUT=* //STATS DD DSN=&SYSUID..EU2015.STATS,DISP=SHR //GENDATA DD DSN=&SYSUID..EU2015.STATS.ESDSCOPY,DISP=OLD //SYSIN DD * DSD OUTPUT=(GENDATA),INPUT=(STATS) FD NAME=F1,LENGTH=3,STARTLOC=1,FORMAT=ZD,INDEX=1 CREATE QUANTITY=1,INPUT=STATS CREATE QUANTITY=50,NAME=(F1),INPUT=STATS END
To copy PS to KSDS the PS data set must be sorted accordingly to the Key defined in VSAM data set. Using SORT is not the best idea in this case because records after sort would be 1,10,11,...,2,20,21 and so on. Because of this we need to convert them to 001, 002 format. IEBDG will do the trick. PS to KSDS copy:
//JSADEK01 JOB NOTIFY=&SYSUID //STEP1 EXEC PGM=IDCAMS //INDD DD DISP=SHR,DSN=&SYSUID..EU2015.STATS.ESDSCOPY //OUTDD DD DISP=OLD,DSN=&SYSUID..EU2015.STATS.KSDS //SYSPRINT DD SYSOUT=* //SYSIN DD * REPRO INFILE(INDD) OUTFILE(OUTDD)
KSDS to PS copy:
//JSADEK01 JOB NOTIFY=&SYSUID //STEP1 EXEC PGM=IDCAMS //INDD DD DISP=SHR,DSN=&SYSUID..EU2015.STATS.KSDS //OUTDD DD DSN=&SYSUID..EU2015.STATS.KSDSCOPY,DISP=(NEW,CATLG), // LIKE=&SYSUID..EU2015.STATS //SYSPRINT DD SYSOUT=* //SYSIN DD * REPRO INFILE(INDD) OUTFILE(OUTDD) FROMKEY(020) TOKEY(030)
FROMKEY and TOKEY define array of records that will be included in copy operation.
Solution 8
JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID //SMFCOPY EXEC PGM=IDCAMS //SYSPRINT DD SYSOUT=* //SYSIN DD * DEFINE AIX( - NAME(JSADEK.EU2015.STATS.KSDS.AIX) - RELATE(JSADEK.EU2015.STATS.KSDS) - TRACK(1 1) - RECORDSIZE(95 120) - KEYS(23 5) - ERASE - ) DEFINE PATH( - NAME(JSADEK.EU2015.STATS.KSDS.PATH) - PATHENTRY(JSADEK.EU2015.STATS.KSDS.AIX) - ) BLDINDEX - IDS(JSADEK.EU2015.STATS.KSDS) - ODS(JSADEK.EU2015.STATS.KSDS.AIX)
Creating KSDS with Alternate Index is a 5 step process: - Defining Base Cluster. - Populating KSDS with data. Without that you won't be able to create AIX or process KSDS. - Defining Alternate Index. - Defining PATH component that connects Alternate Index with Base Cluster. - Building Alternate Index with BLDINDEX command. First two steps were done in Task#7. The job above does the last three steps of the process. Now Alternate Key is ready to use. You can print AIX component just like Base Cluster. You'll notice that it contains only Alternate Key along with it's relation to the Primary Key. So while using Alternate Key AIX is read, Primary Key is taken from there and then it's used for standard record retrieval in Base Cluster. Copy job:
//JSADEK01 JOB NOTIFY=&SYSUID //SMFCOPY EXEC PGM=IDCAMS //INDD DD DISP=SHR,DSN=&SYSUID..EU2015.STATS.KSDS.PATH //OUTDD DD DSN=&SYSUID..EU2015.STATS.KSDSCOPY,DISP=(NEW,CATLG), // LIKE=&SYSUID..EU2015.STATS //SYSPRINT DD SYSOUT=* //SYSIN DD * REPRO INFILE(INDD) OUTFILE(OUTDD) - FROMKEY(Poland) TOKEY(Russia)
Notice that while using Alternate Key to record retrieval you need to use PATH component, not AIX or Base Cluster. Similarly you can retrieve only specific record:
REPRO INFILE(INDD) OUTFILE(OUTDD) - FROMKEY(Finland) COUNT(1)
DFSORT
Introduction
DFSORT is the main z/OS Utility used for data sorting but it can be also used for other operations like record summing, data set merging or copy operations. You can execute it by using either SORT or ICEMAN program name. There is no difference and both versions will execute DFSORT product. There is also an Utility called ICETOOL which extends DFSORT functionality. It's not as often used and won't be covered in this Assignment.
Tasks
1. Sort 'userid.EU2015.STATS' by country name in descending order. Save output in 'userid.SORT.STATS1'. 2. Modify job from Task#1: - Add first step that ensures that output data set does not exists. - Second step should copy header only. - Third step should sort countries without header and append them to the output data set. - Save output in 'userid.SORT.STATS2'. 3. Copy records from data set created in Task#2: - Name data set 'userid.SORT.STATSVB'. - It should have VB record format. - Sort the data set by Population column in ascending order. - Save output in 'userid.SORT.STATS3'. 4. Copy records from 'userid.EU2015.STATS': - Use DFSORT to justify all numeric columns to the right and save new version as 'userid.SORT.STATSFMT'. Also skip first record with columns headers. - Use new formatted version and copy countries with population higher than 25 millions to 'userid.EU2015.STATS4'. 5. Use SUM control statement to check how many people live in Europe in total. Save the result in 'userid.SORT.TOTAL'. 6. Use DFSORT to extract all SMF records from yesterday into 'userid.SORT.SMF1'. Convert record organization from VBS to VB. 7. Modify job from Task#6 so only records about Job Initiation recorded between 08:00 and 12:00 are extracted. 8. Create three step job: - STEP1 ensures that output data set does not exists. - STEP2 does the same thing as job from Task#7 but not with use of DFSORT. Instead use IFASMFDP Utility. - STEP3 sorts SMF records extracted by STEP2 by Jobname. 9. Modify job from Task#8: - First sort records by SMF Record Type. - Omit Dump Header and Dump Trailer added by IFASMFDP Utility. - Convert rest of the records so they contain only three columns in that order: Jobname, Date, Time. - Convert Date and Time to user readable formats.
Hint 1-9
“DFSORT: Getting Started” and “DFSORT Application Programming Guide” are two main documents you'll need while learning DFSORT. For interesting examples and uses of DFSORT check “Smart DFSORT Tricks” and “DFSORT: Beyond Sorting”.
Hint 4
For this Task you'll need to do some research in “DFSORT Application Programming Guide”. Check examples of OUTREC control statement to see how data can be justified with DFSORT. Data formats used by DFSORT are described in “Appendix C” of “DFSORT Application Programming Guide”.
Hint 6
SMF records are described in “MVS System Management Facilities”. Record descriptions already contain RDW so although SMF Logs are in VB format you don't have to add four bytes to the values specified in this document. Also note that column numeration in “MVS System Management Facilities” starts with 0 not 1 so you'll also need to take it into consideration.
Solution 1
JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID //SORT EXEC PGM=SORT //SORTIN DD DISP=SHR,DSN=&SYSUID..EU2015.STATS //SORTOUT DD DSN=&SYSUID..SORT.STATS1,DISP=(NEW,CATLG), // LIKE=&SYSUID..EU2015.STATS //SYSOUT DD SYSOUT=* //SYSIN DD * SORT FIELDS=(6,23,CH,D)
DFSORT writes report from it's operation to SYSOUT DD statement, not SYSPRINT as most other Utilities. DFSORT is often used for sorting huge data objects such as SMF logs or DB2 Table Spaces (during database reorganization). A common problem is lack of storage for sorting data. DFSORT first copies all records from data set to temporary work data sets and from those temporary files to output so when you sort 10GB data set you'll also have to have over 10GB of available space in Storage Group used for Temporary data sets.
Solution 2
JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID // SET DS=&SYSUID..SORT.STATS2 //DEL EXEC PGM=IEFBR14 //DELDD DD SPACE=(TRK,1),DISP=(MOD,DELETE),DSN=&DS //COPY EXEC PGM=SORT //SORTIN DD DISP=SHR,DSN=&SYSUID..EU2015.STATS //SORTOUT DD DSN=&DS,DISP=(NEW,PASS),LIKE=&SYSUID..EU2015.STATS //SYSOUT DD SYSOUT=* //SYSIN DD * OPTION COPY OUTFIL ENDREC=1 //SORT EXEC PGM=SORT //SORTIN DD DISP=SHR,DSN=&SYSUID..EU2015.STATS //SORTOUT DD DSN=&DS,DISP=(MOD,CATLG),LIKE=&SYSUID..EU2015.STATS //SYSOUT DD SYSOUT=* //SYSIN DD * SORT FIELDS=(6,23,CH,D),SKIPREC=1
DFSORT usually is used to coping data itself – without column headers and it doesn't have control statement for omitting it. You need to do this in two steps. First step copies headers only and second one sorts records and appends them to the data set.
Solution 3
Copy job:
//JSADEK01 JOB NOTIFY=&SYSUID //COPY EXEC PGM=IEBGENER //SYSUT1 DD DISP=SHR,DSN=&SYSUID..EU2015.STATS //SYSUT2 DD DSN=&SYSUID..SORT.STATSVB,DISP=(NEW,CATLG),LRECL=124, // LIKE=&SYSUID..EU2015.STATS,RECFM=VB,BLKSIZE=27998 //SYSPRINT DD SYSOUT=* //SYSIN DD DUMMY
Sort job:
//JSADEK01 JOB NOTIFY=&SYSUID //SORT EXEC PGM=SORT //SORTIN DD DISP=SHR,DSN=&SYSUID..SORT.STATSVB //SORTOUT DD DSN=&SYSUID..SORT.STATS3,DISP=(NEW,CATLG), // LIKE=&SYSUID..SORT.STATSVB //SYSOUT DD SYSOUT=* //SYSIN DD * SORT FIELDS=(33,12,CH,A)
Notice that although Population starts in 29 column proper sort must start from 33 column. DFSORT always considers entire record. Because of this you often need to add few bytes to depending on record format: - FB – no additional data at the beginning so COLS command will show actual bytes in records. - FBA - +1 byte (additional ANSI control character at the beginning of each record). - VB - +4 bytes (each record has RDW at the beginning). - VBA - +5 (RDW + ANSI).
Solution 4
Job for column justification:
//JSADEK01 JOB NOTIFY=&SYSUID //SORT EXEC PGM=SORT //SORTIN DD DISP=SHR,DSN=&SYSUID..EU2015.STATS //SORTOUT DD DSN=&SYSUID..SORT.STATSFMT,DISP=(NEW,CATLG), // LIKE=&SYSUID..EU2015.STATS //SYSOUT DD SYSOUT=* //SYSIN DD * OPTION COPY,SKIPREC=1 OUTREC OVERLAY=(1:1,3,JFY=(SHIFT=RIGHT,LENGTH=3), 29:29,11,JFY=(SHIFT=RIGHT,LENGTH=11), 41:41,6,JFY=(SHIFT=RIGHT,LENGTH=6), 57:57,8,JFY=(SHIFT=RIGHT,LENGTH=8), 73:73,6,JFY=(SHIFT=RIGHT,LENGTH=6), 93:93,5,JFY=(SHIFT=RIGHT,LENGTH=5))
To process numeric data DFSORT requires data justified to the right. Sometimes data for processing does not follow this format (like in EU2015 stats) and you need to justify numeric data prior to processing. Countries with population above 25 mil:
//JSADEK01 JOB NOTIFY=&SYSUID //SORT EXEC PGM=SORT //SORTIN DD DISP=SHR,DSN=&SYSUID..SORT.STATSFMT //SORTOUT DD DSN=&SYSUID..SORT.STATS4,DISP=(NEW,CATLG), // LIKE=&SYSUID..SORT.STATSFMT //SYSOUT DD SYSOUT=* //SYSIN DD * OPTION COPY INCLUDE COND=(29,11,ZD,GE,25000000)
Solution 5
JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID //DEL EXEC PGM=IEFBR14 //DELDD DD SPACE=(TRK,1),DISP=(MOD,DELETE),DSN=&SYSUID..SORT.TOTAL //SORT EXEC PGM=SORT //SORTIN DD DISP=SHR,DSN=&SYSUID..SORT.STATSFMT //SORTOUT DD DSN=&SYSUID..SORT.TOTAL,DISP=(NEW,CATLG), // LIKE=&SYSUID..SORT.STATSFMT //SYSOUT DD SYSOUT=* //SYSIN DD * SORT FIELDS=(1,1,CH,D) OUTREC FIELDS=(C'SUM: ',6:29,11) SUM FIELDS=(29,11,ZD)
While summing values you must remember that only values from duplicated fields are added. SORT statement specifies field that is considered – in our example first column is filled with blanks so all records are considered duplicated and all of them are summed.
Solution 6
JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID //VAREXP EXPORT SYMLIST=(YR,DOY) // SET YR=17 <-- YEAR: '17' FOR 2017 // SET DOY=013 <-- DAY OF YEAR: '032' FOR 01 FEB //DEL EXEC PGM=IEFBR14 // DD SPACE=(TRK,1),DISP=(MOD,DELETE),DSN=&SYSUID..SORT.SMF1 //SORT EXEC PGM=SORT //SORTIN DD DISP=SHR,DSN=SMF.MVSA(0) // DD DISP=SHR,DSN=SMF.MVSA(-1) // DD DISP=SHR,DSN=SMF.MVSA(-2) //SORTOUT DD DSN=&SYSUID..SORT.SMF1,DISP=(NEW,CATLG), // SPACE=(CYL,(50,50),RLSE),RECFM=VB,LRECL=32756 //SYSOUT DD SYSOUT=* //SYSIN DD *,SYMBOLS=EXECSYS OPTION COPY INCLUDE COND=(11,4,CH,EQ,X'01&YR.&DOY.F')
You can use DFSORT or IDCAMS to convert data sets with VBS record format to VB. VBS is standard format in which SMF logs are stored. ISPF Editor doesn't support RECFM=VBS, more importantly REXX EXECIO operation also won't process it. So, if you need to process SMF records with REXX or simply display them you need to convert them first. This job can be used just for this purpose – it converts SMF records to VB format and additionally extracts only records from the specific day. SMF data format follows “01yydddF” format. You can enter extracted data set and use HEX command to confirm that appropriate records were extracted.
Solution 7
JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID //VAREXP EXPORT SYMLIST=(YR,DOY) // SET YR=17 <-- YEAR: '17' FOR 2017 // SET DOY=018 <-- DAY OF YEAR: '032' FOR 01 FEB //DEL EXEC PGM=IEFBR14 //DELDD DD SPACE=(TRK,1),DISP=(MOD,DELETE),DSN=&SYSUID..SORT.SMF2 //SORT EXEC PGM=SORT //SORTIN DD DISP=SHR,DSN=SMF.MVSA(0) // DD DISP=SHR,DSN=SMF.MVSA(-1) // DD DISP=SHR,DSN=SMF.MVSA(-2) //SORTOUT DD DSN=&SYSUID..SORT.SMF2,DISP=(NEW,CATLG), // SPACE=(CYL,(50,50),RLSE),RECFM=VB,LRECL=32756,BLKSIZE=32760 //SYSOUT DD SYSOUT=* //SYSIN DD *,SYMBOLS=EXECSYS OPTION COPY INCLUDE COND=(11,4,CH,EQ,X'01&YR.&DOY.F',AND, 6,1,CH,EQ,X'14',AND, 7,4,BI,GE,X'002BF200',AND, 7,4,BI,LE,X'0041EB00')
Last two lines define time frame from which records are extracted. SMF20TME description states: “Time since midnight, in hundredths of a second, when the record was moved into the SMF buffer.” So you can calculate 8AM in following way: 8*60*60*100=2880000 Then use any DEC-TO-HEX converter and you have desired value. Note that DFSORT requires full number so if you specified 4 bytes – there must be four bytes even if first one is '00'.
Solution 8
JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID // SET OUT=&SYSUID..SORT.SMF3 //DEL EXEC PGM=IEFBR14 //DELDD DD SPACE=(TRK,1),DISP=(MOD,DELETE),DSN=&OUT //SMFEXTRT EXEC PGM=IFASMFDP //SMFIN DD DISP=SHR,DSN=SMF.MVSA(0) // DD DISP=SHR,DSN=SMF.MVSA(-1) // DD DISP=SHR,DSN=SMF.MVSA(-2) //SMFOUT DD DSN=&TEMPDATA,DISP=(NEW,PASS), // SPACE=(CYL,(50,50),RLSE),DCB=*.SMFIN //SYSPRINT DD SYSOUT=* //SYSIN DD * INDD(SMFIN,OPTIONS(DUMP)) OUTDD(SMFOUT,TYPE(20)) DATE(2017018,2017018) START(0800) END(1200) //SORT EXEC PGM=SORT,COND=(0,NE) //SORTIN DD DISP=(OLD,DELETE,DELETE),DSN=&TEMPDATA //SORTOUT DD DSN=&OUT,DISP=(NEW,CATLG), // SPACE=(CYL,(50,50),RLSE),RECFM=VB,LRECL=32756,BLKSIZE=32760 //SYSOUT DD SYSOUT=* //SYSIN DD * OPTION VLSHRT SORT FIELDS=(19,8,CH,A)
As you can see IFASMFDP is much better choice when it comes to SMF record extraction. You avoid time calculation, checking SMF records documentation and unnecessary coding. “OPTION VLSHRT“ is used here to prevent common ICE218A error. IFASMFDP adds two SMF records Dump Header and Trailer which are very short and therefore DFSORT cannot address columns 19-26 in those two records and ends in error.
Solution 9
JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID // SET OUT=&SYSUID..SORT.SMF4 //DEL EXEC PGM=IEFBR14 //DELDD DD SPACE=(TRK,1),DISP=(MOD,DELETE),DSN=&OUT //SMFEXTRT EXEC PGM=IFASMFDP //SMFIN DD DISP=SHR,DSN=SMF.MVSA(0) // DD DISP=SHR,DSN=SMF.MVSA(-1) // DD DISP=SHR,DSN=SMF.MVSA(-2) //SMFOUT DD DSN=&TEMPDATA,DISP=(NEW,PASS), // SPACE=(CYL,(50,50),RLSE),DCB=*.SMFIN //SYSPRINT DD SYSOUT=* //SYSIN DD * INDD(SMFIN,OPTIONS(DUMP)) OUTDD(SMFOUT,TYPE(20)) DATE(2017018,2017018) START(0800) END(1200) //SORT EXEC PGM=SORT,COND=(0,NE) //SORTIN DD DISP=(OLD,DELETE,DELETE),DSN=&TEMPDATA //SORTOUT DD DSN=&OUT,DISP=(NEW,CATLG), // SPACE=(CYL,(50,50),RLSE),RECFM=VB,LRECL=32756,BLKSIZE=32760 //SYSOUT DD SYSOUT=* //SYSIN DD * SORT FIELDS=COPY OMIT COND=(6,1,CH,NE,X'14') OUTREC FIELDS=(1,4, 5:19,8, C'|', 14:11,4,DT1, C'|', 23:7,4,TM1)
DFSORT supports SMF data formats (DT1 & TM1) so you can very easily convert SMF date or time fields to desired format. OMIT statement ensures that only records about Job initiation X'14' are included in further processing. You can check DFSORT statements processing order in “Appendix C” of “DFSORT: Getting Started”. OUTREC statement is used for record reformatting. Notice the first line of this statement 'FIELDS=(1,4,' - it simply copies first four bytes of each records (RDW). Second line '5:19,8,' copies 8 bytes from column 19 and puts them in column 5 of output data set.
ADRDSSU
Introduction
ADRDSSU is the primary Utility used for data movement on z/OS. It's one of SMS components called DFSMSdss (Data Set Services). It's also the most powerful tool for data sets movement, other Utilities like IEHMOVE, IEBCOPY, IDCAMS and even DFSORT have some restrictions while ADRDSSU can move and copy pretty much everything. The most basic operation done by ADRDSSU include: - To copy selected data sets. - To copy all data sets on volume. - Volume dumps. - Data sets dumps. - Restore operations. - Volume conversion from non-SMS to SMS managed and the other way around. - Space management operations such as DEFRAG or RELEASE.
Tasks
1. Allocate following data sets under 'userid.ADRDSSU.*' name (use any Utility, this is just a preparation for ADRDSSU exericses). Allocate 20 tracks for each. - PDS/E - FBA - VBS - VSAM KSDS - GDG group with Limit=3 along with three generations. 2. Copy all data sets you've allocated in Task#1 except GDG data sets. Use 'userid.ADRDSSU.*.COPY1' names. - Exclude the GDG group from processing. - Re-run job with ALLD(*) & ALLX keyword to create 'userid.ADRDSSU.*.COPY2' data sets. What's the difference between COPY1 and COPY2 data sets? - Lock the FBA data set with Browse ISPF panel and rerun job to create third copy '**.COPY3'. How to fix this problem? 3. Use ADRDSSU to remove all data sets created in Task#2. 4. Copy the GDG group you've allocated in Task#1 under 'userid.ADRDSSU.GDG2.*' name: - Use 3.2 panel to add few more generations to test if older generations of 'userid.ADRDSSU.GDG2' are automatically removed. - Remove GDG2 using IDCAMS. 5. Move data sets from Task#1 to another Storage Group: - Use Generic name format as selection criteria. - Exclude GDG group from processing. - Before move, create dump of selected data sets in case of any problems with data consistency. - Move data sets back to the original Storage Group. 6. Copy data sets from Task#1 to non-SMS volume: - Exclude GDG group and KSDS from processing. - Keep the original data set names. - Create second set of copies with SYS1 prefix on the same volume. - Remove all data sets allocated in this Task. 7. Create dump of data sets created in Task#1: - Include GDG data sets. - Display DUMP contents before restore operation. - Restore them replacing second name segment with 'ADRDSSU2'. - Issue IDCAMS commands manually (as TSO commands) to remove 'ADRDSSU2' data sets. 8. Create full volume dump: - Copy 20 various data sets to an empty non-SMS volume (VOL1). Do not catalog them. - To use more space and simulate normal workload - remove few copied data sets and copy the same data sets with different name. Repeat this step few times. - Dump this volume as 'userid.DUMP.FULL'. - Restore the dump to another empty non-SMS volume (VOL2). Do not use COPYVOLID parameter. - Use IEHLIST to print VTOC of both volumes to 'userid.VTOC.SOURCE' & 'userid.VTOC.FULL'. - Remove restored data sets (VOL2). 9. Create physical dump of data sets copied in Task#8 (VOL1): - Dump those data sets to 'userid.DUMP.PHYSICAL'. - Restore the dump to another empty volume (VOL2). - Use IEHLIST to print VTOC of second volume (VOL2) to 'userid.VTOC.PHYSICAL'. - Remove restored data sets (VOL2). 10. Create logical dump of data sets copied in Task#8 (VOL1): - Dump those data sets to 'userid.DUMP.LOGICAL'. - Restore the dump to another empty volume (VOL2) - Use IEHLIST to print VTOC of second volume (VOL2) to 'userid.VTOC.LOGICAL'. - Remove restored data sets (VOL2). - Compare VTOC prints - what's the difference between SOURCE, FULL, PHYSICAL and LOGICAL listings? 11. Regain space on volume used for three previous Tasks (VOL1). Create four ADRDSSU jobs that issue following commands: CONSOLIDATE, COMPRESS, RELEASE & DEFRAG. - Check following fields in ISMF after each operation: 'FREE SPACE', 'FRAG INDEX', 'FREE EXTENDS' & 'FREE DSCBS'. - What you should consider before performing each of those operations?
Hint 1
For more details about allocating VSAM and GDG data sets check “DFSMS Access Method Services for Catalogs”. Parameters doesn't matter in this Assignment, you need those data sets only for testing. All data sets can be allocated via 3.2 ISPF panel. For GDG and KSDS use 'V' option.
Hint 2
ADRDSSU is described in “DFSMSdss Storage Administration”. Search for COPY control statement. ALLD(*) and ALLX keywords are also described there. You can also take a look at “ALLDATA and ALLEXCP Interactions” table. When using ADRDSSU always remember to run job with 'TYPRUN=NORUN' to avoid any errors during actual run.
Hint 3
ADRDSSU doesn't have normal delete operation but you can do it by using DUMP. Simply DUMP data sets to DUMMY DD statement and use DELETE control statement.
Hint 4
When it comes to GDG and ADRDSSU the rule is simple – you can process all generations with ADRDSSU but not GDG Base. So if you want to remove, move or create GDG Base – you'll need to run step with IDCAMS before.
Hint 5
STORGRP keyword for ADRDSSU specifies source volumes (volumes from which data set will be selected for processing) so this is not the option you're looking for. Storage Group is selected on the basis of Storage Class assigned to the data set. You can select specific Storage Class in ADRDSSU but first you need to investigate ACS routines to figure out which Storage Class is associated with Storage Group you want to use.
Hint 7
You may be interested in “Dumping data efficiently” and “Restoring data sets with special requirements” chapters of “DFSMSdss Storage Administration”.
Hint 8
When doing full volume dump you must consider following setting: - DASD type – target volume should be the same type of dumped volume (for example 3390-27). It's only possible to restore smaller model to a larger one. - SMS – if source volume is SMS-managed target should also be SMS-managed. And if source volume is non-SMS, target volume also shouldn't be. - VTOC index and VVDS – those data sets are system managed and they are rebuilt during restore operation. So even if you restore one volume (VOL001) onto another (VOL002) VTOC index and VVDS will be rebuilt with correct name (VOL002). Unless you specify COPYVOLID. - Volume name – if you'll decide to use COPYVOLID keyword you may encounter problem with duplicated DASD names. WTOR will ask you which one should be online, no two DASD with the same volser can be used at the same time. - RLS – you should be especially careful when restoring data sets used by RLS mechanism since there may be integrity issues. - DASD sharing – before restore operation you should ensure that target volume is not online on other systems. Use 'DS QD,devnum,QHA' command to check DASD status on all systems that have access to it. If those systems are in Sysplex (which is not always the case) you can use 'RO *ALL,V devnum,OFFLINE' command to vary it offline in all systems in a Sysplex. - DASD allocation – before restore operation you should ensure that target volume is not allocated to any job or task. Use 'D U,DASD,ALLOC,devnum,1' command to check if anything allocates target volume. - If there are any data sets present on the target volume they'll be removed so ensure you use empty volume.
Solution 1
JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID //VSAM EXEC PGM=IDCAMS //SYSPRINT DD SYSOUT=* //SYSIN DD * DEFINE CLUSTER (NAME(JSADEK.ADRDSSU.KSDS) - TRACKS(20 20) - KEYS(8 1) - RECORDSIZE(100 100) - SHAREOPTIONS(3 3) - INDEXED) DEFINE GDG (NAME(JSADEK.ADRDSSU.GDG) - LIMIT(3) - SCRATCH //BASIC EXEC PGM=IEFBR14 //GDG1 DD DSN=JSADEK.ADRDSSU.GDG(+1),DISP=(NEW,CATLG), // SPACE=(TRK,(20,20)),BLKSIZE=27920,LRECL=80,RECFM=FB //GDG2 DD DSN=JSADEK.ADRDSSU.GDG(+2),DISP=(NEW,CATLG), // SPACE=(TRK,(20,20)),BLKSIZE=27920,LRECL=80,RECFM=FB //GDG3 DD DSN=JSADEK.ADRDSSU.GDG(+3),DISP=(NEW,CATLG), // SPACE=(TRK,(20,20)),BLKSIZE=27920,LRECL=80,RECFM=FB //PDSE DD DSN=JSADEK.ADRDSSU.PDSE,DISP=(NEW,CATLG),RECFM=FB, // SPACE=(TRK,(20,20,5)),BLKSIZE=27920,LRECL=80,DSNTYPE=LIBRARY //FBA DD DSN=JSADEK.ADRDSSU.FBA,DISP=(NEW,CATLG), // SPACE=(TRK,(20,20)),BLKSIZE=27977,LRECL=101,RECFM=FBA //VBS DD DSN=JSADEK.ADRDSSU.VBS,DISP=(NEW,CATLG), // SPACE=(TRK,(20,20)),BLKSIZE=27900,LRECL=100,RECFM=VBS
Usually it's better to allocate each data set in different step. This way you are able to easily restart job in case some error appears during allocation of one of those data sets, but you can also do it as in this Solution.
Solution 2
First copy operation:
//JSADEK01 JOB NOTIFY=&SYSUID //COPY EXEC PGM=ADRDSSU,REGION=0M PARM='TYPRUN=NORUN' //SYSPRINT DD SYSOUT=* //SYSIN DD * COPY DATASET(INCLUDE(JSADEK.ADRDSSU.FBA - JSADEK.ADRDSSU.KSDS - JSADEK.ADRDSSU.PDSE - JSADEK.ADRDSSU.VBS - )) - RENUNC((JSADEK.ADRDSSU.FBA,JSADEK.ADRDSSU.FBA.COPY1) - (JSADEK.ADRDSSU.KSDS,JSADEK.ADRDSSU.KSDS.COPY1) - (JSADEK.ADRDSSU.PDSE,JSADEK.ADRDSSU.PDSE.COPY1) - (JSADEK.ADRDSSU.VBS,JSADEK.ADRDSSU.VBS.COPY1) - ) /*-------------------- COMMON FUNCTIONS ----------------------------*/ /* ALLD(*) - COPY EVEN UNUSED SPACE IN DATA SET */ /* ALLX - COPY EVEN EMPTY DATA SETS */ /* CATALOG - CATALOG DATA SET */ /* SPHERE - TO COPY VSAM AIX & PATH COMPONENTS */ /*-------------------- REMOVE ORIGINAL DATA SETS -------------------*/ /* DELETE - REMOVE ORIGINAL DATA SETS */ /* PURGE - REMOVE ORIGINAL DATA SETS */ /*-------------------- INCREASE AUTHORIZATION ----------------------*/ /* ADMIN - STORADMIN AUTHORIZATION */ /* PROCESS(SYS1) - WORK ON SYS1.** DATA SETS */ /*-------------------- CONTENTION OPTIONS --------------------------*/ /* SHARE - ALLOW SHARE ACCESS DURING COPY */ /* TOL(ENQF) - IGNORE CONTENTION */ /* DYNALLOC - IF DATA SETS ARE USED ACROSS SYSPLEX */ /* WAIT(5,5) - WAIT FOR DATA SETS AVAILABILITY */ /*-------------------- SELECT MC & SC CLASSES ----------------------*/ /* MGMTCLAS(MGNAME) - USE SPECIFIC MANAGEMENT CLASS */ /* STORCLAS(SCNAME) - USE SPECIFIC STORAGE CLASS */ /*-------------------- WORK ON NON-SMS VOLUMES ---------------------*/ /* BYPASSACS(**) - OVERWRITE ACS ROUTINES */ /* NMC - NULLIFY MANAGEMENT CLASS */ /* NSC - NULLIFY STORAGE CLASS */ /* OUTDYNAM(VOLSER) - TO COPY TO NON-SMS VOLUME */
This is most basic version of copy operation in this Assignment. INCLUDE statement can use generic names so you can also use 'userid.ADRDSSU.*' (if there are no other data sets that match that mask). - RENUNC (Rename Unconditional) – this is the rename operation that's almost always used. It's valid both for RESTORE and COPY control statement. “RENAME” is another version but it's only used with RESTORE. With RENAME operation data set name is changed only if data set with it's name already exists. If not, RENAME won't change the name. RENUNC also supports generic names but it works only if old and new name have the same number of qualifiers(name segments). In this example original data sets have names with three segments 'userid.ADRDSSU.dstype' and copy data sets have four so we cannot use generic name here. - PARM='TYPRUN=NORUN' – always before actual operation check it in NORUN mode. In this mode you'll be able to confirm if only desired data sets will be processed. And of course many error types can be detected in NORUN mode. At the bottom of the job there are some common keywords commented. This way you can quickly modify Copy operation accordingly without checking documentation so often. Second copy operation:
//JSADEK01 JOB NOTIFY=&SYSUID //COPY EXEC PGM=ADRDSSU,REGION=0M PARM='TYPRUN=NORUN' //SYSPRINT DD SYSOUT=* //SYSIN DD * COPY DATASET(INCLUDE(JSADEK.ADRDSSU.FBA - JSADEK.ADRDSSU.KSDS - JSADEK.ADRDSSU.PDSE - JSADEK.ADRDSSU.VBS - )) - RENUNC((JSADEK.ADRDSSU.FBA,JSADEK.ADRDSSU.FBA.COPY2) - (JSADEK.ADRDSSU.KSDS,JSADEK.ADRDSSU.KSDS.COPY2) - (JSADEK.ADRDSSU.PDSE,JSADEK.ADRDSSU.PDSE.COPY2) - (JSADEK.ADRDSSU.VBS,JSADEK.ADRDSSU.VBS.COPY2) - ) - CATALOG - ALLD(*) - ALLX
- ALLD(*) & ALLX – basically we use those keywords to ensure that all space allocated for all data sets is copied. In almost all copy operations this is our goal so it's good to practice to use those keywords by default. As you may have noticed without those keywords data sets were copied but they didn't have 20 tracks but 1. Detailed description of those two parameter is store in “ALLDATA and ALLEXCP Interactions” table in “DFSMSdss Storage Administration”. - CATALOG – if you use SMS managed volumes data sets will be cataloged anyway. In this example we don't specify any non-SMS volume so ACS routines will be used for allocation. Because of this CATALOG keyword is not needed in this example but it makes the code more clear. In third run, by blocking 'userid.ADRDSSU.FBA' with Browse panel you lock it in SHR mode. With 'TOL(ENQF)' statement you can copy this data set even if it's locked in SHR or EXC mode. Sometimes – especially when it comes to VSAM data set – this is acceptable situation but most often you'll need to wait until data set is freed to keep data integrity. You can use 'WAIT(5,5)' keyword to make ADRDSSU wait 25 seconds for the data set.
Solution 3
JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID //DELETE EXEC PGM=ADRDSSU,REGION=0M PARM='TYPRUN=NORUN' //SYSPRINT DD SYSOUT=* //DUMMYDD DD DUMMY //SYSIN DD * DUMP DATASET(INCLUDE(JSADEK.ADRDSSU.*.COPY% - )) - OUTDD(DUMMYDD) - DELETE - PURGE
This operation creates a dump to DUMMY data set therefore no actual DUMP is saved and data sets are removed thanks to DELETE and PURGE keywords. It creates some unnecessary workload and because of this it shouldn't be used in production. ADRDSSU can use generic names, including '**' and '%' which may be and advantage over IDCAMS so this is a method wroth knowing.
Solution 4
JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID //GDG EXEC PGM=IDCAMS //SYSPRINT DD SYSOUT=* //SYSIN DD * DEFINE GDG (NAME(JSADEK.ADRDSSU.GDG2) - LIMIT(3) - SCRATCH //COPY EXEC PGM=ADRDSSU,REGION=0M,COND=(0,NE) PARM='TYPRUN=NORUN' //SYSPRINT DD SYSOUT=* //SYSIN DD * COPY DATASET(INCLUDE(JSADEK.ADRDSSU.GDG(*) - )) - RENUNC((*.*.GDG.**,*.*.GDG2.**) - ) - TGTGDS(ACTIVE) - CATALOG - WAIT(5,5) - ALLD(*) - ALLX
GDG statuses are described in “Rolling In a Generation Data Set” chapter of “z/OS DFSMS Using Data Sets”. ACTIVE status means that GDG data set is managed according to GDG Base setting. You can use LISTC ENT('dsname') ALL to check if copied GDG generation have correct status. If you've used this status old generations will be automatically removed during addition of new ones. To remove entire GDG you'll also need additional IDCAMS step:
//JSADEK01 JOB NOTIFY=&SYSUID //DELETE EXEC PGM=IDCAMS //SYSPRINT DD SYSOUT=* //SYSIN DD * DEL JSADEK.ADRDSSU.GDG2.* IF LASTCC=0 THEN DO DEL JSADEK.ADRDSSU.GDG2 GDG END
This is an alternate way to remove entire GDG. You can achieve the same effect with FORCE keyword but you need additional RACF authorization to use that keyword.
Solution 5
Before any risky data set operation or like in this case – when you specify DELETE and PURGE keywords you should always make DUMP of the data set you'll be processing. And of course test your program with 'TYPRUN=NORUN' parameter. Here is an example DUMP operation:
//JSADEK01 JOB NOTIFY=&SYSUID //COPY EXEC PGM=ADRDSSU,REGION=0M PARM='TYPRUN=NORUN' //DUMPDD DD DSN=JSADEK.DUMP.ADRDSSU,DISP=(,CATLG), // SPACE=(CYL,(100,100),RLSE) //SYSPRINT DD SYSOUT=* //SYSIN DD * DUMP DATASET(INCLUDE(JSADEK.ADRDSSU.**) - EXCLUDE(JSADEK.ADRDSSU.GDG.**) - ) - OUTDD(DUMPDD) - COMPRESS - WAIT(5,5) - ALLD(*) - ALLX
Move operation:
//JSADEK01 JOB NOTIFY=&SYSUID //COPY EXEC PGM=ADRDSSU,REGION=0M PARM='TYPRUN=NORUN' //SYSPRINT DD SYSOUT=* //SYSIN DD * COPY DATASET(INCLUDE(JSADEK.ADRDSSU.**) - EXCLUDE(JSADEK.ADRDSSU.GDG.**) - ) - STORCLAS(WRKTST) - BYPASSACS(**) - DELETE - PURGE - CATALOG - WAIT(5,5) - ALLD(*) - ALLX
First you need to select Storage Group you want to use, ensure that there is enough space there for the operation (not a problem in this exercise, but you should always confirm it) and at last investigate ACS routines to find which Storage Class is associated with desired Storage Group. In this example it was 'WRKTST'. - EXCLUDE keyword was used to filter out GDG group from processed data sets. - When you overwrite Management Class or Storage Class you also need to use BYPASSACS keyword to ensure that selected class is actually used. '**' mask means that BYPASSACS applies to all data sets selected in DATASET control statement. - In this assignment our goal was to move data sets, not copy them. Because of this we don't need to use RENUNC parameter, instead DELETE and PURGE parameters are needed.
Solution 6
JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID //COPY EXEC PGM=ADRDSSU,REGION=0M PARM='TYPRUN=NORUN' //SYSPRINT DD SYSOUT=* //SYSIN DD * COPY DATASET(INCLUDE(JSADEK.ADRDSSU.**) - EXCLUDE(JSADEK.ADRDSSU.GDG.**, - JSADEK.ADRDSSU.KSDS - )) - OUTDYNAM(SPARE1) - BYPASSACS(**) - NMC - NSC - WAIT(5,5) - ALLD(*) - ALLX
In this Task we have to copy data sets with the same name. SMS doesn't allow duplicated data set names in Catalogs. Because of that copied data sets have to be uncatalogued. Also KSDS must be excluded from processing since all VSAM data sets must be cataloged, after all they're referred to via Cluster component which is simply a catalog entry. This time we use non-SMS volume. On SMS-managed volumes only cataloged data sets can be stored and therefore we don't have to use CATALOG control statements – SMS will catalog them anyway. If you use non-SMS volumes this is not the case and data sets won't be cataloged unless CATALOG statement is used. Four keywords are needed when you use non-SMS volumes:
/*-------------------- WORK ON NON-SMS VOLUMES ---------------------*/ /* OUTDYNAM(VOLSER) - TO COPY TO NON-SMS VOLUME */ /* BYPASSACS(**) - OVERWRITE ACS ROUTINES */ /* NMC - NULLIFY MANAGEMENT CLASS */ /* NSC - NULLIFY STORAGE CLASS */
It's good moment to mention difference between standard device allocation ADRDSSU dynamic allocation. - OUTDYNAM – dynamic allocation - no DD statement required only volser. DASD will be allocated to the job when ADRDSSU will execute control statements. - OUTDDNAME – this parameter is used for standard allocation through DD statement. You need to allocate DASD volume in separate DD statement and specify DD name here. DASD will be allocated when job starts. Here is DD statement that can be used with OUTDDNAME(DASD1) statement:
//DASD1 DD DISP=OLD,UNIT=3390,VOL=SER=SPARE1
Data Set Copy with SYS1 prefix:
//JSADEK01 JOB NOTIFY=&SYSUID //COPY EXEC PGM=ADRDSSU,REGION=0M PARM='TYPRUN=NORUN' //SYSPRINT DD SYSOUT=* //SYSIN DD * COPY DATASET(INCLUDE(JSADEK.ADRDSSU.**) - EXCLUDE(JSADEK.ADRDSSU.GDG.**, - JSADEK.ADRDSSU.KSDS - )) - RENUNC(SYS1) - OUTDYNAM(SPARE1) - BYPASSACS(**) - NMC - NSC - WAIT(5,5) - ALLD(*) - ALLX
When you replace HLQ only you can simply specify new HLQ in RENUNC control statement. Also note that you create new data sets with SYS1 prefix, not process existing SYS1.** data sets so you don't need PROCESS(SYS1) parameter.
Solution 7
DUMP JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID //DELDUMP EXEC PGM=IEFBR14 //DELETE DD DSN=&SYSUID..ADRDSSU.DUMP,SPACE=(TRK,1), // DISP=(MOD,DELETE) //DUMP EXEC PGM=ADRDSSU,REGION=0M PARM='TYPRUN=NORUN' //DUMP DD DSN=&SYSUID..DUMP.ADRDSSU,DISP=(NEW,CATLG), // SPACE=(CYL,(100,100),RLSE) //SYSPRINT DD SYSOUT=* //SYSIN DD * DUMP DATASET(INCLUDE(JSADEK.ADRDSSU.**) - )) - OUTDD(DUMP) - COMPRESS - WAIT(5,5) - ALLD(*) - ALLX
Notice DELDUMP step here. DUMP data set is created even if you specify 'TYPRUN=NORUN' after all it's allocated via DD statement. So if you want to test it with 'TYPRUN=NORUN' you would have to remove this data set before each rerun, this step does it for you. You should also remember to use different name for DUMP data set that data sets you select in ADRDSSU control statements. In this example if 'userid.ADRDSSU.DUMP' name is used the dump itself (empty at that point) would be also included in dump. RESTORE JCL Code:
//JSADEK01 JOB NOTIFY=&SYSUID //GDG EXEC PGM=IDCAMS //SYSPRINT DD SYSOUT=* //SYSIN DD * DEFINE GDG (NAME(JSADEK.ADRDSSU2.GDG) - LIMIT(3) - SCRATCH //RESTORE EXEC PGM=ADRDSSU,REGION=0M,COND=(0,NE) PARM='TYPRUN=NORUN' //DUMP DD DISP=SHR,DSN=&SYSUID..DUMP.ADRDSSU //SYSPRINT DD SYSOUT=* //SYSIN DD * RESTORE DATASET(INCLUDE(**)) - RENUNC(*.ADRDSSU.**,*.ADRDSSU2.**) - INDD(DUMP) - TGTGDS(ACTIVE) - CATALOG
As before GDG base must be created and 'TGTGDS(ACTIVE)' parameter used during GDG processing. There is a simply trick to display data sets included in ADRDSSU DUMP – simply run RESTORE job but with 'TYPRUN=NORUN' keyword. Example cleanup job:
//JSADEK01 JOB NOTIFY=&SYSUID //DELETE EXEC PGM=IDCAMS //SYSPRINT DD SYSOUT=* //SYSIN DD * DELETE JSADEK.ADRDSSU2.GDG.* DELETE JSADEK.ADRDSSU2.*
But it's much faster to issue those commands manually from TSO level. Some IDCAMS commands can be issued via TSO. You can use panel 6 or simply issue them with TSO prefix from any ISPF or SDSF screen:
TSO DEL 'JSADEK.ADRDSSU2.GDG.*' TSO DEL 'JSADEK.ADRDSSU2.*'
The only difference is that you need to use quotes with data set names because TSO would add your user ID as prefix otherwise. This is method worth remembering because it's the fastest way to remove many data sets using Generic names. LISTCAT is another example of IDCAMS command often used via TSO.
Solution 8
Copy JCL code:
//JSADEK01 JOB NOTIFY=&SYSUID //COPY EXEC PGM=ADRDSSU,REGION=0M PARM='TYPRUN=NORUN' //SYSPRINT DD SYSOUT=* //SYSIN DD * COPY DATASET(INCLUDE( - --- your data sets --- )) - RENUNC(**,*.COPY1.**) - OUTDYNAM(SPARE1) - WAIT(2,20) - TGTGDS(ROLLEDOFF) - BYPASSACS(**) - NMC - NSC - ALLD(*) - ALLX
Full volume dump:
//JSADEK01 JOB NOTIFY=&SYSUID //DELETE EXEC PGM=IEFBR14 //DELDD DD DSN=&SYSUID..DUMP.FULL,SPACE=(TRK,1), // DISP=(MOD,DELETE) //FULLDUMP EXEC PGM=ADRDSSU,REGION=0M PARM='TYPRUN=NORUN' //DUMP DD DSN=&SYSUID..DUMP.FULL,DISP=(NEW,CATLG), // SPACE=(CYL,(100,100),RLSE) //SYSPRINT DD SYSOUT=* //SYSIN DD * DUMP INDYNAM(SPARE1) - OUTDD(DUMP) - COMPRESS
Quick checklist before restore: - DASD type of source and target volumes? - SMS – are source volume SMS or non-SMS? - If target volume is different than source volume – make sure target volume is empty. - If target and source volume point to the same DASD – make you data sets on source volume are not used by RLS and there aren't any other data integrity risks. - Status of target volume on all systems that have access to it 'DS QD,devnum,QHA'. - If you restore dump to a different volume with COPYVOLID keyword also check device allocation status 'D U,DASD,ALLOC,devnum,1'. Full volume restore:
//JSADEK01 JOB NOTIFY=&SYSUID //RESTORE EXEC PGM=ADRDSSU,REGION=0M PARM='TYPRUN=NORUN' //DUMP DD DISP=SHR,DSN=&SYSUID..DUMP.FULL //SYSPRINT DD SYSOUT=* //SYSIN DD * RESTORE INDD(DUMP) - OUTDYNAM(SPARE2)
During restore operation WTOR “ADR369D AUTHORIZE FOR WRITE ACCESS A VTOCIX DATA SET” will ask you for confirmation that VTOC index can be rebuilt. It's name will be retained but it will copied from source volume so for example if VTOCIX on SPARE1 have 15 tracks and the one on SPARE2 30 tracks then after restore VTOCIX on SPARE2 will have 15, not 30 tracks. We don't use COPYVOLID. This parameter allows you to rename target volume to source volume name. There cannot be two DASDs with the same volser online so either target volume will be automatically put offline or WTOR will be issued to ask which one should be put offline. For later comparison save VTOC listing for both volumes, for example:
//JSADEK01 JOB NOTIFY=&SYSUID //STEP1 EXEC PGM=IEHLIST //SYSPRINT DD DSN=&SYSUID..VTOC.FULL,DISP=(NEW,CATLG), // SPACE=(TRK,(60,60),RLSE),LRECL=121,RECFM=FB,BLKSIZE=12100 //DD1 DD UNIT=3390,VOL=SER=SPARE1,DISP=OLD //SYSIN DD * LISTVTOC FORMAT,VOL=3390=SPARE1
Solution 9
Physical dump JCL code:
//JSADEK01 JOB NOTIFY=&SYSUID //DELETE EXEC PGM=IEFBR14 //DELDD DD DSN=&SYSUID..DUMP.PHYSICAL,SPACE=(TRK,1), // DISP=(MOD,DELETE) //PHYSDUMP EXEC PGM=ADRDSSU,REGION=0M PARM='TYPRUN=NORUN' //DUMP DD DSN=&SYSUID..DUMP.PHYSICAL,DISP=(NEW,CATLG), // SPACE=(CYL,(100,100),RLSE) //SYSPRINT DD SYSOUT=* //SYSIN DD * DUMP DATASET(EXCLUDE(SYS1.VTOCIX.*,SYS1.VVDS.*)) - PHYSINDYNAM(SPARE1) - OUTDD(DUMP) - COMPRESS
If you want to dump entire volume with physical or logical dump you must remember to exclude VTOC index and VVDS and of course you must consider all types of data sets that reside on the volume to create appropriate job for them. Physical restore JCL code:
//JSADEK01 JOB NOTIFY=&SYSUID //RESTORE EXEC PGM=ADRDSSU,REGION=0M PARM='TYPRUN=NORUN' //DUMP DD DISP=SHR,DSN=&SYSUID..DUMP.PHYSICAL //SYSPRINT DD SYSOUT=* //SYSIN DD * RESTORE DATASET(INCLUDE(**)) - INDD(DUMP) - OUTDYNAM(SPARE2) - BYPASSACS(**) - NMC - NSC
Solution 10
Logical dump JCL code:
//JSADEK01 JOB NOTIFY=&SYSUID //DELETE EXEC PGM=IEFBR14 //DELDD DD DSN=&SYSUID..DUMP.LOGICAL,SPACE=(TRK,1), // DISP=(MOD,DELETE) //LOGDUMP EXEC PGM=ADRDSSU,REGION=0M PARM='TYPRUN=NORUN' //DUMP DD DSN=&SYSUID..DUMP.LOGICAL,DISP=(NEW,CATLG), // SPACE=(CYL,(100,100),RLSE) //SYSPRINT DD SYSOUT=* //SYSIN DD * DUMP DATASET(EXCLUDE(SYS1.VTOCIX.*,SYS1.VVDS.*)) - LOGINDYNAM(SPARE1) - OUTDD(DUMP) - COMPRESS
ADRDSSU control statements for logical and physical restore are identical. ADRDSSU selects appropriate mode based on the input dump data set. Now you have four VTOC listing: - userid.VTOC.FULL - userid.VTOC.LOGICAL - userid.VTOC.PHYSICAL - userid.VTOC.SOURCE You can use SuperC Utility (panel 3.12 by default) to compare VTOC listing of source volume with each dump and see the difference: - Full dump – there is almost no difference here. Data sets are identical and are stored in the same track address as originally. Also VTOC entries are identical. Only volser and VTOC index name are different. Note that even data set residing on SPARE2 volume still have SPARE1 in 'SER NO' field in VTOC records (DSCBs). - Physical dump – Now 'SER NO' fields have correct value. Data sets addresses on the target volume different then the original. Data set characteristics such as used space are the same. - Logical dump – Like in case of physical dump addresses on target and source volumes don't match but also space allocation for data sets has changed. If no ALLD(*) and ALLX keywords are used, space without data is not copied – this is the most important difference between Logical and Physical dump – Physical dump copies all data sets characteristics while Logical focuses on the data used. If you use Logical with ALLD(*) and ALLX keywords in most cases there is no difference. Free DSCBs: - SOURCE - 2117 - FULL - 2117 - PHYSICAL - 2117 - LOGICAL - 2117 In this case there is no reduction in DSCBs after each restore. Probably because there was no data sets with more than 3 extends and first 3 extends are stored in first DSCB. If there were such data sets physical and logical dump would free some DSCBs. Free space (CYL/TRK): - SOURCE – 1790/25 - FULL – 1790/25 - PHYSICAL – 1791/10 – physical dump retains data set characteristics so space was probably regained by extend reorganization similar to done with DEFRAG command. - LOGICAL – 1802/16 – logical dump copies only data so effect will be the same as if you used RELEASE command on all data sets. - LOGICAL with ALLD(*) & ALLX – 1791/10 – the same as physical.
Solution 11
Consolidate JCL code:
//JSADEK01 JOB NOTIFY=&SYSUID //RESTORE EXEC PGM=ADRDSSU,REGION=0M PARM='TYPRUN=NORUN' //SYSPRINT DD SYSOUT=* //SYSIN DD * CONSOLIDATE DATASET(INCLUDE(**)) - PHYSINDY(SPARE1) - WAIT(2,20)
Consolidate command tries to reduce extends, join them together. This is done only when there is free continuous space after some extends. For example after extend #5 there are 2 free cylinders, if extend #6 is small enough to fit there it will be moved but if it has 3 cylinders move won't be performed. Compress JCL code:
//JSADEK01 JOB NOTIFY=&SYSUID //RESTORE EXEC PGM=ADRDSSU,REGION=0M PARM='TYPRUN=NORUN' //SYSPRINT DD SYSOUT=* //SYSIN DD * COMPRESS INCLUDE(**) - DYNAM(SPARE1) - WAIT(2,20)
Compress works only on PDS data sets and regains space inside them by member reorganization so it shouldn't have any effect on the volume space utilization. This operation is sometimes periodically done to ensure that PDS doesn't run out of space. Release JCL code:
//JSADEK01 JOB NOTIFY=&SYSUID //RESTORE EXEC PGM=ADRDSSU,REGION=0M PARM='TYPRUN=NORUN' //SYSPRINT DD SYSOUT=* //SYSIN DD * RELEASE INCLUDE(**) - DYNAM(SPARE1)
Release command free unused space from data sets allocation. You should take special care during that operation because very often data sets need this additional space. For example some sequential data set is often updated with MOD disposition. Or PDS have additional space to be able to store additional members in the future. Issuing release operation on such data sets will cause space problems and you'll have to eventually reallocate them with more space. Defrag JCL code:
//JSADEK01 JOB NOTIFY=&SYSUID //RESTORE EXEC PGM=ADRDSSU,REGION=0M PARM='TYPRUN=NORUN' //SYSPRINT DD SYSOUT=* //SYSIN DD * DEFRAG DYNAM(XX2A00) - WAIT(2,20)
Defrag is standard dick defragmentation operation. It moves data sets from one location on volume to another so they use continuous space. It speeds up data set access and in z/OS also frees extends so data sets will be able to extend further. During all those operation you need to consider if data sets on which you want to work are used by anything. It's best to schedule those activities to periods in which volume is not used. You can investigate what's allocating volume by using 'D U,DASD,ALLOC,devnum,1' command. You should pay special attention when using RELEASE command since it may cause space problems so if you don't know the purpose of data set on which you want to issue it it's best not to do so. Note: VTOC, VTOC Index and VVDS are system managed data sets and operations performed in this Task won't process them.
Executing Utilities without JCL
Introduction
Utility is just an another name for executable program. You can execute IEBGENER, DFSORT or ADRDSSU and any other Utility from many environments not only in JES2 environment via JCL scripts. You can use TSO, CLIST, REXX, C, C++, COBOL, Java and pretty much any other language used on z/OS. This exercise will teach you few alternate ways to use those programs. This will become very useful while coding in REXX or COBOL. For example you'll be able to use power of DFSORT instead of coding your own sort routines in REXX program.
Tasks
1. Execute IEBGENER via TSO. Leave ISPF or enter ISPF option 6(Command) and from that level execute IEBGENER to copy 'userid.EU2015.STATS' to 'userid.UTILEXEC.TSO'. 2. Execute IEBGENER via CLIST. Copy first 10 countries from 'userid.EU2015.STATS' to 'userid.UTILEXEC.CLIST'. 3. Execute IEBGENER via REXX. Copy first 20 countries from 'userid.EU2015.STATS' to 'userid.UTILEXEC.REXX'.
Hint 1
You'll need “TSO Command Reference”. Workflow is almost exactly the same as in JCL, first you'll need to allocate appropriate data sets (DD statements) and then execute IEBGENER.
Hint 2
CLIST (Command List) is a simple script language used to speed up and automatize your interactions with TSO. For more advanced tasks REXX is almost always a better choice but in this Task we want to perform task for which CLIST was created – to issue TSO command in specific order. Document “TSO/E CLISTs” describes this language. To execute CLIST use 'EXEC' line command next to the member name or issue “TSO EXEC 'dsname(memname)'”.
Hint 3
REXX is very useful language that can be interpreted in flight like CLISTs or compiled like C++ and COBOL. This is also the most useful language in z/OS administration. It's not likely you'll need to execute Utilities from TSO or CLIST but it's very useful to know how to do it via REXX. “TSO/E REXX User's Guide” and “TSO/E REXX Reference” are two primary documents describing this language. You may need to take a look at 'ADDRESS TSO' function.
Solution 1
TSO Commands:
ALLOC DDNAME(SYSUT1) DSNAME('JSADEK.EU2015.STATS') SHR ALLOC DDNAME(SYSUT2) DSNAME('JSADEK.UTILEXEC.TSO') NEW CATALOG LIKE('JSADEK.EU2015.STATS') ALLOC DDNAME(SYSPRINT) SYSOUT ALLOC DDNAME(SYSIN) DUMMY CALL 'SYS1.LINKLIB(IEBGENER)' FREE DDNAME(SYSUT1) FREE DDNAME(SYSUT2) FREE DDNAME(SYSPRINT) FREE DDNAME(SYSIN)
When it comes to commands itself you can see that this are pretty much the same keywords you use in JCL, only syntax is different but you can even use keywords like REFDD or LIKE. Another difference is that must specify data set name of IEBGENER since LINKLIST is not searched by default. But there is a solution for that, you can issue standard module search by using asterisk '*':
CALL *(IEBGENER)
Now system will search LPA and LINKLIST. Next difference is that you need to manually free allocated DD names. You can issue 'TSO ISRDDN' command to display data sets allocated by your TSO user session and the system. Before issuing FREE command you'll find there all data set you've allocated:
SYSUT1 JSADEK.EU2015.STATS SYSUT2 JSADEK.UTILEXEC.TSO SYSIN NULLFILE (Dummy) SYSPRINT ---------- JES2 Subsystem file -------------
SYSPRINT is worth mentioning here “JES2 Subsystem file” means spool but you need to know where in spool it's stored. When you execute Utility via JCL it runs in Initiator address space (batch job) or in Task address space (Started Tasks). But now IEBGENER is executed via TSO. This means that it will run in Address Space of you TSO User Session and there you'll find additional output 'SYSPRINT'. In case of JCL Initiator automatically frees allocated data sets, this is not the case here. Even after executing IEBGENER SYSUT1 will be still locked in SHR mode and SYSUT2 in EXC mode you need to always remember to free your allocations. Especially in your CLIST and REXX scripts.
Solution 2
CLIST Script:
ALLOC DDNAME(SYSUT1) DSNAME('JSADEK.EU2015.STATS') SHR ALLOC DDNAME(SYSUT2) DSNAME('JSADEK.UTILEXEC.CLIST') NEW CATALOG - LIKE('JSADEK.EU2015.STATS') ALLOC DDNAME(SYSPRINT) SYSOUT ALLOC DDNAME(SYSIN) DSNAME(TEMP) NEW DELETE DELETE - LRECL(80) RECFM(F,B) BLKSIZE(8000) OPENFILE SYSIN OUTPUT SET SYSIN = &STR( GENERATE MAXGPS=1) PUTFILE SYSIN SET SYSIN = &STR( RECORD IDENT=(2,'10',1)) PUTFILE SYSIN CLOSFILE SYSIN CALL *(IEBGENER) FREE DDNAME(SYSUT1) FREE DDNAME(SYSUT2) FREE DDNAME(SYSPRINT) FREE DDNAME(SYSIN)
The only real difference between CLIST and TSO commands from Task#1 is use of in-stream data. You cannot simply write it as part of CLIST but allocate new temporary data set and write IEBGENER controls statements in there with use of SET and PUTFILE CLIST commands. Of course depending on your needs you can use additional control instruction or error handling. Here is example of the same script but with some additional instructions:
SET IN='JSADEK.EU2015.STATS' SET OUT='JSADEK.UTILEXEC.CLIST' IF (&SYSDSN(&OUT) EQ DATASET NOT FOUND) AND + (&SYSDSN(&IN) EQ OK) THEN + DO FREE DDNAME(SYSUT1,SYSUT2,SYSPRINT,SYSIN) ALLOC DDNAME(SYSUT1) DSNAME(&IN) SHR ALLOC DDNAME(SYSUT2) DSNAME(&OUT) NEW CATALOG LIKE(&IN) ALLOC DDNAME(SYSPRINT) SYSOUT ALLOC DDNAME(SYSIN) NEW DELETE DELETE + LRECL(80) RECFM(F,B) BLKSIZE(8000) OPENFILE SYSIN OUTPUT SET SYSIN = &STR( GENERATE MAXGPS=1) PUTFILE SYSIN SET SYSIN = &STR( RECORD IDENT=(2,'10',1)) PUTFILE SYSIN CLOSFILE SYSIN CALL *(IEBGENER) FREE DDNAME(SYSUT1,SYSUT2,SYSPRINT,SYSIN) WRITE IEBGENER EXECUTED WITH RC=&MAXCC END ELSE WRITE ALLOCATION ERROR OCCURED. END
Solution 3
REXX Script:
/* REXX */ ADDRESS TSO IN='JSADEK.EU2015.STATS' /* SUPPLY INPUT DATA SET */ OUT='JSADEK.UTILEXEC.REXX' /* SUPPLY OUTPUT DATA SET */ IF SYSDSN("'"IN"'") <> 'OK' THEN DO SAY 'ERROR: INPUT DATA SET NOT ACCESSIBLE.' EXIT 8 END IF SYSDSN("'"OUT"'") <> 'DATASET NOT FOUND' THEN DO SAY 'ERROR: OUTPUT DATA SET ALREADY EXISTS.' EXIT 8 END "ALLOC FI(SYSUT1) DSNAME('"IN"') SHR" "ALLOC FI(SYSUT2) DSNAME('"OUT"') NEW CATALOG LIKE('"IN"')" "ALLOC FI(SYSPRINT) NEW TRACKS SPACE(5 5) RECFM(F B) LRECL(80)" "ALLOC FI(SYSIN) NEW TRACKS SPACE(5 5) RECFM(F B) LRECL(80)" SIN.1 = " GENERATE MAXGPS=1" SIN.2 = " RECORD IDENT=(2,'20',1)" "EXECIO * DISKW SYSIN (STEM SIN. FINIS" ADDRESS LINKMVS "IEBGENER" UTRC=RC "EXECIO * DISKR SYSPRINT (STEM SOUT. FINIS" "FREE FILE(SYSUT1,SYSUT2,SYSIN,SYSPRINT)" DO I=1 TO SOUT.0 SAY SOUT.I END SAY 'IEBGENER EXECUTED WITH RC='UTRC EXIT UTRC
REXX also can use TSO commands (ADDRESS TSO). ADDRESS function defines environment with which your script can communicate. You can address SDSF or MVS environments in the same way. REXX allows much easier and more intuitive coding than CLISTs so it's almost always a batter choice than CLIST.