The backup process has grown increasingly important over the years. Ironically, when DASD was unreliable some 20 years ago, backup operations were standard operating procedure. Today, they still are on the iSeries platform but not so much so on the PC. When was the late time you backed up your PC data? I purchased a small 4 GB external hard drive that attaches to my PC via a USB 2.0 cable. I plug it in, launch my backup routine, and 5 or 10 minutes later, my entire library of data files is backed up. I unplug it, throw it in a secure location (front pants pocket), and I've got an offsite backup.
But what about AS/400 and iSeries backups? Wouldn't it be great if it were just as easy to connect simple storage devices to the iSeries as it is to the PC? Well, it can be.
If IBM would give us the ability to back up data to the IFS, we could then map the IFS folder to a network drive on the PC and back up that data just like any others. I could, for example, back up my small company's critical data to the IFS and then copy it to a DVD-RAM drive, a CD, or even a reusable external disk drive.
Well, I'm here to tell you they do give you that capability. But like all things on the iSeries, you have to work for it a little.
Saving to a PC Disk
There are two ways to save your iSeries data to a PC disk. Both techniques work with FTP, but only one works with Mapped Network Drive support:
- Save to a save file in any OS/400 library.
- Save to a save file and move the save file to the IFS.
The first option is fairly straightforward. You create a save file, save your data to it, and then FTP the data to your PC. The save file can be FTPed like a database file. Just use the .SAVF file extension when transferring the save files. For example:
GET /qsys.lib/qgpl.lib/myback.savf
These two FTP commands do the following: The BINARY command sets up the FTP transfer so that the data is not sent as clear ASCII text (which is important if you ever need to send the save file back up to the iSeries; it can't be altered). The GET command retrieves the save file. The save file is stored on your PC in the current local directory. I'm never really sure which directory that is while running Windows, so I've created a directory called BACKUP just for my save files. In this case, I would first run the following FTP command:
Today, placing things in a directory just off the root directory isn't very popular, so if you have some deeply nested Windows directory, you should specify that instead. Remember to prefix any long directory name with double quotes (") or you'll get FTP syntax errors. For example:
The quotes in front of the path name allow FTP to ignore the embedded blanks in the path name.
Many shops do not allow FTP or do not allow it from most OS/400 libraries. So this first option may not be viable for everyone. Many shops do, however, allow FTP from directories on the IFS. So the solution is to move the save file over to the IFS and then FTP it from there.
To do this, you need to do the following:
- Create the save file.
- Save the data to the save file.
- Use CPYTOSTMF to copy the save file to the IFS.
- FTP the save file from the IFS to your PC.
Obviously, an automated way to accomplish the first three steps would be a nice feature. Listed below is a CL command that will do the first three of these steps for you. I've called it Save Objects to the IFS (SAVOBJIFS). This command saves data to a save file and then copies the save file to the specified IFS location. Here is the command definition source code:
/* Command processing program is: SAVOBJIFS */
PARM KWD(SAVCMD) TYPE(*CMDSTR) LEN(2048) MIN(1) +
PROMPT('SAVxxx command to run')
PARM KWD(SAVFLR) TYPE(*PNAME) LEN(640) +
DFT('/BACKUP') EXPR(*YES) PROMPT('IFS +
folder location')
PARM KWD(STMF) TYPE(*CHAR) LEN(32) DFT(*SAVF) +
SPCVAL((*SAVF) (*SAVFLR)) EXPR(*YES) +
PROMPT('SAVF file name on IFS')
PARM KWD(STMFOPT) TYPE(*CHAR) LEN(10) RSTD(*YES) +
DFT(*REPLACE) SPCVAL((*NONE) (*REPLACE) +
(*ADD)) EXPR(*YES) PROMPT('Stream file +
option')
SAVOBJIFS Parameter Descriptions
The following describes each parameter of the SAVOBJIFS command.
SAVCMD is the save command you want to run to perform your save routine. Since TYPE(*CMDSTR) is specified for this parameter, you may prompt any OS/400 CL command, including the save commands, such as SAVOBJ or SAVLIB. This is similar to the CMD parameter of the SBMJOB command.
The specified command is run, and the data is saved. You are expected to specify the following parameters on the SAVOBJ or SAVLIB commands:
The DEV parameter indicates that the save should be performed to a save file. The save file does not need to exist; the SAVOBJIFS command will automatically create it for you.
- The SAVF parameter indicates the name of the save file into which the save is performed.
- The CLEAR parameter causes the save file to be cleared first before saving the new data. If you do not specify the CLEAR parameter, you'll get an inquiry message that asks you to enter a C or G. Typing a G clears the save file; a C causes the save operation to be cancelled.
SAVFLR is the name of the directory on your IFS where the save file will be copied. You may specify only the folder/directory name or the folder/directory name and the IFS file name into which the save file is copied. If you do not specify a file name, the file name on the STMF parameter is used as the file name.
STMF is the stream file name. "Stream file" is a confusing term IBM ported from other platforms. It basically means "file name." For this parameter, specify the name of the file as it will appear on the IFS in the folder/directory specified on the SAVFLR parameter.
Two special values may be specified for this parameter:
- *SAVF causes SAVOBJIFS to detect and extract the save file name specified on the SAVOBJ or SAVLIB command on the SAVCMD parameter. The save file name is used as the IFS file name, and the .SAVF file extension is added. So if the value SAVF(QGPL/MYBACKP) is specified, the file named MYBACKUP.SAVF is created.
- *SAVFLR indicates that you have already specified a full path and file name on the SAVFLR parameter. So the STMF parameter is not used.
STMFOPT is the stream file replace/add option. If *REPLACE is specified, the existing stream file is replaced. If *ADD is specified, the existing stream file is added to. If *NONE is specified, it is assumed that the stream file does not exist.
To make this command work, I had to choose between CL and RPG IV. Since CL doesn't have built-in search capabilities, I decided to go with pure RPG IV as the command processing program.
The RPG IV source below is the command processing program for the SAVOBJIFS command. This version requires the save file to already exist (just like the SAVOBJ and SAVLIB commands do). A future version will automatically create the save file for you.
H DFTACTGRP(*NO) ACTGRP(*NEW) BNDDIR('QC2LE')
**************************************************************
** SAVE OBJECTS to the IFS **
** (c) 2005 - Robert Cozzi, Jr. **
**************************************************************
** Parameters
D SaveCmd S 2048A
D ifsLoc S 640A
D stmfName S 32A
D stmfopt S 10A
** Command string work fields
D szCmd S 2048A Varying
D szStmf S 1024A Varying
D szIFSName S 1024A Varying
D szMbrOpt S 32A Varying
** Fields to hold the name of the save file
D savf S 21A
D SaveFile DS
D SAVFile 10A
D SAVFLib 10A
** Helper function to do simple lower
** to upper case conversion
D ToUpper PR 4096A Varying
D inString 4096A Varying VALUE
** Helper function to determine the library
** name when *LIBL or *CURLIB is specified
** for the save file name.
D GetObjLib PR 10A
D Object 20A Const
D objType 10A Const
** Helper function to write ad-hoc messages
** out to the joblog
D JobLog PR
D szMsg 1024A Const Varying
** Unix API to write to the joblog
D Qp0zLprintf PR 10I 0 ExtProc('Qp0zLprintf')
D szOutputString...
D * Value OPTIONS(*STRING)
D * Value OPTIONS(*STRING:*NOPASS)
D * Value OPTIONS(*STRING:*NOPASS)
D * Value OPTIONS(*STRING:*NOPASS)
*********************************************************
** R E T R I E V E O B J E C T D E S C R I P I T I O N
*********************************************************
/INCLUDE QSYSINC/QRPGLESRC,QUSEC
/INCLUDE QSYSINC/QRPGLESRC,QUSROBJD
D QRtvObjD PR ExtPgm('QUSROBJD')
D rtnData 65535A OPTIONS(*VARSIZE)
D nRtnDataLen 10I 0 Const
D Format 8A Const
D QualObj 20A Const
D ObjType 10A Const
D apiError Like(QUSEC)
** C runtime function to run OS/400 CL commands.
D system PR 10I 0 ExtProc( 'system' )
D szCmd * Value Options( *String )
** Named constants used to find the save file name
D SAVDEV C Const('DEV(*SAVF)')
D SAVFPARM C Const('SAVF(')
** Work fields used for location
** and offset of save file name.
D nPos S 10I 0
D nStart S 10I 0
D nEnd S 10I 0
D nLen S 10I 0
C *ENTRY PLIST
C Parm SaveCmd
C Parm ifsLoc
C Parm stmfName
C Parm stmfOpt
C eval *INLR = *ON
** Convert the SAVxxx command to upper case to
** make searching it easier.
C eval szCmd = ToUpper(saveCmd)
C eval nPos = %scan(SAVDEV : szCmd )
** Sorry, can't help you if you don't specify DEV(*SAVF)
C if nPos = 0
C Callp JobLog('* Must specify DEV(*SAVF) for +
C SAVOBJIFS command.')
C return
C endif
C eval nPos = %scan(SAVFPARM : szCmd )
C if nPos = 0
C Callp JobLog('* Must specify SAVF name for +
C SAVOBJIFS command.')
C return
C endif
** We're okay!
** Find the end of the save file parameter
** so that we can extract the save file name
C eval nEnd = %scan(')':szCmd:nPos+%len(SAVFPARM))
C if nPos > 0 and nEnd > 0
C eval nStart = nPos + %Len(SAVFPARM)
C eval nLen = nEnd - nStart
C if nLen > 0
C eval SAVF = %subst(szCmd:nStart:nLen)
C eval nPos = %scan('/':savf)
C if nPos = 0 or %subst(savf:1:1) = '*'
C eval savflib = GetObjLib(savfile : '*FILE')
C else
C eval savflib = %subst(savf:1:nPos-1)
C eval savfile = %subst(savf:nPos+1)
C endif
C endif
C endif
C if SAVF = *BLANKS
C callp Joblog('* Save file name missing. It is +
C required for SAVOBJIFS command.')
C return
C endif
** TODO: Insert code here to create save file
** if it does not exist.
** Run the user-specified SAVxxx command
C callp(e) system(savecmd)
C if %Error
C callp Joblog('* Error on save command. +
C See joblog for details.')
C return
C endif
** Get ready for transfer to the IFS
C if stmfName = '*SAVF'
C eval szIFSName = %TrimR(ifsloc) + '/' +
C %TrimR(savfile) + '.savf'
C endif
C if stmfName = '*STMF' or
C stmfName = '*IFSFLR' or
C stmfName = '*STMFLR' or
C stmfName = '*SAVFLR'
C eval szIFSName = %TrimR(ifsloc)
C endif
C if %subst(stmfName:1:1) <> '*'
C eval szIFSName = %TrimR(ifsloc) + '/' +
C %TrimR(stmfName)
C endif
C if stmfopt <> *BLANKS
C eval szMbrOpt = 'STMFOPT(' + %trimr(stmfopt) + ')'
C endif
C eval szStmf = '/qsys.lib' +
C '/' + %Trim(savflib) + '.lib' +
C '/' + %Trim(savfile) + '.file'
** The CPYTOSTMF CL command works for our needs.
C eval szCmd = 'CPYTOSTMF FROMMBR(''' +
C %TrimR(szStmf) + ''') ' +
C 'TOSTMF(''' + %TrimR(szIfsName) +
C ''') CVTDTA(*NONE) ' + szMbrOpt
C
** Copy the save file to the IFS.
C callp(e) system(szCmd)
C return
P ToUpper B
D ToUpper PI 4096A Varying
D inString 4096A Varying VALUE
D lower C 'abcdefghijklmnopqrstuvwxyz'
D UPPER C 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
C if %Len(inString) > 0
C lower:UPPER XLate inString inString
C endif
C return inString
P ToUpper E
P Joblog B
D JobLog PI
D szMsg 1024A Const Varying
C Callp Qp0zLprintf(szMsg + X'25')
C return
P Joblog E
P GetObjLib B
D GetObjLib PI 10A
D Object 20A Const
D objType 10A Const
** OBJECT input parameter must have the following format:
D ObjName DS
D Obj 10A
D Lib 10A
C callp(e) QrtvObjD(QUSD0100 : %size(QUSD0100) :
C 'OBJD0100' : object : objtype :
C QUSEC )
C return QUSOBJLN
P GetObjLib E
(Note: As always, the source for this week's programs is available on my Web site. Click on "Free RPG IV Downloads.")
To compile these two source members, just use the default PDM option 14 settings. The RPG IV header specifications will override the default settings, and the CMD source will use the command name as the command processing program name.
Once the programs are compiled and you've run the SAVOBJIFS command, you'll have a copy of your save file on the IFS that you can easily FTP to an external PC storage device.
If you use the Map Network Drive function, you could even drag and drop the save file onto a recordable CD, DVD, or micro drive, thereby keeping your important iSeries files in your own desk drawer.
Bob Cozzi is a programmer/consultant, writer/author, and software developer. His popular RPG xTools add-on subprocedure library for RPG IV is fast becoming a standard with RPG developers. His book The Modern RPG Language has been the most widely used RPG programming book for more than a decade. He, along with others, speaks at and produces the highly popular RPG World conference for RPG programmers.
LATEST COMMENTS
MC Press Online