0/10 for JCL 101 homework

When I worked with customers, you could often tell people who were not experienced, and setting up subsystems and applications

“My first JCL”

//STEPLIB   DD DSN=ABC120.EG1.SABCAUTH,DISP=SHR   /* USER LIB  */ 
// DD DSN=ABC120.SABCANLE,DISP=SHR
// DD DSN=ABC120.SABCAUTH,DISP=SHR
// DD DSN=CEE.SCEERUN,DISP=SHR
...
//FILE1 DD DSN=ABC120.EG1.FILE01,DISP=SHR
//FILE2 DD DSN=ABC120.EG1.FILE02,DISP=SHR

Where the FILE datasets contain user data.

All the ABC120.* datasets were shipped on a volume ABCV12. When the system was updated to a newer service level, the volume ABCV12 was refreshed and put on all systems.

What could go wrong?

The first problem – whoops

With the volume ABCV12 being replaced, all the user data is replaced – Whoops.

Solution: You need to keep your libraries and user data separate. Product libraries on ABCV12, and user data on USRxxx. You might want to make the volume for the product libraries (ABCV12) read only.

The second problem – what is this?

Once you have fixed the problem and separated the data onto different volumes you upgrade to the next version ABCV13.

Now your JCL is

//STEPLIB   DD DSN=ABC130.EG1.SABCAUTH,DISP=SHR   /* USER LIB  */ 
// DD DSN=ABC130.SABCANLE,DISP=SHR
// DD DSN=ABC130.SABCAUTH,DISP=SHR
// DD DSN=CEE.SCEERUN,DISP=SHR
...
//FILE1 DD DSN=ABC120.EG1.FILE01,DISP=SHR
//FILE2 DD DSN=ABC120.EG1.FILE02,DISP=SHR

People looking at this will be confused and will ask what release are we running, it looks like 1.3, but the data sets say 1.2

Solution: Use a name like ABCUSER.EG1.FILE01 instead of ABC120.EG1.FILE01. These names never change when you migrate to a newer release.

You can enforce which HLQ’s can use which volumes using HSM rules.

You want to do a test upgrade to the next release: – how much work is it!!

Over this weekend, you want to test out the next release and go from release 1.3 to 1.4. You look at all your JCL, use SRCHFOR ABC130. and find all the places where you have ABC130 (wow, lots of places). You will have to change the JCL to run the subsystem at the start of the test, run your test, and change it all back ready for production next week. With all the changes you need to be careful not to make a mistake. (And of course all the change request paper work needs to be approved)

A better way is to use dataset aliases.

DEFINE ALIAS(NAME(ABC.SABCAUTH) RELATE(ABC120.SABCAUTH))
DEFINE ALIAS(NAME(ABC.SABCANLE) RELATE(ABC120.SABCANLE))
etc

So when you use ABC.SABCAUTH under the covers it uses ABC920.SABCAUTH

Your JCL now looks like

//STEPLIB   DD DSN=ABCUSR.EG1.SABCAUTH,DISP=SHR   /* USER LIB  */ 
// DD DSN=ABC.SABCANLE,DISP=SHR
// DD DSN=ABC.SABCAUTH,DISP=SHR
// DD DSN=CEE.SCEERUN,DISP=SHR
...
//FILE1 DD DSN=ABCUSER.EG1.FILE01,DISP=SHR
//FILE2 DD DSN=ABCUSER.EG1.FILE02,DISP=SHR

You do not need to worry about APF authorising the CSQ.SCSQAUTH. The dataset which is checked is the dataset the alias points to.

To test the next release this weekend, you delete the aliases and define the new ones. You do not need to change your JCL libraries. You run your tests and at the end delete the new aliases and redefine the old one. The JCL will fit on one screen is much easier than changing all your JCL libraries, and less error prone. (And someone else can review the JCL before you make the changes)

An alternative way

You could use system symbolics EGHLQ = ABC120, and refer to it as in //STEPLIB DSN=&EGHLQ..SABCAUTH

Hands up…

If you are guilty of the problems raised in the blog post, you can get round them.

You can implement the alias for the product libraries, and gradually change all references to use the aliases.

Where you have

//FILE1     DD DSN=ABC120.EG1.FILE01,DISP=SHR 
//FILE2 DD DSN=ABC120.EG1.FILE02,DISP=SHR

You can define an alias for these and use DSN=ABCUSER.EG1.FILE01. Once you’ve made the change your friends will appreciate the clarity, and the only people who know about the mess you made are the storage administrators.

In the long term you may be able to fix it by copying the datasets to new ones with the proper name, and deleting the old ones.

Defining dataset aliases is good, but take care

I can define a dataset alias CSQ.SCSQAUTH which points to dataset CSQ920.SCSQAUTH, and use CSQ,SCSQAUTH in my JCL. When I want to change to the next level of code, I just change CSQ.SCSQAUTH to point to CSQ940.SCSQAUTH, and my JCL just works unchanged! Every one should do this.

Background

As part of z/OS catalogs, you can define aliases to keep user information out of the master catalog. For example point a high level qualifier to a catalog

DEFINE ALIAS (NAME(CSQ920) RELATE('USERCAT.Z31B.PRODS')
DEFINE ALIAS (NAME(CSQ) RELATE('USERCAT.Z31B.PRODS')

If I now define a dataset CSQ.COLIN, the information about this data set will be store in the catalog USERCAT.Z31B.PRODS. When the dataset is used, the name is looked up in the master catalog, which says go and use catalog USERCAT.Z31B.PRODS.

Dataset level aliases

I can also define an alias at the data set level. For example CSQ.SCSQAUTH is an alias of CSQ920.SCSQAUTH. I can then use CSQ.SCSQAUTH in my JCL instead of CSQ920.SCSQAUTH

When the next version of code is available, I can change the alias of CSQ.SCSQAUTH to point to CSQ940.SCSQAUTH and my JCL will work as before. I do not need to go through my JCL libraries and replacing the old with new. This is great – every one should use it.

Create the alias using

DEFINE ALIAS(NAME(CSQ.SCSQAUTH) RELATE(CSQ920.CSQ9.SCSQAUTH))

For this to work the data set alias CSQ.SCSQAUTH must be in the same catalog as the data set it references, so both name and target need to be in USERCAT.Z31B.PRODS.

If I use ISPF 3.4 with CSQ.SCSQAUTH it gives volume of *ALIAS. If I browse the dataset it shows data set CSQ920.CSQ9.SCSQAUTH.

You do not need to worry about APF authorisation because controls are on the target data set CSQ920.CSQ9.SCSQAUTH.

What problems did I have?

I had a frustrating hour or so until I got it to work.

I had a different user catalog for the CSQ HLQ.

DEFINE ALIAS (NAME(CSQ920) RELATE('USERCAT.Z31B.PRODS')
DEFINE ALIAS (NAME(CSQ) RELATE('USERCAT.COLINS')
DEFINE ALIAS(NAME(CSQ.SCSQAUTH) RELATE(CSQ920.CSQ9.SCSQAUTH))

The above statements worked successfully, but ISPF 3.4 did not show CSQ.SCSQAUTH.

The commands

LISTCAT CATALOG('CATALOG.Z31B.MASTER') ALIAS
LISTCAT CATALOG('USERCAT.COLINS') ALIAS

did not show any entries for CSQ.SCSQAUTH.
If I tried to redefine the data set alias, it said DUPLICATE entry.

I had to use

LISTCAT CATALOG('USERCAT.Z31B.PRODS') ALIAS

and there was my CSQ.SCSQAUTH.

The documentation says

If the entryname in the RELATE parameter is non-VSAM, choose an aliasname in the NAME parameter that resolves to the same catalog as the entryname.

which I missed the first time round.

I had to delete the dataset alias from the catalog for the target dataset

DELETE CSQ.SCSQAUTH  CATALOG('USERCAT.Z31B.PRODS') 

I then deleted the alias for CSQ, redefined it to point to the correct user catalog, redefined the data set alias and it worked.

DELETE    CSQ          ALIAS 
DEFINE ALIAS (NAME(CSQ) RELATE('USERCAT.Z31B.PRODS')
DEFINE ALIAS(NAME(CSQ.SCSQAUTH) RELATE(CSQ920.CSQ9.SCSQAUTH))

Getting sshfs to work to z/OS

You can “mount” a remote file system as a local directory over sshfs. (ssh file system).

Getting this working was a challenge. I do not know if it is an FTP problem, or a z/OS problem

The command, from Linux, is

sshfs colin@10.1.1.2: ~/mountpoint

where mountpoint is a local directory, and my z/OS system is on 10.1.1.2

This flows into the SSH daemon (SSHD) on z/OS which handles the handshake and encryption.

For the IBM provided SSHD, the /etc/ssh/sshd_config config file has

Subsystem sftp /usr/lib/ssh/sftp-server 

Where /usr/lib/ssh/sftp-server is the executable to do the work. The IBM supplied object is a load module. You could replace this with a script or other module.

Once the session has been established you can access the files, as if they were on the local system.

What is running on z/OS?

If you use the ps -ef command it displays

     UID        PID       PPID  CMD                                               
OMVSKERN 50397264 67174474 /usr/sbin/sshd -f /etc/ssh/sshd_config -R
COLIN 67174482 50397264 /usr/sbin/sshd -f /etc/ssh/sshd_config -R
COLIN 50397267 67174482 sh -c /usr/lib/ssh/sftp-server
COLIN 83951719 50397267 /usr/lib/ssh/sftp-server

This shows the calling chain – the first (SSHD) is at the top, and the last, /usr/lib/ssh/sftp-server, is doing the work to process the files

The shell used depends on the OMVS(PROGRAM()) defined for the userid.

When did sshfs work?

If I had OMVS(PROGRAM(‘/bin/sh’)) then the sshfs worked ok, I could used the files as expected.

If the program was for bash or for zhs, then the data as seen from Linux was in EBCDIC and so was not usable.

So how do I use zsh or bash?

I got round this problem…

I specified the userid as having OMVS(PROGRAM(‘/bin/sh’)), and changed to use the bash shell in the logon script

If I logon with ssh colin@10.1.1.2 then there are environment variables in /etc/profile and ~/.profile.

SSH_CLIENT="10.1.0.2 44898 22"
SSH_CONNECTION="10.1.0.2 44898 10.1.1.2 22"
SSH_TTY="/dev/ttyp0000"

In my ~/.profile I’ve put

if [[ ! -z "$SSH_CLIENT"  ]] 
then
set -x
# SSH_CLIENT has a value ... so an SSH terminal
# bash="/usr/lpp/Rocket/rsusr/ported/bin/bash"
bash="/u/zopen/usr/local/bin/bash"
echo "shell $SHELL bash $bash"
if [[ $SHELL != $bash ]]
then
echo "using the bash shell"
export SHELL="$bash"
exec "$bash" # replace the current script with bash
# any code after the exec is not executed
fi
fi

which says. If the $SSH_CLIENT variable is not the empty string, (the session came in over an ssh connection) then invoke $bash, and it replaces the current environment with the /u/zopen/usr/local/bin/bash.

With this I could use both sshfs for remote file access, and ssh for terminal access.

If there are better ways of doing this, please let me know

OMVS is the way ahead!

If you have any suggestions in this area – please let me know!

I recently found this article which covers the same ground with more/better explanations.

With lots of development of open source tools for OMVS on z/OS, I thought I would try it out. I’ve been amazed at how good it is. This blog post is “one liners” to help people get started and over the initial hump to moving towards this. I’ll add more blog posts as I go further down the path.

My original task was to develop some Python scripts to extract profiles from RACF. I use Ubuntu Linux on my laptop.

I used to use OMVS from ISPF, because I thought the interface through SSH was poor in comparison. I now think that the OMVS interace is limited compare to the SSH interface, because of all of the enhancements and packages available to it.

One example is I use the “less” command on Linux very frequently. This does not work with ISPF OMVS, but it is available through SSH.

See Setting Up the z/OS UNIX Shell (Correctly & Completely) for an excellent article on moving to OMVS though SSH.

Editing is easy

  • Create a mountpoint on your laptop.
  • use sshfs colin@10.1.1.2: ~/mountpoint
  • use vscode to edit the files. This is a very popular editor/IDE.
  • you have to be careful of tagging the file. Create a file using touch, then use “chtag -t -c ISO8859-1 filename “, and then edit it. It is editable in vscode and ISPF (but not at the same time of course). Yesterday the files needed the tag ISO8859-1, today they only work without the tag! ( chtag -r newtry.py) – I do not know what has changed!

I used other tools such as diff, from my laptop to files in my z/OS Home directory.

You can install packages like zowe on z/OS and use vscode to edit files and datasets from lists, to issue z/OS commands, and look at spool. This is a heavy weight package, but is very popular. The editing via sshfs is very easy.

Install zopen

zopen is a set of packages ported from open source. It was easy to install.

I used zopen install … to install packages. I used

  • zopen install which, this tells you the full path of a command
  • zopen install less, less is a fast display of a file in a terminal, with search capability. It is often faster than an editor/browser. Less is a more advanced version of the more command. The more command allows you to page through a file.

Use the bash or zsh shell

In my OMVS userid profile I set PROGRAM(/u/zopen/usr/local/bin/bash) This version of bash has proper key support. For example delete really does delete characters. For the Rocket port of bash the delete key is a dead key.

If your delete key does not work on the command line

Use the zopen bash shell, PROGRAM(/u/zopen/usr/local/bin/bash) or the zsh shell PROGRAM(/bin/zsh).

Logon

Use a command like ssh colin@10.1.1.2 to get to z/OS. You can configure SSH and transfer a key file to z/OS, so you can logon without a password.

Using the right shell

The default borne shell is so back level. You should use bash or zsh.

bash

You should use bash from zopen. Use PROGRAM(/u/zopen/usr/local/bin/bash) in your RACF profile. Use bash from zopen because this has more function than Rocket’s bash – and the delete key works as expected.

zsh

Many people recommend zsh. Use program(/bin/zsh) in your RACF profile to use it. See Oh My Zsh or: How I Learned to Stop Worrying and Love the Shell to a good introduction to zsh extensions. For example there are sudo, and a git interface.

Issuing TSO commands

You can use the tsocmd to issue a command and get a response back

tsocmd "LU COLIN" |less

you can then page through the output.

Command complete

Bash and zsh have command completion.
if you type zopen [tab] [tab] it will display the options available for the zopen command

You can use ls [tab] [tab] to display all the files in the current directory

RACF

I’ve been using the Python interface (pysear) to RACF to display information, and manage profiles. It’s great and very flexible.

SDSF

There is a python interface to sdsf, available in z/OS 3.1, but it is not available in the 3.1 images I have.

My ~/.profile

export _BPXK_AUTOCVT=ON
export _CEE_RUNOPTS="FILETAG(AUTOCVT,AUTOTAG) POSIX(ON)"
export _TAG_REDIR_ERR=txt
export _TAG_REDIR_IN=txt
export _TAG_REDIR_OUT=txt
export CXX="/bin/xlclang++"
export CC="/bin/xlC"
export CC="/bin/xlclang++"
export PATH=${PATH}:/bin
export PATH=${PATH}:/u/colin/.local/bin
export PATH=${PATH}:/u/tmp/zowep/bin/
export PATH=${PATH}:/usr/lpp/IBM/cyp/v3r12/pyz/bin
export LIBPATH=${LIBPATH}:/usr/lpp/IBM/cyp/v3r12/pyz/lib
. /u/zopen//etc/zopen-config --override-zos-tools
# if Ive come in from SSH....
if [[ -z "$SSH_CLIENT" ]]
then
# dummy
xxx="$SSH_CLIENT"
else
set -x
zopenkw="alt audit build clean compare-versions compute-builddeps \
config-helper create-cicd-job create-repo diagnostics \
generate help2man info init install md2man migrate-buildenv \
migrate-groovy promote publish query remove split-patch \
Cupdate-cacert usage version whichproject "
echo $kw
complete -W "$zopenkw " zopen
fi

That’s as far as I’ve got.

Keeping people out of the master catalog.

I had written Here’s another nice mess I’ve gotten into! My master catalog is full of junk which describes what I did once I found my master catalog was full of stuff which should not be there.

I’ve now got round to finding out how to stop people from putting rubbish there in the first place!

See One minute mvs: catalogs and datasets for an introduction to master and user catalogs.

The master catalog should have some system datasets, aliases, and not much else.

An alias says for this high level qualifier (COLIN) go to the usercatalog(‘USER.COLIN.CATALOG).

A catalog is a dataset, and you can use a RACF profile to protect it, so only authorised people can update it. Typically, when you define a userid or a high level qualifier, you should also define an alias for that userid (or HLQ), pointing to a user catalog.

To keep user data out of the master catalog you need

  • one or more user catalogs – for example do you give each user their own catalog, have one per deparment, or one for all users. These catalogs are typically defined by storage administrators (or automation set up by storage administrators).
  • an alias for each userid and the name of the catalog that userid should use. These aliases are set up by people (or automation) which defines userids.
  • an alias for each dataset High Level Qualifier (HLQ) and the name of the catalog that the HLQ should use. These aliases are set up by people (or automation) which defines the high level qualifiers. An example HLQ is CEE, or DB2.

If you migrate to a system with a new master catalog (for example with zPDT or zD&T), you will need to import the usercatalogs into the master catalog, and redefine the aliases.

Import a user catalog

When I tried to import a user catalog into the master catalog, I got

 ICH408I USER(COLIN   ) GROUP(TEST    ) NAME(CCPAICE             ) 
CATALOG.Z31B.MASTER CL(DATASET ) VOL(B3SYS1)
INSUFFICIENT ACCESS AUTHORITY
FROM CATALOG.Z31B.* (G)
ACCESS INTENT(UPDATE ) ACCESS ALLOWED(READ )

so any userid importing or exporting a catalog needs update access to the catalog.

Defining and deleting an alias

Having set up RACF profiles, and given my userid COLIN only READ access to the master catalog, I found my userid could still define and delete aliases. It took a couple of days to find out why.

  • If a userid has ALTER access to CLASS(FACILITY) STGADMIN.IGG.DEFDEL.UALIAS the userid can define and delete ALIAS profiles. This overrides dataset access checks.
  • If a userid does not have ALTER access to the profile, then normal dataset checks are made.

What I learned…

  • My userid had “special”. As the documentation says The RACF SPECIAL attribute allows you to update any profile in the RACF database. This meant I could display and update any profile.
  • There is a profile class(facility) STGADMIN.IGG.DEFDEL.UALIAS which allows you to define and delete user aliases in the (master) catalog
  • If my userid had SPECIAL, or the userid was in group SYS1 I could issue the command

rlist facility STGADMIN.IGG.DEFDEL.UALIAS

and it gave

CLASS      NAME
----- ----
FACILITY STGADMIN.IGG.* (G)
LEVEL OWNER UNIVERSAL ACCESS YOUR ACCESS WARNING
----- -------- ---------------- ----------- -------
00 IBMUSER NONE ALTER NO

USER ACCESS
---- ------
SYS1 ALTER
IBMUSER ALTER

If my userid did not have special and was not in SYS1, I got

ICH13002I NOT AUTHORIZED TO LIST STGADMIN.IGG.*

When my userid was connected to the group SYS1, it got the ALTER access to the profile, and overrode the RACF profiles for the catalog data set.

Which is my master catalog?

At IPL, it reports

IEA370I MASTER CATALOG SELECTED IS CATALOG.Z31B.MASTER 

You can use the operator command D IPLINFO

SYSTEM IPLED AT 07.26.58 ON 01/02/2026                                              
RELEASE z/OS 03.01.00 LICENSE = z/OS
USED LOADCP IN SYS1.IPLPARM ON 00ADF

My load parm member, SYS1.IPLPARM(LOADCP) has

IODF     99 SYS1 
INITSQA 0000M 0008M
SYSCAT B3SYS1113CCATALOG.Z31B.MASTER
SYSPARM CP
IEASYM (00,CP)

The catalog is called CATALOG.Z31B.MASTER and is on volume B3SYS1

Does a RACF profile exist?

See What RACF profile is used for a data set?

tso listdsd dataset(‘CATALOG.Z31B.MASTER’)
tso listdsd dataset(‘CATALOG.Z31B.MASTER’) generic

Showed there was no profile defined.

Create the profile

* DELDSD  'CATALOG.Z31B.*'                                   
ADDSD 'CATALOG.Z31B.*' UACC(READ)
PERMIT 'CATALOG.Z31B.*' ID(IBMUSER ) ACCESS(CONTROL)
PERMIT 'CATALOG.Z31B.*' ID(COLIN ) ACCESS(READ )

When I tried to use the master catalog from a general userid the request failed.

DELETE TEST  ALIAS                                                                                                 
IDC3018I SECURITY VERIFICATION FAILED+
IDC3009I ** VSAM CATALOG RETURN CODE IS 56 - REASON CODE IS IGG0CLFT-6
IDC0551I ** ENTRY COLIN.TEST NOT DELETED
IDC0014I LASTCC=8

Hmm that’s strange

With userid COLIN, I could still issue commands, such as DELETE TEST ALIAS, even though I had given it only read access.
If I displayed the profile from userid COLIN it had

 INFORMATION FOR DATASET CATALOG.Z31B.* (G)

LEVEL OWNER UNIVERSAL ACCESS WARNING ERASE
----- -------- ---------------- ------- -----
00 COLIN READ NO NO
YOUR ACCESS CREATION GROUP DATASET TYPE
----------- -------------- ------------
READ SYS1 NON-VSAM

This had me confused for several hours. That’s when I found out about the presence of the STGADMIN.IGG.DEFDEL.UALIAS profile.

Summary

You want users (non system) datasets to be in a user catalog, rather than the master catalog. This makes migrating to a new master catalog much easier, You just have to import the catalogs, and redefine the aliases.

You need to set up

  • one (or more) user catalogs
  • aliases to connect the userid (and High Level Qualifiers) to a catalog
  • give authorised used alter access to class(facility) STGADMIN.IGG.DEFDEL.UALIAS to allow them to maintain aliases.
  • define a RACF profile for the master catalog and make the UACC(READ).
  • for those people who need to need to define, import or export catalogs, they need update access to the master catalog dataset.

How do I use updated libraries in the linklst?… and then whoops

I have an updated C run time library. How do I test it on z/OS, bearing in mind the libraries are in the linklist (dataset available to every one), and I want to use them from Unix.

You can refresh the Linklist, by creating a new definition using console commands, and activating it.

Because you may need to update more that one library as part of the update, you update the definitions, then activate them. If you update linklist one data set at a time, you could get inconsistent libraries in the link list for a short period.

You have one active (current list) and can have multiple other list definitions.

You can

  • copy the current definitions
  • add data sets
  • remove data sets
  • activate a definition

To display what is in the current link list you can use the SDSF option LNK, or use the operator command D PROG,LNKLST

D PROG,LNKLST                               
CSV470I 12.06.05 LNKLST DISPLAY 605
LNKLST SET LNKLST00 LNKAUTH=LNKLST
ENTRY APF VOLUME DSNAME
1 A B3RES1 SYS1.LINKLIB
2 A B3RES1 SYS1.MIGLIB
3 A B3RES1 SYS1.CSSLIB
4 A B3RES1 SYS1.SIEALNKE
5 A B3RES1 SYS1.SIEAMIGE
6 A B3RES1 SYS1.SHASLNKE
7 A B3RES1 SYS1.SERBLNKE
8 A B3RES1 SYS1.SGRBLINK
9 A B3RES1 SYS1.SHASMIG
10 B3RES1 SYS1.SCBDHENU
...

Note: Some of these are APF authorised.

You can display what lists are active using the command

D PROG,LNKLST,NAMES

This gave

CSV472I 19.25.26 LNKLST DISPLAY 848             
LNKLST SET LNKLST SET LNKLST SET LNKLST SET
LNKLST00 COLIN

To create a new definition called MY based on my current defintion; and activate it

SETPROG LNKLST,DEFINE,NAME=MY,COPYFROM=CURRENT
SETPROG LNKLST,ADD,NAME=MY,DSN=CEE.SCEERUN.NEW
SETPROG LNKLST,delete,NAME=MY,dsname=CEE.SCEERUN
SETPROG LNKLST,ADD,NAME=MY,DSN=CEE.SCEERUN2.NEW
SETPROG LNKLST,delete,NAME=MY,dsname=CEE.SCEERUN2
SETPROG LNKLST,ACTIVATE,NAME=MY

You can put these statements in a parmlib member PROGxx see here, and then activate them using the operator command

t prog=xx

Or you can issue these as operator commands.

How do jobs get the new libraries

This is a more subtle than I first thought.

From my TSO userid COLIN, I went into Unix and issued a Python command, and the command now worked, so I was picking up the libraries. Round of applause – job done.

I then checked my ISPF session. The command ISRDDN displays the datasets allocated to ISPF. The lnk command, shows what is defined in the lnklst. This showed

B3RES1              >    LINKLIST SYS1.LINKLIB               
B3RES1 > SYS1.MIGLIB
...
B3RES2 > CEE.SCEERUN
...
B3RES2 > CEE.SCEERUN2

so my main ISPF task was unchanged.

I used the command

setprog LNKLST,UPDATE,JOB=COLIN
CSV504I JOB COLIN IS NOW USING THE CURRENT LNKLST SET

to update the COLIN job, and then the ISRDDN LNK gave

B3PRD1              >    LINKLIST FAN140.SEAGLMD        
...
USER08 *SMS > CEE.SCEERUN.NEW
B3USR1 *SMS > CEE.SCEERUN2.NEW

which has update the COLIN job.

Logging on with a different userid, it got the updated definitions.

I tried to logon using SSH, and this failed with messages on the console

BPXP024I BPXAS INITIATOR STARTED ON BEHALF OF JOB SSHD1 RUNNING I
004B
ICH408I USER(OMVSKERN) GROUP(OMVSGRP ) NAME(OMVSKERN )
CSFIQA CL(CSFSERV )
WARNING: INSUFFICIENT AUTHORITY - TEMPORARY ACCESS ALLOWED
FROM CSF* (G)
ACCESS INTENT(READ ) ACCESS ALLOWED(NONE )
ICH420I PROGRAM CEEBINIT FROM LIBRARY CEE.SCEERUN.NEW CAUSED THE
ENVIRONMENT TO BECOME UNCONTROLLED.
BPXP014I ENVIRONMENT MUST BE CONTROLLED FOR DAEMON (BPX.DAEMON)
PROCESSING.
ICH420I PROGRAM CEEBINIT FROM LIBRARY CEE.SCEERUN.NEW CAUSED THE
ENVIRONMENT TO BECOME UNCONTROLLED.
BPXP014I ENVIRONMENT MUST BE CONTROLLED FOR DAEMON (BPX.DAEMON)
PROCESSING.

This is because the CEE.SCEERUN was APF authorised, and CEE.SCEERUN.NEW was not APF authorised.

I dynamically APF authorised them

SETPROG APF,add,DSN=CEE.SCEERUN2.NEW,SMS 
SETPROG APF,add,DSN=CEE.SCEERUN.NEW,SMS

SSH failed the same way.

The easiest thing for me to do on my system was Re-IPL.

Once you’ve done the activate

Thanks to Todd Burch  for reminding me that you need to refresh the Link List Lookaside(LLA).

f lla,refresh

Any new jobs will use the updated LNKLST.

Previously running jobs will continue to use the old LNKLST, unless you tell the the jobs, they can use the new LNKLIST, with the UPDATE option.

 setprog LNKLST,UPDATE,JOB=* 

It is still not that simple…

Todd Birch told me

The process documented by IBM leaves some room for interpretation, unfortunately. After a COPYFROM=CURRENT, I DELETE the old DSNAME and then ADD the new DSNAME. I prefer to use BEFORE or AFTER to put the new DSNAME back in the same place, otherwise, the ADD defaults to the end of the linklist concat.

Also, we use shared dasd, so we tend to use the same dataset names when we delete and re-add. Our process is to IEBCOPY w/replace the old library from our build system (via shared dasd), then on the testing system, stop LLA, define a new LL with COPYFROM=CURRENT, then delete the old DSNAME lib, then re-add the same name using BEFORE or AFTER to keep the concatenation as before**, and then activate and update and then restart LLA.

**it’s typical for us to have both a test library allocated just prior to a production library, akin to

MY.TEST.PRODUCT.LIB
MY.PROD.PRODUCT.LIB

and since we are testing a new test lib, we delete MY.TEST.PRODUCT.LIB and then add it back BEFORE MY.PROD.PRODUCT.LIB.

Whoops

When I tried to use these new libraries I got

ICH420I PROGRAM CEEBINIT FROM LIBRARY CEE.SCEERUN.NEW CAUSED THE
ENVIRONMENT TO BECOME UNCONTROLLED.
BPXP014I ENVIRONMENT MUST BE CONTROLLED FOR DAEMON (BPX.DAEMON)
PROCESSING.

when trying to use SSHD. Because the SSH Daemon is a special program, in that it changes userid to that in the request, it has extra security controls.

It took me a few minutes to understand how to do this.

Background

You need a statement like

RDEFINE PROGRAM CEEBINIT -
ADDMEM('CEE.SCEERUN.NEW'/USER08/NOPADCHK) UACC(READ)

Which sets up the additional security for the program CEEBINIT in the specified library.

However this is not enough, as there are other programs than need to be controlled as well.
You do not use RDEFINE PROGRAM * ADDMEM(‘CEE.SCEERUN.NEW’…. (That would be too simple).

There is (usually) a profile RDEFINE PROGRAM *… define. You have to extend this using

RDALTER PROGRAM *  -
ADDMEM('CEE.SCEERUN.NEW'/USER08/NOPADCHK) UACC(READ)
RDALTER PROGRAM * -
ADDMEM('CEE.SCEERUN2.NEW'/B3USR1/NOPADCHK) UACC(READ)

With the command RLIST PROGRAM * it gave me

CLASS      NAME                                                           
----- ----
PROGRAM *

MEMBER CLASS NAME
------ ----- ----
PMBR

DATA SET NAME VOLSER PADS CHECKING
-------------------------------------------- ------ -------------
BBO401.SBBOLOAD NO
CBC.SCLBDLL NO
CEE.SCEERUN NO
CEE.SCEERUN ****** NO
CEE.SCEERUN2 NO
CEE.SCEERUN2 ****** NO
CEE.SCEERUN2.NEW B3USR1 NO
COLIN.LOAD2 ****** NO
...

Unix services automount is a blessing and curse.

If someone logs on to z/OS and uses Unix Services they need a home directory. By default it may be /u. This is not a good idea because they could fill up the disk space and prevent other people from doing any work in /u. Automount can create a ZFS for a directory if the directory such as /u/colin does not exist.

Lionel Dyck has a good write up on automount.

The blessing

With automount you can configure a file which says when I logon with a home directory of /u/colin, and this does not exist then allocate a dataset and mount it. For example it allocated a ZFS called OMVS.USER.COLIN.ZFS. You can control the name and size of the ZFS.

The curse

I wanted to mount an existing ZFS on /u/zopen. I created /u/zopen, then mounted the file system on it – but it said /u/zopen as in use!

I had a BPXPRMUS member in parmlib which mounted my file systems.

MOUNT TYPE(ZFS) 
MODE(RDWR)
NOAUTOMOVE
MOUNTPOINT('/u/tmp')
FILESYSTEM('COLIN.ZFS2')

MOUNT FILESYSTEM('COLIN.ZFS.ZOWE.PROD') TYPE(ZFS)
MOUNTPOINT('/u/tmp/zowep') MODE(RDWR)
PARM('AGGRGROW') AUTOMOVE

MOUNT FILESYSTEM('COLIN.ZOPEN.ZFS') TYPE(ZFS)
MOUNTPOINT('/u/zopen') MODE(RDWR)
PARM('AGGRGROW') AUTOMOVE

When I activated this member with

T OMVS=(US)

I got

BPXO032I THE SET OMVS COMMAND WAS SUCCESSFUL.             
BPXF236I FILE SYSTEM COLIN.ZFS2 WAS NOT MOUNTED.
THE MOUNT POINT SPECIFIED IN BPXPRMUS ALREADY HAS
FILE SYSTEM OMVS.USER.TMP.ZFS MOUNTED ON IT.

BPXF236I FILE SYSTEM COLIN.ZOPEN.ZFS WAS NOT MOUNTED.
THE MOUNT POINT SPECIFIED IN BPXPRMUS ALREADY HAS
FILE SYSTEM OMVS.USER.ZOPEN.ZFS MOUNTED ON IT.

I could not mount under /u – because it created the file systems.

The ZOWE file system did mount, because it was mounted under /u/tmp which was not covered by automount.

What controls it?

There is a file /etc/auto.master which controls what directories are automounted.

Mine ( a very simple one) has

/u /etc/auto.map 

Which says for the /u directory enable automount and see the file /etc/auto.map. This file has

name * 
type ZFS 
filesystem OMVS.USER.<uc_name>.ZFS 
mode rdwr 
delay 0 
duration 5 
parm FSFULL(50,5) 
allocany space(20,50) cyl vol(XXXVS1) pathperm(755) euid 

Where

  • name * is a generic (or specific) file
  • delay 0 The minimum amount of time in minutes to leave the file system mounted after the duration expires and the file system is no longer in use. The default is 10 minutes.
  • duration 5 the minimum amount of time in minutes to leave the file system mounted. The default is nolimit.
  • <uc_name> is used to represent the name in uppercase characters. This creates COLIN from “colin”
  • <asis_name>used to represent the name exactly, as is.

Turning it off

Lionel’s document explains how to enable it.

I tried changed the file /etc/auto.master to have a different directory to /u, which mostly worked. Some tasks depending on the auto-mount behaviour, and didn’t work.

I compromised. I used automount, but instead of using the /u/zopen directory, I used /u/tmp/zopen etc and the mounts worked.

Updating the I/O configuration for zD&T (zPDT)

Initial comments

As part of the move from the ADCD provided systems to the standard image, I found that existing device map with not migrated to the new system. This challenge gave me the opportunity to learn about configuring the I/O subsystem and Hardware Configuration Definition (HCD) for ZD&T, zPDT and the standard image.

Concepts

The I/O configuration is pointed to by the LOAD member in SYS1.IPLPARM or SYS0.IPLPARM

For example

*---+----1----+----2----+----3----+-
IODF 05 PROV DEFAULT 00
...

Where the columns are important. This would use dataset PROV.IODF05 and look for system DEFAULT.

The names of the production IODFs are id.IODFnn where nn is 00 to 99

You can display the currently active HCD by using operator command

Activate test

To configure the HCD you use ISPF. On my system to get to the HCD application you need option 12;2

  • 12 z/OS System z/OS system programmer applications
  • 2 HCD HCD I/O configuration

When working with HCD you cannot update the currently active, you use a working dataset, and create a new IODF image at the end.

With input fields ending in a +, you can use PF4 to display the available options.

Basic configuration

You define a device range, for example 0700 for 16 units; and the device type 3277.
For these to be visible in z/OS the devices must be connected to an operating system definition. I spent many an hour trying to work out why my newly configured DASD was not in my z/OS system – it was because I had not connected the devices.

Print the configuration

Once you have made changes, you should print the configuration and check they are as you expect, for example the devices are connected to the operating system.

//IBMHCD JOB MSGCLASS=H 
//GCREP EXEC PGM=CBDMGHCP, 
// PARM='REPORT,CSMEN,,,,,00' 
//HCDIODFS DD DISP=SHR,DSN=PROV.IODF06 
//* DIODFS DD DSN=PROV.IODF05,DISP=SHR 
//HCDRPT DD SYSOUT=H, 
//    DCB=(RECFM=FBA,LRECL=200,BLKSIZE=6400) 
//HCDMLOG DD SYSOUT=H, 
//   DCB=(RECFM=FBA,LRECL=200,BLKSIZE=6400) 

The output is like

                                        DEVICE SUMMARY REPORT             
--- DEVICE --- DEVICE
NUMBER,RANGE TYPE-MODEL ATTACHING CONTROL UNITS
______________ _____________ |____|____|____|____|____|____|____|____|
0700,64 3277-2
0A80,64 3390
0AA0,64 3390
...
OPERATING SYSTEM SUMMARY REPORT
OPERATING D/R
SYSTEM ID TYPE GEN DESCRIPTION OS I
_________ ________ ___ ________________________________ ____
DEFAULT MVS Default OS Config
MVS DEVICE REPORT
OPERATING SYSTEM CONFIGURATION ID: DEFAULT
DEV#,RANGE TYPE-MODEL SS BASE UCB-TYPE ...
__________ _____________ __ ____ ________ ...
0700,64 3277-2 0 12001009 ...
0AA0,64 3390 0 3030200F ...

and note device range 0A80 for 64 is not in the DEFAULT system configuration. At IPL this range of devices will not be there.

What is my current configuration?

The operator command ACTIVATE TEST gives

activate test                                                           
...                             
IEF196I IEF285I   PROV.IODF05                                  KEPT     
IEF196I IEF285I   VOL SER NOS= OPEVS1.                                  
IEF196I IEF285I   PROV.IODF05                                  KEPT     
IEF196I IEF285I   VOL SER NOS= OPEVS1.                                  

Configuring the HCD

ISPF 12;2 gave me

                           Hardware Configuration                   
                                                                    
Select one of the following.                                        
                                                                    
1   0.  Edit profile options and policies                           
    1.  Define, modify, or view configuration data                  
    2.  Activate or process configuration data                      
    3.  Print or compare configuration data                         
    4.  Create or view graphical configuration report               
    5.  Migrate configuration data                                  
    6.  Maintain I/O definition files                               
    7.  Query supported hardware and installed UIMs                 
    8.  Getting started with this dialog                            
    9.  What's new in this release                                  
                                                                    
For options 1 to 5, specify the name of the IODF to be used.        
                                                                    
I/O definition file . . . 'PROV.IODF04'____                   +  
  • At the bottom, I/O Definition file – put the cursor in the input field and press PF4, to display the available files.
  • Select 1 Define, modify, or view configuration data.

This gives lines with

  • The start address, and count. For example DE00, for 41 ( so address range DE00 to DE40)
  • The device type: 3390
  • OS 1… connected to the 1st system definition. If this is blank it is not connected,
  • Press PF11 to add a device (or put D in the line command for an entry to delete an entry). This may display

This is creating a work file, so you do not update the currently active one. Specify the volser

You will get

Specify an address, and a count of addresses. Put the cursor in the Device type input file and press PF4 ( as indicated by the + sign at the end of the field).

This gives

This is the list of systems you can connect the I/O devices to. Put a / in front of the config id (DEFAULT) and press enter. This gives

Select 1 because you want to connect the device to the DEFAULT system.

This gives

You can customise the options. Each device type has different options. Press enter till you get back to the I/O Device List (with your address range added).

Generate the production IOCD

From the initial panel select option 2. Activate or process configuration data, and specify the work dataset.

The I/O definition dataset name at the bottom should be the one you are currently working with. You can use PF4 to display the datasets names you have worked with.

Enter a new data set name, such as PROD.IODF08, and the volume serial. (I think this is the same volume as your SYSn.IPLPARM dataset.

Press enter for

Print the IODF using the JCL above.

Update your LOADXX member with the new number, and when you next IPL the changes should be active. ( I created a new LOADYY member, so I could go back to the old IODF if I had problems.)

What systems and consoles are defined?

You can define consoles in the IOCD – you still need to have the z/OS CONSOLE definition.

From the HCD main panel, select

  • 1. Define, modify, or view configuration data
  • 1. Operating system configurations

if you select the default configiguration with / and press enter it gives

You can either select by number, or note the letter at the end of the line. Work with console -> n.

You can specify this command (‘n’) in

to go directly to the console definitions.

This gives

so you can see there are two console defined. One at address 0060, the other at address 0061.

The old zD&T IODF

The IODF from the ZD&T IODF is below. Ive simplified it – replacing 0700,1; 0701,1; 0702,1 etc with 0700,64.

----------Device------ --#--- --------Control Unit Numbers + --------      

 / Number   Type +       CSS OS 1---
 _ 000C     2540                 ____
 _ 000C     2540R-1           1  ____
 _ 000E,2   1403-N1           1  ____
 _ 0120     3380             64  ____
 _ 01C0,64  3390                 ____
 _ 0240,32  3380                 ____
 _ 0260,32  3390                 ____
 _ 0300,25  3390              1  0300
 _ 0400,16  OSA               1  ____
 _ 0550,16  3420-8            1  ____
 _ 0560,16  3480              1  ____
 _ 0580,16  3490              1  0580
 _ 0590,16  3590              1  0590
 _ 0600,16  3390              1  ____
 _ 0900     3270-X           32  ____
 _ 0A80     3390             64  ____
 _ 0E20     CTC               4  ____
 _ 0E40     CTC               4  0E40
 _ 1A00,256 3390              1  ____
 _ 2A00,256 3390              1  ____
 _ 3A00,256 3390              1  ____

Do I really want to restore these datasets? – let me check first.

I needed to restore a product which had shipped files in ADRDSSU BACKUP format.

Before following the instructions and creating lots of files, I thought it would be useful to see what’s going to happen. You can do this by specifying

//S2 EXEC PGM=ADRDSSU,REGION=0M,PARM='TYPRUN=NORUN'

This shows you what will happen, but does not do any of the work.

My JCL was originally

//S1      EXEC PGM=AMATERSE,PARM=UNPACK 
//SYSPRINT DD SYSOUT=*
//SYSUT1 DD DISP=SHR,DSN=COLIN.PROD.TRS
//SYSUT2 DD DSN=&&TEMP,SPACE=(CYL,(500,500)),DISP=(,PASS)
//*

//S2 EXEC PGM=ADRDSSU,REGION=0M,PARM='TYPRUN=NORUN'
//SYSPRINT DD SYSOUT=*
//DD1 DD DISP=SHR,DSN=*.S1.SYSUT2
//SYSIN DD *
RESTORE -
IMPORT -
INDDNAME(DD1) -
CANCELERROR -
DATASET(INCLUDE(**)) -
RENAMEU( -
(**.PRODANLC,COLIN.PRODANLC) -
(**.PRODANLE,COLIN.PRODANLE) -

...

The output had

ADR489I (001)-TDLOG(01), DATA SET COLIN.PRODANLC WAS SELECTED         
ADR489I (001)-TDLOG(01), DATA SET COLIN.PRODANLE WAS SELECTED


This would create datasets like COLIN.PRODANLC which I did not want to use.
I wanted to include the version and release so I used

(**.PRODANLC,COLIN.PROD321.PRODANLC) - 
(**.PRODANLE,COLIN.PROD321.PRODANLE) -

and my files came out COLIN.PROD321.PRODANLC etc.

This saved me a lot of time – having to delete many data sets with the wrong name.

Whoops – I should have defined a security profile.

When I restored from the backup, the output included

ADR755W (001)-PROTD(01), SOURCE DATA SET BETA.PROD.OUT.PRODANLC WAS GENERICALLY PROTECTED. THE TARGET DATA SET COLIN.PROD321.PRODANLC IS NOT PROTECTED BY ANY PROFILE                                        

I defined a RACF profile

tso addsd 'COLIN.PROD321.**' uacc(NONE)  

and when I retested it I did not get the ADR755W messages.

You should define the profile before you restore the files. If you do not, there is a small chance that someone could change the unprotected file. If you define the profile first – the file is protected from the moment it is created.

Linux mapping the keyboard, and on z/OS SSH

I wanted to configure the keyboard in zsh and bash on z/OS so the delete key (top right of the keyboard) deleted the current character. (Backspace deletes the previous character) I could not find any good documentation on how to do it.

I found some bash for Linux documentation and have based this blog post on that. I’ve given the command I used, then sections on the background of how it works.

Note the binding of key to action depends on the shell. The shells zsf and bash support binding. shell does/may not.

Having written the original blog post, I found some additional useful information which will make the document clearer.

How to set the delete key to delete

With my Bash shell, I initially had to do it in stages:

  • Type bind “ that’s bind space double quote
  • Control+V, delete key to insert the value of the key. This made it bind “^[[3~
  • Type “:delete-char with no space after the :
  • It now looks like bind “^[[3~”:delete-char
  • Press enter
  • The delete key should delete the character under the cursor

The command bind -p |grep delete gave

"\C-h": backward-delete-char
"\C-?": backward-delete-char
"\C-d": delete-char
"\M-[3~": delete-char
"\\": delete-char
# delete-char-o

Which shows that Ctrl+d and \\ also deletes the current character.

In a shell (in ASCII) this is (in ISPF edit with hex on)

bind '" ∇3~":delete-char' 
6666222153723666676266672222
29E4072BB3E2A45C545D38127000

Where the incantation is x1b5b337e.

What does the mapping mean?

It took me many hours of looking for a good description of what the key mapping is.

The Wikipedia page ANSI escape codes, was very helpful and clear.

  • You can press the “a” key – and “a” is displayed in the command window.
  • You can press shift “a” – and “A” is displayed in the command window
  • You can press Control (Ctrl) “a” – and this may do something
  • You can press Meta “the Windows” key “a” and this may do something
  • You can press Alt + “a” and it may do something.
  • You can press combinations of those keys, such as Ctrl+shift + “a” and this may do something.

The operating system may intercept the key and not pass it to the window. For example on my Linux, Ctrl+Alt+Delete is logout.

In the command window the shell code will intercept a key press combination and take an action, for example move the cursor left, clear the screen, delete word, or just the the character.

You can change the mapping using the bind or bindkeys command for bash and zsf shells.

You can find the code for a key combination by using ctrl+v. For example with the left cursor key

Ctrl+v, < gives ^[[D

How to decode ^[[D ?

There are several formats.

  • <esc>[ number(;modifier)~
  • <esc>[ letters

The string starts with an escape sequence. ^[ This can be written as \e ,\033,  0x1b, or ^[. Where \0 is octal 33, which is hex 1B, (and decimal 27). When specifying a key sequence any of the values can be used. I mentioned above the incantation x1b5b337e.

Because there is no trailing ~ we need to lookup the “[D” in the Wikipedia page section xterm sequences. This has

<esc>[D     - Left 

So for ^[[D we have <esc>, Left key pressed

For ^[[3;5~ we have

  • ^[ is escape
  • [3 isDelete key
  • ; is a modifier
  • 5 is Control + shift
  • ~ end of escape

so the key presses was Control + Delete key (top right on my keyboard). Shift seems to be ignored!

Another popular key is ^M which is Carriage Return – (and process any data on the line) and move the cursor to column 0.

\C is the Ctrl key, \M is the meta key. For keyboards without the Meta key this is displayed as Escape \e.

Keys like \M-OD comes from

Keypad mode
"\M-OD":backward-char
"\M-OC":forward-char
"\M-OA":previous-history
"\M-OB":next-history

This information is not well documented.

What is key mapping

On Linux Ubuntu the control-right arrow combination moves the cursor right one word. The control-left arrow moves the cursor left one word. Control-L clears the screen, but leaves the command line intact.

You can list the possible actions

bind - l

This gave

...
arrow-key-prefix
backward-byte
backward-char
backward-delete-char
backward-kill-line
backward-kill-word
...

Get a list of functions and what keys use them

With upper case -P

bind -P |grep backward

This gave

backward-byte is not bound to any keys
backward-char can be found on "\C-b", "\eOD", "\e[D".
backward-delete-char can be found on "\C-h", "\C-?".

Where does \eOD come from ? See here.

Get a list of keys and their functions in bind format

with lower case -p

bind -p |grep backward

gave

"\eOD": backward-char
"\e[D": backward-char
"\C-h": backward-delete-char
"\C-?": backward-delete-char
...

where

  • Control-h moves the cursor left one character and deletes the character
  • \e is the escape key. The alt key is usually mapped to the escape key by terminal emulators.

This output is slightly untrue. If there is no blank after the : you can use bind….

If you have a blank after the : you need to enclose it in single quotes.

bind ‘”\C-h”: backward-delete-char’

to set the key.

What is the code for a key press combination?

The Linux command Ctrl-V (verbatim insert) followed by a key, gives the mapping for that key.

Ctrl+V LeftArrow
^[[D

Ctrl+V Ctrl+Leftarrrow
^[[1;5D

Where ^[ means the escape key and [D is OD.

^[[3~ is escape Delete key.

Verbatim insert gives the code of the key which was pressed. This works on z/OS if you have the Bash or zsf shell installed.

What keys are mapped?

In the zsh shell you can issue

bindkey -L

(With bash you can use the bind command).

This gives output like

bindkey "^E" end-of-line
...
bindkey "^L" clear-screen

Where ^ is the ctrl key.

If you type (on Linux) man bash , and locate Readline Command Names if lists the function names and what they mean.

The bash command bind -l lists all of the functions

$ bind -q backward-char
backward-char can be invoked via "\C-b", "\M-OD", "\M-[D".

It gets very confusing

A sequence can be created in different formats. For example many commands begin with the Escape (or Meta key). This can be written as \e ,\033,  0x1b, or ^[. Where \0 is octal 33 which is hex 1B, ( or decimal 27). It is confusing when you display information with different commands.

Where does \eOD (or \M-OD)come from?

It was a challenge to find this information.

In the Linux terminfo documentation it says

The codes sent by the left arrow, right arrow, up arrow, down arrow, and home keys can be given as kcub1, kcuf1, kcuu1, kcud1, and khome respectively. If there are function keys such as f0, f1, …, f10, the codes they send can be given as kf0, kf1, …, kf10. If these keys have labels other than the default f0 through f10, the labels can be given as lf0, lf1, …, lf10.

The linux command infocmp

infocmp|grep kcu 

gave

kcbt=\E[Z, kcub1=\EOD, kcud1=\EOB, kcuf1=\EOC, kcuu1=\EOA,

so this all says the left arrow key maps to backward character. – Phew

Problems

If there was a space after the : I got

readline: delete-char: no key sequence terminator

from the bind command.

Putting the command into my .profile file didn’t work because of the wrong character set.

I could put the command into a shell script, and invoke it – but I could not get it to work from the .profile.