У меня есть интересная проблема, которая может иметь решение, а может и нет, но я бы хотел его получить, если это возможно:
В 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);
}'