12 #include <sys/types.h> 20 #include <zypp/base/LogTools.h> 21 #include <zypp-core/base/DefaultIntegral> 22 #include <zypp/base/String.h> 24 #include <zypp/base/IOStream.h> 27 #include <zypp/ExternalProgram.h> 28 #include <zypp/PathInfo.h> 32 #undef ZYPP_BASE_LOGGER_LOGGROUP 33 #define ZYPP_BASE_LOGGER_LOGGROUP "zypp::plugin" 41 const char * PLUGIN_DEBUG = getenv(
"ZYPP_PLUGIN_DEBUG" );
46 struct PluginDebugBuffer
48 PluginDebugBuffer(
const std::string & buffer_r ) :
_buffer( buffer_r ) {}
55 L_DBG(
"PLUGIN") <<
"< (empty)" << endl;
59 std::istringstream datas(
_buffer );
70 struct PluginDumpStderr
72 PluginDumpStderr( ExternalProgramWithStderr & prog_r ) :
_prog( prog_r ) {}
76 while (
_prog.stderrGetline( line ) )
77 L_WAR(
"PLUGIN") <<
"! " << line << endl;
79 ExternalProgramWithStderr &
_prog;
82 inline void setBlocking( FILE * file_r,
bool yesno_r =
true )
85 ZYPP_THROW( PluginScriptException(
"setNonBlocking" ) );
87 int fd = ::fileno( file_r );
89 ZYPP_THROW( PluginScriptException(
"setNonBlocking" ) );
91 int flags = ::fcntl( fd, F_GETFL );
93 ZYPP_THROW( PluginScriptException(
"setNonBlocking" ) );
97 else if ( flags & O_NONBLOCK )
100 flags = ::fcntl( fd, F_SETFL, flags );
102 ZYPP_THROW( PluginScriptException(
"setNonBlocking" ) );
105 inline void setNonBlocking( FILE * file_r,
bool yesno_r =
true )
106 { setBlocking( file_r, !yesno_r ); }
125 {
try {
close(); }
catch(...) {} }
145 {
return _cmd !=
nullptr; }
165 scoped_ptr<ExternalProgramWithStderr>
_cmd;
181 const long PLUGIN_TIMEOUT = str::strtonum<long>( getenv(
"ZYPP_PLUGIN_TIMEOUT" ) );
182 const long PLUGIN_SEND_TIMEOUT = str::strtonum<long>( getenv(
"ZYPP_PLUGIN_SEND_TIMEOUT" ) );
183 const long PLUGIN_RECEIVE_TIMEOUT = str::strtonum<long>( getenv(
"ZYPP_PLUGIN_RECEIVE_TIMEOUT" ) );
187 : ( PLUGIN_TIMEOUT > 0 ? PLUGIN_TIMEOUT : 30 ) );
189 : ( PLUGIN_TIMEOUT > 0 ? PLUGIN_TIMEOUT : 30 ) );
195 dumpRangeLine(
DBG <<
"Open " << script_r, args_r.begin(), args_r.end() ) << endl;
209 args.reserve( args_r.size()+1 );
211 args.insert(
args.end(), args_r.begin(), args_r.end() );
215 setNonBlocking(
_cmd->outputFile() );
216 setNonBlocking(
_cmd->inputFile() );
231 DBG <<
"Close:" << *
this << endl;
241 _lastExecError = ret.
body();
250 _lastReturn = _cmd->close();
251 _lastExecError = _cmd->execError();
253 DBG << *
this <<
" -> [" << _lastReturn <<
"] " << _lastExecError << endl;
264 if ( frame_r.
command().empty() )
265 WAR <<
"Send: No command in frame" << frame_r << endl;
270 std::ostringstream datas;
272 datas.str().swap( data );
274 DBG << *
this <<
" ->send " << frame_r << endl;
278 std::istringstream datas( data );
283 FILE * filep = _cmd->outputFile();
287 int fd = ::fileno( filep );
293 PluginDumpStderr _dump( *_cmd );
295 const char * buffer = data.c_str();
296 ssize_t buffsize = data.size();
300 watchFd.events = G_IO_OUT | G_IO_ERR;
303 int retval = g_poll( &watchFd, 1, _sendTimeout * 1000 );
307 ssize_t ret =
::write( fd, buffer, buffsize );
308 if ( ret == buffsize )
323 if ( errno != EINTR )
325 ERR <<
"write(): " <<
Errno() << endl;
326 if ( errno == EPIPE )
333 else if ( retval == 0 )
335 WAR <<
"Not ready to write within timeout." << endl;
336 ZYPP_THROW( PluginScriptSendTimeout(
"Not ready to write within timeout." ) );
340 if ( errno != EINTR )
342 ERR <<
"select(): " <<
Errno() << endl;
356 FILE * filep = _cmd->inputFile();
360 int fd = ::fileno( filep );
367 PluginDebugBuffer _debug( data );
368 PluginDumpStderr _dump( *_cmd );
370 int ch = fgetc( filep );
373 data.push_back( ch );
377 else if ( ::feof( filep ) )
379 WAR <<
"Unexpected EOF" << endl;
382 else if ( errno != EINTR )
384 if ( errno == EWOULDBLOCK )
389 rfd.events = G_IO_IN | G_IO_HUP | G_IO_ERR;
392 int retval = g_poll( &rfd, 1, _receiveTimeout * 1000 );
397 else if ( retval == 0 )
399 WAR <<
"Not ready to read within timeout." << endl;
400 ZYPP_THROW( PluginScriptReceiveTimeout(
"Not ready to read within timeout." ) );
404 if ( errno != EINTR )
406 ERR <<
"select(): " <<
Errno() << endl;
413 ERR <<
"read(): " <<
Errno() << endl;
420 std::istringstream datas( data );
422 DBG << *
this <<
" <-" << ret << endl;
463 : _pimpl( new
Impl( script_r ) )
467 : _pimpl( new
Impl( script_r, args_r ) )
Base class for PluginScript Exception.
std::ostream & writeTo(std::ostream &stream_r) const
Write frame to stream.
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
ExternalProgramWithStderr & _prog
void send(const PluginFrame &frame_r) const
Convenience errno wrapper.
Command frame for communication with PluginScript.
std::vector< std::string > Arguments
Commandline arguments passed to a script on open.
PluginScript implementation.
const std::string & command() const
Return the frame command.
ExternalProgram extended to offer reading programs stderr.
const Arguments & args() const
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.
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.
String related utilities and Regular expression matching.
PluginScript()
Default ctor.
const Pathname & script() const
Return the script path if set.
std::ostream & operator<<(std::ostream &str, const SerialNumber &obj)
std::string _lastExecError
static const pid_t NotConnected
pid_t(-1) constant indicating no connection.
PluginFrame receive() const
Receive a PluginFrame.
const Pathname & script() 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
const Arguments & args() const
Return the script arguments if set.
long receiveTimeout() const
Local default timeout (sec.) when receiving data.
static long _defaultReceiveTimeout
Convenient building of std::string via std::ostringstream Basically a std::ostringstream autoconverti...
RW_pointer< Impl > _pimpl
Pointer to implementation.
const std::string & _buffer
const std::string & asString() const
String representation.
void send(const PluginFrame &frame_r) const
Send a PluginFrame.
const std::string & body() const
Return the frame body.
const std::string & lastExecError() const
static long defaultSendTimeout()
Global default timeout (sec.) when sending data.
static long defaultReceiveTimeout()
Global default timeout (sec.) when receiving data.
pid_t getPid() const
Return a connected scripts pid or NotConnected.
TInt strtonum(const C_Str &str)
Parsing numbers from string.
long sendTimeout() const
Local default timeout (sec.) when sending data.
void open()
Setup connection and execute script.
bool isAckCommand() const
Convenience to identify an ACK command.
const std::string & lastExecError() const
Remembers a scripts execError string after close until next open.
PluginFrame receive() const
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).
Wrapper class for ::stat/::lstat.
int lastReturn() const
Remembers a scripts return value after close until next open.
Interface to plugin scripts using a Stomp inspired communication protocol.
Easy-to use interface to the ZYPP dependency resolver.
scoped_ptr< ExternalProgramWithStderr > _cmd
bool isOpen() const
Whether we are connected to a script.