如何在RedHat系统中编程判断系统即将重启并区分信号触发原因?
Great question! Distinguishing between signals sent by system shutdown/reboot vs user-initiated termination is a common pain point, especially when you need to conditionally save state. Let's break down the solutions tailored for your Red Hat system, since RHEL uses different init systems depending on the version.
For RHEL 7+ (systemd-based systems)
Systemd creates a dedicated marker file when scheduling a shutdown or reboot, which is the most reliable way to distinguish system-initiated signals from user ones. Here's what you can do:
- Check the shutdown marker file: When systemd plans a reboot or poweroff, it creates
/run/systemd/shutdown/scheduled. This file contains plaintext details likeUSEC=1700000000000 MODE=reboot(for reboot) orMODE=poweroff(for shutdown). - In your signal handler: When your app receives
SIGTERMorSIGHUP, check if this file exists and parse its content to confirm if a system shutdown/reboot is in progress.
Python Example
import signal import os def handle_system_signal(signum, frame): shutdown_marker = "/run/systemd/shutdown/scheduled" system_shutdown = False if os.path.exists(shutdown_marker): with open(shutdown_marker, "r") as f: content = f.read() if "MODE=reboot" in content or "MODE=poweroff" in content: system_shutdown = True if system_shutdown: print("System reboot/shutdown detected — saving application state...") # Add your state-saving logic here else: print("User-initiated termination — skipping state save.") exit(0) # Register handlers for TERM and HUP signals signal.signal(signal.SIGTERM, handle_system_signal) signal.signal(signal.SIGHUP, handle_system_signal) # Keep the app running (replace with your actual application logic) while True: pass
C Example
#include <stdio.h> #include <signal.h> #include <unistd.h> #include <fcntl.h> #include <string.h> #include <stdlib.h> void handle_signal(int signum, siginfo_t *info, void *context) { int fd = open("/run/systemd/shutdown/scheduled", O_RDONLY); int is_system_shutdown = 0; if (fd != -1) { char buf[256]; ssize_t read_bytes = read(fd, buf, sizeof(buf) - 1); if (read_bytes > 0) { buf[read_bytes] = '\0'; if (strstr(buf, "MODE=reboot") || strstr(buf, "MODE=poweroff")) { is_system_shutdown = 1; } } close(fd); } if (is_system_shutdown) { printf("System reboot/shutdown detected — saving state...\n"); // Add state-saving logic here } else { printf("User-initiated termination — no state save.\n"); } exit(0); } int main() { struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_sigaction = handle_signal; sa.sa_flags = SA_SIGINFO; sigaction(SIGTERM, &sa, NULL); sigaction(SIGHUP, &sa, NULL); while (1) { pause(); } return 0; }
For RHEL 6 and older (SysVinit-based systems)
Older RHEL versions use SysVinit, which relies on runlevels to trigger shutdown/reboot:
- Runlevel 0 = Shutdown
- Runlevel 6 = Reboot
You can:
- Check if the system is transitioning to runlevel 0 or 6 using the
runlevelcommand, or by reading the/var/run/utmpfile directly. - Verify the existence of the
/var/run/shuttingdownmarker file (created by some SysVinit implementations during shutdown).
Quick Bash Check (can be called from your app)
target_runlevel=$(runlevel | awk '{print $2}') if [ "$target_runlevel" = "0" ] || [ "$target_runlevel" = "6" ]; then echo "System shutdown/reboot in progress" else echo "User-initiated termination" fi
Key Notes
- Permissions: The marker files (
/run/systemd/shutdown/scheduledand/var/run/shuttingdown) are world-readable, so even non-root apps can access them. - Timing: Systemd creates the shutdown marker before sending termination signals to services, so your signal handler will always see the file if the signal is system-initiated.
- Edge Cases: Avoid relying solely on signal sender PID checks (e.g., checking if the sender is PID 1) — user-initiated signals via
sudo killcan also trace back to PID 1, leading to false positives.
内容的提问来源于stack exchange,提问作者Mark Arnold
相关产品推荐
相关产品推荐

