12 #define _GNU_SOURCE 1 // for ::getline
35 ExternalProgram::ExternalProgram()
47 const Pathname & root )
54 argv[2] = commandline.c_str();
57 const char* rootdir = NULL;
58 if(!root.empty() && root !=
"/")
60 rootdir = root.asString().c_str();
63 start_program (argv, environment, stderr_disp, stderr_fd, default_locale, rootdir);
69 bool use_pty,
int stderr_fd,
75 const char * argvp[argv.size() + 1];
77 for_( i, argv.begin(), argv.end() )
79 argvp[c] = i->c_str();
85 const char* rootdir = NULL;
86 if(!root.empty() && root !=
"/")
88 rootdir = root.asString().c_str();
90 start_program (argvp, environment, stderr_disp, stderr_fd, default_locale, rootdir);
97 bool use_pty,
int stderr_fd,
103 const char * argvp[argv.size() + 1];
105 for_( i, argv.begin(), argv.end() )
107 argvp[c] = i->c_str();
112 const char* rootdir = NULL;
113 if(!root.empty() && root !=
"/")
115 rootdir = root.asString().c_str();
117 start_program (argvp, environment, stderr_disp, stderr_fd, default_locale, rootdir);
129 const Pathname & root )
133 const char* rootdir = NULL;
134 if(!root.empty() && root !=
"/")
136 rootdir = root.asString().c_str();
139 start_program (argv, environment, stderr_disp, stderr_fd, default_locale, rootdir);
145 int stderr_fd,
bool default_locale,
146 const Pathname& root)
150 const char* rootdir = NULL;
151 if(!root.empty() && root !=
"/")
153 rootdir = root.asString().c_str();
155 start_program (argv, environment, stderr_disp, stderr_fd, default_locale, rootdir);
167 const char *argv[i + 1];
169 memcpy (&argv[1], argv_1, (i - 1) *
sizeof (
char *));
183 const char *argv[i + 1];
185 memcpy (&argv[1], argv_1, (i - 1) *
sizeof (
char *));
198 int stderr_fd,
bool default_locale,
const char* root)
202 int to_external[2], from_external[2];
203 int master_tty, slave_tty;
205 const char * redirectStdin = 0;
206 if ( argv[0] && *argv[0] ==
'<' )
208 redirectStdin = argv[0]+1;
209 if ( *redirectStdin ==
'\0' )
210 redirectStdin =
"/dev/null";
218 for (
int i = 0; argv[i]; i++)
220 if (i>0) cmdstr <<
' ';
226 cmdstr <<
" < '" << redirectStdin <<
"'";
235 DBG <<
"Using ttys for communication with " << argv[0] << endl;
236 if (openpty (&master_tty, &slave_tty, 0, 0, 0) != 0)
247 if (pipe (to_external) != 0 || pipe (from_external) != 0)
257 if ((
pid = fork()) == 0)
275 ttyname_r(slave_tty, name,
sizeof(name));
290 int inp_fd = open( redirectStdin, O_RDONLY );
297 int null_fd = open(
"/dev/null", O_WRONLY);
312 for ( Environment::const_iterator it = environment.begin(); it != environment.end(); ++it ) {
313 setenv( it->first.c_str(), it->second.c_str(), 1 );
317 setenv(
"LC_ALL",
"C",1);
321 if(chroot(root) == -1)
336 for (
int i = ::getdtablesize() - 1; i > 2; --i ) {
340 execvp(argv[0], const_cast<char *const *>(argv));
377 inputfile = fdopen(from_external[0],
"r");
381 DBG <<
"pid " <<
pid <<
" launched" << endl;
385 ERR <<
"Cannot create streams to external program " << argv[0] << endl;
404 int inputfileFd = ::fileno( inputfile );
411 FD_SET( inputfileFd, &rfds );
415 tv.tv_sec = (delay < 0 ? 1 : 0);
416 tv.tv_usec = (delay < 0 ? 0 : delay*100000);
417 if ( delay >= 0 && ++delay > 9 )
419 int retval = select( inputfileFd+1, &rfds, NULL, NULL, &tv );
423 ERR <<
"select error: " <<
strerror(errno) << endl;
424 if ( errno != EINTR )
432 getline( &linebuffer, &linebuffer_size, inputfile );
435 if ( ::feof( inputfile ) )
437 clearerr( inputfile );
453 ret = waitpid(
pid, &status, 0);
455 while (ret == -1 && errno == EINTR);
470 if (WIFEXITED (status))
472 status = WEXITSTATUS (status);
475 DBG <<
"Pid " <<
pid <<
" exited with status " << status << endl;
482 DBG <<
"Pid " <<
pid <<
" successfully completed" << endl;
486 else if (WIFSIGNALED (status))
488 status = WTERMSIG (status);
489 WAR <<
"Pid " <<
pid <<
" was killed by signal " << status
490 <<
" (" << strsignal(status);
491 if (WCOREDUMP (status))
493 WAR <<
", core dumped";
496 _execError =
str::form(
_(
"Command was killed by signal %d (%s)."), status, strsignal(status) );
500 ERR <<
"Pid " <<
pid <<
" exited with unknown error" << endl;
501 _execError =
_(
"Command exited with unknown error.");
522 if (
pid < 0 )
return false;
525 int p = waitpid(
pid, &status, WNOHANG );
529 ERR <<
"waitpid( " <<
pid <<
") returned error '" <<
strerror(errno) <<
"'" << endl;
551 dup2 (origfd, newfd);
570 namespace _ExternalProgram
576 ::pipe2(
_fds, O_NONBLOCK );
579 ::fcntl(
_fds[
R], F_SETFD, O_NONBLOCK );
580 ::fcntl(
_fds[
W], F_SETFD, O_NONBLOCK );
597 if ( delim_r && !
_buffer.empty() )
601 if ( pos != std::string::npos )
603 retval_r =
_buffer.substr( 0, returnDelim_r ? pos+1 : pos );
613 if ( ch != delim_r || ! delim_r )
628 else if ( errno != EINTR )