MVS TOOLS AND TRICKS OF THE TRADE JANUARY 2008 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. PROTECTING OUR CODE FROM SYSTEM ERRORS This month, I'd like to talk about something that professional coders generally do, rather than something that systems programmers normally do. But this topic is of much concern for us as systems programmers as well, and you'll soon see why. Today I want to convey an appreciation for the fact that whenever we enter a wrong parameter in a system utility, we don't get a crazy, hard to diagnose system abend, but rather a nice, polite little message. This doesn't happen automatically when you write system code, but it has to be planned for. Today we'll look at just a few of the wrong things that can happen when we write system code, and at some of the corrections we (as programmers) can make to intercept the problems and have the program play nice. We generally take "protection from system abends" for granted, and we figure that the coders have already done all the work for us. But programmers of system utilities often have to guard against bad looking and unnecessary crashes that seem to come from out of nowhere, when they're testing out a new utility program. And the coders, sooner or later, learn to anticipate many of these. Not all of us (being sysprogs who don't code that often) generally have the chance to code a complete system tool for ourselves. But when we do use a tool that has flaws, we ALL NOTICE THE ERRORS immediately and are quite disturbed when they occur. These errors don't have to happen, and we should appreciate when the programmer has cleaned up his or her code to prevent them. I'll show you what I mean with a simple example. Suppose that you are using a certain tool to flip a system bit on or off. For instance, I'll invent an imaginary tool that makes a job cancelable or non-cancelable. Let's say the tool is a TSO command which is called "CANCL". You would use the tool as follows. From a TSO tube, if you wanted to make job MYJOBA cancelable, you would enter the command: "CANCL MYJOBA CNCL". And similarly, if you wanted to make MYJOBA non-cancelable, you would enter the command "CANCL MYJOBA NOCN". Fair enough. Now suppose additionally, that no provision was made by the coder of the CANCL tool to enter any other subcommand besides CNCL or NOCN. If a user would enter a misspelled subcommand like NOCL instead of NOCN, he might get a SOC1 or a SOC4 abend (instead of an informative message) with no meaningful further help forthcoming. This result certainly is very disturbing, and would render the CANCL tool nearly useless, unless you had some prior training and warning about not to enter the wrong subcommands. Today we'll illustrate a few of the ways in which a coder can protect the user from errors like this, just to give you an idea about what kinds of things have to be done. When we are the user, we don't tend to appreciate the efforts which the coder had made to protect us from our own errors, or from the system's errors. But when we are the coder, it is critical to think of every possible thing that can go wrong, and to not any errors creep in which would bring about serious or confusing consequences. ONE EXAMPLE Here is one example where the coder can "silently" protect the user. Suppose he has written a TSO command that has to be run APF authorized, and it wasn't run that way. The "unprotected" result will usually be a System 047 abend, which signifies that an "authorized function" was requested by this program, and since the actual program was not run "APF authorized", this function cannot be fulfilled. That would happen when you just allow the Operating System to detect the error, and the above S047 abend would probably be the result. But now, if the programmer had anticipated the situation, he or she could have coded a TESTAUTH macro with FCTN=1 before trying to perform the authorized operation in the code. If the return code from TESTAUTH was not zero, this means that the code was not (at that point) running APF authorized, and a proper reaction by the programmer would be to issue an error message which says that "This Program must be run APF-authorized". After issuing that message, the program would exit. If the return code from TESTAUTH WAS zero, then the program could go on to do its job. Such a "programmed protection" will tell the user what was wrong, and it also could give some hint as to how to correct the situation. So you can now see, that it is usually up to the programmer of any system tool, to protect the user from "system errors" as well as "user errors" in using his/her tool. And it is especially important for the programmer NOT to leave the user at the mercy of the Operating System (which will probably generate a barely decipherable abend, at best). In a worse case, an uncorrected user error might actually cause the program to flip the wrong bit, or it might incorrectly alter some other storage in a bad way. Our emphasis this month however, is to show a few ways how our trusty system tools shelter us from the operating system's very raw error mechanisms by intercepting "error calls" to the Operating System BEFORE they occur, and then clearly telling us what the error was, AS it occurs. WE (as programmers) can write the error messages for our users more coherently than the operating system can! IF FILES ARE MISSING Here is a situation which is not usually anticipated by the casual user of a system tool, if that tool happens to require the allocation of one or more files. What if you leave out a DD name in the JCL, or similarly for a TSO command, what if you don't allocate (dynamically or statically) a file that the program needs? Here are a few of the possible consequences, if the programmer did not make provisions to protect the program. One example: if you try to CLOSE a file that has not been OPENed, you get a nasty S0C1 abend. Another example: if you leave out a SYSPRINT DD name where the output of the program is supposed to go, and the program tries to WRITE to SYSPRINT. Blooey! Here comes another S0C1 (probably). That's enough to mention, for now. There are two tiers of protection for missing DD names, or in the case of a TSO command, for missing file allocations. The first tier is to do a TIOT scan to see if the DD name is even there. If there's no DD name, then there isn't even a possibility to OPEN the file at all, much less to try and CLOSE it. The second tier is to check, after an attempted file OPEN, to see if the OPEN really worked. If you ran an OPEN macro to attempt to OPEN a file, and the OPEN failed, you need to know that the file isn't OPEN. Then, you wouldn't try afterwards to CLOSE the file. Also, you might try and issue a message that the file could not be OPENed. After that, you'd exit the program gracefully. This post-OPEN check is done by examining the OPEN flags, at (decimal) location 48 or X'30' past the beginning of the DCB being OPENed, to see if if the X'10' bit is turned on. If that bit is not on, then the OPEN didn't work, and you have to take the necessary measures to protect the rest of the program, and the user. IF FILES ARE IN THE WRONG FORMAT Once you know that a file is there, and you have OPENed it, you might then try to READ a record from it or WRITE a record to it. But what if you need information about the physical file itself that was just OPENed, such as its DSORG (data set organization, PS, PO, etc.) or its Record Format (FB, VB, etc.), its record length, or its block size, or even extra information about the allocation, like if any secondary extents were asked for? You find that out, in your program, by issuing a RDJFCB (or Read The JFCB) macro. The RDJFCB macro can be issued before or after an OPEN macro, and it brings the current contents of the file's JFCB (Job File Control Block) into the program for your examination. Examining the JFCB by reading it with a RDJFCB macro, can expose more subtle errors in your program, without having to force the user do the diagnosis. For example, if your program tries to write a long record to a file, and the record length of the file (as shown by an inquiry into the JFCB after a RDJFCB) is not big enough to accommodate the long record, then you can make provision for that possibility without the user having to worry about it. And this applies to many similar situations--just use your imagination. In short, it is better for the program to intercept an error than for the system to find it, or for the error to cause an "explosion" that bursts unexpectedly on the user. SUMMARY Today, I've tried to give a small indication as to how the programmers of system tools have to work hard, to protect the users of their tools from being unnecessarily exposed to system errors or from being "splattered to bits" by simple user errors. Of course, application programmers also know very much about some of these principles. But system tools, since they deal with system quantities and system storage, and they might also have to be run APF-authorized, have special needs, to be able to run correctly. I'm sorry that I don't have space today, to go into more details. But I trust that once you see a few of the possibilities, you'll get the idea that there's more to writing a system tool than to just get to the right place and perform the right action. The users (of the tool) have to be protected from unnecessary system abends, too. I wish all of you the very best of everything, and a very happy and prosperous year. I'm looking forward to seeing all of you here again, next month.