proc.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. /*
  2. * ngIRCd -- The Next Generation IRC Daemon
  3. * Copyright (c)2001-2010 Alexander Barton (alex@barton.de)
  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. * Process management
  12. */
  13. #include "portab.h"
  14. #include "imp.h"
  15. #include <assert.h>
  16. #include <errno.h>
  17. #include <signal.h>
  18. #include <string.h>
  19. #include <stdlib.h>
  20. #include <unistd.h>
  21. #include "log.h"
  22. #include "io.h"
  23. #include "conn.h"
  24. #include "exp.h"
  25. #include "sighandlers.h"
  26. #include "proc.h"
  27. /**
  28. * Initialize process structure.
  29. */
  30. GLOBAL void
  31. Proc_InitStruct (PROC_STAT *proc)
  32. {
  33. assert(proc != NULL);
  34. proc->pid = 0;
  35. proc->pipe_fd = -1;
  36. }
  37. /**
  38. * Fork a child process.
  39. */
  40. GLOBAL pid_t
  41. Proc_Fork(PROC_STAT *proc, int *pipefds, void (*cbfunc)(int, short), int timeout)
  42. {
  43. pid_t pid;
  44. assert(proc != NULL);
  45. assert(pipefds != NULL);
  46. assert(cbfunc != NULL);
  47. if (pipe(pipefds) != 0) {
  48. Log(LOG_ALERT, "Can't create output pipe for child process: %s!",
  49. strerror(errno));
  50. return -1;
  51. }
  52. pid = fork();
  53. switch (pid) {
  54. case -1:
  55. /* Error on fork: */
  56. Log(LOG_CRIT, "Can't fork child process: %s!", strerror(errno));
  57. close(pipefds[0]);
  58. close(pipefds[1]);
  59. return -1;
  60. case 0:
  61. /* New child process: */
  62. Signals_Exit();
  63. signal(SIGTERM, Proc_GenericSignalHandler);
  64. signal(SIGALRM, Proc_GenericSignalHandler);
  65. close(pipefds[0]);
  66. alarm(timeout);
  67. Conn_CloseAllSockets();
  68. return 0;
  69. }
  70. /* Old parent process: */
  71. close(pipefds[1]);
  72. if (!io_setnonblock(pipefds[0])
  73. || !io_event_create(pipefds[0], IO_WANTREAD, cbfunc)) {
  74. Log(LOG_CRIT, "Can't register callback for child process: %s!",
  75. strerror(errno));
  76. close(pipefds[0]);
  77. return -1;
  78. }
  79. proc->pid = pid;
  80. proc->pipe_fd = pipefds[0];
  81. return pid;
  82. }
  83. /**
  84. * Generic signal handler for forked child processes.
  85. */
  86. GLOBAL void
  87. Proc_GenericSignalHandler(int Signal)
  88. {
  89. switch(Signal) {
  90. case SIGTERM:
  91. #ifdef DEBUG
  92. Log_Subprocess(LOG_DEBUG, "Child got TERM signal, exiting.");
  93. #endif
  94. exit(1);
  95. case SIGALRM:
  96. #ifdef DEBUG
  97. Log_Subprocess(LOG_DEBUG, "Child got ALARM signal, exiting.");
  98. #endif
  99. exit(1);
  100. }
  101. }
  102. /**
  103. * Read bytes from a pipe of a forked child process.
  104. * In addition, this function makes sure that the child process is ignored
  105. * after all data has been read or a fatal error occurred.
  106. */
  107. GLOBAL size_t
  108. Proc_Read(PROC_STAT *proc, void *buffer, size_t buflen)
  109. {
  110. ssize_t bytes_read = 0;
  111. assert(buffer != NULL);
  112. assert(buflen > 0);
  113. bytes_read = read(proc->pipe_fd, buffer, buflen);
  114. if (bytes_read < 0) {
  115. if (errno == EAGAIN)
  116. return 0;
  117. Log(LOG_CRIT, "Can't read from child process %ld: %s",
  118. proc->pid, strerror(errno));
  119. bytes_read = 0;
  120. }
  121. #if DEBUG
  122. else if (bytes_read == 0)
  123. LogDebug("Can't read from child process %ld: EOF", proc->pid);
  124. #endif
  125. Proc_InitStruct(proc);
  126. return (size_t)bytes_read;
  127. }
  128. /* -eof- */