1 /* source: xiosigchld.c */
2 /* Copyright Gerhard Rieger and contributors (see file CHANGES) */
3 /* Published under the GNU General Public License V.2, see file COPYING */
5 /* this is the source of the extended child signal handler */
8 #include "xiosysincludes.h"
12 /*!! with socat, at most 4 exec children exist */
13 pid_t diedunknown
[NUMUNKNOWN
]; /* children that died before they were registered */
14 int statunknown
[NUMUNKNOWN
]; /* exit state of unknown dead child */
16 int engine_result
= EXIT_SUCCESS
;
19 /* register for a xio filedescriptor a callback (handler).
20 when a SIGCHLD occurs, the signal handler will ??? */
21 int xiosetsigchild(xiofile_t
*xfd
, int (*callback
)(struct single
*)) {
22 if (xfd
->tag
!= XIO_TAG_DUAL
) {
23 xfd
->stream
.sigchild
= callback
;
25 xfd
->dual
.stream
[0]->sigchild
= callback
;
26 xfd
->dual
.stream
[1]->sigchild
= callback
;
31 /* exec'd child has died, perform appropriate changes to descriptor */
32 /* is async-signal-safe */
33 static int sigchld_stream(struct single
*file
) {
34 /*!! call back to application */
35 file
->para
.exec
.pid
= 0;
37 return (*file
->sigchild
)(file
);
42 /* return 0 if socket is not responsible for deadchild */
43 static int xio_checkchild(xiofile_t
*socket
, int socknum
, pid_t deadchild
) {
46 if (socket
->tag
!= XIO_TAG_DUAL
) {
47 if ((socket
->stream
.howtoend
== END_KILL
||
48 socket
->stream
.howtoend
== END_CLOSE_KILL
||
49 socket
->stream
.howtoend
== END_SHUTDOWN_KILL
) &&
50 socket
->stream
.para
.exec
.pid
== deadchild
) {
51 Info2("exec'd process %d on socket %d terminated",
52 socket
->stream
.para
.exec
.pid
, socknum
);
53 sigchld_stream(&socket
->stream
); /* is async-signal-safe */
57 if (retval
= xio_checkchild((xiofile_t
*)socket
->dual
.stream
[0], socknum
, deadchild
))
60 return xio_checkchild((xiofile_t
*)socket
->dual
.stream
[1], socknum
, deadchild
);
66 /* this is the "physical" signal handler for SIGCHLD */
67 /* the current socat/xio implementation knows two kinds of children:
68 exec/system addresses perform a fork: these children are registered and
69 there death influences the parents flow;
70 listen-socket with fork children: these children are "anonymous" and their
71 death does not affect the parent process (now; maybe we have a child
72 process counter later) */
73 void childdied(int signum
) {
80 _errno
= errno
; /* save current value; e.g., select() on Cygwin seems
81 to set it to EINTR _before_ handling the signal, and
82 then passes the value left by the signal handler to
83 the caller of select(), accept() etc. */
85 Notice1("childdied(): handling signal %d", signum
);
86 Info1("childdied(signum=%d)", signum
);
88 pid
= Waitpid(-1, &status
, WNOHANG
);
90 Msg(wassig
?E_INFO
:E_WARN
,
91 "waitpid(-1, {}, WNOHANG): no child has exited");
92 Info("childdied() finished");
96 } else if (pid
< 0 && errno
== EINTR
) {
97 Info1("childdied(): %s", strerror(errno
));
98 } else if (pid
< 0 && errno
== ECHILD
) {
99 Msg(wassig
?E_INFO
:E_NOTICE
,
100 "waitpid(-1, {}, WNOHANG): "F_strerror
);
101 Info("childdied() finished");
108 Warn1("waitpid(-1, {%d}, WNOHANG): "F_strerror
, status
);
109 Info("childdied() finished");
117 Info1("number of children decreased to %d", num_child
);
119 /* check if it was a registered child process */
121 while (i
< XIO_MAXSOCK
) {
122 if (xio_checkchild(sock
[i
], i
, pid
)) break;
125 if (i
== XIO_MAXSOCK
) {
126 Info2("childdied(%d): cannot identify child %d", signum
, pid
);
127 if (num_child
) num_child
--;
128 if (nextunknown
== NUMUNKNOWN
) {
131 diedunknown
[nextunknown
] = pid
;
132 statunknown
[nextunknown
++] = WEXITSTATUS(status
);
133 Debug1("saving pid in diedunknown"F_Zu
,
134 nextunknown
/*sic, for compatibility*/);
137 if (WIFEXITED(status
)) {
138 if (WEXITSTATUS(status
) == 0) {
139 Info2("waitpid(): child %d exited with status %d",
140 pid
, WEXITSTATUS(status
));
142 if (i
== XIO_MAXSOCK
) {
143 Info2("waitpid(): child %d exited with status %d",
144 pid
, WEXITSTATUS(status
));
146 Warn2("waitpid(): child %d exited with status %d",
147 pid
, WEXITSTATUS(status
));
151 } else if (WIFSIGNALED(status
)) {
152 if (i
== XIO_MAXSOCK
) {
153 Info2("waitpid(): child %d exited on signal %d",
154 pid
, WTERMSIG(status
));
156 Warn2("waitpid(): child %d exited on signal %d",
157 pid
, WTERMSIG(status
));
160 } else if (WIFSTOPPED(status
)) {
161 Info2("waitpid(): child %d stopped on signal %d",
162 pid
, WSTOPSIG(status
));
164 Warn1("waitpid(): cannot determine status of child %d", pid
);
168 /* we might need to re-register our handler */
169 if (Signal(SIGCHLD
, childdied
) == SIG_ERR
) {
170 Warn("signal(SIGCHLD, childdied): "F_strerror
);
172 #endif /* !HAVE_SIGACTION */
174 Info("childdied() finished");
180 int xiosetchilddied(void) {
182 struct sigaction act
;
183 memset(&act
, 0, sizeof(struct sigaction
));
184 act
.sa_flags
= SA_NOCLDSTOP
/*|SA_RESTART*/
189 act
.sa_handler
= childdied
;
190 sigfillset(&act
.sa_mask
);
191 if (Sigaction(SIGCHLD
, &act
, NULL
) < 0) {
192 /*! man does not say that errno is defined */
193 Warn2("sigaction(SIGCHLD, %p, NULL): %s", childdied
, strerror(errno
));
195 #else /* HAVE_SIGACTION */
196 if (Signal(SIGCHLD
, childdied
) == SIG_ERR
) {
197 Warn2("signal(SIGCHLD, %p): %s", childdied
, strerror(errno
));
199 #endif /* !HAVE_SIGACTION */