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;
91 auto str = str::Str();
93 while (
_prog.stderrGetline( line ) ) {
94 L_WAR(
"PLUGIN") <<
"! " << line << endl;
103 inline void setBlocking(
FILE * file_r,
bool yesno_r =
true )
106 ZYPP_THROW( PluginScriptException(
"setNonBlocking" ) );
108 int fd = ::fileno( file_r );
110 ZYPP_THROW( PluginScriptException(
"setNonBlocking" ) );
112 int flags = ::fcntl( fd, F_GETFL );
114 ZYPP_THROW( PluginScriptException(
"setNonBlocking" ) );
118 else if ( flags & O_NONBLOCK )
121 flags = ::fcntl( fd, F_SETFL, flags );
123 ZYPP_THROW( PluginScriptException(
"setNonBlocking" ) );
126 inline void setNonBlocking(
FILE * file_r,
bool yesno_r =
true )
127 { setBlocking( file_r, !yesno_r ); }
178 {
return _cmd !=
nullptr; }
198 scoped_ptr<ExternalProgramWithStderr>
_cmd;
214 const long PLUGIN_TIMEOUT = str::strtonum<long>( getenv(
"ZYPP_PLUGIN_TIMEOUT" ) );
215 const long PLUGIN_SEND_TIMEOUT = str::strtonum<long>( getenv(
"ZYPP_PLUGIN_SEND_TIMEOUT" ) );
216 const long PLUGIN_RECEIVE_TIMEOUT = str::strtonum<long>( getenv(
"ZYPP_PLUGIN_RECEIVE_TIMEOUT" ) );
220 : ( PLUGIN_TIMEOUT > 0 ? PLUGIN_TIMEOUT : 30 ) );
222 : ( PLUGIN_TIMEOUT > 0 ? PLUGIN_TIMEOUT : 30 ) );
242 args.reserve( args_r.size()+1 );
244 args.insert(
args.end(), args_r.begin(), args_r.end() );
247 if ( not
_cmd->running() ) {
248 const std::string execError(
_cmd->execError() );
254 setNonBlocking(
_cmd->outputFile() );
255 setNonBlocking(
_cmd->inputFile() );
270 DBG <<
"Close:" << *
this << endl;
272 if ( _cmd->running() ) {
290 _lastReturn = _cmd->close();
291 _lastExecError = _cmd->execError();
293 DBG << *
this <<
" -> [" << _lastReturn <<
"] " << _lastExecError << endl;
304 if ( frame_r.
command().empty() )
305 WAR <<
"Send: No command in frame" << frame_r << endl;
310 std::ostringstream datas;
312 datas.str().swap( data );
314 DBG << *
this <<
" ->send " << frame_r << endl;
318 std::istringstream datas( data );
323 FILE * filep = _cmd->outputFile();
327 int fd = ::fileno( filep );
333 PluginDumpStderr _dump( *_cmd );
335 const char * buffer = data.c_str();
336 ssize_t buffsize = data.size();
340 watchFd.events = G_IO_OUT | G_IO_ERR;
344 int retval = g_poll( &watchFd, 1, _sendTimeout * 1000 );
348 ssize_t ret =
::write( fd, buffer, buffsize );
349 if ( ret == buffsize )
364 if ( errno != EINTR )
366 ERR <<
"write(): " <<
Errno() << endl;
367 if ( errno == EPIPE )
368 ZYPP_THROW( PluginScriptDiedUnexpectedly(
"Send: script died unexpectedly", _dump.take() ) );
374 else if ( retval == 0 )
376 WAR <<
"Not ready to write within timeout." << endl;
377 ZYPP_THROW( PluginScriptSendTimeout(
"Not ready to write within timeout." ) );
381 if ( errno != EINTR )
383 ERR <<
"select(): " <<
Errno() << endl;
397 FILE * filep = _cmd->inputFile();
401 int fd = ::fileno( filep );
408 PluginDebugBuffer _debug( data );
409 PluginDumpStderr _dump( *_cmd );
411 int ch = fgetc( filep );
414 data.push_back( ch );
418 else if ( ::feof( filep ) )
420 WAR <<
"Unexpected EOF" << endl;
421 ZYPP_THROW( PluginScriptDiedUnexpectedly(
"Receive: script died unexpectedly", _dump.take() ) );
423 else if ( errno != EINTR )
425 if ( errno == EWOULDBLOCK )
430 rfd.events = G_IO_IN | G_IO_HUP | G_IO_ERR;
433 int retval = g_poll( &rfd, 1, _receiveTimeout * 1000 );
438 else if ( retval == 0 )
440 WAR <<
"Not ready to read within timeout." << endl;
441 ZYPP_THROW( PluginScriptReceiveTimeout(
"Not ready to read within timeout." ) );
445 if ( errno != EINTR )
447 ERR <<
"select(): " <<
Errno() << endl;
454 ERR <<
"read(): " <<
Errno() << endl;
461 std::istringstream datas( data );
463 DBG << *
this <<
" <-" << ret << endl;
504 : _pimpl( new
Impl(
std::move(script_r) ) )
508 : _pimpl( new
Impl(
std::move(script_r),
std::move(args_r) ) )
545 {
_pimpl->
open( script_r, args_r, chroot_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 "> " ).
static std::string showRootIf(const Pathname &root_r, const Pathname &path_r)
String representation as "(root)/path", unless root is "/" or empty.
std::string asString() const
DefaultIntegral & reset()
Reset to the defined initial value.
String related utilities and Regular expression matching.
PluginScript()
Default ctor.
const Pathname & script() const
Return the script path if set.
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
static long _defaultSendTimeout
void open(const Pathname &script_r=Pathname(), const Arguments &args_r=Arguments(), const Pathname &root_r=Pathname())
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.
Pathname getChroot() const
Return a connected scripts chroot or an empty Pathname.
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.
Pathname getChroot() const
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::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.
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.
std::ostream & operator<<(std::ostream &str, const Capabilities &obj)
relates: Capabilities Stream output
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.
std::string sprint(Args &&... args)
Print words as string.
scoped_ptr< ExternalProgramWithStderr > _cmd
bool isOpen() const
Whether we are connected to a script.
void openChrooted(const Pathname &chroot_r)
Like open() but runs the script chrooted into chroot_r.