Как обнаружить ожидающее отключение системы в Linux?
Я работаю над приложением, где мне нужно обнаружить выключение системы.
Однако я не нашел надежного способа получить уведомление об этом событии.
Я знаю, что при выключении мое приложение получит сигнал SIGTERM
, за которым следует SIGKILL
. Я хочу знать, есть ли способ запросить, если SIGTERM
является частью последовательности выключения?
Кто-нибудь знает, есть ли способ запросить это программно (C API)?
Насколько я знаю, система не предоставляет какой-либо другой метод для запроса о предстоящем завершении работы. Если да, это также решит мою проблему. Я также пробовал runlevels
, но изменение в runlevels
кажется мгновенным и без каких-либо предварительных предупреждений.
Ответы
Ответ 1
Невозможно определить, является ли SIGTERM
частью последовательности выключения. Чтобы обнаружить последовательность выключения, вы можете использовать скрипты rc.d
, такие как ereOn и Eric Sepanson, или использовать такие механизмы, как DBus.
Однако, с точки зрения дизайна, нет смысла игнорировать SIGTERM
, даже если он не является частью выключения. SIGTERM
Основная цель - вежливо просить приложения выйти из системы чисто, и маловероятно, что кто-то с достаточными правами выдаст SIGTERM
, если он/она не хочет, чтобы приложение выходило.
Ответ 2
Может быть, немного поздно. Да, вы можете определить, находится ли SIGTERM в завершающем процессе, вызывая команду уровень выполнения. Пример:
#!/bin/bash
trap "runlevel >$HOME/run-level; exit 1" term
read line
echo "Input: $line"
сохраните его как, скажем, term.sh
и запустите его. Выполняя killall term.sh
, вы должны увидеть и исследовать файл run-level
в своем домашнем каталоге. Выполняя любое из следующих действий:
sudo reboot
sudo halt -p
sudo shutdown -P
и сравните разницу в файле. Тогда у вас должна быть идея о том, как это сделать.
Ответ 3
Отключение пользователя:
Если используется аргумент времени, за 5 минут до спуска системы файл /etc/nologin
создается для обеспечения того, чтобы дальнейшие логины не допускается.
Итак, вы можете проверить существование /etc/nologin
. Это не оптимально, но, вероятно, лучше всего вы можете получить.
Ответ 4
Приведение вашего приложения в соответствие с некоторыми сигналами SIGTERM, чем другие, кажется непрозрачным и потенциально запутанным. Это доказывает, что вы всегда должны реагировать одинаково на определенный сигнал. Добавление необычных условий затрудняет понимание и тестирование поведения приложения.
Добавление rc script, который обрабатывает выключение (путем отправки специального сигнала), является полностью стандартным способом решения такой проблемы; если этот script установлен как часть стандартного пакета (make install
или rpm/deb), не должно быть никаких проблем с управлением пользовательскими машинами.
Ответ 5
Немного взломать, но если сервер работает systemd, если вы можете запустить
/bin/systemctl list-jobs shutdown.target
... он сообщит...
JOB UNIT TYPE STATE
755 shutdown.target start waiting <---- existence means shutting down
1 jobs listed.
... если сервер выключается или перезагружается (подсказка: там reboot.target, если вы хотите посмотреть конкретно на это)
Вы получите No jobs running.
, если он не будет завершен.
Вам нужно разобрать вывод, который немного беспорядочен, так как systemctl не возвращает другой код выхода для двух результатов. Но это кажется достаточно надежным. Если вы обновите систему, вам нужно будет следить за изменением формата сообщений.
Ответ 6
Я думаю, что понял.
Источник =
https://github.com/mozilla-b2g/busybox/blob/master/miscutils/runlevel.c
Я копирую часть кода здесь, на всякий случай эта ссылка исчезает.
#include "libbb.h"
...
struct utmp *ut;
char prev;
if (argv[1]) utmpname(argv[1]);
setutent();
while ((ut = getutent()) != NULL) {
if (ut->ut_type == RUN_LVL) {
prev = ut->ut_pid / 256;
if (prev == 0) prev = 'N';
printf("Runlevel: prev=%c current=%c\n", prev, ut->ut_pid % 256);
endutent();
return 0;
}
}
puts("unknown");
Ответ 7
Когда система выключается, вызывается сценарий rc.d
.
Возможно, вы можете добавить script там, где вы посылаете специальный сигнал в вашу программу.
Однако, я сомневаюсь, что вы можете остановить остановку системы таким образом.
Ответ 8
Практический ответ на то, что вы изначально хотели, это то, что вы проверяете процесс выключения (например, ps aux | grep "shutdown -h" ), а затем, если вы хотите убедиться, что вы проверяете его аргументы командной строки и время (например, "shutdown -h +240", начатое в 14:51, завершится в 18:51).
В общем случае с точки зрения всей системы нет способа сделать это. Существует много разных способов "остановки". Например, кто-то может решить вытащить вилку, чтобы сильно остановить программу, что теперь у них плохое/опасное поведение во время выключения, или ИБП может сначала отправить SIGHUP, а затем просто потерпеть неудачу. Так как такое завершение работы может произойти внезапно и без предупреждения в любой точке системы, нет никакого способа убедиться, что все в порядке продолжать работать после SIGHUP.
Если процесс получает SIGHUP, вы должны в принципе предполагать, что скоро произойдет что-то более неприятное. Если вы хотите сделать что-то особенное и частично проигнорировать SIGHUP, тогда a) вам нужно координировать это с любой программой, которая сделает остановку, и b) вам нужно быть готовым к тому, что если какая-либо другая система выключит компьютер и убивает вас вскоре после SIGHUP ваше программное обеспечение и данные сохранятся. Выпишите все данные, которые у вас есть, и продолжайте запись только в файлы append с безопасными атомными обновлениями.
В вашем случае я почти уверен, что ваше текущее решение (рассматривайте все SIGHUP как закрытие) - это правильный путь. Если вы хотите улучшить ситуацию, вы, вероятно, должны добавить функцию к программе выключения, которая уведомляет через DBUS или что-то подобное.
Ответ 9
см. man systemctl
, вы можете определить, закрывается ли система следующим образом:
if [ "`systemctl is-system-running`" = "stopping" ]; then
# Do what you need
fi
это в bash, но вы можете сделать это с помощью 'system' в C