libzypp  17.31.0
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 
14 #include "PluginRepoverification.h"
15 
16 #include <zypp/Globals.h>
17 #include <zypp/PathInfo.h>
18 #include <zypp/ZYppCallbacks.h>
19 #include <zypp/ExternalProgram.h>
20 #include <zypp/base/LogTools.h>
21 #include <zypp/base/WatchFile.h>
22 using std::endl;
23 
25 namespace zypp_private
26 {
27  using namespace zypp;
29  namespace repo
30  {
31 
32  struct Monitor
33  {
35  using Callback = std::function<bool(std::optional<std::string>)>;
36 
38  : _timeout { timeout_r }
39  {}
40 
41  int operator()( ExternalProgram & prog_r, Callback cb_r = Callback() )
42  {
43  std::string line;
44  bool goOn = true;
45  prog_r.setBlocking( false );
46  FILE * inputfile = prog_r.inputFile();
47  do {
48  const auto &readResult = io::receiveUpto( inputfile, '\n', _timeout );
49  line += readResult.second; // we always may have received a partial line
50  goOn = true;
51  switch ( readResult.first ) {
52 
54  goOn = reportLine( line, cb_r );
55  line.clear(); // in case the CB did not move it out
56  break;
57 
59  goOn = reportTimeout( cb_r );
60  break;
61 
64  reportFinalLineUnlessEmpty( line, cb_r );
65  line.clear(); // in case the CB did not move it out
66  goOn = false;
67  break;
68  }
69  } while ( goOn );
70 
71  if ( prog_r.running() ) {
72  WAR << "ABORT by callback: pid " << prog_r.getpid() << endl;
73  prog_r.kill();
74  }
75  return prog_r.close();
76  }
77 
78  private:
79  bool reportLine( std::string & line_r, Callback & cb_r )
80  {
81  if ( cb_r ) {
82  if ( not line_r.empty() && line_r.back() == '\n' )
83  line_r.pop_back();
84  return cb_r( std::move(line_r) );
85  }
86  return true;
87  }
88  bool reportTimeout( Callback & cb_r )
89  {
90  return cb_r ? cb_r( std::nullopt ) : true;
91  }
92  bool reportFinalLineUnlessEmpty( std::string & line_r, Callback & cb_r )
93  {
94  if ( cb_r && not line_r.empty() ) // implies an incomplete line (no NL)
95  cb_r( std::move(line_r) );
96  return false;
97  }
98  private:
100  };
101 
107  {
108  public:
110  Pathname sigpathLocal_r, Pathname keypathLocal_r, const RepoInfo & repo_r )
111  : _parent { parent_r }
112  , _sigpathLocal { std::move(sigpathLocal_r) }
113  , _keypathLocal { std::move(keypathLocal_r) }
114  , _repoinfo { repo_r }
115  {}
116 
118  Pathname _sigpathLocal;
119  Pathname _keypathLocal;
121  };
122 
128  {
129  friend std::ostream & operator<<( std::ostream & str, const Impl & obj );
130  friend std::ostream & dumpOn( std::ostream & str, const Impl & obj );
131 
132  public:
134  {}
135 
136  Impl( Pathname plugindir_r, Pathname chroot_r )
137  : _watchPlugindir { std::move(plugindir_r), WatchFile::NO_INIT }
138  , _chroot { std::move(chroot_r) }
139  {}
140 
142  {}
143 
144  bool isNeeded() const
145  { return _isNeeded; }
146 
148  {
149  if ( _watchPlugindir.hasChanged() ) {
150  _isNeeded = false;
151  // check for at least one executable plugin inside..
153  [this]( const Pathname & dir_r, const char *const name_r ) -> bool {
154  PathInfo pi ( dir_r/name_r );
155  if ( pi.isFile() && pi.userMayRX() ) {
156  this->_isNeeded = true;
157  return false;
158  }
159  return true;
160  } );
161  }
162  return _isNeeded;
163  }
164 
166  {
167  // Execute the plugins. They will throw if something is wrong...
169  [&,this]( const Pathname & dir_r, const char *const name_r ) -> bool {
170  PathInfo pi ( dir_r/name_r );
171  if ( pi.isFile() && pi.userMayRX() )
172  this->pluginVerify( name_r, file_r, *datap_r );
173  return true;
174  } );
175  }
176 
177  private:
178  void pluginVerify( std::string plugin_r, const Pathname & file_r, const PluginRepoverification::Checker::Impl & data_r ) const
179  {
180  Pathname pluginPath { plugindir()/plugin_r };
181  if ( not _chroot.emptyOrRoot() ) {
182  pluginPath = Pathname::stripprefix( _chroot, pluginPath );
183  // we need to make sure the files are available inside the chroot
184  INT << "chroot PluginRepoverification does not yet work." << endl;
185  return;
186  }
187 
189  args.push_back( pluginPath.asString() );
191  args.push_back( "--file" );
192  args.push_back( file_r.asString() );
193  args.push_back( "--fsig" );
194  args.push_back( data_r._sigpathLocal.asString() );
195  args.push_back( "--fkey" );
196  args.push_back( data_r._keypathLocal.asString() );
197  args.push_back( "--ralias" );
198  args.push_back( data_r._repoinfo.alias() );
199  ExternalProgram cmd { args, ExternalProgram::Stderr_To_Stdout, false, -1, false, _chroot };
200 
201  // draft: maybe integrate jobReport into Monitor
202  Monitor monitor( 800 );
203  UserDataJobReport jobReport { "cmdout", "monitor" };
204  jobReport.set( "CmdId", unsigned(cmd.getpid()) );
205  jobReport.set( "CmdTag", str::numstring( cmd.getpid() ) );
206  jobReport.set( "CmdName", "Repoverification plugin "+plugin_r );
207  jobReport.set( "RepoInfo", data_r._repoinfo );
208 
209  std::optional<std::ostringstream> buffer; // Send output in exception is no one is listening
210  jobReport.debug( "?" ); // someone listening?
211  if ( not jobReport.haskey( "!" ) ) // no
212  buffer = std::ostringstream();
213 
214  int ret = monitor( cmd, [&jobReport,&buffer,&cmd]( std::optional<std::string> line_r )->bool {
215  if ( line_r ) {
216  DBG << "["<<cmd.getpid()<<"> " << *line_r << endl;
217  if ( buffer ) (*buffer) << *line_r << endl;
218  return jobReport.data( *line_r );
219  }
220  else {
221  return jobReport.debug( "ping" );
222  }
223  return true;
224  } );
225 
226  if ( ret ) {
227  const std::string & msg { str::Format( "Metadata rejected by '%1%' plugin (returned %2%)" ) % plugin_r % ret };
228 
229  ExceptionType excp { msg };
230  if ( buffer ) excp.addHistory( buffer->str() );
231  excp.addHistory( str::Format( "%1%%2% returned %3%" ) % (_chroot.emptyOrRoot()?"":"("+_chroot.asString()+")") % pluginPath % ret );
232 
233  ZYPP_THROW( std::move(excp) );
234  }
235  }
236 
237  const Pathname & plugindir() const
238  { return _watchPlugindir.path(); }
239 
240  private:
243  bool _isNeeded = false;
244  };
245 
247  inline std::ostream & operator<<( std::ostream & str, const PluginRepoverification::Impl & obj )
248  { return str << "PluginRepoverification::Impl"; }
249 
251  inline std::ostream & dumpOn( std::ostream & str, const PluginRepoverification::Impl & obj )
252  { return str << obj; }
253 
254 
256  //
257  // CLASS NAME : PluginRepoverification
258  //
260 
262  : _pimpl( new Impl )
263  {}
264 
265  PluginRepoverification::PluginRepoverification( Pathname plugindir_r, Pathname chroot_r )
266  : _pimpl( new Impl( std::move(plugindir_r), std::move(chroot_r) ) )
267  {}
268 
270  {}
271 
272 
274  { return _pimpl->isNeeded(); }
275 
277  { return _pimpl->checkIfNeeded(); }
278 
279  PluginRepoverification::Checker PluginRepoverification::getChecker( const Pathname & sigpathLocal_r, const Pathname & keypathLocal_r,
280  const RepoInfo & repo_r ) const
281  { return Checker( new Checker::Impl( _pimpl, sigpathLocal_r, keypathLocal_r, repo_r ) ); }
282 
283 
284  std::ostream & operator<<( std::ostream & str, const PluginRepoverification & obj )
285  { return str << *obj._pimpl; }
286 
287  std::ostream & dumpOn( std::ostream & str, const PluginRepoverification & obj )
288  { return dumpOn( str, *obj._pimpl ); }
289 
291  { return lhs._pimpl == rhs._pimpl; }
292 
294  //
295  // CLASS NAME : PluginRepoverification::Checker
296  //
299  : _pimpl { pimpl_r }
300  {}
301 
303  {}
304 
305  void PluginRepoverification::Checker::operator()( const Pathname & file_r ) const
306  { _pimpl->_parent->verifyWorkflow( file_r, _pimpl ); }
307 
308 
309  } // namespace repo
311 } // namespace zypp
Impl(Pathname plugindir_r, Pathname chroot_r)
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:428
bool kill()
Kill the program.
bool hasChanged()
Definition: watchfile.h:80
#define INT
Definition: Logger.h:100
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())
String related utilities and Regular expression matching.
Checker getChecker(const Pathname &sigpathLocal_r, const Pathname &keypathLocal_r, const RepoInfo &repo_r) const
FileChecker factory remembering the location of the master index files GPG signature and key...
Definition: Arch.h:351
What is known about a repository.
Definition: RepoInfo.h:71
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
std::vector< std::string > Arguments
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)
bool emptyOrRoot() const
Test for "" or "/".
Definition: Pathname.h:121
friend std::ostream & operator<<(std::ostream &str, const Impl &obj)
Impl(RW_pointer< PluginRepoverification::Impl > parent_r, Pathname sigpathLocal_r, Pathname keypathLocal_r, const RepoInfo &repo_r)
size_t timeout_type
Definition: IOTools.h:76
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:118
const std::string & asString() const
String representation.
Definition: Pathname.h:91
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:97
std::string numstring(char n, int w=0)
Definition: String.h:289
friend std::ostream & dumpOn(std::ostream &str, const Impl &obj)
bool operator==(const PluginRepoverification &lhs, const PluginRepoverification &rhs)
bool userMayRX() const
Definition: PathInfo.h:350
int close()
Wait for the progamm to complete.
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
std::ostream & operator<<(std::ostream &str, const PluginRepoverification &obj)
const Pathname & path() const
Definition: watchfile.h:65
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:285
RW_pointer< Impl > _pimpl
Implementation class.
Wrapper class for ::stat/::lstat.
Definition: PathInfo.h:220
void setBlocking(bool mode)
Set the blocking mode of the input stream.
std::ostream & operator<<(std::ostream &str, const PluginRepoverification::Impl &obj)
pid_t getpid()
return pid
FILE * inputFile() const
Return the input stream.
static const timeout_type no_timeout
Definition: IOTools.h:77
PluginRepoverification::Checker data storage.
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc:1
static Pathname stripprefix(const Pathname &root_r, const Pathname &path_r)
Return path_r with any root_r dir prefix striped.
Definition: Pathname.cc:280
std::ostream & dumpOn(std::ostream &str, const PluginRepoverification &obj)
#define DBG
Definition: Logger.h:95
bool checkIfNeeded()
Checks whether there are plugins to execute at all.