recuperando o arquivo deletado mantido aberto pelo apache?

10

Suponha que um arquivo de log do apache seja excluído, mas mantido aberto pelo apache; então é isso que estou fazendo:

pid=$(lsof | grep text.txt | awk '/deleted/ {print $2}')
fd=$(lsof | grep text.txt | awk '/deleted/ {print $4}' | grep -oE "[[:digit:]]{1,}")

cp /proc/$pid/fd/$fd directorytobecopied/testfile.txt

Isso é o que estou fazendo para recuperar o arquivo e colocá-lo de volta onde estava. Existe alguma maneira mais simples de fazer isso porque o código acima não parece bom. Além disso, como eu sei de onde o arquivo foi excluído ( directorytobecopied ) para que eu não tenha para perguntar manualmente a alguém onde o arquivo estava localizado originalmente e colocá-lo de volta.

    
por munish 20.12.2012 / 05:21

1 resposta

14

Se um arquivo foi excluído, mas ainda está aberto, isso significa que o arquivo ainda existe no sistema de arquivos (ele tem um inode ) mas tem um link link físico de 0. Como não há link para o arquivo, não é possível abri-lo até nome. Não há facilidade para abrir um arquivo por inode.

Não há como descobrir o arquivo através de seu sistema de arquivos e, especialmente, nenhuma maneira de procurar o arquivo no diretório em que ele durou. A entrada do diretório desapareceu. Tudo o que resta é o próprio arquivo. Você pode acessar o arquivo com um depurador de sistema de arquivos, mas isso requer permissões de root e é difícil de usar e propenso a erros.

O Linux expõe arquivos abertos através de links simbólicos especiais em /proc . Esses links são chamados /proc/12345/fd/42 onde 12345 é o PID de um processo e 42 é o número de um descritor de arquivo nesse processo. Um programa em execução como o mesmo usuário desse processo pode acessar o arquivo (as permissões de leitura / gravação / execução são as mesmas que você tinha quando o arquivo foi excluído).

O nome sob o qual o arquivo foi aberto ainda é visível no destino do link simbólico: se o arquivo for /var/log/apache/foo.log , o destino do link será /var/log/apache/foo.log (deleted) . (Se o arquivo foi renomeado depois que ele foi aberto, o destino do link simbólico pode refletir a renomeação).

Assim, você pode recuperar o conteúdo de um arquivo excluído aberto, considerando o PID de um processo que o tenha aberto e o descritor que ele abriu assim:

recover_open_deleted_file () {
  old_name=$(readlink "$1")
  case "$old_name" in
    *' (deleted)')
      old_name=${old_name%' (deleted)'}
      if [ -e "$old_name" ]; then
        new_name=$(TMPDIR=${old_name%/*} mktemp)
        echo "$oldname has been replaced, recovering content to $new_name"
      else
        new_name="$old_name"
      fi
      cat <"$1" >"$new_name";;
    *) echo "File is not deleted, doing nothing";;
  esac
}
recover_open_deleted_file "/proc/$pid/fd/$fd"

Se você conhece apenas o ID do processo, mas não o descritor, você pode recuperar todos os arquivos com

for x in /proc/$pid/fd/*; do
  recover_open_deleted_file "$x"
done

Se você também não conhece o ID do processo, pode pesquisar entre todos os processos:

for x in /proc/[1-9]*/fd/*; do
  case $(readlink "$x") in
    /var/log/apache/*) recover_open_deleted_file "$x";;
  esac
done

Você também pode obter essa lista analisando a saída de lsof , mas não é mais simples nem mais confiável nem mais portátil (de qualquer forma, isso é específico do Linux).

    
por 21.12.2012 / 03:07