crash-handler.c 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. /* crash-handler.c -- PID 1 helper to dump core upon a crash on GNU/Linux.
  2. Copyright © 2019 Ludovic Courtès <ludo@gnu.org>
  3. This file is part of the GNU Shepherd.
  4. The GNU Shepherd is free software; you can redistribute it and/or modify it
  5. under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 3 of the License, or (at
  7. your option) any later version.
  8. The GNU Shepherd is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with the GNU Shepherd. If not, see <http://www.gnu.org/licenses/>. */
  14. #define _GNU_SOURCE
  15. #include <stdlib.h>
  16. #include <unistd.h>
  17. #include <sched.h>
  18. #include <sys/time.h>
  19. #include <sys/resource.h>
  20. #include <sys/types.h>
  21. #include <sys/wait.h>
  22. #include <sys/syscall.h> /* For SYS_xxx definitions */
  23. #include <signal.h>
  24. /* Arrange to dump core. */
  25. static void
  26. handle_crash (int sig)
  27. {
  28. static const char msg[] = "Shepherd crashed!\n";
  29. write (2, msg, sizeof msg);
  30. #ifdef __sparc__
  31. /* See 'raw_clone' in systemd. */
  32. # error "SPARC uses a different 'clone' syscall convention"
  33. #endif
  34. /* Start a child process that will be able to dump core. */
  35. pid_t pid = syscall (SYS_clone, SIGCHLD, NULL);
  36. if (pid < 0)
  37. abort ();
  38. if (pid == 0)
  39. {
  40. /* Restore the default signal handler to get a core dump. */
  41. signal (sig, SIG_DFL);
  42. const struct rlimit infinity = { RLIM_INFINITY, RLIM_INFINITY };
  43. setrlimit (RLIMIT_CORE, &infinity);
  44. chdir ("/");
  45. int pid = syscall (SYS_getpid);
  46. kill (pid, sig);
  47. /* As it turns out, 'kill' simply returns without doing anything, which
  48. is consistent with the "Notes" section of kill(2). Thus, force a
  49. crash. */
  50. * (int *) 0 = 42;
  51. _exit (254);
  52. }
  53. else
  54. {
  55. /* Wait for the child process and terminate. */
  56. signal (sig, SIG_IGN);
  57. int status;
  58. waitpid (pid, &status, 0);
  59. sync ();
  60. _exit (255);
  61. }
  62. _exit (253);
  63. }
  64. static void initialize_crash_handler (void)
  65. __attribute__ ((constructor));
  66. static void
  67. initialize_crash_handler (void)
  68. {
  69. /* Register raw signal handlers. This cannot be done in Scheme because the
  70. handler can only call async-signal-safe functions. */
  71. signal (SIGSEGV, handle_crash);
  72. signal (SIGABRT, handle_crash);
  73. }