diff options
| author | Robin Haberkorn <rhaberkorn@fmsbw.de> | 2026-01-24 16:29:23 +0100 |
|---|---|---|
| committer | Robin Haberkorn <rhaberkorn@fmsbw.de> | 2026-01-24 16:37:27 +0100 |
| commit | 7ff541040edc3b3f8a25bb69e04ecb57cba12954 (patch) | |
| tree | 36e3e6fd6edca9f05f0e6afe193f0f241c305907 | |
| parent | 54858904a67e683483bdfb33c08fe9941ab16cf4 (diff) | |
GTK: fixed --detach and support stdout/stderr redirections
* We fork after command line arguments have been parsed, which
is after gtk_get_option_group() has been called.
This means that GTK was already initialized and it wasn't safe
to continue after forking.
* As a workaround, we now re-exec with the original argv array,
so GTK can be properly reinitialized.
Since we did not remove `--detach` from argv (and that would be
nontrivial), it would fork again endlessly,
so we use an environment variable
$__SCITECO_DETACHED to guard against recursive forks.
* Also, do not close stdin/stdout/stderr if has been redirected
to a file, so you can now e.g. call `gsciteco -d >some-file`.
* This was broken since v2.5.0.
| -rw-r--r-- | configure.ac | 2 | ||||
| -rw-r--r-- | src/interface-curses/interface.c | 2 | ||||
| -rw-r--r-- | src/interface-gtk/interface.c | 31 | ||||
| -rw-r--r-- | src/interface.h | 2 | ||||
| -rw-r--r-- | src/main.c | 2 |
5 files changed, 30 insertions, 9 deletions
diff --git a/configure.ac b/configure.ac index ed5e056..a469a98 100644 --- a/configure.ac +++ b/configure.ac @@ -215,7 +215,7 @@ case $host in *-*-linux* | *-*-*bsd* | *-*-darwin* | *-*-cygwin* | *-*-haiku*) # NOTE: Keep this on a single line for compatibility # with ancient versions of Autoconf. - AC_CHECK_FUNCS([realpath readlink pathconf fchown dup dup2 getpid open read kill mmap popen pclose isatty fork setsid], , [ + AC_CHECK_FUNCS([realpath readlink pathconf fchown dup dup2 getpid open read kill mmap popen pclose isatty fork execv setsid], , [ AC_MSG_ERROR([Missing libc function]) ]) AC_SEARCH_LIBS(dladdr, [dl], , [ diff --git a/src/interface-curses/interface.c b/src/interface-curses/interface.c index 6c8b231..365a096 100644 --- a/src/interface-curses/interface.c +++ b/src/interface-curses/interface.c @@ -443,7 +443,7 @@ static void teco_interface_set_window_title(const gchar *title); static void teco_interface_draw_info(void); void -teco_interface_init(void) +teco_interface_init(gint argc, gchar **argv) { for (guint i = 0; i < G_N_ELEMENTS(teco_interface.color_table); i++) teco_interface.color_table[i] = -1; diff --git a/src/interface-gtk/interface.c b/src/interface-gtk/interface.c index ace3a2f..08ccf5d 100644 --- a/src/interface-gtk/interface.c +++ b/src/interface-gtk/interface.c @@ -22,6 +22,7 @@ #include <stdlib.h> #include <string.h> #include <signal.h> +#include <unistd.h> #include <glib.h> #include <glib/gprintf.h> @@ -132,10 +133,10 @@ static struct { } teco_interface; void -teco_interface_init(void) +teco_interface_init(gint argc, gchar **argv) { #ifdef G_OS_UNIX - if (teco_interface.detach) { + if (teco_interface.detach && !g_getenv("__SCITECO_DETACHED")) { /* * NOTE: There is also daemon() on BSD/Linux, * but the following should be more portable. @@ -148,9 +149,29 @@ teco_interface_init(void) setsid(); - g_freopen("/dev/null", "r", stdin); - g_freopen("/dev/null", "a+", stdout); - g_freopen("/dev/null", "a+", stderr); + if (isatty(0)) { + G_GNUC_UNUSED FILE *stdin_new = g_freopen("/dev/null", "r", stdin); + g_assert(stdin_new != NULL); + } + if (isatty(1)) { + G_GNUC_UNUSED FILE *stdout_new = g_freopen("/dev/null", "a+", stdout); + g_assert(stdout_new != NULL); + } + if (isatty(2)) { + G_GNUC_UNUSED FILE *stderr_new = g_freopen("/dev/null", "a+", stderr); + g_assert(stderr_new != NULL); + } + + /* + * gtk_get_option_group() already initialized GTK and even though the + * display is not yet opened, it's unsafe to continue. + * Instead, we re-exec already in the child process. + * We cannot easily remove --detach from argv, but still guard against + * recursive forks by using an environment variable. + */ + g_setenv("__SCITECO_DETACHED", "1", TRUE); + execv(argv[0], argv); + g_assert_not_reached(); } #endif diff --git a/src/interface.h b/src/interface.h index f196a83..54f807b 100644 --- a/src/interface.h +++ b/src/interface.h @@ -51,7 +51,7 @@ extern teco_view_t *teco_interface_current_view; /** @pure */ -void teco_interface_init(void); +void teco_interface_init(gint argc, gchar **argv); /** @pure */ GOptionGroup *teco_interface_get_options(void); @@ -445,7 +445,7 @@ main(int argc, char **argv) */ teco_qreg_table_init(&teco_qreg_table_globals, TRUE); - teco_interface_init(); + teco_interface_init(argc, argv); /* * QRegister view must be initialized only now |
