Como recuperar um arquivo excluído se ele ainda estiver aberto por algum processo?

19
$ cat important_file > /dev/null &
[1] 9711
$ rm important_file 
$ killall -STOP cat

[1]+  Stopped                 cat important_file > /tmp/p
$ ls -l /proc/`pidof cat`/fd/
total 0
lrwx------ 1 vi vi 64 May 13 20:32 0 -> /dev/pts/29
l-wx------ 1 vi vi 64 May 13 20:32 1 -> /tmp/p
lrwx------ 1 vi vi 64 May 13 20:32 2 -> /dev/pts/29
lr-x------ 1 vi vi 64 May 13 20:32 3 -> /home/vi/important_file (deleted)

Como recuperar isso important_file?

Eu tentei algo como

injcode -m dup2 -ofd=3 -ofilename=/tmp/recovered_file -oflags=O_CREAT $PID_OF_CAT

mas não faz nada.

Vi.
fonte

Respostas:

11

Se / home for NFS, haverá um arquivo .nfsNNNNNNNNNNN em / home / vi que você poderá acessar / copiar. Se home for um sistema de arquivos local, você poderá fazer o mesmo através do link / proc / PID / fd / 3:

cp /proc/PID/fd/3 /tmp/recovered_file

Se você realmente deseja cancelar a exclusão do arquivo, aqui está uma postagem de blog sobre o assunto.

Mark Johnson
fonte
11
OK, fiquei confuso com isso readlink /proc/13381/fd/3-> "/ home / vi / important_file (excluído)" e, /home/vi/important_file\ \(deleted\)obviamente, não existe.
Vi.
22

... melhor do que copiar em um determinado momento (e reunir apenas o instantâneo do conteúdo do arquivo) é " tail -f" esse arquivo em um novo arquivo:

tail -c +0 -f /proc/PIDofProgram>/fd/# > /new/path/to/file

(graças aos programadores cautelosos da cauda, ​​que funcionam até com saída binária).

Durante o tempo de execução, tail -fele próprio mantém o arquivo aberto, impedindo com segurança que ele seja removido do disco quando o programa original terminar. Portanto, não pare tail -fimediatamente após o término do programa original - verifique /new/path/to/fileprimeiro se é o que você deseja. Se não for (ou não for satisfatório por qualquer outro motivo), você poderá copiar o arquivo original novamente, mas desta vez depois de concluir a gravação no "Programa" e no tail -fdiretório / proc / PIDoftail / fd / diretório.

cristão
fonte
3
Que tal criar um hardlink para / proc / PIDofProgram> / fd / #?
Becko
2
@becko Invalid cross-device link.
Kamil Maciorowski
10

Use lsof para encontrar o número do inode e debugfs para recriar um link físico para ele. Por exemplo:

# lsof -p 12345 | grep /var/log/messages
syslogd 12345 root    3w   REG                8,3    3000    987654 /var/log/messages (deleted)
# mount | grep var
/dev/sda2 on /var type ext3 (rw)
# debugfs -w /dev/sda2
debugfs: cd log
debugfs: ln <987654> tmp
debugfs: mi tmp
                      Mode    [0100600] 
                   User ID    [0] 
                  Group ID    [0] 
                      Size    [3181271] 
             Creation time    [1375916400] 
         Modification time    [1375916322] 
               Access time    [1375939901]
             Deletion time    [9601027] 0
                Link count    [0] 1
               Block count    [6232] 
                File flags    [0x0] 
...snip...
debugfs:  q
# mv /var/log/tmp /var/log/messages
# ls -al /var/log/messages
-rw------- 0 root root 3301 Aug  8 10:10 /var/log/messages

Antes de você reclamar, falsifiquei a transcrição acima, pois não tenho um arquivo excluído no momento ;-)

Eu uso mipara redefinir o tempo de exclusão e a contagem de links para valores sensíveis (0 e 1 respectivamente), mas não funciona corretamente - você pode ver que a contagem de links permanece em zero ls. Eu acho que o kernel pode estar armazenando em cache os dados do inode. Você provavelmente deve fsck na primeira oportunidade depois de usar o debugfs, para estar do lado seguro.

Na minha experiência, você deve criar o link usando um nome de arquivo temporário e renomear para o nome apropriado. Vinculá-lo diretamente ao nome do arquivo original parece causar corrupção no diretório. YMMV!

Andrew Gallagher
fonte
Por que exatamente você está sugerindo isso se realmente não funciona corretamente e causa danos ao sistema? Acho que você deve ter um aviso mais claro na resposta de que este é simplesmente um WiP e não deve ser realmente experimentado na produção.
CNST
3

Você pode apenas cpo arquivo, ou seja:

cp /proc/<pid>/fd/<fdno> /new/path/to/file

Obviamente, se o arquivo ainda estiver sendo modificado, você terá problemas com essa abordagem.

ninjalj
fonte