1 /* source: xiosigchld.c */
2 /* Copyright Gerhard Rieger */
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 */
17 /* register for a xio filedescriptor a callback (handler).
18 when a SIGCHLD occurs, the signal handler will ??? */
19 int xiosetsigchild(xiofile_t
*xfd
, int (*callback
)(struct single
*)) {
20 if (xfd
->tag
!= XIO_TAG_DUAL
) {
21 xfd
->stream
.sigchild
= callback
;
23 xfd
->dual
.stream
[0]->sigchild
= callback
;
24 xfd
->dual
.stream
[1]->sigchild
= callback
;
29 /* exec'd child has died, perform appropriate changes to descriptor */
30 /* is async-signal-safe */
31 static int sigchld_stream(struct single
*file
) {
32 /*!! call back to application */
33 file
->para
.exec
.pid
= 0;
35 return (*file
->sigchild
)(file
);
40 /* return 0 if socket is not responsible for deadchild */
41 static int xio_checkchild(xiofile_t
*socket
, int socknum
, pid_t deadchild
) {
44 if (socket
->tag
!= XIO_TAG_DUAL
) {
45 if ((socket
->stream
.howtoend
== END_KILL
||
46 socket
->stream
.howtoend
== END_CLOSE_KILL
||
47 socket
->stream
.howtoend
== END_SHUTDOWN_KILL
) &&
48 socket
->stream
.para
.exec
.pid
== deadchild
) {
49 Info2("exec'd process %d on socket %d terminated",
50 socket
->stream
.para
.exec
.pid
, socknum
);
51 sigchld_stream(&socket
->stream
); /* is async-signal-safe */
55 if (retval
= xio_checkchild((xiofile_t
*)socket
->dual
.stream
[0], socknum
, deadchild
))
58 return xio_checkchild((xiofile_t
*)socket
->dual
.stream
[1], socknum
, deadchild
);
64 /* this is the "physical" signal handler for SIGCHLD */
65 /* the current socat/xio implementation knows two kinds of children:
66 exec/system addresses perform a fork: these children are registered and
67 there death influences the parents flow;
68 listen-socket with fork children: these children are "anonymous" and their
69 death does not affect the parent process (now; maybe we have a child
70 process counter later) */
71 void childdied(int signum
) {
78 _errno
= errno
; /* save current value; e.g., select() on Cygwin seems
79 to set it to EINTR _before_ handling the signal, and
80 then passes the value left by the signal handler to
81 the caller of select(), accept() etc. */
83 Notice1("childdied(): handling signal %d", signum
);
84 Info1("childdied(signum=%d)", signum
);
86 pid
= Waitpid(-1, &status
, WNOHANG
);
88 Msg(wassig
?E_INFO
:E_WARN
,
89 "waitpid(-1, {}, WNOHANG): no child has exited");
90 Info("childdied() finished");
94 } else if (pid
< 0 && errno
== ECHILD
) {
95 Msg(wassig
?E_INFO
:E_WARN
,
96 "waitpid(-1, {}, WNOHANG): "F_strerror
);
97 Info("childdied() finished");
104 Warn1("waitpid(-1, {%d}, WNOHANG): "F_strerror
, status
);
105 Info("childdied() finished");
111 if (num_child
) num_child
--;
112 /* check if it was a registered child process */
114 while (i
< XIO_MAXSOCK
) {
115 if (xio_checkchild(sock
[i
], i
, pid
)) break;
118 if (i
== XIO_MAXSOCK
) {
119 Info2("childdied(%d): cannot identify child %d", signum
, pid
);
120 if (nextunknown
== NUMUNKNOWN
) {
123 diedunknown
[nextunknown
++] = pid
;
124 Debug1("saving pid in diedunknown"F_Zu
,
125 nextunknown
/*sic, for compatibility*/);
128 if (WIFEXITED(status
)) {
129 if (WEXITSTATUS(status
) == 0) {
130 Info2("waitpid(): child %d exited with status %d",
131 pid
, WEXITSTATUS(status
));
133 Warn2("waitpid(): child %d exited with status %d",
134 pid
, WEXITSTATUS(status
));
136 } else if (WIFSIGNALED(status
)) {
137 Info2("waitpid(): child %d exited on signal %d",
138 pid
, WTERMSIG(status
));
139 } else if (WIFSTOPPED(status
)) {
140 Info2("waitpid(): child %d stopped on signal %d",
141 pid
, WSTOPSIG(status
));
143 Warn1("waitpid(): cannot determine status of child %d", pid
);
147 /* we might need to re-register our handler */
148 if (Signal(SIGCHLD
, childdied
) == SIG_ERR
) {
149 Warn("signal(SIGCHLD, childdied): "F_strerror
);
151 #endif /* !HAVE_SIGACTION */
153 Info("childdied() finished");
159 int xiosetchilddied(void) {
161 struct sigaction act
;
162 memset(&act
, 0, sizeof(struct sigaction
));
163 act
.sa_flags
= SA_NOCLDSTOP
/*|SA_RESTART*/
168 act
.sa_handler
= childdied
;
169 sigfillset(&act
.sa_mask
);
170 if (Sigaction(SIGCHLD
, &act
, NULL
) < 0) {
171 /*! man does not say that errno is defined */
172 Warn2("sigaction(SIGCHLD, %p, NULL): %s", childdied
, strerror(errno
));
174 #else /* HAVE_SIGACTION */
175 if (Signal(SIGCHLD
, childdied
) == SIG_ERR
) {
176 Warn2("signal(SIGCHLD, %p): %s", childdied
, strerror(errno
));
178 #endif /* !HAVE_SIGACTION */