sighandlers.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. /*
  2. * ngIRCd -- The Next Generation IRC Daemon
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. * Please read the file COPYING, README and AUTHORS for more information.
  9. */
  10. #include "portab.h"
  11. /**
  12. * @file
  13. * Signal Handlers: Actions to be performed when the program
  14. * receives a signal.
  15. */
  16. #include <errno.h>
  17. #include <unistd.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <signal.h>
  21. #include <sys/types.h>
  22. #include <sys/wait.h>
  23. #include "imp.h"
  24. #include "conn.h"
  25. #include "conf-ssl.h"
  26. #include "channel.h"
  27. #include "conf.h"
  28. #include "io.h"
  29. #include "log.h"
  30. #include "ngircd.h"
  31. #include "sighandlers.h"
  32. static int signalpipe[2];
  33. static const int signals_catch[] = {
  34. SIGINT, SIGQUIT, SIGTERM, SIGHUP, SIGCHLD, SIGUSR1, SIGUSR2
  35. };
  36. #ifdef DEBUG
  37. static void
  38. Dump_State(void)
  39. {
  40. Log(LOG_DEBUG, "--- Internal server state: %s ---",
  41. Client_ID(Client_ThisServer()));
  42. Log(LOG_DEBUG, "time()=%ld", time(NULL));
  43. Conf_DebugDump();
  44. Conn_DebugDump();
  45. Client_DebugDump();
  46. Log(LOG_DEBUG, "--- End of state dump ---");
  47. } /* Dump_State */
  48. #endif
  49. static void
  50. Signal_Block(int sig)
  51. {
  52. #ifdef HAVE_SIGPROCMASK
  53. sigset_t set;
  54. sigemptyset(&set);
  55. sigaddset(&set, sig);
  56. sigprocmask(SIG_BLOCK, &set, NULL);
  57. #else
  58. sigblock(sig);
  59. #endif
  60. }
  61. static void
  62. Signal_Unblock(int sig)
  63. {
  64. #ifdef HAVE_SIGPROCMASK
  65. sigset_t set;
  66. sigemptyset(&set);
  67. sigaddset(&set, sig);
  68. sigprocmask(SIG_UNBLOCK, &set, NULL);
  69. #else
  70. int old = sigblock(0) & ~sig;
  71. sigsetmask(old);
  72. #endif
  73. }
  74. /**
  75. * Reload the server configuration file.
  76. */
  77. static void
  78. Rehash(void)
  79. {
  80. char old_name[CLIENT_ID_LEN];
  81. unsigned old_nicklen;
  82. Log( LOG_NOTICE|LOG_snotice, "Re-reading configuration NOW!" );
  83. /* Remember old server name and nickname length */
  84. strlcpy( old_name, Conf_ServerName, sizeof old_name );
  85. old_nicklen = Conf_MaxNickLength;
  86. /* Re-read configuration ... */
  87. if (!Conf_Rehash( ))
  88. return;
  89. /* Close down all listening sockets */
  90. Conn_ExitListeners( );
  91. /* Recover old server name and nickname length: these values can't
  92. * be changed during run-time */
  93. if (strcmp(old_name, Conf_ServerName) != 0 ) {
  94. strlcpy(Conf_ServerName, old_name, sizeof Conf_ServerName);
  95. Log(LOG_ERR, "Can't change \"ServerName\" on runtime! Ignored new name.");
  96. }
  97. if (old_nicklen != Conf_MaxNickLength) {
  98. Conf_MaxNickLength = old_nicklen;
  99. Log(LOG_ERR, "Can't change \"MaxNickLength\" on runtime! Ignored new value.");
  100. }
  101. /* Create new pre-defined channels */
  102. Channel_InitPredefined( );
  103. if (!ConnSSL_InitLibrary())
  104. Log(LOG_WARNING, "Re-Initializing SSL failed, using old keys");
  105. /* Start listening on sockets */
  106. Conn_InitListeners( );
  107. /* Sync configuration with established connections */
  108. Conn_SyncServerStruct( );
  109. Log( LOG_NOTICE|LOG_snotice, "Re-reading of configuration done." );
  110. } /* Rehash */
  111. /**
  112. * Signal handler of ngIRCd.
  113. * This function is called whenever ngIRCd catches a signal sent by the
  114. * user and/or the system to it. For example SIGTERM and SIGHUP.
  115. *
  116. * It blocks the signal and queues it for later execution by Signal_Handler_BH.
  117. * @param Signal Number of the signal to handle.
  118. */
  119. static void
  120. Signal_Handler(int Signal)
  121. {
  122. switch (Signal) {
  123. case SIGTERM:
  124. case SIGINT:
  125. case SIGQUIT:
  126. /* shut down sever */
  127. NGIRCd_SignalQuit = true;
  128. return;
  129. case SIGCHLD:
  130. /* child-process exited, avoid zombies */
  131. while (waitpid( -1, NULL, WNOHANG) > 0)
  132. ;
  133. return;
  134. #ifdef DEBUG
  135. case SIGUSR1:
  136. if (! NGIRCd_Debug) {
  137. Log(LOG_INFO|LOG_snotice,
  138. "Got SIGUSR1, debug mode activated.");
  139. #ifdef SNIFFER
  140. strcpy(NGIRCd_DebugLevel, "2");
  141. NGIRCd_Debug = true;
  142. NGIRCd_Sniffer = true;
  143. #else
  144. strcpy(NGIRCd_DebugLevel, "1");
  145. NGIRCd_Debug = true;
  146. #endif /* SNIFFER */
  147. } else {
  148. Log(LOG_INFO|LOG_snotice,
  149. "Got SIGUSR1, debug mode deactivated.");
  150. strcpy(NGIRCd_DebugLevel, "");
  151. NGIRCd_Debug = false;
  152. #ifdef SNIFFER
  153. NGIRCd_Sniffer = false;
  154. #endif /* SNIFFER */
  155. }
  156. return;
  157. #endif
  158. }
  159. /*
  160. * other signal: queue for later execution.
  161. * This has the advantage that we are not restricted
  162. * to functions that can be called safely from signal handlers.
  163. */
  164. if (write(signalpipe[1], &Signal, sizeof(Signal)) != -1)
  165. Signal_Block(Signal);
  166. } /* Signal_Handler */
  167. /**
  168. * Signal processing handler of ngIRCd.
  169. * This function is called from the main conn event loop in (io_dispatch)
  170. * whenever ngIRCd has queued a signal.
  171. *
  172. * This function runs in normal context, not from the real signal handler,
  173. * thus its not necessary to only use functions that are signal safe.
  174. * @param Signal Number of the signal that was queued.
  175. */
  176. static void
  177. Signal_Handler_BH(int Signal)
  178. {
  179. switch (Signal) {
  180. case SIGHUP:
  181. /* re-read configuration */
  182. Rehash();
  183. break;
  184. #ifdef DEBUG
  185. case SIGUSR2:
  186. if (NGIRCd_Debug) {
  187. Log(LOG_INFO|LOG_snotice,
  188. "Got SIGUSR2, dumping internal state ...");
  189. Dump_State();
  190. }
  191. break;
  192. default:
  193. Log(LOG_DEBUG, "Got signal %d! Ignored.", Signal);
  194. #endif
  195. }
  196. Signal_Unblock(Signal);
  197. }
  198. static void
  199. Signal_Callback(int fd, short UNUSED what)
  200. {
  201. int sig, ret;
  202. (void) what;
  203. do {
  204. ret = (int)read(fd, &sig, sizeof(sig));
  205. if (ret == sizeof(int))
  206. Signal_Handler_BH(sig);
  207. } while (ret == sizeof(int));
  208. if (ret == -1) {
  209. if (errno == EAGAIN || errno == EINTR)
  210. return;
  211. Log(LOG_EMERG, "read from signal pipe: %s", strerror(errno));
  212. exit(1);
  213. }
  214. Log(LOG_EMERG, "EOF on signal pipe");
  215. exit(1);
  216. }
  217. /**
  218. * Initialize the signal handlers, catch
  219. * those signals we are interested in and sets SIGPIPE to be ignored.
  220. * @return true if initialization was sucessful.
  221. */
  222. bool
  223. Signals_Init(void)
  224. {
  225. size_t i;
  226. #ifdef HAVE_SIGACTION
  227. struct sigaction saction;
  228. #endif
  229. if (signalpipe[0] > 0 || signalpipe[1] > 0)
  230. return true;
  231. if (pipe(signalpipe))
  232. return false;
  233. if (!io_setnonblock(signalpipe[0]) ||
  234. !io_setnonblock(signalpipe[1]))
  235. return false;
  236. if (!io_setcloexec(signalpipe[0]) ||
  237. !io_setcloexec(signalpipe[1]))
  238. return false;
  239. #ifdef HAVE_SIGACTION
  240. memset( &saction, 0, sizeof( saction ));
  241. saction.sa_handler = Signal_Handler;
  242. #ifdef SA_RESTART
  243. saction.sa_flags |= SA_RESTART;
  244. #endif
  245. #ifdef SA_NOCLDWAIT
  246. saction.sa_flags |= SA_NOCLDWAIT;
  247. #endif
  248. for (i=0; i < C_ARRAY_SIZE(signals_catch) ; i++)
  249. sigaction(signals_catch[i], &saction, NULL);
  250. /* we handle write errors properly; ignore SIGPIPE */
  251. saction.sa_handler = SIG_IGN;
  252. sigaction(SIGPIPE, &saction, NULL);
  253. #else
  254. for (i=0; i < C_ARRAY_SIZE(signals_catch) ; i++)
  255. signal(signals_catch[i], Signal_Handler);
  256. signal(SIGPIPE, SIG_IGN);
  257. #endif
  258. return io_event_create(signalpipe[0], IO_WANTREAD, Signal_Callback);
  259. } /* Signals_Init */
  260. /**
  261. * Restores signals to their default behaviour.
  262. *
  263. * This should be called after a fork() in the new
  264. * child prodcess, especially when we are about to call
  265. * 3rd party code (e.g. PAM).
  266. */
  267. void
  268. Signals_Exit(void)
  269. {
  270. size_t i;
  271. #ifdef HAVE_SIGACTION
  272. struct sigaction saction;
  273. memset(&saction, 0, sizeof(saction));
  274. saction.sa_handler = SIG_DFL;
  275. for (i=0; i < C_ARRAY_SIZE(signals_catch) ; i++)
  276. sigaction(signals_catch[i], &saction, NULL);
  277. sigaction(SIGPIPE, &saction, NULL);
  278. #else
  279. for (i=0; i < C_ARRAY_SIZE(signals_catch) ; i++)
  280. signal(signals_catch[i], SIG_DFL);
  281. signal(SIGPIPE, SIG_DFL);
  282. #endif
  283. close(signalpipe[1]);
  284. close(signalpipe[0]);
  285. signalpipe[0] = signalpipe[1] = 0;
  286. }
  287. /* -eof- */