proc.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. /*
  2. * ngIRCd -- The Next Generation IRC Daemon
  3. * Copyright (c)2001-2014 Alexander Barton (alex@barton.de) and Contributors.
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. * Please read the file COPYING, README and AUTHORS for more information.
  10. */
  11. #include "portab.h"
  12. /**
  13. * @file
  14. * Process management
  15. */
  16. #include <assert.h>
  17. #include <errno.h>
  18. #include <signal.h>
  19. #include <string.h>
  20. #include <stdlib.h>
  21. #include <sys/types.h>
  22. #include <unistd.h>
  23. #include <time.h>
  24. #include "log.h"
  25. #include "io.h"
  26. #include "sighandlers.h"
  27. #include "proc.h"
  28. /**
  29. * Initialize process structure.
  30. */
  31. GLOBAL void
  32. Proc_InitStruct (PROC_STAT *proc)
  33. {
  34. assert(proc != NULL);
  35. proc->pid = 0;
  36. proc->pipe_fd = -1;
  37. }
  38. /**
  39. * Fork a child process.
  40. */
  41. GLOBAL pid_t
  42. Proc_Fork(PROC_STAT *proc, int *pipefds, void (*cbfunc)(int, short), int timeout)
  43. {
  44. pid_t pid;
  45. #ifndef HAVE_ARC4RANDOM
  46. unsigned int seed;
  47. #endif
  48. assert(proc != NULL);
  49. assert(pipefds != NULL);
  50. assert(cbfunc != NULL);
  51. if (pipe(pipefds) != 0) {
  52. Log(LOG_ALERT, "Can't create output pipe for child process: %s!",
  53. strerror(errno));
  54. return -1;
  55. }
  56. #ifndef HAVE_ARC4RANDOM
  57. seed = (unsigned int)rand();
  58. #endif
  59. pid = fork();
  60. switch (pid) {
  61. case -1:
  62. /* Error on fork: */
  63. Log(LOG_CRIT, "Can't fork child process: %s!", strerror(errno));
  64. close(pipefds[0]);
  65. close(pipefds[1]);
  66. return -1;
  67. case 0:
  68. /* New child process: */
  69. #ifdef HAVE_ARC4RANDOM_STIR
  70. arc4random_stir();
  71. #endif
  72. #ifndef HAVE_ARC4RANDOM
  73. srand(seed ^ (unsigned int)time(NULL) ^ getpid());
  74. #endif
  75. Signals_Exit();
  76. signal(SIGTERM, Proc_GenericSignalHandler);
  77. signal(SIGALRM, Proc_GenericSignalHandler);
  78. close(pipefds[0]);
  79. alarm(timeout);
  80. return 0;
  81. }
  82. /* Old parent process: */
  83. close(pipefds[1]);
  84. if (!io_setnonblock(pipefds[0])
  85. || !io_event_create(pipefds[0], IO_WANTREAD, cbfunc)) {
  86. Log(LOG_CRIT, "Can't register callback for child process: %s!",
  87. strerror(errno));
  88. close(pipefds[0]);
  89. return -1;
  90. }
  91. proc->pid = pid;
  92. proc->pipe_fd = pipefds[0];
  93. return pid;
  94. }
  95. /**
  96. * Generic signal handler for forked child processes.
  97. */
  98. GLOBAL void
  99. Proc_GenericSignalHandler(int Signal)
  100. {
  101. switch(Signal) {
  102. case SIGTERM:
  103. #ifdef DEBUG
  104. Log_Subprocess(LOG_DEBUG, "Child got TERM signal, exiting.");
  105. #endif
  106. exit(1);
  107. case SIGALRM:
  108. #ifdef DEBUG
  109. Log_Subprocess(LOG_DEBUG, "Child got ALARM signal, exiting.");
  110. #endif
  111. exit(1);
  112. }
  113. }
  114. /**
  115. * Read bytes from a pipe of a forked child process.
  116. * In addition, this function makes sure that the child process is ignored
  117. * after all data has been read or a fatal error occurred.
  118. */
  119. GLOBAL size_t
  120. Proc_Read(PROC_STAT *proc, void *buffer, size_t buflen)
  121. {
  122. ssize_t bytes_read = 0;
  123. assert(buffer != NULL);
  124. assert(buflen > 0);
  125. bytes_read = read(proc->pipe_fd, buffer, buflen);
  126. if (bytes_read < 0) {
  127. if (errno == EAGAIN)
  128. return 0;
  129. Log(LOG_CRIT, "Can't read from child process %ld: %s",
  130. proc->pid, strerror(errno));
  131. Proc_Close(proc);
  132. bytes_read = 0;
  133. } else if (bytes_read == 0) {
  134. /* EOF: clean up */
  135. LogDebug("Child process %ld: EOF reached, closing pipe.",
  136. proc->pid);
  137. Proc_Close(proc);
  138. }
  139. return (size_t)bytes_read;
  140. }
  141. /**
  142. * Close pipe to a forked child process.
  143. */
  144. GLOBAL void
  145. Proc_Close(PROC_STAT *proc)
  146. {
  147. /* Close socket, if it exists */
  148. if (proc->pipe_fd >= 0)
  149. io_close(proc->pipe_fd);
  150. Proc_InitStruct(proc);
  151. }
  152. /* -eof- */