Someone asked me how to detect if any of their system commands have been changed. By "system commands" they meant any of the commands in the library QSYS. I can think of two ways to do this, and I will describe both below.
I have written before about how to retrieve the defaults of a command, so I will not repeat that here.
When I tested both methods in the IBM i partition I use when writing these posts I found that only one command was returned as changed, therefore, the results I am going to show will be limited to that one command.
Has command's defaults changed? Using SQL
I think this method is only available to people using newer releases of IBM i, 7.3 and 7.4, and with the more recent Technology Refreshes. The Object Statistics table function, OBJECT_STATISTICS has been enhanced a lot in recent TRs, adding many new columns to the results. Two of these additions are:
- APAR_ID
- USER_CHANGED
The default values for these two columns for an unchanged command is the APAR id to be null and the User changed flag to be '0'.
When a command is changed, using the Change Default command, CHGDFT, or the Change Object Description API, QLICOBJD, the columns are updated. APAR id will now contain 'CHGDFT' and User changed flag will be '1'.
For this example if I wanted to see which, if any, commands had been changed in QSYS library I would use the following statement:
01 SELECT OBJNAME,APAR_ID,USER_CHANGED 02 FROM TABLE(QSYS2.OBJECT_STATISTICS('QSYS','CMD')) 03 WHERE APAR_ID = 'CHGDFT' ; |
Line 1: I want the following information returned to me:
- OBJNAME: Object name
- APAR_ID: APAR id
- USER_CHANGED: User changed flag
Line 2: These are the parameters passed to the table function. The first is the name of the library. The second is the object type. I could have used '*CMD', but I chose just to use 'CMD'. The results retuned from this function will be a list of all the commands in QSYS library.
Line 3: But I do not want all commands. I just want those that have changed. With this Where clause I select only those results where the APAR id is 'CHGDFT'.
The results show the changed command:
OBJNAME APAR_ID USER_CHANGED ------- ------- ------------ CRTLIB CHGDFT YES |
If I just wanted to check whether one command had changed I would change my SQL statement to be:
01 SELECT OBJNAME,APAR_ID,USER_CHANGED 02 FROM TABLE(QSYS2.OBJECT_STATISTICS('QSYS','CMD','CRTLIB')) ; |
Line 2: The third parameter is the name of the object.
There is no longer a need for a Where clause.
The result is the same as before.
Has command's defaults changed? Not using SQL
This becomes a two-step process. First I need to make a list of all the commands in QSYS library using the Display Object Description command, DSPBJD.
DSPOBJD OBJ(QSYS/*ALL) OBJTYPE(*CMD) DETAIL(*FULL) OUTPUT(*OUTFILE) OUTFILE(QTEMP/@DSPOBJD) |
Then I need to look in the output file, @DSPOBJD, for the two fields:
- ODAPAR: APAR id
- ODUMOD: User modified flag
What tool do I use to access the data from the output file?
I could use something as simple as the Run Query command, RUNQRY, and select any object that is a command and where the APAR id is 'CHGDFT'.
RUNQRY QRY(*NONE) QRYFILE((QTEMP/@DSPOBJD)) RCDSLT(*YES) Select Records Type comparisons, press Enter. Specify OR to Tests: EQ, NE, LE, GE, LT, GT, RANGE, LIST, AND/OR Field Test Value (Field, ODOBTP EQ '*CMD' AND ODAPAR EQ 'CHGDFT' |
But the results shows all the columns.
I know I said this was the "Not using SQL" method, but I meant gathering of the data not to use SQL. I can display what I want and in the format I want with this SQL statement:
01 SELECT ODOBNM,ODAPAR,ODUMOD 02 FROM QTEMP.@DSPOBJD 03 WHERE ODOBTP = '*CMD' 04 AND ODAPAR = 'CHGDFT' ; |
Line 1: Display Object name, APAR id, and User modified flag.
Lines 3 and 4: Only include in the results any object that is a command and the APAR id is 'CHGDFT'.
The results look the same as the one from OBJECT_STATISTICS:
ODOBNM ODAPAR ODUMOD ------ ------ ------ CRTLIB CHGDFT 1 |
I have to admit I do not know how to tell which parameters changed and what was the original value of those parameters. If you do know how to determine that please post in comments below.
This article was written for IBM i 7.4, and should work for some earlier releases too.
Thank you - getting ready to do an upgrade in a few weeks and always wondered which commands I've changed. Will add this gem to my checklist of things to do afterwards. I appreciate this.
ReplyDeleteHad a few projects get taken by surprise by this years ago.
ReplyDeleteI make it a rule to create a CL program that includes all the changes to IBM objects that you can run after an upgrade. Include any CHGCMDDFT commands as well as any other changes to IBM objects such as authority changes. That said, this is a good query to run to validate that nothing got missed.
ReplyDeleteI do exactly the same.
DeleteYou should never change defaults on commands in QSYS. Better to duplicate the command to a separate library, put that library on the system library list, and change the default there.
ReplyDeleteAlso, some third party products depend on certain command defaults in QSYS.
When I worked on a change control product, a standard part of our diagnostic was to determine if any commands we used had their defaults changed in QSYS.
Interestingly, I looked for a way to figure out if by chance someone changes the cmddft (for example from a ptf) and I found to use the exit linked to the QIBM_QCA_RTV_COMMAND object But I can’t find usable examples
ReplyDeletehttps://www.ibm.com/docs/en/i/7.3?topic=program-changing-cl-command-defaults
"You can track changes you make to CL command defaults for use when you install a new release. To track changes, register an exit program for exit point QIBM_QCA_RTV_COMMAND. The exit program is called when you run the CHGCMDDFT command. One of the parameters passed to the exit program is the command string that is being run. You can save the command string to a source file and then compile the source file into a CL program. Finally, you use this program to reproduce the changes you have made to command defaults during the previous release."