Vinculando um arquivo excluído

33

Às vezes, as pessoas excluem arquivos que não deveriam, um processo de longa execução ainda tem o arquivo aberto e a recuperação dos dados por catting /proc/<pid>/fd/Nnão é impressionante o suficiente. O mais impressionante seria se você pudesse "desfazer" a exclusão executando uma opção mágica em ln que permitiria que você se vinculasse novamente ao número do inode (recuperado através de lsof).

Não consigo encontrar nenhuma ferramenta Linux para fazer isso, pelo menos com o Google superficial.

O que você tem, falha no servidor?

EDIT1: A razão pela qual capturar o arquivo /proc/<pid>/fd/Nnão é impressionante o suficiente é porque o processo que ainda tem o arquivo aberto ainda está gravando nele. Uma exclusão remove a referência ao inode do espaço para nome do sistema de arquivos. O que eu quero é uma maneira de recriar a referência.

EDIT2: 'debugfs ln' funciona, mas o risco é muito alto, pois gera dados brutos do sistema de arquivos. O arquivo recuperado também é louco inconsistente. A contagem de links é zero e não consigo adicionar links. Estou pior desse jeito, já que posso apenas /proc/<pid>/fd/Nacessar os dados sem corromper meu fs.

mbac32768
fonte

Respostas:

14

O mais impressionante seria se você pudesse "desfazer" a exclusão executando uma opção mágica em ln que permitiria que você se vinculasse novamente ao número do inode (recuperado através de lsof).

Essa grandiosidade foi introduzida lnna v8.0 (GNU / coreutils) com a -L|--logicalopção que faz lncom que a desreferencia seja a /proc/<pid>/fd/<handle>primeira. Então, um simples

ln -L /proc/<pid>/fd/<handle> /path/to/deleted/file

é suficiente para vincular novamente um arquivo excluído.

tnimeu
fonte
7
Isso não funciona; se o arquivo for excluído, ele falhará.
Random832
1
Não, não vai. Eu o uso regularmente para restaurar arquivos excluídos, mas ainda abertos. Mas você precisa ter certeza de que o novo /path/to/deleted/fileestá no mesmo sistema de arquivos que o arquivo estava pouco antes de ser excluído; caso contrário, isso realmente irá falhar. (Você pode obter o caminho antigo com ls -l /proc/<pid>/fd/<handle>)
tnimeu
2
Esse tipo de funcionalidade (consulte esta pergunta e resposta) foi especificamente rejeitado como um risco de segurança [para um esquema de segurança hipotético que gira em torno de um processo privilegiado, fornecendo ao processo um identificador de arquivo somente leitura para um arquivo que você possui, mas que de outra forma não tem acesso a ]; Eu tentei (embora com um pequeno programa C para usar diretamente a chamada de sistema relevante) e não funcionou.
usar o seguinte comando
7
Obviamente, eu testei isso antes de postar minha solução e, na época, ela realmente funcionou para mim. O que eu não sabia era que só funcionava em tmpfssistemas de arquivos, mas não em, por exemplo ext3. Além disso, esse recurso foi completamente desativado na 2.6.39, consulte o commit . Portanto, esta solução não funcionará mais com o kernel 2.6.39 ou mais recente e, nas versões anteriores, depende do sistema de arquivos.
tnimeu
7
@tnimeu ln -Lnão funciona para mim. Eu tenho um arquivo excluído e tentei vinculá-lo novamente ao caminho original. lnme dá um ln: failed to create hard link /my/path/file.pdf => /proc/19674/fd/16: No such file or directory. Mas eu posso, por exemplo, com sucessocat /proc/19674/fd/16
Eugene Beresovsky
13

Parece que você já entende muito, então não vou entrar em detalhes em excesso. Existem vários métodos para encontrar o inode e, geralmente, você pode gato e redirecionar STDOUT. Você pode usar debugfs. Execute este comando dentro de:

ln <$INODE> FILENAME

Verifique se você possui backups do sistema de arquivos. Você provavelmente precisará executar um fsck depois. Eu testei isso com sucesso com um inode ainda sendo gravado e funciona para criar um novo link físico para um inode não referenciado.

Se o arquivo for desvinculado de um arquivo fechado no ext3, os dados serão perdidos. Não tenho certeza de quão consistentemente isso é verdade, mas a maior parte da minha experiência de recuperação de dados está no ext2. Na FAQ do ext3:

P: Como posso recuperar (excluir) arquivos excluídos da minha partição ext3? Na verdade, você não pode! Isto é o que um dos desenvolvedores, Andreas Dilger, disse sobre isso:

Para garantir que o ext3 possa retomar com segurança um desassociação após uma falha, ele zera os ponteiros do bloco no inode, enquanto o ext2 apenas marca esses blocos como não utilizados nos bitmaps do bloco e marca o inode como "excluído" e sai do bloco ponteiros sozinho.

Sua única esperança é "grep" para partes de seus arquivos que foram excluídos e esperar o melhor.

Há também informações relevantes nesta pergunta:

Eu substituí um arquivo grande por um em branco em um servidor Linux. Posso recuperar o arquivo existente?

Warner
fonte
Espero que o comentário seja excluído, pois não foi revelado.
Mdpc
1
No caso de um arquivo excluído, mas ainda aberto, não acho que zeraria os ponteiros no inode. Além disso, em vez de usar "ln" no debugfs, eu usaria "undel" para que as contagens de referência do inode sejam atualizadas corretamente.
Mark Wagner
Eu não quis aludir como tal, embobo. Não, testei o desempenho. Eu esclarei meu idioma.
Warner
Inteligente, mas corrompe meu sistema de arquivos. :)
mbac32768
É a única solução para o cenário que você descreve. Manipular um sistema de arquivos em um nível baixo montado rw e gravado ativamente provavelmente causará corrupção em quase todos os cenários.
Warner
8

a maneira como você viu os debugfs realmente não funciona e, na melhor das hipóteses, seu arquivo será excluído automaticamente (devido ao diário) após a reinicialização e, na pior das hipóteses, você pode lixeira no seu sistema de arquivos resultante de "reboot cycle of death". A solução certa (TM) é executar a exclusão no nível do VFS (que também possui o benefício adicional de trabalhar com praticamente todos os sistemas de arquivos Linux atuais). A maneira de chamada do sistema (flink) foi abatida toda vez que apareceu no LKML, portanto a melhor maneira é através de um módulo + ioctl.

Um projeto que implementa essa abordagem e possui um código razoavelmente pequeno e limpo é o fdlink ( https://github.com/pkt/fdlink.git para uma versão testada com o kernel do ubuntu maverick). Com ele, depois de inserir o módulo (sudo insmod flink_dev.ko), você pode simplesmente fazer "./flinkapp / proc // fd / X / meu / link / caminho" e ele fará exatamente o que você deseja.

Você também pode usar uma versão de porta direta do vfs-undelete.sourceforge.net que também funciona (e também pode vincular automaticamente novamente ao nome original), mas o código do fdlink é mais simples e funciona da mesma forma, portanto, é minha preferência.

pktoss
fonte
3

Não sei como fazer exatamente o que você deseja, mas o que eu faria é:

  • Abra o arquivo RO de outro processo
  • Aguarde o processo original sair
  • Copie os dados do seu FD aberto para um arquivo

Não é o ideal, obviamente, mas é possível. A outra opção é brincar com os debugfs (usando o linkcomando), mas isso é meio assustador em uma máquina de produção!

Bill Weiss
fonte
O comando debugfs link não suporta esse caso de uso.
mbac32768
tldp.org/HOWTO/Ext2fs-Undeletion-11.html sugere que sim. Eu não tentei, mas isso parece razoável.
Bill Weiss
linknão funcionou nos meus testes, mas lnfuncionou.
Warner
3

Encontrei o mesmo problema hoje. O melhor que eu poderia pensar é correr

% tail -n +0 -f /proc/<pid>/fd/<fd> /path/to/deleted_file

em uma sessão tmux / screen até o processo terminar.

nickray
fonte
2
A vinculação aos arquivos originais, como na resposta aceita, deve funcionar.
Chris S
1
Não há uma resposta aceita para esta pergunta, a qual você está se referindo?
Hamman Samuel 04/02
Isso não precisa de um redirecionamento ( >) para o arquivo excluído?
Ncsas 13/09/19
1

Pergunta interessante. Um entrevistador me fez a mesma pergunta em uma entrevista de emprego. O que eu disse a ele foi que não havia uma maneira fácil de fazer isso e, em geral, não valia o tempo e o esforço envolvidos. Perguntei a ele o que ele achava que a solução para esse problema era ....

  1. Use lsof para encontrar o número do inode no disco para o processo, pois ele ainda aparecerá, mesmo que o arquivo tenha sido excluído ... a chave é que ele ainda está aberto.
  2. Extraia as informações do sistema de arquivos com base nisso, através de um depurador do sistema de arquivos.
mdpc
fonte
Posso extrair os dados muito bem de / proc / <pid> / fd / N, mas não é isso que estou tentando fazer.
mbac32768
1

Use Sleuthkit icat.

sudo icat /dev/rdisk1s2 5484287 > accidentally_deleted_open_file
Isaac
fonte
Isso funciona ignorando a funcionalidade do sistema de arquivos do sistema operacional e analisando os bytes do disco diretamente.
Flimm
0

A solução rápida que funcionou para mim, sem ferramentas intimidantes:

1) encontre o processo + fd olhando diretamente em / proc:

ls -al /proc/*/fd/* 2>/dev/null | grep {filename}

2) Em seguida, uma técnica semelhante à @ nickray's, pvlançada em:

tail -c +0 -f /proc/{procnum}/fd/{fdnum} | pv -s {expectedsize} > {recovery_filename}

Pode ser necessário pressionar Ctrl-C quando terminar ( ls /proc/{procnum}/fd/{fdnum}informará que o arquivo não existe mais), mas se você souber o tamanho exato em bytes, poderá usá pv -S-lo para sair quando a contagem for atingida.

xenoid
fonte