1 puntos por GN⁺ 2 시간 전 | 1 comentarios | Compartir por WhatsApp
  • BusyBox usa una estructura de binario multicall que ofrece varios comandos en un solo ejecutable, y el wget predeterminado de Alpine también se ejecuta a través de BusyBox
  • En un contenedor Alpine, /usr/bin/wget no era un binario real sino un enlace simbólico que apuntaba a /bin/busybox
  • Al ejecutarse, BusyBox lee el nombre invocado desde argv[0] y determina qué applet ejecutar usando el último nombre de la ruta
  • Cada applet se busca por nombre y entra a su función main correspondiente; wget está implementado en wget.c y finalmente se ejecuta wget_main
  • Se pueden ver los comandos compilados con busybox --list, y en el ejemplo de Alpine aparecen 304, mientras que cada utilidad parece una versión reducida

Cómo funciona BusyBox

  • BusyBox usa una estructura de binario multicall (multicall binary) que ofrece varios comandos en un solo ejecutable
  • En un contenedor Alpine, /usr/bin/wget no era un ejecutable real sino un enlace simbólico que apuntaba a /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
    
  • En /usr/bin, más de 130 ejecutables parecen provenir de un solo binario, lo que se relaciona con la estructura de binario multicall de BusyBox
  • Al ejecutarse, BusyBox toma el nombre invocado desde argv[0], extrae solo el último nombre de la ruta y decide qué applet ejecutar
    applet_name = argv[0];
    if (applet_name[0] == '-')
      applet_name++;
    applet_name = bb_basename(applet_name);
    
  • También funciona si se pasa explícitamente el nombre del applet, como en busybox ls -1; si se le da un nombre inexistente, muestra applet not found
    / # busybox ls -1
    bin
    dev
    etc
    home
    
    / # busybox meheh
    meheh: applet not found
    

Configuración de applets y forma de instalación

  • BusyBox busca el applet por nombre y luego ejecuta la función main correspondiente de ese applet
    int applet = find_applet_by_name(name);
    // ...
    run_applet_no_and_exit(applet, name, argv);
    // ...
    xfunc_error_retval = applet_main[applet_no](argc, argv);
    
  • Cada applet tiene su propio archivo C, y wget está implementado en wget.c
  • La configuración de cada applet está definida en forma de comentarios dentro del código; la configuración de WGET incluye wget (41 kb), activación predeterminada, una ayuda que lo describe como una utilidad para descargar archivos de servidores HTTP y FTP sin interacción, y el objetivo de build 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
    
  • Al final, el applet wget entra en wget_main
    int wget_main(int argc UNUSED_PARAM, char **argv)
    
  • BusyBox también soporta enlaces duros, y en busybox --install -s, -s significa crear enlaces simbólicos
    busybox --install -s
    
  • La lista de comandos incluidos en la compilación puede verse con busybox --list, y en el entorno de ejemplo de Alpine aparecen 304
    / # busybox --list | wc -l
    304
    
  • Varios comandos de Alpine funcionan como una interfaz hacia binarios basados en BusyBox, y cada utilidad parece una versión reducida frente a la utilidad original completa

1 comentarios

 
GN⁺ 2 시간 전
Opiniones en Lobste.rs
  • La respuesta a la pregunta citada está más cerca de una reimplementación
    La introducción a BusyBox está en https://busybox.net/about.html y el código fuente está en https://github.com/vda-linux/busybox_mirror

  • Es bastante molesto que un programa finja tener un nombre distinto del real
    El peor caso es cuando ejecutas gcc en macOS y en realidad obtienes clang; PowerShell también funciona de forma parecida. Sería mejor que simplemente usaran otro nombre

    • Parte de esto también viene de que muchos desarrolladores no conocían clang, no tenían una Mac para probar, o empezaron en una época en la que no había alternativas realistas
      Nixpkgs tiene que aplicar muchos parches como https://github.com/NixOS/nixpkgs/…, y ni siquiera proyectos conocidos como sqlite son la excepción. En cambio, macOS simplemente optó por la ruta engañosa
    • Hay gente que escribe makefiles para mucho software y no conoce cc
    • Entiendo la frustración, pero probablemente se difundió porque, si es lo suficientemente compatible como para ejecutar la mayoría de los scripts de compilación, permite reutilizar en cierta medida los mismos scripts entre Linux y varios sistemas tipo Unix
    • A veces es algo irrealizable en la práctica
      Debe haber muchos makefiles con gcc hardcodeado, y pasa algo parecido en otros contextos. Por ejemplo, como muchos programas existentes revisan xterm-* en la variable de entorno TERM en lugar de usar la base de datos terminfo, que sería la solución correcta, elegir otro nombre no funciona
  • Cuando diagnostico problemas raros en contenedores, uso seguido podman cp /usr/bin/busybox-static somecontainer:/bin

  • toybox tiene una estructura parecida
    Algunas herramientas parecen traídas o portadas desde otros lugares, pero muchas fueron implementadas de nuevo para BusyBox, y el objetivo es mantenerlas pequeñas y usar solo funciones limitadas de libc para que al compilar con enlace estático sigan siendo pequeñas. Otra ventaja es que en scripts de shell estas herramientas pueden usarse como si fueran comandos integrados. Algunas se ejecutan con fork+jump en vez de fork+exec, y unas cuantas incluso pueden ejecutarse sin fork, como una llamada normal a función

    • Según entiendo, toybox se creó originalmente como una alternativa con licencia BSD a BusyBox, que tiene licencia GPL
      Como agregado, según Toybox en Wikipedia, “Toybox fue iniciado a comienzos de 2006 por Rob Landley después de dejar su rol como mantenedor de BusyBox tras una disputa con Bruce Perens, el creador original de BusyBox”
  • En realidad sí es una reimplementación. Aun así, si la licencia lo permite, no sería sorprendente que hubiera tomado algo de código de la implementación original más grande
    Según la 'pedia:, BusyBox fue escrito originalmente por Bruce Perens en 1995, y en 1996 se declaró terminado para su uso previsto. El objetivo inicial era meter en un solo disquete un sistema completo y arrancable que sirviera como disco de rescate e instalador para la distribución Debian. Después se expandió hasta convertirse en el conjunto de herramientas básicas de espacio de usuario de facto estándar para dispositivos Linux embebidos y para instaladores de distribuciones Linux, y como cada ejecutable de Linux requiere varios KB de sobrecarga, combinar más de 200 programas en uno solo puede ahorrar bastante espacio en disco y memoria
    Relacionado con esto, Toybox también tiene una estructura y filosofía parecidas, pero con licencia BSD. Si mal no recuerdo, su desarrollador principal, Rob Landley, pensaba que una licencia más fácil de aceptar comercialmente permitiría incluirlo en dispositivos Android, y que eso podría convertir a todos los teléfonos y tablets Android en una especie de entorno de desarrollo similar a Unix. Toybox todavía parece ser parte de Android, pero sin herramientas de apoyo en capas superiores, como Termux, Android no es tan fácil de usar como Unix

    • Difícil encontrar un caso más de manual para mostrar cómo hacer trabajo no remunerado para empresas como Google puede terminar perjudicándote a ti mismo
      Más aún considerando que Google lleva años amenazando con bloquear Termux
  • También hay un port para Windows: https://github.com/rmyorston/busybox-w32
    El tamaño reducido de BusyBox hace que este tipo de port sea más viable. Aunque ahora que puedes simplemente ejecutar Linux dentro de Windows, parece haber perdido algo de relevancia