From: Eric Wong Date: Wed, 30 Aug 2023 05:10:44 +0000 (+0000) Subject: xap_helper.h: limit stderr assignment to glibc+FreeBSD X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1bc05a93b7a7259fece20655e65220cdc05cce5d;p=thirdparty%2Fpublic-inbox.git xap_helper.h: limit stderr assignment to glibc+FreeBSD 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. --- diff --git a/lib/PublicInbox/xap_helper.h b/lib/PublicInbox/xap_helper.h index e10527d1d..922105110 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);