Developers’ Weblog

Sponsored by
HostEurope Logo

Developers’ Weblog

⚠ This page contains old, outdated, obsolete, … historic or WIP content! No warranties e.g. for correctness!

All 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38

mksh on Jehanne, a guest post by Shamar

2018-04-15 by tg@
Tags: archaeology debian fun guest mksh pcli

Giacomo Tesio referenced mksh(1) in his annual Jehanne report and provided a guest post (dated 2018-01-09, sorry for posting it this late only) for us on his journey on porting mksh to Jehanne, his Plan 9 derivative operating system. Read on for his story!


MirBSD's Korn Shell on Plan9 Jehanne

Let start by saying that I'm not really a C programmer.
My last public contribution to a POSIX C program was a little improvement to the Snort's react module back in 2008.

So while I know the C language well enough, I do not know anything about the subtliness of the standard library and I have little experience with POSIX semantics.

This is not a big issue with Plan 9, since the C library and compiler are not standard anyway, but with Jehanne (a Plan 9 derivative of my own) I want to build a simple, loosely coupled, system that can actually run useful free software ported from UNIX.

So I ported RedHat's newlib to Jehanne on top of a new system library I wrote, LibPOSIX, that provides the necessary emulations. I wrote several test, checking they run the same on Linux and Jehanne, and then I begun looking for a real-world, battle tested, application to port first.

I approached MirBSD's Korn Shell for several reason:

  • it is simple, powerful and well written
  • it has been ported to several different operating systems
  • it has few dependencies
  • it's the default shell in Android, so it's really battle tested

I was very confident. I had read the POSIX standard after all! And I had a test suite!
I remember, I thought "Given newlib, how hard can it be?"

The porting begun on September 1, 2017. It was completed by tg on January 5, 2018. 125 nights later.

Turn out, my POSIX emulation was badly broken. Not just because of the usual bugs that any piece of C can have: I didn't understood most POSIX semantics at all!

 

First, Cinap had to patiently explain me on #cat-v that UNIX signals are reentrant.
It took him a while: I wasn't able to understand.
Even now, I keep asking: "Why?!? Why they did this! why..."

 

Fixed that, I saw that mksh was unable to execute ls: in Plan 9 common environment variables are lower case.
The $PATH variable is called $path, the $CDPATH variable is called $cdpath and so on.
Also, when appropriate, they are NULL separated char arrays, since they are exposed as files from the env device, and rc can get their size with a simple seek.

I reflected on the issue for a while, tried several solutions to preserve both conventions (some of which even worked).
But finally, I surrended to the simplest solution: I adopted the POSIX convention for Jehanne.

Aesthetics amuse, but simplicity helps.

However it was not enough: I needed to hook mksh startup to read the variables from the filesystem (just like rc does). How to do that cleanly? I asked on #!/bin/mksh and tg did not simply explained a poor noob how to do that. He did it himself!

I was enchanted by his kindness. So far Jehanne is just a toy. Still he spent his own time for me.

 

But the journey was still ongoing.

I realized that to run a command, mksh requires SIGCHLD support. I added it. The first implementation worked.

Once.

It was able to run exactly one command in mksh. The shell stopped reading input after the second one.

So I wrote it again from scratch. And it worked! Yuppy! :-)

Till I tried echo test | grep test

Grep didn't get EOF, as mksh for some strange reason was keeping the pipe open.
I extended devdup to ensure fcntl's emulation was working as expected. I rewrote fcntl emulation. Still broken.

Out of despair I turned to annoy tg again over IRC. Talking with him I realized that the problem was the signal dispatching. So I rewrote it again, introducing a new 9P2000 file server that handles signal IPC among POSIX processes, taking care of masks, ignored signals, waited ones.

Finally echo test | grep test worked.

 

But...

mksh was blaming me with two annoying warnings:

mksh: No controlling tty: open /dev/tty: No such file or directory
mksh: warning: won't have full job control

I asked tg and he tried to explain me what /dev/tty is, providing links about /dev/tty, /dev/ttyN and /dev/console.

So I modified vt (and later hmi/pipeconsole) to provide /dev/tty as an alias to /dev/cons.

The first warning was gone... but only the first one!

It was not just a matter of warnings: I was unable to interrupt a script (what you do with Ctrl+C on unix).

 

Down the rabbit hole, again.

I had to study the complex semantics of tty job control (asking boring questions to tg, again).
I had to fix setsid, getsid, setpgid, getpgid, getpgrp and to add support for termios' tcgetpgrp and tcsetpgrp.
Worse: I had to mostly rewrite the file server I had just written. Sob!

It took a while.
In the process I realized that a sys/posixly instance actually represents a single terminal session..

 

... did I say it took a while?

 

Then, suddenly... I saw this, and it was like an epiphany:

mksh running in Jehanne with full job control

 

MirBSD's Korn Shell was working on Jehanne! What a happy new year! :-D

MirOS Logo