ExternalProgram::ExternalProgram()
: use_pty (false)
, pid( -1 )
- {
- }
+ {}
ExternalProgram::ExternalProgram( std::string commandline,
argv[2] = commandline.c_str();
argv[3] = 0;
- const char* rootdir = NULL;
- if(!root.empty() && root != "/")
- {
- rootdir = root.asString().c_str();
- }
- Environment environment;
- start_program (argv, environment, stderr_disp, stderr_fd, default_locale, rootdir);
+ start_program( argv, Environment(), stderr_disp, stderr_fd, default_locale, root.c_str() );
}
- ExternalProgram::ExternalProgram (const Arguments &argv,
+ ExternalProgram::ExternalProgram( const Arguments & argv,
Stderr_Disposition stderr_disp,
- bool use_pty, int stderr_fd,
+ bool use_pty,
+ int stderr_fd,
bool default_locale,
- const Pathname& root)
+ const Pathname & root )
: use_pty (use_pty)
, pid( -1 )
{
- const char * argvp[argv.size() + 1];
- unsigned c = 0;
- for_( i, argv.begin(), argv.end() )
- {
- argvp[c] = i->c_str();
- ++c;
- }
- argvp[c] = 0;
+ const char * argvp[argv.size() + 1];
+ unsigned c = 0;
+ for_( i, argv.begin(), argv.end() )
+ {
+ argvp[c] = i->c_str();
+ ++c;
+ }
+ argvp[c] = 0;
- Environment environment;
- const char* rootdir = NULL;
- if(!root.empty() && root != "/")
- {
- rootdir = root.asString().c_str();
- }
- start_program (argvp, environment, stderr_disp, stderr_fd, default_locale, rootdir);
+ start_program( argvp, Environment(), stderr_disp, stderr_fd, default_locale, root.c_str() );
}
- ExternalProgram::ExternalProgram (const Arguments &argv,
+ ExternalProgram::ExternalProgram( const Arguments & argv,
const Environment & environment,
Stderr_Disposition stderr_disp,
- bool use_pty, int stderr_fd,
+ bool use_pty,
+ int stderr_fd,
bool default_locale,
- const Pathname& root)
+ const Pathname & root )
: use_pty (use_pty)
, pid( -1 )
{
- const char * argvp[argv.size() + 1];
- unsigned c = 0;
- for_( i, argv.begin(), argv.end() )
- {
- argvp[c] = i->c_str();
- ++c;
- }
- argvp[c] = 0;
-
- const char* rootdir = NULL;
- if(!root.empty() && root != "/")
- {
- rootdir = root.asString().c_str();
- }
- start_program (argvp, environment, stderr_disp, stderr_fd, default_locale, rootdir);
+ const char * argvp[argv.size() + 1];
+ unsigned c = 0;
+ for_( i, argv.begin(), argv.end() )
+ {
+ argvp[c] = i->c_str();
+ ++c;
+ }
+ argvp[c] = 0;
+ start_program( argvp, environment, stderr_disp, stderr_fd, default_locale, root.c_str() );
}
-
ExternalProgram::ExternalProgram( const char *const *argv,
Stderr_Disposition stderr_disp,
bool use_pty,
: use_pty (use_pty)
, pid( -1 )
{
- const char* rootdir = NULL;
- if(!root.empty() && root != "/")
- {
- rootdir = root.asString().c_str();
- }
- Environment environment;
- start_program (argv, environment, stderr_disp, stderr_fd, default_locale, rootdir);
+ start_program( argv, Environment(), stderr_disp, stderr_fd, default_locale, root.c_str() );
}
- ExternalProgram::ExternalProgram (const char *const *argv, const Environment & environment,
- Stderr_Disposition stderr_disp, bool use_pty,
- int stderr_fd, bool default_locale,
- const Pathname& root)
+ ExternalProgram::ExternalProgram( const char *const * argv,
+ const Environment & environment,
+ Stderr_Disposition stderr_disp,
+ bool use_pty,
+ int stderr_fd,
+ bool default_locale,
+ const Pathname & root )
: use_pty (use_pty)
, pid( -1 )
{
- const char* rootdir = NULL;
- if(!root.empty() && root != "/")
- {
- rootdir = root.asString().c_str();
- }
- start_program (argv, environment, stderr_disp, stderr_fd, default_locale, rootdir);
+ start_program( argv, environment, stderr_disp, stderr_fd, default_locale, root.c_str() );
}
- ExternalProgram::ExternalProgram (const char *binpath, const char *const *argv_1,
- bool use_pty)
+ ExternalProgram::ExternalProgram( const char *binpath,
+ const char *const *argv_1,
+ bool use_pty )
: use_pty (use_pty)
, pid( -1 )
{
;
const char *argv[i + 1];
argv[0] = binpath;
- memcpy (&argv[1], argv_1, (i - 1) * sizeof (char *));
- Environment environment;
- start_program (argv, environment);
+ memcpy( &argv[1], argv_1, (i - 1) * sizeof (char *) );
+ start_program( argv, Environment() );
}
- ExternalProgram::ExternalProgram (const char *binpath, const char *const *argv_1, const Environment & environment,
- bool use_pty)
+ ExternalProgram::ExternalProgram( const char *binpath,
+ const char *const *argv_1,
+ const Environment & environment,
+ bool use_pty )
: use_pty (use_pty)
, pid( -1 )
{
;
const char *argv[i + 1];
argv[0] = binpath;
- memcpy (&argv[1], argv_1, (i - 1) * sizeof (char *));
- start_program (argv, environment);
+ memcpy( &argv[1], argv_1, (i - 1) * sizeof (char *) );
+ start_program( argv, environment );
}
ExternalProgram::~ExternalProgram()
- {
- }
+ {}
- void
- ExternalProgram::start_program (const char *const *argv, const Environment & environment,
- Stderr_Disposition stderr_disp,
- int stderr_fd, bool default_locale, const char* root)
+
+ void ExternalProgram::start_program( const char *const *argv,
+ const Environment & environment,
+ Stderr_Disposition stderr_disp,
+ int stderr_fd,
+ bool default_locale,
+ const char * root )
{
pid = -1;
_exitStatus = 0;
- int to_external[2], from_external[2]; // fds for pair of pipes
- int master_tty, slave_tty; // fds for pair of ttys
+ int to_external[2], from_external[2]; // fds for pair of pipes
+ int master_tty, slave_tty; // fds for pair of ttys
+
+ // retrieve options at beginning of arglist
+ const char * redirectStdin = nullptr; // <[file]
+ const char * redirectStdout = nullptr; // >[file]
+ const char * chdirTo = nullptr; // #/[path]
- const char * redirectStdin = 0;
- if ( argv[0] && *argv[0] == '<' )
+ if ( root )
{
- redirectStdin = argv[0]+1;
- if ( *redirectStdin == '\0' )
- redirectStdin = "/dev/null";
- ++argv;
+ if ( root[0] == '\0' )
+ {
+ root = nullptr; // ignore empty root
+ }
+ else if ( root[0] == '/' && root[1] == '\0' )
+ {
+ // If root is '/' do not chroot, but chdir to '/'
+ // unless arglist defines another dir.
+ chdirTo = "/";
+ root = nullptr;
+ }
+ }
+
+ for ( bool strip = false; argv[0]; ++argv )
+ {
+ strip = false;
+ switch ( argv[0][0] )
+ {
+ case '<':
+ strip = true;
+ redirectStdin = argv[0]+1;
+ if ( *redirectStdin == '\0' )
+ redirectStdin = "/dev/null";
+ break;
+
+ case '>':
+ strip = true;
+ redirectStdout = argv[0]+1;
+ if ( *redirectStdout == '\0' )
+ redirectStdout = "/dev/null";
+ break;
+
+ case '#':
+ strip = true;
+ if ( argv[0][1] == '/' ) // #/[path]
+ chdirTo = argv[0]+1;
+ break;
+ }
+ if ( ! strip )
+ break;
}
// do not remove the single quotes around every argument, copy&paste of
}
if ( redirectStdin )
cmdstr << " < '" << redirectStdin << "'";
+ if ( redirectStdout )
+ cmdstr << " > '" << redirectStdout << "'";
_command = cmdstr.str();
}
DBG << "Executing " << _command << endl;
dup2( inp_fd, 0 );
}
+ if ( redirectStdout )
+ {
+ ::close( 1 );
+ int inp_fd = open( redirectStdout, O_WRONLY|O_CREAT|O_APPEND, 0600 );
+ dup2( inp_fd, 1 );
+ }
+
// Handle stderr
if (stderr_disp == Discard_Stderr)
{
std::cerr << _execError << endl;// After fork log on stderr too
_exit (128); // No sense in returning! I am forked away!!
}
- if(chdir("/") == -1)
- {
- _execError = str::form( _("Can't chdir to '/' inside chroot (%s)."), strerror(errno) );
- std::cerr << _execError << endl;// After fork log on stderr too
- _exit (128); // No sense in returning! I am forked away!!
- }
+ if ( ! chdirTo )
+ chdirTo = "/";
}
+ if ( chdirTo && chdir( chdirTo ) == -1 )
+ {
+ _execError = root ? str::form( _("Can't chdir to '%s' inside chroot '%s' (%s)."), chdirTo, root, strerror(errno) )
+ : str::form( _("Can't chdir to '%s' (%s)."), chdirTo, strerror(errno) );
+ std::cerr << _execError << endl;// After fork log on stderr too
+ _exit (128); // No sense in returning! I am forked away!!
+ }
+
// close all filedesctiptors above stderr
for ( int i = ::getdtablesize() - 1; i > 2; --i ) {
::close( i );
// Data is available now.
static size_t linebuffer_size = 0; // static because getline allocs
static char * linebuffer = 0; // and reallocs if buffer is too small
- ssize_t nread = getline( &linebuffer, &linebuffer_size, inputfile );
+ getline( &linebuffer, &linebuffer_size, inputfile );
// ::feof check is important as select returns
// positive if the file was closed.
if ( ::feof( inputfile ) )
return out_r;
}
+ //////////////////////////////////////////////////////////////////////
+ //
+ // class ExternalProgramWithStderr
+ //
+ //////////////////////////////////////////////////////////////////////
+
+ namespace externalprogram
+ {
+ EarlyPipe::EarlyPipe()
+ {
+ _fds[R] = _fds[W] = -1;
+#ifdef HAVE_PIPE2
+ ::pipe2( _fds, O_NONBLOCK );
+#else
+ ::pipe( _fds );
+ ::fcntl(_fds[R], F_SETFD, O_NONBLOCK );
+ ::fcntl(_fds[W], F_SETFD, O_NONBLOCK );
+#endif
+ _stderr = ::fdopen( _fds[R], "r" );
+ }
+
+ EarlyPipe::~EarlyPipe()
+ {
+ closeW();
+ if ( _stderr )
+ ::fclose( _stderr );
+ }
+ } // namespace externalprogram
+
+ bool ExternalProgramWithStderr::stderrGetUpTo( std::string & retval_r, const char delim_r, bool returnDelim_r )
+ {
+ if ( ! _stderr )
+ return false;
+ if ( delim_r && ! _buffer.empty() )
+ {
+ // check for delim already in buffer
+ std::string::size_type pos( _buffer.find( delim_r ) );
+ if ( pos != std::string::npos )
+ {
+ retval_r = _buffer.substr( 0, returnDelim_r ? pos+1 : pos );
+ _buffer.erase( 0, pos+1 );
+ return true;
+ }
+ }
+ ::clearerr( _stderr );
+ do {
+ int ch = fgetc( _stderr );
+ if ( ch != EOF )
+ {
+ if ( ch != delim_r || ! delim_r )
+ _buffer.push_back( ch );
+ else
+ {
+ if ( returnDelim_r )
+ _buffer.push_back( delim_r );
+ break;
+ }
+ }
+ else if ( ::feof( _stderr ) )
+ {
+ if ( _buffer.empty() )
+ return false;
+ break;
+ }
+ else if ( errno != EINTR )
+ return false;
+ } while ( true );
+ // HERE: we left after readig at least one char (\n)
+ retval_r.swap( _buffer );
+ _buffer.clear();
+ return true;
+ }
+
} // namespace zypp