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