+static struct chandler stdhandler = {
+ .handle = stdhandle,
+ .merge = stdmerge,
+ .destroy = stddestroy,
+};
+
+static int stdhandle(struct child *ch, struct hthead *req, int fd, void (*chinit)(void *), void *idata)
+{
+ struct stdchild *sd = ch->pdata;
+ int serr;
+
+ void stdinit(void *data)
+ {
+ int i;
+
+ for(i = 0; sd->envp[i]; i += 2)
+ putenv(sprintf2("%s=%s", sd->envp[i], sd->envp[i + 1]));
+ if(chinit != NULL)
+ chinit(data);
+ }
+
+ if(sd->type == CH_SOCKET) {
+ if(sd->fd < 0)
+ sd->fd = stdmkchild(sd->argv, stdinit, idata);
+ if(sendreq2(sd->fd, req, fd, MSG_NOSIGNAL | MSG_DONTWAIT)) {
+ serr = errno;
+ if((serr == EPIPE) || (serr == ECONNRESET)) {
+ /* Assume that the child has crashed and restart it. */
+ close(sd->fd);
+ sd->fd = stdmkchild(sd->argv, stdinit, idata);
+ if(!sendreq2(sd->fd, req, fd, MSG_NOSIGNAL | MSG_DONTWAIT))
+ return(0);
+ }
+ flog(LOG_ERR, "could not pass on request to child %s: %s", ch->name, strerror(serr));
+ if(serr != EAGAIN) {
+ close(sd->fd);
+ sd->fd = -1;
+ }
+ return(-1);
+ }
+ } else if(sd->type == CH_FORK) {
+ if(stdforkserve(sd->argv, req, fd, chinit, idata) < 0)
+ return(-1);
+ }
+ return(0);
+}
+
+static void stdmerge(struct child *dst, struct child *src)
+{
+ struct stdchild *od, *nd;
+
+ if(src->iface == &stdhandler) {
+ nd = dst->pdata;
+ od = src->pdata;
+ nd->fd = od->fd;
+ od->fd = -1;
+ }
+}
+
+static void stddestroy(struct child *ch)
+{
+ struct stdchild *d = ch->pdata;
+
+ if(d->fd >= 0)
+ close(d->fd);
+ if(d->argv)
+ freeca(d->argv);
+ if(d->envp)
+ freeca(d->envp);
+ free(d);
+}
+