fixup Fix to build with libxml 2.12.x (fixes #505)
[platform/upstream/libzypp.git] / zypp / ExternalProgram.h
index f33a6d6..5f46aa4 100644 (file)
 #ifndef ZYPP_EXTERNALPROGRAM_H
 #define ZYPP_EXTERNALPROGRAM_H
 
+#include <unistd.h>
+
 #include <map>
 #include <string>
 #include <vector>
 
-#include "zypp/base/ExternalDataSource.h"
-#include "zypp/Pathname.h"
+#include <zypp/APIConfig.h>
+#include <zypp/base/ExternalDataSource.h>
+#include <zypp/Pathname.h>
 
 namespace zypp {
 
@@ -83,7 +86,7 @@ namespace zypp {
        * @param commandline a shell commandline that is appended to
        * <tt>/bin/sh -c</tt>.
        * @param default_locale whether to set LC_ALL=C before starting
-       * @param root directory to chroot into, / or empty to not chroot
+       * @param root directory to chroot into; or just 'cd' if '/'l;  nothing if empty
        */
       ExternalProgram (std::string commandline,
                     Stderr_Disposition stderr_disp = Normal_Stderr,
@@ -94,7 +97,22 @@ namespace zypp {
        * Start an external program by giving the arguments as an arry of char *pointers.
        * If environment is provided, varaiables will be added to the childs environment,
        * overwriting existing ones.
-       * \throws ExternalProgramException if fork fails.
+       *
+       * Initial args starting with \c # are discarded but some are treated specially:
+       *       #/[path] - chdir to /[path] before executing
+       *
+       * Stdin redirection: If the \b 1st argument starts with a \b '<', the remaining
+       * part is treated as file opened for reading on standard input (or \c /dev/null
+       * if empty).
+       * \code
+       *   // cat file /tmp/x
+       *   const char* argv[] = { "</tmp/x", "cat", NULL };
+       *   ExternalProgram prog( argv );
+       * \endcode
+       *
+       * Stdout redirection: If the \b 1st argument starts with a \b '>', the remaining
+       * part is treated as file opened for writing on standard output (or \c /dev/null
+       * if empty).
        */
 
       ExternalProgram();
@@ -138,6 +156,11 @@ namespace zypp {
       bool kill();
 
       /**
+       * Send a signal to the program
+       */
+      bool kill( int sig );
+
+      /**
        * Return whether program is running
        */
       bool running();
@@ -208,12 +231,97 @@ namespace zypp {
       /** Remember execution errors like failed fork/exec. */
       std::string _execError;
 
+    protected:
+
       void start_program (const char *const *argv, const Environment & environment,
                        Stderr_Disposition stderr_disp = Normal_Stderr,
                        int stderr_fd = -1, bool default_locale = false,
-                       const char* root = NULL);
+                       const char* root = NULL, bool switch_pgid = false, bool die_with_parent = false );
+
+    };
 
+
+  namespace externalprogram
+  {
+    /** Helper providing pipe FDs for \ref ExternalProgramWithStderr.
+     * Moved to a basse class because the pipe needs to be initialized
+     * before the \ref ExternalProgram base class is initialized.
+     * \see \ref ExternalProgramWithStderr
+     */
+    struct EarlyPipe
+    {
+      enum { R=0, W=1 };
+      EarlyPipe();
+      ~EarlyPipe();
+      void closeW()            { if ( _fds[W] != -1 ) { ::close( _fds[W] ); _fds[W] = -1; } }
+      FILE * fStdErr()         { return _stderr; }
+      protected:
+       FILE * _stderr;
+       int _fds[2];
     };
+  } // namespace externalprogram
+
+  /** ExternalProgram extended to offer reading programs stderr.
+   * \see \ref ExternalProgram
+   */
+  class ExternalProgramWithStderr : private externalprogram::EarlyPipe, public ExternalProgram
+  {
+    public:
+      ExternalProgramWithStderr( const Arguments & argv_r, bool defaultLocale_r = false, const Pathname & root_r = "" )
+      : ExternalProgram( argv_r, Stderr_To_FileDesc, /*use_pty*/false, _fds[W], defaultLocale_r, root_r )
+      { _initStdErr(); }
+      /** \overlocad Convenience taking just the \a root_r. */
+      ExternalProgramWithStderr( const Arguments & argv_r, const Pathname & root_r )
+      : ExternalProgramWithStderr( argv_r, false, root_r )
+      {}
+
+      ExternalProgramWithStderr( const Arguments & argv_r, const Environment & environment_r, bool defaultLocale_r = false, const Pathname & root_r = "" )
+      : ExternalProgram( argv_r, environment_r, Stderr_To_FileDesc, /*use_pty*/false, _fds[W], defaultLocale_r, root_r )
+      { _initStdErr(); }
+      /** \overlocad Convenience taking just the \a root_r.  */
+      ExternalProgramWithStderr( const Arguments & argv_r, const Environment & environment_r, const Pathname & root_r )
+      : ExternalProgramWithStderr( argv_r, environment_r, false, root_r )
+      {}
+  public:
+      /** Return \c FILE* to read programms stderr (O_NONBLOCK set). */
+      using externalprogram::EarlyPipe::fStdErr;
+
+      /** Read data up to \c delim_r from stderr (nonblocking).
+       * \note If \c delim_r is '\0', we read as much data as possible.
+       * \return \c false if data are not yet available (\c retval_r remains untouched then).
+       */
+      bool stderrGetUpTo( std::string & retval_r, const char delim_r, bool returnDelim_r = false );
+
+      /** Read next complete line from stderr (nonblocking).
+       * \return \c false if data are not yet available (\c retval_r remains untouched then).
+       */
+      bool stderrGetline( std::string & retval_r, bool returnDelim_r = false  )
+      { return stderrGetUpTo( retval_r, '\n', returnDelim_r ); }
+
+    private:
+      /** Close write end of the pipe (childs end). */
+      void _initStdErr()
+      { closeW(); }
+
+    private:
+      std::string _buffer;
+  };
+
+  /** ExternalProgram extended to change the progress group ID after forking.
+   * \see \ref ExternalProgram
+   */
+  class ZYPP_LOCAL ExternalProgramWithSeperatePgid : public ExternalProgram
+  {
+    public:
+      ExternalProgramWithSeperatePgid (const char *const *argv,
+                   Stderr_Disposition stderr_disp = Normal_Stderr,
+                   int stderr_fd = -1, bool default_locale = false,
+                   const Pathname& root = "") : ExternalProgram()
+      {
+        start_program( argv, Environment(), stderr_disp, stderr_fd, default_locale, root.c_str(), true );
+      }
+
+  };
 
 } // namespace zypp