FTP転送コマンドとしてSNDFILという適用業務を作成してみよう。
このコマンドを学習すればIBM iのすベてのデータをFTPでWINDOWSサーバーなどに転送できるようになる。
SNDFILの実行は
ファイルの FTP 転送 (SNDFIL) 選択項目を入力して,実行キーを押してください。 転送ファイル . . . . . . . . . SHOHIN 名前 ライブラリー . . . . . . . . QTRFIL 名前 , *LIBL, *CURLIB ホスト IP アドレス . . . . . . '*DFT' 相手先 IP アドレス . . . . . . '192.168.1.80' 相手先ファイル・パス . . . . . /BACKUP 遠隔ユーザー ID . . . . . . . . *NONE 遠隔パスワード . . . . . . . . *NONE 結果 . . . . . . . . . . . . . 文字値 終り F3= 終了 F4=プロンプト F5= 最新表示 F12= 取り消し F13= この画面の使用法 F24= キーの続き
[注意]
このコマンドは結果(RES)の値を戻すので対話式環境では実行できない。
結果のパラメータをはずせば対話式環境でも使用可能になる。
[コマンド: SNDFIL ]
ソースはこちらから
0001.00 CMD PROMPT(' ファイルの FTP 転送 ') ALLOW(*BPGM + 0002.00 *IPGM) 0003.00 PARM KWD(FILE) TYPE(FILE) + 0004.00 PROMPT(' 転送ファイル ') 0005.00 FILE: QUAL TYPE(*NAME) LEN(10) 0006.00 QUAL TYPE(*NAME) LEN(10) SPCVAL((*LIBL) + 0007.00 (*CURLIB)) PROMPT(' ライブラリー ') 0008.00 PARM KWD(FRMADDRESS) TYPE(*CHAR) LEN(15) + 0009.00 DFT('*DFT') + 0010.00 PROMPT(' ホスト IP アドレス ') 0011.00 PARM KWD(TOADDRESS) TYPE(*CHAR) LEN(15) + 0012.00 DFT('192.168.1.8') + 0013.00 PROMPT(' 相手先 IP アドレス ') 0014.00 PARM KWD(TOPASS) TYPE(*CHAR) LEN(128) + 0015.00 CASE(*MIXED) PROMPT(' 相手先ファイル・パス ') 0016.00 PARM KWD(USER) TYPE(*CHAR) LEN(13) DFT(*NONE) + 0017.00 SPCVAL((*NONE)) CASE(*MIXED) + 0018.00 PROMPT(' 遠隔ユーザー ID') 0019.00 PARM KWD(PASSWORD) TYPE(*CHAR) LEN(13) DFT(*NONE) + 0020.00 SPCVAL((*NONE)) CASE(*MIXED) + 0021.00 PROMPT(' 遠隔パスワード ') 0022.00 PARM KWD(RES) TYPE(*CHAR) LEN(1) PROMPT(' 結果 ')
[コンパイル]
このコマンドはバッチ環境のみの実行に限られるので
CRTCMD CMD(MYLIB/SNDFIL) PGM(MYLIB/SNDFIL) SRCFILE(MYSRCLIB/QCMDSRC) ALLOW(*BPGM *IPGM) AUT(*ALL)
のようにALLOW(*BPGM *IPGM)を指定してコンパイルする必要がある。(Ver5.4以前)
しかしVer6.1以上では
0001.00 CMD PROMPT(' ファイルの FTP 転送 ') ALLOW(*BPGM + 0002.00 *IPGM)
とソースの中に記述しておくと
CRTCMD CMD(MYLIB/SNDFIL) PGM(MYLIB/SNDFIL) SRCFILE(MYSRCLIB/QCMDSRC) AUT(*ALL)
のように通常のコンパイルで済む。
再コンパイルのときには ALLOW の指定は忘れがちなのでソースに記述しておくことを
お奨めする。
[CLP: SNDFILCL ]
ソースはこちらから
0001.00 PGM PARM(&FILLIBLIB &FRMADDR &TOADDR &TOPASS + 0002.00 &USER &PASSWRD &RES) 0003.00 /*-------------------------------------------------------------------*/ 0004.00 /* SNDFILCL : ファイルの FTP 転送 */ 0005.00 /* */ 0006.00 /* 2020/12/09 作成 */ 0007.00 /*-------------------------------------------------------------------*/ 0008.00 DCL VAR(&RES) TYPE(*CHAR) LEN(1) 0009.00 DCL VAR(&FILLIBLIB) TYPE(*CHAR) LEN(20) 0010.00 DCL VAR(&FILE) TYPE(*CHAR) LEN(10) 0011.00 DCL VAR(&FILLIB) TYPE(*CHAR) LEN(10) 0012.00 DCL VAR(&FRMADDR) TYPE(*CHAR) LEN(15) 0013.00 DCL VAR(&TOADDR) TYPE(*CHAR) LEN(15) 0014.00 DCL VAR(&FROMPASS) TYPE(*CHAR) LEN(128) 0015.00 DCL VAR(&TODIR) TYPE(*CHAR) LEN(128) 0016.00 DCL VAR(&TOPASS) TYPE(*CHAR) LEN(128) 0017.00 DCL VAR(&USER) TYPE(*CHAR) LEN(13) 0018.00 DCL VAR(&PASSWRD) TYPE(*CHAR) LEN(13) 0019.00 DCL VAR(&MSG) TYPE(*CHAR) LEN(132) 0020.00 DCL VAR(&MSGID) TYPE(*CHAR) LEN(7) 0021.00 DCL VAR(&STSMSG) TYPE(*CHAR) LEN(132) 0022.00 DCL VAR(&MSGF) TYPE(*CHAR) LEN(10) 0023.00 DCL VAR(&MSGFLIB) TYPE(*CHAR) LEN(10) 0024.00 DCL VAR(&MSGDTA) TYPE(*CHAR) LEN(132) 0025.00 DCL VAR(&TYPE) TYPE(*CHAR) LEN(1) 0026.00 DCL VAR(&TOPGMQ) TYPE(*CHAR) LEN(10) 0027.00 DCL VAR(&MSGTYPE) TYPE(*CHAR) LEN(10) + 0028.00 VALUE('*ESCAPE ') 0029.00 DCL VAR(&APIERR) TYPE(*CHAR) LEN(116) + 0030.00 VALUE(X'000074') /* 2 進数 */ 0031.00 DCL VAR(&ERR) TYPE(*CHAR) LEN(1) 0032.00 DCL VAR(&NULL4) TYPE(*CHAR) LEN(4) + 0033.00 VALUE(X'00000000') 0034.00 MONMSG MSGID(CPF0000) EXEC(GOTO CMDLBL(ERROR)) 0035.00 0036.00 /*( 環境の取得 )*/ 0037.00 RTVJOBA TYPE(&TYPE) 0038.00 IF COND(&TYPE *EQ '0') THEN(DO) /* バッチ */ 0039.00 CHGVAR VAR(&TOPGMQ) VALUE('*SYSOPR ') 0040.00 ENDDO /* バッチ */ 0041.00 ELSE CMD(DO) /* 対話式 */ 0042.00 CHGVAR VAR(&TOPGMQ) VALUE('*TOPGMQ ') 0043.00 ENDDO /* 対話式 */ 0044.00 0045.00 /*( パラメータの取得 )*/ 0046.00 CHGVAR VAR(&RES) VALUE('E') 0047.00 CHGVAR VAR(&FILE) VALUE(%SST(&FILLIBLIB 01 10)) 0048.00 CHGVAR VAR(&FILLIB) VALUE(%SST(&FILLIBLIB 11 10)) 0049.00 0050.00 /*( パラメータの検査 )*/ 0051.00 IF COND(%SST(&PASSWRD 1 5) *EQ '*NONE') THEN(DO) 0052.00 CHGVAR VAR(&MSG) + 0053.00 VALUE(' パスワードが指定されていません。 ') 0054.00 GOTO SNDMSG 0055.00 ENDDO 0056.00 0057.00 /******************/ 0058.00 /* SEND: FTP 送信 */ 0059.00 /******************/ 0060.00 /**************************************************/ 0061.00 /* (2) QTEMP に保管記述ファイルを作成する */ 0062.00 /**************************************************/ 0063.00 CHKOBJ OBJ(QTEMP/INPUT) OBJTYPE(*FILE) 0064.00 MONMSG MSGID(CPF9800) EXEC(DO) 0065.00 CRTSRCPF FILE(QTEMP/INPUT) RCDLEN(92) IGCDTA(*YES) + 0066.00 CCSID(65535) AUT(*ALL) 0067.00 ENDDO 0068.00 /*( INPUT の作成 )*/ 0069.00 CHKOBJ OBJ(QTEMP/INPUT) OBJTYPE(*FILE) MBR(&FILE) 0070.00 MONMSG MSGID(CPF9800) EXEC(DO) 0071.00 ADDPFM FILE(QTEMP/INPUT) MBR(&FILE) 0072.00 ENDDO 0073.00 CLRPFM FILE(QTEMP/INPUT) MBR(&FILE) 0074.00 OVRDBF FILE(INPUT) TOFILE(QTEMP/INPUT) MBR(&FILE) + 0075.00 SECURE(*YES) OVRSCOPE(*JOB) 0076.00 CALL PGM(QUATTRO/ADDINPUT) PARM(&FILE &FRMADDR + 0077.00 &FROMPASS &TOADDR &TOPASS &USER &PASSWRD + 0078.00 '*IFS') 0079.00 DLTOVR FILE(INPUT) LVL(*JOB) 0091.00 /*******************************************/ 0092.00 /* (3) FTP で保管ファイルを転送する */ 0093.00 /*******************************************/ 0094.00 CHGVAR VAR(&STSMSG) VALUE(' ファイル ' *CAT &FILLIB + 0095.00 *TCAT '/' *CAT &FILE *TCAT + 0096.00 ' を FTP で転送中です。 ') 0097.00 SNDPGMMSG MSGID(CPF9897) MSGF(QCPFMSG) MSGDTA(&STSMSG) + 0098.00 TOPGMQ(*EXT) MSGTYPE(*STATUS) 0099.00 CHGVAR VAR(&TOPASS) VALUE(&TODIR *TCAT &FILE *TCAT + 0100.00 '.SAV') 0101.00 OVRDBF FILE(INPUT) TOFILE(QTEMP/INPUT) MBR(&FILE) + 0102.00 SECURE(*YES) OVRSCOPE(*JOB) 0103.00 OVRDBF FILE(OUTPUT) TOFILE(QTEMP/OUTPUT) MBR(&FILE) + 0104.00 SECURE(*YES) OVRSCOPE(*JOB) 0105.00 FTP RMTSYS(*INTNETADR) INTNETADR(&TOADDR) 0106.00 DLTOVR FILE(INPUT OUTPUT) LVL(*JOB) 0107.00 CHGVAR VAR(&RES) VALUE(' ') /* 成功を報告 */ 0108.00 RETURN 0109.00 0110.00 APIERR: 0111.00 CHGVAR VAR(&MSGID) VALUE(%SST(&APIERR 9 7)) 0112.00 CHGVAR VAR(&MSGDTA) VALUE(%SST(&APIERR 17 100)) 0113.00 CHGVAR VAR(&MSGF) VALUE('QCPFMSG ') 0114.00 CHGVAR VAR(&MSGFLIB) VALUE('QSYS ') 0115.00 GOTO SNDMSG 0116.00 0117.00 ERROR: RCVMSG MSGTYPE(*LAST) RMV(*NO) MSG(&MSG) + 0118.00 MSGDTA(&MSGDTA) MSGID(&MSGID) MSGF(&MSGF) + 0119.00 SNDMSGFLIB(&MSGFLIB) 0120.00 SNDMSG: IF COND(&MSGID *EQ ' ') THEN(DO) 0121.00 SNDPGMMSG MSGID(CPF9897) MSGF(QCPFMSG) MSGDTA(&MSG) + 0122.00 TOMSGQ(&TOPGMQ) MSGTYPE(&MSGTYPE) 0123.00 MONMSG MSGID(CPF2400) EXEC(RETURN) 0124.00 ENDDO 0125.00 ELSE CMD(DO) 0126.00 SNDPGMMSG MSGID(&MSGID) MSGF(&MSGFLIB/&MSGF) + 0127.00 MSGDTA(&MSGDTA) TOMSGQ(&TOPGMQ) + 0128.00 MSGTYPE(&MSGTYPE) 0129.00 MONMSG MSGID(CPF2400) EXEC(RETURN) 0130.00 ENDDO 0131.00 ENDPGM
[コンパイル]
CRTCLPGM PGM(MYLIB/SNDFILCL) SRCFILE(MYSRCLIB/QCLSRC) AUT(*ALL)
[解説]
ライブラリーQTEMPに92バイトのソース・ファイルINPUTを作成しておく。
0060.00 /**************************************************/ 0061.00 /* (2) QTEMP に保管記述ファイルを作成する */ 0062.00 /**************************************************/ 0063.00 CHKOBJ OBJ(QTEMP/INPUT) OBJTYPE(*FILE) 0064.00 MONMSG MSGID(CPF9800) EXEC(DO) 0065.00 CRTSRCPF FILE(QTEMP/INPUT) RCDLEN(92) IGCDTA(*YES) + 0066.00 CCSID(65535) AUT(*ALL) 0067.00 ENDDO
次にこのINPUTの中にプログムADDINPUTで内容を追加する
0068.00 /*( INPUT の作成 )*/ 0069.00 CHKOBJ OBJ(QTEMP/INPUT) OBJTYPE(*FILE) MBR(&FILE) 0070.00 MONMSG MSGID(CPF9800) EXEC(DO) 0071.00 ADDPFM FILE(QTEMP/INPUT) MBR(&FILE) 0072.00 ENDDO 0073.00 CLRPFM FILE(QTEMP/INPUT) MBR(&FILE) 0074.00 OVRDBF FILE(INPUT) TOFILE(QTEMP/INPUT) MBR(&FILE) + 0075.00 SECURE(*YES) OVRSCOPE(*JOB) 0076.00 CALL PGM(QUATTRO/ADDINPUT) PARM(&FILE &FRMADDR + 0077.00 &FROMPASS &TOADDR &TOPASS &USER &PASSWRD + 0078.00 '*IFS') 0079.00 DLTOVR FILE(INPUT) LVL(*JOB)
ライブラリーQTEMPに92バイトのソース・ファイルOUTPUTも作成しておく。
0080.00 /*( OUTPUT の作成 )*/ 0081.00 CHKOBJ OBJ(QTEMP/OUTPUT) OBJTYPE(*FILE) 0082.00 MONMSG MSGID(CPF9800) EXEC(DO) 0083.00 CRTSRCPF FILE(QTEMP/OUTPUT) RCDLEN(92) IGCDTA(*YES) + 0084.00 CCSID(65535) AUT(*ALL) 0085.00 ENDDO 0086.00 CHKOBJ OBJ(QTEMP/OUTPUT) OBJTYPE(*FILE) MBR(&FILE) 0087.00 MONMSG MSGID(CPF9800) EXEC(DO) 0088.00 ADDPFM FILE(QTEMP/OUTPUT) MBR(&FILE) 0089.00 ENDDO 0090.00 CLRPFM FILE(QTEMP/OUTPUT) MBR(&FILE)
INPUT, OUTPUTにオーバーライドで一時変更を宣言してIBMのFTPを実行する
0091.00 /*******************************************/ 0092.00 /* (3) FTP で保管ファイルを転送する */ 0093.00 /*******************************************/ 0094.00 CHGVAR VAR(&STSMSG) VALUE(' ファイル ' *CAT &FILLIB + 0095.00 *TCAT '/' *CAT &FILE *TCAT + 0096.00 ' を FTP で転送中です。 ') 0097.00 SNDPGMMSG MSGID(CPF9897) MSGF(QCPFMSG) MSGDTA(&STSMSG) + 0098.00 TOPGMQ(*EXT) MSGTYPE(*STATUS) 0099.00 CHGVAR VAR(&TOPASS) VALUE(&TODIR *TCAT &FILE *TCAT + 0100.00 '.SAV') 0101.00 OVRDBF FILE(INPUT) TOFILE(QTEMP/INPUT) MBR(&FILE) + 0102.00 SECURE(*YES) OVRSCOPE(*JOB) 0103.00 OVRDBF FILE(OUTPUT) TOFILE(QTEMP/OUTPUT) MBR(&FILE) + 0104.00 SECURE(*YES) OVRSCOPE(*JOB) 0105.00 FTP RMTSYS(*INTNETADR) INTNETADR(&TOADDR) 0106.00 DLTOVR FILE(INPUT OUTPUT) LVL(*JOB)
[RPG: ADDINPUT ]
ソースはこちらから
0001.00 H DFTNAME(ADDINPUT) DATEDIT(*YMD/) 0002.00 F********** FTP INPUT ファイルの作成 ********************************** 0003.00 FINPUT UF A F 92 DISK 0004.00 F********************************************************************** 0005.00 0006.00 * CRTRPGMOD OBJ(QTEMP/ADDINPUT) SRCFILE(R610SRC/QRPGLESRC) 0007.00 * DBGVIEW(*SOURCE) AUT(*ALL) 0008.00 * CRTPGM PGM(QUATTRO/ADDINPUT) MODULE(QTEMP/ADDINPUT) ACTGRP(*NEW) 0009.00 * AUT(*ALL) 0010.00 0011.00 *-------------------------------------------------------------------* 0012.00 * 2020/12/04 : 作成 0013.00 *-------------------------------------------------------------------* 0014.00 *( 作業変数 ) 0015.00 D DTR S 80 DIM(4) CTDATA PERRCD(1) 0016.00 D AR S 1A DIM(256) 0017.00 D N S 4S 0 0018.00 D M S 4S 0 0019.00 D LEN S 4S 0 0020.00 D TRUE S 1A DIM(256) 0021.00 D TRUE# S 4B 0 INZ(0) 0022.00 D FALSE# S 4B 0 INZ(-1) 0023.00 D QUOT C CONST(X'7D') 0024.00 D OE C CONST(X'0E') 0025.00 D OF C CONST(X'0F') 0026.00 D NULL C CONST(X'00') 0027.00 D ELEM S 4S 0 0028.00 D HEAD S 80A 0029.00 D TRAIL S 80A 0030.00 0031.00 D*( プログラム状況データ構造 ) 0032.00 D INFDS_THIS SDS 0033.00 D PROC_NAM *PROC 0034.00 D ROUTINE *ROUTINE 0035.00 D 512A 0036.00 D PGMINFO 1 512 0037.00 D LINE_NUM 21 28 0038.00 D CPFID 40 46 0039.00 D CPFDTA 91 170 0040.00 D ERRMSGID 46 51 0041.00 D CURUSR 358 367 0042.00 0043.00 D*( WORK 日付 YYMMDD データ 構造 ) 0044.00 D DATEDS DS 0045.00 D CENTURY 1 2 0 INZ(20) 0046.00 D YYMMDD 3 8 0 0047.00 D YY 3 4 0048.00 D MM 5 6 0049.00 D DD 7 8 0050.00 D CYY 1 4 0051.00 0052.00 IINPUT BB 01 0053.00 I 13 92 SRCDTA 0054.00 0055.00 C*-------------------------------------------------------------------------+ 0056.00 C *ENTRY PLIST | 0057.00 C PARM LIB 10 | 0058.00 C PARM FROMIP 15 | 0059.00 C PARM FROMPASS 128 | 0060.00 C PARM TOIP 15 | 0061.00 C PARM TOPASS 128 | 0062.00 C PARM USER 13 | 0063.00 C PARM PASWRD 13 | 0064.00 C PARM OPT 4 | 0065.00 C*-------------------------------------------------------------------------+ 0066.00 C EVAL SRCDTA = %TRIMR(USER) + ' ' + 0067.00 C %TRIMR(PASWRD) 0068.00 C*----------------------------------------------------------------- 0069.00 C EXCEPT @SRCDTA 0070.00 C*----------------------------------------------------------------- 0071.00 C ADD 1 SRCNO 0072.00 C EVAL ELEM = %ELEM(DTR) 0073.00 C 1 DO ELEM N DO-LOOP-N 0074.00 C MOVEL DTR(N) SRCDTA 0075.00 *( LIB ) 0076.00 C N IFEQ 2 N=2 0077.00 C IF OPT = '*LIB' *LIB 0078.00 C EXSR REPLACE 0079.00 C ELSE *LIB 0080.00 C ITER 0081.00 C ENDIF *LIB 0082.00 C ENDIF N=2 0083.00 *( IFS ) 0084.00 C N IFEQ 3 N=2 0085.00 C IF OPT = '*IFS' *IFS 0086.00 C EXSR REPLACE 0087.00 C ELSE *IFS 0088.00 C ITER 0089.00 C ENDIF *IFS 0090.00 C ENDIF N=2 0091.00 C*----------------------------------------------------------------- 0092.00 C EXCEPT @SRCDTA 0093.00 C*----------------------------------------------------------------- 0094.00 C ADD 1 SRCNO 0095.00 C ENDDO DO-LOOP-N 0096.00 C SETON LR 0097.00 C RETURN 0098.00 C****************************************************** 0099.00 C *INZSR BEGSR 0100.00 C****************************************************** 0101.00 C* 初期 CYCLE のみの実行 0102.00 C Z-ADD 1 SRCNO 6 2 0103.00 C ENDSR 0104.00 C****************************************************** 0105.00 C REPLACE BEGSR 0106.00 C****************************************************** 0107.00 C AGAIN TAG 0108.00 C '%s' SCAN SRCDTA:1 M 50 0109.00 C *IN50 IFEQ *ON FOUND 0110.00 C SUB 1 M 0111.00 C EVAL HEAD = %SUBST(SRCDTA:1:M) 0112.00 C ADD 3 M 0113.00 C 80 SUB M LEN 0114.00 C EVAL TRAIL = %SUBST(SRCDTA:M:LEN) 0115.00 C EVAL SRCDTA = %TRIMR(HEAD) + 0116.00 C %TRIMR(LIB) + TRAIL 0117.00 C GOTO AGAIN 0118.00 C ENDIF FOUND 0119.00 C ENDSR 0120.00 OINPUT EADD @SRCDTA 0121.00 O SRCDTA 92 0122.00 O SRCNO 6 0123.00 0124.00 ** DTR 0125.00 BINARY 0126.00 PUT QTEMP/%s /BACKUP/V3R7/LIB/%s.SAV 0127.00 PUT IFSLIB/%s /BACKUP/V3R7/IFS/%s.SAV 0128.00 QUIT
[コンパイル]
CRTBNDRPG PGM(MYLIB/ADDINPUT) SRCFILE(MYSRCLIB/QRPGLESRC) DFTACTGRP(*NO)
ACTGRP(*NEW) DBGVIEW(*SOURCE) AUT(*ALL)
[解説]
わずか 128ステップのRPGプログラムであるが最新の洗練されたテクニックがいくつか使用されているので
ぜひ参考にして欲しい。
%TRIMR とは右端のブランクを除去するトリム関数である。
REPLACEというサプルーチンでは
PUT QTEMP/%s /BACKUP/V3R7/LIB/%s.SAV
という文字列の %s の部分を別の文字列に置換えている。
これは C言語で一般的に使用されるテクニックをRPGに取り入れたもので
文字列の置き換えに非常にわかりやすくなる方法である。
お気づきかも知れないが弊社ではこのSNDFILはV3R7M0のIBM i (AS/400)で使用しているものである。
このプログラムによって弊社のV3R7M0のIBM i(AS/400)では毎晩深夜にジョブ・スケジュールとして
FTPで別のWindowsサーバーにBACKUPを実行している。
RPGのフリー・フォーマットも利用したいところであるがさすがに
V3R7M0ではフリー・フォーマットは存在していないので使うことができなかった。
このV3R7M0のIBM i(AS/400)は最近、UPS(無停電電源装置)を追加してさらに
HDD(ハード・デスク)を追加してミラーリングを施したばかりである。
(この詳細はFacebookを参照)
25年前に購入したIBM i(AS/400)を何故そこまで大事にするかというと
ごく稀にこのIBM i(AS/400)にしか存在していないソースが必要になる場合があるからである。
弊社の他のIBM iも深夜にテープ装置とWindowsサーバーに自動バックアップしているが
このIBM i(AS/400)だけは自動バックアップされていなかったがこれで
すべてのIBM iのバックアップが行われるようになったのである。
V3R7M0 では CPYTOIMPF で SAVF をIFSに保存することができなかった。
そのため弊社のSNDFTPコマンドが使えなかったのでIBM のFTPコマンドを使って
ここに紹介したSNDFILコマンドを開発したような次第である。
しかし25年前のV3R7M0がFTPコマンドを備えていたのには驚いた。
IBM i は誕生のときからスゴイ機能を備えていたのだ。