Relevant links:
- https://old.reddit.com/r/linux/comments/10eccv9/config_vtn_in_2023
- https://old.reddit.com/r/linux/comments/snzvur/cage_and_foot_in_an_initramfs_acting_as_a
- https://old.reddit.com/r/linux/comments/sycbn0/showstoppers_in_desktop_linux_without_vts_in_2022
Explainer
As described in the links above, it’s possible to replace the kernel’s built-in virtual terminals (VTs) with a userspace terminal.
This isn’t what this post is about.
Instead, this whole thing started because I wanted to get the cage foot
command combo working in a non-transitioning initramfs image, which has it’s own benefits distinct from removing VTs such as: Reintroducing scrollback, being able to use more sophisticated fonts, and even the ability to use your mouse.
However, there are no step-by-step guides for running cage foot
in VTs, so I had to figure this out myself…
The (semi-)step-by-step guide
I say “semi” because this isn’t a set of exact instructions for how to make the initramfs, though if you stick around you’ll be finding out how I made mine using the mkosi
tool in some future posts, but rather, these are things you need to keep in mind if you attempt this yourself.
Cage
Cage is a Wayland kiosk, a compositor that runs a single maximised app (think ATM screens), which is a perfect fit for what we’re doing. It’s small enough to not increase the size of the initramfs substantially, and it only handles single apps.
If you start another app inside of a
cage
session, it’ll open that app on top of the previous one and leave the other app running in the background, which could be useful as a basic substitute for thescreen
ortmux
commands.
Mesa
Since we’re dealing with an initramfs image, and keeping the size down is a priority, we’ll want to exclude installing GPU drivers. Thankfully, the kernel already provides the necessary DRM device at /dev/dri/card0
for software rendering. Unfortunately, that still leaves the mesa
package as a dependency of the wlroots
package which is a dependency of cage
. Great.
Technically speaking, wlroots doesn’t need Mesa when using software rendering, which you can use by setting WLR_RENDERER=pixman as an environment variable (where “pixman” is a pixel manipulation library), however, wlroots is compiled with a dynamic dependency on /usr/lib/libgbm.so.1.0.0
which must be satisfied for wlroots to even be executed.
The smart way to get around this would be to compile wlroots without GBM and GLES2 support, as well as any other renderers you don’t need while you’re at it, thus removing the dependency on “libgbm”. Buuuuut… I was too lazy.
Instead, you can install mesa
, move /usr/lib/{libgbm.so,libgbm.so.1,libgbm.so.1.0.0}
to a safe location, uninstall mesa
, and then move the libraries back again. This is… actually completely fine, as the first two files are actually symlinks, and the real library file is only about ~60KiB (1KiB
= 1024 bytes).
Be careful not to remove the libdrm
package, which is pulled in as a dependency of Mesa, as Cage does need that library too. Explicitly installing libdrm
should prevent it from being uninstalled by most package managers.
xorg-xwayland
As of writing, Cage has a bug where it always expects /usr/bin/Xwayland
to exist, even when you’re trying to run a Wayland-only app. So using the exact same strategy as I used for mesa
, you’ll need to do the same thing with that binary up until the next release of Cage is available.
Keyboard layout & mouse cursors
Currently, in the Wayland ecosystem, there is no standardised configs to tell the compositor about your keyboard layout, unlike Xorg which has /etc/vconsole.conf
among other configs, so we need to deal with that (unless you’re using a United States keyboard layout. Then you’re already set you lucky motherfu-).
Thankfully, this is really simple for Cage. Just set the XKB_DEFAULT_LAYOUT environment variable to the correct value, however, be aware the value isn’t always the same as the one you’d set KEYMAP
to in /etc/vconsole.conf
(e.g. KEYMAP=uk
vs XKB_DEFAULT_LAYOUT=gb).
Foot
foot
is a minimal Wayland terminal, which perfectly pairs with Cage for similar size reasons. And also similarly, we’re gonna need to change some things.
foot.ini
When trying to run cage foot
normally, you’ll likely notice major visual artefacting as soon as you type or clear the screen, however, this is easy to fix with a simple config addition:
Unfortunately, as the option’s name implies, this causes the entire screen to be refreshed when any part of the screen needs updating, which noticeably degrades performance (especially when moving the mouse cursor around). I don’t know why this issue occurs, but for now, this is the only working solution I have to offer.
Addendum
As it turns out, this artefacting doesn’t appear when using WLR_RENDERER=pixman, and was most likely a bug I experienced from another renderer wlroots was using during my testing. So, you probably don’t need this and should definitely test if foot
works properly for you without the tweak first.
Wrong working directory
When you first run cage foot
, you might notice that the current working directory isn’t set to the user’s home directory, but instead, it’s set to /
. I don’t really know why this happens, however, including something like the following in your shells start-up scripts can fix this:
Addendum
The behaviour described above turns out to be expected, and setting the current working directory to the correct location is documented in Foot’s wiki page.
Fonts
Since you don’t need to deal with the VT font limitations, you can use virtually any monospace Freetype font you like (aka. ttf-*-mono
fonts). I personally use ttf-fira-mono
, which is admittedly a pretty large addition to the initramfs image, but…
No that’s it, I ain’t got a good reason, other than it looks damn nice.
Don’t forget to set your font in the
foot.ini
config file as mentioned two sections ago.
Terminfo
In /usr/share/terminfo
, you’ll find various files corresponding to different terminals, sometimes with multiple files per terminal. These files describe what the terminal is capable of, and significantly affect how certain tools behave (e.g. without foot’s terminfo files, journalctl
will complain and refuse to use less
), which makes all the unused terminfo files good candidates for removal.
In this case, /usr/share/terminfo/f/foot*
(for foot
) and /usr/share/terminfo/l/linux
(for the VT) are all the files we need (unless you add other terminals) which saves about 700KiB from the compressed initramfs size.
Removing
/usr/share/foot/themes
in favour of manually configuringfoot
is also a good space-saving trick.
Replacing getty
I haven’t even thought about compiling the kernel without VTs, however, I have figured out a simple way to replace getty@.service
, the service that normally runs on VTs, with the cage foot
command combo I’ve been explaining here.
To get straight to the point, and let the file’s comments do the talking, here’s the service file:
Replace the value of
User=rescue
with whatever regular user you’ve configured in your initramfs, and add anyXKB_DEFAULT_*
variable keypairs you need to/etc/environment
.This service file was heavily based off the one from the Cage Wiki.
And additionally, you’ll need the following file:
After copying these files into the initramfs, enable cage-foot@tty1.service
and disable any getty@ttyN.service
services that are configured. When you switch VTs, you’ll get the standard getty service where you can manually start the cage-foot@ttyN
service (where “N” is the TTY number, which you can find with the tty
or who
commands).
And finally, the end
It was a painstaking journey to discover all this myself, about 3-4 days of looking up obscure error codes and pouring through man
pages and issue trackers, but after all that, I’d say it was worth it.
Of course, this isn’t the only thing I’ve been working on since the last blog post, although I do realise it has been a while, and in the next couple of posts, I’ll be telling you all about the mkosi
tool.