Jak odzyskać usunięty plik, jeśli nadal jest otwarty przez jakiś proces?

18
$ 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)

Jak to odzyskać important_file?

Próbowałem czegoś takiego

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

ale nic nie robi.

Vi.
źródło

Odpowiedzi:

11

Jeśli / home to NFS, w katalogu / home / vi będzie plik .nfsNNNNNNNNNN, do którego można uzyskać dostęp / skopiować. Jeśli home jest lokalnym systemem plików, powinieneś być w stanie zrobić to samo za pomocą linku / proc / PID / fd / 3:

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

Jeśli chcesz cofnąć usunięcie pliku, oto post na blogu na ten temat.

Mark Johnson
źródło
1
OK, byłem zdezorientowany tym readlink /proc/13381/fd/3-> „/ home / vi / important_file (usunięty)” i /home/vi/important_file\ \(deleted\)oczywiście nie istnieje.
Vi.
18

... lepiej niż kopiowanie w danym momencie (i gromadzenie tylko migawki tego pliku z zawartością) jest „ tail -f” dodanie tego pliku do nowego pliku:

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

(dzięki ostrożnym programistom tail, którzy będą nawet pracować z wyjściem binarnym.)

Podczas działania tail -fsam utrzymuje plik otwarty, bezpiecznie zapobiegając jego wyczyszczeniu z dysku po zakończeniu oryginalnego programu. Dlatego nie zatrzymuj się tail -fnatychmiast po zakończeniu oryginalnego programu - /new/path/to/filenajpierw sprawdź, czy to jest to, czego chcesz. Jeśli nie jest (lub jest niezadowalający z jakiegokolwiek innego powodu), możesz ponownie skopiować oryginalny plik, ale tym razem po zakończeniu zapisywania do niego przez „Program” i nadal działającego programu tail -f/ proc / PIDoftail / katalog fd /.

chrześcijanin
źródło
3
Co z utworzeniem twardego łącza do / proc / PIDofProgram> / fd / #?
becko
2
@becko Invalid cross-device link.
Kamil Maciorowski
9

Użyj lsof, aby znaleźć numer i-węzła, a debugfs, aby odtworzyć twardy link do niego. Na przykład:

# 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

Zanim narzekasz, sfałszowałem powyższą transkrypcję, ponieważ nie mam teraz pod ręką usuniętego pliku ;-)

Używam, miaby zresetować czas usuwania i liczbę linków do rozsądnych wartości (odpowiednio 0 i 1), ale to nie działa poprawnie - widać, że liczba linków pozostaje na zero ls. Myślę, że jądro może buforować dane i-węzła. Prawdopodobnie powinieneś fsck jak najszybciej po użyciu debugfs, aby być bezpiecznym.

Z mojego doświadczenia wynika, że ​​należy utworzyć łącze przy użyciu tymczasowej nazwy pliku, a następnie zmienić nazwę na prawidłową. Łączenie go bezpośrednio z oryginalną nazwą pliku powoduje uszkodzenie katalogu. YMMV!

Andrew Gallagher
źródło
Dlaczego dokładnie to sugerujesz, jeśli tak naprawdę nie działa poprawnie i powoduje uszkodzenie systemu? Myślę, że powinieneś mieć bardziej żywe zastrzeżenie w ramach odpowiedzi, że jest to po prostu WiP i nie należy go wypróbowywać w produkcji.
cnst
3

Możesz po prostu cpplik, tzn .:

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

Oczywiście, jeśli plik jest nadal modyfikowany, będziesz mieć kłopoty z tym podejściem.

ninjalj
źródło