Imported Upstream version 17.22.1
[platform/upstream/libzypp.git] / zypp / ExternalProgram.cc
index 54a5f2d..3a38f04 100644 (file)
@@ -18,6 +18,7 @@
 #include <fcntl.h>
 #include <pty.h> // openpty
 #include <stdlib.h> // setenv
+#include <sys/prctl.h> // prctl(), PR_SET_PDEATHSIG
 
 #include <cstring> // strsignal
 #include <iostream>
@@ -178,12 +179,12 @@ namespace zypp {
 
 
 
-    void ExternalProgram::start_program( const char *const *argv,
+    void ExternalProgram::start_program(const char *const *argv,
                                         const Environment & environment,
                                         Stderr_Disposition stderr_disp,
                                         int stderr_fd,
                                         bool default_locale,
-                                        const char * root )
+                                        const char * root , bool switch_pgid, bool die_with_parent )
     {
       pid = -1;
       _exitStatus = 0;
@@ -256,7 +257,7 @@ namespace zypp {
           cmdstr << " > '" << redirectStdout << "'";
         _command = cmdstr.str();
       }
-      DBG << "Executing " << _command << endl;
+      DBG << "Executing" << (default_locale?"[C] ":" ") << _command << endl;
 
 
       if (use_pty)
@@ -283,6 +284,8 @@ namespace zypp {
        }
       }
 
+      pid_t ppid_before_fork = ::getpid();
+
       // Create module process
       if ((pid = fork()) == 0)
       {
@@ -307,6 +310,8 @@ namespace zypp {
        }
        else
        {
+            if ( switch_pgid )
+              setpgid( 0, 0);
            renumber_fd (to_external[0], 0); // set new stdin
            ::close(from_external[0]);    // Belongs to father process
 
@@ -378,6 +383,23 @@ namespace zypp {
          ::close( i );
        }
 
+        if ( die_with_parent ) {
+          // process dies with us
+          int r = prctl(PR_SET_PDEATHSIG, SIGTERM);
+          if (r == -1) {
+            //ignore if it did not work, worst case the process lives on after the parent dies
+            std::cerr << "Failed to set PR_SET_PDEATHSIG" << endl;// After fork log on stderr too
+          }
+
+          // test in case the original parent exited just
+          // before the prctl() call
+          pid_t ppidNow = getppid();
+          if (ppidNow != ppid_before_fork) {
+            std::cerr << "PPID changed from "<<ppid_before_fork<<" to "<< ppidNow << endl;// After fork log on stderr too
+            _exit(128);
+          }
+        }
+
        execvp(argv[0], const_cast<char *const *>(argv));
         // don't want to get here
         _execError = str::form( _("Can't exec '%s' (%s)."), argv[0], strerror(errno) );
@@ -486,20 +508,23 @@ namespace zypp {
          } while ( true );
        }
 
-       // Wait for child to exit
-       int ret;
-       int status = 0;
-       do
+       if ( pid > 0 )  // bsc#1109877: must re-check! running() in the loop above may have already waited.
        {
-         ret = waitpid(pid, &status, 0);
-       }
-       while (ret == -1 && errno == EINTR);
+         // Wait for child to exit
+         int ret;
+         int status = 0;
+         do
+         {
+           ret = waitpid(pid, &status, 0);
+         }
+         while (ret == -1 && errno == EINTR);
 
-       if (ret != -1)
-       {
-        _exitStatus = checkStatus( status );
+         if (ret != -1)
+         {
+           _exitStatus = checkStatus( status );
+         }
+         pid = -1;
        }
-       pid = -1;
       }
 
       return _exitStatus;
@@ -556,6 +581,14 @@ namespace zypp {
       return true;
     }
 
+    bool ExternalProgram::kill(int sig)
+    {
+      if (pid > 0)
+      {
+        ::kill(pid, sig);
+      }
+      return true;
+    }
 
     bool
     ExternalProgram::running()