1 Punkte von GN⁺ 2 시간 전 | 1 Kommentare | Auf WhatsApp teilen
  • BusyBox ist ein Multicall-Binary, das mehrere Befehle in einer einzigen ausführbaren Datei bereitstellt; auch Alpines Standard-wget wird über BusyBox ausgeführt
  • In einem Alpine-Container war /usr/bin/wget kein echtes Binary, sondern ein symbolischer Link, der auf /bin/busybox zeigt
  • Beim Start liest BusyBox den aufgerufenen Namen aus argv[0] und bestimmt anhand des letzten Namensbestandteils im Pfad, welches Applet ausgeführt werden soll
  • Jedes Applet wird über seinen Namen gefunden und springt dann in die entsprechende main-Funktion; wget ist in wget.c implementiert und führt am Ende wget_main aus
  • Mit busybox --list lassen sich die einkompilierten Befehle anzeigen; im Alpine-Beispiel werden 304 angezeigt, und jedes Utility wirkt wie eine abgespeckte Version

Funktionsweise von BusyBox

  • BusyBox verwendet eine Multicall-Binary-Struktur, bei der mehrere Befehle in einer einzigen ausführbaren Datei bereitgestellt werden
  • In einem Alpine-Container war /usr/bin/wget keine echte ausführbare Datei, sondern ein symbolischer Link auf /bin/busybox
    docker 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
    
  • In /usr/bin scheinen mehr als 130 ausführbare Dateien aus einem einzigen Binary zu stammen, was mit der Multicall-Binary-Struktur von BusyBox zusammenhängt
  • Beim Start übernimmt BusyBox den aufgerufenen Namen aus argv[0], extrahiert nur den letzten Namensbestandteil des Pfads und entscheidet so, welches Applet ausgeführt werden soll
    applet_name = argv[0];
    if (applet_name[0] == '-')
      applet_name++;
    applet_name = bb_basename(applet_name);
    
  • Es funktioniert auch, den Applet-Namen explizit zu übergeben, etwa mit busybox ls -1; wird ein nicht vorhandener Name angegeben, erscheint applet not found
    / # busybox ls -1
    bin
    dev
    etc
    home
    
    / # busybox meheh
    meheh: applet not found
    

Aufbau der Applets und Installationsweise

  • BusyBox sucht zunächst anhand des Namens das Applet und führt dann dessen main-Funktion aus
    int applet = find_applet_by_name(name);
    // ...
    run_applet_no_and_exit(applet, name, argv);
    // ...
    xfunc_error_retval = applet_main[applet_no](argc, argv);
    
  • Jedes Applet besitzt eine eigene C-Datei; wget ist in wget.c implementiert
  • Die appletspezifischen Einstellungen sind in Form von Code-Kommentaren definiert; die WGET-Konfiguration enthält wget (41 kb), die Standardaktivierung, einen Hilfetext als Utility zum nicht interaktiven Herunterladen von Dateien von HTTP- und FTP-Servern sowie das Build-Ziel wget.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
    
  • Das wget-Applet springt letztlich in wget_main
    int wget_main(int argc UNUSED_PARAM, char **argv)
    
  • BusyBox unterstützt auch Hardlinks; bei busybox --install -s steht -s für das Erstellen symbolischer Links
    busybox --install -s
    
  • Die Liste der in die Kompilierung aufgenommenen Befehle lässt sich mit busybox --list anzeigen; in der Alpine-Beispielumgebung werden 304 ausgegeben
    / # busybox --list | wc -l
    304
    
  • Viele Befehle in Alpine fungieren wie eine Schnittstelle zu BusyBox-basierten Binaries, und jedes Utility wirkt im Vergleich zum vollständigen Original eher wie eine abgespeckte Version

1 Kommentare

 
GN⁺ 2 시간 전
Meinungen auf Lobste.rs
  • Die Antwort auf die zitierte Frage ist eher Neuimplementierung
    Eine Einführung zu BusyBox gibt es unter https://busybox.net/about.html, und der Quellcode liegt unter https://github.com/vda-linux/busybox_mirror

  • Es nervt ziemlich, wenn ein Programm so tut, als hätte es einen anderen Namen als in Wirklichkeit
    Am schlimmsten ist es, wenn man unter macOS gcc ausführt und tatsächlich clang bekommt; PowerShell verhält sich ähnlich. Es wäre besser, einfach einen anderen Namen zu verwenden

    • Das Problem ist auch dadurch entstanden, dass viele Entwickler clang nicht kannten, keinen Mac zum Testen hatten oder es keine realistische Alternative gab
      Nixpkgs braucht viele Patches wie https://github.com/NixOS/nixpkgs/…, und selbst bekannte Projekte wie sqlite sind keine Ausnahme. macOS hat sich stattdessen offenbar einfach für den täuschenden Pfad entschieden
    • Manche Leute, die makefiles für viel Software schreiben, kennen cc nicht
    • Ich verstehe den Frust, aber vermutlich hat es sich verbreitet, weil es hinreichend kompatibel ist, um die meisten Build-Skripte auszuführen, sodass man auf Linux und verschiedenen Unix-Systemen dieselben Skripte bis zu einem gewissen Grad wiederverwenden kann
    • Manchmal ist es praktisch unmöglich
      Es gibt vermutlich viele Makefiles, in denen gcc fest verdrahtet ist, und in anderen Kontexten ist es ähnlich. Zum Beispiel prüfen viele bestehende Programme auf xterm-* in der TERM-Umgebungsvariable statt die korrekte Lösung über die terminfo-Datenbank zu nutzen, daher funktioniert der Ansatz mit einem anderen Namen nicht
  • Wenn ich in einem Container seltsame Probleme diagnostiziere, nutze ich oft podman cp /usr/bin/busybox-static somecontainer:/bin

  • toybox hat eine ähnliche Struktur
    Einige Tools scheinen von anderswo übernommen oder portiert worden zu sein, aber viele wurden für BusyBox neu implementiert; das Ziel ist, sie klein zu halten und nur eingeschränkte libc-Funktionen zu verwenden, damit sie beim statischen Linken klein kompiliert werden. Ein weiterer Vorteil ist, dass man diese Tools in Shell-Skripten wie Built-ins verwenden kann. Manche werden nicht per fork+exec, sondern per fork+jump ausgeführt, und einige lassen sich sogar ohne Fork als normaler Funktionsaufruf ausführen

    • Soweit ich weiß, wurde toybox ursprünglich als BSD-lizenzierte Alternative zur GPL-lizenzierten BusyBox geschaffen
      Ergänzend dazu heißt es in Toybox on Wikipedia: „Toybox was started at the beginning of 2006 after Rob Landley stopped serving as maintainer of BusyBox due to a disagreement with Bruce Perens, the original creator of BusyBox.“
  • Technisch gesehen ist es eine Neuimplementierung. Wenn die Lizenz es erlaubt, wäre es allerdings nicht überraschend, wenn etwas Code aus der ursprünglichen großen Implementierung übernommen wurde
    Laut der 'pedia: BusyBox wurde 1995 erstmals von Bruce Perens geschrieben und 1996 für seinen beabsichtigten Zweck als fertig erklärt. Das ursprüngliche Ziel war, ein vollständiges bootfähiges System, das als Rettungsdiskette und Installationsprogramm für die Debian-Distribution dient, auf eine einzige Diskette zu packen. Später entwickelte es sich zum De-facto-Standard-Kernset von User-Space-Werkzeugen für Embedded-Linux-Geräte und Installationsprogramme von Linux-Distributionen; da jede Linux-Binärdatei einige KB Overhead benötigt, spart das Zusammenfassen von mehr als 200 Programmen in einem einzigen erheblich Plattenplatz und Speicher
    In diesem Zusammenhang ist auch Toybox in Struktur und Philosophie ähnlich, steht aber unter einer BSD-Lizenz. Ich erinnere mich, dass der Hauptentwickler Rob Landley meinte, mit einer für den kommerziellen Einsatz leichter akzeptablen Lizenz könnte es in Android-Geräte aufgenommen werden, und dann hätten alle Android-Smartphones und -Tablets das Potenzial, sich in eine Unix-ähnliche Entwicklungsumgebung zu verwandeln. Toybox scheint noch immer Teil von Android zu sein, aber ohne Werkzeuge aus darüberliegenden Schichten wie Termux lässt sich Android nicht besonders leicht wie ein Unix-System nutzen

    • Schwer vorstellbar, ein perfekteres Lehrbuchbeispiel dafür zu finden, wie es einem selbst schadet, unbezahlte Arbeit für Firmen wie Google zu leisten
      Vor allem, wenn man bedenkt, dass Google jahrelang damit gedroht hat, Termux zu blockieren
  • Es gibt auch einen Windows-Port: https://github.com/rmyorston/busybox-w32
    Durch die geringe Größe von BusyBox ist so ein Port realistischer. Allerdings scheint das heute etwas weniger relevant zu sein, weil man unter Windows inzwischen einfach Linux ausführen kann