Зима меня что-то прям знатно так подзаебала, тысяча одёжек, реанимация автомобиля в -40, то дождь за шиворот, то метель в морду лица. Всё же летом как-то попроще мне кажется, хотя и жара сильно изматывает. Нежные мы стали с этой удалёнкой, жёсткая зависимость от зоны комфорта. Ладно…
Начинать неделю с ебобо-постов очень не хочется, поэтому давай расслабим булки и решим одну интересную, нетривиальную задачку.
Можно ли после запуска скрипта, перенаправить STDOUT и STDERR в другое место, не останавливая сам скрипт/процесс? Ответ ты и сам знаешь, конечно можно! Ща покажу как.
Чтобы все стало понятным, берем для эксперимента такую команду и запускаем ее в терминале.
tail -f /var/log/auth.log &
Запускаем в фоне просмотр логов авторизации. Задачка запустилась в фоне и отдала нам консоль обратно в интерактивное состояние.
Как только в файле auth.log появляются новые записи, оно начинает нам срать в терминал, мешая дальнейшей работе. Хоть задача и запущена в фоне, но активно работает с текущим tty и stdout.
Чтобы нам все это дело отправить в dev/null не останавливая фоновую задачу/скрипт. Проделываем следующий трюк:
ps aux | grep tail
Узнаём PID процесса, в моём случае это 1327692, далее смотрим файловые дескрипторы этого процесса:
ls -l /proc/1327692/fd
Получаем нечто подобное:
0 -> /dev/pts/1
1 -> /dev/pts/1
2 -> /dev/pts/1
3 -> /var/log/auth.log
Знакомо? stdout = 1 (поток вывода), stderr = 2 (поток с ошибками) и т.п. Уже наталкивает на мысль чо будем делать? Нет? Поехали дальше.
Теперь каким-то образом, надо зареврайтить это говнище в dev/null. Для этого будем использовать утилиту gdb, она обычно идет в коробке либо ставится через апт-инсталл.
gdb - отладчик для программ, написанных на Си. Отладчик позволяет выполнить программу пошагово, посмотреть значения всех переменных на каждом из этапов выполнения, а если это необходимо, то и дизассемблировать код и посмотреть состояние регистров процессора.
Запускаем кракена:
gdb -p 1327692 /usr/bin/tail
Подключаемся к процессу 1327692 и указываем путь до tail. На экран вывалит кучу всякого мусора, не пугайся, он тебе не нужен.
Всё, теперь ты находишься в «хакерской» оболочке (gdb), начинаем реврайтить говнище. Вводим такие команды:
p (int) dup2((int) open("/dev/null", 0), 1)
p (int) dup2((int) open("/dev/null", 0), 2)
На экран получишь нечто подобное:
$1 = 1
$2 = 2
После этого закрываем gdb:
detach
quit
Вот и всё. Говнище из auth.log перестало выводиться на экран, хотя фоновый процесс продолжает работать. Смотрим что у нас получилось:
ls -l /proc/1327692/fd
И видим что наш реврайт сработал:
0 -> /dev/pts/1
1 -> /dev/null
2 -> /dev/null
3 -> /var/log/auth.log
4 -> anon_inode:inotify
5 -> /dev/null
6 -> /dev/null
Разберем команды gdb
«p» (print), выводим результат команды на экран.
«dup2», дублирует файловый дескриптор. Первым аргументом идет файловый дескриптор, который нужно продублировать. Второй аргумент это новый файловый дескриптор, который нужно использовать.
Все это дело приводим к типу Int, хотя раньше и без этого всё отлично работало, видимо что-то поменялось.
И получается такое: Команда сначала открывает файл dev/null, затем дублирует его файловый дескриптор, а затем перенаправляет stdout в этот файл. Прозрачно? Прозрачно!
Вот такие пироги. Надеюсь было интересно.
Кстати чтобы не упарываться с gdb, существует софтина под названием reredirect, делает то же самое, если интересно, можешь потыкать, ссылка git на репозиторий.
Ставь лайк, подписывайся, рекомендуй друзьям. Хорошей тебе рабочей недели!








Комментарии