z/OS Dataset Utilities

These links lead to sections in the text below.

IEBGENER
Copying flat files
IEBCOPY
Copying PDS files
IEFBR14
A useful dummy program
IDCAMS
Using IDCAMS with flat files
PDSMAN
Easier PDS file management

FDReport is a utility program that gets data from VTOCS and Catalogs. See the FDR Report section for details.

IEBGENER

IEBGENER is used for copying Physical Sequential files, and for copying members of Partitioned datasets or PDSEs. IEBGENER can only cope with record lengths up to 32760 bytes, longer records are truncated. It can also be used to convert sequential files to partitioned and partitioned to sequential. The example below shows IEBGENER at its simplest, to just copy a file. It is using a dataclass to get the attributes for the output file.

//S1       EXEC PGM=IEBGENER
//SYSUT1   DD DISP=SHR,DSN=input dataset
//SYSUT2   DD DISP=(,CATLG,DELETE),DSN=output dataset,
//      DATACLAS=SEQ80
//SYSPRINT DD SYSOUT=*
//SYSIN    DD *

Incidentally, if you are creating a new dataset, you must specify DISP=(,CATALOG) at the very least. The first parameter will default to NEW, but the second one defaults to DELETE! If you don't specify a disposition at all, the default is DISP=(NEW,DELETE,DELETE). So the job creates the file, writes data out to it, then deletes it! I once spend several hours in the middle of the night trying to work out why a job was not creating a file, when the problem was simply that I'd forgotten to add a DISP statement.

   EADM Advert

Accelerate DB2 Write with zHyperWrite and "EADM™ by Improving DB2 Logs Volumes Response Time:

Stacking datasets on tape using JCL

Some tape management systems, TLMS for example, will not let you add a file to an existing tape, as it considered the tape as non-scratch, so you have to stack them all up in one job. How do you stack datasets on a tape using JCL? If you want to copy several datasets to a single tape, you need to use a combination of label parameters and referbacks, and this can be quite complicated. Here is working sample using IEBGEBER.

//S1     EXEC PGM=IEBGENER
//SYSUT1 DD DISP=SHR,DSN=DSPRD.INPUT.FILE1,
//SYSUT2 DD DISP=(,CATLG,DELETE),
//       DSN=DSPRD.TAPE.FILE1,
//       VOL=(,RETAIN,,20),
//       LABEL=01,
//       UNIT=(CART,,DEFER)
//SYSPRINT DD SYSOUT=*
//SYSIN  DD *
/*
//S2     EXEC PGM=IEBGENER
//SYSUT1 DD DISP=SHR,DSN=DSPRD.INPUT.FILE2,
//SYSUT2 DD DISP=(,CATLG,DELETE),
//     DSN=DSPRD.TAPE.FILE2,
//     VOL=(,RETAIN,,20,
//     REF=*.S1.SYSUT2),
//     LABEL=02,
//     UNIT=(CART,,DEFER)
//SYSPRINT DD SYSOUT=*
//SYSIN  DD *
/*
//S3   EXEC PGM=IEBGENER
//SYSUT1 DD DISP=SHR,DSN=DSPRD.INPUT.FILE3,
//SYSUT2 DD DISP=(,CATLG,DELETE),
//       DSN=DSPRD.TAPE.FILE3,
//       VOL=(,RETAIN,,20,
//       REF=*.S2.SYSUT2),
//       LABEL=03,
//       UNIT=(CART,,DEFER)

Within the VOL statement, the ,RETAIN keeps the volume on the drive,and the ,,20 means the output can span up to 20 volumes.
When you allocate a tape to the first step, you mount a non-specific scratch tape. You want the other steps to use that tape, but you do not know in advance what the tape is. The REF=*.S1.SYSUT2 means use the same volume as was used in STEP S1, DDNAME SYSUT2.
LABEL=01 in the first step is not required as it will default, but it makes the job look consistent. The other LABEL statements must be specified and must be in incremental order.
If you are stacking DFDSS dumps using this technique, then make sure that every step has some data to dump, because if a step has no data, the dump is missed out, then the label statements go out of sequence and the job fails.

    GFS Advert

If you are processing several tape files in one job, each with its own DD statement, then z/OS will try to allocate all the tape drives that it needs up front. This is a waste of resources if you will only ever access one tape dataset at a time. To stop z/OS from allocating all the tape units up front, use the UNIT=AFF parameter like this

//DD1   DD DISP=OLD,DSN=DSPRD.INPUT.FILE1
//DD2   DD DISP=OLD,DSN=DSPRD.INPUT.FILE2,
//       UNIT=AFF=DD1
//DD3   DD DISP=OLD,DSN=DSPRD.INPUT.FILE3,
//       UNIT=AFF=DD2

It is more efficient to write data to tape with large blocksizes, as that allows the tapes to stream and not backhitch every time they write a new block. The largest blocksize allowed for disk datasets is 32760, but IEBGENER can write bigger blocksizes to tape using the SDB (system determined blocksize) PARM statement. The parameter is

//STEPNAME   EXEC PGM=IEBGENER,PARM=SDB=LARGE

This allows IEBGENER to write blocksizes bigger than 32760. The actual optimum blocksize is picked by the system. Other valid options are

  • SDB=SMALL - do not use blocksizes greater that 32760
  • SDB=INPUT - make the blocksize the same as the input file
  • SDB=YES - same effect as SMALL
  • SDB=NO - do not use system determined blocksize, so the blocksize will be the same as the input file, unless the input file is a large blocksize tape and the output is disk, in which case the blocksize will be 32760.

The default if the SDB parm is not specified is usually to copy the input blocksize. This is defined in the COPYSDB= parameter in the DEVSUPxx PARMLIB member.

back to top


IEBCOPY

IEBCOPY is used to copy a PDS, to copy a PDS into a PDSE, or to merge two PDS files together. It can also be used to compress a PDS in batch.

In the example below, the input file and output file are the same, so this is a batch compress

//COMPRESS    EXEC     PGM=IEBCOPY
//A    DD  DSNAME=input.dataset,
//       DISP=OLD
//B    DD  DSNAME=input.dataset,
//       DISP=OLD
//SYSIN DD *
       COPY OUTDD=B,INDD=A

The next example shows an entire PDS being copied to another. If you try to do this with an IEBGENER, the job will 'work' but all the members will be joined into one big file. IEBCOPY will use the DCB from the input file by default, unless you override it. In the example, all the DCB except space comes from the input file.

//S1       EXEC PGM=IEBCOPY
//SYSUT1   DD DISP=SHR,DSN=input.pds
//SYSUT2   DD DISP=(,CATLG),DSN=output.pds,
//       SPACE=(TRK,(50,50))
//         UNIT=3390
//SYSPRINT DD SYSOUT=*
//SYSIN    DD *
  COPY INDD=SYSUT1,OUTDD=SYSUT2
//

If the following input statements are used, instead of copying the whole PDS, the job will just copy the four selected members.

 COPY INDD=((SYSUT1,R)),OUTDD=SYSUT2
   SELECT M=(XMB8DY01)
   SELECT M=(XMB8DY02)
   SELECT M=(XMB8DY03)
   SELECT M=(XMB8DY04)

Finally, here's a job I run if I need to make a PDS larger. You need to alter the file name from 'changeme' to your file, and change the space units in STEP2 to suit your needs.


//STEP01   EXEC PGM=IDCAMS
//SYSPRINT  DD  SYSOUT=*
//SYSUDUMP  DD  SYSOUT=*
//SYSIN    DD  *
   ALTER  changeme -
        NEWNAME(changeme.O)
//*
//    IF (STEP01.RC = 0) THEN
//*
//STEP02    EXEC PGM=IEBCOPY
//SYSPRINT  DD SYSOUT=*
//SYSUDUMP  DD SYSOUT=*
//SYSUT1    DD DISP=SHR,DSN=changeme.O
//SYSUT2    DD DSN=changeme,
//          UNIT=3390,DISP=(,CATLG,DELETE),
//          SPACE=(CYL,(400,25,700)),
//          LIKE=changeme.O
//SYSIN     DD *
     COPY INDD=(SYSUT1),OUTDD=SYSUT2
/*
//   ENDIF
//

If you are really brave, you add a final step which deletes the changeme.o file, provided all the previous steps worked. Me, I delete it manually once I'm sure the bigger file is working ok.

back to top


IEFBR14

IEFBR14 is a dummy program that does nothing except return a completion code of 0. However, when you run IEFBR14, all the attached JCL statements are checked and executed. This means it is a very useful program for working with files in batch. For instance, if you want to create a new dataset and delete an old one as part of a batch run, the following JCL would do the job

//BR14JOB1 JOB 1,AJA,MSGCLASS=X
//       EXEC PGM=IEFBR14
//NEWDS  DD DSN=NEWFILE.LIB.CNTL,DISP=(NEW,CATLG),
//       UNIT=3390,SPACE=(CYL,(3,1,25)
//OLDDS  DD DSN=OLDFILE.DATA,DISP=(OLD,DELETE)

Yes, you can do this easily using ISPF, but if you need to create and delete files as part of a batch run, IEFBR14 is an easy way to do it.

back to top


IDCAMS

IDCAMS is mainly used for VSAM datasets, and this is discussed in the VSAM section and the ICF catalog section. IDCAMS has a few uses for ordinary files, as described below. Standard IDCAMS uses the following DD cards

//STEP01 EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//SYSUDUMP DD SYSOUT=*
//SYSIN DD *

After this, the SYSIN cards are all different. The first example will add 5 new candidate volumes to a file, that is, it allows the file to extend over 5 more volumes. You need to close the file before the extra volumes are picked up. These volumes are non-specific, and allocated by SMS

  ALTER dataset.name ADDVOLUMES(* * * * *)

The next example will change the management class of a file

  ALTER AH.TEST.DUMP MGMTCLAS(NOMGMT)

In both these examples, if you are just changing a few files, its easier to enter these commands as line commands from ISPF option 3.4. as shown below.

How do you fix an SMS dataset which has become uncataloged? You can't simply enter a 'C' as a line command against it. The answer is to use IDCAMS as shown below


  DEFINE NONVSAM -
   (NAME(uncataloged.file) -
     DEVICETYPES(3390) VOLUMES(VG0023) RECATALOG) -
     CATALOG(CATALOG.TSOUSER)

While z/OS datasets have to be accessed through their catalog entry, it is possible to define 'aliases', which are alternative catalog entries that point to a physical dataset. They are often used for different versions of test programs, so that different versions can be identified by name, but a consistent 'production' name is used for the alias name. This means that JCL does not need to be changed when new program versions are introduced. For example, the production name for a program library might be PASP.ONLINE.CMDLIB and the current version might be PASP.ONLV217.CMDLIB. You then point an alias from PASP.ONLINE.CMDLIB to PASP.ONLV217.CMDLIB and your online systems will pickup the correct data. You set this up with an IDCAMS define alias command.


  DEFINE ALIAS -
     (NAME(PASP.ONLINE.CMDLIB) -
     RELATE(PASP.ONLV217.CMDLIB) ) -
     CATALOG(USERCAT3)

There was a restriction, that the Alias had to be in the same catalog as the entryname, but this restriction was removed in z/OS 2.1. That release also records the alias creation date, which is useful if you are cleaning up old and obsolete data.

IDCAMS can be used to delete DFSMS managed files that have become faulty. Because SMS insists that every managed file must be catalogued you cannot delete an uncatalogued file with 'D' or 'DEL' as a 3.4 line command. The following IDCAMS statements will delete an non-vsam file and is the equivalent of the TSO DEL command.

   DELETE FDRABR.VX3003B -
      NONVSAM

The statement below will delete an non-vsam file from a specific catalog, that exists on the volume specified in DD1.

//DD1       DD  VOL=SER=SYSV00,
//    DISP=SHR,UNIT=DISK
//SYSIN   DD *
    DELETE FDRABRT.VSYSV00 -
      NONVSAM FILE(DD1) -
      CATALOG(CATALOG.ABRBASET)

This statement will delete the catalog entry for a dataset, but will not delete the actual data from the disk. This one is useful to get rid of catalog entries that have no data.

    DELETE FDRABR.VSYSV00 NOSCRATCH

This is the opposite to the example above. It will delete an uncatalogued dataset from the disk identified in the DD2 ddname. The NVR parameter identifies that this is not a VSAM dataset.

//DD2     DD  VOL=SER=VOL001,
//    DISP=SHR,UNIT=DISK
//SYSIN   DD  *
    DELETE PIB.TEST.DPLETTER.L95 NVR FILE(DD2)

The DCOLLECT utility is accessed through IDCAMS. This will provide very comprehensive statistics about disks and datasets, but in a raw and difficult to interpret format. If you use IDCAMS then you really need to invest in Merril's MXG SAS programs to interpret it. This example will return lots of SMS data for every online volume

//GDSDD1   DD  DSN=DXP.LISTING.DCOLLECT,
//    DISP=(,CATLG,DELETE),
//          SPACE=(CYL,(250,50),RLSE)
//SYSUDUMP  DD  SYSOUT=*
//SYSIN     DD *
  DCOLLECT -
    OUTFILE(GDSDD1) -
    VOLUMES(*) -
    SMSDATA(ACTIVE)

This example will extract MCDS data from HSM

//SYSIN    DD  *
    DCOLLECT -
      OUTFILE(GDSDD1) -
      MIGRATEDATA

back to top


PDSMAN

Sites which run PDSMAN usually alias it out, so it looks like you are executing IBM's IEBCOPY, but you are actually executing CA's PDSMAN. You can usually work out what you are running by checking the first line in the SYSPRINT output file, which will look like
PDSMANr7.52 FASTCOPY FACILITY
if you are running PDSMAN

This example shows how to extend a PDS directory dynamically using PDSMAN. The program name is IEBCOPY, but it is actually executing PDSMAN

//STEP1    EXEC PGM=IEBCOPY
//SYSPRINT DD SYSOUT=*
//OUT      DD DISP=SHR,DSN=dataset.with.full.directory
//SYSIN    DD *
  ALTERDIR OUTDD=OUT,BLOCKS=10

The next example empties all the members out of a PDS

//STEP1   EXEC PGM=PDSM10,PARM='EMPTY'
//PDSMPDS  DD DISP=OLD,DSN=test.library

The next example will check on the structure of a PDS, and report on any errors it finds

//STEP1   EXEC PGM=PDSM13,PARM='VALIDATE'
//PDSMPDS  DD DISP=SHR,DSN=faulty.dataset
//PDSMRPT  DD SYSOUT=*

You cannot use wildcards to select members to copy between PDS files using IEBCOPY, but you can with use wildcards with PDSMAN

 COPY INDD=SYSUT1,OUTDD=SYSUT2
   SELECT MEMBER=(DM*)
   SELECT M=((+S++D*))
   SELECT M=((A*,B*),(+B*,+C*,R))

SELECT MEMBER=(DM*) will copy all members starting DM

SELECT M=((+S++D*)) will copy all members with S in position 2 and D in position 5

SELECT M=((A*,B*),(+B*,+C*,R)) will copy all members starting with A, and rename them so they start with B, and also copy all members with B in position 2, rename them so they have a C there instead, and replace any members that already exist.

This example will scan two libraries, and report on all members which contain the string '3590'

//S1        EXEC PGM=PDSM18,PARM='.ALL'
//PDSMPDS   DD DISP=SHR,DSN=master.schedule.joblib
//          DD DISP=SHR,DSN=master.schedule.proclib
//PDSMRPT   DD SYSOUT=*,OUTLIM=100000
//SYSIN     DD *
  OPTION LISTMEM=N
  SCAN TARGET='3590'
//

back to top