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;
60 L_DBG(
"PLUGIN") <<
"< (empty)" << endl;
64 std::istringstream datas(
_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;
88 ExternalProgramWithStderr &
_prog;
91 inline void setBlocking( FILE * file_r,
bool yesno_r =
true )
94 ZYPP_THROW( PluginScriptException(
"setNonBlocking" ) );
96 int fd = ::fileno( file_r );
98 ZYPP_THROW( PluginScriptException(
"setNonBlocking" ) );
100 int flags = ::fcntl( fd, F_GETFL );
102 ZYPP_THROW( PluginScriptException(
"setNonBlocking" ) );
106 else if ( flags & O_NONBLOCK )
109 flags = ::fcntl( fd, F_SETFL, flags );
111 ZYPP_THROW( PluginScriptException(
"setNonBlocking" ) );
114 inline void setNonBlocking( FILE * file_r,
bool yesno_r =
true )
115 { setBlocking( file_r, !yesno_r ); }
163 {
return _cmd !=
nullptr; }
185 scoped_ptr<ExternalProgramWithStderr>
_cmd;
202 const long PLUGIN_SEND_TIMEOUT =
str::strtonum<long>( getenv(
"ZYPP_PLUGIN_SEND_TIMEOUT" ) );
203 const long PLUGIN_RECEIVE_TIMEOUT =
str::strtonum<long>( getenv(
"ZYPP_PLUGIN_RECEIVE_TIMEOUT" ) );
207 : ( PLUGIN_TIMEOUT > 0 ? PLUGIN_TIMEOUT : 30 ) );
209 : ( PLUGIN_TIMEOUT > 0 ? PLUGIN_TIMEOUT : 30 ) );
215 dumpRangeLine(
DBG <<
"Open " << script_r, args_r.begin(), args_r.end() ) << endl;
229 args.reserve( args_r.size()+1 );
231 args.insert(
args.end(), args_r.begin(), args_r.end() );
235 setNonBlocking(
_cmd->outputFile() );
236 setNonBlocking(
_cmd->inputFile() );
251 DBG <<
"Close:" << *
this << endl;
270 _lastReturn = _cmd->close();
271 _lastExecError = _cmd->execError();
273 DBG << *
this <<
" -> [" << _lastReturn <<
"] " << _lastExecError << endl;
284 this->
send( frame_r );
289 ret.first = atoi( resp.
getHeaderNT(
"PLUGIN_PROGRESS_CURRENT",
"-1").c_str() );
290 ret.second = atoi( resp.
getHeaderNT(
"PLUGIN_PROGRESS_MAX",
"-1").c_str() );
301 if ( frame_r.
command().empty() )
302 WAR <<
"Send: No command in frame" << frame_r << endl;
307 std::ostringstream datas;
309 datas.str().swap( data );
311 DBG << *
this <<
" ->send " << frame_r << endl;
315 std::istringstream datas( data );
320 FILE * filep = _cmd->outputFile();
324 int fd = ::fileno( filep );
330 PluginDumpStderr _dump( *_cmd );
332 const char * buffer = data.c_str();
333 ssize_t buffsize = data.size();
337 watchFd.events = G_IO_OUT | G_IO_ERR;
341 int retval = g_poll( &watchFd, 1, _sendTimeout * 1000 );
345 ssize_t ret = ::write( fd, buffer, buffsize );
346 if ( ret == buffsize )
361 if ( errno != EINTR )
363 ERR <<
"write(): " <<
Errno() << endl;
364 if ( errno == EPIPE )
371 else if ( retval == 0 )
373 WAR <<
"Not ready to write within timeout." << endl;
374 ZYPP_THROW( PluginScriptSendTimeout(
"Not ready to write within timeout." ) );
378 if ( errno != EINTR )
380 ERR <<
"select(): " <<
Errno() << endl;
394 FILE * filep = _cmd->inputFile();
398 int fd = ::fileno( filep );
405 PluginDebugBuffer _debug( data );
406 PluginDumpStderr _dump( *_cmd );
408 int ch = fgetc( filep );
411 data.push_back( ch );
415 else if ( ::feof( filep ) )
417 WAR <<
"Unexpected EOF" << endl;
420 else if ( errno != EINTR )
422 if ( errno == EWOULDBLOCK )
427 rfd.events = G_IO_IN | G_IO_HUP | G_IO_ERR;
430 int retval = g_poll( &rfd, 1, _receiveTimeout * 1000 );
435 else if ( retval == 0 )
437 WAR <<
"Not ready to read within timeout." << endl;
438 ZYPP_THROW( PluginScriptReceiveTimeout(
"Not ready to read within timeout." ) );
442 if ( errno != EINTR )
444 ERR <<
"select(): " <<
Errno() << endl;
451 ERR <<
"read(): " <<
Errno() << endl;
458 std::istringstream datas( data );
460 DBG << *
this <<
" <-" << ret << endl;
501 : _pimpl( new
Impl(
std::move(script_r) ) )
505 : _pimpl( new
Impl(
std::move(script_r),
std::move(args_r) ) )
ExternalProgramWithStderr & _prog
const std::string & _buffer
std::string asString() const
Integral type with defined initial value when default constructed.
DefaultIntegral & reset()
Reset to the defined initial value.
Convenience errno wrapper.
ExternalProgram extended to offer reading programs stderr.
Command frame for communication with PluginScript.
bool empty() const
Whether this is an empty frame.
const ByteArray & body() const
Return the frame body.
const std::string & command() const
Return the frame command.
const 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.
Interface to plugin scripts using a Stomp inspired communication protocol.
PluginFrame receive() const
Receive a PluginFrame.
std::vector< std::string > Arguments
Commandline arguments passed to a script on open.
long sendTimeout() const
Local default timeout (sec.) when sending data.
void send(const PluginFrame &frame_r) const
Send a PluginFrame.
PluginScript()
Default ctor.
std::pair< int, int > Progress
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.
Progress progress() const
Send PLUGIN_PROGRESS frame and return /ref PluginScript::Progress.
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 "> " ).
SolvableSpec & operator=(const SolvableSpec &)=default
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 SerialNumber &obj)
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
void open(const Pathname &script_r=Pathname(), const Arguments &args_r=Arguments())
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
Progress progress() const
Convenient building of std::string via std::ostringstream Basically a std::ostringstream autoconverti...
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.