22#include <zypp-core/base/DefaultIntegral>
33#undef ZYPP_BASE_LOGGER_LOGGROUP
34#define ZYPP_BASE_LOGGER_LOGGROUP "zypp::plugin"
42 const char * PLUGIN_DEBUG = getenv(
"ZYPP_PLUGIN_DEBUG" );
47 struct PluginDebugBuffer
49 PluginDebugBuffer(
const std::string &buffer_r) : _buffer(buffer_r) {}
50 PluginDebugBuffer(
const PluginDebugBuffer &) =
delete;
51 PluginDebugBuffer(PluginDebugBuffer &&) =
delete;
52 PluginDebugBuffer &operator=(
const PluginDebugBuffer &) =
delete;
53 PluginDebugBuffer &operator=(PluginDebugBuffer &&) =
delete;
58 if ( _buffer.empty() )
60 L_DBG(
"PLUGIN") <<
"< (empty)" << endl;
64 std::istringstream datas( _buffer );
69 const std::string & _buffer;
75 struct PluginDumpStderr
77 PluginDumpStderr(ExternalProgramWithStderr &prog_r) : _prog(prog_r) {}
78 PluginDumpStderr(
const PluginDumpStderr &) =
delete;
79 PluginDumpStderr(PluginDumpStderr &&) =
delete;
80 PluginDumpStderr &operator=(
const PluginDumpStderr &) =
delete;
81 PluginDumpStderr &operator=(PluginDumpStderr &&) =
delete;
85 while ( _prog.stderrGetline( line ) )
86 L_WAR(
"PLUGIN") <<
"! " << line << endl;
91 auto str = str::Str();
93 while ( _prog.stderrGetline( line ) ) {
94 L_WAR(
"PLUGIN") <<
"! " << line << endl;
100 ExternalProgramWithStderr & _prog;
103 inline void setBlocking( FILE * file_r,
bool yesno_r =
true )
106 ZYPP_THROW( PluginScriptException(
"setNonBlocking" ) );
108 int fd = ::fileno( file_r );
110 ZYPP_THROW( PluginScriptException(
"setNonBlocking" ) );
112 int flags = ::fcntl( fd, F_GETFL );
114 ZYPP_THROW( PluginScriptException(
"setNonBlocking" ) );
118 else if ( flags & O_NONBLOCK )
121 flags = ::fcntl( fd, F_SETFL, flags );
123 ZYPP_THROW( PluginScriptException(
"setNonBlocking" ) );
126 inline void setNonBlocking( FILE * file_r,
bool yesno_r =
true )
127 { setBlocking( file_r, !yesno_r ); }
178 {
return _cmd !=
nullptr; }
215 const long PLUGIN_SEND_TIMEOUT =
str::strtonum<long>( getenv(
"ZYPP_PLUGIN_SEND_TIMEOUT" ) );
216 const long PLUGIN_RECEIVE_TIMEOUT =
str::strtonum<long>( getenv(
"ZYPP_PLUGIN_RECEIVE_TIMEOUT" ) );
220 : ( PLUGIN_TIMEOUT > 0 ? PLUGIN_TIMEOUT : 30 ) );
222 : ( PLUGIN_TIMEOUT > 0 ? PLUGIN_TIMEOUT : 30 ) );
242 args.reserve( args_r.size()+1 );
244 args.insert(
args.end(), args_r.begin(), args_r.end() );
247 if ( not
_cmd->running() ) {
248 const std::string execError(
_cmd->execError() );
254 setNonBlocking(
_cmd->outputFile() );
255 setNonBlocking(
_cmd->inputFile() );
270 DBG <<
"Close:" << *
this << endl;
272 if (
_cmd->running() ) {
304 if ( frame_r.
command().empty() )
305 WAR <<
"Send: No command in frame" << frame_r << endl;
310 std::ostringstream datas;
312 datas.str().swap( data );
314 DBG << *
this <<
" ->send " << frame_r << endl;
318 std::istringstream datas( data );
323 FILE * filep =
_cmd->outputFile();
327 int fd = ::fileno( filep );
333 PluginDumpStderr _dump( *
_cmd );
335 const char * buffer = data.c_str();
336 ssize_t buffsize = data.size();
340 watchFd.events = G_IO_OUT | G_IO_ERR;
344 int retval = g_poll( &watchFd, 1,
_sendTimeout * 1000 );
348 ssize_t ret = ::write( fd, buffer, buffsize );
349 if ( ret == buffsize )
364 if ( errno != EINTR )
366 ERR <<
"write(): " <<
Errno() << endl;
367 if ( errno == EPIPE )
368 ZYPP_THROW( PluginScriptDiedUnexpectedly(
"Send: script died unexpectedly", _dump.take() ) );
374 else if ( retval == 0 )
376 WAR <<
"Not ready to write within timeout." << endl;
377 ZYPP_THROW( PluginScriptSendTimeout(
"Not ready to write within timeout." ) );
381 if ( errno != EINTR )
383 ERR <<
"select(): " <<
Errno() << endl;
397 FILE * filep =
_cmd->inputFile();
401 int fd = ::fileno( filep );
408 PluginDebugBuffer _debug( data );
409 PluginDumpStderr _dump( *
_cmd );
411 int ch = fgetc( filep );
414 data.push_back( ch );
418 else if ( ::feof( filep ) )
420 WAR <<
"Unexpected EOF" << endl;
421 ZYPP_THROW( PluginScriptDiedUnexpectedly(
"Receive: script died unexpectedly", _dump.take() ) );
423 else if ( errno != EINTR )
425 if ( errno == EWOULDBLOCK )
430 rfd.events = G_IO_IN | G_IO_HUP | G_IO_ERR;
438 else if ( retval == 0 )
440 WAR <<
"Not ready to read within timeout." << endl;
441 ZYPP_THROW( PluginScriptReceiveTimeout(
"Not ready to read within timeout." ) );
445 if ( errno != EINTR )
447 ERR <<
"select(): " <<
Errno() << endl;
454 ERR <<
"read(): " <<
Errno() << endl;
461 std::istringstream datas( data );
463 DBG << *
this <<
" <-" << ret << endl;
488 {
return _pimpl->_sendTimeout; }
491 {
return _pimpl->_receiveTimeout; }
494 {
_pimpl->_sendTimeout = newval_r > 0 ? newval_r : 0; }
497 {
_pimpl->_receiveTimeout = newval_r > 0 ? newval_r : 0; }
512 {
return _pimpl->script(); }
515 {
return _pimpl->args(); }
518 {
return _pimpl->isOpen(); }
521 {
return _pimpl->getPid(); }
524 {
return _pimpl->getChroot(); }
527 {
return _pimpl->lastReturn(); }
530 {
return _pimpl->lastExecError(); }
536 {
_pimpl->open( script_r ); }
539 {
_pimpl->open( script_r, args_r ); }
545 {
_pimpl->open( script_r, args_r, chroot_r ); }
551 {
return _pimpl->close(); }
554 {
_pimpl->send( frame_r ); }
557 {
return _pimpl->receive(); }
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
std::string asString() const
Integral type with defined initial value when default constructed.
Convenience errno wrapper.
ExternalProgram extended to offer reading programs stderr.
static std::string showRootIf(const Pathname &root_r, const Pathname &path_r)
String representation as "(root)/path", unless root is "/" or empty.
Command frame for communication with PluginScript.
const ByteArray & body() const
Return the frame body.
const std::string & command() const
Return the frame command.
std::string getHeaderNT(const std::string &key_r, const std::string &default_r=std::string()) const
Not throwing version returing one of the matching header values or default_r string.
bool isAckCommand() const
Convenience to identify an ACK command.
std::ostream & writeTo(std::ostream &stream_r) const
Write frame to stream.
Base class for PluginScript Exception.
PluginFrame receive() const
Receive a PluginFrame.
std::vector< std::string > Arguments
Commandline arguments passed to a script on open.
Pathname getChroot() const
Return a connected scripts chroot or an empty Pathname.
void openChrooted(const Pathname &chroot_r)
Like open() but runs the script chrooted into chroot_r.
long sendTimeout() const
Local default timeout (sec.) when sending data.
void send(const PluginFrame &frame_r) const
Send a PluginFrame.
PluginScript()
Default ctor.
RW_pointer< Impl > _pimpl
Pointer to implementation.
int lastReturn() const
Remembers a scripts return value after close until next open.
static long defaultReceiveTimeout()
Global default timeout (sec.) when receiving data.
static const pid_t NotConnected
pid_t(-1) constant indicating no connection.
int close()
Close any open connection.
const std::string & lastExecError() const
Remembers a scripts execError string after close until next open.
pid_t getPid() const
Return a connected scripts pid or NotConnected.
void open()
Setup connection and execute script.
const Pathname & script() const
Return the script path if set.
static long defaultSendTimeout()
Global default timeout (sec.) when sending data.
bool isOpen() const
Whether we are connected to a script.
long receiveTimeout() const
Local default timeout (sec.) when receiving data.
const Arguments & args() const
Return the script arguments if set.
Exception safe signal handler save/restore.
Wrapper class for stat/lstat.
const std::string & asString() const
String representation.
String related utilities and Regular expression matching.
std::ostream & copyIndent(std::istream &from_r, std::ostream &to_r, const std::string &indent_r="> ")
Copy istream to ostream, prefixing each line with indent_r (default "> " ).
std::string sprint(Args &&... args)
Print words as string.
TInt strtonum(const C_Str &str)
Parsing numbers from string.
Easy-to use interface to the ZYPP dependency resolver.
std::ostream & dumpRangeLine(std::ostream &str, TIterator begin, TIterator end)
Print range defined by iterators (single line style).
std::ostream & operator<<(std::ostream &str, const Capabilities &obj)
relates: Capabilities Stream output
PluginScript implementation.
PluginFrame receive() const
std::string _lastExecError
static long _defaultSendTimeout
Impl(const Impl &)=delete
DefaultIntegral< int, 0 > _lastReturn
Impl & operator=(const Impl &)=delete
const Pathname & script() const
scoped_ptr< ExternalProgramWithStderr > _cmd
Pathname getChroot() const
void send(const PluginFrame &frame_r) const
Impl & operator=(Impl &&)=delete
static long _defaultReceiveTimeout
const std::string & lastExecError() const
Impl(Pathname &&script_r=Pathname(), Arguments &&args_r=Arguments())
const Arguments & args() const
void open(const Pathname &script_r=Pathname(), const Arguments &args_r=Arguments(), const Pathname &root_r=Pathname())
Convenient building of std::string via std::ostringstream Basically a std::ostringstream autoconverti...