#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 {
* @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,
* 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();
bool kill();
/**
+ * Send a signal to the program
+ */
+ bool kill( int sig );
+
+ /**
* Return whether program is running
*/
bool running();
/** 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