sigevent.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  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. #include <memory.h>
  25. #ifdef SA_SIGINFO
  26. #ifdef HAVE_UCONTEXT_H
  27. #ifdef GNU_LINUX
  28. /* get REG_EIP from ucontext.h */
  29. #ifndef __USE_GNU
  30. #define __USE_GNU
  31. #endif /* __USE_GNU */
  32. #endif /* GNU_LINUX */
  33. #include <ucontext.h>
  34. #endif /* HAVE_UCONTEXT_H */
  35. #endif /* SA_SIGINFO */
  36. /* master signals descriptor struct */
  37. struct quagga_sigevent_master_t
  38. {
  39. struct thread *t;
  40. struct quagga_signal_t *signals;
  41. int sigc;
  42. volatile sig_atomic_t caught;
  43. } sigmaster;
  44. /* Generic signal handler
  45. * Schedules signal event thread
  46. */
  47. static void
  48. quagga_signal_handler (int signo)
  49. {
  50. int i;
  51. struct quagga_signal_t *sig;
  52. for (i = 0; i < sigmaster.sigc; i++)
  53. {
  54. sig = &(sigmaster.signals[i]);
  55. if (sig->signal == signo)
  56. sig->caught = 1;
  57. }
  58. sigmaster.caught = 1;
  59. }
  60. /* check if signals have been caught and run appropriate handlers */
  61. int
  62. quagga_sigevent_process (void)
  63. {
  64. struct quagga_signal_t *sig;
  65. int i;
  66. #ifdef SIGEVENT_BLOCK_SIGNALS
  67. /* shouldnt need to block signals, but potentially may be needed */
  68. sigset_t newmask, oldmask;
  69. /*
  70. * Block most signals, but be careful not to defer SIGTRAP because
  71. * doing so breaks gdb, at least on NetBSD 2.0. Avoid asking to
  72. * block SIGKILL, just because we shouldn't be able to do so.
  73. */
  74. sigfillset (&newmask);
  75. sigdelset (&newmask, SIGTRAP);
  76. sigdelset (&newmask, SIGKILL);
  77. if ( (sigprocmask (SIG_BLOCK, &newmask, &oldmask)) < 0)
  78. {
  79. zlog_err ("quagga_signal_timer: couldnt block signals!");
  80. return -1;
  81. }
  82. #endif /* SIGEVENT_BLOCK_SIGNALS */
  83. if (sigmaster.caught > 0)
  84. {
  85. sigmaster.caught = 0;
  86. /* must not read or set sigmaster.caught after here,
  87. * race condition with per-sig caught flags if one does
  88. */
  89. for (i = 0; i < sigmaster.sigc; i++)
  90. {
  91. sig = &(sigmaster.signals[i]);
  92. if (sig->caught > 0)
  93. {
  94. sig->caught = 0;
  95. sig->handler ();
  96. }
  97. }
  98. }
  99. #ifdef SIGEVENT_BLOCK_SIGNALS
  100. if ( sigprocmask (SIG_UNBLOCK, &oldmask, NULL) < 0 );
  101. return -1;
  102. #endif /* SIGEVENT_BLOCK_SIGNALS */
  103. return 0;
  104. }
  105. #ifdef SIGEVENT_SCHEDULE_THREAD
  106. /* timer thread to check signals. Shouldnt be needed */
  107. int
  108. quagga_signal_timer (struct thread *t)
  109. {
  110. struct quagga_sigevent_master_t *sigm;
  111. struct quagga_signal_t *sig;
  112. int i;
  113. sigm = THREAD_ARG (t);
  114. sigm->t = thread_add_timer (sigm->t->master, quagga_signal_timer, &sigmaster,
  115. QUAGGA_SIGNAL_TIMER_INTERVAL);
  116. return quagga_sigevent_process ();
  117. }
  118. #endif /* SIGEVENT_SCHEDULE_THREAD */
  119. /* Initialization of signal handles. */
  120. /* Signal wrapper. */
  121. static int
  122. signal_set (int signo)
  123. {
  124. int ret;
  125. struct sigaction sig;
  126. struct sigaction osig;
  127. sig.sa_handler = &quagga_signal_handler;
  128. sigfillset (&sig.sa_mask);
  129. sig.sa_flags = 0;
  130. if (signo == SIGALRM) {
  131. #ifdef SA_INTERRUPT
  132. sig.sa_flags |= SA_INTERRUPT; /* SunOS */
  133. #endif
  134. } else {
  135. #ifdef SA_RESTART
  136. sig.sa_flags |= SA_RESTART;
  137. #endif /* SA_RESTART */
  138. }
  139. ret = sigaction (signo, &sig, &osig);
  140. if (ret < 0)
  141. return ret;
  142. else
  143. return 0;
  144. }
  145. #ifdef SA_SIGINFO
  146. /* XXX This function should be enhanced to support more platforms
  147. (it currently works only on Linux/x86). */
  148. static void *
  149. program_counter(void *context)
  150. {
  151. #ifdef HAVE_UCONTEXT_H
  152. #ifdef GNU_LINUX
  153. /* these are from GNU libc, rather than Linux, strictly speaking */
  154. # if defined(REG_EIP)
  155. # define REG_INDEX REG_EIP
  156. # elif defined(REG_RIP)
  157. # define REG_INDEX REG_RIP
  158. # elif defined(__powerpc__)
  159. # define REG_INDEX 32
  160. # endif
  161. #elif defined(SUNOS_5) /* !GNU_LINUX */
  162. # define REG_INDEX REG_PC
  163. #endif /* GNU_LINUX */
  164. #ifdef REG_INDEX
  165. # ifdef HAVE_UCONTEXT_T_UC_MCONTEXT_GREGS
  166. # define REGS gregs[REG_INDEX]
  167. # elif defined(HAVE_UCONTEXT_T_UC_MCONTEXT_UC_REGS)
  168. # define REGS uc_regs->gregs[REG_INDEX]
  169. # endif /* HAVE_UCONTEXT_T_UC_MCONTEXT_GREGS */
  170. #endif /* REG_INDEX */
  171. #ifdef REGS
  172. if (context)
  173. return (void *)(((ucontext_t *)context)->uc_mcontext.REGS);
  174. #elif defined(HAVE_UCONTEXT_T_UC_MCONTEXT_REGS__NIP)
  175. /* older Linux / struct pt_regs ? */
  176. if (context)
  177. return (void *)(((ucontext_t *)context)->uc_mcontext.regs->nip);
  178. #endif /* REGS */
  179. #endif /* HAVE_UCONTEXT_H */
  180. return NULL;
  181. }
  182. #endif /* SA_SIGINFO */
  183. static void __attribute__ ((noreturn))
  184. exit_handler(int signo
  185. #ifdef SA_SIGINFO
  186. , siginfo_t *siginfo, void *context
  187. #endif
  188. )
  189. {
  190. zlog_signal(signo, "exiting..."
  191. #ifdef SA_SIGINFO
  192. , siginfo, program_counter(context)
  193. #endif
  194. );
  195. _exit(128+signo);
  196. }
  197. static void __attribute__ ((noreturn))
  198. core_handler(int signo
  199. #ifdef SA_SIGINFO
  200. , siginfo_t *siginfo, void *context
  201. #endif
  202. )
  203. {
  204. zlog_signal(signo, "aborting..."
  205. #ifdef SA_SIGINFO
  206. , siginfo, program_counter(context)
  207. #endif
  208. );
  209. /* dump memory stats on core */
  210. log_memstats_stderr ("core_handler");
  211. abort();
  212. }
  213. static void
  214. trap_default_signals(void)
  215. {
  216. static const int core_signals[] = {
  217. SIGQUIT,
  218. SIGILL,
  219. #ifdef SIGEMT
  220. SIGEMT,
  221. #endif
  222. SIGFPE,
  223. SIGBUS,
  224. SIGSEGV,
  225. #ifdef SIGSYS
  226. SIGSYS,
  227. #endif
  228. #ifdef SIGXCPU
  229. SIGXCPU,
  230. #endif
  231. #ifdef SIGXFSZ
  232. SIGXFSZ,
  233. #endif
  234. };
  235. static const int exit_signals[] = {
  236. SIGHUP,
  237. SIGINT,
  238. SIGALRM,
  239. SIGTERM,
  240. SIGUSR1,
  241. SIGUSR2,
  242. #ifdef SIGPOLL
  243. SIGPOLL,
  244. #endif
  245. #ifdef SIGVTALRM
  246. SIGVTALRM,
  247. #endif
  248. #ifdef SIGSTKFLT
  249. SIGSTKFLT,
  250. #endif
  251. };
  252. static const int ignore_signals[] = {
  253. SIGPIPE,
  254. };
  255. static const struct {
  256. const int *sigs;
  257. u_int nsigs;
  258. void (*handler)(int signo
  259. #ifdef SA_SIGINFO
  260. , siginfo_t *info, void *context
  261. #endif
  262. );
  263. } sigmap[] = {
  264. { core_signals, array_size(core_signals), core_handler},
  265. { exit_signals, array_size(exit_signals), exit_handler},
  266. { ignore_signals, array_size(ignore_signals), NULL},
  267. };
  268. u_int i;
  269. for (i = 0; i < array_size(sigmap); i++)
  270. {
  271. u_int j;
  272. for (j = 0; j < sigmap[i].nsigs; j++)
  273. {
  274. struct sigaction oact;
  275. if ((sigaction(sigmap[i].sigs[j],NULL,&oact) == 0) &&
  276. (oact.sa_handler == SIG_DFL))
  277. {
  278. struct sigaction act;
  279. sigfillset (&act.sa_mask);
  280. if (sigmap[i].handler == NULL)
  281. {
  282. act.sa_handler = SIG_IGN;
  283. act.sa_flags = 0;
  284. }
  285. else
  286. {
  287. #ifdef SA_SIGINFO
  288. /* Request extra arguments to signal handler. */
  289. act.sa_sigaction = sigmap[i].handler;
  290. act.sa_flags = SA_SIGINFO;
  291. #else
  292. act.sa_handler = sigmap[i].handler;
  293. act.sa_flags = 0;
  294. #endif
  295. }
  296. if (sigaction(sigmap[i].sigs[j],&act,NULL) < 0)
  297. zlog_warn("Unable to set signal handler for signal %d: %s",
  298. sigmap[i].sigs[j],safe_strerror(errno));
  299. }
  300. }
  301. }
  302. }
  303. void
  304. signal_init (struct thread_master *m, int sigc,
  305. struct quagga_signal_t signals[])
  306. {
  307. int i = 0;
  308. struct quagga_signal_t *sig;
  309. /* First establish some default handlers that can be overridden by
  310. the application. */
  311. trap_default_signals();
  312. while (i < sigc)
  313. {
  314. sig = &signals[i];
  315. if ( signal_set (sig->signal) < 0 )
  316. exit (-1);
  317. i++;
  318. }
  319. sigmaster.sigc = sigc;
  320. sigmaster.signals = signals;
  321. #ifdef SIGEVENT_SCHEDULE_THREAD
  322. sigmaster.t =
  323. thread_add_timer (m, quagga_signal_timer, &sigmaster,
  324. QUAGGA_SIGNAL_TIMER_INTERVAL);
  325. #endif /* SIGEVENT_SCHEDULE_THREAD */
  326. }