Как обнаружить завершение работы системы в Linux? - PullRequest
19 голосов
/ 14 мая 2010

Я работаю над приложением, в котором мне нужно обнаружить завершение работы системы. Однако я не нашел надежного способа получить уведомление об этом событии.

Я знаю, что при завершении работы мое приложение получит сигнал SIGTERM, за которым следует SIGKILL. Я хочу знать, есть ли способ запросить, является ли SIGTERM частью последовательности выключения ?

Кто-нибудь знает, есть ли способ запросить это программно (C API)?

Насколько я знаю, система не предоставляет никакого другого метода для запроса на предстоящее завершение работы. Если это произойдет, это решит и мою проблему. Я тоже пробовал runlevels, но изменения в runlevels кажутся мгновенными и без каких-либо предварительных предупреждений.

Ответы [ 9 ]

11 голосов
/ 27 ноября 2013

Может быть, немного поздно.Да, вы можете определить, находится ли SIGTERM в процессе выключения, вызвав команду runlevel .Пример:

#!/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

и сравните разницу в файле.Тогда у вас должна быть идея, как это сделать.

6 голосов
/ 20 мая 2010

Нет способа определить, является ли SIGTERM частью последовательности выключения.Чтобы обнаружить последовательность выключения, вы можете использовать сценарии rc.d, например, как предложили ereOn и Эрик Сепансон, или использовать механизмы, такие как DBus.

Однако с точки зрения дизайна не имеет смысла игнорировать SIGTERM, даже если он не является частью отключения.Основная цель SIGTERM состоит в том, чтобы вежливо попросить приложений выйти корректно, и маловероятно, что кто-то с достаточными привилегиями выдаст SIGTERM, если он / она не хочет, чтобы приложение выходило.1010 *

5 голосов
/ 02 ноября 2011

От выключения человека:

Если используется аргумент времени, за 5 минут до отключения системы файл /etc/nologin создан для того, чтобы дальнейшие входы в систему не допускается.

Таким образом, вы можете проверить существование /etc/nologin. Это не оптимально, но, вероятно, лучшее, что вы можете получить.

3 голосов
/ 14 мая 2010

То, что ваше приложение реагирует на некоторые сигналы SIGTERM иначе, чем на других, кажется непрозрачным и потенциально запутанным. Можно утверждать, что вы всегда должны одинаково реагировать на данный сигнал. Добавление необычных условий усложняет понимание и тестирование поведения приложения.

Добавление сценария rc, который обрабатывает завершение работы (отправляя специальный сигнал), является полностью стандартным способом решения такой проблемы; если этот сценарий установлен как часть стандартного пакета (make install или пакета rpm / deb), не стоит беспокоиться о контроле над пользовательскими машинами.

2 голосов
/ 13 января 2017

см. man systemctl, вы можете определить, выключается ли система, следующим образом:

if [ "`systemctl is-system-running`" = "stopping" ]; then
    # Do what you need
fi

это в bash, но вы можете сделать это с 'system' в C

2 голосов
/ 17 июля 2016

Я думаю, что понял.

Источник = 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");
2 голосов
/ 17 февраля 2016

Немного хак, но если на сервере работает 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 не возвращает различный код выхода для двух результатов. Но это кажется достаточно надежным. Однако при обновлении системы вам нужно будет следить за изменением формата сообщений.

1 голос
/ 21 сентября 2016

Практический ответ, чтобы сделать то, что вы изначально хотели, состоит в том, что вы проверяете процесс завершения работы (например, ps aux | grep "shutdown -h"), а затем, если хотите быть уверенным, проверяете его аргументы командной строки и определяете время был запущен (например, «shutdown -h +240», запущенный в 14:51, завершит работу в 18:51).

В общем случае с точки зрения всей системы нет способа сделать это. Есть много разных способов «выключения». Например, кто-то может решить отключить штепсельную вилку, чтобы жестко остановить программу, которая сейчас имеет плохое / опасное поведение во время выключения, или ИБП может сначала отправить SIGHUP, а затем просто дать сбой. Поскольку такое отключение может произойти внезапно и без предупреждения нигде в системе, невозможно быть уверенным, что после SIGHUP можно продолжать работу.

Если процесс получает SIGHUP, вы должны предположить, что в скором времени последует что-то более неприятное. Если вы хотите сделать что-то особенное и частично игнорировать SIGHUP, то а) вам нужно согласовать это с любой программой, которая выполнит выключение, и б) вы должны быть готовы к тому, что, если какая-то другая система завершит работу и убьет вас мертвыми вскоре после SIGHUP Ваше программное обеспечение и данные выживут. Запишите все имеющиеся у вас данные и продолжайте записывать только в файлы только для добавления с безопасными атомарными обновлениями.

В вашем случае я почти уверен, что ваше текущее решение (рассматривайте все SIGHUP как остановку) - правильный путь. Если вы хотите что-то улучшить, вам, вероятно, следует добавить в программу завершения работы функцию, которая делает уведомление через DBUS или что-то подобное.

1 голос
/ 14 мая 2010

Когда система выключается, вызываются сценарии rc.d.

Может быть, вы можете добавить туда скрипт, который посылает какой-то особый сигнал вашей программе.

Однако я сомневаюсь, что таким образом вы можете остановить отключение системы.

...