]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
su: fix exit status if terminated by signal
authorOndrej Oprala <ooprala@redhat.com>
Fri, 17 May 2013 08:50:58 +0000 (10:50 +0200)
committerKarel Zak <kzak@redhat.com>
Fri, 7 Jun 2013 10:00:01 +0000 (12:00 +0200)
[kzak@redhat.com: - add comment]

Signed-off-by: Ondrej Oprala <ooprala@redhat.com>
Signed-off-by: Karel Zak <kzak@redhat.com>
login-utils/su-common.c
login-utils/su.1

index 8b08df16c0a4d632a6db3719157da98161a23ca3..6df176382a596edd00d34eb53591158c5cd5b888 100644 (file)
@@ -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);
 }
index eab1a6f7f3bd99ed663086d2adfe1c6f810cff32..e48a4f34cfb6f69cb80ecfeb57805ef13c698229 100644 (file)
@@ -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