From 4681d88ba1034d488814bbbb6e7d06d17e33322d Mon Sep 17 00:00:00 2001
From: Karel Zak <kzak@redhat.com>
Date: Wed, 16 Nov 2022 09:17:52 +0100
Subject: [PATCH] llib/pty-session: split PTY and signalfd setup

In some cases applications need to use PTY before signalfd is enabled.

Signed-off-by: Karel Zak <kzak@redhat.com>
---
 include/pty-session.h   |  1 +
 lib/pty-session.c       | 29 +++++++++++++++++++++++++----
 login-utils/su-common.c |  2 ++
 term-utils/scriptlive.c |  2 ++
 4 files changed, 30 insertions(+), 4 deletions(-)

diff --git a/include/pty-session.h b/include/pty-session.h
index 09eff43..3242992 100644
--- a/include/pty-session.h
+++ b/include/pty-session.h
@@ -98,6 +98,7 @@ void ul_pty_set_child(struct ul_pty *pty, pid_t child);
 struct ul_pty_callbacks *ul_pty_get_callbacks(struct ul_pty *pty);
 int ul_pty_is_running(struct ul_pty *pty);
 int ul_pty_setup(struct ul_pty *pty);
+int ul_pty_signals_setup(struct ul_pty *pty);
 void ul_pty_cleanup(struct ul_pty *pty);
 int ul_pty_chownmod_slave(struct ul_pty *pty, uid_t uid, gid_t gid, mode_t mode);
 void ul_pty_init_slave(struct ul_pty *pty);
diff --git a/lib/pty-session.c b/lib/pty-session.c
index 6f038e1..d89dfbb 100644
--- a/lib/pty-session.c
+++ b/lib/pty-session.c
@@ -149,12 +149,12 @@ static void pty_signals_cleanup(struct ul_pty *pty)
 int ul_pty_setup(struct ul_pty *pty)
 {
 	struct termios attrs;
-	sigset_t ourset;
 	int rc = 0;
 
 	assert(pty->sigfd == -1);
 
-	/* save the current signals setting */
+	/* save the current signals setting (to make ul_pty_cleanup() usable,
+	 * otherwise see ul_pty_signals_setup() */
 	sigprocmask(0, NULL, &pty->orgsig);
 
 	if (pty->isterm) {
@@ -198,6 +198,26 @@ int ul_pty_setup(struct ul_pty *pty)
 		tcsetattr(pty->slave, TCSANOW, &attrs);
 	}
 
+done:
+	if (rc)
+		ul_pty_cleanup(pty);
+
+	DBG(SETUP, ul_debugobj(pty, "pty setup done [master=%d, slave=%d, rc=%d]",
+				pty->master, pty->slave, rc));
+	return rc;
+}
+
+/* call me before fork() */
+int ul_pty_signals_setup(struct ul_pty *pty)
+{
+	sigset_t ourset;
+	int rc = 0;
+
+	assert(pty->sigfd == -1);
+
+	/* save the current signals setting */
+	sigprocmask(0, NULL, &pty->orgsig);
+
 	sigfillset(&ourset);
 	if (sigprocmask(SIG_BLOCK, &ourset, NULL)) {
 		rc = -errno;
@@ -221,8 +241,7 @@ done:
 	if (rc)
 		ul_pty_cleanup(pty);
 
-	DBG(SETUP, ul_debugobj(pty, "pty setup done [master=%d, slave=%d, rc=%d]",
-				pty->master, pty->slave, rc));
+	DBG(SETUP, ul_debugobj(pty, "pty signals setup done [rc=%d]", rc));
 	return rc;
 }
 
@@ -692,6 +711,8 @@ int main(int argc, char *argv[])
 
 	if (ul_pty_setup(pty))
 		err(EXIT_FAILURE, "failed to create pseudo-terminal");
+	if (ul_pty_signals_setup(pty))
+		err(EXIT_FAILURE, "failed to initialize signals handler");
 
 	fflush(stdout);			/* ??? */
 
diff --git a/login-utils/su-common.c b/login-utils/su-common.c
index afd0ea8..46dc116 100644
--- a/login-utils/su-common.c
+++ b/login-utils/su-common.c
@@ -536,6 +536,8 @@ static void create_watching_parent(struct su_context *su)
 		/* create pty */
 		if (ul_pty_setup(su->pty))
 			err(EXIT_FAILURE, _("failed to create pseudo-terminal"));
+		if (ul_pty_signals_setup(su->pty))
+			err(EXIT_FAILURE, _("failed to initialize signals handler"));
 	}
 #endif
 	fflush(stdout);			/* ??? */
diff --git a/term-utils/scriptlive.c b/term-utils/scriptlive.c
index d81712d..3e68f3c 100644
--- a/term-utils/scriptlive.c
+++ b/term-utils/scriptlive.c
@@ -294,6 +294,8 @@ main(int argc, char *argv[])
 
 	if (ul_pty_setup(ss.pty))
 		err(EXIT_FAILURE, _("failed to create pseudo-terminal"));
+	if (ul_pty_signals_setup(ss.pty))
+		err(EXIT_FAILURE, _("failed to initialize signals handler"));
 
 	fflush(stdout);			/* ??? */
 
-- 
2.27.0

