1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/ExternalProgram.h
13 #ifndef ZYPP_EXTERNALPROGRAM_H
14 #define ZYPP_EXTERNALPROGRAM_H
22 #include <zypp/APIConfig.h>
23 #include <zypp/base/ExternalDataSource.h>
24 #include <zypp/Pathname.h>
29 * @short Execute a program and give access to its io
30 * An object of this class encapsulates the execution of
31 * an external program. It starts the program using fork
32 * and some exec.. call, gives you access to the program's
33 * stdio and closes the program after use.
37 * const char* argv[] =
45 * ExternalProgram prog( argv,
46 * ExternalProgram::Discard_Stderr,
49 * for(line = prog.receiveLine();
51 * line = prog.receiveLine() )
59 class ExternalProgram : public zypp::externalprogram::ExternalDataSource
64 typedef std::vector<std::string> Arguments;
67 * Define symbols for different policies on the handling
70 enum Stderr_Disposition {
79 * For passing additional environment variables to set
81 typedef std::map<std::string,std::string> Environment;
84 * Start the external program by using the shell <tt>/bin/sh<tt>
85 * with the option <tt>-c</tt>. You can use io direction symbols < and >.
86 * @param commandline a shell commandline that is appended to
87 * <tt>/bin/sh -c</tt>.
88 * @param default_locale whether to set LC_ALL=C before starting
89 * @param root directory to chroot into; or just 'cd' if '/'l; nothing if empty
91 ExternalProgram (std::string commandline,
92 Stderr_Disposition stderr_disp = Normal_Stderr,
93 bool use_pty = false, int stderr_fd = -1, bool default_locale = false,
94 const Pathname& root = "");
97 * Start an external program by giving the arguments as an arry of char *pointers.
98 * If environment is provided, varaiables will be added to the childs environment,
99 * overwriting existing ones.
101 * Initial args starting with \c # are discarded but some are treated specially:
102 * #/[path] - chdir to /[path] before executing
104 * Stdin redirection: If the \b 1st argument starts with a \b '<', the remaining
105 * part is treated as file opened for reading on standard input (or \c /dev/null
109 * const char* argv[] = { "</tmp/x", "cat", NULL };
110 * ExternalProgram prog( argv );
113 * Stdout redirection: If the \b 1st argument starts with a \b '>', the remaining
114 * part is treated as file opened for writing on standard output (or \c /dev/null
120 ExternalProgram (const Arguments &argv,
121 Stderr_Disposition stderr_disp = Normal_Stderr,
122 bool use_pty = false, int stderr_fd = -1, bool default_locale = false,
123 const Pathname& root = "");
125 ExternalProgram (const Arguments &argv, const Environment & environment,
126 Stderr_Disposition stderr_disp = Normal_Stderr,
127 bool use_pty = false, int stderr_fd = -1, bool default_locale = false,
128 const Pathname& root = "");
130 ExternalProgram (const char *const *argv,
131 Stderr_Disposition stderr_disp = Normal_Stderr,
132 bool use_pty = false, int stderr_fd = -1, bool default_locale = false,
133 const Pathname& root = "");
135 ExternalProgram (const char *const *argv, const Environment & environment,
136 Stderr_Disposition stderr_disp = Normal_Stderr,
137 bool use_pty = false, int stderr_fd = -1, bool default_locale = false,
138 const Pathname& root = "");
140 ExternalProgram (const char *binpath, const char *const *argv_1,
141 bool use_pty = false);
144 ExternalProgram (const char *binpath, const char *const *argv_1, const Environment & environment,
145 bool use_pty = false);
150 /** Wait for the progamm to complete. */
159 * Send a signal to the program
161 bool kill( int sig );
164 * Return whether program is running
171 pid_t getpid() { return pid; }
173 /** The command we're executing. */
174 const std::string & command() const
177 /** Some detail telling why the execution failed, if it failed.
178 * Empty if the command is still running or successfully completed.
180 * \li <tt>Can't open pty (%s).</tt>
181 * \li <tt>Can't open pipe (%s).</tt>
182 * \li <tt>Can't fork (%s).</tt>
183 * \li <tt>Command exited with status %d.</tt>
184 * \li <tt>Command was killed by signal %d (%s).</tt>
186 const std::string & execError() const
187 { return _execError; }
190 * origfd will be accessible as newfd and closed (unless they were equal)
192 static void renumber_fd (int origfd, int newfd);
197 * Redirect all command output to an \c ostream.
198 * Returns when the command has completed.
200 * std::ostringstream s;
201 * ExternalProgram("pwd") >> s;
202 * SEC << s.str() << endl;
205 * std::ostringstream s;
206 * ExternalProgram prog("ls -l wrzl");
208 * if ( prog.close() == 0 )
209 * MIL << s.str() << endl;
211 * ERR << prog.execError() << endl;
214 std::ostream & operator>>( std::ostream & out_r );
217 int checkStatus( int );
222 * Set to true, if a pair of ttys is used for communication
223 * instead of a pair of pipes.
229 /** Store the command we're executing. */
230 std::string _command;
231 /** Remember execution errors like failed fork/exec. */
232 std::string _execError;
236 void start_program (const char *const *argv, const Environment & environment,
237 Stderr_Disposition stderr_disp = Normal_Stderr,
238 int stderr_fd = -1, bool default_locale = false,
239 const char* root = NULL, bool switch_pgid = false, bool die_with_parent = false );
244 namespace externalprogram
246 /** Helper providing pipe FDs for \ref ExternalProgramWithStderr.
247 * Moved to a basse class because the pipe needs to be initialized
248 * before the \ref ExternalProgram base class is initialized.
249 * \see \ref ExternalProgramWithStderr
256 void closeW() { if ( _fds[W] != -1 ) { ::close( _fds[W] ); _fds[W] = -1; } }
257 FILE * fStdErr() { return _stderr; }
262 } // namespace externalprogram
264 /** ExternalProgram extended to offer reading programs stderr.
265 * \see \ref ExternalProgram
267 class ExternalProgramWithStderr : private externalprogram::EarlyPipe, public ExternalProgram
270 ExternalProgramWithStderr( const Arguments & argv_r, bool defaultLocale_r = false, const Pathname & root_r = "" )
271 : ExternalProgram( argv_r, Stderr_To_FileDesc, /*use_pty*/false, _fds[W], defaultLocale_r, root_r )
273 /** \overlocad Convenience taking just the \a root_r. */
274 ExternalProgramWithStderr( const Arguments & argv_r, const Pathname & root_r )
275 : ExternalProgramWithStderr( argv_r, false, root_r )
278 ExternalProgramWithStderr( const Arguments & argv_r, const Environment & environment_r, bool defaultLocale_r = false, const Pathname & root_r = "" )
279 : ExternalProgram( argv_r, environment_r, Stderr_To_FileDesc, /*use_pty*/false, _fds[W], defaultLocale_r, root_r )
281 /** \overlocad Convenience taking just the \a root_r. */
282 ExternalProgramWithStderr( const Arguments & argv_r, const Environment & environment_r, const Pathname & root_r )
283 : ExternalProgramWithStderr( argv_r, environment_r, false, root_r )
286 /** Return \c FILE* to read programms stderr (O_NONBLOCK set). */
287 using externalprogram::EarlyPipe::fStdErr;
289 /** Read data up to \c delim_r from stderr (nonblocking).
290 * \note If \c delim_r is '\0', we read as much data as possible.
291 * \return \c false if data are not yet available (\c retval_r remains untouched then).
293 bool stderrGetUpTo( std::string & retval_r, const char delim_r, bool returnDelim_r = false );
295 /** Read next complete line from stderr (nonblocking).
296 * \return \c false if data are not yet available (\c retval_r remains untouched then).
298 bool stderrGetline( std::string & retval_r, bool returnDelim_r = false )
299 { return stderrGetUpTo( retval_r, '\n', returnDelim_r ); }
302 /** Close write end of the pipe (childs end). */
310 /** ExternalProgram extended to change the progress group ID after forking.
311 * \see \ref ExternalProgram
313 class ZYPP_LOCAL ExternalProgramWithSeperatePgid : public ExternalProgram
316 ExternalProgramWithSeperatePgid (const char *const *argv,
317 Stderr_Disposition stderr_disp = Normal_Stderr,
318 int stderr_fd = -1, bool default_locale = false,
319 const Pathname& root = "") : ExternalProgram()
321 start_program( argv, Environment(), stderr_disp, stderr_fd, default_locale, root.c_str(), true );
328 #endif // ZYPP_EXTERNALPROGRAM_H