From 4204d68eedc03e8cdfc25df031f23d1880cb0a97 Mon Sep 17 00:00:00 2001 From: yukkop Date: Sun, 3 May 2026 03:14:00 +0000 Subject: [PATCH] fix(db-tool): prevent fd leak from logger to long-running daemons The hectic logger opens fd 3 as a dup of stderr. Child processes inherit this fd, and daemonized PostgreSQL/PostgREST keeping it open prevents the terminal from returning to the prompt after the spawning script exits. - Add with_closed_fds helper that runs commands in a subshell with fds 3-9 redirected to /dev/null - Inline the helper into both database and postgres-init builds - Wrap pg_ctl start and postgrest with the helper --- legacy/helper/posix-shell/default.nix | 3 +++ legacy/helper/posix-shell/log.sh | 2 +- legacy/helper/posix-shell/with_closed_fds.sh | 22 ++++++++++++++++++++ package/db-tool/default.nix | 7 ++++++- package/db-tool/postgres-init.sh | 2 +- 5 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 legacy/helper/posix-shell/with_closed_fds.sh diff --git a/legacy/helper/posix-shell/default.nix b/legacy/helper/posix-shell/default.nix index 5a7ed47..a12525c 100644 --- a/legacy/helper/posix-shell/default.nix +++ b/legacy/helper/posix-shell/default.nix @@ -21,4 +21,7 @@ in { pager_or_cat = hectic.writeDash "pager_or_cat.sh" '' ${builtins.readFile ./pager_or_cat.sh} ''; + with_closed_fds = hectic.writeDash "with_closed_fds.sh" '' + ${builtins.readFile ./with_closed_fds.sh} + ''; } diff --git a/legacy/helper/posix-shell/log.sh b/legacy/helper/posix-shell/log.sh index 5a46bff..581d419 100644 --- a/legacy/helper/posix-shell/log.sh +++ b/legacy/helper/posix-shell/log.sh @@ -148,7 +148,7 @@ log() { '' # shellcheck disable=SC1003 - fmt="$(printf "%s$delimetr" "$@" | sed 's/\\033\[0m/''\'"$color"'/g')" + fmt="$(printf "%s$delimetr" "$@" | sed 's/\\033\[0m/'\'"$color"'/g')" shift # shellcheck disable=SC1003 printf "${BBLACK}${HECTIC_NAMESPACE}> %b\n" "$color$fmt$NC" >&3 diff --git a/legacy/helper/posix-shell/with_closed_fds.sh b/legacy/helper/posix-shell/with_closed_fds.sh new file mode 100644 index 0000000..8867730 --- /dev/null +++ b/legacy/helper/posix-shell/with_closed_fds.sh @@ -0,0 +1,22 @@ +#!/bin/dash + +# with_closed_fds -- run command with leaked file descriptors closed +# +# Shell libraries (e.g. hectic logger) may open extra file descriptors +# (like fd 3 as a dup of stderr). Child processes inherit these fds. +# Long-running daemons (postgres, postgrest) that keep fd 3 open can +# prevent the terminal from returning to the prompt even after the +# spawning script exits. +# +# Usage: +# with_closed_fds pg_ctl -D "$data" -w start +# with_closed_fds postgrest "$config" > "$log" 2>&1 & +# +# Runs the command in a subshell where fds 3-9 are redirected to +# /dev/null. The parent shell's fd table is untouched. +with_closed_fds() { + ( + exec 3>/dev/null 4>/dev/null 5>/dev/null 6>/dev/null 7>/dev/null 8>/dev/null 9>/dev/null + "$@" + ) +} diff --git a/package/db-tool/default.nix b/package/db-tool/default.nix index 02b7adb..a0bdf27 100644 --- a/package/db-tool/default.nix +++ b/package/db-tool/default.nix @@ -43,6 +43,7 @@ let ${builtins.readFile hectic.helpers.posix-shell.change_namespace} ${builtins.readFile hectic.helpers.posix-shell.quote} ${builtins.readFile hectic.helpers.posix-shell.pager_or_cat} + ${builtins.readFile hectic.helpers.posix-shell.with_closed_fds} ${hecticEnv} ${applyBundle} ${builtins.readFile ./database.sh} @@ -62,7 +63,11 @@ let name = "postgres-init"; runtimeInputs = [ postgresql coreutils ]; - text = builtins.readFile ./postgres-init.sh; + text = '' + ${builtins.readFile hectic.helpers.posix-shell.with_closed_fds} + ${builtins.readFile ./postgres-init.sh} + ''; + meta = { description = "Initialize local PostgreSQL instance"; diff --git a/package/db-tool/postgres-init.sh b/package/db-tool/postgres-init.sh index d0074b9..6a197c7 100644 --- a/package/db-tool/postgres-init.sh +++ b/package/db-tool/postgres-init.sh @@ -36,7 +36,7 @@ postgres_init_main() { sed -i '/^[[:space:]]*port[[:space:]]*=/d' "$data/postgresql.conf" || return 1 sed -i '/^[[:space:]]*unix_socket_directories[[:space:]]*=/d' "$data/postgresql.conf" || return 1 { printf '%s\n' "port = $PG_PORT"; printf '%s\n' "unix_socket_directories = '$sockdir'"; } >> "$data/postgresql.conf" || return 1 - pg_ctl -D "$data" -o "-F" -w start || return 2 + with_closed_fds pg_ctl -D "$data" -o "-F" -w start || return 2 user="$(id -un)" || return 1 if [ "$PG_REUSE" -eq 0 ]; then