JWSPLF 工具可用於 OS/400 V5R1 以後,含原始檔。
TechTip: Upgrade Your JWSPLF
by Giuseppe Costagliola
https://www.mcpressonline.com/programming/rpg/techtip-upgrade-your-jwsplf
Published June 2003
下載 SAVF 及原始檔
安裝程序:
The zip contains a savf and all the sources in clear text (for people that
do not want or can't restore savf).
The savf is an entire library (JWSPLF) with all the programs compiled and
the source file as well. You can create
a savf JWSPLF in your as/400,
ftp and restore the library. If you restored the library, you can use the
command immediately However if you want to recreate the tool by your own just
create a library (say JWSPLF or any other else) and run the REXX JWMAKE
(directly from PDM - opt. 16).
If you want to build the pkg in a library other than JWSPLF just change
the variable LIB in REXX procedure.
A blog about IBM i (AS/400), MQ and other things developers or Admins need to know.
星期一, 11月 06, 2023
2003-06-12 JWSPLF 功能比 WRKSPLF 強,非常好用(Command JWSPLF)
2003-01-06 報表安全系列五:如何限制指令 CHGSPLFA 的使用, 防止使用者更改其他人報表的屬性?
報表安全系列五:如何限制指令 CHGSPLFA 的使用, 防止使用者更改其他人報表的屬性?
有鑑於 報表的安全性管理,iSeries(AS/400) 作業系統並未提供完善的保護,我將建議使用 VCP 命令
語法檢核程式來做安全空管,
報表安全系列一 :如何限制指令 WRKSPLF 的使用, 防止使用者察看全系統的報表 ?
報表安全系列二 :如何限制指令 DSPSPLF 的使用, 防止使用者於 WRKSPLF 畫面中瀏覽全系統的報表 ?
報表安全系列三 :如何限制指令 DLTSPLF 的使用, 防止使用者刪除其他人的報表 ?
報表安全系列四 :如何限制指令 CPYSPLF 的使用, 防止使用者複製其他人的報表 ?
報表安全系列五 :如何限制指令 CHGSPLFA 的使用, 防止使用者更改其他人報表的屬性?
有 *SPLCTL 權限的人可以更改系統上任何報表的屬性,如印表機,Outq 輸出佇列..等屬性,
要如何防止非授權使用者更改機密敏感的報表資料屬性,為了要防止這種情形發生,只能從命
令檢核程式著手,此範例與其他相關報表命令
(WRKSPLF, DSPSPLF, DLTSPLF, CPYSPLF)的檢核程式一樣,限制除了 QSECOFR, QSYSOPR
之外,使用者僅能刪除自己的報表,同樣也分 OS V5R1(含)以前及OS V5R2(含)以後的版本。
CHGSPLFAVC 命令語法檢核程式 for V5R1
File : QCLSRC
Member: CHGSPLFAVC
Type : CLP
OS version: V5R1 以前
Usage : CRTCLPGM mylib/CHGSPLFAVC
CHGCMD CMD(CHGSPLFA) VLDCKR(mylib/CHGSPLFAVC)
若執行有問題或不使用命令語法檢核程式時,執行
CHGCMD CMD(CHGSPLFA) VLDCKR(*NONE)
/* Program : CHGSPLFVAVC */
/* System : iSeries 400 */
/* */
/* Validity Checking program for command CHGSPLFA */
/* */
/* Example : protecting an OUTQ from a USER */
/* */
/* CHGCMD CMD(CHGSPLFA) VLDCKR(MYLIB/CHGSPLFVAL) */
/* To reset (in case you made errors) : */
/* CHGCMD CMD(CHGSPLFA) VLDCKR(*NONE) */
CHGSPLFVAL: PGM PARM(&P1 &P2 &P3 &P4 &P5 &P6 &P7 &P8 &P9 +
&P10 &P11 &P12 &P13 &P14 &P15 &P16 &P17 +
&P18 &P19 &P20 &P21 &P22 &P23 &P24 &P25 +
&P26 &P27 &P28 &P29 &P30 &P31 &P32 &P33 +
&P34 &P35 &P36 &P37 &P38 &P39)
DCL VAR(&P1) TYPE(*CHAR) LEN(1)
DCL VAR(&P2) TYPE(*CHAR) LEN(10) /* FILE */
DCL VAR(&P3) TYPE(*CHAR) LEN(26) /* JOB */
DCL VAR(&P4) TYPE(*CHAR) LEN(1)
DCL VAR(&P5) TYPE(*CHAR) LEN(44) /* SELECT */
DCL VAR(&P6) TYPE(*CHAR) LEN(10) /* PRINTER */
DCL VAR(&P7) TYPE(*CHAR) LEN(1)
DCL VAR(&P8) TYPE(*CHAR) LEN(20) /* OUTQ */
DCL VAR(&P9) TYPE(*CHAR) LEN(10) /* OUTQ LIB */
DCL VAR(&P10) TYPE(*CHAR) LEN(1)
DCL VAR(&P11) TYPE(*CHAR) LEN(1)
DCL VAR(&P12) TYPE(*CHAR) LEN(1)
DCL VAR(&P13) TYPE(*CHAR) LEN(1)
DCL VAR(&P14) TYPE(*CHAR) LEN(1)
DCL VAR(&P15) TYPE(*CHAR) LEN(1)
DCL VAR(&P16) TYPE(*CHAR) LEN(1)
DCL VAR(&P17) TYPE(*CHAR) LEN(1)
DCL VAR(&P18) TYPE(*CHAR) LEN(1)
DCL VAR(&P19) TYPE(*CHAR) LEN(1)
DCL VAR(&P20) TYPE(*CHAR) LEN(1)
DCL VAR(&P21) TYPE(*CHAR) LEN(1)
DCL VAR(&P22) TYPE(*CHAR) LEN(1)
DCL VAR(&P23) TYPE(*CHAR) LEN(1)
DCL VAR(&P24) TYPE(*CHAR) LEN(1)
DCL VAR(&P25) TYPE(*CHAR) LEN(1)
DCL VAR(&P26) TYPE(*CHAR) LEN(1)
DCL VAR(&P27) TYPE(*CHAR) LEN(1)
DCL VAR(&P28) TYPE(*CHAR) LEN(1)
DCL VAR(&P29) TYPE(*CHAR) LEN(1)
DCL VAR(&P30) TYPE(*CHAR) LEN(1)
DCL VAR(&P31) TYPE(*CHAR) LEN(1)
DCL VAR(&P32) TYPE(*CHAR) LEN(1)
DCL VAR(&P33) TYPE(*CHAR) LEN(1)
DCL VAR(&P34) TYPE(*CHAR) LEN(1)
DCL VAR(&P35) TYPE(*CHAR) LEN(1)
DCL VAR(&P36) TYPE(*CHAR) LEN(1)
DCL VAR(&P37) TYPE(*CHAR) LEN(1)
DCL VAR(&P38) TYPE(*CHAR) LEN(1)
DCL VAR(&P39) TYPE(*CHAR) LEN(1)
DCL VAR(&OUTQ) TYPE(*CHAR) LEN(10)
DCL VAR(&SPLUSR) TYPE(*CHAR) LEN(10)
DCL VAR(&USER) TYPE(*CHAR) LEN(10)
DCL VAR(&JOBNAME) TYPE(*CHAR) LEN(10)
DCL VAR(&JOBNBR) TYPE(*CHAR) LEN(6)
RTVJOBA JOB(&JOBNAME) USER(&USER) NBR(&JOBNBR)
CHGVAR &OUTQ %SST(&P8 1 10)
IF (%SST(&P3 1 1) *EQ '*') DO
CHGVAR &SPLUSR &USER
CHGVAR %SST(&P3 1 10) &JOBNAME
CHGVAR %SST(&P3 11 10) &USER
CHGVAR %SST(&P3 21 6) &JOBNBR
ENDDO
ELSE +
CHGVAR &SPLUSR %SST(&P3 11 10)
/* Check here your criteria. */
/* (f.e. Userprofile ... */
/* If a user is authorized based on your criteria, then */
/* RETURN. */
/* If he is not authorized then goto NOT_OK. */
/* In that case an escape message is send. */
/* USER QSECOFR, QSYSOPR UNLIMIT ACCESS SPOOLED FILE */
IF ((&USER *EQ 'QSECOFR') *OR +
(&USER *EQ 'QSYSOPR')) +
THEN(GOTO OK)
/* LIMIT ONLY SPOOLED CREATION USER CAN BROWSE OWN'S SPOOLED FILE */
IF COND(&USER *NE &SPLUSR) +
THEN(GOTO NOT_OK)
/* LIMIT OUTQ FOR SPECIFIED USER */
IF COND(&USER *EQ 'JOE' *AND &P8 *EQ 'MYOUTQ') +
THEN(GOTO NOT_OK)
OK:
RETURN
NOT_OK: SNDPGMMSG MSGID(CPD0006) MSGF(QCPFMSG) +
MSGDTA('0000' *CAT 'You are not +
authorized to output queue MYOUTQ') +
MSGTYPE(*DIAG)
SNDPGMMSG MSGID( CPF0002 ) +
MSGF( QSYS/QCPFMSG ) +
MSGTYPE( *ESCAPE )
END: ENDPGM
CPYSPLF 命令語法檢核程式 for V5R2
因為 CHGSPLFA 命令於 OS V5R2 中的參數個數增加至 42 個,而 CLP 的 PARM 參數僅能
接收 40 個參數,所以我改用 RPGLE 來撰寫命令語法檢核程式。
File : QRPGLESRC
Member: CHGSPLFAVR
Type : RPGLE
OS version: V5R2 以後
Usage : CRTBNDRPG mylib/CHGSPLFAVR
CHGCMD CMD(CHGSPLFA) VLDCKR(mylib/CHGSPLFAVR)
若執行有問題或不使用命令語法檢核程式時,執行
CHGCMD CMD(CHGSPLFA) VLDCKR(*NONE)
****************************************************************************************
* CHGSPLFA VCP for iSeries V5R2
*
/* * Validity Checking program for command CHGSPLFA
/*
/* * Example : protecting an SPOOL From a USER
/* *
/* * CHGCMD CMD(CHGSPLFA) VLDCKR(MYLIB/CHGSPLFAVR)
/* * To reset (in case you made errors) :
/* * CHGCMD CMD(CHGSPLFA) VLDCKR(*NONE)
****************************************************************************************
****************************************************************************************
* D E F I N I T I O N S P E C I F I C A T I O N *
****************************************************************
*
* Program Status Data Structure
*
D PGMDS SDS
D Pgmq## *PROC
D ErrorSts *STATUS
D PrvStatus 16 20S 0
D SrcLinNum 21 28
D Routine *ROUTINE
D NumParms *PARMS
D ExcpType 40 42
D ExcpNum 43 46
*
D PgmLib 81 90
D ExcpData 91 170
D ExcpId 171 174
D LastFile 201 208
D FileErr 209 243
D JobName 244 253
D User 254 263
D JobNumA 264 269
D JobNum 264 269S 0
D JobDate 270 275S 0
D RunDate 276 281S 0
D RunTime 282 287S 0
D PgmCrtDt 288 293
D PgmCrtTm 294 299
D CmplrLvl 300 303
D SrcFile 304 313
D SrcLib 314 323
D SrcMbr 324 333
D ProcPgm 334 343
D ProcMod 344 353
D cmd_str S 1024 INZ
D cmd_len S 15P 5 INZ(1024)
D msg_str S 256
D vApiErrDs ds
D vbytpv 10i 0 inz(%size(vApiErrDs)) bytes provided
D vbytav 10i 0 inz(0) bytes returned
D vmsgid 7a error msgid
D vresvd 1a reserved
D vrpldta 50a replacement data
D qmhsndpm PR ExtPgm('QMHSNDPM') SEND MESSAGES
D 7 const ID
D 20 const FILE
D 73 const TEXT
D 10i 0 const LENGTH
D 10 const TYPE
D 10 const QUEUE
D 10i 0 const STACK ENTRY
D 4 const KEY
Db like(vApiErrDS)
* QCMDEXC - Prototyped Call
D qcmdexc PR EXTPGM('QCMDEXC')
D cmd_str 1024 OPTIONS(*VARSIZE) CONST
D cmd_len 15P 5 CONST
C *entry Plist
C Parm P1 1
C Parm P2 10 File
C Parm P3 26 Job
C Parm P4 4 Splnbr
C Parm P5 8 Sysname
C Parm P6 6
C Parm P7 44
C Parm P8 10 Device
C Parm P9 1
C Parm P10 20
C Parm P11 1
C Parm P12 1
C Parm P13 1
C Parm P14 1
C Parm P15 1
C Parm P16 1
C Parm P17 1 Outq
C Parm P18 1
C Parm P19 1
C Parm P21 1
C Parm P22 1
C Parm P23 1
C Parm P24 1
C Parm P25 1
C Parm P26 1
C Parm P27 1
C Parm P28 1
C Parm P29 1
C Parm P30 1
C Parm P31 1
C Parm P32 1
C Parm P33 1
C Parm P34 1
C Parm P35 1
C Parm P36 1
C Parm P37 1
C Parm P38 1
C Parm P39 1
C Parm P40 1
C Parm P41 1
C Parm P42 1
C
C If %Subst(P3:1:1) = '*'
C Eval %Subst(P3: 1:10)= JobName
C Eval %Subst(P3:11:10)= User
C Eval %Subst(P3:21: 6)= JobNumA
C EndIf
* Exclude highest authority user
C If User <> 'QSECOFR' and
C User <> 'QSYSOPR'
* Limit user can chgsplfa on their own spooled
C If %Subst(P3:11:10)<> User
C Eval msg_str =
C '0000 You are not authorized to ' +
C 'spooled file ' + P2
* Send diag message
C callp QMHSNDPM(
C 'CPD0006':'QCPFMSG *LIBL ':
C msg_str:
C 256:'*DIAG ':'*CTLBDY ': 1:' ':
C vApiErrDS)
C
* Send Excape message
C callp QMHSNDPM(
C 'CPF0002':'QCPFMSG *LIBL ':
C ' ' :
C 0 :'*ESCAPE':'*CTLBDY ': 1:' ':
C vApiErrDS)
C EndIf
C EndIf
C
C Eval *InLr = *On
2003-01-05 報表安全系列四:如何限制指令 CPYSPLF 的使用, 防止使用者複製其他人的報表 ?
如何限制指令 CPYSPLF 的使用, 防止使用者複製其他人的報表 ?
有鑑於 報表的安全性管理,iSeries(AS/400) 作業系統並未提供完善的保護,我將建議使用 VCP 命令
語法檢核程式來做安全空管,
報表安全系列一 :如何限制指令 WRKSPLF 的使用, 防止使用者察看全系統的報表 ?
報表安全系列二 :如何限制指令 DSPSPLF 的使用, 防止使用者於 WRKSPLF 畫面中瀏覽全系統的報表 ?
報表安全系列三 :如何限制指令 DLTSPLF 的使用, 防止使用者刪除其他人的報表 ?
報表安全系列四 :如何限制指令 CPYSPLF 的使用, 防止使用者複製其他人的報表 ?
有 *SPLCTL 權限的人可以複製系統上任何報表,要如何防止非授權使用者複製機密敏感
的報表資料,為了要防止這種情形發生,只能從命令檢核程式著手,此範例與其他相關報
表命令(WRKSPLF, DSPSPLF, DLTSPLF)的檢核程式一樣,限制除了 QSECOFR, QSYSOPR 之外,
使用者僅能刪除自己的報表,同樣也分 OS V5R1(含)以前及OS V5R2(含)以後的版本。
CPYSPLF 命令語法檢核程式 for V5R1
File : QCLSRC
Member: CPYSPLFVC
Type : CLP
OS version: V5R1 以前
Usage : CRTCLPGM mylib/CPYSPLFVC
CHGCMD CMD(CPYSPLF) VLDCKR(mylib/CPYSPLFVC)
若執行有問題或不使用命令語法檢核程式時,執行
CHGCMD CMD(DSPSPLF) VLDCKR(*NONE)
/* Program : CPYSPLFVC */
/* System : iSeries 400 FOR V5R1 */
/* */
/* Validity Checking program for command CPYSPLF */
/* */
/* Example : protecting an SPOOL From a USER */
/* */
/* CHGCMD CMD(CPYSPLF) VLDCKR(MYLIB/CPYSPLFVC) */
/* To reset (in case you made errors) : */
/* CHGCMD CMD(CPYSPLF) VLDCKR(*NONE) */
DSPSPLFVC: PGM PARM(&P1 &P2 &P3 &P4 &P5 +
&P6 &P7 &P8 &P9 &P10)
DCL VAR(&P1) TYPE(*CHAR) LEN(10) /* FILE */
DCL VAR(&P2) TYPE(*CHAR) LEN(20) /* TOFILE */
DCL VAR(&P3) TYPE(*CHAR) LEN(26) /* JOB */
DCL VAR(&P4) TYPE(*CHAR) LEN(4) /* SPLNBR */
DCL VAR(&P5) TYPE(*CHAR) LEN(10) /* MEMBER */
DCL VAR(&P6) TYPE(*CHAR) LEN(1) /* MBR OPTION */
DCL VAR(&P7) TYPE(*CHAR) LEN(1) /* CTLCHAR */
DCL VAR(&P8) TYPE(*CHAR) LEN(1)
DCL VAR(&P9) TYPE(*CHAR) LEN(1)
DCL VAR(&P10) TYPE(*CHAR) LEN(1)
DCL VAR(&SPLUSR) TYPE(*CHAR) LEN(10)
DCL VAR(&USER) TYPE(*CHAR) LEN(10)
DCL VAR(&JOBNAME) TYPE(*CHAR) LEN(10)
DCL VAR(&JOBNBR) TYPE(*CHAR) LEN(6)
RTVJOBA JOB(&JOBNAME) USER(&USER) NBR(&JOBNBR)
IF (%SST(&P3 1 1) *EQ '*') DO
CHGVAR &SPLUSR &USER
CHGVAR %SST(&P3 1 10) &JOBNAME
CHGVAR %SST(&P3 11 10) &USER
CHGVAR %SST(&P3 21 6) &JOBNBR
ENDDO
ELSE +
CHGVAR &SPLUSR %SST(&P3 11 10)
/* QSECOFR, QSYSOPR CAN BROWSE ALL SPOOLED FILE */
IF COND((&USER *EQ 'QSECOFR') *OR +
(&USER *EQ 'QSYSOPR')) +
THEN(GOTO CMDLBL(OK))
/* LIMIT ONLY SPOOLED CREATION USER CAN BROWSE OWN'S SPOOLED FILE */
IF COND(&USER *NE &SPLUSR) +
THEN(GOTO NOT_OK)
OK:
RETURN
NOT_OK: SNDPGMMSG MSGID(CPD0006) MSGF(QCPFMSG) MSGDTA('0000' +
*CAT 'You are not authorized to spooled +
file' *BCAT &P1) MSGTYPE(*DIAG)
SNDPGMMSG MSGID( CPF0002 ) +
MSGF( QSYS/QCPFMSG ) +
MSGTYPE( *ESCAPE )
ENDPGM
CPYSPLF 命令語法檢核程式 for V5R2
File : QCLSRC
Member: CPYSPLFVC
Type : CLP
OS version: V5R2 以後
Usage : CRTCLPGM mylib/CPYSPLFVC
CHGCMD CMD(CPYSPLF) VLDCKR(mylib/CPYSPLFVC)
若執行有問題或不使用命令語法檢核程式時,執行
CHGCMD CMD(DSPSPLF) VLDCKR(*NONE)
/* Program : CPYSPLFVC */
/* System : iSeries 400 FOR V5R2 */
/* */
/* Validity Checking program for command CPYSPLF */
/* */
/* Example : protecting an SPOOL From a USER */
/* */
/* CHGCMD CMD(CPYSPLF) VLDCKR(MYLIB/CPYSPLFVC) */
/* To reset (in case you made errors) : */
/* CHGCMD CMD(CPYSPLF) VLDCKR(*NONE) */
DSPSPLFVC: PGM PARM(&P1 &P2 &P3 &P4 &P5 &P6 +
&P7 &P8 &P9 &P10 &P11 &P12)
DCL VAR(&P1) TYPE(*CHAR) LEN(10) /* FILE */
DCL VAR(&P2) TYPE(*CHAR) LEN(20) /* TOFILE */
DCL VAR(&P3) TYPE(*CHAR) LEN(26) /* JOB */
DCL VAR(&P4) TYPE(*CHAR) LEN(4) /* SPLNBR */
DCL VAR(&P5) TYPE(*CHAR) LEN(8) /* SYSNAME*/
DCL VAR(&P6) TYPE(*CHAR) LEN(6) /* CRTDATE */
DCL VAR(&P7) TYPE(*CHAR) LEN(10) /* MEMBER */
DCL VAR(&P8) TYPE(*CHAR) LEN(1) /* MBR OPTION */
DCL VAR(&P9) TYPE(*CHAR) LEN(1) /* CTLCHAR */
DCL VAR(&P10) TYPE(*CHAR) LEN(1)
DCL VAR(&P11) TYPE(*CHAR) LEN(1)
DCL VAR(&P12) TYPE(*CHAR) LEN(1)
DCL VAR(&SPLUSR) TYPE(*CHAR) LEN(10)
DCL VAR(&USER) TYPE(*CHAR) LEN(10)
DCL VAR(&JOBNAME) TYPE(*CHAR) LEN(10)
DCL VAR(&JOBNBR) TYPE(*CHAR) LEN(6)
RTVJOBA JOB(&JOBNAME) USER(&USER) NBR(&JOBNBR)
IF (%SST(&P3 1 1) *EQ '*') DO
CHGVAR &SPLUSR &USER
CHGVAR %SST(&P3 1 10) &JOBNAME
CHGVAR %SST(&P3 11 10) &USER
CHGVAR %SST(&P3 21 6) &JOBNBR
ENDDO
ELSE +
CHGVAR &SPLUSR %SST(&P3 11 10)
/* QSECOFR, QSYSOPR CAN BROWSE ALL SPOOLED FILE */
IF COND((&USER *EQ 'QSECOFR') *OR +
(&USER *EQ 'QSYSOPR')) +
THEN(GOTO CMDLBL(OK))
/* LIMIT ONLY SPOOLED CREATION USER CAN BROWSE OWN'S SPOOLED FILE */
IF COND(&USER *NE &SPLUSR) +
THEN(GOTO NOT_OK)
OK:
RETURN
NOT_OK: SNDPGMMSG MSGID(CPD0006) MSGF(QCPFMSG) MSGDTA('0000' +
*CAT 'You are not authorized to spooled +
file' *BCAT &P1) MSGTYPE(*DIAG)
SNDPGMMSG MSGID( CPF0002 ) +
MSGF( QSYS/QCPFMSG ) +
MSGTYPE( *ESCAPE )
ENDPGM
2003-01-04 報表安全列三:如何限制指令 DLTSPLF 的使用, 防止使用者刪除其他人的報表 ?
報表安全列三:如何限制指令 DLTSPLF 的使用, 防止使用者刪除其他人的報表 ?
有鑑於 報表的安全性管理,iSeries(AS/400) 作業系統並未提供完善的保護,我將建議使用 VCP 命令語
法檢核程式來做安全空管,
報表安全系列一 :如何限制指令 WRKSPLF 的使用, 防止使用者察看全系統的報表 ?
報表安全系列二 :如何限制指令 DSPSPLF 的使用, 防止使用者於 WRKSPLF 畫面中瀏覽全系統的報表 ?
報表安全系列三 :如何限制指令 DLTSPLF 的使用, 防止使用者刪除其他人的報表 ?
你是否常會遇到使用者反應他的報表不見了,有可能被其他有 *SPLCTL 權限的人刪除,
為了要防止這種情形發生,只能從命令檢核程式著手,此範例與其他相關報表命令
(WRKSPLF, DSPSPLF)的檢核程式一樣,限制除了 QSECOFR, QSYSOPR 之外,使
用者僅能刪除自己的報表,同樣也分 OS V5R1(含)以前及OS V5R2(含)以後的版本。
DLTSPLF 命令語法檢核程式 for V5R1
File : QCLSRC
Member: DLTSPLFVC
Type : CLP
OS version: V5R1 以前
Usage : CRTCLPGM mylib/DLTSPLFVC
CHGCMD CMD(DLTSPLF) VLDCKR(mylib/DLTSPLFVC)
若執行有問題或不使用命令語法檢核程式時,執行
CHGCMD CMD(DSPSPLF) VLDCKR(*NONE)
/* Program : DLTSPLFVC */
/* System : iSeries 400 FOR V5R1 */
/* */
/* Validity Checking program for command DLTSPLF */
/* */
/* Example : protecting an SPOOL From a USER */
/* */
/* CHGCMD CMD(DLTSPLF) VLDCKR(MYLIB/DLTSPLFVC) */
/* To reset (in case you made errors) : */
/* CHGCMD CMD(DLTSPLF) VLDCKR(*NONE) */
DSPSPLFVC: PGM PARM(&P1 &P2 &P3 &P4 &P5)
DCL VAR(&P1) TYPE(*CHAR) LEN(10) /* FUNC */
DCL VAR(&P2) TYPE(*CHAR) LEN(10) /* FILE */
DCL VAR(&P3) TYPE(*CHAR) LEN(26) /* JOB */
DCL VAR(&P4) TYPE(*CHAR) LEN(4) /* SPLNBR */
DCL VAR(&P5) TYPE(*CHAR) LEN(40) /* SELECT */
DCL VAR(&SPLUSR) TYPE(*CHAR) LEN(10)
DCL VAR(&USER) TYPE(*CHAR) LEN(10)
DCL VAR(&JOBNAME) TYPE(*CHAR) LEN(10)
DCL VAR(&JOBNBR) TYPE(*CHAR) LEN(6)
RTVJOBA JOB(&JOBNAME) USER(&USER) NBR(&JOBNBR)
IF (%SST(&P3 1 1) *EQ '*') DO
CHGVAR &SPLUSR &USER
CHGVAR %SST(&P3 1 10) &JOBNAME
CHGVAR %SST(&P3 11 10) &USER
CHGVAR %SST(&P3 21 6) &JOBNBR
ENDDO
ELSE +
CHGVAR &SPLUSR %SST(&P3 11 10)
/* USER QSECOFR, QSYSOPR UNLIMIT ACCESS SPOOLED FILE */
IF ((&USER *EQ 'QSECOFR') *OR +
(&USER *EQ 'QSYSOPR')) +
THEN(GOTO OK)
/* LIMIT ONLY SPOOLED CREATION USER CAN BROWSE OWN'S SPOOLED FILE */
IF COND(&USER *NE &SPLUSR) +
THEN(GOTO NOT_OK)
OK:
RETURN
NOT_OK: SNDPGMMSG MSGID(CPD0006) MSGF(QCPFMSG) MSGDTA('0000' +
*CAT 'You are not authorized to spooled +
file' *BCAT &P2) MSGTYPE(*DIAG)
SNDPGMMSG MSGID( CPF0002 ) +
MSGF( QSYS/QCPFMSG ) +
MSGTYPE( *ESCAPE )
ENDPGM
DLTSPLF 命令語法檢核程式 for V5R2
File : QCLSRC
Member: DLTSPLFVC
Type : CLP
OS version: V5R2 以後
Usage : CRTCLPGM mylib/DLTSPLFVC
CHGCMD CMD(DLTSPLF) VLDCKR(mylib/DLTSPLFVC)
若執行有問題或不使用命令語法檢核程式時,執行
CHGCMD CMD(DSPSPLF) VLDCKR(*NONE)
/* Program : DLTSPLFVC */
/* System : iSeries 400 FOR V5R2 */
/* */
/* Validity Checking program for command DLTSPLF */
/* */
/* Example : protecting an SPOOL From a USER */
/* */
/* CHGCMD CMD(DLTSPLF) VLDCKR(MYLIB/DLTSPLFVC) */
/* To reset (in case you made errors) : */
/* CHGCMD CMD(DLTSPLF) VLDCKR(*NONE) */
DSPSPLFVC: PGM PARM(&P1 &P2 &P3 &P4 &P5 &P6 &P7)
DCL VAR(&P1) TYPE(*CHAR) LEN(1) /* FUNC */
DCL VAR(&P2) TYPE(*CHAR) LEN(10) /* FILE */
DCL VAR(&P3) TYPE(*CHAR) LEN(26) /* JOB */
DCL VAR(&P4) TYPE(*CHAR) LEN(4) /* SPLNBR */
DCL VAR(&P5) TYPE(*CHAR) LEN(8) /* SYSNAME */
DCL VAR(&P6) TYPE(*CHAR) LEN(6) /* CRTDATE */
DCL VAR(&P7) TYPE(*CHAR) LEN(40) /* SELECT */
DCL VAR(&SPLUSR) TYPE(*CHAR) LEN(10)
DCL VAR(&USER) TYPE(*CHAR) LEN(10)
DCL VAR(&JOBNAME) TYPE(*CHAR) LEN(10)
DCL VAR(&JOBNBR) TYPE(*CHAR) LEN(6)
RTVJOBA JOB(&JOBNAME) USER(&USER) NBR(&JOBNBR)
IF (%SST(&P3 1 1) *EQ '*') DO
CHGVAR &SPLUSR &USER
CHGVAR %SST(&P3 1 10) &JOBNAME
CHGVAR %SST(&P3 11 10) &USER
CHGVAR %SST(&P3 21 6) &JOBNBR
ENDDO
ELSE +
CHGVAR &SPLUSR %SST(&P3 11 10)
/* USER QSECOFR, QSYSOPR UNLIMIT ACCESS SPOOLED FILE */
IF ((&USER *EQ 'QSECOFR') *OR +
(&USER *EQ 'QSYSOPR')) +
THEN(GOTO OK)
/* LIMIT ONLY SPOOLED CREATION USER CAN BROWSE OWN'S SPOOLED FILE */
IF COND(&USER *NE &SPLUSR) +
THEN(GOTO NOT_OK)
OK:
RETURN
NOT_OK: SNDPGMMSG MSGID(CPD0006) MSGF(QCPFMSG) MSGDTA('0000' +
*CAT 'You are not authorized to spooled +
file' *BCAT &P2) MSGTYPE(*DIAG)
SNDPGMMSG MSGID( CPF0002 ) +
MSGF( QSYS/QCPFMSG ) +
MSGTYPE( *ESCAPE )
ENDPGM
星期四, 11月 02, 2023
2003-01-03 如何限制指令 DSPSPLF 的使用, 防止使用者於 WRKSPLF 畫面中刪除全系統的報表 ?
如何限制指令 DSPSPLF 的使用, 防止使用者於 WRKSPLF 畫面中刪除全系統的報表 ?
使用者若有 *SPLCTL 特殊權限,於 WRKSPLF 指令可以指定其他使用者或全部使用者報表,
畫面中可以使用 選項 5 瀏覽全系統的報表,那要如何限制選項 5 瀏覽報表指令 DSPSPLF
的使用, 以保護機密資訊,不被未授權的人存取 ?
若要做到報表的安全防護,最佳的方式只有透過命令語法檢核程式(VCP - Validity Checking Program),但這個命令語法檢核程式
有時需要隨 OS 版本升級而更改,因為某些命令會增加參數,如 DSPSPLF 命令,於
OS V5R2 時多了二個參數,所以需要更改才可以繼續使用,針對每個 Command 的所有參數
(含隱藏的常數),IBM 並未記錄於其手冊中,是需要透過系統擷取命令定義的 API 或利用工具 RTVCMD
http://www.iseriesnetwork.com/code/sharewarefiles/rtvcmd.zip
取得命令真正的定義(Command Source),
相關報表的命令有
WRKSPLF
CHGSPLFA
DLTSPLF
DSPSPLF
上述指令可以設定命令語法檢核程式加以檢核哪些使用者可以存取其他人的報表,
我已於前一期電子報中介紹 "如何限制指令 WRKSPLF 的使用, 防止使用者察看全系統的報表 ?"
的VCP 命令語法檢核程式,因 WRKSPLF 參數數目 V5R1與 V5R2 相同,所以該程式不必修改即可用於 V5R2 中。
本期我再介紹 DSPSPLF 的 VCP 命令語法檢核程式 for OS V5R1 及 V5R2 :
DSPSPLF VCP 命令語法檢核程式 for V5R1
File : QCLSRC
Member: DSPSPLFVC
Type : CLP
OS version: V5R1 以前
Usage : CRTCLPGM mylib/DSPSPLFVC
CHGCMD CMD(DSPSPLF) VLDCKR(mylib/DSPSPLFVC)
若執行有問題或不使用命令語法檢核程式時,執行
CHGCMD CMD(DSPSPLF) VLDCKR(*NONE)
/* Program : DSPSPLFVC */
/* System : iSeries 400 FOR V5R1 */
/* */
/* Validity Checking program for command DSPSPLF */
/* */
/* Example : protecting an SPOOL From a USER */
/* */
/* CHGCMD CMD(DSPSPLF) VLDCKR(MYLIB/DSPSPLFVC) */
/* To reset (in case you made errors) : */
/* CHGCMD CMD(DSPSPLF) VLDCKR(*NONE) */
DSPSPLFVC: PGM PARM(&P1 &P2 &P3 &P4)
DCL VAR(&P1) TYPE(*CHAR) LEN(10)
DCL VAR(&P2) TYPE(*CHAR) LEN(26)
DCL VAR(&P3) TYPE(*CHAR) LEN(4)
DCL VAR(&P4) TYPE(*CHAR) LEN(1)
DCL VAR(&SPLUSR) TYPE(*CHAR) LEN(10)
DCL VAR(&USER) TYPE(*CHAR) LEN(10)
DCL VAR(&JOBNAME) TYPE(*CHAR) LEN(10)
DCL VAR(&JOBNBR) TYPE(*CHAR) LEN(6)
RTVJOBA JOB(&JOBNAME) USER(&USER) NBR(&JOBNBR)
IF (%SST(&P2 1 1) *EQ '*') DO
CHGVAR &SPLUSR &USER
CHGVAR %SST(&P2 1 10) &JOBNAME
CHGVAR %SST(&P2 11 10) &USER
CHGVAR %SST(&P2 21 6) &JOBNBR
ENDDO
ELSE +
CHGVAR &SPLUSR %SST(&P2 11 10)
/* USER QSECOFR, QSYSOPR UNLIMIT ACCESS SPOOLED FILE */
IF ((&USER *EQ 'QSECOFR') *OR +
(&USER *EQ 'QSYSOPR')) +
THEN(GOTO OK)
/* LIMIT ONLY SPOOLED CREATION USER CAN BROWSE OWN'S SPOOLED FILE */
IF COND(&USER *NE &SPLUSR) +
THEN(GOTO NOT_OK)
OK:
RETURN
NOT_OK: SNDPGMMSG MSGID(CPD0006) MSGF(QCPFMSG) MSGDTA('0000' +
*CAT 'You are not authorized to spooled +
file' *BCAT &P1) MSGTYPE(*DIAG)
SNDPGMMSG MSGID( CPF0002 ) +
MSGF( QSYS/QCPFMSG ) +
MSGTYPE( *ESCAPE )
ENDPGM
DSPSPLF VCP 命令語法檢核程式 for V5R2
File : QCLSRC
Member: DSPSPLFVC
Type : CLP
OS version: V5R2 以後
Usage : CRTCLPGM mylib/DSPSPLFVC
CHGCMD CMD(DSPSPLF) VLDCKR(mylib/DSPSPLFVC)
若執行有問題或不使用檢核程式時,執行
CHGCMD CMD(DSPSPLF) VLDCKR(*NONE)
/* Program : DSPSPLFVC */
/* System : iSeries 400 FOR V5R2 */
/* */
/* Validity Checking program for command DSPSPLF */
/* */
/* Example : protecting an SPOOL From a USER */
/* */
/* CHGCMD CMD(DSPSPLF) VLDCKR(MYLIB/DSPSPLFVC) */
/* To reset (in case you made errors) : */
/* CHGCMD CMD(DSPSPLF) VLDCKR(*NONE) */
DSPSPLFVC: PGM PARM(&P1 &P2 &P3 &P4 &P5 &P6)
DCL VAR(&P1) TYPE(*CHAR) LEN(10) /* FILE */
DCL VAR(&P2) TYPE(*CHAR) LEN(26) /* FULLJOB */
DCL VAR(&P3) TYPE(*CHAR) LEN(4) /* SPLNBR */
DCL VAR(&P4) TYPE(*CHAR) LEN(8) /* SYSNAME */
DCL VAR(&P5) TYPE(*CHAR) LEN(6) /* CRTDATE */
DCL VAR(&P6) TYPE(*CHAR) LEN(1) /* FOLD */
DCL VAR(&SPLUSR) TYPE(*CHAR) LEN(10)
DCL VAR(&USER) TYPE(*CHAR) LEN(10)
DCL VAR(&JOBNAME) TYPE(*CHAR) LEN(10)
DCL VAR(&JOBNBR) TYPE(*CHAR) LEN(6)
RTVJOBA JOB(&JOBNAME) USER(&USER) NBR(&JOBNBR)
IF (%SST(&P2 1 1) *EQ '*') DO
CHGVAR &SPLUSR &USER
CHGVAR %SST(&P2 1 10) &JOBNAME
CHGVAR %SST(&P2 11 10) &USER
CHGVAR %SST(&P2 21 6) &JOBNBR
ENDDO
ELSE +
CHGVAR &SPLUSR %SST(&P2 11 10)
/* USER QSECOFR, QSYSOPR UNLIMIT ACCESS SPOOLED FILE */
IF ((&USER *EQ 'QSECOFR') *OR +
(&USER *EQ 'QSYSOPR')) +
THEN(GOTO OK)
/* LIMIT ONLY SPOOLED CREATION USER CAN BROWSE OWN'S SPOOLED FILE */
IF COND(&USER *NE &SPLUSR) +
THEN(GOTO NOT_OK)
OK:
RETURN
NOT_OK: SNDPGMMSG MSGID(CPD0006) MSGF(QCPFMSG) MSGDTA('0000' +
*CAT 'You are not authorized to spooled +
file' *BCAT &P1) MSGTYPE(*DIAG)
SNDPGMMSG MSGID( CPF0002 ) +
MSGF( QSYS/QCPFMSG ) +
MSGTYPE( *ESCAPE )
ENDPGM
2002-12-18 如何限制指令 WRKSPLF 的使用, 防止使用者指定參數 USER(*ALL) 察看全系統的報表 ?
如何限制指令 WRKSPLF 的使用, 防止使用者指定參數 USER(*ALL) 察看全系統的報表 ?
某些使用者只要授與 *SPLCTL 的特殊權限,那他對系統上所有報表均有最高的權限,
他可以搬移刪除檢視所有報表,當然包含重要的機密資料,如薪資資料,所以我們需
要做適當的限制,我們可以利用命令檢核程式(Validity Checking Program) 達
到控管的目的。你可以利用下述範例更改呈自己的需求。
File : QCLSRC
Member: WRKSPLFVC
Type : CLP
OS Version : All
Usage : CRTCLPGM PGM(your-lib/WRKSPLFVC)
Execute the following command :
CHGCMD CMD(QSYS/WRKSPLF) VLDCKR(your-lib/VALWRKSPLF)
To reset (If you made a mistake) :
CHGCMD CMD(QSYS/WRKSPLF) VLDCKR(*NONE)
/* The user is not authorised to use parameter USER *ALL */
/* (Except QSYSOPR, QSECOFR, QSRV) */
/* */
/* EXECUTE THE FOLLOWING COMMAND : */
/* */
/* CHGCMD CMD(QSYS/WRKSPLF) VLDCKR(MYLIB/WRKSPLFVC) */
/* */
/* TO RESET (IF YOU MADE A MISTAKE) : */
/* */
/* CHGCMD CMD(QSYS/WRKSPLF) VLDCKR(*NONE) */
/* */
WRKSPLFVC: PGM PARM(&P1 &P2 &P3 &P4)
DCL VAR(&P1) TYPE(*CHAR) LEN(44)
DCL VAR(&P2) TYPE(*CHAR) LEN(7)
DCL VAR(&P3) TYPE(*CHAR) LEN(10)
DCL VAR(&P4) TYPE(*CHAR) LEN(1)
DCL VAR(&USER) TYPE(*CHAR) LEN(10)
DCL VAR(&USERPARM) TYPE(*CHAR) LEN(10)
DCL VAR(&FORMTYPE) TYPE(*CHAR) LEN(10)
DCL VAR(&DEVICE) TYPE(*CHAR) LEN(10)
DCL VAR(&USERDATA) TYPE(*CHAR) LEN(10)
DCL VAR(&ASP_BIN) TYPE(*CHAR) LEN(2)
DCL VAR(&ASP_DEC) TYPE(*DEC) LEN(2 0)
RTVJOBA USER(&USER)
/* Return if the USER is authorized to use all parameter values */
IF COND(&USER *EQ QSYSOPR *OR &USER *EQ QSECOFR +
*OR &USER *EQ QSRV) THEN(RETURN)
/* Parse the command parameters */
CHGVAR VAR(&ASP_BIN) VALUE(%SST(&P1 43 2))
CHGVAR VAR(&ASP_DEC) VALUE(%BIN(&ASP_BIN 1 2))
CHGVAR VAR(&USERPARM) VALUE(%SST(&P1 3 10))
CHGVAR VAR(&FORMTYPE) VALUE(%SST(&P1 13 10))
CHGVAR VAR(&DEVICE) VALUE(%SST(&P1 23 10))
CHGVAR VAR(&USERDATA) VALUE(%SST(&P1 33 10))
/* Check the value of the parameter USER */
IF COND(&USERPARM *NE *ALL) THEN(RETURN)
/* User is not allowed to execute WRKSPLF with USER *ALL */
/* Send a diagnostic message to the user. */
NOT_OK: SNDPGMMSG MSGID(CPD0006) MSGF(QCPFMSG) MSGDTA('0000 +
You are not Authorized to use parameter +
USER *ALL.') MSGTYPE(*DIAG)
/* Message CPF0002 is used in validity checking programs to */
/* indicate an error condition */
SNDPGMMSG MSGID(CPF0002) MSGF(QSYS/QCPFMSG) +
MSGTYPE(*ESCAPE)
END: ENDPGM
2002-12-02 如何複製報表並可更改報表屬性(如報表擁有人, 報表名稱...) (Command DUPCHGSPLF)?
如何複製報表並可更改報表屬性(如報表擁有人, 報表名稱...) (Command DUPCHGSPLF)?
要複製報表並可更改報表屬性(如報表擁有人, 報表名稱...), 有多種方式, 利用
CPYSPLF, OVRPRTF, 及 CPYF 三個指令組合方式也可以完成, 但繁瑣耗時, 這裡介
紹直接用 API , 並製作成指令 DUPCHGSPLF.
File : QCLSRC
Member: DUPCHGSPLF
Type : CLP
Usage : CRTCLPGM DUPCHGSPLF
Version: ALL
/* Program : DUPCHGSPLF */
/* System : iSeries */
/* */
/* Description : Duplicate and Change Spooled File */
/* */
/* To compile : */
/* */
/* CRTCLPGM PGM(XXX/DUPCHGSPLF) SRCFILE(XXX/QCLSRC) */
/* */
DUPCHGSPLF: PGM PARM(&JOB &SPLFILE &SPLNBRBIN &LPI &CPI +
&FONT &PAGRTT &OUTQ &DRAWER &FORMTYPE +
&USRDTA &HOLD &SAVE &DUPLEX &OUTBIN +
&NEWUSER &NEWSPLNAME &DLTSPLF)
/* Parameters */
DCL VAR(&JOB) TYPE(*CHAR) LEN(26)
DCL VAR(&SPLFILE) TYPE(*CHAR) LEN(10)
DCL VAR(&SPLNBRBIN) TYPE(*CHAR) LEN(4)
DCL VAR(&LPI) TYPE(*CHAR) LEN(4)
DCL VAR(&CPI) TYPE(*CHAR) LEN(4)
DCL VAR(&PAGRTT) TYPE(*CHAR) LEN(4)
DCL VAR(&DRAWER) TYPE(*CHAR) LEN(4)
DCL VAR(&FONT) TYPE(*CHAR) LEN(5)
DCL VAR(&OUTQ) TYPE(*CHAR) LEN(20)
DCL VAR(&FORMTYPE) TYPE(*CHAR) LEN(10)
DCL VAR(&USRDTA) TYPE(*CHAR) LEN(10)
DCL VAR(&HOLD) TYPE(*CHAR) LEN(10)
DCL VAR(&SAVE) TYPE(*CHAR) LEN(10)
DCL VAR(&DUPLEX) TYPE(*CHAR) LEN(10)
DCL VAR(&OUTBIN) TYPE(*CHAR) LEN(4)
DCL VAR(&NEWUSER) TYPE(*CHAR) LEN(10)
DCL VAR(&NEWSPLNAME) TYPE(*CHAR) LEN(10)
DCL VAR(&DLTSPLF) TYPE(*CHAR) LEN(10)
/* Variables */
DCL VAR(&SPLNBRDEC) TYPE(*DEC) LEN(8 0)
DCL VAR(&SPLNBRCHR) TYPE(*CHAR) LEN(8)
DCL VAR(&JOBNAME) TYPE(*CHAR) LEN(10)
DCL VAR(&JOBUSER) TYPE(*CHAR) LEN(10)
DCL VAR(&JOBNBR) TYPE(*CHAR) LEN(6)
DCL VAR(&HANDLE) TYPE(*CHAR) LEN(4) /* Spooled +
file handle */
DCL VAR(&BUFFER) TYPE(*CHAR) LEN(4) /* number of +
buffers to get */
DCL VAR(&SPLATTR) TYPE(*CHAR) LEN(5000)
DCL VAR(&ATTRLEN) TYPE(*CHAR) LEN(4)
DCL VAR(&INDIC) TYPE(*CHAR) LEN(1)
/* Parameters for the QUSCRTUS API */
DCL VAR(&USPNAME) TYPE(*CHAR) LEN(10) /* user +
space name */
DCL VAR(&USPLIB) TYPE(*CHAR) LEN(10) /* user +
space library */
DCL VAR(&USPQUAL) TYPE(*CHAR) LEN(20) /* user +
space qualified name */
DCL VAR(&USPTYPE) TYPE(*CHAR) LEN(10) /* user +
space type */
DCL VAR(&USPSIZE) TYPE(*CHAR) LEN(4) /* user +
space size */
DCL VAR(&USPFILL) TYPE(*CHAR) LEN(1) /* user +
space fill character */
DCL VAR(&USPAUT) TYPE(*CHAR) LEN(10) /* user +
space authority */
DCL VAR(&USPTEXT) TYPE(*CHAR) LEN(50) /* user +
space text */
/* Parameters for the QUSRTVUS API */
DCL VAR(&STARTPOS) TYPE(*CHAR) LEN(4)
DCL VAR(&DATALEN ) TYPE(*CHAR) LEN(4)
DCL VAR(&HEADER) TYPE(*CHAR) LEN(150)
CHGVAR VAR(%BIN(&ATTRLEN)) VALUE(5000)
/* Create User space */
CHGVAR VAR(&USPNAME) VALUE('DUPCHGSPLF') /* set +
user space name */
CHGVAR VAR(&USPLIB) VALUE('QTEMP') /* set user +
space library */
CHGVAR VAR(&USPQUAL) VALUE(&USPNAME *CAT &USPLIB) +
/* set user space qualified name */
CHGVAR VAR(&USPTYPE) VALUE('MYTYPE') /* set user +
space type */
CHGVAR VAR(%BIN(&USPSIZE)) VALUE(64000) /* set +
user space size */
CHGVAR VAR(&USPFILL) VALUE(' ') /* set user space +
fill character */
CHGVAR VAR(&USPAUT) VALUE('*USE') /* set user +
space authority */
CHGVAR VAR(&USPTEXT) VALUE('my user space') +
/* set user space text */
CALL PGM(QUSCRTUS) PARM(&USPQUAL &USPTYPE +
&USPSIZE &USPFILL &USPAUT &USPTEXT)
/* Open spooled file */
CHGVAR VAR(&BUFFER) VALUE(X'FFFFFFFF')
CALL PGM(QSPOPNSP) PARM(&HANDLE &JOB ' ' ' ' +
&SPLFILE &SPLNBRBIN &BUFFER X'00000000')
/* Get spooled file data */
CALL PGM(QSPGETSP) PARM(&HANDLE &USPQUAL +
'SPFR0200' &BUFFER '*WAIT' X'00000000')
/* Close spooled file */
CALL PGM(QSPCLOSP) PARM(&HANDLE X'00000000')
/* Retrieve Spooled file attributes */
CALL PGM(QUSRSPLA) PARM(&SPLATTR &ATTRLEN +
'SPLA0200' &JOB ' ' ' ' &SPLFILE &SPLNBRBIN)
IF COND(%BIN(&LPI) *NE 0) THEN(CHGVAR +
VAR(%SST(&SPLATTR 181 4)) VALUE(&LPI))
IF COND(%BIN(&CPI) *NE 0) THEN(CHGVAR +
VAR(%SST(&SPLATTR 185 4)) VALUE(&CPI))
IF COND(&FONT *NE *SAME) THEN(CHGVAR +
VAR(%SST(&SPLATTR 537 4)) VALUE(&FONT))
IF COND(%BIN(&PAGRTT) *NE -4) THEN(CHGVAR +
VAR(%SST(&SPLATTR 553 4)) VALUE(&PAGRTT))
IF COND(&OUTQ *NE *SAME) THEN(CHGVAR +
VAR(%SST(&SPLATTR 191 20)) VALUE(&OUTQ))
IF COND(%BIN(&DRAWER) *NE 0) THEN(CHGVAR +
VAR(%SST(&SPLATTR 533 4)) VALUE(&DRAWER))
IF COND(%BIN(&OUTBIN) *NE -1) THEN(CHGVAR +
VAR(%SST(&SPLATTR 3313 4)) VALUE(&OUTBIN))
IF COND(&FORMTYPE *NE *SAME) THEN(CHGVAR +
VAR(%SST(&SPLATTR 89 10)) VALUE(&FORMTYPE))
IF COND(&USRDTA *NE *SAME) THEN(CHGVAR +
VAR(%SST(&SPLATTR 99 10)) VALUE(&USRDTA))
IF COND(&HOLD *NE *SAME) THEN(CHGVAR +
VAR(%SST(&SPLATTR 129 10)) VALUE(&HOLD))
IF COND(&SAVE *NE *SAME) THEN(CHGVAR +
VAR(%SST(&SPLATTR 139 10)) VALUE(&SAVE))
IF COND(&DUPLEX *NE *SAME) THEN(CHGVAR +
VAR(%SST(&SPLATTR 561 10)) VALUE(&DUPLEX))
IF COND(&NEWUSER *NE *SAME) THEN(CHGVAR +
VAR(%SST(&SPLATTR 59 10)) VALUE(&NEWUSER))
CHGVAR VAR(&JOBNAME) VALUE(%SST(&SPLATTR 49 10))
CHGVAR VAR(&JOBUSER) VALUE(%SST(&SPLATTR 59 10))
IF COND(&NEWSPLNAME *EQ *JOBNAME) THEN(CHGVAR +
VAR(&NEWSPLNAME) VALUE(&JOBNAME))
IF COND(&NEWSPLNAME *EQ *USER) THEN(CHGVAR +
VAR(&NEWSPLNAME) VALUE(&JOBUSER))
IF COND(&NEWSPLNAME *NE *SAME) THEN(CHGVAR +
VAR(%SST(&SPLATTR 75 10)) VALUE(&NEWSPLNAME))
/* Create Spooled file */
CALL PGM(QSPCRTSP) PARM(&HANDLE &SPLATTR +
X'00000000')
/* Put Spooled File data */
CALL PGM(QSPPUTSP) PARM(&HANDLE &USPQUAL +
X'00000000')
/* Close Spooled file */
CALL PGM(QSPCLOSP) PARM(&HANDLE X'00000000')
/* Retrieve User space HEADER information */
CHGVAR VAR(%BIN(&STARTPOS)) VALUE(1) /* set start +
position */
CHGVAR VAR(%BIN(&DATALEN)) VALUE(140) /* set data +
length */
CALL PGM(QUSRTVUS) PARM(&USPQUAL &STARTPOS +
&DATALEN &HEADER)
DLTUSRSPC USRSPC(&USPLIB/&USPNAME)
CHGVAR VAR(&INDIC) VALUE(%SST(&HEADER 87 1))
IF COND(&INDIC *EQ C) THEN(DO)
SNDPGMMSG MSGID(CPF9898) MSGF(QCPFMSG) MSGDTA('Spooled +
file' *BCAT &SPLFILE *BCAT 'duplicated') +
MSGTYPE(*COMP)
ENDDO
ELSE CMD(DO)
SNDPGMMSG MSGID(CPF9898) MSGF(QCPFMSG) MSGDTA('Spooled +
file' *BCAT &SPLFILE *BCAT 'not +
completely duplicated') MSGTYPE(*ESCAPE)
ENDDO
/* Delete Original Spooled File */
IF COND(&DLTSPLF *EQ *NO) THEN(RETURN)
IF COND(&JOB *EQ '*') THEN(RTVJOBA +
JOB(&JOBNAME) USER(&JOBUSER) NBR(&JOBNBR))
ELSE CMD(DO)
CHGVAR VAR(&JOBNAME) VALUE(%SST(&JOB 1 10))
CHGVAR VAR(&JOBUSER) VALUE(%SST(&JOB 11 10))
CHGVAR VAR(&JOBNBR) VALUE(%SST(&JOB 21 6))
ENDDO
IF COND(%BIN(&SPLNBRBIN) *EQ 0) THEN(CHGVAR +
VAR(&SPLNBRCHR) VALUE(*ONLY))
IF COND(%BIN(&SPLNBRBIN) *EQ -1) THEN(CHGVAR +
VAR(&SPLNBRCHR) VALUE(*LAST))
IF COND(%BIN(&SPLNBRBIN) *GT 0) THEN(DO)
CHGVAR VAR(&SPLNBRDEC) VALUE(%BIN(&SPLNBRBIN))
CHGVAR VAR(&SPLNBRCHR) VALUE(&SPLNBRDEC)
ENDDO
DLTSPLF FILE(&SPLFILE) +
JOB(&JOBNBR/&JOBUSER/&JOBNAME) +
SPLNBR(&SPLNBRCHR)
MONMSG MSGID(CPF0000)
END: ENDPGM
File : QCMDSRC
Member: DUPCHGSPLF
Type : CMD
Usage : CRTCMD CMD(DUPCHGSPLF) PGM(DUPCGHSPLF)
Version: ALL
/* */
/* \\\\\\\ */
/* ( o o ) */
/*------------------------oOO----(_)----OOo-------------------------*/
/* */
/* Command : DUPCHGSPLF */
/* System : iSeries */
/* */
/* Description : Duplicate and Change Spooled file */
/* */
/* ooooO Ooooo */
/* ( ) ( ) */
/*----------------------( )-------------( )---------------------*/
/* (_) (_) */
/* */
/* To compile : */
/* */
/* CRTCMD CMD(XXX/DUPCHGSPLF) PGM(XXX/DUPCHGSPLF) + */
/* SRCFILE(XXX/QCMDSRC) */
/* */
DUPCHGSPLF: CMD PROMPT('Duplicate and change SPLF')
PARM KWD(JOB) TYPE(JOBNAME) DFT(*) SNGVAL((*)) +
PROMPT('Job name')
PARM KWD(SPLFILE) TYPE(*NAME) LEN(10) DFT(QPRINT) +
PROMPT('Spooled file name')
PARM KWD(SPLNBR) TYPE(*INT4) DFT(*LAST) RANGE(1 +
9999) SPCVAL((*ONLY 0) (*LAST -1)) MIN(0) +
PROMPT('Spooled file number')
PARM KWD(LPI) TYPE(*INT4) RSTD(*YES) DFT(*SAME) +
SPCVAL((*SAME 0) (6 60) (8 80) (3 30) (4 +
40) (7.5 75) (7,5 75) (9 90) (12 120)) +
MIN(0) PROMPT('Lines per inch')
PARM KWD(CPI) TYPE(*INT4) RSTD(*YES) DFT(*SAME) +
SPCVAL((*SAME 0) (10 100) (5 50) (12 120) +
(13.3 133) (13,3 133) (15 150) (16.7 167) +
(16,7 167) (18 180) (20 200)) MIN(0) +
PROMPT('Characters per inch')
PARM KWD(FONT) TYPE(*CHAR) LEN(5) RSTD(*YES) +
DFT(*SAME) VALUES(*SAME *CPI) PROMPT('Font')
PARM KWD(PAGRTT) TYPE(*INT4) RSTD(*YES) +
DFT(*SAME) VALUES(0 90 180 270) +
SPCVAL((*AUTO -1) (*DEVD -2) (*COR -3) +
(*SAME -4)) PROMPT('Degree of page rotation')
PARM KWD(OUTQ) TYPE(OUTQ) DFT(*SAME) +
SNGVAL((*SAME)) MIN(0) PROMPT('Output queue')
PARM KWD(DRAWER) TYPE(*INT4) DFT(*SAME) RANGE(1 +
255) SPCVAL((*SAME 0) (*E1 -1)) +
PROMPT('Source drawer')
PARM KWD(FORMTYPE) TYPE(*CHAR) LEN(10) DFT(*SAME) +
SPCVAL((*SAME) (*STD)) PROMPT('Formtype')
PARM KWD(USRDTA) TYPE(*CHAR) LEN(10) DFT(*SAME) +
SPCVAL((*SAME)) PROMPT('User specified data')
PARM KWD(HOLD) TYPE(*CHAR) LEN(10) RSTD(*YES) +
DFT(*SAME) VALUES(*YES *NO) +
SPCVAL((*SAME)) PROMPT('Hold file before +
written')
PARM KWD(SAVE) TYPE(*CHAR) LEN(10) RSTD(*YES) +
DFT(*SAME) VALUES(*YES *NO) +
SPCVAL((*SAME)) PROMPT('Save file after +
written')
PARM KWD(DUPLEX) TYPE(*CHAR) LEN(10) RSTD(*YES) +
DFT(*SAME) VALUES(*YES *NO *TUMBLE +
*FORMDF) SPCVAL((*SAME)) PROMPT('Print on +
both sides (Duplex)')
PARM KWD(OUTBIN) TYPE(*INT4) DFT(*SAME) RANGE(1 +
65535) SPCVAL((*SAME -1) (*DEVD 0)) +
PROMPT('Output bin')
PARM KWD(NEWUSER) TYPE(*NAME) LEN(10) DFT(*SAME) +
SPCVAL((*SAME)) PROMPT('New User')
PARM KWD(NEWSPLNAME) TYPE(*NAME) LEN(10) +
DFT(*SAME) SPCVAL((*SAME) (*JOBNAME) +
(*USER)) PROMPT('New Spool file name')
PARM KWD(DLTSPLF) TYPE(*CHAR) LEN(10) RSTD(*YES) +
DFT(*NO) VALUES(*YES *NO) PROMPT('Delete +
file after duplication')
OUTQ: QUAL TYPE(*NAME) LEN(10) MIN(1)
QUAL TYPE(*NAME) LEN(10) DFT(*LIBL) +
SPCVAL((*CURLIB) (*LIBL)) PROMPT('Library')
JOBNAME: QUAL TYPE(*NAME) LEN(10) MIN(1)
QUAL TYPE(*NAME) LEN(10) DFT(' ') SPCVAL((' ')) +
CHOICE('Name') PROMPT('User')
QUAL TYPE(*CHAR) LEN(6) DFT(' ') RANGE(000000 +
999999) SPCVAL((' ')) FULL(*YES) +
CHOICE('000000-999999') PROMPT('Number')
2002-09-11 如何讓報表管理自動化?
2002-09-11 如何讓報表管理自動化?
報表管理通常是一般系統管理的工作,AS/400(iSeries) 系統已包含以使用者及使用者自己的報表連結相關
的印表機及輸出佇列(Outq -- Output Queue)的報表管理技術,通常管理人員會允許使用者使用指令
WRKSPLF(Work with Spool Files) 及 WRKOUTQ(Work with Output Queues) 截取報表資料,這些指令讓使
用者管理他們自己的報表,及若某使用者同時擁有 *SPLCTL 特殊權限時,該使用者同時可以管理其他人的
報表,然而使用這些指令仍然無法讓報表管理自動化。使用者仍然需要從一個輸出佇列搬移報表至另一個輸
出佇列或從一台印表機搬移報表至另一台印表機。
為什麼有人想要讓報表管理自動化?因為當報表很多時,如週報月報季報年報累計一段時間後,就會有報表
儲存的需求,因為報表本身於 AS/400(iSeries)系統上並不是一個物件,所以無法利用 SAVE 指令儲存,所
以需要採用某些技巧才將報表儲存起來,當然報表可以利用複製報表至資料庫檔案儲存在 AS/400(iSeries)
或下載至 PC 上,但報表非常多時便無法一一用手動的方式來完成,所以可以利用其他廠商所開發的報表管
理軟體,所以仍需要額外的成本才能完成報表管理自動化的工作,基於成本考量,我將教您如何達成報表管
理自動化的方式。其步驟如下:
1:取得哪些報表放置於輸出佇列中的詳細資料,即報表管理自動化的先決條件是以輸出佇列(Outq)為管理
單位。
2:使用指令 CPYSPLF 複製報表資料至資料庫檔案(PF -- Physical file)。
3:
a 若僅需儲存報表於 AS/400(iSeries)上,則定期備份步驟2所產生的資料庫檔案(需要自行定義資
料庫檔案名稱及其 member 成員名稱,方便於備份及回複管理)。
b 若僅需儲存報表於 PC 上,則有三種方式:
一: 使用指令 CPYTOSTMF 複製步驟2所產生的資料庫檔案至 IFS 的一般 PC 檔案即可使用
SAV/RST 指令備份/回複或
二: 使用 FTP 方式將步驟2所產生的資料庫檔案傳送到 PC 的 FTP 伺服器或
三: 於 AS/400(iSeries) 及 PC 端撰寫 Socket 程式,傳送步驟2所產生的資料庫檔案至 PC。
在這裡我僅以方式一來做例子。
要如何將上述三個步驟組合自動處理而不用人工介入輸入指令呢?
這起始點是如何取得放置於輸出佇列中報表的詳細資料,您可以藉由系統所提供用以連結輸出佇列(Outq)的
資料佇列(DTAQ -- Data Queue)來取得放置於輸出佇列(Outq)中報表的詳細資料,來完成第一個步驟,所以
第一步是藉由下述指令新增一個資料佇列(DTAQ -- Data Queue),
CRTDTAQ DTAQ(lib/AUTOSPLDTAQ) MAXLEN(128)
然後新增一個輸出佇列(Outq),同時指定 DTAQ(Data Queue) 參數連結上述指令所新增的資料佇列(DTAQ --
Data Queue),指令如下,
CRTOUTQ OUTQ(lib/AUTOSPLOUTQ) DTAQ(lib/AUTOSPLDTAQ)
在上述例子中 "lib" 是您所希望放置輸出佇列Outq(Output Queue)及 資料佇列DTAQ(Data Queue) 物件的程
式庫(附註:Outq 及 Dtaq 可以放置於不同的程式庫)。
上述指令在輸出佇列 AUTOSPLOUTQ 及資料佇列 AUTOSPLDTAQ 間建立了一個連結關係,所以當有報表放置於輸
出佇列 AUTOSPLOUTQ 時,同時會有一筆該報表的相關資料放置於資料佇列 AUTOSPLDTAQ 中。
放置於資料佇列 AUTOSPLDTAQ 中資訊的長度有 128 位,包含如下資訊:
報表資訊放置於資料佇列DTAQ(Data Queue)的資料格式
===========================================
起始位置 長度 說明
==== ==== =================================
1 CHAR(10) Function "*SPOOL" 表此筆記錄是報表相關資訊(不需要)
11 CHAR(02) Record type "01" 表示已放置至輸出佇列的報表狀態為 Ready(不需要)
13 CHAR(26) Qualified job name 產生此報表的 Job 全名
CHAR(10) Job name
CHAR(10) User name
CHAR(6) Job number
39 CHAR(10) Spool file name 表示已放置至輸出佇列報表的報表名稱
49 BINARY(4) Spool file number 表示已放置至輸出佇列報表的報表序號
53 CHAR(20) Qualified output queue name 表示此報表所放置的輸出佇列名稱全名
CHAR(10) Output queue name
CHAR(10) Library of the output queue
73 CHAR(56) 56 bytes of filler 此 56 位保留不用(不需要)
上述資訊可能用於指令 CPYSPLF 及 CPYTOSTMF。
要記住當有有一份新的報表放置於輸出佇列Outq(Output Queue)中時,而且該報表的狀態是 Ready(RDY),此時
即有一筆報表紀錄放置於資料佇列 DTAQ(Data Queue)中,所以我們需要一個批次工作用以監控是否有新的報表
資訊放置於資料佇列 DTAQ(Data Queue) 中。
下列是用於處理這個程序的 RPGIV 程式片斷,底下是依照報表資訊放置於資料佇列DTAQ(Data Queue)的資料格
式用於接收資料佇列 DTAQ(Data Queue)資料的資料結構:
D SpoolInfo DS
D Function 10
D RecordType 2
D QualJobName 26
D JobName 10 Overlay(QualJobName:1)
D JobUser 10 Overlay(QualJobName:11)
D JobNumber 6 Overlay(QualJobName:21)
D FileName 10
D FileNumber 9B 0
D QualQueueName 20
D QueueName 10 Overlay(QualQueueName:1)
D QueueLibrary 10 Overlay(QualQueueName:11)
D Filler 56
這個資料結構包含從資料佇列 DTAQ(Data Queue) 所取得的資訊,job name,job user,job number,file name
及 file number 是重要的資訊,並提供給指令 CPYSPLF 使用。
下列是要擷取資料佇列 DTAQ(Data Queue) 報表資訊所需要使用的資料欄位範例:
* Data Queue Variables
D RcvQueueName S 10 Inz(‘AUTOSPLDTAQ’)
D RcvQueueLib S 10 Inz('*LIBL')
D RcvMsgSize S 5 0 Inz(%Size(RcvMsg))
D RcvMsg S 128
D RcvWaitTime S 5 0 Inz(-1)
下列是接收資料佇列 DTAQ(Data Queue) 報表資訊所使用的 RPGIV 運算:
C Call 'QRCVDTAQ'
C Parm RcvQueueName
C Parm RcvQueueLib
C Parm RcvMsgSize
C Parm RcvMsg
C Parm RcvWaitTime
欄位 RcvWaitTime 值為 -1,表示接收資料佇列 DTAQ(Data Queue) 報表資訊時,若資料佇列 DTAQ(Data Queue)
沒有報表資訊紀錄時,即一直等待至有資訊時才讀取,等待時並不會耗用系統資源。如果程式還要執行除了處理
資料佇列 DTAQ(Data Queue) 之外的其他工作時,RcvWaitTime 值也可以設定一個以秒為單位的值,以符合您的
需求。
當然這個程序也可以使用 CL 程式而不用 RPGIV 來開發,由於 RPGIV 的字串處理函數功能比 CL 好,所以我選擇
RPGIV。
接著要進行第二個步驟,也就是要使用指令 CPYSPLF 複製報表資料至資料庫檔案。
這個工作類似大部分系統管理人員所要做的,有時候系統管理人員需要拷貝報表資料給公司內部人員或廠商使用,
或將儲存報表資料並拷貝至磁帶後,再將報表及儲存報表的資料庫檔案刪除,才能釋放系統儲存空間,有需要使用
時再回複(restore)回系統。在這裡我想將報表分享給 PC 使用者,所以我將儲存報表的資料庫檔案拷貝至 IFS 的
一個目錄,並將該目錄分享出來,如同一般 PC 的網路磁碟機,PC 使用者可以透過網路磁碟機,直接讀取報表。
您可以使用 Client Access Operation Navigator 將在 IFS 下放置報表的目錄分享出來。
對我而言,RPGIV 處理字串的功能比 CL 好,所以我仍使用 RPGIV 來執行系統指令。我於 RPGIV 中使用系統所提
供的 QCMDEXC 程式來執行系統指令,
在呼叫 QCMDEXC 前需要定義所要使用的二個參數宣告:
D CmdStr S 512
D CmdLen S 15 5
接著呼叫 QCMDEXC 的傳統方式如下:
C Eval CmdStr = ‘WRKSPLF’
C Eval CmdLen = %Len(%Trim(CmdLine))
C Call 'QCMDEXC'
C Parm CmdLine
C Parm CmdLength
"CmdLine" 包含所要執行的指令,及 "CmdLength" 包含所要執行指令的長度。
另一種呼叫 QCMDEXC 的方式是如 C 語言藉由宣告外部函式,我較喜歡此種方式,因為可以使用 RPGIV 的錯誤偵測
功能,下列是宣告外部函式的例子:
D Cmd PR ExtPgm('QCMDEXC')
D 512 Options(*VarSize)
D Const
D 15 5 Const
我使用上述相同的 CmdStr 及 CmdLen 定義。
下列是使用外部函式呼叫 QCMDEXC 的範例:
C Eval CmdStr = 'WRKSPLF’
C Eval CmdLen = %Len(%Trim(CmdStr))
C CallP(E) Cmd(CmdStr:CmdLen)
C If %Error
* (error handling code here)
C EndIf
在 CallP(Call a Prototype Procedure or Program) 後指定一個 "E" 運算元延伸器,當 CallP 指令執行有錯誤時
,我能擷取錯誤並做適當的處理,這就如同 CLP 中的 MOMMSG(Monitor Message) 功能。您覺得哪一個比較好用?
複製報表資料至資料庫檔案包含二個步驟,首先,新增一個資料庫檔案用以存放報表資料,接著,複製報表資料至資
料庫檔案。我新增一個資料庫檔案於程式館 QTEMP 中,並給予該新增的資料庫檔案一個由時間產生的唯一的名稱,
該名稱您可依據自己的需求定義之,下列是我設定的資料庫檔案名稱的定義:
D TimeStamp S Z
D CharTimeStamp S 26
我以 CPY 開頭,後加上時間的微秒(microseconds) 部分當成資料庫檔案名稱,這確保有唯一的名稱,我使用 TIME
運算元,放置程式執行至 TIME 運算元的當時系統時間至 TimeStamp 變數中,然後使用內建函數 %CHAR 將 TimeStamp
值轉換成文字,接著使用內建函數 %SUBST 擷取微秒(microseconds)部分,然後新增一個命令字串如下:
CRTPF FILE(CPYxxxxxx) RCDLEN(200) SIZE(*NOMAX) IGCDTA(*YES) AUT(*ALL)
"xxxxxx" 表示時間的微秒(microseconds)部分,而 "200" 表是報表每行的最大長度,IGCDTA(*YES) 表可容納中文 DBCS。
* Create the file to receive CPYSPLF output in QTEMP.
C CrtFile BegSr
C Time TimeStamp
C Eval CharTimeStamp = %Char(TimeStamp)
C Eval CmdStr = 'CRTPF FILE(QTEMP/' +
C 'CPY' +
C %SubSt(CharTimeStamp:21:6) +
C ')' + ' ' + 'RCDLEN(200) +
C SIZE(*NOMAX) +
C IGCDTA(*YES) +
C AUT(*ALL)'
C Eval CmdLen = %Len(%Trim(CmdStr))
C CallP(E) Cmd(CmdStr:CmdLen)
* (error handling code here)
C EndSr
上述程式片斷新增一個唯一名稱的資料庫檔案於程式館 QTEMP 中。
下一個指令是複製報表資料至資料庫檔案,此時需要使用先前從資料佇列 DTAQ(Data Queue)中收到的資料 ,
當有有一份新的報表放置於輸出佇列Outq(Output Queue)中時,而且該報表的狀態是 Ready(RDY),同時也有一
筆報表紀錄放置於資料佇列 DTAQ(Data Queue)中,而這筆記錄由程式讀入,並放置於一個資料結構中,資料結
構中的資訊可以用來擷取指定的報表,為了便於參照,這裡再將資料佇列 DTAQ(Data Queue)中報表相關資料的
資料格式列出:
D SpoolInfo DS
D Function 10
D RecordType 2
D QualJobName 26
D JobName 10 Overlay(QualJobName:1)
D JobUser 10 Overlay(QualJobName:11)
D JobNumber 6 Overlay(QualJobName:21)
D FileName 10
D FileNumber 9B 0
D QualQueueName 20
D QueueName 10 Overlay(QualQueueName:1)
D QueueLibrary 10 Overlay(QualQueueName:11)
D Filler 56
複製報表資料至資料庫檔案的指令如下:
CPYSPLF FILE(FILENAME) TOFILE(CPYxxxxxx) JOB(QUALJOBNAME) SPLNBR(FILENUMBER)
"FileName" 表從資料佇列 DTAQ(Data Queue) 所取得的報表名稱,
"CPYxxxxxx" 是前一步驟所新增的資料庫檔案名稱,
"QualJobName" 表從資料佇列 DTAQ(Data Queue) 所取得產生報表 Job,
"FileNumber" 表從資料佇列 DTAQ(Data Queue) 所取得的報表序號。
* Execute a CPYSPLF to file in QTEMP.
C CpyFile BegSr
C
C Eval ZoneNumber = FileNumber
C Move ZoneNumber CharNumber
C Eval CmdStr = 'CPYSPLF FILE(' +
C %Trim(FileName) +')' + ' ' +
C 'TOFILE(QTEMP/' +
C 'CPY' +
C %SubSt(CharTimeStamp:21:6) +
C ')' +
C ' ' + 'JOB(' +
C %Trim(JobNumber) + '/' +
C %Trim(JobUser) + '/' +
C %Trim(JobName) +
C ')' + ' ' +
C 'SPLNBR(' + CharNumber + ')'
C Eval CmdLen = %Len(%Trim(CmdStr))
C CallP(E) Cmd(CmdStr:CmdLen)
* (error handling code here)
C EndSr
上述程式片斷,複製報表資料至資料庫檔案。
在步驟一及步驟二已完成了擷取報表相關資訊及複製報表資料至資料庫檔案,接著步驟三要拷貝含有報表資料的
資料庫檔案至 IFS 分享目錄的 stream file,所謂的 stream file 是一個以位元(Byte)為單位的檔案,他是一
個連續性的檔案,而不是 AS/400(iSeries) 資料庫以欄位為基礎的紀錄格式(record format)檔案,stream file
並沒有欄位,而是像 PC 的純文字格式的檔案,所以是由程式來決定它的結構,stream file 使用於非資料庫結
構的資料,如影像檔,聲音檔,最重要的是文件檔。
使用指令
CPYTOSTMF(Copy to Stream File) 或 CPYTOIMPF(Copy to Import File),拷貝資料庫檔案至 IFS 分享目錄的
stream file,其中 CPYTOIMPF 較適用於拷貝大量資料,下列是執行範例:
CPYTOSTMF FROMMBR('/QSYS.LIB/QTEMP.LIB/CPY123456.FILE/CPY123456.MBR')
TOSTMF('/spool/QSYSPRT-201134-0001.txt') STMFOPT(*REPLACE) STMFCODPAG(*PCASCII)
CPYTOSTMF FROMMBR('/QSYS.LIB/QTEMP.LIB/CPY123456.FILE/CPY123456.MBR')
TOSTMF('/spool/QSYSPRT-201134-0001.txt') STMFOPT(*REPLACE) STMFCODPAG(950)
CPYTOSTMF FROMMBR('/QSYS.LIB/QTEMP.LIB/CPY123456.FILE/CPY123456.MBR')
TOSTMF('/spool/QSYSPRT-201134-0001.txt') STMFOPT(*REPLACE)
CVTDTA(*AUTO) DBFCCSID(*FILE) STMFCODPAG(950)
參數 CVTDTA(*AUTO) 及 DBFCCSID(*FILE) 是預設值可以不用設,在此僅列出參考。
或
CPYTOIMPF FROMFILE(QTEMP/CPY123456) TOSTMF('/spool/QSYSPRT-201134-0001.txt') MBROPT(*REPLACE)
STMFCODPAG(*PCASCII) RCDDLM(*CRLF) STRDLM(*NONE)
CPYTOIMPF FROMFILE(QTEMP/CPY123456) TOSTMF('/spool/QSYSPRT-201134-0001.txt') MBROPT(*REPLACE)
STMFCODPAG(950) RCDDLM(*CRLF) STRDLM(*NONE)
上述 STMFCODPAG 指的是 PC 的字元頁碼,您可以特別指定 950 是中文 Big5 的字元頁碼,若使用 *PCASCII,
則系統會自行依照相關系統資訊運算出您的 PC 字元頁碼,這會花少許時間,不過使用者不會有延遲的感覺,我傾
像使用較明確的指定 PC 的字元頁碼,這樣較不會混淆。不過我於範例中使用 STMFCODPAG(*PCASCII)。
當轉換中文時,系統會自動將中文控制碼 0E 及 0F 裁掉,所以資料會往左靠,您將需要於轉換前作額外的處理,
如將加一個空白於 0E 前及 0F 後,下列詳細說明整個 0E 及 0F 的處理方式:
位置 .123456789012
原來資料 .0 0
.E中文F123
轉換後的資料 .中文123 ====> 資料會往左靠,造成有中文的報表格式位移
位置 .123456789012
.0 0
原來資料 .E中文F123
. 0 0
原來資料插入空白後 . E中文F 123 <==== 於 0E 前插入一個空白及 0F 後插入一個空白
轉換後的資料 . 中文 123 ====> 將中文控制碼 0E 及 0F 裁掉後,資料與原來資料格式一樣,
所以中文的報表格式正確
我在範例中使用 CPYTOSTMF 執行拷貝的動作,我仍然使用先前所定義的呼叫外部函式的方式如下:
宣告呼叫執行系統指令的系統外部函式:
D Cmd PR ExtPgm('QCMDEXC')
D 512 Options(*VarSize)
D Const
D 15 5 Const
宣告外部函式所要使用的參數定義:
D CmdStr S 512
D CmdLen S 15 5
* single quote 單引號
D Quote S 1 Inz(X'7D')
下列 SndFile 副程序是用於產生指令 CPYTOSTMF 及使用 QCMDEXC 執行指令:
C SndFile Begsr
* Send the spooled file output to the appropriate IFS directory.
C Eval CmdLine = 'CPYTOSTMF +
C FROMMBR(' + Quote +
C '/QSYS.LIB/QTEMP.LIB/' +
C 'CPY' +
C %SubSt(CharTimeStamp:21:6) +
C '.FILE' + '/' +
C 'CPY' +
C %SubSt(CharTimeStamp:21:6) +
C '.MBR' + Quote + ')' + ' ' +
C 'TOSTMF(' + Quote +
C '/spool' + ‘/’ +
C %Trim(FileName) + '_' +
C JobNumber + '_' +
C CharNumber +
C Quote + ')' + ' ' +
C 'STMFCODPAG(*PCASCII)' + ' ' +
C 'STMFOPT(*REPLACE)'
C Eval CmdLen = %Len(%Trim(CmdStr))
C CallP(E) Cmd(CmdStr:CmdLen)
* (error handling code here)
C EndSr
上述程式碼中參數 FROMMBR 指定 CPYSPLF 指令所輸出的資料庫檔案名稱,FROMMBR 參數所指定的格式
不同於 AS/400(iSeries)的傳統檔案格式,我雖指定 AS/400(iSeries) 的傳統檔案,但使用 IFS 的檔
案結構格式,檔名以 "/QSYS.LIB" 開頭表示指定 AS/400(iSeries) 的傳統檔案,接著下一層是
"/QTEMP.LIB",最後加上以 "CPY" 加上時間的微秒部分組合成檔案名稱,且也需要指定檔案成員名稱。
一個於 AS/400(iSeries)的傳統(QSYS)檔案中的物件均需要以 ".LIB",".FILE",".MBR" 結尾,這是
CPYTOSTMF 指令及其他相關 IFS 整合性檔案系統的指令所必須的,就如同 PC 或 Unix 的目錄架構。
這個 TOSTMF(To Stream File) 參數是由一個目錄(在這個例子中是指定 "/spool",但您也可以自行指定)
及報表名稱、Job Number、報表序號組成的檔名所組成。
這個 STMFCODPAG(Stream File Code Page) 有多個參數值,其中二個重要的參數值 *PCASCII 及 *STDASCII
,STDASCII 參數值是使用於 IBM PC 所使用的字元編碼,一般是使用 *PCASCII,所指的是一般 Windows 應
用軟體所使用的格式,而 STMFOPT (File Options) 參數是所拷貝的資料是要加入檔尾或覆蓋原有資料的選項
,並利用呼叫函式 QCMDEXC 執行 CPYTOSTMF 指令,拷貝資料庫檔案的報表內容至 IFS 的目錄中。
您可能也需要設定一個 AS/400 NetServer 的目錄分享,AS/400 NetServer 提供分享 IFS 目錄的功能,來讓
Windows PC 當成網路磁碟機,新增目錄分享只要執行一次,AS/400 會保留目錄分享直到刪除該目錄的分享設
定,此刪除動作並不會刪除該分享目錄的資料而僅刪除該目錄的分享設定。
設定 AS/400 NetServer 目錄分享,可以藉由 Operations Navigator 或 APIs 完成,有許多的 AS/400 NetServer
API 可供使用,底下列出部分 APIs 即其使用方法(附註:V5R2 已提供所有 NetServer API 工具於程式庫
QUSRTOOL 中 http://www-1.ibm.com/servers/eserver/iseries/netserver/qusrtool.htm):
* 新增目錄分享 Add File Server Share (QZLSADFS)
CALL QZLSADFS PARM(ROOT '/' x'00000001' x'00000000' 'Root File System Share' x'00000002' x'ffffffff' x'00000000')
* 更改目錄分享 Change File Server Share (QZLSCHFS) 更改目錄分享
CALL QZLSCHFS PARM(ROOT '/' x'00000001' x'00000000' 'Root File System Share' x'00000002' x'ffffffff' x'00000000')
Add and change file server share.
ROOT - 分享名稱 share name
'/' - 分享路徑 path name
x'00000001' - 分享路徑長度 length of path name
x'00000000' - 路徑名稱的字元頁碼 CCSID encoding of path name (0 indicates same as job)
'Root File System Share' - 分享說明 text description
x'00000002' - 分享權限 permissions (2 指可讀寫 indicates r/w)
x'ffffffff' - 同時可以幾個人存取分響目錄 maximum users (-1 只不限制 indicates no max)
x'00000000' - used in error code structure
* Add Print Server Share (QZLSADPS)
CALL QZLSADPS PARM(OUTQ 'QPRINT QGPL ' 'default iSeries outq' x'00000001' 'IBM 4039 LaserPrinter' x'00000000')
* Change Print Server Share (QZLSCHPS)
CALL QZLSCHPS PARM(OUTQ 'QPRINT QGPL ' 'default iSeries outq' x'00000001' 'IBM 4039 LaserPrinter' x'00000000')
Add and change print server share.
OUTQ - share name
'QPRINT QGPL ' - qualified output queue (10 spaces needed for queue, and 10 for library)
'default iSeries outq' - text description
x'0000001' - spool file type (1 indicates *USERASCII, 2 *AFP, 3 *SCS)
'IBM 4039 LaserPrinter' - print driver type (indentifes appropriate print driver for share)
x'00000000' - used in error code structure
* Change Server Guest (QZLSCHSG)
CALL QZLSCHSG PARM(lowauth x'00000000')
lowauth - name of guest user profile
x'00000000' - used in error code structure
* Change Server Information (QZLSSCHSI)
CALL QZLSCHSI PARM(RequestVar x'00000112' ZLSS0100 x'00000000')
RequestVar - variable holding input data structure
x'00000112' - length of variable data
ZLSS0100 - format requested for change (ZLSS0100 indicates server information)
x'00000000' - used in error code structure
* 更改 NetServer 名稱 Change Server Name (QZLSCHSN)
CALL QZLSCHSN PARM(qas400 smbmania 'demo server' x'00000000')
qas400 - server name
smbmania - domain name
'demo server' - text description
x'00000000' - used in error code structure
* 停止NetServer End Server (QZLSENDS)
CALL QZLSENDS PARM(x'00000000')
* End Server Session (QZLSENSS)
CALL QZLSENSS PARM(bucky x'00000000')
bucky - workstation name
x'00000000' - used in error code structure
* List Server Information (QZLSLSTI)
CALL QZLSLSTI PARM('OUTDATA TEST ' ZLSL0100 *ALL x'00000000')
'OUTDATA TEST ' - name of user space to receive information (10 spaces needed for space name, 10 for library)
ZLSL0300 -format of data requested (ZLSL0100 indicates configuration information)
*ALL - information qualifier
x'00000000' - used in error code structure
* Open List of Server Information (QZLSOLST)
* 移除目錄分享設定 Remove Server Share (QZLSRMS)
CALL QZLSRMS PARM(OUTQ x'00000000')
OUTQ - share name
x'00000000' - used in lieu of error code structure
* 啟動NetServer Start Server (QZLSSTRS)
CALL QZLSSTRS PARM('0' x'00000000')
這個 QZLSADFS API 使用於設定目錄分享,底下是如何使用 QZLSADFS API 的範例:
* Call the create share API.
C CreateShare BegSr
C Call 'QZLSADFS'
C Parm ShrName
C Parm ShrPath
C Parm ShrPathLen
C Parm PathCcsid
C Parm ShrTextDesc
C Parm Permissions
C Parm ShrMaxUsrs
C Parm ErroeCode
C EndSr
"ShrName" 指的是 Windows 環境中所看到的目錄分享的名稱,"ShrPath" 指的是 IFS 所要分享的目錄
全名,"ShrTextDesc" 是目錄分享的說明,"ShrPathLen" 是分享目錄全名即 "ShrPath" 的長度,執行
這個副程序會指定一個 IFS 的目錄路徑分享,這允許 Windows 使用者從網路芳鄰看到此分享目錄的檔
案,並且可以存取分享目錄下的檔案。
有關 As/400(iSeries) NetServer 詳細資料請參照 http://www-1.ibm.com/servers/eserver/iseries/netserver/
在這篇文章中,我們提到從拷貝報表資料至資料庫檔案,再從資料庫檔案拷貝至 IFS 的分享目錄中,並
設定目錄分享,讓 Windows 使用者可以可以從網路磁碟機存取資料,藉由這些步驟,您能自行整合從
AS/400 的報表至 Windows PC 的文字檔,並將此流程自動化。我想留這個如何自動化的工作給您自行完
成,因為我知道您可以完成。 在此我僅給您一個間單的 Outq 監控的範例 MONOUTQC CLP 範例。
/* */
/* *********************************************************** */
/* * * */
/* * PROGRAM MONOUTQC * */
/* * * */
/* * By Vengoal Chang * */
/* * DATE 8/29/2002 * */
/* * * */
/* *********************************************************** */
/* */
/* */
/* MONOUTQC - READ DTAQ AND CONVERT SPOOL FILE */
/* */
/* This Program: */
/* - Wait up to 300 seconds to receive an entry from */
/* the data queue */
/* - If no entry read, it check if the program should end */
/* The program stop if: */
/* - Job was cancel with a ENDJOB command */
/* - Subsystem was stop ENDSBS command */
/* - System shut down PWRDWNSYS command */
/* - If the entry is "STOP" program stop immediately */
/* - Split the entry in fields */
/* - Call program CVTSSPL to do the spool file conversion */
/* - Move or Delete the spool file */
/* - Return wait for an entry */
/* */
/*-------------------------------------------------------------*/
/* */
/* PROGRAM CHANGES */
/* */
/* VERSION DATE PROGRAMMER DETAIL */
/* YY/MM/DD */
/* */
/* 1.0 02/08/29 Vengoal INITIAL VERSION */
/* */
/*-------------------------------------------------------------*/
PGM
DCL &DTAQNAME *CHAR 10 VALUE(CVTSDTAQ)
DCL &DTAQLIB *CHAR 10 VALUE(*LIBL)
DCL &ENTLEN *DEC 5 VALUE(128)
DCL &ENTRY *CHAR 128
DCL &WAIT *DEC 5 VALUE(300)
DCL &ENDSTS *CHAR 1
DCL &SPLFIL *CHAR 10
DCL &JOBNAM *CHAR 10
DCL &JOBUSR *CHAR 10
DCL &JOBNBR *CHAR 6
DCL &SPLNBRB *CHAR 4 /* BINARY */
DCL &SPLNBRD *DEC 6 /* DECIMAL */
DCL &SPLNBR *CHAR 6 /* CHARACTER */
DCL &OUTQN *CHAR 10
DCL &OUTQL *CHAR 10
DCL &USRDTA *CHAR 10
/* ----------------------------------------------------------------- */
/* RECEIVE AN ENTRY FROM THE DTAQ (FIRST IN FIRST OUT) */
/* ----------------------------------------------------------------- */
RCVDTAQ: CALL PGM(QRCVDTAQ) PARM(&DTAQNAME &DTAQLIB +
&ENTLEN &ENTRY &WAIT)
/* ----------------------------------------------------------------- */
/* CHECK IF AN ENTRY WAS RECEIVE OR TIMEOUT */
/* ----------------------------------------------------------------- */
IF COND(&ENTLEN *EQ 0) THEN(GOTO CMDLBL(TIMEOUT))
/* ----------------------------------------------------------------- */
/* CHECK IF THE ENTRY RECEIVE IS THE "STOP" COMMAND */
/* ----------------------------------------------------------------- */
IF COND(%SST(&ENTRY 1 4) *EQ 'STOP') THEN(GOTO +
CMDLBL(END))
/* ----------------------------------------------------------------- */
/* READ THE FIELD FROM THE RECEIVE ENTRY */
/* ----------------------------------------------------------------- */
CHGVAR &JOBNAM VALUE(%SST(&ENTRY 13 10))
CHGVAR &JOBUSR VALUE(%SST(&ENTRY 23 10))
CHGVAR &JOBNBR VALUE(%SST(&ENTRY 33 6))
CHGVAR &SPLFIL VALUE(%SST(&ENTRY 39 10))
CHGVAR &SPLNBRB VALUE(%SST(&ENTRY 49 4))
CHGVAR &SPLNBRD VALUE(%BIN(&SPLNBRB))
CHGVAR &SPLNBR &SPLNBRD
/* ----------------------------------------------------------------- */
/* CALL PROGRAM CVTSPL TO WORK WITH THE SPOOL */
/* 您需要依自己的需求自行撰寫 CVTSPL */
/* 於 CVTSPL 中可以 CPYSPLF Copy spooled file TO DB */
/* 並 CPYTOSTMF Copy to Stream File */
/* ----------------------------------------------------------------- */
CALL PGM(CVTSPL) PARM(&ENTRY &OUTQN &OUTQL +
&USRDTA)
/* ----------------------------------------------------------------- */
/* Move or Delete the spool file */
/* ----------------------------------------------------------------- */
IF COND(&OUTQN *EQ '*DELETE') THEN(DLTSPLF +
FILE(&SPLFIL) +
JOB(&JOBNBR/&JOBUSR/&JOBNAM) +
SPLNBR(&SPLNBR) SELECT(*ALL))
ELSE CMD(CHGSPLFA FILE(&SPLFIL) +
JOB(&JOBNBR/&JOBUSR/&JOBNAM) +
SPLNBR(&SPLNBR) SELECT(*ALL) +
OUTQ(&OUTQL/&OUTQN) USRDTA(&USRDTA))
/* ----------------------------------------------------------------- */
/* GO READ NEXT ENTRY IN THE DTAQ */
/* ----------------------------------------------------------------- */
GOTO CMDLBL(RCVDTAQ)
/* ----------------------------------------------------------------- */
/* TIME OUT (CHECK IF THE JOB MUST END) */
/* ----------------------------------------------------------------- */
TIMEOUT: RTVJOBA ENDSTS(&ENDSTS)
IF COND(&ENDSTS *EQ '1') THEN(GOTO CMDLBL(END))
ELSE CMD(GOTO CMDLBL(RCVDTAQ))
GOTO CMDLBL(RCVDTAQ)
/* ----------------------------------------------------------------- */
/* ERROR HANDLING */
/* */
/* ----------------------------------------------------------------- */
ERROR:
GOTO CMDLBL(RCVDTAQ)
END: ENDPGM
新增 OS/400 的目錄分享指令範例
使用範例:
分享 OS/400 CD Drive 給 Windows 使用者
ADDSHARE SHARENAME(AS400CD) PATHNAME('/QOPT') TEXTDESC('AS400 CD DRIVER')
-----------------------------------------------------------------------
CMD Creation
CRTCMD CMD(yourlib/ADDSHARE) PGM(yourlib/ADDSHARE) +
SRCFILE(yourlib/yourPFSourceFile) SRCMBR(ADDSHARECM)
-----------------------------------------------------------------------
ADDSHARECM.CMD Source
CMD
PARM KWD(SHARENAME) TYPE(*CHAR) LEN(12) +
CHOICE('New Share Name (MAX:12 chars)') +
PMTCTL(*PMTRQS) PROMPT('Share Name')
PARM KWD(PATHNAME) TYPE(*CHAR) LEN(20) +
CHOICE('First char must be slash U/U') +
PMTCTL(*PMTRQS) PROMPT('Share Path') /* +
'First char must be slash U/U' */
PARM KWD(TEXTDESC) TYPE(*CHAR) LEN(50) +
CHOICE('Share Comment') PMTCTL(*PMTRQS) +
PROMPT('Share comment') /* 'Share comment' */
PARM KWD(PERMS) TYPE(*CHAR) LEN(4) RTNVAL(*NO) +
RSTD(*YES) DFT(1) VALUES(1 2) +
CHOICE('Permissions (1: R/O, 2:R/W)') +
PMTCTL(*PMTRQS) PROMPT('Permissons') /* +
'1: READ/ONLY 2:READ/WRITE' */
PARM KWD(MAXUSERS) TYPE(*CHAR) LEN(4) RSTD(*NO) +
DFT(-1) RANGE(-1 255) CHOICE('Max users +
(-1 to 255,-1:NOMAX)') PMTCTL(*PMTRQS) +
PROMPT('Max users')
-----------------------------------------------------------------------
ADDSHARE.CLP Source
/*****************************************************************/
/* */
/* ADD WINDOWS SHARE FOR AS/400 */
/* 21.02.2002 MAB13 */
/*****************************************************************/
PGM PARM(&SHARENAME &PATHNAME &TEXTDESC &PERMS &MAXUSERS)
DCL VAR(&SHARENAME ) TYPE(*CHAR) LEN(12)
DCL VAR(&PATHNAME ) TYPE(*CHAR) LEN(20)
DCL VAR(&PATHNAMEL) TYPE(*CHAR) LEN(4)
DCL VAR(&CCSPATHN) TYPE(*CHAR) LEN(4)
DCL VAR(&TEXTDESC) TYPE(*CHAR) LEN(50)
DCL VAR(&PERMS) TYPE(*CHAR) LEN(4)
DCL VAR(&PERMSP) TYPE(*CHAR) LEN(4)
DCL VAR(&MAXUSERS) TYPE(*CHAR) LEN(4)
DCL VAR(&MAXUSERSP) TYPE(*CHAR) LEN(4)
DCL VAR(&ERRORCODE) TYPE(*CHAR) LEN(255)
DCL &LENGTH *DEC LEN(2) VALUE(20)
DCL &LENGTHC *CHAR LEN(4)
CHGVAR VAR(%BIN(&CCSPATHN)) VALUE(0)
CHGVAR VAR(%BIN(&MAXUSERSP)) VALUE(&MAXUSERS)
CHGVAR VAR(%BIN(&PERMSP)) VALUE(&PERMS)
LOOP:
IF (%SUBSTRING(&PATHNAME &LENGTH 1) *EQ ' ') (DO)
CHGVAR VAR(&LENGTH) VALUE(&LENGTH - 1)
IF (&LENGTH *EQ 0) GOTO CMDLBL(EXIT)
GOTO CMDLBL(LOOP)
ENDDO
CHGVAR VAR(&LENGTHC) VALUE(&LENGTH)
CHGVAR VAR(%BIN(&PATHNAMEL)) VALUE(&LENGTHC)
CALL PGM(QZLSADFS) +
PARM(&SHARENAME +
&PATHNAME +
&PATHNAMEL +
&CCSPATHN +
&TEXTDESC +
&PERMSP +
&MAXUSERS +
&ERRORCODE)
IF (&ERRORCODE *NE '*') +
SNDPGMMSG MSG('ERROR CODE:' *CAT &ERRORCODE)
ELSE SNDPGMMSG MSG('SHARED RESOURCES SUCCESSFULY ADDED')
EXIT:
ENDPGM
-----------------------------------------------------------------------
Add File Server Share (QZLSADFS) API Parameters
Required Parameter Group:
1 Share name Input CHAR(12)
2 Path name Input CHAR(*)
3 Length of path name Input BINARY(4)
4 CCSID encoding of path name Input BINARY(4)
5 Text description Input CHAR(50)
6 Permissions Input BINARY(4)
7 Maximum users Input BINARY(4)
8 Error code I/O CHAR(*)
-----------------------------------------------------------------------
API Error Messages
CPF3C1E E Required parameter &1 omitted.
CPF3C36 E Number of parameters, &1, entered for this API was not valid.
CPF3CF1 E Error code parameter not valid.
CPF3CF2 E Error(s) occurred during running of &1 API.
CPFA0D4 E File system error occurred.
CPFB682 E API &1 failed with reason code &2.
CPFB683 E Data conversion failed for API &1.
CPFB684 E User does not have the correct authority for API &1.
CPFB68A E Error occurred while working with shared resource &2.
CPFB68B E Character is not valid for value &3.
CPFB68D E Length specified in parameter &2 for API &1 not valid.
CPFB693 E Data conversion failed for &5 API.
CPIB685 E Error occurred on AS/400 Support for Windows Network Neighborhood (AS/400 NetServer) request.
更詳細資訊請參照手冊 OS/400 Printer Device Programming V4R4
http://publib.boulder.ibm.com/cgi-bin/bookmgr/books/qb3auj03/COVER
AS/400 印表機相關列印的手冊
http://www.printers.ibm.com/R5PSC.NSF/Web/4man
訂閱:
文章 (Atom)