sigevent.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. /* Quagga signal handling functions.
  2. * Copyright (C) 2004 Paul Jakma,
  3. *
  4. * This file is part of Quagga.
  5. *
  6. * Quagga is free software; you can redistribute it and/or modify it
  7. * under the terms of the GNU General Public License as published by the
  8. * Free Software Foundation; either version 2, or (at your option) any
  9. * later version.
  10. *
  11. * Quagga is distributed in the hope that it will be useful, but
  12. * WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Quagga; see the file COPYING. If not, write to the Free
  18. * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  19. * 02111-1307, USA.
  20. */
  21. #include <zebra.h>
  22. #include <sigevent.h>
  23. #include <log.h>
  24. #ifdef SA_SIGINFO
  25. #ifdef HAVE_UCONTEXT_H
  26. #ifdef GNU_LINUX
  27. /* get REG_EIP from ucontext.h */
  28. #ifndef __USE_GNU
  29. #define __USE_GNU
  30. #endif /* __USE_GNU */
  31. #endif /* GNU_LINUX */
  32. #include <ucontext.h>
  33. #endif /* HAVE_UCONTEXT_H */
  34. #endif /* SA_SIGINFO */
  35. /* master signals descriptor struct */
  36. struct quagga_sigevent_master_t
  37. {
  38. struct thread *t;
  39. struct quagga_signal_t *signals;
  40. int sigc;
  41. volatile sig_atomic_t caught;
  42. } sigmaster;
  43. /* Generic signal handler
  44. * Schedules signal event thread
  45. */
  46. static void
  47. quagga_signal_handler (int signo)
  48. {
  49. int i;
  50. struct quagga_signal_t *sig;
  51. for (i = 0; i < sigmaster.sigc; i++)
  52. {
  53. sig = &(sigmaster.signals[i]);
  54. if (sig->signal == signo)
  55. sig->caught = 1;
  56. }
  57. sigmaster.caught = 1;
  58. }
  59. /* check if signals have been caught and run appropriate handlers */
  60. int
  61. quagga_sigevent_process (void)
  62. {
  63. struct quagga_signal_t *sig;
  64. int i;
  65. #ifdef SIGEVENT_BLOCK_SIGNALS
  66. /* shouldnt need to block signals, but potentially may be needed */
  67. sigset_t newmask, oldmask;
  68. /*
  69. * Block most signals, but be careful not to defer SIGTRAP because
  70. * doing so breaks gdb, at least on NetBSD 2.0. Avoid asking to
  71. * block SIGKILL, just because we shouldn't be able to do so.
  72. */
  73. sigfillset (&newmask);
  74. sigdelset (&newmask, SIGTRAP);
  75. sigdelset (&newmask, SIGKILL);
  76. if ( (sigprocmask (SIG_BLOCK, &newmask, &oldmask)) < 0)
  77. {
  78. zlog_err ("quagga_signal_timer: couldnt block signals!");
  79. return -1;
  80. }
  81. #endif /* SIGEVENT_BLOCK_SIGNALS */
  82. if (sigmaster.caught > 0)
  83. {
  84. sigmaster.caught = 0;
  85. /* must not read or set sigmaster.caught after here,
  86. * race condition with per-sig caught flags if one does
  87. */
  88. for (i = 0; i < sigmaster.sigc; i++)
  89. {
  90. sig = &(sigmaster.signals[i]);
  91. if (sig->caught > 0)
  92. {
  93. sig->caught = 0;
  94. sig->handler ();
  95. }
  96. }
  97. }
  98. #ifdef SIGEVENT_BLOCK_SIGNALS
  99. if ( sigprocmask (SIG_UNBLOCK, &oldmask, NULL) < 0 );
  100. return -1;
  101. #endif /* SIGEVENT_BLOCK_SIGNALS */
  102. return 0;
  103. }
  104. #ifdef SIGEVENT_SCHEDULE_THREAD
  105. /* timer thread to check signals. Shouldnt be needed */
  106. int
  107. quagga_signal_timer (struct thread *t)
  108. {
  109. struct quagga_sigevent_master_t *sigm;
  110. struct quagga_signal_t *sig;
  111. int i;
  112. sigm = THREAD_ARG (t);
  113. sigm->t = thread_add_timer (sigm->t->master, quagga_signal_timer, &sigmaster,
  114. QUAGGA_SIGNAL_TIMER_INTERVAL);
  115. return quagga_sigevent_process ();
  116. }
  117. #endif /* SIGEVENT_SCHEDULE_THREAD */
  118. /* Initialization of signal handles. */
  119. /* Signal wrapper. */
  120. static int
  121. signal_set (int signo)
  122. {
  123. int ret;
  124. struct sigaction sig;
  125. struct sigaction osig;
  126. sig.sa_handler = &quagga_signal_handler;
  127. sigfillset (&sig.sa_mask);
  128. sig.sa_flags = 0;
  129. if (signo == SIGALRM) {
  130. #ifdef SA_INTERRUPT
  131. sig.sa_flags |= SA_INTERRUPT; /* SunOS */
  132. #endif
  133. } else {
  134. #ifdef SA_RESTART
  135. sig.sa_flags |= SA_RESTART;
  136. #endif /* SA_RESTART */
  137. }
  138. ret = sigaction (signo, &sig, &osig);
  139. if (ret < 0)
  140. return ret;
  141. else
  142. return 0;
  143. }
  144. #ifdef SA_SIGINFO
  145. /* XXX This function should be enhanced to support more platforms
  146. (it currently works only on Linux/x86). */
  147. static void *
  148. program_counter(void *context)
  149. {
  150. #ifdef HAVE_UCONTEXT_H
  151. #ifdef GNU_LINUX
  152. #ifdef REG_EIP
  153. if (context)
  154. return (void *)(((ucontext_t *)context)->uc_mcontext.gregs[REG_EIP]);
  155. #endif /* REG_EIP */
  156. #endif /* GNU_LINUX */
  157. #endif /* HAVE_UCONTEXT_H */
  158. return NULL;
  159. }
  160. #endif /* SA_SIGINFO */
  161. static void __attribute__ ((noreturn))
  162. exit_handler(int signo
  163. #ifdef SA_SIGINFO
  164. , siginfo_t *siginfo, void *context
  165. #endif
  166. )
  167. {
  168. zlog_signal(signo, "exiting..."
  169. #ifdef SA_SIGINFO
  170. , siginfo, program_counter(context)
  171. #endif
  172. );
  173. _exit(128+signo);
  174. }
  175. static void __attribute__ ((noreturn))
  176. core_handler(int signo
  177. #ifdef SA_SIGINFO
  178. , siginfo_t *siginfo, void *context
  179. #endif
  180. )
  181. {
  182. zlog_signal(signo, "aborting..."
  183. #ifdef SA_SIGINFO
  184. , siginfo, program_counter(context)
  185. #endif
  186. );
  187. abort();
  188. }
  189. static void
  190. trap_default_signals(void)
  191. {
  192. static const int core_signals[] = {
  193. SIGQUIT,
  194. SIGILL,
  195. #ifdef SIGEMT
  196. SIGEMT,
  197. #endif
  198. SIGFPE,
  199. SIGBUS,
  200. SIGSEGV,
  201. #ifdef SIGSYS
  202. SIGSYS,
  203. #endif
  204. #ifdef SIGXCPU
  205. SIGXCPU,
  206. #endif
  207. #ifdef SIGXFSZ
  208. SIGXFSZ,
  209. #endif
  210. };
  211. static const int exit_signals[] = {
  212. SIGHUP,
  213. SIGINT,
  214. SIGALRM,
  215. SIGTERM,
  216. SIGUSR1,
  217. SIGUSR2,
  218. #ifdef SIGPOLL
  219. SIGPOLL,
  220. #endif
  221. #ifdef SIGVTALRM
  222. SIGVTALRM,
  223. #endif
  224. #ifdef SIGSTKFLT
  225. SIGSTKFLT,
  226. #endif
  227. };
  228. static const int ignore_signals[] = {
  229. SIGPIPE,
  230. };
  231. static const struct {
  232. const int *sigs;
  233. u_int nsigs;
  234. void (*handler)(int signo
  235. #ifdef SA_SIGINFO
  236. , siginfo_t *info, void *context
  237. #endif
  238. );
  239. } sigmap[] = {
  240. { core_signals, sizeof(core_signals)/sizeof(core_signals[0]), core_handler},
  241. { exit_signals, sizeof(exit_signals)/sizeof(exit_signals[0]), exit_handler},
  242. { ignore_signals, sizeof(ignore_signals)/sizeof(ignore_signals[0]), NULL},
  243. };
  244. u_int i;
  245. for (i = 0; i < sizeof(sigmap)/sizeof(sigmap[0]); i++)
  246. {
  247. u_int j;
  248. for (j = 0; j < sigmap[i].nsigs; j++)
  249. {
  250. struct sigaction oact;
  251. if ((sigaction(sigmap[i].sigs[j],NULL,&oact) == 0) &&
  252. (oact.sa_handler == SIG_DFL))
  253. {
  254. struct sigaction act;
  255. sigfillset (&act.sa_mask);
  256. if (sigmap[i].handler == NULL)
  257. {
  258. act.sa_handler = SIG_IGN;
  259. act.sa_flags = 0;
  260. }
  261. else
  262. {
  263. #ifdef SA_SIGINFO
  264. /* Request extra arguments to signal handler. */
  265. act.sa_sigaction = sigmap[i].handler;
  266. act.sa_flags = SA_SIGINFO;
  267. #else
  268. act.sa_handler = sigmap[i].handler;
  269. act.sa_flags = 0;
  270. #endif
  271. }
  272. if (sigaction(sigmap[i].sigs[j],&act,NULL) < 0)
  273. zlog_warn("Unable to set signal handler for signal %d: %s",
  274. sigmap[i].sigs[j],safe_strerror(errno));
  275. }
  276. }
  277. }
  278. }
  279. void
  280. signal_init (struct thread_master *m, int sigc,
  281. struct quagga_signal_t signals[])
  282. {
  283. int i = 0;
  284. struct quagga_signal_t *sig;
  285. /* First establish some default handlers that can be overridden by
  286. the application. */
  287. trap_default_signals();
  288. while (i < sigc)
  289. {
  290. sig = &signals[i];
  291. if ( signal_set (sig->signal) < 0 )
  292. exit (-1);
  293. i++;
  294. }
  295. sigmaster.sigc = sigc;
  296. sigmaster.signals = signals;
  297. #ifdef SIGEVENT_SCHEDULE_THREAD
  298. sigmaster.t =
  299. thread_add_timer (m, quagga_signal_timer, &sigmaster,
  300. QUAGGA_SIGNAL_TIMER_INTERVAL);
  301. #endif /* SIGEVENT_SCHEDULE_THREAD */
  302. }