You are on page 1of 10

Utilities uncovered

Introduction
Just imagine, you have IPLed your brand-new MVT system (or MVS, if and
when it becomes available for Hercules). Now you decide to change some
parameters in SYS1.PARMLIB. Of course, you want to play it safe, like

 Wear a belt
 Wear suspenders
 Keep your hands in your pockets

With other words, before you change a crucial member (let's say
LNKLST00) you will want to make a safe copy, or backup, of this member.
Very simple, you say:

You fire up explorer, click with the mouse, drag the member.... Oooops -
wrong timeframe, wrong system, restarting.....

You enter COPY LNKLST00 LNKLST01 at the MVT master console....


Ooops again, it ain't as simple as that at all

What you really do is: You call up a little helper and tell him to do the
copying for you. IBM has provided a lot of little helpers in MVT, and they
are called UTILITIES. We will discuss a few of the more useful ones here.

General Syntax Guidelines


Utilities (aka utility programs) are invoked using standard JCL. (For a short
introduction see the JCL in the N.U.D.E. document). You will neither need a
JOBLIB nor a STEPLIB DD statement, as the utilities are in the standard
system library. Depending on the utility program you will need certain
required DD statements in your JCL

SYSPRINT

With the SYSPRINT DD statement you tell MVT into which output queue
you want the utility to place its messages and report. Usually you would
code
//SYSPRINT DD SYSOUT=A

or, if you are not interested in the messages:


//SYSPRINT DD DUMMY
SYSIN

The SYSIN DD statement specifies the dataset that contains the commands
you want to give to the utility program. In most cases this is an instream
data set, i.e.:
//SYSIN DD *

or
//SYSIN DD DATA

If you do not want to issue any specific commands (but rely on some default
action the utility will take), you code:
//SYSIN DD DUMMY

Whenever you code commands for the utility (they are called Utility Control
Statements), some special rules apply:

• Commands must go in column 2 or later


• Anything written in column 1 is considered a label
• If a command does not fit unto one line, place a nonblank characer in
column 72 and continue in the next line at exactly column 16

Utility Programs
The following utility program will be discussed in this article (eventually)

IEFBR14
A Dummy Program. Does Nothing. Really. Nothing. Nada. Ne Riens.
Inge Ting. Nix.
IEBGENER
Copies sequential data sets
IEBCOPY
Copies partitoned data sets
IEHDASDR
Doing weird things to a DASD (...aka disk)
IEBPTPCH
Prints (or punches) partitioned or sequential datsets or members of
partitioned data sets
IEHLIST
Prints datasets and VTOC information
IEHPROGM
Maintains the catalog. Can delete and uncatalog datasets
IEFBR14
A program that REALLY does nothing. Zilch. Why do we need such a
thing? Well, look at the following JCL:
//MYJOB JOB CLASS=A,MSGCLASS=A,REGION=256K,MSGLEVEL=(1,1)
//NEWFILE DD DISP=(NEW,CATLG),DSN=MY.NEW.FILE,
// UNIT=3330,VOL=SER=WORK01,
// SPACE=(CYL,(10,10,10)),DCB=SYS1.PARMLIB
//

From the NEWFILE DD statement it is clearly seen that this job tries to
make a new file. Unfortunately, it will fail with a JCL error!!! Can you see
the error in the JCL statement?

It is not really obvious, but the error is in the EXEC statement! Which
EXEC statement? Well, THAT exec statement, the one that has not been
coded. The JCL error message is
JOB HAS NO STEPS

And here is where IEFBR14 comes in: A program that just doesn't do
anything - but keeps the MVT JCL parser happy:
//MYJOB JOB CLASS=A,MSGCLASS=A,REGION=256K,MSGLEVEL=(1,1)
//ALLOC EXEC PGM=IEFBR14
//NEWFILE DD DISP=(NEW,CATLG),DSN=MY.NEW.FILE,
// UNIT=3330,VOL=SER=WORK01,
// SPACE=(CYL,(10,10,10)),DCB=SYS1.PARMLIB
//

IEFBR14 can also be used to get rid of a data set:


//MYJOB JOB CLASS=A,MSGCLASS=A,REGION=256K,MSGLEVEL=(1,1)
//DELETE EXEC PGM=IEFBR14
//GETRID DD DISP=(OLD,DELETE,DELETE),DSN=NOT.NEEDED.ANY.MORE

This is nice, of course, but what if the file to be deleted doesn't exist? Your
job will fail with
JCL ERROR, DATASET NOT FOUND

and none of the subsequent steps will execute. Therefore it might be better
to code sometimes:
//MYJOB JOB CLASS=A,MSGCLASS=A,REGION=256K,MSGLEVEL=(1,1)
//DELETE EXEC PGM=IEFBR14
//GETRID DD DISP=(MOD,DELETE,DELETE),DSN=NOT.NEEDED.ANY.MORE,
// UNIT=SYSDA,SPACE=(TRK,(0))
If the file exists, it will be deleted, and if it does not exist, it will be created
at step beginning and deleted at step end
By the way, do not try to delete a member of a PDS with IEFBR14 - grown
men have been known to cry because of this. What would the following JCL
do:
//DONTRUN JOB (REALLY,DONT),'RUN THIS!!',CLASS=Z,MSGCLASS=A
//ALLOC EXEC PGM=IEFBR14
//GETRID DD
DISP=(OLD,DELETE,DELETE),DSN=VERY.IMPORTNT.FILE(OBSOLETE)

Will it delete the member OBSOLETE which is in file


VERY.IMPORTNT.FILE? Hm - after the job completes, the member is
gone. Good. but also, the file is gone. Not so good. Remember, disposition
in JCL refers to the whole dataset, not to individual members!!!

IEBGENER
IEBGENER is basically a copy program that copies sequential file to
another sequential file. It can also be used to read a sequential file and place
parts of it into different members of a partitioned dataset.

Required DD statements

SYSUT1

Dataset containing the INPUT data for IEBGENER

SYSUT2

Dataset containing the OUTPUT data from IEBGENER

SYSIN

Utility control statements. Can be DUMMY. If DUMMY, the default


operation is COPY from SYSUT1 to SYSUT2, no editing

SYSPRINT

Utility Message Data Set

To make a backup copy of a member of a PDS, you might code:


//MYJOB JOB CLASS=A,MSGCLASS=A,REGION=256K,MSGLEVEL=(1,1)
//BACKUP EXEC PGM=IEBGENER
//SYSPRINT DD SYSOUT=A
//SYSUT1 DD DISP=SHR,DSN=SYS1.PARMLIB(LNKLST00)
//SYSUT2 DD DISP=SHR,DSN=SYS1.PARMLIB(LNKLST01)
//SYSIN DD DUMMY
Note, that you code DISP=SHR on the SYSUT2 DD statement, AND NOT
DISP=NEW. DISP applies to the whole dataset, not to a member!!!. Also,
do not forget the member name on the SYSUT2 DD statement!!! Can you
guess what happens if you do forget? IEBGENER will gladly
write the contents of the member LNKLST00 to the
beginning of the dataset SYS1.PARMLIB.
Unfortunately, this is the place where the directory of
SYS1.PARMLIB is located, and it will be overwritten,
making the whole SYS1.PARMLIB dataset contents
unaccessible.
Okay, but now you want to make a backup of library SYS1.LINKLIB.
Would you want to code several hundred jobs, each copying one member at
a time to a new dataset? Surely not!. This is where our next utility can shine:

IEBCOPY
IEBCOPY is a utility program used to copy partitioned datasets (aka
libraries)

Required DD statements

SYSUT1

Dataset containing the INPUT data for IEBCOPY

SYSUT2

Dataset containing the OUTPUT data from IEBCOPY

SYSIN

Utility control statements. Can be DUMMY. If DUMMY, the default


operation is COPY from SYSUT1 to SYSUT2, no editing

SYSPRINT

Utility Message Data Set

To make a backup copy of a partitioned dataset, you can code:


//MYJOB JOB CLASS=A,MSGCLASS=A,REGION=256K,MSGLEVEL=(1,1)
//CLEANUP EXEC PGM=IEFBR14
//SYS2LNK DD DISP=(MOD,DELETE,DELETE),DSN=SYS2.LINKLIB,SPACE=(TRK,
(0)),
// UNIT=3330,VOL=SER=WORK01
//BACKUP EXEC PGM=IEBCOPY
//SYSPRINT DD SYSOUT=A
//SYSUT1 DD DISP=SHR,DSN=SYS1.LINKLIB
//SYSUT2 DD DISP=(NEW,CATLG),UNIT=3330,VOL=SER=WORK01,
// SPACE=(CYL,(100,10,500)),
// DCB=SYS1.LINKLIB,
// DSN=SYS2.LINKLIB
//SYSIN DD DUMMY

The first step deletes a preexisting SYS2.LINKLIB. In the second step all
the members of SYS1.LINKLIB will we copied to a newly created
SYS2.LINKLIB. Finito. Simple.

Now, sometimes you might want to use more than one pair of datasets for
copying. You could achieve this with multiple IEBCOPY steps, of course.
But a more elegant way can be chosen:
//MYJOB JOB CLASS=A,MSGCLASS=A,REGION=256K,MSGLEVEL=(1,1)
//BACKUP EXEC PGM=IEBCOPY
//SYSPRINT DD SYSOUT=A
//SOURCE DD DISP=SHR,DSN=SYS1.LINKLIB
//TARGET DD DISP=SHR,DSN=SYS2.LINKLIB
//PARMLIB DD DISP=SHR,DSN=SYS1.PARMLIB
//PARMSAVE DD DISP=SHR,DSN=SYS2.PARMLIB
//SYSIN DD *
COPY INDD=SOURCE,OUTDD=TARGET
C I=PARMLIB,O=PARMSAVE

What has changed? We added Utility Control Statements. The first one tells
IEBCOPY to copy from INput DDname SOURCE to the OUTput DDname
TARGET, i.e. we tell IEBCOPY to use different DDnames than the default
ones, SYSUT1 and SYSUT2. The second control statement looks a bit more
crypric, but actually, it isn't. Commands and keywords can be abbreviated to
one character codes. The second command therefore tells IEBCOPY to copy
all members from SYS1.PARMLIB to SYS2.PARMLIB.

We can also copy several datasets into one target file. There are two
possibilities, one using concatenation (see JCL in the N.U.D.E.). The other
one by using a list of DDames
//MYJOB JOB CLASS=A,MSGCLASS=A,REGION=256K,MSGLEVEL=(1,1)
//BACKUP EXEC PGM=IEBCOPY
//SYSPRINT DD SYSOUT=A
//PROCLIB DD DISP=SHR,DSN=SYS1.PROCLIB
//PARMLIB DD DISP=SHR,DSN=SYS2.PARMLIB
//PARMPROC DD DISP=SHR,DSN=SYS1.PARMPROC
//SYSIN DD *
COPY INDD=(PROCLIB,PARMLIB),OUTDD=PARMPROC

A list of DD-names is enclosed in brackets


Actually, I have not been telling the truth, the whole truth, and nothing but
the truth. Members will only be copied when they do not already exist in the
target dataset, i.e. like named members will not be overwritten. This is not a
problem when the target dataset has just been created. But what if the target
dataset does already exist? Then we must tell IEBCOPY explicitly that we
want members to be overwritten:
//MYJOB JOB CLASS=A,MSGCLASS=A,REGION=256K,MSGLEVEL=(1,1)
//BACKUP EXEC PGM=IEBCOPY
//SYSPRINT DD SYSOUT=A
//PROCLIB DD DISP=SHR,DSN=SYS1.PROCLIB
//PARMPROC DD DISP=SHR,DSN=SYS1.PARMPROC
//SYSIN DD *
COPY INDD=((PROCLIB,R)),OUTDD=PARMPROC

Very good. So far you know how to copy complete libraries. Obviously, you
would also want to jsu copy a few member, or only one. Don't even think
about wildcards, they do not exist!! The correct way to copy just a few
members is
//MYJOB JOB CLASS=A,MSGCLASS=A,REGION=256K,MSGLEVEL=(1,1)
//BACKUP EXEC PGM=IEBCOPY
//SYSPRINT DD SYSOUT=A
//PROCLIB DD DISP=SHR,DSN=SYS1.PROCLIB
//PARMPROC DD DISP=SHR,DSN=SYS1.PARMPROC
//SYSIN DD *
COPY INDD=PROCLIB,OUTDD=PARMPROC
SELECT MEMBER=(ONEMEMBR)
S M=(MEMBERA,MEMBERB,MEMBERC)

with other words, you add another utility control statement where you tell
IEBCOPY which members you want selected. Keywords can be abbreviated
again. Also, you can copy a full library except for selected members. Look
at the next example:
//MYJOB JOB CLASS=A,MSGCLASS=A,REGION=256K,MSGLEVEL=(1,1)
//BACKUP EXEC PGM=IEBCOPY
//SYSPRINT DD SYSOUT=A
//PROCLIB DD DISP=SHR,DSN=SYS1.PROCLIB
//PARMPROC DD DISP=SHR,DSN=SYS1.PARMPROC
//SYSIN DD *
C I=PROCLIB,O=PARMPROC
EXCLUDE MEMBER=(ONEMEMBR)

Again, existing members in the target dataset will not be overwritten. If you
really want to do this, code
//MYJOB JOB CLASS=A,MSGCLASS=A,REGION=256K,MSGLEVEL=(1,1)
//BACKUP EXEC PGM=IEBCOPY
//SYSPRINT DD SYSOUT=A
//PROCLIB DD DISP=SHR,DSN=SYS1.PROCLIB
//PARMPROC DD DISP=SHR,DSN=SYS1.PARMPROC
//SYSIN DD *
C I=PROCLIB,O=PARMPROC
SELECT MEMBER=((MEMBERA,,R))

Note the double brackets again. This command will take MEMBERA from
SYS1.PROCLIB and will copy it to SYS1.PARMPROC, and will overwrite
any existing MEMBERA in the process. You might wonder what the pair of
brackets commas is all about...they indicate that a parameter has been
omitted. The omitted parameter specifies the new name of a member in the
target dataset:
//MYJOB JOB CLASS=A,MSGCLASS=A,REGION=256K,MSGLEVEL=(1,1)
//BACKUP EXEC PGM=IEBCOPY
//SYSPRINT DD SYSOUT=A
//PROCLIB DD DISP=SHR,DSN=SYS1.PROCLIB
//PARMPROC DD DISP=SHR,DSN=SYS1.PARMPROC
//SYSIN DD *
C I=PROCLIB,O=PARMPROC
SELECT MEMBER=((MEMBERA,MEMBERB,R))

This will take MEMBERA, and will store it as MEMBERB in the target
dataset, overwriting an existing MEMBERB.

Compress

Every so often (and more often than you like) a PDS fills up with garbage.
Actually, every time you change or overwrite an existing member, this
member is still part of the dataset, even if it cannot easily be accessed. When
your datset fills up this way, a COMPRESS is required for garbage
collection. This is done using IEBCOPY again. A compress (=garbage
collection) is performed if and only if the input and the output dataset of
IEBCOPY are identical:
//MYJOB JOB CLASS=A,MSGCLASS=A,REGION=256K,MSGLEVEL=(1,1)
//BACKUP EXEC PGM=IEBCOPY
//SYSPRINT DD SYSOUT=A
//PROCLIB DD DISP=SHR,DSN=SYS1.PROCLIB
//SYSIN DD *
COPY INDD=PROCLIB,OUTDD=PROCLIB

would reclaim space in the SYS1.PROCLIB dataset. Another possibility to


achieve the same result would have been
//MYJOB JOB CLASS=A,MSGCLASS=A,REGION=256K,MSGLEVEL=(1,1)
//BACKUP EXEC PGM=IEBCOPY
//SYSPRINT DD SYSOUT=A
//SYSUT1 DD DISP=SHR,DSN=SYS1.PROCLIB
//SYSUT2 DD DISP=SHR,DSN=SYS1.PROCLIB
//SYSIN DD DUMMY

IEHLIST
provided by Kevin Shelly

IEHLIST is a utility program used to list information from a VTOC


(Volume Table of Contents), a catalog, or a PDS (Partitioned Data Set)
directory.

Required DD statements

anyname

A DD reference to a disk volume that IEHLIST requires in order to read


stuff on that volume. Choose any DDNAME you want. The utility doesn't
care.

SYSIN

Utility control statements.

SYSPRINT

Utility message data set.

To list a Volume Table of Contents, you can code:


//MYJOB JOB CLASS=A,MSGCLASS=A,REGION=256K,MSGLEVEL=(1,1)
//LISTVTOC EXEC PGM=IEHLIST
//SYSPRINT DD SYSOUT=A
//VOLDD DD UNIT=SYSDA,VOL=SER=DLIB01,DISP=OLD
//SYSIN DD *
LISTVTOC FORMAT,VOL=3330=DLIB01
/*
//

This will print a list of the datasets on that volume along with some of their
attributes. There are two choices for the type of report generated. The
FORMAT option is formatted for easy reading. The DUMP format shows
each record of the VTOC in a dump-like format.

To list the contents of the catalog on a particular volume, you can code:
//MYJOB JOB CLASS=A,MSGCLASS=A,REGION=256K,MSGLEVEL=(1,1)
//LISTCTLG EXEC PGM=IEHLIST
//SYSPRINT DD SYSOUT=A
//VOLDD DD UNIT=SYSDA,VOL=SER=IPL001,DISP=OLD
//SYSIN DD *
LISTCTLG VOL=3330=IPL001
/*
//

In order to list the contents of a PDS directory, you can code:


//MYJOB JOB CLASS=A,MSGCLASS=A,REGION=256K,MSGLEVEL=(1,1)
//LISTPDS EXEC PGM=IEHLIST
//SYSPRINT DD SYSOUT=A
//VOLDD DD UNIT=SYSDA,VOL=SER=MVTRES,DISP=OLD
//SYSIN DD *
LISTPDS DSNAME=(SYS1.LINKLIB,SYS1.PL1LIB),VOL=3330=MVTRES,FORMAT
/*
//

Like the LISTVTOC control card, the LISTPDS control card accepts either
a FORMAT option or a DUMP option. The FORMAT option is for PDS
members created by the linkage editor (load modules).

Any number of control statements can be included in one IEHLIST step as


long as all the referenced volumes are mentioned in DD statements similar
to the VOLDD DD statement shown above. If the DASD volume is
mountable instead of permanently mounted, use something like:
//VOLDD DD UNIT=(SYSDA,,DEFER),VOL=(PRIVATE,SER=PUB001),DISP=OLD

instead.

IEHDASDR
Sorry, didn't het around to writing this chapter yet. If you have a write-up
on IEHDASDR, why don't you send it to me?

You might also like