notesassorted ramblings on computer

Statically-linked OpenBSD ksh for SSH Hosts

I spent the majority of my time at the computer in a terminal running shell commands. Occasionally, I run these shell commands on systems that I do not administer myself via SSH. In these cases, I still want to use my preferred shell: OpenBSD ksh. Unfortunately, contrary to bash or zsh, ksh is (a) not as widely packaged and (b) not as widely installed.

Exec’ing into a static ksh

Luckily, ksh can be easily compiled into a single self-contained binary, which I usually drop in ~/bin. This binary can then be executed from whatever the configured login shell is, for example, via the following ~/.bash_profile:

if [ "$(uname -s)" = "Linux" -a -x "${HOME}/bin/ksh" ]; then
	exec env SHELL="${HOME}/bin/ksh" "${HOME}/bin/ksh" -l
fi

Obtaining such a fully statically-linked ksh binary for Linux is straightforward using the community-maintained loksh port. Though, it presupposes that the static libraries of required dependencies are installed on the host. For example, on Alpine Linux, the ncurses-static package is needed.

$ git clone --recursive https://github.com/dimkr/loksh
$ cd loksh
$ CFLAGS="-Os" LDFLAGS="-static" meson setup --buildtype=plain . output
$ meson compile -C output/

Dealing with Bashisms in /etc/profile

Some servers assume that everyone uses bash and therefore facilitate features not compatible with POSIX shell in /etc/profile. This will cause issues with ksh login shells. As a last resort, it can therefore be useful to remove loading of /etc/profile from the statically-linked executable by applying the following patch:

diff --git a/main.c b/main.c
index b011b22..30a92ad 100644
--- a/main.c
+++ b/main.c
@@ -405,7 +405,6 @@ main(int argc, char *argv[])
 		warningf(false, "Cannot determine current working directory");
 
 	if (Flag(FLOGIN)) {
-		include(KSH_SYSTEM_PROFILE, 0, NULL, 1);
 		if (!Flag(FPRIVILEGED))
 			include(substitute("$HOME/.profile", 0), 0, NULL, 1);
 	}