Home | History | Annotate | Line # | Download | only in dist
      1 /*
      2  * Signal handlers
      3  */
      4 
      5 #include "ctwm.h"
      6 
      7 #include <signal.h>
      8 #include <stdio.h>
      9 #include <stdlib.h>
     10 #include <unistd.h>
     11 #include <errno.h>
     12 #include <sys/wait.h>
     13 
     14 #include "ctwm_shutdown.h"
     15 #include "signals.h"
     16 
     17 
     18 /* Our backends */
     19 static void sh_restart(int signum);
     20 static void sh_shutdown(int signum);
     21 
     22 
     23 // Internal flags for which signals have called us
     24 static bool sig_restart = false;
     25 static bool sig_shutdown = false;
     26 
     27 // External flag for whether some signal handler has set a flag that
     28 // needs to trigger an action.
     29 bool SignalFlag = false;
     30 
     31 void ChildExit(int signum)
     32 {
     33 	int Errno = errno;
     34 	/* reap dead children, ignore status */
     35 	while (waitpid(-1, NULL, WNOHANG) > 0)
     36 		continue;
     37 	/* restore errno for interrupted sys calls */
     38 	errno = Errno;
     39 }
     40 
     41 /**
     42  * Setup signal handlers (run during startup)
     43  */
     44 void
     45 setup_signal_handlers(void)
     46 {
     47 	// INT/QUIT/TERM: shutdown
     48 	// XXX Wildly unsafe handler; to be reworked
     49 	signal(SIGINT,  sh_shutdown);
     50 	signal(SIGQUIT, sh_shutdown);
     51 	signal(SIGTERM, sh_shutdown);
     52 
     53 	// SIGHUP: restart
     54 	signal(SIGHUP, sh_restart);
     55 
     56 	// We don't use alarm(), but if we get the stray signal we shouldn't
     57 	// die...
     58 	signal(SIGALRM, SIG_IGN);
     59 
     60 	/* Setting SIGCHLD to SIG_IGN detaches children from the parent
     61 	 * immediately, so it need not be waited for.
     62 	 * In fact, you cannot wait for it, so a function like system()
     63 	 * breaks.
     64 	 */
     65 	signal(SIGCHLD, ChildExit);
     66 
     67 	return;
     68 }
     69 
     70 
     71 /**
     72  * Handle stuff set by a signal flag.  Could be a Restart, could be a
     73  * Shutdown...
     74  */
     75 void
     76 handle_signal_flag(Time t)
     77 {
     78 	// Restarting?
     79 	if(sig_restart) {
     80 		// In case it fails, don't loop
     81 		sig_restart = false;
     82 
     83 		// Handle
     84 		DoRestart(t);
     85 
     86 		// Shouldn't return, but exec() might fail...
     87 		return;
     88 	}
     89 
     90 	// Shutting down?
     91 	if(sig_shutdown) {
     92 		// Doit
     93 		DoShutdown();
     94 
     95 		// Can't return!
     96 		fprintf(stderr, "%s: DoShutdown() shouldn't return!\n", ProgramName);
     97 		exit(1);
     98 	}
     99 
    100 	// ???
    101 	fprintf(stderr, "%s: Internal error: unexpected signal flag.\n",
    102 	        ProgramName);
    103 	return;
    104 }
    105 
    106 
    107 
    108 /*
    109  * Internal backend bits
    110  */
    111 
    112 /**
    113  * Set flag to restart.  Backend for SIGHUP.
    114  */
    115 static void
    116 sh_restart(int signum)
    117 {
    118 	// Signal handler; stdio isn't async-signal-safe, write(2) is
    119 	const char srf[] = ":  signal received, setting restart flag\n";
    120 	write(2, ProgramName, ProgramNameLen);
    121 	write(2, srf, sizeof(srf));
    122 
    123 	SignalFlag = sig_restart = true;
    124 }
    125 
    126 /**
    127  * Set flag to shutdown.  Backend for SIGTERM etc.
    128  */
    129 static void
    130 sh_shutdown(int signum)
    131 {
    132 	// Signal handler; stdio isn't async-signal-safe, write(2) is
    133 	const char srf[] = ":  signal received, setting shutdown flag\n";
    134 	write(2, ProgramName, ProgramNameLen);
    135 	write(2, srf, sizeof(srf));
    136 
    137 	SignalFlag = sig_shutdown = true;
    138 }
    139 
    140