MVS TOOLS AND TRICKS OF THE TRADE FEBRUARY 2001 Sam Golob MVS Systems Programmer P.O. Box 906 Tallman, New York 10982 Sam Golob is a Senior Systems Programmer. He also participates in library tours and book signings with his wife, author Courtney Taylor. Sam can be contacted at sbgolob@cbttape.org. Information about the CBT MVS Tapes can be found on the web, at http://www.cbttape.org. DEFINING DATASET CHARACTERISTICS The MVS Operating System, unlike some other operating systems, defines how to deal with datasets by classifying them into certain formats. MVS has concepts of Fixed Blocked data, Variable Blocked data, Undefined record format data, among others. When managing data in MVS, we always have to reckon with such data descriptions. How do we communicate such descriptions of data to MVS when we run a job or an interactive task? We describe a dataset to MVS in a problem program using DCB information in the program code, and externally from the program, using JCL information, label information, and catalog information. In addition to those ways, tape management systems and databases add extra descriptions. But today, we're considering only "pure MVS" ways of describing dataset characteristics. There's enough to know, just in terms of pure MVS externals, to keep us very busy for a good while. Every one of us knows that there is a lot of information and detail in the OS/390 JCL manual. None of that information is superfluous, and a considerable amount of it can be necessary for our everyday work. After today's discussion, we'll hopefully have a better idea what all this detail is about, and why we might need it. Practically speaking though, we don't have to know "everything about JCL." One of the reasons for that, is because a lot of the dataset information is already contained in other places, and we don't have to add any extra JCL to supply it. Actually, many of the defining characteristics for datasets that we use, are contained in the DCB of the program, in catalog information, and in dataset labels on both disk and tape. The JCL that we actually code, is only necessary for filling in some of the information about the datasets, which the labels or catalog entries (or the VVDS on the volume) do not contain. System managed storage introduces a new dimension in the process of defining datasets, but we'll stick to the basics here, because once you know the basics of MVS datasets, you can understand later what System Managed Storage is defining, and managing. Much information about MVS dataset management, in my opinion, centers around the JFCB (Job File Control Block) control block. The DCB (Data Control Block) is more familiar to most people, and the DCB is the control block that the OPEN processing deals with most directly, but I think that a major key to understanding data management is in the JFCB also. There is one JFCB created for each dataset in a job step. Each JFCB is created by a DD card or a dynamic allocation request. And this JFCB is one of the places where MVS looks first, when it actually wants to OPEN and use a dataset. The OPEN processing actually "opens" the DCB (Data Control Block), and the "ultimate" processing of the dataset centers around the DCB, but I think you can learn a lot by concentrating on the potential information which can go into the JFCB. The IBM macro which describes the possible contents of the JFCB, called IEFJFCBN, is very detailed in its description of fields that describe dataset characteristics. Therefore I think that the IEFJFCBN macro is worth spending some time in studying. As is well known, presenting dataset information to an MVS job step is a merging process. Roughly speaking, any dataset characteristic not actually present in the DCB of the program, is filled in from the DD card information, which has gone into the JFCB. Dataset label information has also been merged into the JFCB, and when the dataset is actually opened, the OPEN process fills in any fields not yet completed in the DCB, from information contained in the JFCB. IBM's "Using Data Sets" manual describes this merging process in much more detail. I have to praise IBM for the fact that they have improved the organization of MVS manuals. Where once, there was more confusion, now there is an inclusive manual called "DFSMS: Using Data Sets" SC26-7339, that describes dataset management from the user's point of view, but which also provides a lot of information about dataset internals. Let's Look at a Program Take a look at Figure 1, which shows the complete text of a simple and general program called CKIEBGEN from Baldomero Castilla. This program copies one sequential dataset (pointed to by the SYSUT1 ddname) to another sequential dataset (pointed to by the SYSUT2 ddname). I can testify that the program works (and you can try it too). Our point in showing this particular program, is that it's very simple, and very general, because most of the particulars of defining the dataset characteristics are missing from it. Where must you supply that information from? It has to come, either from JCL, or from label information, or from catalog information. The CKIEBGEN program uses QSAM (Queued Sequential Access Method) to do I/O for its copy operations. QSAM works with "logical records" and not with physical blocks, using the GET macro to read a record from a file to a data buffer (MACRF=GM), and the PUT macro to write a record from that data buffer to another file (MACRF=PM). The use of QSAM simplifies a programmer's effort in coding I/O. However, QSAM has to "know" which part of a physical block is a "record", and in order for QSAM to have that information, all the dataset attribute information has to be present in the DCB after the dataset is OPENed. IBM has programmed the QSAM routines to use the dataset description information in the DCB, to construct proper channel programs to figure out how much data from a block constitutes a "record", and to GET and PUT only that much data each time. Now how does that work, inside our CKIEBGEN program? For example, suppose you have a cataloged partitioned dataset which is fixed blocked, LRECL=80, BLKSIZE=6000, and it has one member called MEMA. Suppose you want to use the CKIEBGEN program to copy MEMA into a new member of the same dataset, called MEMB. Our JCL to do so would be very simple. SYSUT1 would be specified as DISP=SHR,DSN=our.pds(MEMA) and SYSUT2 would be specified as DISP=SHR,DSN=our.pds(MEMB) . How can we get away with supplying so little dataset information? The answer is that the system can find out all the dataset characteristics from the label information (the Format 1 VTOC entry for the dataset on disk), and the catalog information (the volume containing the dataset). By the time CKIEBGEN OPENs the two DCB's, the QSAM copy operation "knows" how to make the correct channel programs, so its GET and the PUT macros will perform the copy properly, logical record by logical record. This same program and the same JCL can be used to copy members in a RECFM=VB, LRECL=255 partitioned dataset. The dataset characteristics of that pds are different from those of the first pds, but the VTOC entry for that dataset (the disk "label information") reflects this. When the MVS system allocates the dataset, the VTOC label information goes into the JFCB, and at OPEN time, QSAM constructs appropriate channel programs to GET and PUT the individual records properly. The channel programs which QSAM now constructs, are going to be different than the ones it constructed for the first dataset copy. But because of what we now know about dataset characteristics, we see that it won't matter to us. The CKIEBGEN program will work anyway. This will definitely NOT be the case if (for example) the input dataset is an unlabeled tape file, while the output dataset will be newly allocated and cataloged on disk. In such a case, in order to get the CKIEBGEN program to work properly, we have to specify a lot more information about these datasets in the JCL. Let's see how it works. In order to specify the characteristics of the input tape file, we have to specify the format of its data. If we don't know that, we might use a program which "feels" the data files on a tape, and reports what it has found about whether the data is fixed blocked, or variable blocked, or an unloaded partitioned dataset, and it might also tell us which program unloaded the pds (e.g. IEBCOPY or IEBUPDTE, or FDR). Such a program is the TAPEMAP program from File 299 of the CBT Tape collection, or the TAPESCAN program from File 102 (which shows more low-level information). Leonard Woren, one of the original authors of TAPEMAP, has his own version of TAPEMAP at his web site: www.best.com/~ldw/mvs . After reading our tape with this type of tool, and deciding which file we'd like to copy, we'd have to code JCL to tell CKIEBGEN what its detailed characteristics are. See Figure 2 for an example, to copy a fixed blocked tape file from an unlabeled tape. The output file, which is new and MVS doesn't know about it yet, also has to be characterized with "dataset properties". Figure 2 will give an example of the kind of additional information about the dataset that will have to be specified. So this example shows that even for relatively simple dataset manipulations, such as a QSAM dataset copy, you still have to know a lot about the dataset for the operation to be successful. Improving the CKIEBGEN Program I have found the CKIEBGEN program useful for my work, because "it is not too smart". For example, when I upload a pkzip'ed file from the pc to MVS, folding it into an FB-80 file on MVS, and I want to use IEBGENER to copy it, I find that IEBGENER "doesn't like" the zip file, thinking it's some (uncopyable) file in a special format. CKIEBGEN is not that "smart", and it obediently copies the FB-80 zip file. To me, this is usefulness. I've gotten my work done. I have improved the CKIEBGEN program somewhat, but not nearly as much as I want to. I added a SYSPRINT output file to report some of the results of its copy operation. I added "count" fields, to show how many GETs and how many PUTs the program did. At least, I know that the program wrote as many records as it read, and I have an idea how big the two files are. But there is much further room for improvement in the area of reporting the dataset characteristics of the files that were copied. (My current version of CKIEBGEN is on CBT Tape File 229.) Actually, I'd like the CKIEBGEN program to report all the input and output dataset characteristics as the program "sees" them. This would tell us information about the datasets that we did not code in the JCL. The potentially improved program would tell us record format and DSORG for input and output datasets, as well as LRECL and BLKSIZE. Then we'd really know how well the CKIEBGEN program worked, and what it actually did. Where should CKIEBGEN "look" for the information, so we could improve it in this way? We have a choice. We can get the information from the two JFCB's (for SYSUT1 and SYSUT2) before or after OPEN time. Or we can get the information from the filled-in DCB's after OPEN time. In order to extract the JFCB information, we'd have to modify each DCB to include an "exit list" which points to a descriptor and a 176-byte data area in our program that would receive a copy of that DD name's JFCB. An execution of the RDJFCB macro, even before OPEN time, would then copy all that JFCB inforamtion into our program. We could then access this JCL data and catalog information, and format it for reporting in the SYSPRINT output file. Our second choice is to get the information from the filled-in DCBs after OPEN time. To do this, we have to map the DCB control blocks using the DCBD macro, and then we can copy the field information into our program and format it for display in SYSPRINT. I can leave it as an exercise for some of you, to improve the CKIEBGEN program in this way, starting from my version on CBT Tape File 229. When you have tested your results, you can email them to me, and I can try to put the nicest version on the CBT Tape for everybody to use. I hope this month's article has helped you to think more about MVS data, both on its own, and in relation to data imported from other computing systems. Everything you learn, or figure out, will help you later, somewhere along the road. Best of luck to all of you! * * * * * * * * * * * * * * * * * * * * * * * Figure 1. Modified version of the CKIEBGEN program to show that if the program doesn't specify most dataset characteristics, then the JCL, or the catalog information, or the VTOC information (label information) have to supply those missing characteristics. These include LRECL, BLKSIZE, record format, DSORG, and others. Without this information, the QSAM GET and PUT macros in this program won't "know" how to construct the proper channel programs to do the copy operation. *------------------------------------------------------------- * * Program to copy a sequential file to another sequential file * * using QSAM. GET a record and write it to a buffer. PUT the * * record from the buffer to an output file. Loop until end of * * input. * * * * QSAM does the blocking. This program is very general, and * * you have to specify many of the dataset characteristics in * * the JCL, unless the system has another way to find them out. * * * * Qriginal program was from Baldomero Castilla. * * (Adapted to comment in English, and to use only IBM macros) * *------------------------------------------------------------- * CKIEBGEN CSECT YREGS USING *,R15 B EYECATCH DC C'CKIEBGEN' SAVEAREA DC 18F'0' EYECATCH DS 0H ENSURE ALIGNMENT SAVE (14,12) LR R5,R1 SAVE PARM POINTER LA R1,SAVEAREA NEW SAVE-AREA ADDR ST R1,8(,R13) FORWARD SAVE-AREA CHAIN PTR ST R13,4(,R1) BACKWARD SAVE-AREA CHAIN PTR LR R13,R1 NEW SAVE AREA ADDRESS LR R1,R5 RESTORE PARM POINTER DROP R15 * ----- SET UP ONE BASE REGISTER USING CKIEBGEN,R12 LR R12,R15 * ----- OPEN INPUT AND OUTPUT FILES OPEN (SYSUT1,(INPUT)) OPEN (SYSUT2,(OUTPUT)) * ----- READ-WRITE AND LOOP UNTIL END LOOPIT GET SYSUT1,AREA PUT SYSUT2,AREA B LOOPIT * ----- AT END OF INPUT, CLOSE FILES FIN CLOSE SYSUT1 CLOSE SYSUT2 * ----- AND FINISH THEEND DS 0H L R13,4(,R13) RETURN (14,12),RC=0 * ----- INPUT AND OUTPUT QSAM DCB'S SYSUT1 DCB DDNAME=SYSUT1,MACRF=GM,EODAD=FIN,DSORG=PS SYSUT2 DCB DDNAME=SYSUT2,MACRF=PM,DSORG=PS * ----- AREA DS CL32768 THIS IS THE DATA BUFFER END CKIEBGEN * * * * * * * * * * * * * * * * * * * * * * * Figure 2. JCL necessary to copy a non-labeled Fixed Block tape file to a newly allocated disk dataset using CKIEBGEN. Notice that the program, as coded, has no reporting facility to show if the copy was successful. You have to look directly at the output dataset to determine success. We've assumed that we've already used the TAPEMAP program or another similar tool, to "feel" for the physical characteristics of the input tape file, and we match our JCL for SYSUT1 to the information that TAPEMAP has obtained for us. //JOBNAME JOB card //* //CKIEBGEN EXEC PGM=CKIEBGEN //STEPLIB DD DISP=SHR,DSN=your.loadlib //SYSUT1 DD DISP=OLD,DSN=input.tape.file, // UNIT=TAPE,VOL=(PRIVATE,RETAIN,SER=TAPEA1), // LABEL=(3,NL,EXPDT=98000), // DCB=(RECFM=FB,BLKSIZE=8880,LRECL=80) //SYSUT2 DD DISP=(NEW,CATLG,DELETE),DSN=your.new.disk.file, // VOL=SER=DISKV1,DCB=*.SYSUT1,SPACE=(TRK,(60,90),RLSE), // UNIT=SYSDA