libzypp  17.35.8
PluginExecutor.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
11 #include <iostream>
12 #include <zypp/base/LogTools.h>
13 #include <zypp/base/NonCopyable.h>
14 
15 #include <zypp/ZConfig.h>
16 #include <zypp/PathInfo.h>
17 #include <zypp/PluginExecutor.h>
18 
19 using std::endl;
20 
21 #undef ZYPP_BASE_LOGGER_LOGGROUP
22 #define ZYPP_BASE_LOGGER_LOGGROUP "zypp::plugin"
23 
25 namespace zypp
26 {
32  {
33  public:
34  Impl()
35  {}
36 
37  Impl(const Impl &) = delete;
38  Impl(Impl &&) = delete;
39  Impl &operator=(const Impl &) = delete;
40  Impl &operator=(Impl &&) = delete;
41 
42  ~Impl() {
43  if ( ! empty() )
44  send( PluginFrame( "PLUGINEND" ) );
45  // ~PluginScript will disconnect all remaining plugins!
46  }
47 
48  bool empty() const
49  { return _scripts.empty(); }
50 
51  size_t size() const
52  { return _scripts.size(); }
53 
54  void load( const Pathname & path_r )
55  {
56  PathInfo pi( path_r );
57  DBG << "+++++++++++++++ load " << pi << endl;
58  if ( pi.isDir() )
59  {
60  std::list<Pathname> entries;
61  if ( filesystem::readdir( entries, pi.path(), false ) != 0 )
62  {
63  WAR << "Plugin dir is not readable: " << pi << endl;
64  return;
65  }
66  for_( it, entries.begin(), entries.end() )
67  {
68  PathInfo pii( *it );
69  if ( pii.isFile() && pii.userMayRX() )
70  doLoad( pii );
71  }
72  }
73  else if ( pi.isFile() )
74  {
75  if ( pi.userMayRX() )
76  doLoad( pi );
77  else
78  WAR << "Plugin file is not executable: " << pi << endl;
79  }
80  else
81  {
82  WAR << "Plugin path is neither dir nor file: " << pi << endl;
83  }
84  DBG << "--------------- load " << pi << endl;
85  }
86 
87  void send( const PluginFrame & frame_r )
88  {
89  DBG << "+++++++++++++++ send " << frame_r << endl;
90  for ( auto it = _scripts.begin(); it != _scripts.end(); )
91  {
92  doSend( *it, frame_r );
93  if ( it->isOpen() )
94  ++it;
95  else
96  it = _scripts.erase( it );
97  }
98  DBG << "--------------- send " << frame_r << endl;
99  }
100 
101  const std::list<PluginScript> scripts() const
102  { return _scripts; }
103 
104  private:
106  void doLoad( const PathInfo & pi_r )
107  {
108  MIL << "Load plugin: " << pi_r << endl;
109  try {
110  PluginScript plugin( pi_r.path() );
111  plugin.open();
112 
113  PluginFrame frame( "PLUGINBEGIN" );
114  if ( ZConfig::instance().hasUserData() )
115  frame.setHeader( "userdata", ZConfig::instance().userData() );
116 
117  doSend( plugin, frame ); // closes on error
118  if ( plugin.isOpen() )
119  _scripts.push_back( plugin );
120  }
121  catch( const zypp::Exception & e )
122  {
123  WAR << "Failed to load plugin " << pi_r << endl;
124  }
125  }
126 
127  PluginFrame doSend( PluginScript & script_r, const PluginFrame & frame_r )
128  {
129  PluginFrame ret;
130 
131  try {
132  script_r.send( frame_r );
133  ret = script_r.receive();
134  }
135  catch( const zypp::Exception & e )
136  {
137  ZYPP_CAUGHT(e);
138  WAR << e.asUserHistory() << endl;
139  }
140 
141  // Allow using "/bin/cat" as reflector-script for testing
142  if ( ! ( ret.isAckCommand() || ret.isEnomethodCommand() || ( script_r.script() == "/bin/cat" && frame_r.command() != "ERROR" ) ) )
143  {
144  WAR << "Bad plugin response from " << script_r << ": " << ret << endl;
145  WAR << "(Expected " << PluginFrame::ackCommand() << " or " << PluginFrame::enomethodCommand() << ")" << endl;
146  script_r.close();
147  }
148 
149  return ret;
150  }
151  private:
152  std::list<PluginScript> _scripts;
153  };
154 
156  //
157  // CLASS NAME : PluginExecutor
158  //
160 
162  : _pimpl( new Impl() )
163  {}
164 
166  {}
167 
169  { return _pimpl->empty(); }
170 
171  size_t PluginExecutor::size() const
172  { return _pimpl->size(); }
173 
174  void PluginExecutor::load( const Pathname & path_r )
175  { _pimpl->load( path_r ); }
176 
177  void PluginExecutor::send( const PluginFrame & frame_r )
178  { _pimpl->send( frame_r ); }
179 
180  std::ostream & operator<<( std::ostream & str, const PluginExecutor & obj )
181  { return str << obj._pimpl->scripts(); }
182 
183 } // namespace zypp
PluginExecutor()
Default ctor: Empty plugin list.
Impl & operator=(const Impl &)=delete
#define MIL
Definition: Logger.h:98
const Pathname & path() const
Return current Pathname.
Definition: PathInfo.h:247
size_t size() const
Number of open plugins.
static ZConfig & instance()
Singleton ctor.
Definition: ZConfig.cc:925
Command frame for communication with PluginScript.
Definition: PluginFrame.h:41
const std::string & command() const
Return the frame command.
Definition: PluginFrame.cc:427
#define for_(IT, BEG, END)
Convenient for-loops using iterator.
Definition: Easy.h:28
Parallel execution of stateful PluginScripts.
String related utilities and Regular expression matching.
const Pathname & script() const
Return the script path if set.
std::ostream & operator<<(std::ostream &str, const SerialNumber &obj)
Definition: SerialNumber.cc:52
PluginFrame receive() const
Receive a PluginFrame.
bool empty() const
Whether no plugins are waiting.
PluginFrame doSend(PluginScript &script_r, const PluginFrame &frame_r)
~PluginExecutor()
Dtor: Send PLUGINEND and close all plugins.
bool isEnomethodCommand() const
Convenience to identify an _ENOMETHOD command.
Definition: PluginFrame.h:122
std::list< PluginScript > _scripts
static const std::string & enomethodCommand()
"_ENOMETHOD" command.
Definition: PluginFrame.cc:384
void send(const PluginFrame &frame_r)
Send PluginFrame to all open plugins.
void send(const PluginFrame &frame_r) const
Send a PluginFrame.
std::string asUserHistory() const
A single (multiline) string composed of asUserString and historyAsString.
Definition: Exception.cc:127
void load(const Pathname &path_r)
#define WAR
Definition: Logger.h:99
void send(const PluginFrame &frame_r)
static const std::string & ackCommand()
"ACK" command.
Definition: PluginFrame.cc:372
void open()
Setup connection and execute script.
int readdir(std::list< std::string > &retlist_r, const Pathname &path_r, bool dots_r)
Return content of directory via retlist.
Definition: PathInfo.cc:610
bool isAckCommand() const
Convenience to identify an ACK command.
Definition: PluginFrame.h:114
bool userMayRX() const
Definition: PathInfo.h:351
#define ZYPP_CAUGHT(EXCPT)
Drops a logline telling the Exception was caught (in order to handle it).
Definition: Exception.h:440
RW_pointer< Impl > _pimpl
Implementation class.
int close()
Close any open connection.
Base class for Exception.
Definition: Exception.h:146
void load(const Pathname &path_r)
Find and launch plugins sending PLUGINBEGIN.
PluginExecutor implementation.
void doLoad(const PathInfo &pi_r)
Launch a plugin sending PLUGINSTART message.
Wrapper class for ::stat/::lstat.
Definition: PathInfo.h:221
void setHeader(const std::string &key_r, const std::string &value_r=std::string())
Set header for key_r removing all other occurrences of key_r.
Definition: PluginFrame.cc:466
Interface to plugin scripts using a Stomp inspired communication protocol.
Definition: PluginScript.h:62
Easy-to use interface to the ZYPP dependency resolver.
Definition: Application.cc:19
const std::list< PluginScript > scripts() const
#define DBG
Definition: Logger.h:97
boost::noncopyable NonCopyable
Ensure derived classes cannot be copied.
Definition: NonCopyable.h:26