Admin Alert: Backing Up i5/OS Partitions to Disk
December 7, 2005 Joe Hertvik
Sometimes it’s neither practical nor possible to save OS/400 data to media on a regular basis. I experienced this recently as I was developing a new partition and all my regular tape drives were allocated to nightly backups. With development happening during the day and no media to back up the system to at night, I had to find another backup solution. The answer I came up with was to back up our data to disk for later transfer to tape or another system.
Backing up data to disk storage before transferring it to tape isn’t necessarily the most elegant solution, but it will perform in a pinch or as a short term solution until a permanent backup routine can be implemented. In my case, I can back up my development partition by using the following three-step process. This process will insure that I can recover valuable data in case of failure.
I use the following three steps to back up a development partition to disk and then to tape:
1. Transfer a tape drive from a production partition to the new development partition on a temporary basis and perform a full system backup using option 21 (Entire system) from the Save menu (GO SAVE). Since my new development partition was not live yet, I could have even performed this step during the day as long as my developers and test users were not working on the new partition. An option 21 backup will provide a baseline picture of my system that I can use to restore the entire operating system and all of its files in the event of a system crash.
2. I then set up a regular nightly backup of all my security data, configuration data, user data, DLO objects, and IFS objects to my development partition hard drive. Each backed up object is saved to a save file in a library called BACKUPLIB. I run this backup at night to take a system snapshot at a time when most of the developers are not changing the system. While the full system backup in point one would allow me to restore the entire system to its baseline state, the nightly backup allows me to do two other things in the event of a crash or data corruption. First, it could complete a full system restore by bringing all the security, configuration, and data objects up to date after restoring the system to its baseline state. Second, it would also allow me to restore individual objects in the event of data or system corruption. The CL program that I developed to back up security, configuration, and user file data to disk is shown and explained below. Also note that I am not backing up the IBM-supplied libraries in this routine (except for QGPL and the IBM user libraries) because those libraries would be restored from the baseline full system backup tape.
3. After performing my nightly backup to the BACKUPLIB library on the development partition, I would perform a second operation that saves my disk-based backup information to media or to another partition. If I’m going to media, I can move a tape drive from another partition during the day (when it’s not being used) and back up my BACKUPLIB library to tape without disturbing my developers or test users. If I do not want to or I cannot back up to tape, I can FTP or transfer the BACKUPLIB library to another i5/OS or OS/400 partition for safekeeping, and the library can be backed up a second time with that partition’s nightly backup. If you don’t want to use FTP, iSeries Operations Navigator has a nice feature for sending a library from one partition to another.
So that’s my basic plan for backing up a development partition when media is not available to it at night. Here’s the CL program I developed for implementing step 2 (backing up the user data to disk).
PGM DCLF FILE(QADSPOBJ) CRTLIB LIB(BACKUPLIB) TYPE(*PROD) MONMSG MSGID(CPF0000) EXEC(CLRLIB LIB(BACKUPLIB)) CRTSAVF FILE(BACKUPLIB/SAVSECDTA) TEXT('savf for + security data') SAVSECDTA DEV(*SAVF) SAVF(BACKUPLIB/SAVSECDTA) MONMSG MSGID(CPF0000 CPA4088) CRTSAVF FILE(BACKUPLIB/SAVCFG) TEXT('savf for + configuration data') SAVCFG DEV(*SAVF) SAVF(BACKUPLIB/SAVCFG) MONMSG MSGID(CPF0000 CPA4088) DSPOBJD OBJ(*ALL) OBJTYPE(*LIB) OUTPUT(*OUTFILE) + OUTFILE(BACKUPLIB/ZZZZZZLIBS) /*LOOP THRU LIST FOR SAVING ALL LIBS, EXCEPT BACKUPLIB AND IBM LIBS */ OVRDBF FILE(QADSPOBJ) TOFILE(BACKUPLIB/ZZZZZZLIBS) LOOP1: RCVF MONMSG MSGID(CPF0864) EXEC(GOTO CMDLBL(ENDLOOP1)) /* CHECKS FOR SYSTEM LIBRARIES. */ IF COND(%SST(&ODOBNM 1 1) = 'Q') THEN(DO) /* LIBRARIES THAT START WITH Q ARE SYSTEM LIBRARIES + THAT WILL NOT BE SAVED. THE EXECPTIONS ARE THE + QGPL AND IBM'S USER LIBS WHICH WILL BE SAVED */ IF COND(&ODOBNM = 'QGPL') THEN(GOTO CMDLBL(SAVE)) IF COND(%SST(&ODOBNM 1 5) = 'QUSER') THEN(GOTO + CMDLBL(SAVE)) IF COND(%SST(&ODOBNM 1 4) = 'QUSR') THEN(GOTO + CMDLBL(SAVE)) GOTO CMDLBL(LOOP1) ENDDO /* CHECK FOR WORK LIBRARIES. */ IF COND(&ODOBNM = 'BACKUPLIB' *OR &ODOBNM = + 'QTEMP') THEN(GOTO CMDLBL(LOOP1)) SAVE: CRTSAVF FILE(BACKUPLIB/&ODOBNM) MAXRCDS(*NOMAX) SAVLIB LIB(&ODOBNM) DEV(*SAVF) SAVF(BACKUPLIB/&ODOBNM)+ SAVACT(*SYSDFN) + SAVACTMSGQ(QUSRSYS/ISJOEH) DTACPR(*YES) + OUTPUT(*PRINT) MONMSG MSGID(CPF0000 CPA4088) GOTO CMDLBL(LOOP1) ENDLOOP1: CRTSAVF FILE(BACKUPLIB/SAVDLO) TEXT('savf for dlo + objects') SAVDLO DLO(*ALL) DEV(*SAVF) SAVF(BACKUPLIB/SAVDLO) + SAVACT(*YES) MONMSG MSGID(CPF0000 CPA4088) CRTSAVF FILE(BACKUPLIB/SAV) TEXT('Savf for AS/400 + IFS objects') SAV DEV('/QSYS.LIB/BACKUPLIB.LIB/SAV.FILE') + OBJ(('/*') ('/QSYS.LIB' *OMIT) ('/QDLS' + *OMIT)) SAVACT(*YES) OUTPUT(*PRINT) + ENDOPT(*LEAVE) MONMSG MSGID(CPF0000 CPA4088) ENDPGM
And here’s how this program works.
First, the program uses the Declare File command (DCLF) to declare the QADSPOBJ file as an input file. This file will be used to compile a list of all the libraries that reside on the system.
The program attempts to create the BACKUPLIB library through the Create Library command (CRTLIB). If the library already exists, as determined by the Monitor Message command (MONMSG), the program clears the library for the upcoming saves.
The program creates save files for system security values, including user profiles, and the system’s configuration data, which contains all the device descriptions. It then runs the Save Security Data (SAVSECDTA) and Save Configuration commands (SAVCFG) to save this data to DASD.
Next, the program uses the Display Object Description command (DSPOBJD) to obtain a list of all the library objects (*LIB) on the system, and it outputs that list to a brand new output file called ZZZZZZLIBS in the BACKUPLIB library, with one record being written for each library on the system. The ZZZZZZLIBS library is formatted according to the file description for the QADSPOBJ file that I defined as my file input in the DCLF command. I named this file ZZZZZZLIBS so that I could easily find it in BACKUPLIB because it will always be listed as the last object in the library. After creating the new file, I used the Override Database File command (OVRDBF) to substitute my new ZZZZZZLIBS file for any command references in my CL program to the QADSPOBJ file.
The user library save is contained in the program loop that I created starting with the Receive File command (RCVF) at the loop1: tag and ending with the endloop1: tag later in the program. Remember that there is one record in the ZZZZZZLIBS for each library that resides on the system. A series of IF commands (IF) checks to see if the current library name in the record starts with a ‘Q”. If so, it only sends that library on to backup if the library name is ‘QGPL’ (the general purpose library) or any of the IBM user libraries that start with the literals ‘QUSER’ or ‘QUSR’. If the name starts with ‘Q’ and it meets those criteria, the library is backed up. If not, the program skips backing up that library and loops back to get the next record.
The next piece of code determines if the library name to be backed up is ‘QTEMP’ or ‘BACKUPLIB’. If the record contains either of those library names, it loops back and gets the next library record, because we don’t want to back up those libraries.
For the library back up, the program creates one save file in my BACKUPLIB library for each library to be backed up. So if I’m backing up the JOE library, it would back up that library to a save file called BACKUPLIB/JOE. While you can back up several libraries to a single save file, backing them up one at a time to their own individual save files gives you more flexibility to locate and restore an entire library or a single object residing in that library. After backing up the library, the program loops back up to get the next library record.
After reading every record in the ZZZZZZLIBS file, the program goes to the endloop1: tag and proceeds to create a save file for backing up document object library (DLO) objects. The program saves the system’s DLOs by using the Save Document Library Object command (SAVDLO). It then does the same thing for all the system Integrated File System (IFS) data by creating an IFS save file and then using the Save command (SAV) to back up that data.
Once all the save commands are executed, the program ends with the End Program command (ENDPGM) and all the relevant system data for a partition restore has been saved to my hard drive. At that point, I’m free to move the data off the machine as described in point three above.
I should make one last point about the various SAVxxx commands used in this program. All the commands that save data back up that data in save while active mode. So all of the benefits of save while active processing can be taken advantage of as you write the program out to disk. This means that you could also run the disk backup during the day but backups are traditionally run at night in order to take advantage of low CPU utilization and to avoid slowing down system users.