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;
259 _lastExecError = ret.
body();
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;
321 int retval = g_poll( &watchFd, 1, _sendTimeout * 1000 );
325 ssize_t ret =
::write( fd, buffer, buffsize );
326 if ( ret == buffsize )
341 if ( errno != EINTR )
343 ERR <<
"write(): " <<
Errno() << endl;
344 if ( errno == EPIPE )
351 else if ( retval == 0 )
353 WAR <<
"Not ready to write within timeout." << endl;
354 ZYPP_THROW( PluginScriptSendTimeout(
"Not ready to write within timeout." ) );
358 if ( errno != EINTR )
360 ERR <<
"select(): " <<
Errno() << endl;
374 FILE * filep = _cmd->inputFile();
378 int fd = ::fileno( filep );
385 PluginDebugBuffer _debug( data );
386 PluginDumpStderr _dump( *_cmd );
388 int ch = fgetc( filep );
391 data.push_back( ch );
395 else if ( ::feof( filep ) )
397 WAR <<
"Unexpected EOF" << endl;
400 else if ( errno != EINTR )
402 if ( errno == EWOULDBLOCK )
407 rfd.events = G_IO_IN | G_IO_HUP | G_IO_ERR;
410 int retval = g_poll( &rfd, 1, _receiveTimeout * 1000 );
415 else if ( retval == 0 )
417 WAR <<
"Not ready to read within timeout." << endl;
418 ZYPP_THROW( PluginScriptReceiveTimeout(
"Not ready to read within timeout." ) );
422 if ( errno != EINTR )
424 ERR <<
"select(): " <<
Errno() << endl;
431 ERR <<
"read(): " <<
Errno() << endl;
438 std::istringstream datas( data );
440 DBG << *
this <<
" <-" << ret << endl;
481 : _pimpl( new
Impl(
std::move(script_r) ) )
485 : _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 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())
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 & 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.
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.