I’m excited to share my journey of porting tmux, a popular terminal multiplexer, to z/OS! This project builds upon my previous experience successfully porting GNU screen and making it available under the z/OS Open Tools umbrella. Following the success of GNU screen, the z/OS community expressed a strong desire for tmux in a recent poll, making it one of the most requested tools for z/OS.
So what is Tmux?
tmux is a terminal multiplexer. It lets you switch easily between several programs in one terminal, detach them (they keep running in the background) and reattach them to a different terminal.
Tmux running on z/OS
Tmux has many advantages over GNU Screen, including mouse integration, supporting terminal splitting into both vertical and horizontal panes, and generally many more configuration options.
Why Tmux on z/OS?
For z/OS users, particularly system administrators and developers, efficient management of multiple shell sessions is critical for efficiency.
Tmux provides the following features:
- Multi-pane Workspaces: Organize your terminal by splitting the window into panes, each running an independent program. This is great when you’re building and editing at the same time like me!
- Detachable Sessions: Leave your work running on z/OS even after disconnecting. Reattach seamlessly from any terminal later. This means you can finish working, sleep and then resume where you left off the following morning.
- Enhanced Workflow: Easily switch between tasks, monitor multiple processes concurrently, and maintain a clutter-free terminal environment. This is one vital for me since I sometimes work on 5+ different tasks during the day.
Why not run tmux on Linux? You can certainly run tmux remotely from a Linux machine to manage your screen sessions, but being able to run it locally on z/OS can reduce latency and is especially good for air-gapped environments.
How do I install it?
Grab it from z/OS Open Tools using the zopen
package manager:
1
zopen install tmux -y
Then run it:
1
tmux
To learn more about the shortcuts, I recommend you read this page.
Porting Tmux to z/OS
Porting tmux to z/OS presented unique challenges due to the underlying differences between z/OS and traditional Unix-like systems. Let’s explore some key areas and the solutions implemented:
-
Missing dependencies: Tmux in itself does not have that many library dependencies. It depends on libevent and ncurses. Fortunately ncurses has already been ported for other projects like Vim and Less so I only had to focus on getting libevent ported.
-
I/O Handling: Standard Unix I/O operations might require special handling on z/OS. We leveraged functionalities provided by ZOSLIB (introduced in the previous blog post) to simplify I/O handling.
Conquering Dependency Challenges:
By leveraging the zopen build framework, I was able to port libevent fairly easily. The port is available at https://github.com/zopencommunity/libeventport. Since libevent is a library, I had to make sure I exposed it as a library when I was adding it as a dependency for Tmux with the following additions to its buildenv file:
1
2
3
4
export ZOPEN_EXTRA_CFLAGS="\${ZOPEN_EXTRA_CFLAGS} -I\$PWD/include"
export ZOPEN_EXTRA_CXXFLAGS="\${ZOPEN_EXTRA_CXXFLAGS} -I\$PWD/include"
export ZOPEN_EXTRA_LDFLAGS="\${ZOPEN_EXTRA_LDFLAGS} -L\$PWD/lib"
export ZOPEN_EXTRA_LIBS="\${ZOPEN_EXTRA_LIBS} -levent"
For a detailed look on how I built it, check out the entire buildenv configuration here https://github.com/zopencommunity/libeventport/blob/main/buildenv.
Now I was ready to build Tmux.
Building tmux
tmux’s buildenv configuration was relatively simple. We added the known dependencies (libevent, ncurses, make, and a few others) and chose the Clang compiler for building. To build it, I used the zopen build
framework.
1
zopen build -v
Unfortunately, tmux had a number of issues at build and runtime and I’ll go through a few of them.
Overcoming the forkpty
hurdle
forkpty
is needed by tmux but is absent on z/OS, so I employed an alternative approach utilizing existing C LE apis. This involved creating a pseudo terminal by opening specific devices and manipulating terminal attributes to simulate a terminal environment for tmux sessions. You can find the patch here.
Testing and Debugging the Build
After testing the build of tmux, I was presented with garbled output immediately! To understand the issue, I leveraged tmux’s -v
option for logging. After further investigation, I realized that the content written to the screen was actually readable and in ASCII format but it wasn’t being converted back to IBM-1047 for the terminal.
The culprit? writev
was not respecting file tags and auto-conversion. This meant the text going to standard output wasn’t being automatically converted to the terminal’s CCSID (IBM-1047).
To resolve this, I modified the libevent code to use write
instead of writev
. This meant I had to create a patch for libevent here.
This enabled tmux to render text correctly, but I wasn’t done yet. The newline characters didn’t seem to register. This resulted in the prompt line being printed without a newline!
After comparing the stty
output from a working terminal to that of the tmux created terminal, I noticed that the flags OPOST and ONLCR were missing. Adding them back in the tmux C code fixed it!
The last major issue was with regards to socketpair. Tmux uses socketpairs instead of pipes for interprocess communication, but socketpairs (as of z/OS 2.4) do not support auto-conversion. Changing the code to use pipes instead of socketpairs fixed this issue!
There’s still a lingering issue when using /bin/sh as the default shell. So for now I set my tmux default shell to bash to overcome it in my $HOME/.tmux.conf
tmux config file as follows:
1
2
3
vim $HOME/.tmux.conf
# Now add the following line
set-option -g default-shell $ZOPEN_PKGINSTALL/bash/bash/bin/bash
For a more involved tmux.config file, you can check mine out here.
Next Steps
There’s still a few issues remaining, but for the most part tmux is pretty much functional. Here’s what remains:
- Resolve issues when using /bin/sh as the default shell
- Migrating the forkpty and writev changes to the common zoslib library
Thank you
Thanks for reading and thanks to Mike Fulton, Haritha D and the z/OS Open Tools contributors!
-
Previous
Exploring ZOSLIB: An open source z/OS library for porting -
Next
Enhancing Vim on z/OS UNIX with Language Server Protocol (LSP) support