Ви випадково видалили важливий лог-файл і використання команди ls це підтверджує. Проте процес, який працює з цим файлом, досі активний. Це означає, що дані фізично залишаються на диску, і ви маєте можливість повернути їх до моменту завершення роботи відповідного процесу.
Коли ви виконуєте команду rm, операційна система Linux видаляє лише запис із каталогу та зменшує лічильник посилань на файл. Якщо хоча б один процес утримує цей файл відкритим, ядро систем збереже відповідний inode.
І зараз ми дізнаємось, як такі файли відновлювати.
Як влаштоване видалення файлів у Linux
Під час виклику rm ядро виключає файл із файлового дерева, після чого він зникає з результатів видачі ls. Однак блоки на диску не звільняються миттєво. Якщо процеси зберігають відкритий файловий дескриптор, кількість посилань на inode залишається більшою за нуль.
Миттєве звільнення блоків ядра відбувається лише тоді, коли останній процес закриває файловий дескриптор або завершує свою роботу. Тільки після цього лічильник посилань падає до нуля, а блоки позначаються як вільні для нового запису.
Отже, якщо вебсервер, СУБД або сервіс збору логів продовжують запис у видалений файл, ваші дані залишаються неушкодженими. Отримати до них доступ можна через спеціальний інтерфейс, який ядро надає у віртуальній файловій системі /proc.
Крок 1. Пошук процесу, який утримує файл відкритим
Для виявлення необхідного процесу використовується утиліта lsof (List Open Files), яка відображає всі файлові дескриптори, відкриті в системі.
Якщо утиліта відсутня у вашій системі, встановіть її за допомогою відповідного пакетного менеджера.
Для Debian, Ubuntu та Mint:
sudo apt install lsof
Для RHEL, CentOS, Fedora, Rocky та AlmaLinux:
sudo dnf install lsof
Використання sudo є обов’язковим, оскільки файлові дескриптори сторонніх процесів недоступні для звичайного користувача.
Виконайте пошук видаленого файла за його назвою або за ключовим словом deleted:
sudo lsof | grep deleted
Приклад виводу:
nginx 1423 www-data 4w REG 253,1 204800 131074 /var/log/nginx/access.log (deleted)
rsyslogd 1201 root 7w REG 253,1 819200 131075 /var/log/syslog (deleted)
Зверніть увагу на такі параметри у виводі:
- Друга колонка (PID): ідентифікатор процесу (наприклад,
1423). - Четверта колонка (FD): номер файлового дескриптора (наприклад,
4wабо7w). - Остання колонка: шлях до файла із позначкою (
deleted).
Якщо файл не відображається за допомогою grep, скористайтеся прапорцем +L1, який виводить усі файли з кількістю посилань менше ніж 1:
sudo lsof +L1
Приклад виводу:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NLINKS NODE NAME
nginx 1423 www-data 4w REG 253,1 204800 0 131074 /var/log/nginx/access.log (deleted)
Значення 0 у колонці NLINKS підтверджує, що запис у директорії вилучено, проте ядро все ще утримує дані в пам’яті та на диску.
Крок 2. Відновлення файла через віртуальну систему /proc
Ядро Linux транслює файлові дескриптори процесів у директорію /proc/<PID>/fd/. У цій структурі кожен дескриптор представлений у вигляді символьного посилання на оригінальний шлях, навіть якщо сам файл був видалений із файлової системи.
Згідно з виводом lsof, процес nginx має PID 1423 та дескриптор 4. Відповідно, повний шлях до відкритих даних буде наступним: /proc/1423/fd/4.
Скопіюйте вміст за допомогою стандартної команди cp:
sudo cp /proc/1423/fd/4 /var/log/nginx/access.log.recovered
Відсутність повідомлень у консолі після виконання команди свідчить про успішне завершення операції.
Перевірте розмір та наявність створеного файла:
ls -lh /var/log/nginx/access.log.recovered
Приклад виводу:
-rw-r--r-- 1 root root 200K May 6 03:14 /var/log/nginx/access.log.recovered
Якщо розмір відповідає очікуваному, дані успішно відновлено. Ви можете перемістити файл на початкове місце або використати за призначенням.
Важливо: Скопійований файл є точковим знімком на момент виконання cp. Якщо процес продовжує запис, нові дані надходитимуть у /proc/<PID>/fd/4, але не потраплять до відновленого файла. Щоб відновити коректний запис у нову файлову структуру, перезапустіть відповідний сервіс.
Якщо при доступі до /proc/<PID>/fd/4 ви отримуєте помилку Permission denied, переконайтеся, що команда виконується з правами root, або перевірте існування PID:
ps aux | grep PID
Автоматизація відновлення
Виконання послідовності команд вручну під час інцидентів підвищує ризик помилки. Для прискорення процесу можна використати Shell-функцію, яка автоматизує пошук дескриптора та копіювання даних.
recover_deleted() {
local filename="$1"
local output="${2:-/tmp/recovered_file}"
local result
result=$(sudo lsof +L1 2>/dev/null | grep "$filename")
if [[ -z "$result" ]]; then
echo "No process holds $filename open. Data may already be gone."
return 1
fi
local pid fd
pid=$(echo "$result" | awk 'NR==1{print $2}')
fd=$(echo "$result" | awk 'NR==1{print $4}' | tr -d 'rwu')
echo "Found: PID=$pid FD=$fd"
sudo cp /proc/"$pid"/fd/"$fd" "$output" && echo "Recovered to $output"
}
Додайте цей код до вашого конфігураційного файла ~/.bashrc або загального дотфайла системного адміністратора та оновіть конфігурацію сесії.
Виклик функції здійснюється наступним чином:
recover_deleted /var/log/nginx/access.log /var/log/nginx/access.log.recovered
Приклад виводу:
Found: PID=1423 FD=4
Recovered to /var/log/nginx/access.log.recovered
Якщо файл утримується кількома процесами одночасно, виконуйте відновлення з дескриптора з найбільшим обсягом даних. Перевірити розміри можна командою:
sudo ls -lh /proc/<PID>/fd/<FD>
Що робити, якщо процес уже завершив роботу
Після того як процес закриє дескриптор або завершить виконання, ядро звільняє блоки файлової системи. На цьому етапі доступ через /proc стає неможливим.
У таких випадках необхідно переходити до низькорівневого відновлення даних з блокового пристрою. Для цього використовуються спеціалізовані утиліти:
extundelete— для файлових системext3/ext4;testdiskабоphotorec— для ширшого спектра файлових систем.
Ці інструменти аналізують неопрацьовані блоки диска, тому успішне відновлення не гарантується, особливо за умов активного перезапису даних. Метод із використанням /proc є значно надійнішим, оскільки працює безпосередньо з живими даними ядра.
Забороняється запускати extundelete або аналогічні утиліти на змонтованій файловій системі в режимі запису (read-write). Перед початком роботи обов’язково демонтуйте розділ або завантажтесь з Live USB, щоб запобігти перезапису блоків, які ви намагаєтеся відновити.
Захист від випадкового видалення
Для критично важливих файлів логів можна завчасно створити жорстке посилання. Це створить додатковий запис у директорії, який вказуватиме на той самий inode. У такому разі випадкове виконання rm зменшить лічильник посилань, але не обнулить його.
Створення жорсткого посилання:
ln /var/log/nginx/access.log /var/log/nginx/access.log.hardlink
Перевірка відповідності inode:
ls -li /var/log/nginx/access.log /var/log/nginx/access.log.hardlink
Приклад виводу:
131074 -rw-r--r-- 2 www-data www-data 204800 May 6 03:14 /var/log/nginx/access.log
131074 -rw-r--r-- 2 www-data www-data 204800 May 6 03:14 /var/log/nginx/access.log.hardlink
Обидва файли мають однаковий номер inode (131074) та значення лічильника посилань 2. Видалення оригінального файла /var/log/nginx/access.log лише зменшить лічильник до 1, а самі дані залишаться доступними за шляхом жорсткого посилання.
Зверніть увагу, що жорсткі посилання працюють виключно в межах однієї файлової системи. Якщо вам потрібен захист між різними монтованими розділами, використовуйте механізм mount --bind.
Висновки
Використання файлової системи /proc/<PID>/fd/ — це ефективний механізм відновлення даних у Linux, який дозволяє швидко усувати наслідки помилкового видалення активних файлів.
Основний алгоритм дій:
- Виявити PID процесу та номер дескриптора за допомогою
lsof +L1. - Скопіювати актуальний стан даних із
/proc/<PID>/fd/<FD>до завершення процесу. - Використовувати автоматизований Shell-скрипт для прискорення процедури в критичних ситуаціях.
Ви можете протестувати цей процес у тестовому середовищі: створіть файл, відкрийте його через tail -f в одному терміналі, видаліть за допомогою rm в іншому, знайдіть дескриптор через lsof +L1 та виконайте відновлення:
cp /proc/<PID>/fd/<FD> /tmp/recovered

