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