Tracing encrypted data to z/OS

I had blogged Collecting a wire-shark trace with TLS active for a browser where you could specify an environment variable export SSLKEYLOGFILE=$HOME/sslkeylog.log. OpenSSL would write the key to this file, and Wireshark could decrypt the traffic using this data.

Unfortunately this only worked with RSA keys. I could not get it to work with modern Elliptic Curve keys.

I’ve updated my zWireshark program to capture AT-TLS application data in clear text from the z/OS side. It uses an IBM provided API, and captures the traffic between AT-TLS and the application.

You need to set up security profiles, for example

permit  EZB.TRCSEC.*.*.ATTLS            - 
CL(SERVAUTH) id(ADCDB) access(READ)
permit EZB.TRCCTL.S0W1.TCPIP.DATTRACE -
CL(SERVAUTH) id(ADCDB) access(READ)
permit EZB.TRCCTL.S0W1.TCPIP.OPEN -
CL(SERVAUTH) id(ADCDB) access(READ)
permit EZB.TRCCTL.*.*.* CL(SERVAUTH) id(ADCDB) access(READ)
SETROPTS RACLIST(SERVAUTH) refresh

and change the AT-TLS configuration to include CtraceClearText On

For my web browser traffic it produced (printed with the ASCII switch)

Data trace.  Data length 345.  ATTLS Clear Text.                             
<GPMSERVE 11:01:57.258946 Src 10.1.1.2 Port 8803 Dst 10.1.0.2 Port 45168
Warning: 199 RMF-DDS-Server SeverityCode(03) Data(0)
Content-Location: perform_20250102110157_20250102110157.xml
Cache-Control: max-age=30
Date: Thu, 02 Jan 2025 11:01:57 GMT
Connection: close
Content-Length: 1468
Content-Type: application/xml
X-UA-Compatible: IE=edge
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block

When the AT-TLS option CtraceClearText was Off, the output was

Data trace.  Data length 0.  PTH_Flag.Confidential.                           
<GPMSERVE 11:27:48.733616 Src 10.1.1.2 Port 8803 Dst 10.1.0.2 Port 52860

So no confidential data was displayed.

The JCL is

//COLINC5    JOB 1,MSGCLASS=H,COND=(4,LE) 
// SET LOADLIB=COLIN.ZWIRESHA.LOAD
//RUN EXEC PGM=TCPDATA,REGION=0M,PARMDD=MYPARMS
//STEPLIB DD DISP=SHR,DSN=&LOADLIB
//SYSPRINT DD SYSOUT=*,DCB=(LRECL=200)
//SYSOUT DD SYSOUT=*
//SYSERR DD SYSOUT=*
//* MYPARMS needs a / to split LE parms from program parms
//* needs a blank before each parm, because trailing blanks removed
//MYPARMS DD *
/
--IP 10.1.0.2
--WAIT 60
--DEBUG 0
--DISCARD 1
--PRINT A
/*

Please let me know of any problems or suggestions

I want to be someone else – or using pthread_security_np

There are times when you are running a job, and you want to do some work as a different userid.

You can configure a userid so it acts as a surrogate – I can submit jobs with your userid, without knowing your password.

You can have a server and have a thread within the server run as different userid by specifying a userid and password, using the pthread_security_applid_np function. You can also have it logon using a certificate, and it looks up the userid from the certificate.

You can extend/restrict this by specifying an RACF APPL which the user must have access to.

RDEFINE APPL YYYY 
PERMIT  CLASS(APPL) YYYY ID(COLIN) ACCESS(READ) 
SETROPTS RACLIST(appl ) REFRESH

My job running with userid IBMUSER specifies a userid COLIN, and COLIN’s password. If applid YYYY is specified, userid COLIN must have read access to the YYYY in CLASS(APPL).

If you use pthread_security_np() is the same as pthread_security_applid_np() and uses the default OMVSAPPL.

My example C program is

Main

int main( int argc, char *argv[]) 
{ 
  pthread_t thid; 
  int rc; 
  void *ret; 
  if (pthread_create(&thid, NULL, thread, "thread 1") != 0) { 
    perror("pthread_create() error"); 
    exit(1); 
  } 
  rc =pthread_join(thid, &ret); 
  printf("Pthread join %d\n",rc); 
  if (rc  != 0) { 
 // perror("pthread_create() error"); 
 // return(3); 
  } 
  printf("thread exited with '%s'\n", ret); 
  return 0  ; 
} 

  #pragma runopts(POSIX(ON)) 
  /*Include standard libraries */ 
  #include <stdio.h> 
  #include <stdlib.h> 
  #include <string.h> 
  #include <stdarg.h> 
  #include <errno.h> 
  #define _OPEN_SYS 1 
  #include <pthread.h> 
                                                                    
  void *thread(void *arg) { 
  char *ret = ""; 
  int rc; 
  printf("thread() entered with argument '%s'\n", arg); 
  rc = pthread_security_applid_np(__CREATE_SECURITY_ENV, 
              __USERID_IDENTITY, 
              5, 
              "COLIN", 
              "PASSW0RD", 
              0,"AAAA"); 
  perror("perror"); 
  printf("colin rc = %d errno %d\n",rc,errno); 
  if (rc == 0) 
  { 
     FILE * f2  ; 
     f2 = fopen("DD:TEST","r                      ") ; 
     printf("DD:TEST  %d\n",f2); 
   } 
  pthread_exit(ret); 
  } 



int main( int argc, char *argv[]) 
{ 
  pthread_t thid; 
  int rc; 
  void *ret; 
  if (pthread_create(&thid, NULL, thread, "thread 1") != 0) { 
    perror("pthread_create() error"); 
    exit(1); 
  } 
  rc =pthread_join(thid, &ret); 
  printf("Pthread join %d\n",rc); 
  if (rc  != 0) { 
    perror("pthread_create() error"); 
   return(3); 
  } 
  printf("thread exited with '%s'\n", ret); 
  return 0  ; 
} 

When the above program ran it gave me

ICH408I USER(COLIN   ) GROUP(SYS1    ) NAME(COLIN PAICE         ) 
  IBMUSER.TRY.PEM CL(DATASET ) VOL(C4USR1)                        
  INSUFFICIENT ACCESS AUTHORITY                                   
  ACCESS INTENT(READ   )  ACCESS ALLOWED(NONE   )                 

which shows that the userid COLIN was used.

EDC5167I Access to the UNIX System Services version of the C RTL is denied. (errno2=0xC10F0001 C10F0001) .

You cannot use the pthread_security… functions in the main thread. You have to attach a subtask using pthread_create().

EDC5143I No such process. (errno2=0x0BE80000 0BE80000)

Invalid userid specified.

EDC5111I Permission denied. (errno2=0x0BE80000 0BE80000)
Invalid password.

EDC5163I SAF/RACF extract error. (errno2=0x0BE8081C 0BE8081C)

Revoked userid.

EDC5168I Password has expired. (errno2=0x0BE80000 0BE80000)

Obvious.

EDC5163I SAF/RACF extract error. (errno2=0x0BE80820 0BE80820)

No OMVS segment, or the new user does not have access to the specified applid class.

rc = pthread_security_np() defaults to pthread_security_applid_np() with an applid of OMVSAPPL

ICH70004I 
ATTEMPTED 'READ' ACCESS OF USER(ADCDE) GROUP(TEST) NAME(ADCDE) ENTITY 'OMVSAPPL' IN CLASS 'APPL' 

EDC5139I Operation not permitted. (errno2=0x0BE802AF 0BE802AF)

ICH420I PROGRAM CERT FROM LIBRARY COLIN.LOAD CAUSED THE ENVIRONMENT TO
BECOME UNCONTROLLED.
BPXP014I ENVIRONMENT MUST BE CONTROLLED FOR SERVER (BPX.SERVER)
PROCESSING.

Needed

RALTER PROGRAM CERT ADDMEM('COLIN.LOAD'//NOPADCHK)
SETROPTS WHEN(PROGRAM) REFRESH

Python could not read a data set I sent from z/OS USS.

I created a file in Unix System Services, and FTPed it down to my Linux box. I could edit it, and process it with no problems, until I came to read in the file using Python.

Python gave me

File “<frozen codecs>”, line 322, in decode
UnicodeDecodeError: ‘utf-8’ codec can’t decode byte 0xb8 in position 3996: invalid start byte

The Linux command file pagentn.txt gave me

pagentn.txt: ISO-8859 text

whereas other files had ASCII text.

I changed my Python program to have

with open(“/home/colinpaice/python/pagentn.txt”,encoding=”ISO-8859-1″) as file:

and it worked!

I browsed the web, and found a Python way of finding the code page of a file

import chardet    
rawdata = open(infile, 'rb').read()
result = chardet.detect(rawdata)
charenc = result['encoding']

it returned a dict with

result {‘encoding’: ‘ISO-8859-1’, ‘confidence’: 0.73, ‘language’: ”}

One minute mvs: data set file system (/dsfs) on z/OS

There is a good overview of dsfs here.

My understanding of how dsfs works is that you can access z/OS datasets, members and spool, through a Unix file system interface, and so use commands like “ls”. When you read a member, it is read into the dsfs file system, and the Unix commands work on this data. When you write to the Unix file, it is written to the dsfs file system, and when the file is closed, the data is written to the dataset.

Some information is cached in the dsfs file system, and some definitions, such as DCB information on a per userid basis is also stored.

DSFS is defined to OMVS as a Physical File System. Part of the definition of the PFS is the started task name. When the PFS is defined to OMVS, it starts the DSFS started task.

To stop it, you issue a command to OMVS to stop the PFS.

Permissions

The dsfs started task has threads which do work. When you issue a request, one of the threads becomes your userid and accesses the data sets, so there is no change to the standard RACF data set protection.

User defaults

You can define defaults for when data sets are created. These are user dependant. To issue these for another user, you have to become a super user to become that id, and then issue the dfsadm command.

Changing configuration

You can change the configuration file and restart DSFS (which will be disruptive).

You can make changes to the active system (which are not saved) using the omvs command

Diagnosis

Messages are produced, and are documented in the M&C manual. if you get a reason code, you can use bpxmtext code to display the meaning of the code.

Creating data sets and members from /dsfs

You can configure defaults when using dsfs to create data sets and members. For example

Creating a PDS(E)

cd /dsfs/txt/colin
dsadm createparm -path . -pdsmodel "dsntype(library) dsorg(po) lrecl(133) recfm(vb)
blksize(0)"

For path /dsfs/txt/colin (-path .) it creates a model for pds (-pdsmodel) with the parameters dsntype…blksize(0)

Note:blksize(0) says “pick the best block size”

You can display this using

dsadm fileinfo   -path /dsfs/txt/colin  

and get

path: /dsfs/txt/colin                                                                                
fid 49,1 anode 1285,4548
length 16384 format BLOCKED
1K blocks 16 dir tree status VALID
PDS model anode 31,60 PS model anode 0,0
object type DIR object linkcount 181
object genvalue 0x00000000 dir version 1
dir name count 431 data set name type HLQ DIR
recfm na lrecl na
data mode TEXT data set status RETRIEVED
data set name COLIN
ENQ held NO
direct blocks 0x00001BAF 0x00001BB0 0xFFFFFFFF 0xFFFFFFFF
0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF
indirect blocks 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF
mtime Sep 9 10:09:55 2024 atime Sep 9 10:09:55 2024
ctime Sep 9 10:09:55 2024 create date Sep 9 2024
not encrypted not compressed
PDS model dsntype(library) dsorg(po) lrecl(133) recfm(vb) blksize(0)
PS model na
vnode,vntok 0x00000050,,0x072003C0 0x0099A7F0,,0x00000000
opens oi=0 rd=0 wr=0
file segments na file unscheduled na
meta buffers 0 dirty meta buffers 2

Creating a sequential file

dsadm createparm -path /dsfs/txt/colin -psmodel "dsorg(ps) lrecl(80) recfm(fb) blksize(3200)"

The command

dsadm fileinfo   -path /dsfs/txt/colin 

now gives

PS model               dsorg(ps) lrecl(80) recfm(fb) blksize(3200)    

The command

echo "hi" > /dsfs/txt/colin/seq2          

creates a data set COLIN.SEQ2 with characteristics

Record format . . . : FB
Record length . . . : 80
Block size . . . . : 3200

If you specify blksize(0) the system applies a default. In my case Block size . . . . : 27920, which makes good usage of the disk space.

Different data set types

There are three data set types

  • bin – binary for example load modules
  • rec – records
  • txt – text files, with a new line character “at the end of the line”

You can define the data set characteristics for each of these.

Problems I experienced when using /dsfs

I played around with /dsfs and found a couple of problems.

My userid is COLIN.

Data set not seen for a time

I created a data set COLIN.ENCR2.DSN in ISPF (and also in batch).

The command

ls -ltr /dsfs/txt/colin/en*

found the data set /dsfs/txt/colin/encrypt.jcl, but it did not find /dsfs/txt/colin/encr2.dsn.

A while later (a minute or two) it found /dsfs/txt/colin/encr2.dsn . This is because of the DIRECTORY_REFRESH_TIMEOUT that controls it. Its default value is 60. You can dynamically change it via command dsadm config -directory_refresh_timeout <number>. The expected value is a number in the range 30-600.

Encrypted data set not seen

I had set up a data set which was encrypted, and empty. I could not list it using /dsfs

I had to set up an encryption ZFS for DSFS (as the documentation says) for it to be seen. I expected the dataset name to be visible, but not the contents.

Create the label in ICSF

//IBMICSF  JOB 1,MSGCLASS=H 
//STEP10 EXEC PGM=CSFKGUP
// SET CKDS=COLIN.SCSFCKDS
//CSFCKDS DD DISP=OLD,DSN=&CKDS
//* LENGTH(32) GENERATES A 256 BIT KEY
//CSFIN DD *,LRECL=80
ADD TYPE(DATA) ALGORITHM(AES),
LABEL(DSFSAES ) LENGTH(32)
/*
DELETE TYPE(DATA) LABEL(COLINBATCHAES )
//CSFDIAG DD SYSOUT=*,LRECL=133
//CSFKEYS DD SYSOUT=*,LRECL=1044
//CSFSTMNT DD SYSOUT=*,LRECL=80
//* REFRESH THE IN MEMORY DATA
//REFRESH EXEC PGM=CSFEUTIL,PARM='&CKDS,REFRESH'

Give the DSFS userid access to the label

//IBMRACF2 JOB 1,MSGCLASS=H RESTART=S2 
// EXPORT SYMLIST=(*)
// SET KEY=DSFSAES
//S1 EXEC PGM=IKJEFT01,REGION=0M
//SYSPRINT DD SYSOUT=*
//SYSTSPRT DD SYSOUT=*
//SYSTSIN DD *,SYMBOLS=(JCLONLY)
RDELETE CSFKEYS &KEY
RDEFINE CSFKEYS &KEY +
ICSF(SYMCPACFWRAP(YES) SYMCPACFRET(YES)) +
UACC(NONE)
PERMIT &KEY +
CLASS(CSFKEYS) ID(DSFS ) +
ACCESS(READ)
SETROPTS RACLIST(CSFKEYS) REFRESH

RLIST CSFKEYS &KEY AUTHUSER ICSF

ADDSD 'COLIN.ZFS.DSFS' UACC(NONE)
ALTDSD 'COLIN.ZFS.DSFS' UACC(NONE) DFP(DATAKEY(&KEY))
/*

Define the ZFS for DSFS

I stopped DSFS using the operator command

f omvs,stoppfs=dsfs

I could then delete and recreate the ZFS. If I wanted to keep the content of the DSFS ZFS, I think I could have using VSAM REPRO to copy the contents to a new file.

//IBMCLUST  JOB 1 
//DEFINE EXEC PGM=IDCAMS,REGION=0M
//SYSPRINT DD SYSOUT=*
//SYSIN DD *
DELETE COLIN.ZFS.DSFS
DEFINE CLUSTER (NAME(COLIN.ZFS.DSFS) -
VOLUMES(* ) -
CYL(100 1000) -
KEYLABEL(DSFSAES) -
DATACLASS(DCEATTR) -
ZFS )
LISTCAT ENT(COLIN.ZFS.DSFS) ALL
/*

The LISTCAT output had

LISTCAT ENT(COLIN.ZFS.DSFS) ALL                                                                            
CLUSTER ------- COLIN.ZFS.DSFS
...
ENCRYPTIONDATA
DATA SET ENCRYPTION----(YES)
DATA SET KEY LABEL-----DSFSAES

I restarted DSFS.

With the DSFS ZFS encrypted, the ls command for the encrypted data set worked, and I was able to read the content.

When my userid COLIN which had access to the encrypted data set, but not the encryption key, tried to display the contents there were messages on the system log

ICH408I USER(COLIN   ) GROUP(SYS1    ) NAME(####################) 008    
COLINBATCHAES CL(CSFKEYS )
INSUFFICIENT ACCESS AUTot HORITY
ACCESS INTENT(READ ) ACCESS ALLOWED(NONE )
IDFS00338E RACROUTE REQUEST=FASTAUTH call to authorize access to the keylabel COLINBATCHAES
for data set COLIN.ENCR.DSN for user COLIN failed with SAF rc 8 RACF rc 8 Reason Code 0.

and the OMVS session got

cat: /dsfs/txt/colin/encr.dsn: EDC5164I SAF/RACF error.    

It is hard work getting error messages

I got

COLIN:/u: >dsadm config -hlq_list_add SYS1.PARMLIB                                                                                
IDFS00324E Could not add the specified high-level qualifier directory names to the HLQ list, error code 139 reason code ED04618D.

To get the full description of the error I had to use

COLIN:/u: >bpxmtext ED04618D                                                                                                      
DSFS Tue Sep 12 19:21:54 EDT 2023
Description: The caller is not UID 0.

Action: Ensure that you are properly authorized for this operation. This
subcommand requires UID 0 or READ access to the SUPERUSER.FILESYS.PFSCTL
profile in the z/OS UNIXPRIV class.

Where’s the $?

Because the OMVS shell uses $ to replace variables, you have to quote the data set name.

IBMUSER:/u/ibmuser: >ls /dsfs/txt/sys1.proclib/$$$COIBM                           
ls: FSUM6785 File or directory "/dsfs/txt/sys1.proclib/50397215" is not found

You have to use

ls '/dsfs/txt/sys1/parmlib/$$$COIBM'     

with quotes around it, or escape the special characters.

ls /dsfs/t*/sys1/proclib/\$\$\$coibm

Setting up data set file system /dsfs on z/OS

There is a good overview of dsfs here.

The documentation is pretty good. It is clear – but I would have ordered the sections differently.

Concept

My understanding of how dsfs works is that you can access z/OS datasets, members and spool, through a Unix file system interface, and so use commands like “ls”. When you read a member, it is read into the dsfs file system, and the Unix commands work on this data. When you write to the Unix file, it is written to the dsfs file system, and the data is written to the dataset when the file is closed.

Some information is cached in the dsfs file system, and some definitions, such as DCB information on a per userid basis is also stored.

Setup the RACF definitions

//IBMRACFL JOB 1,MSGCLASS=H                                
//S1 EXEC PGM=IKJEFT01,REGION=0M
//SYSPRINT DD SYSOUT=*
//SYSTSPRT DD SYSOUT=*
//SYSTSIN DD *
ADDGROUP DSFSGRP SUPGROUP(SYS1)
ADDUSER DSFS DFLTGRP(DSFSGRP) AUTHORITY(USE) UACC(NONE)
RDEFINE STARTED DSFS.** STDATA(USER(DSFS))
SETROPTS RACLIST(STARTED)
SETROPTS RACLIST(STARTED) REFRESH
/*
//

The started task procedure is in IOE.SIOESAMP(DSFS)

You can configure it to use the parmlib concatenation. I configured it to use a member in user….parmlib.

//DSFS     PROC REGSIZE=0M                                            
//*
//DSFSGO EXEC PGM=BPXVCLNY,REGION=&REGSIZE,TIME=1440
//*
//*STEPLIB DD DISP=SHR,DSN=hlq.SIEALNKE <--DSFS LOADLIB
//IDFZPRM DD DISP=SHR,DSN=USER.Z31A.PARMLIB(DSFS) <--DSFS PARM FILE

This is automatically started when you activate the dsfs physical file system (in a bpxprmxx member).

Create the ZFS

If you are going to use encrypted data sets the ZFS needs to be encrypted. See One minute MVS – Using individual data set encryption on z/OS.

I do not know how much space you actually need. If you specify a secondary extent, the ZFS can expand as needed.

If you want the ZFS to be larger than 4GB you need to specify Extended Addressability. On ADCD there is an SMS Data Class DCEATTR with extended attributes.

The documentation talks about having the z/OS image name as part of the data set when part of a sysplex. I specified the name as part of DSFS startup.

If you are using ADCD and you use a “system” HLQ such as ZFS.DSFS, then when you move to the next release of ADCD you’ll have to migrate it. By using COLIN as a HLQ, it gets picked up automatically in the next release after I have imported the user catalog.

//IBMCLUST  JOB 1 
//DEFINE EXEC PGM=IDCAMS,REGION=0M
//SYSPRINT DD SYSOUT=*
//SYSIN DD *
DEFINE CLUSTER (NAME(COLIN.ZFS.DSFS) -
VOLUMES(* ) -
CYL(100 1000) -
DATACLASS(DCEATTR) -
ZFS )

/*
LISTCAT ENT(COLIN.ZFS.DSFS) ALL
DELETE COLIN.ZFS.DSFS

The ZFS is formatted when it is first used, and as it expands.

Startup parameters

In USER.Z31A.PARMLIB(DSFS), referred to in the DSFS started procedure, I have

* 
UTFS_NAME=COLIN.ZFS.DSFS

Without the UTFS_NAME, it will look for a data set with the image name. If you are running in a sysplex each system needs its own ZFS.

Define the root

In TSO OMVS use mkdir /dsfs

Define the physical file system, and mount the file

I created USER.Z31A.PARMLIB(BPXPRMFS) with

FILESYSTYPE TYPE(DSFS) ENTRYPOINT(IDFFSCM) ASNAME(DSFS)

MOUNT TYPE(DSFS)
MODE(RDWR)
NOAUTOMOVE
MOUNTPOINT('/dsfs')
FILESYSTEM('COLIN.ZFS.DSFS')

Activate and start it

You can use the operator command set omvs=(FS) to activate the member bpxprmfs (defined above). This starts the address space DSFS. You could have this activated as part of IPL in the usual way.

The first time I started DSFS, I got messages

SET OMVS=(FS)                                                         
IEE252I MEMBER BPXPRMFS FOUND IN USER.Z31A.PARMLIB
BPXO032I THE SET OMVS COMMAND WAS SUCCESSFUL.
IEF196I IEF285I USER.Z31A.PARMLIB KEPT
IEF196I IEF285I VOL SER NOS= A3CFG1.
...
$HASP100 DSFS ON STCINRDR
$HASP373 DSFS STARTED
IEF403I DSFS - STARTED - TIME=08.51.23
IDFS00153I DSFS kernel: Initializing z/OS DSFS 279
Version 03.01.00 Service Level OA65531 - HZFS510.
Created on Tue Sep 12 19:21:54 EDT 2023.
Address space asid x47.
IDFS00064I USER.Z31A.PARMLIB(DSFS) is the configuration data set currently in use.
IDFS00352I DSFS is using HLQ EXCLUDE mode.
IDFS00039I DSFS kernel: initialization complete.
BPXF025I FILE SYSTEM COLIN.ZFS.DSFS IS BEING MOUNTED.
IDFS00320I Formatting to 4096 control interval 18000 for primary
IDFS00003I Primary extent loaded successfully for COLIN.ZFS.DSFS.
IDFS00034I Detaching utility file system COLIN.ZFS.DSFS.

Stop dsfs

If you get messages saying data set in use etc, this may be due to the DSFS program has started. You can stop it using f omvs,stoppfs=dsfs, fix any problems, and restart it.

Setting up permissions

Some of the dsadm commands, for example which change the configuration, need permission. The issuer must be logged in as a root user (UID=0) or have READ authority to the
SUPERUSER.FILESYS.PFSCTL resource in the z/OS UNIXPRIV class. Note: If you are permitted READ to the BPX.SUPERUSER resource in the RACF FACILITY class, you can become a UID of 0 by issuing the su command to get uid 0.

PERMIT SUPERUSER.FILESYS.PFSCTL CLASS(UNIXPRIV) ID(userid) ACCESS(READ)
SETROPTS RACLIST(UNIXPRIV) REFRESH

PERMIT BPX.SUPERUSER CLASS(FACILITY) ID(userid) ACCESS(READ)
SETROPTS RACLIST(FACILITY) REFRESH

Once it has started – now what?

In OMVS you can use the ls -ltr command

IBMUSER:/u/ibmuser: >ls -ltr  /dsfs                           
total 0
drwxrwxrwx 2 OMVSKERN SYS1 0 Sep 9 03:51 txt
drwxrwxrwx 2 OMVSKERN SYS1 0 Sep 9 03:51 sysout
drwxrwxrwx 2 OMVSKERN SYS1 0 Sep 9 03:51 rec
drwxrwxrwx 2 OMVSKERN SYS1 0 Sep 9 03:51 bin

You can use the dsfs commands in Unix Services

dsadm fsinfo
File System Name: COLIN.ZFS.DSFS

System: S0W1 Devno: 0
Size: 72000K Free 8K Blocks: 8732
Free 1K Fragments: 7 Log File Size: 2056K
Bitmap Size: 16K Anode Table Size: 8K
File System Objects: 7 Version: 1
Overflow Pages: 0 Overflow HighWater: 0
Space Monitoring: 0,0
ENOSPC Errors: 0 Disk IO Errors: 0
Status: NE,NC

File System Creation Time: Sep 9 03:51:25 2024
Mount Time: Sep 9 03:51:25 2024

Last Grow Time: n/a

Using z/OS health checker is good – but how do I use it?

I had a message on the console saying

HZS0001I CHECK(IBMICSF,ICSF_CLEAR_KEYS): CSFH0056E Clear keys in the CKDS, PKDS, or TKDS were found.

Great – but what next?

In SDSF, you can use the CK command to display the health-checker events.

There were a lot of checks. The SDSF command CK E, displays only those with exceptions; where the result was > 0.

There are various line commands, but SE gives you all of the information, in the ISPF editor.

In the page it told me

CSFH0054I Check for clear keys in the CKDS, PKDS, and TKDS. 
Active TKDS: COLIN.SCSFTKDS
-----------------------------------------------------
PKISRVD.PKITOKEN 00000001T
Explanation: ...
System Action: ...
Operator Response: ...
System Programmer Response: ...

Great – this is very useful. However the action “Contact the ICSF administrator” is not very helpful as I am the ICSF administrator!

Migrating an ADCD z/OS release: user data sets, user catalogs and High Level Qualifier

Start here:Migrating an ADCD z/OS release to the next release.

I have covered datasets, aliases and catalogs in One minute mvs: catalogs and datasets.

If your master catalog is a mess

If you have your personal data sets in the master catalog instead of a user catalog, see Here’s another nice mess I’ve gotten into!

You could start again on the new system and do it properly.

Note down which volumes your data sets are on. On the new system define a user catalog and alias, and use ISPF 3.4, to list the contents of the volume and use the C local command to catalog the data set.

I found the easiest way of doing VSAM datasets is a backup and restore

If you have a user catalog for your user data sets

You need to get a list of the user aliases in the master catalog on the old system, and the user catalogs the aliases refer to, before trying to import them into the new system. I could not find a way to list the master catalog from another system. See here for example JCL

To access your data sets in a user catalog you need to import the catalog into the master catalog on the new system, and define the aliases for your data to the catalog.

On your new system, you will not have immediate access to your data sets, so you either need

  • to access a dataset, and specify the volser information,
  • or you need to have a copy of the JCL to import a user catalog, and define alias, stored in a note pad area outside of z/OS. Edit a member such as USER.*.PROCLIB(TEMP) and paste the import catalog JCL. When that has worked, paste in the add alias to your datasets ( COLIN.*). Once you have done this, you can use ISPF 3.4 and use COLIN.* to locate your data sets.

Once you have your list of aliases and user catalogs, you can IPL the new system and import the user catalogs, and define the aliases.

Product data sets

There is usually an alias in the master catalog for a program product. The alias may have the product release as part of the name. If you have customised any of the product owned datasets, you may need to copy the data off.

Migrating an ADCD z/OS release: ZFS files.

Start here:Migrating an ADCD z/OS release to the next release.

For background see Should I use tar or pax to backup my Unix files?

System files

If you have done any configuration to products which use Unix services, you are likely to have changed files in the file system. For example /etc/syslog.conf.

Configuration files

Many configuration files are configured in the /etc directory.

If you want to find which files have been changed since you have been using the system you could use the ls -ltr command to display the files in each directory, displayed with the latest changed date at the bottom.

This gets very tedious when you have a lot of directories to example. However you can ask Unix to list all files which match a critera, such as changed in the last n days, or newer than an existing file.

Create a file of the comparison data

touch -t 202202211456 /tmp/foo

This creates a file /tmp/foo with the given date year 2022 month 02 date 21 time 1456

find . -type f -newer /tmp/foo |xargs ls -ltr > aa

This is two commands.

  • The find command
    • looks in the current directory (.) and subdirectories
    • for objects with type of files (rather than directories etc)
    • which have been changed more recently than /tmp/foo.
  • The file name is passed to the ls -ltr command to display the date time information.
-rwx------   1 OMVSKERN OMVSGRP       32 Feb 13  2023 ./cssmtp.env 
-rw-r--r-- 1 OMVSKERN OMVSGRP 3453 Feb 13 2023 ./mail/ezatmail.cf
-rwxr-xr-x 1 OMVSKERN OMVSGRP 250 Feb 28 2023 ./hosts
-rw-r--r-- 1 OMVSKERN OMVSGRP 226441 Jun 16 2023 ./pkiserv/pkiserv.tmpl.old
-rw-r--r-- 1 OMVSKERN OMVSGRP 22406 Jun 16 2023 ./pkiserv/pkiserv.conf.old
...

if you use

find . -type f -newer /tmp/foo |tar -cvf ~/etc.tar –

it will create a tar file containing the changed files. You can then transport the etc.tar file to the newer system and untar it.

You can use the pax command to package the files

find . -type f -newer /tmp/foo |pax -W “seqparms=’space=(cyl,(10,10))'” -o saveext -wzvf “//’COLIN.PAX.TEST'” -x os390

to save the files in pax format into the data set COLIN.PAX.TEST. If the high level qualifier has been defined as an alias is the master catalog on both systems, the data set will be visible on both systems.

Note: If you specify

find . -type d -newer /tmp/foo

It displays all directory entries which have been changed, and displays all the files within those directories.

For example

total 1344 
-rw-r--r-- 1 OMVSKERN OMVSGRP 3252 May 7 2019 ssh_config
-rw-r--r-- 1 OMVSKERN OMVSGRP 553761 May 7 2019 moduli
-rwx------ 1 OMVSKERN OMVSGRP 65 Oct 29 2019 sshd.sh

For example the sshd directory was changed in September this year, so all the files below it are listed. 

Application output files

These are usually in the /var sub-directory. You may not need to move these files across.

User data

You will have your own data in the Unix file systems. If you put the data under the /u file system it should be easy to find! 

You may have configured userids so their home directory is on a “user” ZFS file system, or your home directory could be mixed in with the systems files. For example the file system for IBMUSER is on an ADCD file system (D5USS2).

IBMUSER:/S0W1/etc: >df -P ~                                                         
Filesystem 512-blocks Used Available Capacity Mounted on
ZFS.USERS 2880000 1277970 1602030 45% /u

The newer system also has a ZFS.USERS. You cannot have both old and new ZFS.USERS mounted at the same time, as the mount takes cataloged data set.

For my application data

IBMUSER:/S0W1/etc: >df -P /u/tmp
Filesystem 512-blocks Used Available Capacity Mounted on
COLIN.ZFS2 2817120 788338 2028782 28% /u/tmp

I can take this ZFS system and mount it on the newer system.

You can tar up the files under a directory and move the tar file to the new system, or you can use pax which I think is better, as it creates a dataset out of the ZFS files.

Using tar

Note: if you use an absolute path in the tar command, when you untar the data it will use the same directory- – which may overrwrite data you wanted to keep.

If you use are relative directory, the data is untarred relative to the current directory.

cd /u/colin
tar -cvf ~/relative.tar *

is better than

tar -cvf ~/absolute.tar /u/colin

On the new system if I use

mk dir oldcolin
cd oldcolin
tar -xtvf relative.tar

it will restore the files in oldcolin.

If I use

mk dir oldcolin
cd oldcolin
tar -xtvf absolute.tar *

it will restore the files to /u/colin – and overwrite any files which were there.

What directories were created?

You can use the command

find /u -type d -newer /tmp/foo |xargs ls -ltrd> aa

to display the directories created/modified since the time of the /tmp/foo file.

This gives output like

drwxrwxrwx  10 OMVSKERN SYS1        8192 Dec  8 13:04 ./adcd 
drwxr-xr-x 2 OMVSKERN 1000 8192 Mar 15 2023 ./tmp/oemput
drwxrwxrwx 2 OMVSKERN WEBGRP 8192 Apr 25 2023 ./mqweb3/logs
drwxr-xr-x 2 OMVSKERN SYS1 8192 Jun 16 2023 ./mqweb2/oldconf

You can use the pax -E option to display the contents and extended attributes.

pax -E -f "//'COLIN.PAX.HTTP2'"

Notes the double / and both sets of quotes.

To unpax the files on the new system, cd into the directory and use

pax -k -rvf  "//'COLIN.PAX.TEST'" .

The

  • -k means do not overwrite
  • -r read
  • -v display the details
  • -f from the following file
  • into . (the current directory)

To mount a ZFS on the system

You can have an entry in an BPXPRMxx parmlib member, so a ZFS is mounted at IPL time.

You can also use a TSO command, or a batch job to mount a ZFS

//IBMMFAMO JOB 1,MSGCLASS=H
//MOUNT EXEC PGM=IKJEFT1A
//SYSTSPRT DD SYSOUT=*
//SYSTSIN DD *
MOUNT FILESYSTEM('AZF220.ZFS') TYPE(ZFS) +
MOUNTPOINT('/u/mfa') +
MODE(RDWR) PARM('AGGRGROW') AUTOMOVE

Sharing File systems

You can display the mounted file systems using the D OMVS,F command

This gives output like

ZFS            16 ACTIVE                      RDWR  01/15/2024  L=30  
NAME=ZFS.USERS 14.38.54 Q=0
PATH=/u
OWNER=S0W1 AUTOMOVE=N CLIENT=N
ZFS 37 ACTIVE RDWR 01/15/2024 L=48
NAME=COLIN.ZFS2 14.38.56 Q=0
PATH=/u/tmp
OWNER=S0W1 AUTOMOVE=Y CLIENT=N

This shows there are two ZFS file systems, both mounted read/write. The first has

  • data set name ZFS.USERS. On the z24C system – this is the z24C file system. You cannot mount both the z24C, and the z25D file systems at the same time, because the mount command uses the cataloged data set.
  • mounted as path /u

The second has

  • data set name COLIN.ZFS2
  • mounted as path /u/tmp

You can choose to mount your data under an existing path, or create a new tree such as “/my”.