2010-05-14 21 views
14

Estoy trabajando en una aplicación donde necesito detectar un cierre del sistema. Sin embargo, no he encontrado ninguna manera confiable de obtener una notificación sobre este evento.¿Cómo detectar el cierre del sistema pendiente en Linux?

Sé que en el cierre, mi aplicación recibirá una señal SIGTERM seguido de un SIGKILL. Quiero saber si hay alguna manera de consultar si un SIGTERM es parte de una secuencia de apagado?

¿Alguien sabe si hay una manera de consultar eso programáticamente (C API)?

Hasta donde yo sé, el sistema no proporciona ningún otro método para consultar un cierre inminente. Si lo hace, eso resolvería mi problema también. He estado probando runlevels también, pero el cambio en runlevels parece ser instantáneo y sin ningún tipo de advertencia previa.

+0

pregunta interesante. ¿Quieres detener el cierre o simplemente ser notificado? – ereOn

+0

Solo quiero ser notificado. – 341008

+0

Bueno, me di por vencido. He decidido tratar cualquier SIGTERM como un mensaje que el sistema operativo quiere apagar. Mi (lamentable) justificación es que el propósito principal de SIGTERM es pedir educadamente a las aplicaciones que salgan limpiamente y no es probable que alguien con suficientes privilegios emitirá un SIGTERM si no quiere que la aplicación salga. Incluso si no es un apagado, la aplicación debería escucharlo. Esto me lleva a otra pregunta. ¿Cuál es el tiempo mínimo entre un SIGTERM y un SIGKILL en una secuencia de apagado? Sé que se puede configurar utilizando el modificador -t, pero ¿hay un límite mínimo? – 341008

Respuesta

5

No hay manera de determinar si SIGTERM es parte de una secuencia de apagado. Para detectar una secuencia de apagado, puede usar las secuencias de comandos rc.d, como ereOn, y Eric Sepanson, o utilizar mecanismos como DBus.

Sin embargo, desde el punto de vista del diseño no tiene sentido ignorar SIGTERM, incluso si no es parte de un apagado. El objetivo principal de SIGTERM es pedir cortésmente a las aplicaciones que salgan limpiamente y no es probable que alguien con suficientes privilegios emita un SIGTERM si no desea que la aplicación salga.

1

Cuando el sistema se apaga, se llaman los scripts rc.d.

Quizás pueda agregar un script allí que envíe una señal especial a su programa.

Sin embargo, dudo que pueda detener el apagado del sistema de esa manera.

+0

Gracias por la respuesta rápida. No tengo control sobre las máquinas en las que se implementará mi aplicación, así que no puedo cambiar nada en ellas. Además, no quiero detener el cierre. Solo quiero saber cuándo está por ocurrir el cierre. – 341008

+0

Bueno, me temo que no hay mucho más que hacer (al menos, que se me ocurra). Tal vez si nos explica lo que quiere lograr, podemos ayudarlo a encontrar una alternativa. – ereOn

3

Hacer que su aplicación responda de manera diferente a algunas señales SIGTERM que otras parece opaca y potencialmente confusa. Es discutible que siempre respondas de la misma manera a una señal dada. Agregar condiciones inusuales hace que sea más difícil comprender y probar el comportamiento de la aplicación.

Agregar una secuencia de comandos rc que maneja el apagado (mediante el envío de una señal especial) es una forma completamente estándar de manejar ese problema; si este script se instala como parte de un paquete estándar (make install o empaquetado rpm/deb), no debería preocuparse por el control de las máquinas de los usuarios.

5

De hombre apagado:

Si se utiliza el argumento de la hora, 5 minutos antes de que el sistema se apaga el archivo /etc/nologin se crea para garantizar que se No se permitirán más inicios de sesión.

Para que pueda probar la existencia de /etc/nologin. No es óptimo, pero probablemente lo mejor que puedas obtener.

+0

Hmm .. Me pregunto si puede usar 'inotifywait' para responder a su creación ... – Izkata

10

Tal vez un poco tarde. Sí, puede determinar si un SIGTERM se encuentra en un proceso de cierre al invocar el comando nivel de ejecución.Ejemplo:

#!/bin/bash 
trap "runlevel >$HOME/run-level; exit 1" term 
read line 
echo "Input: $line" 

guardarlo como, por ejemplo, term.sh y ejecutarlo. Al ejecutar killall term.sh, debería poder ver e investigar el archivo run-level en su directorio personal. Mediante la ejecución de cualquiera de los siguientes:

sudo reboot 
sudo halt -p 
sudo shutdown -P 

y compare la diferencia en el archivo. Entonces deberías tener la idea de cómo hacerlo.

2

Es un poco de un truco pero si el servidor se está ejecutando systemd si se puede ejecutar

/bin/systemctl list-jobs shutdown.target

... reportará ...

JOB UNIT   TYPE STATE 
755 shutdown.target start waiting  <---- existence means shutting down 

1 jobs listed. 

... si el servidor se está cerrando o reiniciando (sugerencia: hay un reinicio.objetivo si desea buscar específicamente eso)

Obtendrá No jobs running. i f no se está cerrando.

Tiene que analizar la salida que es un poco desordenada ya que el sistema no devuelve un código de salida diferente para los dos resultados. Pero parece razonablemente confiable. Deberá tener cuidado con un cambio de formato en los mensajes si actualiza el sistema.

+0

esto no parece funcionar para mí –

+0

Gracias, funciona para mí – Javi

2

Creo que lo tengo.

Fuente = https://github.com/mozilla-b2g/busybox/blob/master/miscutils/runlevel.c

copio parte del código que aquí, por si acaso la referencia desaparece.

#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"); 
0

La respuesta práctica para hacer lo que originalmente quería decir que compruebe el proceso de apagado (por ejemplo ps aux | grep "-h apagado") y luego, si usted quiere estar seguro de comprobar su línea de comandos argumentos y hora en que se inició (por ejemplo, "shutdown -h +240" iniciado a las 14:51 se cerrará a las 18:51).

En el caso general hay desde el punto de vista de todo el sistema no hay forma de hacerlo. Hay muchas maneras diferentes en que puede ocurrir un "cierre". Por ejemplo, alguien puede decidir desconectarse para detener un programa que ahora tiene un comportamiento malo/peligroso en el momento del cierre o un UPS podría primero enviar un SIGHUP y luego simplemente fallar. Como tal apagado puede ocurrir repentinamente y sin previo aviso en ningún lugar del sistema, no hay forma de estar seguro de que está bien seguir corriendo después de un SIGHUP.

Si un proceso recibe SIGHUP, debe asumir básicamente que algo más desagradable seguirá pronto. Si quieres hacer algo especial e ignorar parcialmente SIGHUP, entonces a) necesitas coordinar eso con cualquier programa que haga el apagado yb) necesitas estar listo que si otro sistema lo apaga y te mata poco después de un SIGHUP su software y datos sobrevivirán. Escriba todos los datos que tenga y solo continúe escribiendo para adjuntar solo archivos con actualizaciones atómicas seguras.

Para su caso, estoy casi seguro de que su solución actual (tratar todos los SIGHUP como un apagado) es la forma correcta de hacerlo. Si desea mejorar las cosas, probablemente debería agregar una función al programa de apagado que hace una notificación a través del DBUS o algo similar.

1

ver man systemctl, se puede determinar si el sistema se está cerrando de esta manera:

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

esto es en bash, pero puede hacerlo con 'sistema' en C

Cuestiones relacionadas