1 pontos por GN⁺ 2 시간 전 | 1 comentários | Compartilhar no WhatsApp
  • BusyBox é um binário multicall que fornece vários comandos em um único executável; até o wget padrão do Alpine é executado via BusyBox
  • No contêiner Alpine, /usr/bin/wget não era um binário real, mas um link simbólico apontando para /bin/busybox
  • Ao ser executado, o BusyBox lê o nome de chamada em argv[0] e determina qual applet executar a partir do último nome do caminho
  • Cada applet é localizado pelo nome e entra na respectiva função main; o wget é implementado em wget.c e, no fim, executa wget_main
  • É possível ver os comandos compilados com busybox --list; no exemplo do Alpine, aparecem 304 e cada utilitário parece uma versão reduzida

Como o BusyBox funciona

  • O BusyBox usa uma estrutura de binário multicall (multicall binary), oferecendo vários comandos em um único executável
  • Em um contêiner Alpine, /usr/bin/wget não era um arquivo executável real, e sim um link simbólico apontando para /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
    
  • Em /usr/bin, mais de 130 executáveis parecem vir de um único binário, o que está ligado à estrutura de binário multicall do BusyBox
  • Ao iniciar, o BusyBox obtém o nome invocado a partir de argv[0] e extrai apenas o último nome do caminho para decidir qual applet executar
    applet_name = argv[0];
    if (applet_name[0] == '-')
      applet_name++;
    applet_name = bb_basename(applet_name);
    
  • Também funciona ao passar explicitamente o nome do applet, como em busybox ls -1; se for informado um nome inexistente, será exibido applet not found
    / # busybox ls -1
    bin
    dev
    etc
    home
    
    / # busybox meheh
    meheh: applet not found
    

Estrutura dos applets e forma de instalação

  • O BusyBox procura o applet pelo nome e então executa a função main correspondente
    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 tem seu próprio arquivo C; o wget é implementado em wget.c
  • As configurações de cada applet são definidas em forma de comentários no código; a configuração de WGET inclui wget (41 kb), ativação padrão, ajuda descrevendo-o como um utilitário para baixar arquivos de servidores HTTP e FTP de forma não interativa, além do alvo 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
    
  • No fim, o applet wget entra em wget_main
    int wget_main(int argc UNUSED_PARAM, char **argv)
    
  • O BusyBox também oferece suporte a hard links, e em busybox --install -s o -s indica a criação de links simbólicos
    busybox --install -s
    
  • A lista de comandos incluídos na compilação pode ser vista com busybox --list; no ambiente de exemplo do Alpine, aparecem 304
    / # busybox --list | wc -l
    304
    
  • Muitos comandos do Alpine funcionam como uma interface para o binário baseado em BusyBox, e cada utilitário parece uma versão reduzida em comparação com o utilitário original completo

1 comentários

 
GN⁺ 2 시간 전
Opiniões no Lobste.rs
  • A resposta à pergunta citada está mais para uma reimplementação
    A apresentação do BusyBox está em https://busybox.net/about.html, e o código-fonte está em https://github.com/vda-linux/busybox_mirror

  • É bem irritante quando um programa finge ter um nome diferente do que realmente é
    O pior caso é quando você executa gcc no macOS e na verdade recebe clang; o PowerShell também funciona de forma parecida. Seria melhor simplesmente usar outro nome

    • Também é um problema que surgiu porque muitos desenvolvedores começaram numa época em que não conheciam o clang, não tinham um Mac para testar ou não havia alternativa prática
      O Nixpkgs precisa aplicar muitos patches como https://github.com/NixOS/nixpkgs/…, e nem projetos famosos como o sqlite são exceção. Já o macOS basicamente escolheu o caminho de enganar pelo caminho
    • Há gente que escreve makefile para muito software e não conhece cc
    • Entendo a frustração, mas isso provavelmente se espalhou porque, se for compatível o suficiente para rodar a maioria dos scripts de build, dá para reaproveitar até certo ponto os mesmos scripts entre Linux e vários Unix
    • Às vezes isso é realisticamente impossível
      Deve haver muitos makefiles com gcc hardcoded, e o mesmo acontece em outros contextos. Por exemplo, como muitos programas existentes verificam xterm-* na variável de ambiente TERM em vez de usar o banco de dados terminfo, que seria a solução correta, escolher outro nome não funciona
  • Ao diagnosticar problemas estranhos em contêineres, eu uso bastante podman cp /usr/bin/busybox-static somecontainer:/bin

  • O toybox também tem uma estrutura parecida
    Algumas ferramentas parecem ter sido trazidas ou portadas de outros lugares, mas muitas foram implementadas do zero para o BusyBox, com o objetivo de serem pequenas e usarem apenas funcionalidades limitadas de libc para também compilarem pequenas com linkagem estática. Outra vantagem é poder usar essas ferramentas em scripts de shell como se fossem comandos embutidos. Algumas rodam com fork+jump em vez de fork+exec, e algumas até rodam sem fork, por chamada de função comum

    • Pelo que eu sei, o toybox foi criado originalmente como uma alternativa com licença BSD ao BusyBox, que é GPL
      Complementando, segundo Toybox on Wikipedia, “Toybox was started at the beginning of 2006 after Rob Landley quit as BusyBox maintainer in a dispute with BusyBox's original creator Bruce Perens”
  • Na prática, é uma reimplementação. Ainda assim, se a licença permitir, não seria surpreendente se algum código tivesse sido aproveitado da implementação original maior
    Segundo a Wikipédia:, o BusyBox foi escrito originalmente por Bruce Perens em 1995, e em 1996 foi declarado completo para o uso pretendido. O objetivo inicial era colocar em um único disquete um sistema totalmente inicializável que servisse como disco de recuperação e instalador da distribuição Debian. Depois disso, ele se expandiu e virou de fato o conjunto padrão de ferramentas essenciais de espaço de usuário em dispositivos Linux embarcados e instaladores de distribuições Linux; como cada executável Linux exige alguns KB de overhead, juntar mais de 200 programas em um só pode economizar bastante espaço em disco e memória
    Nesse contexto, o Toybox também tem estrutura e filosofia parecidas, mas com licença BSD. Pelo que lembro, o principal desenvolvedor, Rob Landley, via uma licença mais fácil de aceitar comercialmente como uma forma de o projeto poder ser incluído em dispositivos Android e, com isso, dar a todos os celulares e tablets Android o potencial de virar um ambiente de desenvolvimento parecido com Unix. O Toybox ainda parece fazer parte do Android, mas sem ferramentas de camada superior como o Termux, o Android não é tão fácil de usar como Unix

    • Seria difícil encontrar um exemplo mais didático de como fazer trabalho gratuito para empresas como o Google pode acabar saindo pela culatra
      Ainda mais considerando que o Google passou anos ameaçando bloquear o Termux
  • Também existe um port para Windows: https://github.com/rmyorston/busybox-w32
    O tamanho pequeno do BusyBox torna esse tipo de port mais viável. Mas hoje isso parece um pouco menos relevante, já que agora dá para simplesmente rodar Linux dentro do Windows