Solução para a cabeça do busybox que baixa o NUL dos dados

2

TL; DR: O busybox (1.23.2) mais recente forneceu head com bugs e ficará feliz com os caracteres NUL nos dados fornecidos. Substituir os binários não é uma opção. Eu estou usando head -[nc] -X em meus scripts, existe uma maneira que eu possa imitá-lo com outras ferramentas fornecidas pelo busybox?

Pessoas não familiarizadas com o upload de arquivos e com o manuseio do busybox pelo httpd podem querer ler isto antes de continuar.

Estou tentando processar uploads de dados recebidos por scripts CGI em um sistema embarcado com o Busybox instalado. Os dados enviados são os seguintes:

$ hexdump -C foo.bin
00000000  03 15 20 00 00 00 75 73  74 61 72 30 30 30 2e 30  |.. ...ustar000.0|
00000010  00 11 00                                          |...|
00000013

Quando enviado por uma solicitação POST, o script CGI que manipula os dados recebe os seguintes dados:

$ hexdump -C 24593.tmp 
00000000  2d 2d 2d 2d 2d 2d 2d 2d  2d 2d 2d 2d 2d 2d 2d 2d  |----------------|
00000010  2d 2d 2d 2d 2d 2d 2d 2d  2d 2d 30 65 34 32 32 64  |----------0e422d|
00000020  63 39 65 64 65 32 34 36  34 30 0d 0a 43 6f 6e 74  |c9ede24640..Cont|
00000030  65 6e 74 2d 44 69 73 70  6f 73 69 74 69 6f 6e 3a  |ent-Disposition:|
00000040  20 66 6f 72 6d 2d 64 61  74 61 3b 20 6e 61 6d 65  | form-data; name|
00000050  3d 22 66 69 6c 65 22 3b  20 66 69 6c 65 6e 61 6d  |="file"; filenam|
00000060  65 3d 22 66 6f 6f 2e 62  69 6e 22 0d 0a 43 6f 6e  |e="foo.bin"..Con|
00000070  74 65 6e 74 2d 54 79 70  65 3a 20 61 70 70 6c 69  |tent-Type: appli|
00000080  63 61 74 69 6f 6e 2f 6f  63 74 65 74 2d 73 74 72  |cation/octet-str|
00000090  65 61 6d 0d 0a 0d 0a 03  15 20 00 00 00 75 73 74  |eam...... ...ust|
000000a0  61 72 30 30 30 2e 30 00  11 00 0d 0a 2d 2d 2d 2d  |ar000.0.....----|
000000b0  2d 2d 2d 2d 2d 2d 2d 2d  2d 2d 2d 2d 2d 2d 2d 2d  |----------------|
000000c0  2d 2d 2d 2d 2d 2d 30 65  34 32 32 64 63 39 65 64  |------0e422dc9ed|
000000d0  65 32 34 36 34 30 2d 2d  0d 0a                    |e24640--..|
000000da

Para recuperar os dados originais acima, é fácil:

$ tail -n +5 24593.tmp | head -n -1 | head -c -2 | hexdump -C
00000000  03 15 20 00 00 00 75 73  74 61 72 30 30 30 2e 30  |.. ...ustar000.0|
00000010  00 11 00                                          |...|
00000013

No entanto, o busybox tem um head quebrado e elimina todos os caracteres NUL nos dados:

$ /firmware/system/xbin/tail -n +5 24593.tmp | /firmware/system/xbin/head -n -1 | /firmware/system/xbin/head -c -2 | hexdump -C
00000000  03 15 20 75 73 74 61 72  30 30 30 2e 30 11        |.. ustar000.0.|
0000000e

Existe algum outro método pelo qual eu possa emular o comportamento de head -[nc] -X (ou pelo menos realizar o trabalho) com outras ferramentas fornecidas pelo busybox?

A coisa mais prudente a fazer é introduzir / substituir um novo binário com o comportamento correto, mas isso não pode ser feito por uma série de razões pelas quais não precisamos entrar aqui.

Este post também parece ser amplamente dedicado a mencionar detalhes que são irrelevantes para o problema em questão, mas eu apresento os detalhes aqui para evitar o XY .

    
por user2064000 25.06.2015 / 08:19

2 respostas

1

Se eu entendi sua pergunta corretamente, você quer extrair um arquivo enviado de uma solicitação que consiste em:

  • uma linha que consiste em traços seguidos de dígitos hexadecimais;
  • um monte de linhas não vazias (cabeçalhos);
  • uma linha vazia;
  • o conteúdo a extrair;
  • quebra de linha;
  • uma repetição da primeira linha;

em que as quebras de linha são uma sequência CRLF e o conteúdo pode conter bytes arbitrários, mas os cabeçalhos não contêm bytes nulos.

Em vez de confiar em head e tail para analisar linhas, você pode fazer isso em duas etapas:

  1. Determine o intervalo de posições de bytes que você deseja extrair.
  2. Extraia esses bytes.

Na primeira etapa, para evitar problemas com bytes nulos, use tr para traduzi-los para outra coisa. Então você pode usar uma ferramenta baseada em linha para detectar a primeira linha vazia e para detectar o início da última linha. Eu uso o awk abaixo e aproveito a oportunidade para também extrair o nome do arquivo. Se você não tiver o awk, poderá usar head , tail , sed ,…

Para a segunda etapa, você pode usar dd com um tamanho de bloco de 1. Isso é lento, mas confiável.

upload=24593.tmp
filename=$(<"$upload" tr '
upload=24593.tmp
filename=$(<"$upload" tr '%pre%' _ | awk '
    {line_start = line_end; line_end += length($0)+1}
    !content_start && /^Content-Disposition:.*filename="/ {
        sub(/.*filename="/, ""); sub(/".*/, "");
        filename = $0
    }
    !content_start && $0=="\r" {content_start=line_end}
    END {print content_start, line_start-2-content_start, filename}
')
skip=${filename%% *}; filename=${filename#* }
count=${filename%% *}; filename=${filename#* }
if [ -z "$filename" ]; then filename=$(mktemp); fi
<$upload dd bs=1 skip="$skip" count="$count" >"$filename"
' _ | awk ' {line_start = line_end; line_end += length($0)+1} !content_start && /^Content-Disposition:.*filename="/ { sub(/.*filename="/, ""); sub(/".*/, ""); filename = $0 } !content_start && $0=="\r" {content_start=line_end} END {print content_start, line_start-2-content_start, filename} ') skip=${filename%% *}; filename=${filename#* } count=${filename%% *}; filename=${filename#* } if [ -z "$filename" ]; then filename=$(mktemp); fi <$upload dd bs=1 skip="$skip" count="$count" >"$filename"
    
por 26.06.2015 / 02:47
0

O Busybox é altamente configurável, então a resposta dependerá do que foi compilado. Aqui estão algumas opções.

catv -v

mostrará nulos como '^ @'.

split -l 1

criará arquivos xaa xab etc, cada um com uma linha.

    
por 25.06.2015 / 15:16