Imported Upstream version 14.45.0
[platform/upstream/libzypp.git] / zypp / ExternalProgram.cc
index b166ca5..d415298 100644 (file)
@@ -35,8 +35,7 @@ namespace zypp {
     ExternalProgram::ExternalProgram()
       : use_pty (false)
       , pid( -1 )
-    {
-    }
+    {}
 
 
     ExternalProgram::ExternalProgram( std::string commandline,
@@ -54,73 +53,56 @@ namespace zypp {
       argv[2] = commandline.c_str();
       argv[3] = 0;
 
-      const char* rootdir = NULL;
-      if(!root.empty() && root != "/")
-      {
-       rootdir = root.asString().c_str();
-      }
-      Environment environment;
-      start_program (argv, environment, stderr_disp, stderr_fd, default_locale, rootdir);
+      start_program( argv, Environment(), stderr_disp, stderr_fd, default_locale, root.c_str() );
     }
 
 
-    ExternalProgram::ExternalProgram (const Arguments &argv,
+    ExternalProgram::ExternalProgram( const Arguments & argv,
                                       Stderr_Disposition stderr_disp,
-                                      bool use_pty, int stderr_fd,
+                                      bool use_pty,
+                                     int stderr_fd,
                                       bool default_locale,
-                                      const Pathname& root)
+                                      const Pathname & root )
       : use_pty (use_pty)
       , pid( -1 )
     {
-        const char * argvp[argv.size() + 1];
-        unsigned c = 0;
-        for_( i, argv.begin(), argv.end() )
-        {
-            argvp[c] = i->c_str();
-            ++c;
-        }
-        argvp[c] = 0;
+      const char * argvp[argv.size() + 1];
+      unsigned c = 0;
+      for_( i, argv.begin(), argv.end() )
+      {
+       argvp[c] = i->c_str();
+       ++c;
+      }
+      argvp[c] = 0;
 
-        Environment environment;
-        const char* rootdir = NULL;
-        if(!root.empty() && root != "/")
-        {
-            rootdir = root.asString().c_str();
-        }
-        start_program (argvp, environment, stderr_disp, stderr_fd, default_locale, rootdir);
+      start_program( argvp, Environment(), stderr_disp, stderr_fd, default_locale, root.c_str() );
     }
 
 
-    ExternalProgram::ExternalProgram (const Arguments &argv,
+    ExternalProgram::ExternalProgram( const Arguments & argv,
                                       const Environment & environment,
                                       Stderr_Disposition stderr_disp,
-                                      bool use_pty, int stderr_fd,
+                                      bool use_pty,
+                                     int stderr_fd,
                                       bool default_locale,
-                                      const Pathname& root)
+                                     const Pathname & root )
       : use_pty (use_pty)
       , pid( -1 )
     {
-        const char * argvp[argv.size() + 1];
-        unsigned c = 0;
-        for_( i, argv.begin(), argv.end() )
-        {
-            argvp[c] = i->c_str();
-            ++c;
-        }
-        argvp[c] = 0;
-
-        const char* rootdir = NULL;
-        if(!root.empty() && root != "/")
-        {
-            rootdir = root.asString().c_str();
-        }
-        start_program (argvp, environment, stderr_disp, stderr_fd, default_locale, rootdir);
+      const char * argvp[argv.size() + 1];
+      unsigned c = 0;
+      for_( i, argv.begin(), argv.end() )
+      {
+       argvp[c] = i->c_str();
+       ++c;
+      }
+      argvp[c] = 0;
 
+      start_program( argvp, environment, stderr_disp, stderr_fd, default_locale, root.c_str() );
     }
 
 
 
-
     ExternalProgram::ExternalProgram( const char *const *argv,
                                       Stderr_Disposition stderr_disp,
                                       bool use_pty,
@@ -130,34 +112,27 @@ namespace zypp {
       : use_pty (use_pty)
       , pid( -1 )
     {
-      const char* rootdir = NULL;
-      if(!root.empty() && root != "/")
-      {
-       rootdir = root.asString().c_str();
-      }
-      Environment environment;
-      start_program (argv, environment, stderr_disp, stderr_fd, default_locale, rootdir);
+      start_program( argv, Environment(), stderr_disp, stderr_fd, default_locale, root.c_str() );
     }
 
 
-    ExternalProgram::ExternalProgram (const char *const *argv, const Environment & environment,
-                                 Stderr_Disposition stderr_disp, bool use_pty,
-                                 int stderr_fd, bool default_locale,
-                                 const Pathname& root)
+    ExternalProgram::ExternalProgram( const char *const * argv,
+                                     const Environment & environment,
+                                     Stderr_Disposition stderr_disp,
+                                     bool use_pty,
+                                     int stderr_fd,
+                                     bool default_locale,
+                                     const Pathname & root )
       : use_pty (use_pty)
       , pid( -1 )
     {
-      const char* rootdir = NULL;
-      if(!root.empty() && root != "/")
-      {
-       rootdir = root.asString().c_str();
-      }
-      start_program (argv, environment, stderr_disp, stderr_fd, default_locale, rootdir);
+      start_program( argv, environment, stderr_disp, stderr_fd, default_locale, root.c_str() );
     }
 
 
-    ExternalProgram::ExternalProgram (const char *binpath, const char *const *argv_1,
-                                 bool use_pty)
+    ExternalProgram::ExternalProgram( const char *binpath,
+                                     const char *const *argv_1,
+                                     bool use_pty )
       : use_pty (use_pty)
       , pid( -1 )
     {
@@ -166,14 +141,15 @@ namespace zypp {
        ;
       const char *argv[i + 1];
       argv[0] = binpath;
-      memcpy (&argv[1], argv_1, (i - 1) * sizeof (char *));
-      Environment environment;
-      start_program (argv, environment);
+      memcpy( &argv[1], argv_1, (i - 1) * sizeof (char *) );
+      start_program( argv, Environment() );
     }
 
 
-    ExternalProgram::ExternalProgram (const char *binpath, const char *const *argv_1, const Environment & environment,
-                                 bool use_pty)
+    ExternalProgram::ExternalProgram( const char *binpath,
+                                     const char *const *argv_1,
+                                     const Environment & environment,
+                                     bool use_pty )
       : use_pty (use_pty)
       , pid( -1 )
     {
@@ -182,33 +158,75 @@ namespace zypp {
        ;
       const char *argv[i + 1];
       argv[0] = binpath;
-      memcpy (&argv[1], argv_1, (i - 1) * sizeof (char *));
-      start_program (argv, environment);
+      memcpy( &argv[1], argv_1, (i - 1) * sizeof (char *) );
+      start_program( argv, environment );
     }
 
 
     ExternalProgram::~ExternalProgram()
-    {
-    }
+    {}
 
 
-    void
-    ExternalProgram::start_program (const char *const *argv, const Environment & environment,
-                               Stderr_Disposition stderr_disp,
-                               int stderr_fd, bool default_locale, const char* root)
+
+    void ExternalProgram::start_program( const char *const *argv,
+                                        const Environment & environment,
+                                        Stderr_Disposition stderr_disp,
+                                        int stderr_fd,
+                                        bool default_locale,
+                                        const char * root )
     {
       pid = -1;
       _exitStatus = 0;
-      int to_external[2], from_external[2];  // fds for pair of pipes
-      int master_tty,  slave_tty;         // fds for pair of ttys
+      int to_external[2], from_external[2];    // fds for pair of pipes
+      int master_tty,  slave_tty;              // fds for pair of ttys
+
+      // retrieve options at beginning of arglist
+      const char * redirectStdin = nullptr;    // <[file]
+      const char * redirectStdout = nullptr;   // >[file]
+      const char * chdirTo = nullptr;          // #/[path]
 
-      const char * redirectStdin = 0;
-      if ( argv[0] && *argv[0] == '<' )
+      if ( root )
       {
-        redirectStdin = argv[0]+1;
-        if ( *redirectStdin == '\0' )
-          redirectStdin = "/dev/null";
-        ++argv;
+       if ( root[0] == '\0' )
+       {
+         root = nullptr;       // ignore empty root
+       }
+       else if ( root[0] == '/' && root[1] == '\0' )
+       {
+         // If root is '/' do not chroot, but chdir to '/'
+         // unless arglist defines another dir.
+         chdirTo = "/";
+         root = nullptr;
+       }
+      }
+
+      for ( bool strip = false; argv[0]; ++argv )
+      {
+       strip = false;
+       switch ( argv[0][0] )
+       {
+         case '<':
+           strip = true;
+           redirectStdin = argv[0]+1;
+           if ( *redirectStdin == '\0' )
+             redirectStdin = "/dev/null";
+           break;
+
+         case '>':
+           strip = true;
+           redirectStdout = argv[0]+1;
+           if ( *redirectStdout == '\0' )
+             redirectStdout = "/dev/null";
+           break;
+
+         case '#':
+           strip = true;
+           if ( argv[0][1] == '/' )    // #/[path]
+             chdirTo = argv[0]+1;
+           break;
+       }
+       if ( ! strip )
+         break;
       }
 
       // do not remove the single quotes around every argument, copy&paste of
@@ -224,6 +242,8 @@ namespace zypp {
         }
         if ( redirectStdin )
           cmdstr << " < '" << redirectStdin << "'";
+        if ( redirectStdout )
+          cmdstr << " > '" << redirectStdout << "'";
         _command = cmdstr.str();
       }
       DBG << "Executing " << _command << endl;
@@ -291,6 +311,13 @@ namespace zypp {
           dup2( inp_fd, 0 );
         }
 
+        if ( redirectStdout )
+        {
+          ::close( 1 );
+          int inp_fd = open( redirectStdout, O_WRONLY|O_CREAT|O_APPEND, 0600 );
+          dup2( inp_fd, 1 );
+        }
+
        // Handle stderr
        if (stderr_disp == Discard_Stderr)
        {
@@ -324,14 +351,18 @@ namespace zypp {
                 std::cerr << _execError << endl;// After fork log on stderr too
                _exit (128);                    // No sense in returning! I am forked away!!
            }
-           if(chdir("/") == -1)
-           {
-                _execError = str::form( _("Can't chdir to '/' inside chroot (%s)."), strerror(errno) );
-                std::cerr << _execError << endl;// After fork log on stderr too
-               _exit (128);                    // No sense in returning! I am forked away!!
-           }
+           if ( ! chdirTo )
+             chdirTo = "/";
        }
 
+       if ( chdirTo && chdir( chdirTo ) == -1 )
+       {
+         _execError = root ? str::form( _("Can't chdir to '%s' inside chroot '%s' (%s)."), chdirTo, root, strerror(errno) )
+                           : str::form( _("Can't chdir to '%s' (%s)."), chdirTo, strerror(errno) );
+         std::cerr << _execError << endl;// After fork log on stderr too
+         _exit (128);                  // No sense in returning! I am forked away!!
+       }
+
        // close all filedesctiptors above stderr
        for ( int i = ::getdtablesize() - 1; i > 2; --i ) {
          ::close( i );
@@ -572,7 +603,13 @@ namespace zypp {
       EarlyPipe::EarlyPipe()
       {
        _fds[R] = _fds[W] = -1;
+#ifdef HAVE_PIPE2
        ::pipe2( _fds, O_NONBLOCK );
+#else
+        ::pipe( _fds );
+        ::fcntl(_fds[R], F_SETFD, O_NONBLOCK );
+        ::fcntl(_fds[W], F_SETFD, O_NONBLOCK );
+#endif
        _stderr = ::fdopen( _fds[R], "r" );
       }
 
@@ -617,6 +654,7 @@ namespace zypp {
        {
          if ( _buffer.empty() )
            return false;
+         break;
        }
        else if ( errno != EINTR )
          return false;