Substituindo o script de shell enquanto o executa

4

Eu tenho uma placa que está executando um script "patch". O script de correção sempre é executado em segundo plano e é um script de shell que executa o seguinte pseudo-código:

while true; do
    # checks if a patch tar file exists and if yes then do patching
    sleep 10
done

Este script está em /opt/patch.sh e foi iniciado pelo script de inicialização SystemV.

O problema é que quando o script encontra o tar, ele é extraído e dentro dele há um script de shell chamado patch.sh que é específico para o conteúdo do tar.

Quando o script em /opt/patch.sh encontra o tar, ele faz o seguinte:

tar -xf /opt/update.tar -C /mnt/update
mv /mnt/update/patch.sh /opt/patch.sh
exec /opt/patch.sh

Ele se substitui pelo outro script e o executa do mesmo local. Pode ocorrer algum problema ao fazer isso?

    
por ErectCrested 25.04.2017 / 20:13

3 respostas

3

Se o arquivo for substituído por escrito no local (inode permanece o mesmo), qualquer processo que tenha aberto verá os novos dados se / quando lerem do arquivo. Se for substituído por desvincular o arquivo antigo e criar um novo com o mesmo nome, o número do inode será alterado e qualquer processo que mantenha o arquivo aberto ainda terá o arquivo antigo .

mv pode fazer qualquer um, dependendo se o movimento acontece entre os sistemas de arquivos ou não ... Para ter certeza de obter um arquivo completamente novo, desvincule ou renomeie o original primeiro. Algo parecido com isto:

mv /opt/patch.sh /opt/patch.sh.old     # or rm
mv /mnt/update/patch.sh /opt/patch.sh

Dessa forma, o shell em execução ainda teria um identificador de arquivo para os dados antigos, mesmo após a movimentação.

Dito isso, até onde eu testei, o Bash lê todo o loop antes de executar qualquer um deles, portanto, qualquer alteração no arquivo subjacente não levará a mudança do script de execução enquanto a execução permanecer dentro do loop. Após sair do loop, o Bash retoma a leitura do arquivo de entrada da posição logo após o término do loop. Eu não tenho certeza se a leitura do loop completo é apenas para que ele possa verificar a sintaxe (pode estar faltando o final done ), ou se é para fins de cache.

Todas as funções definidas no script também são carregadas na memória, portanto, colocar a lógica principal do script em uma função e apenas chamá-la no final tornaria o script bastante seguro contra modificações no arquivo:

#!/bin/sh
main() {
    do_stuff
    exit
}
main

De qualquer forma, não é muito difícil testar o que acontece quando um script é sobrescrito:

$ cat > old.sh <<'EOF'
#!/bin/bash
for i in 1 2 3 4 ; do
        # rm old.sh
        cat new.sh > old.sh 
        sleep 1
        echo $i
done
echo will this be reached?
EOF
$ cat > new.sh <<'EOF'
#!/bin/bash
echo xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
echo xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
echo xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
echo xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
EOF
$ bash old.sh

Com o rm old.sh comentado, o script será alterado no local. Sem o comentário, um novo arquivo será criado.

    
por 25.04.2017 / 22:39
0

Já tive esse problema antes e posso confirmar que isso pode ser um problema. No meu caso, um script de regressão primeiro executa um git pull e pode ser atualizado depois que ele for executado, causando problemas.

O problema é geralmente quando o shell vai voltar e verifica se há mais linhas para interpretar. Isso pode causar erros, mesmo quando o código desejado está dentro de um loop. Para evitar isso, use a estrutura em este post .

    
por 25.04.2017 / 23:14
0

Um script auto-executável e auto-modificável? Isso não é uma boa ideia.

Uma solução melhor seria criar um daemon stub com funcionalidade mínima (ou seja, responsável por instalar novas versões do script escravo e invocá-lo em intervalos). Algo como ... (não testado)

while true; do
  # check if a patch tar file exists and if yes then do patching
  if [ -f "$PATCH" ]; then
      ( cd /usr/local/mydaemon \
      && tar -xzf "$PATCH" \
      && rm -f "$PATCH" ) \
      || exit -1
  fi
  $SCRIPT
  sleep 10
done
    
por 25.04.2017 / 23:15