This Time Self-Hosted
dark mode light mode Search

How down can you strip a Gentoo system?

In my previous post I noted I’m working on a project here in Los Angeles, of which I don’t wan to get much into the details of. On the other hand, what I’m going to tell you about this, for now, is that it’s a device and it’s running Gentoo as part of its firmware.

You can also guess, if you know us, that since both me and Luca are involved, there is some kind of multimedia work going on.

I came here to strip down as much as possible the production firmware so that the image could be as small as possible, and still allow all the features we need on the device. This is not a new task for me, as I’ve done my best to strip down my own router so that it would require the least amount of space as possible, and I’ve also done some embedded firmwares based on Gentoo before.

The first obstacle you have if you want to reduce the size of Gentoo is almost certainly the set of init scripts that come with OpenRC; for a number of reasons, the init scripts for things like loadkeys and hwclock are not installed by the package that install the commands (respectively sys-apps/kbd and sys-apps/util-linux) but rather are installed by OpenRC itself. They are also both enabled by default, which is okay for a general desktop system but fails badly on embedded systems, especially when they don’t even have a clock.

Then you have to deal with the insane amount of packages that form our base system; without going into the details of having man, tar and so on as part of the base untouchable system (which luckily is much easier to override with the new Portage 2.2, even if it insists bothering you about an overridden system set), and focusing on what you’re going to use to boot the system, OpenRC is currently requiring you a mixture of packages including coreutils, which (a single command that lies in its own package … for ESR’s sake, why was it not implemented within coreutils yet?), grep, findutils, gawk and sed (seriously, four packages for these? I mean I know they are more widely used than coreutils, as they are often used on non-Linux operating systems, but do they really deserve their own package, each of them?).

The most irritating part nowadays for me I guess is the psmisc vs procps battle: with the latter now maintained by Debian, I wonder why they haven’t merged the former yet. Given that they are implementing utilities for the same areas of the system… of course one could wonder why they are not all part of util-linux anyway — yes I know that Debian is also supporting GNU/kFreeBSD on their package. At any rate there is another consideration to be made: only the newer procps allows you to drop support for the ncurses library, earlier depended on it forcefully, and the same is still true for psmisc.

For what it’s worth, what I decided to do was to replace as much as possible with just busybox, including the troublesome psmisc, so that I could drop ncurses from our firmware altogether — interestingly enough, OpenRC depends explicitly on psmisc even though it is not bringing in most of the rest of its dependencies.

Public Service Announcement: if you’re writing an init script and you’re tempted to use which, please replace it with type -p use command -v instead … depending on an extra program when sh already has its built-in is bad, ‘mkay?

Edit: people made me notice that type -p is not in POSIX so it does not work in Dash. I’m afraid that my only trials to run OpenRC without bash before have used BusyBox, which supports it quite fine; the option to use command -v is valid though, thanks Tim.

Oh right, of course to replace coreutils usage with BusyBox you have to be able to drop it out of the dependency tree. Sounds easy, doesn’t it? Well, the problem is that even if you’re not deal with PulseAudio (which we are), which brings in eselect-esd, as of yesterday at least every package that could use Python would bring eselect-python in! Even when you were setting USE=-python.

Fortunately, after I bitched a bit about it to Luca, he made a change which at least solves the issue at hand until the stupid eclass is gone out of the tree. And yes I’m no longer even trying to consider it sane, the code is just so hairy and so encrypted that you can’t make heads or tails of it.

There are more issues with a project like this that I can discuss, outside of those part that are “trade secret” (or rather business logic), so expect to hear a bit more about it before it’s announced full out. And many of these have to do with how easy (or not) is to use Gentoo as a basis for devices’ firmwares.

Comments 19
  1. You suggest type -p for init scripts instead of which, but openrc uses /bin/sh, and unless you have bash linked to /bin/sh, it will propably fail, dash, which is imo the closes to real /bin/sh (and I have it symlinked to) does not know the -p switch for typo.Openrc is full of bashism here and there, I wonder why it insist in using /bin/sh instead of just rely on /bin/bash direcly.

  2. Have you considered using systemd instead of openrc?I’m using it (actually I was one of the guys to do the gentoo version) and it works nicely! Most of the tools are provided by systemd itself, and if you cut off the fat (acl, selinux, …) you can get pretty lean. Also consider not installing things you don’t use, like some dbus daemons to notify of hostname or time changes.If you use the latest udev, then you can also use kmod instead of module-init-tools, saving some space. If you don’t need the runtime commands, you can even remove the “kmod” tool as udev will call the library directly.

  3. I’ve found that it’s easier to build a minimal system by installing with ROOT to somewhere empty, rather than starting with a stage. At least last time I did it, this allowed you to avoid having the full “system” set in ROOT.

  4. Piotr are you sure? I should check I guess. I was pretty sure it worked, but admittedly I only use @busybox@ as shell, not dash itself. Still, launching @which@ just for that doesn’t sound like a very good idea.Gustavo, you missed the point _entirely_! Beside the point that if you’re making an embedded system you’re not even using modules – and the fact that if I didn’t require usb hotplug I wouldn’t even use udev! – systemd is not a solution for my problem at all. It’s designed for desktop and, at most, server usage, not embedded!Donnie, that’s what I’m doing actually, but it’s a bit tricky; as I said it’s much easier now with Portage 2.2. On the other hand, the best result is by using two-stage ROOTs: one you install normally, the other you install with @-B@ so that you drop the buildtime-only dependencies. This got trickier though, once again due to @python.eclass@ as libxcb fails to build: it tries to set the Python version on the ROOT rather than on / … and you don’t really _have_ Python on the ROOT at that point almost in all cases. D’oh!

  5. Hi Diego,Now it’s bit clearer to me. Being embedded does not veto modules usage, of course what’s built in (hw) should be built in (kernel), but pluggable usually is not. But as you said, hotplug is not a need, then you’re right about it and udev ;-)I’m working with systemd for embedded, it does help a lot compared to traditional openrc. But you have some constraints I did not (yet?) and thus there is no upstream work to reduce it even further. Maybe you’d be interested in that for the long run? To start you can get way less “fork/exec”, the process is way cleaner.The always bashed “it depends on dbus” bit shouldn’t impact much (248kb here on 64bits), and it makes the overall system control clean. Although you can skip this if you don’t want to control it.I always read your blog and follow your great Gentoo work. If not now due time constraints, at least later would be great to have you to test systemd and share your impressions. 🙂

  6. How much of the system set can be replaced by busybox? is there a way to allow busybox to meet most of those deps?

  7. Right now my system set is actually busybox, openrc, util-linux and sysvinit (and glibc and timezone-data obviously). This makes it _very_ slim a system at the end of the day, especially since at least for the init scripts we do use, we’re not looking at any bashism or stuff like that.The only reason why I’ve not replaced util-linux yet is simply that udev requires some of its libraries, and I’m not interested in splitting them up yet. Since we might just decide to drop udev soon (as we might not need the hotplug if our boot speed is cut short enough), at that point I’ll probably drop it as well.It all depends, I guess, on how many init scripts are you going to use.

  8. x11-libs/libxcb-1.8.1::gentoo no longer calls python_set_active_version().python.eclass from Progress Overlay has fixed handling of ROOT != “/” in EAPIs, in which API of python.eclass allows to check run-time dependency on Python: elif [[ “$1” == “2” ]]; then-if ! _python_implementation && ! has_version “=dev-lang/python-2*” then-die “${FUNCNAME}(): ‘=dev-lang/python-2*’ is not installed”+if ! _python_implementation; then+if ! ROOT=”/” has_version “=dev-lang/python-2*”; then+die “${FUNCNAME}(): ‘=dev-lang/python-2*’ not installed in ROOT=”/””+fi+if [[ “${ROOT}” != “/” ]] && _python_check_run-time_dependency then+if ! has_version “=dev-lang/python-2*”; then+die “${FUNCNAME}(): ‘=dev-lang/python-2*’ not installed in ROOT=”${ROOT}””+fi+fi fi

  9. Hi,type -p is not POSIX (dash does not support it) so please use command -v instead.

  10. I have suggested many times to integrate procps and psmisc to util-linux, but this idea has been rejected by procps guys. We all use git, so any distributed development should be pretty simple. BTW, procps[-ng] is actively maintained again.

  11. Gustavo, since I’m trying to figure out what’s good in systemd, could you please tell me exactly what’s better or what should be fixed in openrc?

  12. @lu_zero: there are many reasons, going blindly trying to compare it to openrc will lead nowhere.Lennart already wrote many articles on most areas. I’d recommend you to read them and mail me (see my site for contact info) if you have any questions. Or talk to me at (k-s). I can discuss it whenever you have a specific question 🙂

  13. @Diego: Please forgive my ignorance, but is there a functionality you need from udev with regards to hotplugging? AFAIK busybox’s mdev is quite capable enough to handle hotplugging if you do the ‘echo … > /proc/sys/kernel/hotplug’ step as explained in mdev’s documentation…

  14. It’s not as much udev’s hotplug as PulseAudio, that requires udev for detection…

  15. I have always thought that Gentoo would be a better system if all packages were moved into overlays. What I mean is that there should be a core gentoo overlay and a series of other overlays for major package. X,KDE, and GNOME come to mind. If the core gentoo overlay were stripped down as much as possible, your original need would be much more easily met. Good luck with your project.

  16. Uhm, I’m afraid you have never actually looked at how much interdependency there is between the various “subsystems”: a split overlay approach not only would *not do anything* to help me in this case, but it would also make debugging and bug triaging so incredibly difficult that I wouldn’t even _try_.So luckily most of the people who propose such a split approach will be left unheard — to me even just the existence of sunrise (with its own little, different policy), is a pain in the backside.

  17. Have you built a image or test image yet? If so, how small did you manage to squeeze Gentoo down too? I think I managed just under 4 megs before (for my Soekris net5501 router). 🙂

  18. The final, production firmware image came down to 8.5MB compressed, 50MB uncompressed ext4 (no journal) filesystem, of which around 40MB are used. If it sounds big, it’s because PulseAudio, udev, Aravis and their dependencies take space.I think I could reduce this further by removing a few more libraries that are present but not strictly needed, but that’s a very low hanging fruit by now, and I don’t think it’ll make any particular issue (any big executable or library that is left unused has been removed already).What still remains a sour spot for me is util-linux: while Busybox could replace its commands, without issues on my side, we need for udev, and I didn’t want to play too much with INSTALL_MASK (yet) to figure out how to keep that working, while at the same time removing everything else.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.