]> git.ipfire.org Git - thirdparty/public-inbox.git/commitdiff
xap_helper.h: limit stderr assignment to glibc+FreeBSD
authorEric Wong <e@80x24.org>
Wed, 30 Aug 2023 05:10:44 +0000 (05:10 +0000)
committerEric Wong <e@80x24.org>
Wed, 30 Aug 2023 05:27:36 +0000 (05:27 +0000)
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.

lib/PublicInbox/xap_helper.h

index e10527d1d217af8f080d6f077055beca9316b9eb..922105110c8e0c166408f8363e55084d43c0fbb5 100644 (file)
 #      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);