12 #include <sys/types.h>
30 #undef ZYPP_BASE_LOGGER_LOGGROUP
31 #define ZYPP_BASE_LOGGER_LOGGROUP "zypp::plugin"
39 const char * PLUGIN_DEBUG = getenv(
"ZYPP_PLUGIN_DEBUG" );
44 struct PluginDebugBuffer
46 PluginDebugBuffer(
const std::string & buffer_r ) :
_buffer( buffer_r ) {}
53 L_DBG(
"PLUGIN") <<
"< (empty)" << endl;
57 std::istringstream datas(
_buffer );
68 struct PluginDumpStderr
70 PluginDumpStderr( ExternalProgramWithStderr & prog_r ) :
_prog( prog_r ) {}
74 while (
_prog.stderrGetline( line ) )
75 L_WAR(
"PLUGIN") <<
"! " << line << endl;
77 ExternalProgramWithStderr &
_prog;
80 inline void setBlocking( FILE * file_r,
bool yesno_r =
true )
83 ZYPP_THROW( PluginScriptException(
"setNonBlocking" ) );
85 int fd = ::fileno( file_r );
87 ZYPP_THROW( PluginScriptException(
"setNonBlocking" ) );
89 int flags = ::fcntl( fd, F_GETFL );
91 ZYPP_THROW( PluginScriptException(
"setNonBlocking" ) );
95 else if ( flags & O_NONBLOCK )
98 flags = ::fcntl( fd, F_SETFL, flags );
100 ZYPP_THROW( PluginScriptException(
"setNonBlocking" ) );
103 inline void setNonBlocking( FILE * file_r,
bool yesno_r =
true )
104 { setBlocking( file_r, !yesno_r ); }
123 {
try {
close(); }
catch(...) {} }
143 {
return _cmd !=
nullptr; }
163 scoped_ptr<ExternalProgramWithStderr>
_cmd;
172 return str <<
"PluginScript[" << obj.
getPid() <<
"] " << obj.
script();
179 const long PLUGIN_TIMEOUT = str::strtonum<long>( getenv(
"ZYPP_PLUGIN_TIMEOUT" ) );
180 const long PLUGIN_SEND_TIMEOUT = str::strtonum<long>( getenv(
"ZYPP_PLUGIN_SEND_TIMEOUT" ) );
181 const long PLUGIN_RECEIVE_TIMEOUT = str::strtonum<long>( getenv(
"ZYPP_PLUGIN_RECEIVE_TIMEOUT" ) );
185 : ( PLUGIN_TIMEOUT > 0 ? PLUGIN_TIMEOUT : 30 ) );
187 : ( PLUGIN_TIMEOUT > 0 ? PLUGIN_TIMEOUT : 30 ) );
193 dumpRangeLine(
DBG <<
"Open " << script_r, args_r.begin(), args_r.end() ) << endl;
199 PathInfo pi( script_r );
200 if ( ! ( pi.isFile() && pi.isX() ) )
207 args.reserve( args_r.size()+1 );
208 args.push_back( script_r.asString() );
209 args.insert( args.end(), args_r.begin(), args_r.end() );
213 setNonBlocking(
_cmd->outputFile() );
214 setNonBlocking(
_cmd->inputFile() );
229 DBG <<
"Close:" << *
this << endl;
239 _lastExecError = ret.
body();
248 _lastReturn = _cmd->close();
249 _lastExecError = _cmd->execError();
251 DBG << *
this <<
" -> [" << _lastReturn <<
"] " << _lastExecError << endl;
262 if ( frame_r.
command().empty() )
263 WAR <<
"Send: No command in frame" << frame_r << endl;
268 std::ostringstream datas;
270 datas.str().swap( data );
272 DBG << *
this <<
" ->send " << frame_r << endl;
276 std::istringstream datas( data );
281 FILE * filep = _cmd->outputFile();
285 int fd = ::fileno( filep );
291 PluginDumpStderr _dump( *_cmd );
293 const char * buffer = data.c_str();
294 ssize_t buffsize = data.size();
301 tv.tv_sec = _sendTimeout;
304 int retval = select( fd+1, NULL, &wfds, NULL, &tv );
308 ssize_t ret =
::write( fd, buffer, buffsize );
309 if ( ret == buffsize )
324 if ( errno != EINTR )
326 ERR <<
"write(): " <<
Errno() << endl;
327 if ( errno == EPIPE )
334 else if ( retval == 0 )
336 WAR <<
"Not ready to write within timeout." << endl;
337 ZYPP_THROW( PluginScriptSendTimeout(
"Not ready to write within timeout." ) );
341 if ( errno != EINTR )
343 ERR <<
"select(): " <<
Errno() << endl;
357 FILE * filep = _cmd->inputFile();
361 int fd = ::fileno( filep );
368 PluginDebugBuffer _debug( data );
369 PluginDumpStderr _dump( *_cmd );
371 int ch = fgetc( filep );
374 data.push_back( ch );
378 else if ( ::feof( filep ) )
380 WAR <<
"Unexpected EOF" << endl;
383 else if ( errno != EINTR )
385 if ( errno == EWOULDBLOCK )
393 tv.tv_sec = _receiveTimeout;
396 int retval = select( fd+1, &rfds, NULL, NULL, &tv );
401 else if ( retval == 0 )
403 WAR <<
"Not ready to read within timeout." << endl;
404 ZYPP_THROW( PluginScriptReceiveTimeout(
"Not ready to read within timeout." ) );
408 if ( errno != EINTR )
410 ERR <<
"select(): " <<
Errno() << endl;
417 ERR <<
"read(): " <<
Errno() << endl;
424 std::istringstream datas( data );
426 DBG << *
this <<
" <-" << ret << endl;
467 : _pimpl( new
Impl( script_r ) )
471 : _pimpl( new
Impl( script_r, args_r ) )
513 {
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 "> " ).
DefaultIntegral & reset()
Reset to the defined initial value.
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::ostringstream Basically a std::ostringstream autoconverti...
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
TInt strtonum(const C_Str &str)
Parsing numbers from string.
void open()
Setup connection and execute script.
PluginFrame receive() const
Receive a PluginFrame.
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.
std::ostream & dumpRangeLine(std::ostream &str, TIterator begin, TIterator end)
Print range defined by iterators (single line style).
std::ostream & writeTo(std::ostream &stream_r) const
Write frame to stream.
Interface to plugin 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.