True, VMFTP must run in the VMTFTP environment, not the COMMAND (or CMS, or 
XEDIT, etc.) environment.

I usually write a "whatever EXEC", that does some setup work, and which then 
calls a rexx "whatever VMFTP" macro.  I suppose it could all be done in one 
EXEC, just by changing the addressing environment to VMFTP, but I started that 
pattern a long time ago.

The following is a console snippet from running the FTPFMZOS EXEC (which calls 
FTPFMZOS VMFTP).  It FTPs a file from one of our z/OS systems with no fuss or 
muss.  I do have a "NETRC DATA A0" file with my z/OS ID and password therein.  
If there was no "NETRC DATA" file, it would prompt for the password.

---<snip>---
ftpfmzos @02663 'SYS1.PROCLIB(AVM)' AVM PROC A  (OLDD
331 Send password please.
250 The working directory "SYS1.PROCLIB" is a partitioned data set

Target output location...
Label  Vdev M  Stat Cylinders Used    Files   Ownerid  Addr Rdev Volser LblType
M2W191 0191 A   R/W   150 CYL  63%     2320 = M2WALTER 0191 09F6 VMPP09 CMS1

200 Port request OK.
125 Sending data set SYS1.PROCLIB(AVM) FIXrecfm 80
250 Transfer completed successfully.
162 bytes transferred in 0.016 seconds. Transfer rate 10.12 Kbytes/sec.
Ready;
---<snip>---

The FTPFMZOS EXEC and VMFTP macro are pasted below my signature as examples of 
using VMFTP.

Mike Walter
Aon Corporation
The opinions expressed herein are mine alone, not my employer's.


/* Prolog; See Epilog for additional information ********************
 * Exec Name     - FTPFMZOS EXEC                                    *
 * Unit Support  - MF S&D                                           *
 * Status        - Version 1, Release 2.0                           *
 ********************************************************************/

   address COMMAND
   parse source xos xct xfn xft xfm xcmd xenvir .
   parse upper arg parms 1 operands '(' options ')' parmrest

   If parms='?' | parms='' then Signal Explain

   parse var parms w1 w2 rest
   parse var w2 w2c1 2 restw2
   parse value reverse(restw2) with w2clast 2 .
   If w2c1="'" & w2clast="'" then
      Do /* For: FTPFMZOS @nnnnn 'gdg.dsn(0)' ofn.oft.ofm (options  */
        parse var rest oprest '(' options ')' parmrest
        operands=w1 w2 oprest
      End


  'VMFTP' xfn '(NOPSWD PARM' parms
   Call Exit rc


/********************************************************************/
/*                   Sub-Routines below this point                  */
/********************************************************************/

Exit:
   parse arg exitrc .
   If verify(exitrc,'-0123456789')=0 then Exit exitrc
                                     else Exit 999999

Error:
   say '+++ "ERROR" error routine entered in:' xfn xft xfm', rc='rc
   say '+++ from line:' sigl', which reads:'
   say '+++'sourceline(sigl)
Call Exit 20


Syntax:
   say '+++ "SYNTAX" error routine entered in:' xfn xft xfm', rc='rc
   say '+++ from line:' sigl', which reads:'
   say '+++'sourceline(sigl)
Call Exit 20


NoValue:
   say '+++ "NoValue" error routine entered in:' xfn xft xfm', rc='rc
   say '+++ from line:' sigl', which reads:'
   say '+++'sourceline(sigl)
   say '+++ Variable with no value is:' condition('Description') Call Exit 24


Explain:
   address 'COMMAND'
  'PIPE (NAME Explain)' ,
     '| <' xfn xft xfm ,
     '| INSIDE /ExplainBegin;/ /ExplainEnd;/' ,
     '| PREFACE STRLITERAL /'xfn xft xfm 'help.../' ,
     '| CONSOLE'
   Call Exit 0
/*
ExplainBegin;

FTPFMZOS opens an FTP session with the hard-coded remote FTP server, and 'GET's 
a sequential, or partitioned (PDS) dataset (one or all members).


>-FTPFMSOZ--@mvs_userid--+-dsn-----------+------------------------------
>>
                         +-pds(mbr_name)-+
                         +-pds(*)--------+



                  +-FTPXFER-+
>>--+-outfn----+--+-outft---+--+-outfm-+--(--+---------+--+---------+--<
>>--+-outfn----+--+-outft---+--+-outfm-+>
    +-=--------+  +-=-------+                +-REPlace-+  +-OLDDate-+
    +-*--------+  +-*-------+


Operands:
=========

dsn            A z/OS dataset name as would be entered from TSO (i.e.
               prefixed with your TSO userid unless enclosed in quotes).

mbr_name       A single member to be copied from a given PDS.

*              ALL members will be copied from the PDS.

outfn          Output filename.
=              The '=' and '*' indicate to use the defaults listed below.
*              For a sequential dataset, the output filename defaults
               to the first index of the dataset (before the 1st '.').
               DEFAULT: for a sequential dataset, the first index (the
                        string before the first '.').
               DEFAULT: for a "PDS", the member name (even if '*' was
                        given to copy all members).



outft          Output filetype.
=              The '=' and '*' are "place holders" should you not want to
*              provide specific filetype, but want provide a filemode.
               DEFAULT='FTPXFER'

outfm          Output filemode at which to write the file(s).
               DEFAULT='A'.

Options:
========
REPlace        Causes the file localfile to be overwritten if the file
               already exists.  If the localfile already exists and you
               do not use the REPLACE option, the GET subcommand does
               does not overwrite the existing file and displays a
               message that a file with that name already exists.

OLDDate        Sets the date and time of the gotten file as:
               - For sequential datasets, date set to LAST REFERENCE
                 date, time set to 00:00:00
               - For PDS members, date and time set to LAST UPDATE
                 date and time as stored in the PDS by ISPF.

Examples:
=========

ftpfmzos @nnnnn 'app.T.sequential' app sequential a    ( repl

ftpfmzos @nnnnn 'some.bigpds(ambr)' = * q ( replace

ftpfmzos @nnnnn 'some.bigpds(*)' * * q ( replace

ftpfmzos @nnnnn 'some.gdg(0)' ( replace

ftpfmzos @nnnnn 'some.gdg(-1)'

ftpfmzos @nnnnn  my.tso.file

Hint: If you receive a message that "@nnnnn.dsn" was not found, and the dsn 
indeed is not your own, you will need to place single-quotes around the mvsdsn 
in the command.

FTPFMZOS EXEC calls an FTPFMZOS VMFTP macro, which is processed by the VMFTP 
MODULE.  VMFTP is a public-domain utility to script FTP processing.

ExplainEnd; */
/* Epilog ***********************************************************
 * Function      - See 'Explain:' subroutine above.                 *
 * Component of  - FTP at Hewitt Associates                         *
 * Command format- See 'Explain:' subroutine above.                 *
 * Called by     - Users or EXECs.                                  *
 * Dependencies  - VMFTP MODULE                                     *
 *                (from http://ukcc.uky.edu/~tools.1997/)           *
 *               - FTPFMZOS VMFTP (macro)                           *
 * Program Lang. - CMS REXX                                         *
 * Date Written  - 20060105                                         *
 * Author        - Michael R. Walter                                *
 * Changed  | By | Description of Change                            *
 * ---------+----+------------------------------------------------- *
 * 20070402  mrw - Properly handle GDGs in quotes                   *
 *                                                                  *
 ********************************************************************/









/* Prolog; See Epilog for additional information ********************
 * Exec Name     - FTPFMZOS VMFTP                                   *
 * Unit Support  - MF S&D                                           *
 * Status        - Version 1, Release 1.0                           *
 ********************************************************************/

   address 'COMMAND'
   parse source xos xct xfn xft xfm xcmd xenvir .

   /* ------------------------------------------------------------- */
   /* Since the DSN may be a PDS containing parens, the standard    */
   /* parse upper arg operands '(' options ')' parmrest will fail.  */
   /* ------------------------------------------------------------- */
   parse upper arg parms 1 mvsid dsn rest   /* Get dsn, even if pds */
   parse var rest operands '(' options ')' parmrest     /* Get rest */
   operands=mvsid dsn operands              /* Build std operands   */

   parse var operands  mvsid dsn outfn outft outfm error

   hi='1DE8'x                               /* 3270 Hilite Char     */
   lo='1D60'x                               /* 3270 Default Char    */

   Signal ON Syntax
   Signal ON NoValue
  /* Signal ON ERROR */

                                  /* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
   remotesys='MVS-SYSB'           /* <<--- Update for local stds !! */
                                  /* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */

   If mvsid='?' | mvsid='' then Signal Explain
   If error<>'' then
      Do
        say xfn'; Extraneous operand(s) found: "'error'"'
        say 'For more help, enter: VMFTP' xfn '(PARM ?'
        Call Exit 20
      End

   parse upper var options wkopts

   ?olddate=0
   replace=''
   Do while wkopts<>''
      parse var wkopts opt wkopts                   /* Get next opt */
      Select
        When abbrev('OLDDATE',opt,4) then ?olddate=1
        When abbrev('REPLACE',opt,3) then replace='( REPLACE'
        Otherwise say 'Unsupported option ignored: "'opt'".'
      End
   End

  'STATE NETRC DATA A'
   ?netrc=(rc=0)

  'STATE QOWNER EXEC *'
   ?qowner=(rc=0)

   address COMMAND ,
     'PIPE COMMAND QUERY DISK' outfm ,        /* Target an SFS dir? */
        '| TAKE LAST 1' ,
        '| PICK W2 == /DIR/' ,                /* Yes                */
        '| COUNT LINES' ,
        '| VAR ?outdir'            /* Set binary true|false flag    */

   /* ------------------------------------------------------------- */
   address 'VMFTP'           /* The default VMFTP macro environment */
   /* ------------------------------------------------------------- */

   /* "Emit" sub-routine syntax:                       */
   /*                                                  */
   /* >>--command string--+---------+--+---------+-->< */
   /*                     +-,OK_RCs-+  +-,'TYPE'-+     */
   If ?netrc then
      Do
        Call Emit 'OPEN' remotesys,230
      End
   Else
      Do
        say 'Enter MVS Password at the prompt.'
        Call Emit 'OPEN' remotesys,220,'TYPE'
        say 'If you have trouble entering your password, enter: QUIT'
        Call Emit mvsid,230,'TYPE'
      End

   /* Prepare for File Transfer */
   Call Emit 'TYPE E',200                        /* Type= EBCDIC    */
   Call Emit 'MODE S',200                        /* Mode= Streaming */

   /* ------------------------------------------------------------- */
   /* Get DCB specs, date/time, etc.                                */
   /* ------------------------------------------------------------- */

   parse var dsn listdsn '('mbr')' quote?   /* Handle PDS or GDG    */
   listdsn=listdsn||quote?                  /* Handle 'SOME.GDG(0)' */

   Call Emit 'LIST' listdsn,250     /* Get DSORG, last update dt/tm */
   /* Sample LIST command "output." stem results...
      200 Port request OK.
      125 List started OK
      Volume Unit    Referred Ext Used Recfm Lrecl BlkSz Dsorg Dsname
      PRD288 3390   2006/01/05  2  135  FB      80 27920  PS  
'OS.P.CCT.PCTNEW.CSECT.G
      6252V00'
      250 List completed successfully.
   */

   address 'COMMAND' ,
  'PIPE (NAME ParseDsorgDateTime)' ,
     '| STEM output.' ,
     '| STRIP LEADING' ,
     '| INSIDE /Volume/ /250/' ,                        /* Keep DCB */
     '| TAKE 1' ,
     '| VAR listdsninfo'
   parse var listdsninfo . . RefDate . . recfm lrecl . dsorg .
   parse var RefDate yyyy'/'mm'/'dd
   RefDate=mm'/'dd'/'yyyy                             /* DMSPLU fmt */

   /* ------------------------------------------------------------- */
   /* Could it be a GDG?                                            */
   /* ------------------------------------------------------------- */
   Call Emit 'LIST' listdsn,250     /* Get DSORG, last update dt/tm */
   /* Sample LIST command "output." stem results...
      200 Port request OK.
      125 List started OK
      Volume Unit    Referred Ext Used Recfm Lrecl BlkSz Dsorg Dsname
      GDG  'OS.P.CCT.PCTNEW.CSECT'
      250 List completed successfully.
   */

   address 'COMMAND' ,
  'PIPE (NAME ParseDsorgDateTime)' ,
     '| STEM output.' ,
     '| STRIP LEADING' ,
     '| INSIDE /Volume/ /250/' ,                        /* Keep DCB */
     '| TAKE 1' ,
     '| VAR listdsninfo'
   parse var listdsninfo w1 w2 rest
   ?gdg=(w1='GDG')

   /* ------------------------------------------------------------- */
   /* Handle different DSorgs.                                      */
   /* ------------------------------------------------------------- */
   ?pds=(dsorg='PO')
   ?gdg=(dsorg='GDG')

   If \?pds then
      Select
        When outfn=''  then parse var dsn outfn "."
        When outfn='*' then parse var dsn outfn '.'
        When outfn='=' then parse var dsn outfn '.'
        Otherwise nop
      End
   outfn=strip(outfn,"L","'")

   Select
     When outft=''  then outft='FTPXFER'
     When outft='*' then outft='FTPXFER'
     When outft='=' then outft='FTPXFER'
     Otherwise nop
   End

   If outfm='' then outfm='A'

   If ?pds
      then Call PDS
      else Call SequentialDSN

   Call Emit 'QUIT'

   address 'COMMAND'                 /* Done with VMFTP environment */

Call Exit 0


/********************************************************************/
/*                   Sub-Routines below this point                  */
/********************************************************************/

Emit:

   cmd   = arg(1)
   okrcs = arg(2)
   disp  = arg(3)
   parse var cmd subcmd subcmdargs

   trace o
      cmd                                   /* Issue FTP subcommand */
      src=rc                                /* Save subcmd rc       */
   trace
   If src=-3 then
      Do
        If subcmd='open' then
           Do
             say hi
             say 'Connection failed to:' subcmdargs
             parse upper var subcmdargs . '-'targetsys'.' .
             say 'Check "System Status" to see if "'targetsys'"' ,
                 'is available.' lo
           End
        Else
           Do
             say hi
             say '"'cmd'" failed with rc-3.'
             say 'This usually indicates a failure of the network' ,
                 'connection.'
           End
        Call Exit src
      End /* rc=-3 */


   If disp='TYPE' then
      If subcmd='put'      /* Don't bother them with SITE/Port msgs */
         then address 'COMMAND' ,
              'PIPE (NAME StripSiteAndPort)' ,
                 '| STEM output.' ,
                 '| STRNLOCATE /200 SITE command was accepted/' ,
                 '| STRNLOCATE /200 Port request OK./' ,
                 '| CONSOLE'
         else
              address 'COMMAND' 'PIPE STEM output. | CONSOLE'

   If okrcs='' then Return
   If wordpos(src,okrcs)>0 then Return

   address 'COMMAND'            /* This FTP session is toast anyway */
   say hi
   say xfn'; FTP Command: "'cmd'" rc='src 'not expected.'

   say output.0 'lines returned:'
  'PIPE STEM output. | CONSOLE'
   say lo

   If cmd='GET' & rc=226 then
      say '+++ Output filemode "'outfm'" is full.'

   Call Exit src
Return /* Doc only */


PDS:
   Call Emit 'CWD' listdsn ,250,'TYPE'            /* Set, /show DSN */

   Call Emit 'DIR',250                           /* Get mbr list    */
   /* Sample DIR command "output." stem results...
     200 Port request OK.
     125 List started OK
      Name     VV.MM   Created       Changed      Size  Init Mod   Id
     mbrname1  01.45 1994/08/22 2003/01/30 09:01   147   100   0 mvsid1
     mbrnamen  01.07 1993/08/25 2003/01/10 18:12   136   136   0 mvsid1
     250 List completed successfully.
   */
   Call TargetDisplay

   parse var dsn . '('mbr')' .
   address 'COMMAND' ,
  'PIPE (NAME KeepAllMbrDtls)' ,
     '| STEM output.' ,
     '| STRIP LEADING' ,
     '| INSIDE /Name/ /250/' ,                   /* Keep only mbrs  */
     '| STEM dir.'

   If mbr<>'' & mbr<>'*' then
      Do                   /* Just get the single, specified member */
        If outfn='' | outfn='=' then outfn=mbr
        address 'COMMAND' 'STATEW' outfn outft outfm
        If rc=0 & replace='' then
           Do
             say hi'Output file "'outfn outft outfm'" already' ,
                   'exists. Use REPLACE option.'lo
             Call Exit 28
           End
        Call Emit 'GET' mbr outfn'.'outft'.'outfm ,
                        replace,129 230 250,'TYPE' /* Get or errmsg */
        If ?olddate then
           Do
             address 'COMMAND' ,
            'PIPE (NAME PickOneMbrDtls)' ,
               '| STEM dir.' ,
               '| PICK WORD1 == /'mbr'/' ,
               '| TAKE 1' ,
               '| VAR pdsdtl'
             parse var pdsdtl mbr vvmm crtdt chgdt chgtm ,
                              recs init mod id .
             parse var chgdt yyyy'/'mm'/'dd .
             address 'COMMAND' ,
            'DMSPLU' outfn outft outfm ,
                     mm'/'dd'/'yyyy chgtm':00'       /* Set OLDDATE */
           End /* Olddate */
      End                  /* Just get the single, specified member */
   Else
      Do                   /* Get ALL members from specified DSN    */
        Do ix=1 to dir.0 /* All members */
           parse var dir.ix mbr vvmm crtdt chgdt chgtm ,
                            recs init mod id .
           address 'COMMAND' 'STATEW' mbr outft outfm
           If rc=0 & replace='' then
              Do
                say hi'Output file "'mbr outft outfm'" already' ,
                      'exists. Use REPLACE option.'lo
                Call Exit 28
              End
           If (ix%25)=(ix/25) | (ix=1) then              /* P.U.F. */
              say 'GETting member' ix 'of' dir.0 'members.'

           Call Emit 'GET' mbr mbr'.'outft'.'outfm ,
                           replace ,129 230 250
           If ?olddate then
              Do
                parse var chgdt yyyy'/'mm'/'dd .
                address 'COMMAND' ,
               'DMSPLU' mbr outft outfm ,
                        mm'/'dd'/'yyyy chgtm':00'     /*Set OLDDATE*/
              End /* Olddate */
        End /* All members */
        say ix-1 'members retrieved.'
      End                  /* Get ALL members from specified DSN    */
Return


SequentialDSN:

   Call Emit 'LIST' dsn,250,'TYPE'               /* Set/show DSN    */
   address 'COMMAND' 'STATEW' outfn outft outfm
   If rc=0 & replace='' then
      Do
        say hi'Output file "'outfn outft outfm'" already' ,
              'exists. Use REPLACE option.'lo
        Call Exit 28
      End


   Call TargetDisplay

   Call Emit 'GET' dsn outfn'.'outft'.'outfm ,
                   replace,129 230 250,'TYPE'

   If ?olddate then
       Do  /* Olddate */
         address 'COMMAND' ,
            'DMSPLU' outfn outft outfm ,
                     RefDate '00:00:00'   /* Set RefDate as OLDDATE */
         say hi
         say 'Warning: OLDDATE for sequential dataset has been set' ,
             'to'

         say '         the MOST RECENT REFERENCE DATE ('RefDate')' ,
             'and TIME=00:00:00.'
         say 'The z/OS FTP server does not return the most recent' ,
             'dataset UPDATE date and time.' lo
       End /* Olddate */
Return


TargetDisplay:
   say
   say 'Target output location...'
   If ?qowner then
      address COMMAND 'EXEC QOWNER' outfm     /* Best info          */
   Else
       Do                                     /* Some info          */
         If ?dir then address COMMAND 'QUERY ACCESSED' outfm
                 else address COMMAND 'QUERY DISK'     outfm
       End
   say
Return


Exit:
   parse arg exitrc .
   If verify(exitrc,'-0123456789')=0 then Exit exitrc
                                     else Exit 999999

Error:
   say '+++ "ERROR" error routine entered in:' xfn xft xfm', rc='rc
   say '+++ from line:' sigl', which reads:'
   say '+++'sourceline(sigl)
Call Exit 20


Syntax:
   say '+++ "SYNTAX" error routine entered in:' xfn xft xfm', rc='rc
   say '+++ from line:' sigl', which reads:'
   say '+++'sourceline(sigl)
Call Exit 20


NoValue:
   say '+++ "NoValue" error routine entered in:' xfn xft xfm', rc='rc
   say '+++ from line:' sigl', which reads:'
   say '+++'sourceline(sigl)
   say '+++ Variable with no value is:' condition('Description') Call Exit 24


Explain:
   address 'COMMAND'
  'PIPE (NAME Explain)' ,
     '| <' xfn xft xfm ,
     '| INSIDE /ExplainBegin;/ /ExplainEnd;/' ,
     '| PREFACE STRLITERAL /'xfn xft xfm 'help.../' ,
     '| CONSOLE'
   Call Exit 0
/*
ExplainBegin;

For help with FTPFMZOS VMFTP, enter: EXEC FTPFMZOS ?

ExplaineEnd; */
/* This help can be displayed once VMFTP is installed by entering:
   vmftp ftpfmzos  (parm ?
*/
/* Epilog ***********************************************************
 * Function      - See 'Explain:' subroutine above.                 *
 * Component of  - System Programmers Toolbox.                      *
 * Command format- See 'Explain:' subroutine above.                 *
 * Called by     - Users or EXECs.                                  *
 * Dependencies  - VMFTP MODULE                                     *
 *                (http://zvm.sru.edu/~DOWNLOAD/LOAD )              *
 *                 Optional: QOWNER EXEC                            *
 * Program Lang. - CMS REXX                                         *
 * Date Written  - 20060105                                         *
 * Author        - Michael R. Walter                                *
 * Changed  | By | Description of Change                            *
 * ---------+----+------------------------------------------------- *
 * 20060113  mrw - Correct LIST to use 'listdsn'                    *
 * 20090722  mrw - Accept any filemode number for NETRC DATA until  *
 *                 we can begn using certificates.                  *
 * 20110826  mrw - Provide alternative to "QOWNER EXEC".            *
 *                                                                  *
 ********************************************************************/


-----Original Message-----
From: CMSTSO Pipelines Discussion List [mailto:[email protected]] On 
Behalf Of John P. Hartmann
Sent: Friday, August 26, 2011 10:20 AM
To: [email protected]
Subject: Re: FTP user exit, ultimately a PIPE stage?

Mike, it's been a while. Could well be VMFTP.  It had problems running
under COMMAND, as you can well imagine.  I never used it other than
make a test case to ensure it worked.

Reply via email to