4. Убить демона

Убить системного демона нетрудно, правда? Или. . . все не так просто?
Если ваш демон функционирует как один процесс, все действительно очень просто. Вы командуете killall rsyslogd, и демон системного лога останавливается. Впрочем, этот метод не вполне корректен, так как он действует не только на самого демона, но и на другие процессы с тем же именем. Иногда подобное поведение может привести к неприятным последствиям. Более правильным будет использование pid-файла:


kill $(cat /var/run/syslogd.pid)


Вот, вроде бы, и все, что вам нужно. . . Или мы упускаем еще что-то?
Действительно, мы забываем одну простую вещь: существуют службы, такие, как Apache, crond, atd, которые по роду служебной деятельности должны запускать дочерние процессы. Это могут быть совершенно посторонние, указанные пользователем программы (например, задачи cron/at, CGI-скрипты) или полноценные серверные процессы (например, Apache workers). Когда вы убиваете основной процесс, он может остановить все дочерние процессы. А может и не остановить. В самом деле, если служба функционирует в штатном режиме, ее обычно останавливают командой stop. К прямому вызову kill администратор, как правило, прибегает только в аварийной ситуации, когда служба работает неправильно и может не среагировать на стандартную команду остановки.
Таким образом, убив, например, основной сервер Apache, вы можете получить от него в наследство работающие CGI-скрипты, причем их родителем автоматически станет PID 1 (init), так что установить их происхождение будет не так-то просто.
systemd спешит к нам на помощь. Команда systemctl kill позволит отправить сигнал всем процессам, порожденным в рамках данной службы. Например:


# systemctl kill crond.service


Вы можете быть уверены, что всем процессам службы cron будет отправлен сигнал SIGTERM. Разумеется, можно отправить и любой другой сигнал. Скажем, если ваши дела совсем уж плохи, вы можете воспользоваться и SIGKILL:


# systemctl kill -s SIGKILL crond.service


После ввода этой команды, служба cron будет жестоко убита вместе со всеми ее дочерними процессами, вне зависимости от того, сколько раз она форкалась, и как бы она ни пыталась сбежать из-под нашего контроля при помощи двойного форка или форк-бомбардировки.
Прим. перев.: Стоит особо отметить, что использование контрольных групп не только упрощает процесс уничтожения форк-бомб, но и значительно уменьшает ущерб от работающей форк-бомбы. Так как systemd автоматически помещает каждую службу и каждый пользовательский сеанс в свою контрольную группу по ресурсу процессорного времени, запуск форк-бомбы одним пользователем или службой не создаст значительных проблем с отзывчивостью системы у других пользователей и служб. Таким образом, в качестве основной угрозы форк-бомбардировки остаются лишь возможности исчерпания памяти и идентификаторов процессов (PID). Впрочем, и их тоже можно легко устранить: достаточно задать соответствующие лимиты в конфигурационном файле службы (см. systemd.exec(5)).
В некоторых случаях возникает необходимость отправить сигнал именно основному процессу службы. Например, используя SIGHUP, мы можем заставить демона перечитать файлы конфигурации. Разумеется, передавать HUP вспомогательным процессам в этом случае совершенно необязательно. Для решения подобной задачи неплохо подойдет и классический метод с pid-файлом, однако у systemd и на этот случай есть простое решение, избавляющее вас от необходимости искать нужный файл:


# systemctl kill -s HUP --kill-who=main crond.service


Итак, что же принципиально новое привносит systemd в рутинный процесс убийства демона? Прежде всего: впервые в истории Linux представлен способ принудительной остановки службы, не зависящий от того, насколько добросовестно основной процесс службы выполняет свои обязательства по остановке дочерних процессов. Как уже упоминалось выше, необходимость отправить процессу SIGTERM или SIGKILL обычно возникает именно в нештатной ситуации, когда вы уже не можете быть уверены, что демон корректно исполнит все свои обязанности.
После прочтения сказанного выше у вас может возникнуть вопрос: в чем разница между systemctl kill и systemctl stop? Отличие состоит в том, что kill просто отправляет сигнал заданному процессу, в то время как stop действует по «официально» определенному методу, вызывая команду, определенную в параметре ExecStop конфигурации службы. Обычно команды stop бывает вполне достаточно для остановки службы, и к kill приходится прибегать только в крайних случаях, например, когда служба «зависла» и не реагирует на команды.
Кстати говоря, при использовании параметра «-s», вы можете указывать названия сигналов как с префиксом SIG, так и без него — оба варианта будут работать.
В завершение стоит сказать, что для нас весьма интересным и неожиданным оказался тот факт, что до появления systemd в Linux просто не существовало инструментов, позволяющих корректно отправить сигнал службе в целом, а не отдельному процессу.

Содержание
Вперед - Три уровня выключения
Назад - Преобразование SysV init-скрипта в systemd service-файл