From 8960f3ae5f4d72be88ee76e50417785e836b35e8 Mon Sep 17 00:00:00 2001 From: Ondrej Oprala Date: Fri, 17 May 2013 10:50:58 +0200 Subject: [PATCH] su: fix exit status if terminated by signal [kzak@redhat.com: - add comment] Signed-off-by: Ondrej Oprala Signed-off-by: Karel Zak --- login-utils/su-common.c | 56 ++++++++++++++++++++++++++++++----------- login-utils/su.1 | 9 +++++++ 2 files changed, 50 insertions(+), 15 deletions(-) diff --git a/login-utils/su-common.c b/login-utils/su-common.c index 8b08df16c0..6df176382a 100644 --- a/login-utils/su-common.c +++ b/login-utils/su-common.c @@ -232,9 +232,9 @@ cleanup_pam (int retcode) /* Signal handler for parent process. */ static void -su_catch_sig (int sig __attribute__((__unused__))) +su_catch_sig (int sig) { - caught_signal = true; + caught_signal = sig; } /* Export env variables declared by PAM modules. */ @@ -258,6 +258,7 @@ create_watching_parent (void) { pid_t child; sigset_t ourset; + struct sigaction oldact[3]; int status = 0; int retval; @@ -312,13 +313,13 @@ create_watching_parent (void) } if (!caught_signal && (sigaddset(&ourset, SIGTERM) || sigaddset(&ourset, SIGALRM) - || sigaction(SIGTERM, &action, NULL) + || sigaction(SIGTERM, &action, &oldact[0]) || sigprocmask(SIG_UNBLOCK, &ourset, NULL))) { warn (_("cannot set signal handler")); caught_signal = true; } - if (!caught_signal && !same_session && (sigaction(SIGINT, &action, NULL) - || sigaction(SIGQUIT, &action, NULL))) + if (!caught_signal && !same_session && (sigaction(SIGINT, &action, &oldact[1]) + || sigaction(SIGQUIT, &action, &oldact[2]))) { warn (_("cannot set signal handler")); caught_signal = true; @@ -341,17 +342,21 @@ create_watching_parent (void) break; } if (pid != (pid_t)-1) - if (WIFSIGNALED (status)) - { - status = WTERMSIG (status) + 128; - if (WCOREDUMP (status)) - fprintf (stderr, _("%s (core dumped)\n"), - strsignal (WTERMSIG (status))); - } - else - status = WEXITSTATUS (status); + { + if (WIFSIGNALED (status)) + { + status = WTERMSIG (status) + 128; + if (WCOREDUMP (status)) + fprintf (stderr, _("%s (core dumped)\n"), + strsignal (WTERMSIG (status))); + } + else + status = WEXITSTATUS (status); + } + else if (caught_signal) + status = caught_signal + 128; else - status = 1; + status = 1; } else status = 1; @@ -369,6 +374,27 @@ create_watching_parent (void) sleep (2); kill (child, SIGKILL); fprintf (stderr, _(" ...killed.\n")); + + /* Let's terminate itself with the received signal. + * + * It seems that shells use WIFSIGNALED() rather than our exit status + * value to detect situations when is necessary to cleanup (reset) + * terminal settings (kzak -- Jun 2013). + */ + switch (caught_signal) { + case SIGTERM: + sigaction(SIGTERM, &oldact[0], NULL); + break; + case SIGINT: + sigaction(SIGINT, &oldact[1], NULL); + break; + case SIGQUIT: + sigaction(SIGQUIT, &oldact[2], NULL); + break; + default: + break; + } + kill(0, caught_signal); } exit (status); } diff --git a/login-utils/su.1 b/login-utils/su.1 index eab1a6f7f3..e48a4f34cf 100644 --- a/login-utils/su.1 +++ b/login-utils/su.1 @@ -135,6 +135,15 @@ Display help text and exit. .TP \fB\-\-version\fR Display version information and exit. +.SH SIGNALS +Upon receiving either +.BR SIGINT , +.BR SIGQUIT +or +.BR SIGTERM , +.BR su +terminates it's child and afterwards terminates itself with +the received signal. .SH CONFIG FILES .B su reads the -- 2.47.3