Qu’est-ce que BusyBox ?
(specular.fi)- BusyBox est un binaire multicall qui fournit plusieurs commandes dans un seul exécutable, et le
wgetpar défaut d’Alpine est lui aussi exécuté via BusyBox - Dans un conteneur Alpine,
/usr/bin/wgetn’était pas un vrai binaire mais un lien symbolique pointant vers/bin/busybox - Lors de l’exécution, BusyBox lit le nom d’appel dans
argv[0]et détermine quelle applet exécuter à partir du dernier élément du chemin - Chaque applet est recherchée par son nom puis entre dans sa fonction
maincorrespondante ;wgetest implémenté danswget.cet exécute finalementwget_main busybox --listpermet de voir les commandes compilées ; dans l’exemple Alpine, 304 sont affichées, et chaque utilitaire ressemble à une version allégée
Fonctionnement de BusyBox
- BusyBox utilise une architecture de binaire multicall (multicall binary) qui fournit plusieurs commandes dans un seul exécutable
- Dans un conteneur Alpine,
/usr/bin/wgetn’était pas un véritable exécutable mais un lien symbolique pointant vers/bin/busyboxdocker run --rm -it alpine sh / # which wget /usr/bin/wget / # ls -lah /usr/bin/wget lrwxrwxrwx 1 root root 12 Apr 15 04:51 /usr/bin/wget -> /bin/busybox - Dans
/usr/bin, plus de 130 exécutables semblent provenir d’un seul binaire, ce qui est lié à l’architecture multicall de BusyBox - Lors de l’exécution, BusyBox récupère le nom invoqué depuis
argv[0], puis n’en extrait que le dernier élément du chemin pour déterminer quelle applet exécuterapplet_name = argv[0]; if (applet_name[0] == '-') applet_name++; applet_name = bb_basename(applet_name); - Il fonctionne aussi si l’on passe explicitement le nom de l’applet, comme avec
busybox ls -1; si on fournit un nom inexistant,applet not founds’affiche/ # busybox ls -1 bin dev etc home / # busybox meheh meheh: applet not found
Organisation des applets et méthode d’installation
- BusyBox recherche l’applet par son nom, puis exécute la fonction
maincorrespondanteint applet = find_applet_by_name(name); // ... run_applet_no_and_exit(applet, name, argv); // ... xfunc_error_retval = applet_main[applet_no](argc, argv); - Chaque applet possède son propre fichier C ;
wgetest implémenté danswget.c - La configuration de chaque applet est définie sous forme de commentaires dans le code ; pour
WGET, on y trouvewget (41 kb), son activation par défaut, un texte d’aide indiquant qu’il s’agit d’un utilitaire de téléchargement non interactif depuis des serveurs HTTP et FTP, ainsi que la cible de buildwget.o//config:config WGET //config: bool "wget (41 kb)" //config: default y //config: help //config: wget is a utility for non-interactive download of files from HTTP //config: and FTP servers. //applet:IF_WGET(APPLET(wget, BB_DIR_USR_BIN, BB_SUID_DROP)) //kbuild:lib-$(CONFIG_WGET) += wget.o - Au final, l’applet
wgetentre danswget_mainint wget_main(int argc UNUSED_PARAM, char **argv) - BusyBox prend aussi en charge les liens physiques, et dans
busybox --install -s,-ssignifie création de liens symboliquesbusybox --install -s - La liste des commandes incluses à la compilation peut être affichée avec
busybox --list; dans l’environnement Alpine de l’exemple, 304 sont affichées/ # busybox --list | wc -l 304 - De nombreuses commandes d’Alpine fonctionnent comme une interface vers un binaire basé sur BusyBox, et chaque utilitaire ressemble à une version allégée de son équivalent complet
1 commentaires
Avis sur Lobste.rs
La réponse à la question citée est plus proche d’une réimplémentation
Une présentation de BusyBox se trouve sur https://busybox.net/about.html, et le code source sur https://github.com/vda-linux/busybox_mirror
Le fait qu’un programme prétende porter un autre nom que le sien est assez agaçant
Le pire, c’est quand on exécute
gccsur macOS et qu’on obtient en réalité clang ; PowerShell fonctionne aussi un peu comme ça. Ce serait mieux d’utiliser simplement un autre nomNixpkgs doit appliquer beaucoup de correctifs comme https://github.com/NixOS/nixpkgs/…, et même un projet connu comme sqlite n’y échappe pas. À l’inverse, macOS a simplement choisi la voie du chemin trompeur
ccIl existe sans doute beaucoup de makefiles où
gccest codé en dur, et on retrouve le même genre de problème ailleurs. Par exemple, de nombreux programmes existants vérifientxterm-*dans la variable d’environnementTERMau lieu d’utiliser la base de donnéesterminfo, qui est pourtant la bonne solution ; dans ce cas, choisir un autre nom ne fonctionne pasQuand je dois diagnostiquer un problème étrange dans un conteneur, j’utilise souvent
podman cp /usr/bin/busybox-static somecontainer:/bintoybox a une structure similaire
Certains outils semblent repris ou portés depuis ailleurs, mais un grand nombre ont été réimplémentés pour BusyBox, avec pour objectif de rester petits et de n’utiliser qu’un sous-ensemble limité des fonctions de libc afin de produire de petits binaires en liaison statique. Un autre avantage est qu’on peut utiliser ces outils dans des scripts shell comme s’il s’agissait de commandes intégrées. Certains s’exécutent avec fork+jump plutôt qu’avec fork+exec, et d’autres peuvent même s’exécuter comme de simples appels de fonction sans fork
À noter que, d’après Toybox sur Wikipedia, « Toybox a été lancé début 2006 par Rob Landley après qu’il a cessé d’être mainteneur de BusyBox à la suite d’un différend avec Bruce Perens, le créateur original de BusyBox »
En pratique, c’est bien une réimplémentation. Cela dit, si la licence l’autorise, il ne serait pas surprenant que du code ait été repris en partie depuis l’implémentation originale plus volumineuse
D’après Wikipédia : BusyBox a été écrit pour la première fois en 1995 par Bruce Perens, et déclaré terminé pour son usage prévu en 1996. L’objectif initial était de faire tenir sur une seule disquette un système entièrement amorçable servant à la fois de disque de secours et d’installateur pour la distribution Debian. Il s’est ensuite imposé comme la collection standard de base d’outils user space pour les appareils Linux embarqués et les installateurs de distributions Linux ; comme chaque exécutable Linux entraîne quelques kilo-octets de surcharge, fusionner plus de 200 programmes en un seul permet d’économiser considérablement de l’espace disque et de la mémoire
À ce sujet, Toybox a lui aussi une structure et une philosophie similaires, mais sous licence BSD. Il me semble que son développeur principal, Rob Landley, pensait qu’avec une licence plus acceptable commercialement, il pourrait être inclus dans les appareils Android ; et que, dans ce cas, tous les téléphones et tablettes Android auraient le potentiel de devenir une sorte d’environnement de développement proche d’Unix. Toybox semble toujours faire partie d’Android, mais sans outils de surcouche comme Termux, Android n’est pas vraiment simple à utiliser comme un système Unix
C’est encore plus vrai quand on pense au fait que Google menace depuis des années de bloquer Termux
Il existe aussi un portage Windows : https://github.com/rmyorston/busybox-w32
La petite taille de BusyBox rend ce genre de portage plus réaliste. Cela dit, on peut désormais simplement exécuter Linux dans Windows, donc cela semble un peu moins pertinent aujourd’hui