libzypp 17.31.1
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
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>
22using std::endl;
23
25namespace 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
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
Execute a program and give access to its io An object of this class encapsulates the execution of an ...
std::vector< std::string > Arguments
bool kill()
Kill the program.
pid_t getpid()
return pid
bool running()
Return whether program is running.
int close()
Wait for the progamm to complete.
What is known about a repository.
Definition: RepoInfo.h:72
Remember a files attributes to detect content changes.
Definition: watchfile.h:50
bool hasChanged()
Definition: watchfile.h:80
const Pathname & path() const
Definition: watchfile.h:65
bool set(const std::string &key_r, AnyType val_r)
Set the value for key (nonconst version always returns true).
Definition: UserData.h:118
void setBlocking(bool mode)
Set the blocking mode of the input stream.
FILE * inputFile() const
Return the input stream.
Wrapper class for ::stat/::lstat.
Definition: PathInfo.h:221
bool userMayRX() const
Definition: PathInfo.h:350
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
bool emptyOrRoot() const
Test for "" or "/".
Definition: Pathname.h:121
const std::string & asString() const
String representation.
Definition: Pathname.h:91
std::string alias() const
unique identifier for this source.
Exceptiontype thrown if a plugins verification fails.
Impl(RW_pointer< PluginRepoverification::Impl > parent_r, Pathname sigpathLocal_r, Pathname keypathLocal_r, const RepoInfo &repo_r)
FileChecker checking all repoverification plugins.
void operator()(const Pathname &file_r) const
Check the downloaded master index file.
void pluginVerify(std::string plugin_r, const Pathname &file_r, const PluginRepoverification::Checker::Impl &data_r) const
Impl(Pathname plugindir_r, Pathname chroot_r)
friend std::ostream & operator<<(std::ostream &str, const Impl &obj)
std::ostream & operator<<(std::ostream &str, const PluginRepoverification::Impl &obj)
Stream output.
void verifyWorkflow(const Pathname &file_r, RW_pointer< PluginRepoverification::Checker::Impl > datap_r) const
friend std::ostream & dumpOn(std::ostream &str, const Impl &obj)
std::ostream & dumpOn(std::ostream &str, const PluginRepoverification::Impl &obj)
Verbose stream output.
Repository metadata verification beyond GPG.
bool isNeeded() const
Whether the last checkIfNeeded found plugins to execute at all.
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.
bool checkIfNeeded()
Checks whether there are plugins to execute at all.
RW_pointer< Impl > _pimpl
Implementation class.
Definition: Arch.h:352
String related utilities and Regular expression matching.
int dirForEach(const Pathname &dir_r, const StrMatcher &matcher_r, function< bool(const Pathname &, const char *const)> fnc_r)
Definition: PathInfo.cc:32
static const timeout_type no_timeout
Definition: IOTools.h:77
std::pair< ReceiveUpToResult, std::string > receiveUpto(FILE *file, char c, timeout_type timeout, bool failOnUnblockError)
Definition: IOTools.cc:85
@ Timeout
Definition: IOTools.h:71
@ Success
Definition: IOTools.h:70
@ Error
Definition: IOTools.h:73
@ EndOfFile
Definition: IOTools.h:72
size_t timeout_type
Definition: IOTools.h:76
std::string numstring(char n, int w=0)
Definition: String.h:289
bool operator==(const PluginRepoverification &lhs, const PluginRepoverification &rhs)
std::ostream & operator<<(std::ostream &str, const PluginRepoverification &obj)
std::ostream & dumpOn(std::ostream &str, const PluginRepoverification &obj)
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc:2
Wrapper for const correct access via Smart pointer types.
Definition: PtrTypes.h:286
JobReport convenience sending this instance of UserData with each message.
Convenient building of std::string with boost::format.
Definition: String.h:253
bool reportFinalLineUnlessEmpty(std::string &line_r, Callback &cb_r)
Monitor(io::timeout_type timeout_r=io::no_timeout)
int operator()(ExternalProgram &prog_r, Callback cb_r=Callback())
bool reportLine(std::string &line_r, Callback &cb_r)
std::function< bool(std::optional< std::string >)> Callback
Report a line of output (without trailing NL) otherwise a life ping on timeout.
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:428
#define DBG
Definition: Logger.h:95
#define WAR
Definition: Logger.h:97
#define INT
Definition: Logger.h:100