Восстановление открытого файла

Восстановление открытого файла

У меня есть интересная проблема, которая может иметь решение, а может и нет, но я бы хотел его получить, если это возможно:

В Solaris был удален открытый файл журнала, который по-прежнему заполняется во время выполнения процесса, но теперь недоступен для всех других инструментов, таких как cat, tailи т. д.

Есть ли способ восстановить запись в каталоге для этого файла, пока все работает?

решение1

Это осуществимо, с некоторыми хакерскими способностями и ограничениями (вам потребуются права root).

Сначала найдите, какой файловый дескриптор использует приложение для записи файла журнала, а затем создайте символическую ссылку в предыдущем местоположении файла журнала, указывающую на запись файла /proc, например:

ln -s /var/tmp/file.log /proc/12345/fd/3

Первое ограничение заключается в том, что если файл был открыт только для записи процессом, его разрешение не позволит непривилегированному пользователю прочитать его содержимое. Однако root и пользователи с привилегией file_dac_read не будут затронуты. В качестве альтернативы вы можете использовать процесс для копирования содержимого файла, как tailпредлагает Жиль в своем комментарии. Например:

tail -c +1 -f /proc/12345/fd/5 > /var/tmp/file.log

ln -sВторая проблема заключается в том, что все содержимое файла ( ) или его часть ( ) будет потеряно, tail -c 1 -fкогда процесс закроет его или завершит работу.

Обходной путь — использовать программу, которая отслеживает это событие и создает резервную копию файла перед фактическим вызовом close.

Вероятные инструменты для выполнения этой работы — dtrace, truss, mdb или dbx.

Вот доказательство концепции с использованием dtrace на Solaris 10.

#!/bin/ksh
#
# This dtrace script is monitoring a file descriptor for a given process
# and copy its content to the given path when the file is closed.
#

pid=${1:?"$0: Usage: pid fd path"}
fd=${2:?}
path=${3:?}
[[ -f $path ]] && { echo "$path exists"; exit 1; }
dtrace -w -n '
syscall::close:entry
/pid=='$pid' && arg0=='$fd'/
{
        stop();
        system("cp /proc/%d/fd/%d %s",pid,arg0,"'"$path"'");
        system("prun %d",pid);
        exit(0);
}'

Связанный контент