Rexx on CMS (part of z/VM) contains some functions that the documentation calls "External functions and routines". These are functions that are not included in Rexx on other platforms, because they are specific to CMS and VM. One of them is CSL, for calling callable services library (CSL) routines and one is CMSFLAG which allows you to test several different flag values in CMS. The ones I use most often are DIAG and DIAGRC, which allow you to call diagnose codes directly from Rexx. As I described in an earlier blog entery, a diagnose instruction or diagnose call is really a hypervisor call in z/VM. In other words, it is a way for an operating system or program, running in a virtual machine, to ask the hypervisor (CP in our case) to do something for you.
The most useful diagnose code is diag 8, which lets you issue a CP command. This is how operating systems, including CMS, can issue a CP command. Not all diagnose codes that you find defined in the CP Programming Services book can be issued by the Rexx diag function, but there are a lot of useful ones. My real reason for this blog post is that the diag interface to CP is the true programming interface to CP. The output to CP commands is intended to be for humans to read, not programs. If a diagnose interface is provided to obtain information from CP, then it should be used instead of the output of commands! However, I agree that many times processing the output to a CP command is the only way to find out some setting or information, so that is what you must do.
For instance, the result returned from diagnose 0 is the "extended identification code". If you want to know the level of z/VM that you're running on, you should use this value, not the output of QUERY CPLEVEL. But, even code you find on your VM system has things like:
"PIPE CP QUERY CPLEVEL | STRIP | XLATE | VAR CPLEVEL"
Parse var cplevel . "VERSION" v "RELEASE" r "." m "," .
vrm = STRIP(v)||STRIP(r)||STRIP(m)
To obtain the "vrm" using diag 0 is actually less complicated and doesn't depend on keywords in the output:
diag0=diag(0)It is true that you have to read the specifications of diag 0 to get the byte numbers, but it isn't that hard. Also, I used 5 lines to write this but it could also be written "vrm = c2d(substr(diag0,11,1)) || c2d(substr(diag0,37,1)) || c2d(substr(diag0,38,1))".
vrm = v||r||m
A bigger pet peeve of mine is using CMS pipelines to just suppress the output of a CP command. I see code like this: "PIPE CP XAUTOLOG VMSERVS" or "PIPE CP SLEEP 30 SEC". This is just as easy to read, runs faster, and achieves the same result: Call diag 8,'XAUTOLOG VMSERVS'. Rexx will put any output from the command in the variable "result" but you can just ignore that. Actually, the XAUTOLOG command isn't a good example because it has asynchronous output, so you're not really suppressing all the output. I code things like Call diag 8,'DETACH 120' frequently so that I don't see the "DASD 120 DETACHED" message. (Note: you can code this as "x=diag(8,'DETACH 120')" if you like, since it does the same thing as the call except assigns the output to "x" instead of "result".) To finish this though, "PIPE CP SLEEP 30 SEC" is really ridiculous, since the SLEEP command doesn't produce any output! Just code it as 'CP SLEEP 30 SEC'.
One other useful diagnose code that should be used instead of a CP command is diag 24 or 210 to get device information. A very good use of diag 24 is to test if your virtual machine is disconnected: If substr(diag(24,-1),13,1) = 2 then say "I am disconnected". I've also coded the test as "substr(diag(24,-1),13,1) <> 0".
I'll close this by wishing some of the new diagnose codes provided in recent releases of VM were supported by the Rexx diagnose interface. An earlier blog post talked about Diag A0 and an assembler routine to query it. It would be nice if Rexx had an interface to diag A0 subcodes 8 and 48. Also, and interface to diag 2cc (SSI query) would be useful, instead of having to parse the output from QUERY SSI!