Imported Upstream version 14.44.1
[platform/upstream/libzypp.git] / zypp / PluginExecutor.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/PluginExecutor.cc
10  */
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
24 ///////////////////////////////////////////////////////////////////
25 namespace zypp
26 {
27   ///////////////////////////////////////////////////////////////////
28   /// \class PluginExecutor::Impl
29   /// \brief PluginExecutor implementation.
30   ///////////////////////////////////////////////////////////////////
31   class PluginExecutor::Impl : private base::NonCopyable
32   {
33   public:
34     Impl()
35     {}
36
37     ~Impl()
38     {
39       if ( ! empty() )
40         send( PluginFrame( "PLUGINEND" ) );
41       // ~PluginScript will disconnect all remaining plugins!
42     }
43
44     bool empty() const
45     { return _scripts.empty(); }
46
47     size_t size() const
48     { return _scripts.size(); }
49
50     void load( const Pathname & path_r )
51     {
52       PathInfo pi( path_r );
53       DBG << "+++++++++++++++ load " << pi << endl;
54       if ( pi.isDir() )
55       {
56         std::list<Pathname> entries;
57         if ( filesystem::readdir( entries, pi.path(), false ) != 0 )
58         {
59           WAR << "Plugin dir is not readable: " << pi << endl;
60           return;
61         }
62         for_( it, entries.begin(), entries.end() )
63         {
64           PathInfo pii( *it );
65           if ( pii.isFile() && pii.userMayRX() )
66             doLoad( pii );
67         }
68       }
69       else if ( pi.isFile() )
70       {
71         if ( pi.userMayRX() )
72           doLoad( pi );
73         else
74           WAR << "Plugin file is not executable: " << pi << endl;
75       }
76       else
77       {
78         WAR << "Plugin path is neither dir nor file: " << pi << endl;
79       }
80       DBG << "--------------- load " << pi << endl;
81     }
82
83     void send( const PluginFrame & frame_r )
84     {
85       DBG << "+++++++++++++++ send " << frame_r << endl;
86       for ( auto it = _scripts.begin(); it != _scripts.end(); )
87       {
88         doSend( *it, frame_r );
89         if ( it->isOpen() )
90           ++it;
91         else
92           it = _scripts.erase( it );
93       }
94       DBG << "--------------- send " << frame_r << endl;
95     }
96
97     const std::list<PluginScript> scripts() const
98     { return _scripts; }
99
100   private:
101     /** Launch a plugin sending PLUGINSTART message. */
102     void doLoad( const PathInfo & pi_r )
103     {
104       MIL << "Load plugin: " << pi_r << endl;
105       try {
106         PluginScript plugin( pi_r.path() );
107         plugin.open();
108
109         PluginFrame frame( "PLUGINBEGIN" );
110         if ( ZConfig::instance().hasUserData() )
111           frame.setHeader( "userdata", ZConfig::instance().userData() );
112
113         doSend( plugin, frame );        // closes on error
114         if ( plugin.isOpen() )
115           _scripts.push_back( plugin );
116       }
117       catch( const zypp::Exception & e )
118       {
119         WAR << "Failed to load plugin " << pi_r << endl;
120       }
121     }
122
123     PluginFrame doSend( PluginScript & script_r, const PluginFrame & frame_r )
124     {
125       PluginFrame ret;
126
127       try {
128         script_r.send( frame_r );
129         ret = script_r.receive();
130       }
131       catch( const zypp::Exception & e )
132       {
133         ZYPP_CAUGHT(e);
134         WAR << e.asUserHistory() << endl;
135       }
136
137       // Allow using "/bin/cat" as reflector-script for testing
138       if ( ! ( ret.isAckCommand() || ret.isEnomethodCommand() || ( script_r.script() == "/bin/cat" && frame_r.command() != "ERROR" ) ) )
139       {
140         WAR << "Bad plugin response from " << script_r << ": " << ret << endl;
141         WAR << "(Expected " << PluginFrame::ackCommand() << " or " << PluginFrame::enomethodCommand() << ")" << endl;
142         script_r.close();
143       }
144
145       return ret;
146     }
147   private:
148     std::list<PluginScript> _scripts;
149   };
150
151   ///////////////////////////////////////////////////////////////////
152   //
153   //    CLASS NAME : PluginExecutor
154   //
155   ///////////////////////////////////////////////////////////////////
156
157   PluginExecutor::PluginExecutor()
158     : _pimpl( new Impl() )
159   {}
160
161   PluginExecutor::~PluginExecutor()
162   {}
163
164   bool PluginExecutor::empty() const
165   { return _pimpl->empty(); }
166
167   size_t PluginExecutor::size() const
168   { return _pimpl->size(); }
169
170   void PluginExecutor::load( const Pathname & path_r )
171   { _pimpl->load( path_r ); }
172
173   void PluginExecutor::send( const PluginFrame & frame_r )
174   { _pimpl->send( frame_r ); }
175
176   std::ostream & operator<<( std::ostream & str, const PluginExecutor & obj )
177   { return str << obj._pimpl->scripts(); }
178
179 } // namespace zypp
180 ///////////////////////////////////////////////////////////////////