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 */
18 /* register for a xio filedescriptor a callback (handler).
19 when a SIGCHLD occurs, the signal handler will ??? */
20 int xiosetsigchild(xiofile_t
*xfd
, int (*callback
)(struct single
*)) {
21 if (xfd
->tag
!= XIO_TAG_DUAL
) {
22 xfd
->stream
.sigchild
= callback
;
24 xfd
->dual
.stream
[0]->sigchild
= callback
;
25 xfd
->dual
.stream
[1]->sigchild
= callback
;
30 /* exec'd child has died, perform appropriate changes to descriptor */
31 /* is async-signal-safe */
32 static int sigchld_stream(struct single
*file
) {
33 /*!! call back to application */
34 file
->para
.exec
.pid
= 0;
36 return (*file
->sigchild
)(file
);
41 /* return 0 if socket is not responsible for deadchild */
42 static int xio_checkchild(xiofile_t
*socket
, int socknum
, pid_t deadchild
) {
45 if (socket
->tag
!= XIO_TAG_DUAL
) {
46 if ((socket
->stream
.howtoend
== END_KILL
||
47 socket
->stream
.howtoend
== END_CLOSE_KILL
||
48 socket
->stream
.howtoend
== END_SHUTDOWN_KILL
) &&
49 socket
->stream
.para
.exec
.pid
== deadchild
) {
50 Info2("exec'd process %d on socket %d terminated",
51 socket
->stream
.para
.exec
.pid
, socknum
);
52 sigchld_stream(&socket
->stream
); /* is async-signal-safe */
56 if (retval
= xio_checkchild((xiofile_t
*)socket
->dual
.stream
[0], socknum
, deadchild
))
59 return xio_checkchild((xiofile_t
*)socket
->dual
.stream
[1], socknum
, deadchild
);
65 /* this is the "physical" signal handler for SIGCHLD */
66 /* the current socat/xio implementation knows two kinds of children:
67 exec/system addresses perform a fork: these children are registered and
68 there death influences the parents flow;
69 listen-socket with fork children: these children are "anonymous" and their
70 death does not affect the parent process (now; maybe we have a child
71 process counter later) */
72 void childdied(int signum
) {
79 _errno
= errno
; /* save current value; e.g., select() on Cygwin seems
80 to set it to EINTR _before_ handling the signal, and
81 then passes the value left by the signal handler to
82 the caller of select(), accept() etc. */
84 Notice1("childdied(): handling signal %d", signum
);
85 Info1("childdied(signum=%d)", signum
);
87 pid
= Waitpid(-1, &status
, WNOHANG
);
89 Msg(wassig
?E_INFO
:E_WARN
,
90 "waitpid(-1, {}, WNOHANG): no child has exited");
91 Info("childdied() finished");
95 } else if (pid
< 0 && errno
== ECHILD
) {
96 Msg(wassig
?E_INFO
:E_WARN
,
97 "waitpid(-1, {}, WNOHANG): "F_strerror
);
98 Info("childdied() finished");
105 Warn1("waitpid(-1, {%d}, WNOHANG): "F_strerror
, status
);
106 Info("childdied() finished");
112 if (num_child
) num_child
--;
113 /* check if it was a registered child process */
115 while (i
< XIO_MAXSOCK
) {
116 if (xio_checkchild(sock
[i
], i
, pid
)) break;
119 if (i
== XIO_MAXSOCK
) {
120 Info2("childdied(%d): cannot identify child %d", signum
, pid
);
121 if (nextunknown
== NUMUNKNOWN
) {
124 diedunknown
[nextunknown
] = pid
;
125 statunknown
[nextunknown
++] = WEXITSTATUS(status
);
126 Debug1("saving pid in diedunknown"F_Zu
,
127 nextunknown
/*sic, for compatibility*/);
130 if (WIFEXITED(status
)) {
131 if (WEXITSTATUS(status
) == 0) {
132 Info2("waitpid(): child %d exited with status %d",
133 pid
, WEXITSTATUS(status
));
135 if (i
== XIO_MAXSOCK
) {
136 Info2("waitpid(): child %d exited with status %d",
137 pid
, WEXITSTATUS(status
));
139 Error2("waitpid(): child %d exited with status %d",
140 pid
, WEXITSTATUS(status
));
143 } else if (WIFSIGNALED(status
)) {
144 if (i
== XIO_MAXSOCK
) {
145 Info2("waitpid(): child %d exited on signal %d",
146 pid
, WTERMSIG(status
));
148 Error2("waitpid(): child %d exited on signal %d",
149 pid
, WTERMSIG(status
));
151 } else if (WIFSTOPPED(status
)) {
152 Info2("waitpid(): child %d stopped on signal %d",
153 pid
, WSTOPSIG(status
));
155 Warn1("waitpid(): cannot determine status of child %d", pid
);
159 /* we might need to re-register our handler */
160 if (Signal(SIGCHLD
, childdied
) == SIG_ERR
) {
161 Warn("signal(SIGCHLD, childdied): "F_strerror
);
163 #endif /* !HAVE_SIGACTION */
165 Info("childdied() finished");
171 int xiosetchilddied(void) {
173 struct sigaction act
;
174 memset(&act
, 0, sizeof(struct sigaction
));
175 act
.sa_flags
= SA_NOCLDSTOP
/*|SA_RESTART*/
180 act
.sa_handler
= childdied
;
181 sigfillset(&act
.sa_mask
);
182 if (Sigaction(SIGCHLD
, &act
, NULL
) < 0) {
183 /*! man does not say that errno is defined */
184 Warn2("sigaction(SIGCHLD, %p, NULL): %s", childdied
, strerror(errno
));
186 #else /* HAVE_SIGACTION */
187 if (Signal(SIGCHLD
, childdied
) == SIG_ERR
) {
188 Warn2("signal(SIGCHLD, %p): %s", childdied
, strerror(errno
));
190 #endif /* !HAVE_SIGACTION */