12 #define _GNU_SOURCE 1 // for ::getline 21 #include <sys/prctl.h> 27 #include <zypp-core/AutoDispose.h> 28 #include <zypp-core/base/Logger.h> 29 #include <zypp-core/base/String.h> 30 #include <zypp-core/base/Gettext.h> 31 #include <zypp-core/ExternalProgram.h> 34 #include <zypp-core/zyppng/base/private/linuxhelpers_p.h> 35 #include <zypp-core/zyppng/io/private/forkspawnengine_p.h> 39 #undef ZYPP_BASE_LOGGER_LOGGROUP 40 #define ZYPP_BASE_LOGGER_LOGGROUP "zypp::exec" 58 argv[2] = commandline.c_str();
71 const char * argvp[argv.size() + 1];
73 for_( i, argv.begin(), argv.end() )
75 argvp[c] = i->c_str();
91 const char * argvp[argv.size() + 1];
93 for_( i, argv.begin(), argv.end() )
95 argvp[c] = i->c_str();
100 start_program( argvp, environment, stderr_disp, stderr_fd, default_locale, root.
c_str(),
false,
false, use_pty );
121 start_program( argv, environment, stderr_disp, stderr_fd, default_locale, root.
c_str(),
false,
false, use_pty );
126 const char *
const *argv_1,
132 const char *argv[i + 1];
134 memcpy( &argv[1], argv_1, (i - 1) *
sizeof (
char *) );
139 const char *
const *argv_1,
146 const char *argv[i + 1];
148 memcpy( &argv[1], argv_1, (i - 1) *
sizeof (
char *) );
162 const char * root ,
bool switch_pgid,
bool die_with_parent ,
bool usePty )
169 DBG <<
"usePty was set, forcing the ForkSpawnEngine to start external processes" << std::endl;
170 _backend = std::make_unique<zyppng::ForkSpawnEngine>();
171 static_cast<zyppng::ForkSpawnEngine&
>(*_backend).setUsePty(
true );
173 _backend = zyppng::AbstractSpawnEngine::createDefaultEngine();
177 const char * redirectStdin =
nullptr;
178 const char * redirectStdout =
nullptr;
179 const char * chdirTo =
nullptr;
183 if ( root[0] ==
'\0' )
187 else if ( root[0] ==
'/' && root[1] ==
'\0' )
196 for (
bool strip =
false; argv[0] !=
nullptr; ++argv )
199 switch ( argv[0][0] )
203 redirectStdin = argv[0]+1;
204 if ( *redirectStdin ==
'\0' )
205 redirectStdin =
"/dev/null";
210 redirectStdout = argv[0]+1;
211 if ( *redirectStdout ==
'\0' )
212 redirectStdout =
"/dev/null";
217 if ( argv[0][1] ==
'/' )
239 int master_tty, slave_tty;
242 DBG <<
"Using ttys for communication with " << argv[0] << endl;
243 if (openpty (&master_tty, &slave_tty, 0, 0, 0) != 0)
252 stdoutFd = slave_tty;
253 childStdinParentFd = master_tty;
254 childStdoutParentFd = master_tty;
258 if ( redirectStdin ) {
259 stdinFd = open( redirectStdin, O_RDONLY );
262 if ( pipe (to_external) != 0 )
269 stdinFd = to_external[0];
270 childStdinParentFd = to_external[1];
273 if ( redirectStdout ) {
274 stdoutFd = open( redirectStdout, O_WRONLY|O_CREAT|O_APPEND, 0600 );
277 int from_external[2];
279 if ( pipe (from_external) != 0 )
286 stdoutFd = from_external[1];
287 childStdoutParentFd = from_external[0];
294 stderrFd = open(
"/dev/null", O_WRONLY);
298 stderrFd = *stdoutFd;
306 stderrFd = stderr_fd;
313 _backend->setWorkingDirectory( chdirTo );
315 _backend->setDieWithParent( die_with_parent );
316 _backend->setSwitchPgid( switch_pgid );
317 _backend->setEnvironment( environment );
318 _backend->setUseDefaultLocale( default_locale );
320 if (
_backend->start( argv, stdinFd, stdoutFd, stderrFd ) ) {
321 bool connected =
true;
322 if ( childStdoutParentFd != -1 ) {
323 inputfile = fdopen( childStdoutParentFd,
"r" );
329 if ( childStdinParentFd != -1 ) {
330 outputfile = fdopen( childStdinParentFd,
"w" );
338 ERR <<
"Cannot create streams to external program " << argv[0] << endl;
347 bool ExternalProgram::waitForExit(std::optional<uint64_t> timeout)
353 return _backend->waitForExit( timeout );
360 ExternalDataSource::close();
379 rfd.fd = inputfileFd;
380 rfd.events = G_IO_IN | G_IO_HUP | G_IO_ERR;
385 gint timeout = delay < 0 ? 1000 : delay*100;
386 if ( delay >= 0 && ++delay > 9 )
389 int retval = g_poll( &rfd, 1, timeout );
393 if ( errno != EINTR ) {
394 ERR <<
"select error: " <<
strerror(errno) << endl;
423 ExternalDataSource::close();
433 ERR <<
"Failed to kill PID " <<
_backend->pid() <<
" with error: " <<
Errno() << std::endl;
446 ERR <<
"Failed to kill PID " <<
_backend->pid() <<
" with error: " <<
Errno() << std::endl;
470 static std::string empty;
479 static std::string empty;
488 return zyppng::renumberFd( origfd, newfd );
505 namespace externalprogram
511 ::pipe2(
_fds, O_NONBLOCK );
514 ::fcntl(
_fds[
R], F_SETFD, O_NONBLOCK );
515 ::fcntl(
_fds[
W], F_SETFD, O_NONBLOCK );
532 if ( delim_r && !
_buffer.empty() )
536 if ( pos != std::string::npos )
538 retval_r =
_buffer.substr( 0, returnDelim_r ? pos+1 : pos );
548 if ( ch != delim_r || ! delim_r )
563 else if ( errno != EINTR )
ExternalProgram()
Start an external program by giving the arguments as an arry of char *pointers.
std::ostream & operator>>(std::ostream &out_r)
Redirect all command output to an ostream.
bool kill()
Kill the program.
Convenience errno wrapper.
const std::string & execError() const
Some detail telling why the execution failed, if it failed.
std::unique_ptr< zyppng::AbstractSpawnEngine > _backend
#define for_(IT, BEG, END)
Convenient for-loops using iterator.
const char * c_str() const
String representation.
bool running()
Return whether program is running.
std::string receiveLine()
Read one line from the input stream.
std::string form(const char *format,...) __attribute__((format(printf
Printf style construction of std::string.
AutoDispose<int> calling ::close
std::vector< std::string > Arguments
std::string getline(std::istream &str)
Read one line from stream.
Stderr_Disposition
Define symbols for different policies on the handling of stderr.
std::map< std::string, std::string > Environment
For passing additional environment variables to set.
void resetDispose()
Set no dispose function.
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, bool switch_pgid=false, bool die_with_parent=false, bool usePty=false)
bool stderrGetUpTo(std::string &retval_r, const char delim_r, bool returnDelim_r=false)
Read data up to delim_r from stderr (nonblocking).
int close()
Wait for the progamm to complete.
const std::string & command() const
The command we're executing.
static void renumber_fd(int origfd, int newfd)
origfd will be accessible as newfd and closed (unless they were equal)
void setBlocking(bool mode)
Set the blocking mode of the input stream.
FILE * inputFile() const
Return the input stream.
std::string strerror(int errno_r)
Return string describing the error_r code.
Easy-to use interface to the ZYPP dependency resolver.