z/OS FTP Reference#
Starting FTP from TSO#
FTP hostname
FTP hostname(port)
FTP hostname PORT(2121)
FTP hostname SECURE (* explicit TLS/FTPS *)
FTP hostname VERBOSE (* show all server responses *)
After connecting you are prompted for userid and password. To skip the prompt, use a NETRC file (see below).
Interactive FTP subcommands#
USER userid password (* re-authenticate or initial login *)
CD remotedir (* change remote directory *)
LCD localdsn (* change local dataset HLQ prefix *)
PWD (* print remote working directory *)
DIR [pattern] (* detailed directory/member listing *)
LS [pattern] (* brief listing *)
GET remote local (* download remote file to local dataset *)
PUT local remote (* upload local dataset to remote file *)
MGET pattern (* download multiple files matching pattern *)
MPUT pattern (* upload multiple datasets matching pattern *)
APPEND local remote (* append local data to remote file *)
DELETE remotefile (* delete remote file *)
RENAME old new (* rename remote file *)
MKDIR remotedir (* create remote directory *)
RMDIR remotedir (* remove remote directory *)
QUOTE cmd (* send raw FTP command to server *)
SITE params (* send SITE parameters to remote FTP server *)
PASSIVE (* toggle passive vs active mode *)
STATUS (* show current connection and settings *)
TYPE A (* ASCII transfer mode β EBCDICβASCII translation *)
TYPE B (* BINARY / IMAGE β no translation *)
TYPE E (* EBCDIC β mainframe-to-mainframe, no translation *)
SENDSITE ON|OFF (* auto-send SITE before each transfer *)
SENDPASV ON|OFF (* passive mode toggle *)
LOCSITE params (* set allocation defaults for local receives *)
LRECL nnn (* set local LRECL for incoming transfers *)
BLKSIZE nnn (* set local BLKSIZE for incoming transfers *)
RECFM type (* set local RECFM for incoming transfers *)
BLOCK nnn (* set block count for transfers *)
OPEN hostname (* connect to a new host without restarting FTP *)
CLOSE (* disconnect from current host, stay in FTP *)
QUIT (* disconnect and exit FTP *)
Transfer types#
| Type | Command | Use when |
|---|---|---|
| ASCII | TYPE A | Text files between mainframe and non-mainframe; translates EBCDICβASCII |
| Binary/Image | TYPE B or TYPE I | Load modules, compiled objects, binary data; no translation |
| EBCDIC | TYPE E | Mainframe-to-mainframe text transfers; no translation |
TYPE A (* ASCII β default for most z/OS FTP servers *)
TYPE B (* Binary/Image *)
TYPE E (* EBCDIC *)
Tip: Always set
TYPE Bbefore transferring load libraries, VSAM exports, or any non-text data. Forgetting this is the most common cause of corrupted transfers.
SITE subcommand β z/OS allocation parameters#
SITE passes dataset allocation instructions to the remote z/OS FTP server before PUT/MPUT. These parameters control how the destination dataset is created.
Record format and space:
SITE RECFM=FB LRECL=80 BLKSIZE=27920 SPACE=(TRK,(5,5)) UNIT=SYSDA
SITE RECFM=VB LRECL=255 BLKSIZE=32760 SPACE=(CYL,(1,1))
SITE RECFM=U BLKSIZE=32760 (* load modules *)
SITE RECFM=FB LRECL=133 (* print/report lines *)
Dataset organization:
SITE PDS (* allocate as PDS *)
SITE PDSE (* allocate as PDSE *)
SITE DSNTYPE=LIBRARY (* PDSE via DSNTYPE keyword *)
SITE FILETYPE=SEQ (* sequential dataset β default *)
SITE FILETYPE=JES (* submit to JES / retrieve spool *)
SMS classes:
SITE MGMTCLAS=STANDARD STORCLAS=FAST DATACLAS=FB80
SITE DATACLAS=VB255
SITE STORCLAS=PREMIUM
Space units:
SITE CYLINDERS SPACE=(5,2)
SITE TRACKS SPACE=(100,20)
SITE BLOCKS SPACE=(27920,(100,20))
SITE BLOCKSIZE=0 (* let system determine optimal BLKSIZE *)
Translation and encoding:
SITE XLATE ON (* enable translation table *)
SITE XLATE OFF
SITE ENCODING=IBM-1047 (* specific EBCDIC code page *)
SITE ENCODING=ISO8859-1 (* ASCII code page *)
Multiple parameters on one line:
SITE RECFM=FB LRECL=80 BLKSIZE=27920 SPACE=(TRK,(10,5)) UNIT=SYSDA
SITE RECFM=VB LRECL=255 BLKSIZE=32760 SPACE=(CYL,(2,1)) MGMTCLAS=STANDARD
Dataset naming β quoted vs unquoted#
Quoting dataset names with single quotes forces absolute naming (no prefix appended):
GET 'SYS1.PROCLIB(IEFBR14)' iefbr14.jcl (* explicit absolute name *)
PUT localfile 'MY.TARGET.DATASET' (* absolute β no userid prefix *)
Without quotes the FTP server prepends your TSO prefix (usually userid) as the high-level qualifier:
GET PROCLIB(IEFBR14) (* becomes userid.PROCLIB(IEFBR14) *)
PUT myfile DATA (* becomes userid.DATA *)
PDS member transfers#
Upload to a specific member:
PUT localfile 'MY.PDS.LIB(MEMBER)'
Upload multiple files β member names taken from filename stems:
MPUT *.cbl 'MY.COBOL.SRC(*)'
MPUT *.jcl 'MY.JCL.LIB(*)'
Download all members of a PDS:
CD 'MY.SOURCE.LIB'
DIR (* verify members *)
MGET * (* download all members as separate local files *)
Download one member:
GET 'MY.PDS.LIB(MEMBER)' member.txt
Submitting JCL and retrieving spool via FTP (FILETYPE=JES)#
Switch to JES mode, submit, and retrieve output:
SITE FILETYPE=JES
PUT myjob.jcl (* submit β FTP returns JOBID e.g. JOB00123 *)
DIR (* list your jobs and their status *)
DIR JOB00123 (* list sysout datasets for specific job *)
GET JOB00123.2 output.txt (* retrieve sysout dataset 2 (JESMSGLG, JESJCL, etc.) *)
DELETE JOB00123 (* purge all sysout for this job *)
SITE FILETYPE=SEQ (* switch back to normal sequential mode *)
JES dataset numbers:
| Sysout DD | Meaning |
|---|---|
.1 | JESMSGLG β JES message log |
.2 | JESJCL β expanded JCL |
.3 | JESYSMSG β JES/system messages |
.4+ | Application SYSOUT DD statements in step order |
Batch FTP via JCL#
Standard batch download:
//FTPGET JOB (ACCT),'FTP GET',CLASS=A,MSGCLASS=X
//FTP EXEC PGM=FTP,PARM='remotehost'
//SYSPRINT DD SYSOUT=*
//OUTPUT DD SYSOUT=*
//INPUT DD *
ftpuser
ftppass
TYPE B
GET remotefile 'MY.RECEIVED.DATA'
QUIT
/*
Batch upload with SITE parameters:
//FTPPUT JOB (ACCT),'FTP PUT',CLASS=A,MSGCLASS=X
//FTP EXEC PGM=FTP,PARM='remotehost'
//SYSPRINT DD SYSOUT=*
//OUTPUT DD SYSOUT=*
//INPUT DD *
ftpuser
ftppass
SITE RECFM=FB LRECL=80 BLKSIZE=27920 SPACE=(TRK,(5,5))
PUT 'MY.JCL.LIB(MYJOB)' MYJOB.JCL
QUIT
/*
Batch submit JCL to remote system via JES mode:
//FTPSUBMT JOB (ACCT),'REMOTE SUBMIT',CLASS=A,MSGCLASS=X
//FTP EXEC PGM=FTP,PARM='remotezos'
//SYSPRINT DD SYSOUT=*
//OUTPUT DD SYSOUT=*
//INPUT DD *
ftpuser
ftppass
SITE FILETYPE=JES
PUT 'MY.JCL.LIB(BATCHJOB)'
QUIT
/*
Batch FTP with NETRC auto-login:
//FTPNETRC JOB (ACCT),'FTP NETRC',CLASS=A,MSGCLASS=X
//FTP EXEC PGM=FTP,PARM='remotehost'
//SYSPRINT DD SYSOUT=*
//OUTPUT DD SYSOUT=*
//NETRC DD DSN=MY.NETRC,DISP=SHR
//INPUT DD *
TYPE B
GET remotefile 'MY.RECEIVED.DATA'
QUIT
/*
Multiple transfers in one batch job:
//FTPMULTI JOB (ACCT),'MULTI FTP',CLASS=A,MSGCLASS=X
//FTP EXEC PGM=FTP,PARM='remotehost'
//SYSPRINT DD SYSOUT=*
//OUTPUT DD SYSOUT=*
//INPUT DD *
ftpuser
ftppass
TYPE B
SITE RECFM=FB LRECL=80 BLKSIZE=27920 SPACE=(TRK,(5,5))
PUT 'MY.FIRST.DATA' first.dat
PUT 'MY.SECOND.DATA' second.dat
TYPE A
PUT 'MY.REPORT.DATA' report.txt
QUIT
/*
Specifying a non-default port:
//FTP EXEC PGM=FTP,PARM='remotehost 2121'
FTP.DATA β client configuration#
FTP.DATA (or hlq.FTP.DATA) controls default FTP client settings. Search order at session start:
userid.FTP.DATA(personal)FTP.DATAunder current prefixSYS1.TCPPARMS(FTPDATA)(site-wide default)
Common FTP.DATA keywords:
FTPKEEPALIVE 60 (* send keepalive every 60 seconds *)
DATATYPE ASCII (* default transfer type: ASCII, BINARY, or EBCDIC *)
SENDSITE TRUE (* auto-send SITE params before each transfer *)
PASSIVE FALSE (* use active mode; TRUE for passive *)
SENDPASV FALSE (* do not send PASV by default *)
VERBOSE FALSE (* suppress server response display *)
NODNS TRUE (* use IP addresses only, skip DNS *)
PROXY proxyhost(port) (* FTP proxy *)
AUTOLOCSITE TRUE (* mirror remote SITE params to local *)
SBDATACONN TRUE (* secondary data connection binding *)
LOCSITE RECFM=FB LRECL=80 BLKSIZE=27920 (* default local allocation for GET *)
LOCSITE SPACE=(TRK,(5,5)) UNIT=SYSDA
TLSMECHANISM TLS (* force TLS β see FTPS section *)
SECURE_CTRLCONN PRIVATE (* require encrypted control connection *)
SECURE_DATACONN PRIVATE (* require encrypted data connection *)
NETRC β automatic login#
NETRC (or userid.NETRC) stores credentials for password-free FTP sessions:
MACHINE remotehost LOGIN ftpuser PASSWORD ftppass
MACHINE prod.zos.example.com LOGIN produser PASSWORD s3cr3t
MACHINE default LOGIN anonymous PASSWORD user@example.com
Reference in JCL with //NETRC DD DSN=MY.NETRC,DISP=SHR. Protect this dataset with RACF β it contains cleartext passwords.
FTPS β FTP over TLS (explicit)#
z/OS FTP supports explicit TLS (FTPS). This is not SFTP β it uses standard FTP protocol over a TLS channel.
From TSO:
FTP hostname SECURE
FTP hostname SECURE PORT(990) (* implicit TLS on port 990 *)
In FTP.DATA for always-on TLS:
TLSMECHANISM TLS
SECURE_CTRLCONN PRIVATE
SECURE_DATACONN PRIVATE
In batch JCL:
//FTP EXEC PGM=FTP,PARM='hostname SECURE'
AT-TLS (Application Transparent TLS) can also be configured at the TCP/IP policy level to enforce TLS transparently without application changes β contact your network/security team.
LOCSITE β default allocation for incoming transfers#
LOCSITE sets allocation defaults for datasets created during GET/MGET on the local (z/OS) side. Can be set in FTP.DATA or issued interactively:
LOCSITE RECFM=FB LRECL=80 BLKSIZE=27920 SPACE=(TRK,(5,5))
LOCSITE RECFM=VB LRECL=255 BLKSIZE=32760 SPACE=(CYL,(1,1))
LOCSITE PDSE (* incoming PDS transfers become PDSE *)
LOCSITE UNIT=SYSDA STORCLAS=STANDARD
Common patterns#
Download a single member:
GET 'PROD.PROCLIB(STARTED)' started.proc
Upload and replace a member:
SITE RECFM=FB LRECL=80
PUT deploy.jcl 'MY.JCL.LIB(DEPLOY)'
Transfer between two z/OS systems (EBCDIC, no translation):
TYPE E
GET 'REMOTE.DS' 'LOCAL.DS'
Bulk download from remote directory:
CD /u/myuser/exports
MGET *.csv
Retrieve multiple spool outputs from a batch job:
SITE FILETYPE=JES
DIR JOB00456
GET JOB00456.3 sysmsgs.txt
GET JOB00456.4 sysprint.txt
DELETE JOB00456
SITE FILETYPE=SEQ
Passive mode for firewall-friendly transfers:
PASSIVE
GET remotefile localfile
FTP return codes#
| Range | Meaning |
|---|---|
| 1xx | Positive preliminary β action initiated |
| 2xx | Positive completion β action succeeded |
| 3xx | Positive intermediate β more information needed |
| 4xx | Transient negative β temporary failure, retry may work |
| 5xx | Permanent negative β do not retry without fixing the cause |
Common codes:
| Code | Meaning |
|---|---|
| 125 | Data connection open, transfer starting |
| 150 | File status OK, opening data connection |
| 200 | Command OK |
| 220 | Service ready (server greeting) |
| 226 | Transfer complete, closing data connection |
| 230 | User logged in |
| 250 | Requested action OK |
| 257 | Pathname created |
| 331 | Username OK, password required |
| 425 | Canβt open data connection |
| 426 | Connection closed, transfer aborted |
| 500 | Syntax error / command unrecognized |
| 501 | Syntax error in parameters |
| 530 | Not logged in / authentication failed |
| 550 | File unavailable β not found, no RACF access, or wrong filetype |
| 553 | File name not allowed |
Troubleshooting#
| Symptom | Likely cause | Fix |
|---|---|---|
425 Can't open data connection | Firewall blocking data port | Issue PASSIVE command or open FTP data port range |
| Garbled text after transfer | Wrong transfer type | Use TYPE A for text, TYPE B for binary |
| Dataset not found (550) | Missing quotes on absolute name | Add single quotes around fully qualified names |
| Userid prefix appended unexpectedly | Unquoted dataset name | Quote the dataset name: 'SYS1.PROCLIB' |
| ABEND in batch FTP | Server-side or allocation error | Check SYSPRINT for response codes and messages |
| Permission denied (550) | RACF access denied | Verify dataset profile and userid permissions |
| TLS handshake failure | Certificate not trusted | Check AT-TLS policy; may need to add server cert to keyring |
| Transfer complete but data wrong | Binary file sent as ASCII | Re-transfer with TYPE B |
| Member truncated | Wrong LRECL | Use SITE LRECL=nnn matching source LRECL |
| Batch job gets RC 12 | FTP authentication or allocation failure | Check SYSPRINT OUTPUT for 4xx/5xx response codes |