12 #include <sys/types.h> 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; }
183 scoped_ptr<ExternalProgramWithStderr>
_cmd;
199 const long PLUGIN_TIMEOUT = str::strtonum<long>( getenv(
"ZYPP_PLUGIN_TIMEOUT" ) );
200 const long PLUGIN_SEND_TIMEOUT = str::strtonum<long>( getenv(
"ZYPP_PLUGIN_SEND_TIMEOUT" ) );
201 const long PLUGIN_RECEIVE_TIMEOUT = str::strtonum<long>( getenv(
"ZYPP_PLUGIN_RECEIVE_TIMEOUT" ) );
205 : ( PLUGIN_TIMEOUT > 0 ? PLUGIN_TIMEOUT : 30 ) );
207 : ( PLUGIN_TIMEOUT > 0 ? PLUGIN_TIMEOUT : 30 ) );
213 dumpRangeLine(
DBG <<
"Open " << script_r, args_r.begin(), args_r.end() ) << endl;
227 args.reserve( args_r.size()+1 );
229 args.insert(
args.end(), args_r.begin(), args_r.end() );
233 setNonBlocking(
_cmd->outputFile() );
234 setNonBlocking(
_cmd->inputFile() );
249 DBG <<
"Close:" << *
this << endl;
268 _lastReturn = _cmd->close();
269 _lastExecError = _cmd->execError();
271 DBG << *
this <<
" -> [" << _lastReturn <<
"] " << _lastExecError << endl;
282 if ( frame_r.
command().empty() )
283 WAR <<
"Send: No command in frame" << frame_r << endl;
288 std::ostringstream datas;
290 datas.str().swap( data );
292 DBG << *
this <<
" ->send " << frame_r << endl;
296 std::istringstream datas( data );
301 FILE * filep = _cmd->outputFile();
305 int fd = ::fileno( filep );
311 PluginDumpStderr _dump( *_cmd );
313 const char * buffer = data.c_str();
314 ssize_t buffsize = data.size();
318 watchFd.events = G_IO_OUT | G_IO_ERR;
322 int retval = g_poll( &watchFd, 1, _sendTimeout * 1000 );
326 ssize_t ret =
::write( fd, buffer, buffsize );
327 if ( ret == buffsize )
342 if ( errno != EINTR )
344 ERR <<
"write(): " <<
Errno() << endl;
345 if ( errno == EPIPE )
352 else if ( retval == 0 )
354 WAR <<
"Not ready to write within timeout." << endl;
355 ZYPP_THROW( PluginScriptSendTimeout(
"Not ready to write within timeout." ) );
359 if ( errno != EINTR )
361 ERR <<
"select(): " <<
Errno() << endl;
375 FILE * filep = _cmd->inputFile();
379 int fd = ::fileno( filep );
386 PluginDebugBuffer _debug( data );
387 PluginDumpStderr _dump( *_cmd );
389 int ch = fgetc( filep );
392 data.push_back( ch );
396 else if ( ::feof( filep ) )
398 WAR <<
"Unexpected EOF" << endl;
401 else if ( errno != EINTR )
403 if ( errno == EWOULDBLOCK )
408 rfd.events = G_IO_IN | G_IO_HUP | G_IO_ERR;
411 int retval = g_poll( &rfd, 1, _receiveTimeout * 1000 );
416 else if ( retval == 0 )
418 WAR <<
"Not ready to read within timeout." << endl;
419 ZYPP_THROW( PluginScriptReceiveTimeout(
"Not ready to read within timeout." ) );
423 if ( errno != EINTR )
425 ERR <<
"select(): " <<
Errno() << endl;
432 ERR <<
"read(): " <<
Errno() << endl;
439 std::istringstream datas( data );
441 DBG << *
this <<
" <-" << ret << endl;
482 : _pimpl( new
Impl(
std::move(script_r) ) )
486 : _pimpl( new
Impl(
std::move(script_r),
std::move(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.
PluginScript implementation.
const std::string & command() const
Return the frame command.
ExternalProgram extended to offer reading programs stderr.
const ByteArray & body() const
Return the frame body.
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 "> " ).
std::string asString() const
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())
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
Impl & operator=(const Impl &)=delete
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 & 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.
Impl(Pathname &&script_r=Pathname(), Arguments &&args_r=Arguments())
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
std::vector< std::string > Arguments
Commandline arguments passed to a script on open.
DefaultIntegral< int, 0 > _lastReturn
constexpr std::string_view FILE("file")
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.
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.
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.