Как восстановить удалённый лог через файловый дескриптор

Живое вмешательство. File descriptors и GDB.

 читать первым в телеграм    читать первым в макс

Написать статью для #балансбатл навеяли 2 события разной давности:

  1. Вопрос на собесе со мной в качестве соискателя: «Что такое файл в Linux?»
  2. Прочтение поста Романа «Один рубит — семеро в хуй трубят».

Что такое файл в Linux, читателю я предлагаю изучить самостоятельно или Роману раскрыть эту тему подробнее.

Роман Шубин
Роман Шубин
CEO & CTO, Главред в «Цифровой улей»
Задать вопрос
Ключевое: файл — это некая абстракция для всего, что можно читать или записывать. Идея — «В Linux всё — это файл».

Далее эту идею постараюсь протянуть тонкой нитью через статью «Один рубит — семеро в хуй трубят».

Кратко: на собесе Серёжа удалил /var/log/nginx/access.log, далее обсуждается несколько моментов:

а) «Серёжа, а почему файл access.log пропал и больше не появляется? Nginx-то в данный момент работает, запросы на него идут»;

б) «Где карта, Билли? Нам нужна карта!»;

в) «Внятного ответа не получил, что-то на уровне — он появится спустя сутки, когда logrotate отработает. Да-да… будем сутки без логов сидеть».

Отвечаем на вопросы и решаем проблемы

а) удаление файлов в Linux лишь убирает название файла из файла каталога, но inode с данными остаётся, пока его держит открытым хоть один процесс.

Так что это не проблема. Идём дальше.

б) и в) Помогаем Билли с картой и не сидим сутки без логов.

Пока процесс открыт, он продолжает держать fd (файловые дескрипторы), даже если файл удалён.

1. Проверим утверждение. Пишем скрипт

#!/bin/bash

echo $$ > /tmp/nginx.pid
exec 3> /tmp/access.log
while true; do
    echo "$(date) Где карта Билли? Нам нужна карта!!!" >&3
    sleep 1
done

2. Запускаем, читаем логи

$ ./simple.sh &
[2] 13502
$ tail -f /tmp/access.log
Sun Aug 10 23:15:42 MSK 2025 Где карта Билли? Нам нужна карта!!!
Sun Aug 10 23:15:43 MSK 2025 Где карта Билли? Нам нужна карта!!!

3. Удалим файл

rm /tmp/access.log

4. Процесс продолжает писать в файл

Смотрим (PID знаем, смотри выше):

$ ls -l /proc/13502/fd
total 0
lrwx------ 1 aflw aflw 64 Aug 10 23:23 0 -> /dev/pts/0
lrwx------ 1 aflw aflw 64 Aug 10 23:23 1 -> /dev/pts/0
lrwx------ 1 aflw aflw 64 Aug 10 23:23 2 -> /dev/pts/0
lr-x------ 1 aflw aflw 64 Aug 10 23:23 255 -> /home/aflw/planka-backup/simple.sh
l-wx------ 1 aflw aflw 64 Aug 10 23:23 3 -> '/tmp/access.log (deleted)'

Или так (тут PID схватим по-другому), через watch наглядно:

watch -n1 -d "lsof -p $(cat /tmp/nginx.pid) | grep deleted"

Every 1.0s: lsof -p 13502 | grep deleted
simple.sh 13502 aflw    3w   REG   8,32   188825 17988 /tmp/access.log (deleted)

5. Билли возвращает карту

cp /proc/13502/fd/3 /tmp/access.log.restored

Вуаля! Дескриптор НЕ потерялся, процесс не сошёл с ума, логи восстановлены.

Что дальше? Файл-то удалён!

Представим, что у нас серьёзный PROD, тяжеленный «Билли»нговый демон СверхБербанка, где перезапуск = потеря соединений и часовое восстановление сессий!

Подкинем новый файл /tmp/access_new.log без перезапуска процесса. Будем использовать отладчик gdb.

1. Запускаем

sudo gdb -p $(cat /tmp/nginx.pid)

2. Выполняем внутри gdb

GNU gdb (Ubuntu 12.1-0ubuntu1~22.04.2) 12.1
# открываем новый файл для логов
(gdb) call (int) open("/tmp/access_new.log", 66, 0644)
$1 = 4 # новый файловый дескриптор

(gdb) call (int) dup2(4, 3) # дублируем fd 4 в позицию 3.
$2 = 3

(gdb) call (int) close(4) # Закрываем временный fd 4
$3 = 0

(gdb) detach
Detaching from program: /usr/bin/bash, process 13502
[Inferior 1 (process 13502) detached]

(gdb) quit

3. Проверяем файловые дескрипторы процесса и лог

$ ls -l /proc/13502/fd
total 0
lrwx------ 1 aflw aflw 64 Aug 10 23:23 0 -> /dev/pts/0
lrwx------ 1 aflw aflw 64 Aug 10 23:23 1 -> /dev/pts/0
lrwx------ 1 aflw aflw 64 Aug 10 23:23 2 -> /dev/pts/0
lr-x------ 1 aflw aflw 64 Aug 10 23:23 255 -> /home/aflw/planka-backup/simple.sh
lrwx------ 1 aflw aflw 64 Aug 10 23:23 3 -> /tmp/access_new.log
$ tail -f /tmp/access_new.log
Mon Aug 11 00:17:54 MSK 2025 Где карта Билли? Нам нужна карта!!!
Роман Шубин
Роман Шубин
CEO & CTO, Главред в «Цифровой улей»
Задать вопрос
На этом всё. Процесс пишет в новый файл с тем же дескриптором.

Комментарии