+static void
+process_errfd(
+ void *cookie)
+{
+ struct active_service *as = cookie;
+
+ /* Process errfd before sending the REP packet */
+ if (as->ev_errfd) {
+ SELECT_ARG_TYPE readset;
+ struct timeval tv;
+ int nfound;
+
+ memset(&tv, 0, SIZEOF(tv));
+ FD_ZERO(&readset);
+ FD_SET(as->errfd, &readset);
+ nfound = select(as->errfd+1, &readset, NULL, NULL, &tv);
+ if (nfound && FD_ISSET(as->errfd, &readset)) {
+ errfd_recv(as);
+ }
+ }
+}
+
+/*
+ * Called when a errfd has received data
+ */
+static void
+errfd_recv(
+ void * cookie)
+{
+ struct active_service *as = cookie;
+ char buf[32769];
+ int n;
+ char *r;
+
+ assert(as != NULL);
+ assert(as->ev_errfd != NULL);
+
+ n = read(as->errfd, &buf, 32768);
+ /* merge buffer */
+ if (n > 0) {
+ /* Terminate it with '\0' */
+ buf[n+1] = '\0';
+
+ if (as->errbuf) {
+ as->errbuf = vstrextend(&as->errbuf, buf, NULL);
+ } else {
+ as->errbuf = stralloc(buf);
+ }
+ } else if (n == 0) {
+ event_release(as->ev_errfd);
+ as->ev_errfd = NULL;
+ } else { /* n < 0 */
+ event_release(as->ev_errfd);
+ as->ev_errfd = NULL;
+ g_snprintf(buf, 32768,
+ "error reading stderr or service: %s\n", strerror(errno));
+ }
+
+ /* for each line terminate by '\n' */
+ while (as->errbuf != NULL && (r = strchr(as->errbuf, '\n')) != NULL) {
+ char *s;
+
+ *r = '\0';
+ s = vstrallocf("ERROR service %s: %s\n",
+ services[as->service].name, as->errbuf);
+
+ /* Add to repbuf, error message will be in the REP packet if it
+ * is not already sent
+ */
+ n = strlen(s);
+ if (as->bufsize == 0) {
+ as->bufsize = NETWORK_BLOCK_BYTES;
+ as->repbuf = alloc(as->bufsize);
+ }
+ while (as->bufsize < as->repbufsize + n) {
+ char *repbuf_temp;
+ as->bufsize *= 2;
+ repbuf_temp = alloc(as->bufsize);
+ memcpy(repbuf_temp, as->repbuf, as->repbufsize + 1);
+ amfree(as->repbuf);
+ as->repbuf = repbuf_temp;
+ }
+ memcpy(as->repbuf + as->repbufsize, s, n);
+ as->repbufsize += n;
+
+ dbprintf("%s", s);
+
+ /* remove first line from buffer */
+ r++;
+ s = stralloc(r);
+ amfree(as->errbuf);
+ as->errbuf = s;
+ }
+}
+