]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/proc.c
11cb0396644548387926407913f09530e3373dcd
[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
27 #include "exp.h"
28 #include "proc.h"
29
30 /**
31  * Initialize process structure.
32  */
33 GLOBAL void
34 Proc_InitStruct (PROC_STAT *proc)
35 {
36         assert(proc != NULL);
37         proc->pid = 0;
38         proc->pipe_fd = -1;
39 }
40
41 /**
42  * Fork a child process.
43  */
44 GLOBAL pid_t
45 Proc_Fork(PROC_STAT *proc, int *pipefds, void (*cbfunc)(int, short))
46 {
47         pid_t pid;
48
49         assert(proc != NULL);
50         assert(pipefds != NULL);
51         assert(cbfunc != NULL);
52
53         if (pipe(pipefds) != 0) {
54                 Log(LOG_ALERT, "Can't create output pipe for child process: %s!",
55                     strerror(errno));
56                 return -1;
57         }
58
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                 signal(SIGTERM, Proc_GenericSignalHandler);
70                 close(pipefds[0]);
71                 return 0;
72         }
73
74         /* Old parent process: */
75         close(pipefds[1]);
76
77         if (!io_setnonblock(pipefds[0])
78          || !io_event_create(pipefds[0], IO_WANTREAD, cbfunc)) {
79                 Log(LOG_CRIT, "Can't register callback for child process: %s!",
80                     strerror(errno));
81                 close(pipefds[0]);
82                 return -1;
83         }
84
85         proc->pid = pid;
86         proc->pipe_fd = pipefds[0];
87         return pid;
88 }
89
90 /**
91  * Kill forked child process.
92  */
93 GLOBAL void
94 Proc_Kill(PROC_STAT *proc)
95 {
96         assert(proc != NULL);
97
98         if (proc->pipe_fd > 0)
99                 io_close(proc->pipe_fd);
100         if (proc->pid > 0)
101                 kill(proc->pid, SIGTERM);
102         Proc_InitStruct(proc);
103 }
104
105 /**
106  * Generic signal handler for forked child processes.
107  */
108 GLOBAL void
109 Proc_GenericSignalHandler(int Signal)
110 {
111         switch(Signal) {
112         case SIGTERM:
113 #ifdef DEBUG
114                 Log_Subprocess(LOG_DEBUG, "Child got TERM signal, exiting.");
115 #endif
116                 exit(1);
117         }
118 }
119
120 /**
121  * Read bytes from a pipe of a forked child process.
122  */
123 GLOBAL size_t
124 Proc_Read(PROC_STAT *proc, void *buffer, size_t buflen)
125 {
126         ssize_t bytes_read = 0;
127
128         assert(buffer != NULL);
129         assert(buflen > 0);
130
131         bytes_read = read(proc->pipe_fd, buffer, buflen);
132         if (bytes_read < 0) {
133                 if (errno == EAGAIN)
134                         return 0;
135                 Log(LOG_CRIT, "Can't read from child process %ld: %s",
136                     proc->pid, strerror(errno));
137                 bytes_read = 0;
138         }
139 #if DEBUG
140         else if (bytes_read == 0)
141                 LogDebug("Can't read from child process %ld: EOF", proc->pid);
142 #endif
143         Proc_Kill(proc);
144         return (size_t)bytes_read;
145 }
146
147 /* -eof- */