libzypp  17.35.12
PluginRepoverification.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
11 #include <iostream>
12 #include <sstream>
13 #include <utility>
14 
15 #include "PluginRepoverification.h"
16 
17 #include <zypp/Globals.h>
18 #include <zypp/PathInfo.h>
19 #include <zypp/ZYppCallbacks.h>
20 #include <zypp/ExternalProgram.h>
21 #include <zypp/base/LogTools.h>
22 #include <zypp/base/WatchFile.h>
23 using std::endl;
24 
26 namespace zypp_private
27 {
28  using namespace zypp;
30  namespace repo
31  {
32 
33  struct Monitor
34  {
36  using Callback = std::function<bool(std::optional<std::string>)>;
37 
39  : _timeout { timeout_r }
40  {}
41 
42  int operator()( ExternalProgram & prog_r, Callback cb_r = Callback() )
43  {
44  std::string line;
45  bool goOn = true;
46  prog_r.setBlocking( false );
47  FILE * inputfile = prog_r.inputFile();
48  do {
49  const auto &readResult = io::receiveUpto( inputfile, '\n', _timeout );
50  line += readResult.second; // we always may have received a partial line
51  goOn = true;
52  switch ( readResult.first ) {
53 
55  goOn = reportLine( line, cb_r );
56  line.clear(); // in case the CB did not move it out
57  break;
58 
60  goOn = reportTimeout( cb_r );
61  break;
62 
65  reportFinalLineUnlessEmpty( line, cb_r );
66  line.clear(); // in case the CB did not move it out
67  goOn = false;
68  break;
69  }
70  } while ( goOn );
71 
72  if ( prog_r.running() ) {
73  WAR << "ABORT by callback: pid " << prog_r.getpid() << endl;
74  prog_r.kill();
75  }
76  return prog_r.close();
77  }
78 
79  private:
80  bool reportLine( std::string & line_r, Callback & cb_r )
81  {
82  if ( cb_r ) {
83  if ( not line_r.empty() && line_r.back() == '\n' )
84  line_r.pop_back();
85  return cb_r( std::move(line_r) );
86  }
87  return true;
88  }
89  bool reportTimeout( Callback & cb_r )
90  {
91  return cb_r ? cb_r( std::nullopt ) : true;
92  }
93  bool reportFinalLineUnlessEmpty( std::string & line_r, Callback & cb_r )
94  {
95  if ( cb_r && not line_r.empty() ) // implies an incomplete line (no NL)
96  cb_r( std::move(line_r) );
97  return false;
98  }
99  private:
101  };
102 
108  {
109  public:
111  Pathname &&sigpathLocal_r, Pathname &&keypathLocal_r, RepoInfo &&repo_r )
112  : _parent { std::move( parent_r ) }
113  , _sigpathLocal { std::move(sigpathLocal_r) }
114  , _keypathLocal { std::move(keypathLocal_r) }
115  , _repoinfo { std::move(repo_r) }
116  {}
117 
119  Pathname _sigpathLocal;
120  Pathname _keypathLocal;
122  };
123 
129  {
130  friend std::ostream & operator<<( std::ostream & str, const Impl & obj );
131  friend std::ostream & dumpOn( std::ostream & str, const Impl & obj );
132 
133  public:
135  {}
136 
137  Impl(const Impl &) = delete;
138  Impl(Impl &&) = delete;
139  Impl &operator=(const Impl &) = delete;
140  Impl &operator=(Impl &&) = delete;
141 
142  Impl(Pathname &&plugindir_r, Pathname &&chroot_r)
143  : _watchPlugindir{std::move(plugindir_r), WatchFile::NO_INIT},
144  _chroot{std::move(chroot_r)} {}
145 
147  {}
148 
149  bool isNeeded() const
150  { return _isNeeded; }
151 
153  {
154  if ( _watchPlugindir.hasChanged() ) {
155  _isNeeded = false;
156  // check for at least one executable plugin inside..
157  filesystem::dirForEach( plugindir(),
158  [this]( const Pathname & dir_r, const char *const name_r ) -> bool {
159  PathInfo pi ( dir_r/name_r );
160  if ( pi.isFile() && pi.userMayRX() ) {
161  this->_isNeeded = true;
162  return false;
163  }
164  return true;
165  } );
166  }
167  return _isNeeded;
168  }
169 
171  {
172  // Execute the plugins. They will throw if something is wrong...
173  filesystem::dirForEach( plugindir(),
174  [&,this]( const Pathname & dir_r, const char *const name_r ) -> bool {
175  PathInfo pi ( dir_r/name_r );
176  if ( pi.isFile() && pi.userMayRX() )
177  this->pluginVerify( name_r, file_r, *datap_r );
178  return true;
179  } );
180  }
181 
182  private:
183  void pluginVerify( std::string plugin_r, const Pathname & file_r, const PluginRepoverification::Checker::Impl & data_r ) const
184  {
185  Pathname pluginPath { plugindir()/plugin_r };
186  if ( not _chroot.emptyOrRoot() ) {
187  pluginPath = Pathname::stripprefix( _chroot, pluginPath );
188  // we need to make sure the files are available inside the chroot
189  INT << "chroot PluginRepoverification does not yet work." << endl;
190  return;
191  }
192 
194  args.push_back( pluginPath.asString() );
196  args.push_back( "--file" );
197  args.push_back( file_r.asString() );
198  args.push_back( "--fsig" );
199  args.push_back( data_r._sigpathLocal.asString() );
200  args.push_back( "--fkey" );
201  args.push_back( data_r._keypathLocal.asString() );
202  args.push_back( "--ralias" );
203  args.push_back( data_r._repoinfo.alias() );
204  ExternalProgram cmd { args, ExternalProgram::Stderr_To_Stdout, false, -1, false, _chroot };
205 
206  // draft: maybe integrate jobReport into Monitor
207  Monitor monitor( 800 );
208  UserDataJobReport jobReport { "cmdout", "monitor" };
209  jobReport.set( "CmdId", unsigned(cmd.getpid()) );
210  jobReport.set( "CmdTag", str::numstring( cmd.getpid() ) );
211  jobReport.set( "CmdName", "Repoverification plugin "+plugin_r );
212  jobReport.set( "RepoInfo", data_r._repoinfo );
213 
214  std::optional<std::ostringstream> buffer; // Send output in exception is no one is listening
215  jobReport.debug( "?" ); // someone listening?
216  if ( not jobReport.haskey( "!" ) ) // no
217  buffer = std::ostringstream();
218 
219  int ret = monitor( cmd, [&jobReport,&buffer,&cmd]( std::optional<std::string> line_r )->bool {
220  if ( line_r ) {
221  DBG << "["<<cmd.getpid()<<"> " << *line_r << endl;
222  if ( buffer ) (*buffer) << *line_r << endl;
223  return jobReport.data( *line_r );
224  }
225  else {
226  return jobReport.debug( "ping" );
227  }
228  return true;
229  } );
230 
231  if ( ret ) {
232  const std::string & msg { str::Format( "Metadata rejected by '%1%' plugin (returned %2%)" ) % plugin_r % ret };
233 
234  ExceptionType excp { msg };
235  if ( buffer ) excp.addHistory( buffer->str() );
236  excp.addHistory( str::Format( "%1%%2% returned %3%" ) % (_chroot.emptyOrRoot()?"":"("+_chroot.asString()+")") % pluginPath % ret );
237 
238  ZYPP_THROW( excp );
239  }
240  }
241 
242  const Pathname & plugindir() const
243  { return _watchPlugindir.path(); }
244 
245  private:
248  bool _isNeeded = false;
249  };
250 
252  inline std::ostream & operator<<( std::ostream & str, const PluginRepoverification::Impl & obj )
253  { return str << "PluginRepoverification::Impl"; }
254 
256  inline std::ostream & dumpOn( std::ostream & str, const PluginRepoverification::Impl & obj )
257  { return str << obj; }
258 
259 
261  //
262  // CLASS NAME : PluginRepoverification
263  //
265 
266  PluginRepoverification::PluginRepoverification()
267  : _pimpl( new Impl )
268  {}
269 
270  PluginRepoverification::PluginRepoverification( Pathname plugindir_r, Pathname chroot_r )
271  : _pimpl( new Impl( std::move(plugindir_r), std::move(chroot_r) ) )
272  {}
273 
275  {}
276 
277 
279  { return _pimpl->isNeeded(); }
280 
282  { return _pimpl->checkIfNeeded(); }
283 
284  PluginRepoverification::Checker PluginRepoverification::getChecker( Pathname sigpathLocal_r, Pathname keypathLocal_r, RepoInfo repo_r ) const
285  { return Checker( new Checker::Impl( _pimpl, std::move(sigpathLocal_r), std::move(keypathLocal_r), std::move(repo_r) ) ); }
286 
287 
288  std::ostream & operator<<( std::ostream & str, const PluginRepoverification & obj )
289  { return str << *obj._pimpl; }
290 
291  std::ostream & dumpOn( std::ostream & str, const PluginRepoverification & obj )
292  { return dumpOn( str, *obj._pimpl ); }
293 
295  { return lhs._pimpl == rhs._pimpl; }
296 
298  //
299  // CLASS NAME : PluginRepoverification::Checker
300  //
303  : _pimpl { pimpl_r }
304  {}
305 
307  {}
308 
309  void PluginRepoverification::Checker::operator()( const Pathname & file_r ) const
310  { _pimpl->_parent->verifyWorkflow( file_r, _pimpl ); }
311 
312 
313  } // namespace repo
315 } // namespace zypp
void verifyWorkflow(const Pathname &file_r, RW_pointer< PluginRepoverification::Checker::Impl > datap_r) const
JobReport convenience sending this instance of UserData with each message.
Repository metadata verification beyond GPG.
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:424
bool kill()
Kill the program.
#define INT
Definition: Logger.h:102
bool reportFinalLineUnlessEmpty(std::string &line_r, Callback &cb_r)
int dirForEach(const Pathname &dir_r, const StrMatcher &matcher_r, function< bool(const Pathname &, const char *const)> fnc_r)
Definition: PathInfo.cc:32
int operator()(ExternalProgram &prog_r, Callback cb_r=Callback())
void addHistory(const std::string &msg_r)
Add some message text to the history.
Definition: Exception.cc:176
String related utilities and Regular expression matching.
Definition: Arch.h:363
What is known about a repository.
Definition: RepoInfo.h:71
Impl(Pathname &&plugindir_r, Pathname &&chroot_r)
bool running()
Return whether program is running.
Convenient building of std::string with boost::format.
Definition: String.h:252
bool isNeeded() const
Whether the last checkIfNeeded found plugins to execute at all.
bool reportLine(std::string &line_r, Callback &cb_r)
Remember a files attributes to detect content changes.
Definition: watchfile.h:49
void pluginVerify(std::string plugin_r, const Pathname &file_r, const PluginRepoverification::Checker::Impl &data_r) const
std::ostream & dumpOn(std::ostream &str, const PluginRepoverification::Impl &obj)
size_t timeout_type
Definition: IOTools.h:77
Execute a program and give access to its io An object of this class encapsulates the execution of an ...
bool set(const std::string &key_r, AnyType val_r)
Set the value for key (nonconst version always returns true).
Definition: UserData.h:119
const std::string & asString() const
String representation.
Definition: Pathname.h:93
std::string alias() const
unique identifier for this source.
void operator()(const Pathname &file_r) const
Check the downloaded master index file.
#define WAR
Definition: Logger.h:99
int close() override
Wait for the progamm to complete.
std::vector< std::string > Arguments
std::string numstring(char n, int w=0)
Definition: String.h:289
std::ostream & operator<<(std::ostream &str, const zypp::sat::detail::CDataiterator *obj)
Definition: LookupAttr.cc:808
bool operator==(const PluginRepoverification &lhs, const PluginRepoverification &rhs)
bool userMayRX() const
Definition: PathInfo.h:351
Impl(RW_pointer< PluginRepoverification::Impl > parent_r, Pathname &&sigpathLocal_r, Pathname &&keypathLocal_r, RepoInfo &&repo_r)
FileChecker checking all repoverification plugins.
std::function< bool(std::optional< std::string >)> Callback
Report a line of output (without trailing NL) otherwise a life ping on timeout.
std::pair< ReceiveUpToResult, std::string > receiveUpto(FILE *file, char c, timeout_type timeout, bool failOnUnblockError)
Definition: IOTools.cc:85
constexpr std::string_view FILE("file")
std::ostream & operator<<(std::ostream &str, const PluginRepoverification &obj)
Monitor(io::timeout_type timeout_r=io::no_timeout)
Exceptiontype thrown if a plugins verification fails.
Wrapper for const correct access via Smart pointer types.
Definition: PtrTypes.h:292
RW_pointer< Impl > _pimpl
Implementation class.
Wrapper class for ::stat/::lstat.
Definition: PathInfo.h:221
void setBlocking(bool mode)
Set the blocking mode of the input stream.
static constexpr timeout_type no_timeout
Definition: IOTools.h:78
std::ostream & operator<<(std::ostream &str, const PluginRepoverification::Impl &obj)
pid_t getpid()
return pid
FILE * inputFile() const
Return the input stream.
PluginRepoverification::Checker data storage.
Checker getChecker(Pathname sigpathLocal_r, Pathname keypathLocal_r, RepoInfo repo_r) const
FileChecker factory remembering the location of the master index files GPG signature and key...
Easy-to use interface to the ZYPP dependency resolver.
Definition: Application.cc:19
static Pathname stripprefix(const Pathname &root_r, const Pathname &path_r)
Return path_r with any root_r dir prefix striped.
Definition: Pathname.cc:281
std::ostream & dumpOn(std::ostream &str, const PluginRepoverification &obj)
#define DBG
Definition: Logger.h:97
bool checkIfNeeded()
Checks whether there are plugins to execute at all.