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

Как восстановить этот important_file?

Я пробовал что-то вроде

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

но это ничего не делает.

4 ответа4

16

... лучше, чем копировать в определенный момент времени (и собирать только моментальный снимок содержимого файла), это " tail -f " этого файла в новый файл:

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

(благодаря осторожным программистам tail, они будут работать даже с двоичным выходом.)

Во время выполнения tail -f сам сохраняет файл открытым, надежно предотвращая его удаление с диска после завершения работы исходной программы. Таким образом, не остановить tail -f сразу после того, как исходная программа заканчивается - проверить tail'ed /new/path/to/file является первым ли это то , что вы хотите. Если это не так (или неудовлетворительно по какой-либо другой причине), вы можете скопировать исходный файл снова, но на этот раз после того, как вся запись в него завершится с помощью "Программы" и из все еще работающего tail -f 's /proc /PIDoftail /fd / каталог.

11

Если /home - это NFS, в /home /vi будет файл .nfsNNNNNNNNNN, к которому вы сможете получить доступ / скопировать. Если home - это локальная файловая система, вы можете сделать то же самое по ссылке / proc / PID / fd / 3:

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

Если вы действительно хотите восстановить файл, вот пост в блоге на эту тему.

9

Используйте lsof, чтобы найти номер инода, и debugfs, чтобы воссоздать жесткую ссылку на него. Например:

# 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

Прежде чем жаловаться, я подделал приведенную выше стенограмму, так как у меня нет удаленного файла для передачи прямо сейчас ;-)

Я использую mi для сброса времени удаления и количества ссылок на разумные значения (0 и 1 соответственно), но это не работает должным образом - вы можете видеть, что количество ссылок остается на нуле в ls . Я думаю, что ядро может кэшировать данные inode. Вероятно, вы должны использовать fsck при первой же возможности после использования debugfs, чтобы быть в безопасности.

По моему опыту, вы должны создать ссылку, используя временное имя файла, а затем переименовать в правильное имя. Связывание его непосредственно с исходным именем файла может привести к повреждению каталога. YMMV!

3

Вы можете просто cp файл, то есть:

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

Конечно, если файл все еще изменяется, у вас возникнут проблемы с этим подходом.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .