12 #include <sys/types.h>
36 const char * PLUGIN_DEBUG = getenv(
"ZYPP_PLUGIN_DEBUG" );
41 struct PluginDebugBuffer
43 PluginDebugBuffer(
const std::string & buffer_r ) :
_buffer( buffer_r ) {}
50 _DBG(
"PLUGIN") <<
"< (empty)" << endl;
54 std::istringstream datas(
_buffer );
65 struct PluginDumpStderr
67 PluginDumpStderr( ExternalProgramWithStderr & prog_r ) :
_prog( prog_r ) {}
71 while (
_prog.stderrGetline( line ) )
72 _WAR(
"PLUGIN") <<
"! " << line << endl;
74 ExternalProgramWithStderr &
_prog;
77 inline void setBlocking( FILE * file_r,
bool yesno_r =
true )
80 ZYPP_THROW( PluginScriptException(
"setNonBlocking" ) );
82 int fd = ::fileno( file_r );
84 ZYPP_THROW( PluginScriptException(
"setNonBlocking" ) );
86 int flags = ::fcntl( fd, F_GETFL );
88 ZYPP_THROW( PluginScriptException(
"setNonBlocking" ) );
92 else if ( flags & O_NONBLOCK )
95 flags = ::fcntl( fd, F_SETFL, flags );
97 ZYPP_THROW( PluginScriptException(
"setNonBlocking" ) );
100 inline void setNonBlocking( FILE * file_r,
bool yesno_r =
true )
101 { setBlocking( file_r, !yesno_r ); }
120 {
try {
close(); }
catch(...) {} }
140 {
return _cmd !=
nullptr; }
160 scoped_ptr<ExternalProgramWithStderr>
_cmd;
170 obj.
args().begin(), obj.
args().end() );
177 const long PLUGIN_TIMEOUT = str::strtonum<long>( getenv(
"ZYPP_PLUGIN_TIMEOUT" ) );
178 const long PLUGIN_SEND_TIMEOUT = str::strtonum<long>( getenv(
"ZYPP_PLUGIN_SEND_TIMEOUT" ) );
179 const long PLUGIN_RECEIVE_TIMEOUT = str::strtonum<long>( getenv(
"ZYPP_PLUGIN_RECEIVE_TIMEOUT" ) );
183 : ( PLUGIN_TIMEOUT > 0 ? PLUGIN_TIMEOUT : 30 ) );
185 : ( PLUGIN_TIMEOUT > 0 ? PLUGIN_TIMEOUT : 30 ) );
191 dumpRangeLine(
DBG <<
"Open " << script_r, args_r.begin(), args_r.end() ) << endl;
197 PathInfo pi( script_r );
198 if ( ! ( pi.isFile() && pi.isX() ) )
205 args.reserve( args_r.size()+1 );
206 args.push_back( script_r.asString() );
207 args.insert( args.end(), args_r.begin(), args_r.end() );
211 setNonBlocking(
_cmd->outputFile() );
212 setNonBlocking(
_cmd->inputFile() );
220 DBG << *
this << endl;
227 DBG <<
"Close:" << *
this << endl;
237 _lastExecError = ret.
body();
246 _lastReturn = _cmd->close();
247 _lastExecError = _cmd->execError();
249 DBG << *
this <<
" -> [" << _lastReturn <<
"] " << _lastExecError << endl;
260 if ( frame_r.
command().empty() )
261 WAR <<
"Send: No command in frame" << frame_r << endl;
266 std::ostringstream datas;
268 datas.str().swap( data );
270 DBG <<
"->send " << frame_r << endl;
274 std::istringstream datas( data );
279 FILE * filep = _cmd->outputFile();
283 int fd = ::fileno( filep );
289 PluginDumpStderr _dump( *_cmd );
291 const char * buffer = data.c_str();
292 ssize_t buffsize = data.size();
299 tv.tv_sec = _sendTimeout;
302 int retval = select( fd+1, NULL, &wfds, NULL, &tv );
306 ssize_t ret =
::write( fd, buffer, buffsize );
307 if ( ret == buffsize )
322 if ( errno != EINTR )
324 ERR <<
"write(): " <<
Errno() << endl;
325 if ( errno == EPIPE )
332 else if ( retval == 0 )
334 WAR <<
"Not ready to write within timeout." << endl;
335 ZYPP_THROW( PluginScriptSendTimeout(
"Not ready to write within timeout." ) );
339 if ( errno != EINTR )
341 ERR <<
"select(): " <<
Errno() << endl;
355 FILE * filep = _cmd->inputFile();
359 int fd = ::fileno( filep );
366 PluginDebugBuffer _debug( data );
367 PluginDumpStderr _dump( *_cmd );
369 int ch = fgetc( filep );
372 data.push_back( ch );
376 else if ( ::feof( filep ) )
378 WAR <<
"Unexpected EOF" << endl;
381 else if ( errno != EINTR )
383 if ( errno == EWOULDBLOCK )
391 tv.tv_sec = _receiveTimeout;
394 int retval = select( fd+1, &rfds, NULL, NULL, &tv );
399 else if ( retval == 0 )
401 WAR <<
"Not ready to read within timeout." << endl;
402 ZYPP_THROW( PluginScriptReceiveTimeout(
"Not ready to read within timeout." ) );
406 if ( errno != EINTR )
408 ERR <<
"select(): " <<
Errno() << endl;
415 ERR <<
"read(): " <<
Errno() << endl;
422 std::istringstream datas( data );
424 DBG <<
"<-" << ret << endl;
449 {
return _pimpl->_sendTimeout; }
452 {
return _pimpl->_receiveTimeout; }
455 {
_pimpl->_sendTimeout = newval_r > 0 ? newval_r : 0; }
458 {
_pimpl->_receiveTimeout = newval_r > 0 ? newval_r : 0; }
465 : _pimpl( new
Impl( script_r ) )
469 : _pimpl( new
Impl( script_r, args_r ) )
473 {
return _pimpl->script(); }
476 {
return _pimpl->args(); }
479 {
return _pimpl->isOpen(); }
482 {
return _pimpl->getPid(); }
485 {
return _pimpl->lastReturn(); }
488 {
return _pimpl->lastExecError(); }
494 {
_pimpl->open( script_r ); }
497 {
_pimpl->open( script_r, args_r ); }
500 {
return _pimpl->close(); }
503 {
_pimpl->send( frame_r ); }
506 {
return _pimpl->receive(); }
511 {
return str << *obj.
_pimpl; }
Base class for PluginScript Exception.
const Arguments & args() const
Return the script arguments if set.
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
ExternalProgramWithStderr & _prog
Convenience errno wrapper.
Command frame for communication with PluginScript.
std::vector< std::string > Arguments
Commandline arguments passed to a script on open.
PluginFrame receive() const
long sendTimeout() const
Local default timeout (sec.) when sending data.
pid_t getPid() const
Return a connected scripts pid or NotConnected.
const Arguments & args() const
const std::string & command() const
Return the frame command.
PluginScript implementation.
ExternalProgram extended to offer reading programs stderr.
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 "> " ).
PluginScript()
Default ctor.
std::string _lastExecError
static const pid_t NotConnected
pid_t(-1) constant indicating no connection.
const std::string & lastExecError() const
void open(const Pathname &script_r=Pathname(), const Arguments &args_r=Arguments())
bool write(const Pathname &path_r, const std::string &key_r, const std::string &val_r, const std::string &newcomment_r)
Add or change a value in sysconfig file path_r.
static long _defaultSendTimeout
int lastReturn() const
Remembers a scripts return value after close until next open.
static long _defaultReceiveTimeout
Convenient building of std::string via std::ostream::operator<<.
RW_pointer< Impl > _pimpl
Pointer to implementation.
std::ostream & operator<<(std::ostream &str, const Exception &obj)
const std::string & _buffer
const Pathname & script() const
Return the script path if set.
static long defaultSendTimeout()
Global default timeout (sec.) when sending data.
long receiveTimeout() const
Local default timeout (sec.) when receiving data.
bool isAckCommand() const
Convenience to identify an ACK command.
static long defaultReceiveTimeout()
Global default timeout (sec.) when receiving data.
void send(const PluginFrame &frame_r) const
void open()
Setup connection and execute script.
_It strtonum(const C_Str &str)
Parsing numbers from string.
PluginFrame receive() const
Receive a PluginFrame.
std::ostream & dumpRangeLine(std::ostream &str, _Iterator begin, _Iterator end)
Print range defined by iterators (single line style).
const Pathname & script() const
bool isOpen() const
Whether we are connected to a script.
const std::string & lastExecError() const
Remembers a scripts execError string after close until next open.
DefaultIntegral< int, 0 > _lastReturn
Impl(const Pathname &script_r=Pathname(), const Arguments &args_r=Arguments())
int close()
Close any open connection.
Exception safe signal handler save/restore.
DefaultIntegral & reset()
Reset to the defined initial value.
std::ostream & writeTo(std::ostream &stream_r) const
Write frame to stream.
Interface to pluigin scripts using a Stomp inspired communication protocol.
void send(const PluginFrame &frame_r) const
Send a PluginFrame.
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.
scoped_ptr< ExternalProgramWithStderr > _cmd
const std::string & body() const
Return the frame body.