about summary refs log tree commit homepage
path: root/lib/PublicInbox/xap_helper.h
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2023-08-30 05:10:44 +0000
committerEric Wong <e@80x24.org>2023-08-30 05:27:36 +0000
commit1bc05a93b7a7259fece20655e65220cdc05cce5d (patch)
treef14c3fba8349e3228ee9c9a591768fb709c31074 /lib/PublicInbox/xap_helper.h
parentb78cd406ff28d8c25081dd81072c362c001bad5b (diff)
downloadpublic-inbox-1bc05a93b7a7259fece20655e65220cdc05cce5d.tar.gz
This fixes the C++ xap_helper compilation on OpenBSD.
Assignable `FILE *' pointers appear to only be supported on
FreeBSD and glibc.  Based on my reading of musl and NetBSD
source code, this should also fix builds on those platforms.
Diffstat (limited to 'lib/PublicInbox/xap_helper.h')
-rw-r--r--lib/PublicInbox/xap_helper.h55
1 files changed, 49 insertions, 6 deletions
diff --git a/lib/PublicInbox/xap_helper.h b/lib/PublicInbox/xap_helper.h
index e10527d1..92210511 100644
--- a/lib/PublicInbox/xap_helper.h
+++ b/lib/PublicInbox/xap_helper.h
@@ -50,9 +50,18 @@
 #        define SET_MAX_EXPANSION set_max_wildcard_expansion
 #endif
 
+#if defined(__FreeBSD__) || defined(__GLIBC__)
+#        define STDERR_ASSIGNABLE (1)
+#else
+#        define STDERR_ASSIGNABLE (0)
+#endif
+
 static const int sock_fd = 0; // SOCK_SEQPACKET as stdin :P
 static pid_t parent_pid;
+#if STDERR_ASSIGNABLE
 static FILE *orig_err = stderr;
+#endif
+static int orig_err_fd = -1;
 static void *srch_tree; // tsearch + tdelete + twalk
 static pid_t *worker_pids; // nr => pid
 static unsigned long nworker;
@@ -820,6 +829,37 @@ static void cleanup_pids(void)
         worker_pids = NULL;
 }
 
+static void stderr_set(FILE *tmp_err)
+{
+#if STDERR_ASSIGNABLE
+        if (my_setlinebuf(tmp_err))
+                perror("W: setlinebuf(tmp_err)");
+        stderr = tmp_err;
+        return;
+#endif
+        int fd = fileno(tmp_err);
+        if (fd < 0) err(EXIT_FAILURE, "BUG: fileno(tmp_err)");
+        while (dup2(fd, STDERR_FILENO) < 0) {
+                if (errno != EINTR)
+                        err(EXIT_FAILURE, "dup2(%d => 2)", fd);
+        }
+}
+
+static void stderr_restore(FILE *tmp_err)
+{
+#if STDERR_ASSIGNABLE
+        stderr = orig_err;
+        return;
+#endif
+        if (ferror(stderr) | fflush(stderr))
+                perror("ferror|fflush stderr");
+        while (dup2(orig_err_fd, STDERR_FILENO) < 0) {
+                if (errno != EINTR)
+                        err(EXIT_FAILURE, "dup2(%d => 2)", orig_err_fd);
+        }
+        clearerr(stderr);
+}
+
 static void recv_loop(void) // worker process loop
 {
         static char rbuf[4096 * 33]; // per-process
@@ -828,18 +868,15 @@ static void recv_loop(void) // worker process loop
                 struct req req = {};
                 if (!recv_req(&req, rbuf, &len))
                         continue;
-                if (req.fp[1]) {
-                        if (my_setlinebuf(req.fp[1]))
-                                perror("W: setlinebuf(req.fp[1])");
-                        stderr = req.fp[1];
-                }
+                if (req.fp[1])
+                        stderr_set(req.fp[1]);
                 req.argc = (int)SPLIT2ARGV(req.argv, rbuf, len);
                 if (req.argc > 0)
                         dispatch(&req);
                 if (ferror(req.fp[0]) | fclose(req.fp[0]))
                         perror("ferror|fclose fp[0]");
                 if (req.fp[1]) {
-                        stderr = orig_err;
+                        stderr_restore(req.fp[1]);
                         if (ferror(req.fp[1]) | fclose(req.fp[1]))
                                 perror("ferror|fclose fp[1]");
                 }
@@ -895,6 +932,12 @@ int main(int argc, char *argv[])
         code_nrp_init();
         atexit(cleanup_all);
 
+        if (!STDERR_ASSIGNABLE) {
+                orig_err_fd = dup(STDERR_FILENO);
+                if (orig_err_fd < 0)
+                        err(EXIT_FAILURE, "dup(2)");
+        }
+
         nworker = 0;
 #ifdef _SC_NPROCESSORS_ONLN
         long j = sysconf(_SC_NPROCESSORS_ONLN);