Once you get over the fact that the code makes your eyes bleed, it has a sort of beauty.
The goal of this was not to use the resulting shell (it's a toy), but as a pathfinder for a similiar translation of the much larger dash shell. Many thanks to Andy Chu who suggested this as a reasonable experiment to run before sinking in too much time.
Experiments are the best time to use new technology, and this one is no different. As a result of using O_NONBLOCK pidfd's in spawn.rs to reap children this requires linux 5.10 or later. Note that at the time of writing the most recently published version of linux is 5.10-rc6, which is also the version this was tested on. This feels like the future, but if you're looking to use this code for anything non-toy in the nearterm I would suggest using a thread to wait on the pidfd's instead. You might want to take advantage of pop-os's pidfd library if you're writing in rust.
From a personal perspective this was a very worthwhile pathfinder, things that I'm glad I took away from it include
- Needing to be careful what references are captured in async blocks (e.g.
&self) - How to reap children in async code
- That handling control flow of the form
fork(); if (pid == 0 and we reach an error) { exit() }is somewaht painful and requires bubbling up errors long distances. Potentially we could use and catchpanicfor this, but I'd rather not. - I need to put some thought into the ownership of file descriptors, because we need to free them at the right times (e.g. with pipes...).
Run with cargo run.
See c2rust.md for brief notes on the commands used to translate sh.c with c2rust. I've also
massaged the commit history of this repo a bit, so it may be instructive to look at the commits.