12 #define _GNU_SOURCE 1 // for ::getline
21 #include <sys/prctl.h>
35 #undef ZYPP_BASE_LOGGER_LOGGROUP
36 #define ZYPP_BASE_LOGGER_LOGGROUP "zypp::exec"
58 argv[2] = commandline.c_str();
74 const char * argvp[argv.size() + 1];
76 for_( i, argv.begin(), argv.end() )
78 argvp[c] = i->c_str();
97 const char * argvp[argv.size() + 1];
99 for_( i, argv.begin(), argv.end() )
101 argvp[c] = i->c_str();
106 start_program( argvp, environment, stderr_disp, stderr_fd, default_locale, root.
c_str() );
134 start_program( argv, environment, stderr_disp, stderr_fd, default_locale, root.
c_str() );
139 const char *
const *argv_1,
147 const char *argv[i + 1];
149 memcpy( &argv[1], argv_1, (i - 1) *
sizeof (
char *) );
155 const char *
const *argv_1,
164 const char *argv[i + 1];
166 memcpy( &argv[1], argv_1, (i - 1) *
sizeof (
char *) );
187 const char * root ,
bool switch_pgid,
bool die_with_parent )
191 int to_external[2], from_external[2];
192 int master_tty, slave_tty;
195 const char * redirectStdin =
nullptr;
196 const char * redirectStdout =
nullptr;
197 const char * chdirTo =
nullptr;
201 if ( root[0] ==
'\0' )
205 else if ( root[0] ==
'/' && root[1] ==
'\0' )
214 for (
bool strip =
false; argv[0]; ++argv )
217 switch ( argv[0][0] )
221 redirectStdin = argv[0]+1;
222 if ( *redirectStdin ==
'\0' )
223 redirectStdin =
"/dev/null";
228 redirectStdout = argv[0]+1;
229 if ( *redirectStdout ==
'\0' )
230 redirectStdout =
"/dev/null";
235 if ( argv[0][1] ==
'/' )
246 std::stringstream cmdstr;
247 for (
int i = 0; argv[i]; i++)
249 if (i>0) cmdstr <<
' ';
255 cmdstr <<
" < '" << redirectStdin <<
"'";
256 if ( redirectStdout )
257 cmdstr <<
" > '" << redirectStdout <<
"'";
260 DBG <<
"Executing" << (default_locale?
"[C] ":
" ") <<
_command << endl;
266 DBG <<
"Using ttys for communication with " << argv[0] << endl;
267 if (openpty (&master_tty, &slave_tty, 0, 0, 0) != 0)
278 if (pipe (to_external) != 0 || pipe (from_external) != 0)
287 pid_t ppid_before_fork =
::getpid();
290 if ((
pid = fork()) == 0)
308 ttyname_r(slave_tty, name,
sizeof(name));
325 int inp_fd = open( redirectStdin, O_RDONLY );
329 if ( redirectStdout )
332 int inp_fd = open( redirectStdout, O_WRONLY|O_CREAT|O_APPEND, 0600 );
339 int null_fd = open(
"/dev/null", O_WRONLY);
354 for ( Environment::const_iterator it = environment.begin(); it != environment.end(); ++it ) {
355 setenv( it->first.c_str(), it->second.c_str(), 1 );
359 setenv(
"LC_ALL",
"C",1);
363 if(chroot(root) == -1)
373 if ( chdirTo && chdir( chdirTo ) == -1 )
382 for (
int i = ::getdtablesize() - 1; i > 2; --i ) {
386 if ( die_with_parent ) {
388 int r = prctl(PR_SET_PDEATHSIG, SIGTERM);
391 std::cerr <<
"Failed to set PR_SET_PDEATHSIG" << endl;
396 pid_t ppidNow = getppid();
397 if (ppidNow != ppid_before_fork) {
398 std::cerr <<
"PPID changed from "<<ppid_before_fork<<
" to "<< ppidNow << endl;
403 execvp(argv[0],
const_cast<char *
const *
>(argv));
440 inputfile = fdopen(from_external[0],
"r");
444 DBG <<
"pid " <<
pid <<
" launched" << endl;
448 ERR <<
"Cannot create streams to external program " << argv[0] << endl;
474 FD_SET( inputfileFd, &rfds );
478 tv.tv_sec = (delay < 0 ? 1 : 0);
479 tv.tv_usec = (delay < 0 ? 0 : delay*100000);
480 if ( delay >= 0 && ++delay > 9 )
482 int retval = select( inputfileFd+1, &rfds, NULL, NULL, &tv );
486 ERR <<
"select error: " <<
strerror(errno) << endl;
487 if ( errno != EINTR )
518 ret = waitpid(
pid, &status, 0);
520 while (ret == -1 && errno == EINTR);
536 if (WIFEXITED (status))
538 status = WEXITSTATUS (status);
541 DBG <<
"Pid " <<
pid <<
" exited with status " << status << endl;
548 DBG <<
"Pid " <<
pid <<
" successfully completed" << endl;
552 else if (WIFSIGNALED (status))
554 status = WTERMSIG (status);
555 WAR <<
"Pid " <<
pid <<
" was killed by signal " << status
556 <<
" (" << strsignal(status);
557 if (WCOREDUMP (status))
559 WAR <<
", core dumped";
562 _execError =
str::form(
_(
"Command was killed by signal %d (%s)."), status, strsignal(status) );
566 ERR <<
"Pid " <<
pid <<
" exited with unknown error" << endl;
567 _execError =
_(
"Command exited with unknown error.");
596 if (
pid < 0 )
return false;
599 int p = waitpid(
pid, &status, WNOHANG );
603 ERR <<
"waitpid( " <<
pid <<
") returned error '" <<
strerror(errno) <<
"'" << endl;
625 dup2 (origfd, newfd);
644 namespace externalprogram
650 ::pipe2(
_fds, O_NONBLOCK );
653 ::fcntl(
_fds[
R], F_SETFD, O_NONBLOCK );
654 ::fcntl(
_fds[
W], F_SETFD, O_NONBLOCK );
671 if ( delim_r && !
_buffer.empty() )
675 if ( pos != std::string::npos )
677 retval_r =
_buffer.substr( 0, returnDelim_r ? pos+1 : pos );
687 if ( ch != delim_r || ! delim_r )
702 else if ( errno != EINTR )