Ahhhh... Back from vacation and wading through email...
To follow-up on the empty file topic, I use EXECIO when I know for sure it
is a sequential file (or member of a PDS). I use the PRINT COUNT(1) technique
when I write utilities that can accept either SEQ or VSAM. Here is some
logic that handles SEQ and VSAM and deals with an empty file that contains a
"seed" record or a known number of "header" records.
/* rexx */
arg dsn count
if count = '' then count = 0
count = count + 1
dsn = strip(dsn,"B","'")
"ALLOC F(EMPTY) DA('"dsn"') SHR REUSE"
call outtrap 'msgs.'
"PRINT INFILE(EMPTY) COUNT("count")"
PRC = RC
select
when PRC = 0 then exit 0
when PRC = 4 then
do
if count > 1 then
do
count = count - 1
"PRINT INFILE(EMPTY) COUNT("count")"
if RC = 0 then
exit 1
end
else
exit 2
end
otherwise
do
do i=1 to msgs.0
select
when pos('RETURN CODE IS 160',msgs.i) <> 0 then
exit 2
otherwise nop
end
end
exit PRC
end
end
"FREE F(EMPTY)"
Here are some quick and dirty examples of using FTP from REXX (forground or
background). There are at least 3 approaches to this (that I know of). The
traditional QUEUE approach, the ALLOCATE INPUT OUTPUT approach and the new
FTP REXX API that appears with z/OS 1.8. All are very well documented in the
manuals with usable examples. If you don't think so, here are a couple more
examples.
FTP EXEC Interface
_http://publibz.boulder.ibm.com/cgi-bin/bookmgr_OS390/BOOKS/F1A1B960/4.10?SHEL
F=F1A1BK81&DT=20060622162500_
(http://publibz.boulder.ibm.com/cgi-bin/bookmgr_OS390/BOOKS/F1A1B960/4.10?SHELF=F1A1BK81&DT=20060622162500)
FTP REXX API
_http://publibz.boulder.ibm.com/cgi-bin/bookmgr_OS390/BOOKS/f1a1d360/12.10?SHE
LF=F1A1BK81.bks&DT=20060622161331#HDRWQ450_
(http://publibz.boulder.ibm.com/cgi-bin/bookmgr_OS390/BOOKS/f1a1d360/12.10?SHELF=F1A1BK81.bks&DT=20060622161331#
HDRWQ450)
In all examples the UserID and Password can be placed in a NETRC DD
pre-allocated to the session or in the EXEC. In batch adding a NETRC DD does the
same thing. NETRC avoids typing in the Userid and Password details and allows
you to create a secure DSN/PDS with these sensitive pieces of information.
This is also well documented in the manuals. While the NETRC approach does
avoid the Userid Password issue for the user, it does not solve the traditional
FTP security issue of unencrypted passwords flying across the wire. Look at
SFTP for that.
NETRC
_http://publibz.boulder.ibm.com/cgi-bin/bookmgr_OS390/BOOKS/f1a1b960/10.2?SHEL
F=F1A1BK81&DT=20060622162500_
(http://publibz.boulder.ibm.com/cgi-bin/bookmgr_OS390/BOOKS/f1a1b960/10.2?SHELF=F1A1BK81&DT=20060622162500)
Always use the "(EXIT" option with FTP. This causes FTP to return a REAL
return code. The return codes also are well documented.
_http://publibz.boulder.ibm.com/cgi-bin/bookmgr_OS390/BOOKS/f1a1b960/4.11?SHEL
F=F1A1BK81&DT=20060622162500_
(http://publibz.boulder.ibm.com/cgi-bin/bookmgr_OS390/BOOKS/f1a1b960/4.11?SHELF=F1A1BK81&DT=20060622162500)
Obviously, it can be extremely valuable knowing what happened and can save
time. This can also allow you to perform some recovery actions in REXX when
possible.
Here are some quick and dirty FTP examples (sorry if the indenting gets lost
during transmission):
The traditional QUEUE approach. Simply QUEUE the FTP subcommands and
execute FTP
arg uid pw dsn file ipaddr
queue uid pw
dsn = "'"strip(dsn,"B","'")"'"
queue "put" dsn file
queue "quit"
"FTP" ipaddr "(EXIT"
say RC
Loading subcommands from an INPUT DD (no OUTPUT DD)
arg uid pw dsn file ipaddr
dsn = "'"strip(dsn,"B","'")"'"
input.1 = uid pw
input.2 = "put" dsn file
input.3 = "quit"
"ALLOC F(INPUT) UNIT(VIO) SPACE(1 1) TRACKS LRECL(80)"
"EXECIO * DISKW INPUT (STEM INPUT. FINIS"
"FTP -i" ipaddr "(EXIT"
say RC
Loading INPUT and interrogating OUTPUT (using a DIR listing in this example)
arg uid pw dsn mem ipaddr
if ipaddr = '' then ipaddr = '127.0.0.1'
input.1 = uid pw
input.2 = "cd '"dsn"'"
input.3 = 'dir'
input.4 = 'QUIT'
"ALLOC F(INPUT) UNIT(VIO) LRECL(80) SPACE(1) TRACKS RECFM(F B)"
"EXECIO * DISKW INPUT (STEM INPUT. FINIS"
"ALLOC F(OUTPUT) UNIT(VIO) LRECL(121) SPACE(1 10) CYLINDERS RECFM(V B)"
"FTP" ipaddr "(EXIT"
if RC <> 0 then exit(RC)
"EXECIO * DISKR OUTPUT (STEM OUTPUT. FINIS"
do i=1 to output.0
parse var output.i msgid dirline
if mem = '' then
do
if msgid = 'EZA2284I' then say dirline
end
else
do
if msgid = 'EZA2284I' & word(dirline,1) = mem then say dirline
end
end
"FREE F(INPUT OUTPUT)"
In production code, you should develop a technique to read/parse the OUTPUT
DD to know what happened. This works very well. I have a standard
subroutine I developed to do this for me whenever I need FTP services in an EXEC.
Aside from the return code, this can tell you in English what happened.
The FTP REXX API has an example in your SYS1.SEZAINST, member name EZAFTPIR.
While the FTP REXX API looks really rich, I have not gotten around to
trying this other than a tailored copy of the example. The example is very
similar to the directory list example above. I stripped out all the extra "stuff"
and reduced all wait times on the IBM example and it still seems to run about
10 times slower than my example above. I'm not passing judgement yet, but
the early experimentation did not provide encouraging results.
TRACEID = 'REZ'
USER_COMMAND = 'user UID'
PASS_COMMAND = 'pass PW'
CD_COMMAND = "cd 'YOUR.PDS'"
DIR_COMMAND = 'dir *'
OPENSTRING = '-w 1 127.0.0.1 21 '
ENVVAR1 = '_CEE_DMPTARG=/tmp'
ENVVAR2 = '_BPX_JOBNAME=MYJOB'
if ftpapi('fcai.', 'create', TRACEID) < 0 then do
Say 'Unable to create the FCAI'
exit -1
end
if ftpapi('fcai.', 'init', OPENSTRING, ENVVAR1, ENVVAR2) < 0 then do
call ftp_error 'fcai.'
end
if ftpapi('fcai.', 'scmd', USER_COMMAND, 'W') < 0 then do
call ftp_error 'fcai.'
end
if fcai.FCAI_Result = FCAI_RESULT_PROMPTPASS then do
if ftpapi('fcai.', 'scmd', PASS_COMMAND, 'W') < 0 then do
call ftp_error 'fcai.'
end
end
if ftpapi('fcai.', 'scmd', CD_COMMAND, 'W') < 0 then do
call ftp_error 'fcai.'
end
if ftpapi('fcai.', 'scmd', DIR_COMMAND, 'W') < 0 then do
call ftp_error 'fcai.'
end
if ftpapi('fcai.', 'getl_copy', 'lines.', 'L') < 0 then do
call ftp_error 'fcai.'
end
say 'Directory output is:'
do i=1 to lines.0
say ' 'lines.i
end
if ftpapi('fcai.', 'scmd', 'QUIT', 'W') < 0 then do
call ftp_error 'fcai.'
end
if ftpapi('fcai.', 'term') < 0 then do
Say "Unexpected error on ftpapi('term')"
exit -1
end
exit
ftp_error: arg stem
say 'FTP Client API Error:'
say ' Result =' value(stem'FCAI_Result')
say ' Status =' value(stem'FCAI_Status')
say ' IE =' value(stem'FCAI_IE')
say ' CEC =' value(stem'FCAI_CEC')
say ' ReturnCode =' value(stem'FCAI_ReturnCode')
say ' ReasonCode =' value(stem'FCAI_ReasonCode')
rc = ftpapi('fcai.', 'term')
exit -1
return
I also have some FTP utilities I have written over the years for various
purposes.
FTPPUT Batch FTP utility supports, SEQ, GDG, PDS, VSAM (REPRO's to
SEQ) and HFS/zFS
@FTPGET ISPF Edit Macro to FTP GET into a member
@FTPPUT ISPF Edit Macro to FTP PUT an Edit session somewhere
Hope this helps,
Rob
In a message dated 10/10/2007 5:13:22 AM US Mountain Standard Time,
***@UNIX.STORTEK.COM writes:
In a recent note, Hamilton, Robert L said:
> Date: Wed, 10 Oct 2007 06:40:22 -0500
>
> I wish FTP was the same as the IDCAMS stuff; Would make FTP a lot easier
to deal with...
>
What are you looking for? A remote version of the IDCAMS "DEFINE ..."
command?
This might be disallowed for security reasons. Anything else?
> Does anyone run FTP from a REXX exec under TSO?
>
I can't find where I've done this. IIRC, I've tried and been confused by
how FTP gets its command stream:
o Under TSO: from GETLINE (TGET? Will it read from Rexx stack?)
o Under shell: from stdin.
o Under batch: from DD INPUT.
But how does it tell? If I run it as "address ATTCHMVS FTP" from TSO or
shell, does that count as batch and read from INPUT? If I run it as
"address TSO FTP" under batch IKJEFT01 or shell, does that count as TSO
and do GETLINE? If I run it as "address SYSCALL spawnp ftp" under
TSO, IKJEFT01, or IRXJCL, does that count as shell and read from stdin?
Etc. I get confused and give up. I believe TFM does little to clarify
this.
-- gil
--
StorageTek
INFORMATION made POWERFUL
----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX
************************************** See what's new at http://www.aol.com
----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to ***@VM.MARIST.EDU with the message: INFO TSO-REXX