libzypp 17.37.17
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
16
17#include <zypp/Globals.h>
18#include <zypp/PathInfo.h>
19#include <zypp/ZYppCallbacks.h>
21#include <zypp/base/LogTools.h>
22#include <zypp/base/WatchFile.h>
23using std::endl;
24
26namespace 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
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..
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...
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(" << obj.plugindir() << ", " << obj.isNeeded() << ")"; }
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
269
271 : _pimpl( new Impl( std::move(plugindir_r), std::move(chroot_r) ) )
272 {}
273
276
277
279 { return _pimpl->isNeeded(); }
280
282 { return _pimpl->checkIfNeeded(); }
283
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
308
310 { _pimpl->_parent->verifyWorkflow( file_r, _pimpl ); }
311
312
313 } // namespace repo
314
315} // namespace zypp
316
void addHistory(const std::string &msg_r)
Add some message text to the history.
Definition Exception.cc:189
Execute a program and give access to its io An object of this class encapsulates the execution of an ...
int close() override
Wait for the progamm to complete.
std::vector< std::string > Arguments
bool kill()
Kill the program.
pid_t getpid()
return pid
bool running()
Return whether program is running.
What is known about a repository.
Definition RepoInfo.h:72
Remember a files attributes to detect content changes.
Definition watchfile.h:50
bool set(const std::string &key_r, AnyType val_r)
Set the value for key (nonconst version always returns true).
Definition UserData.h:119
bool haskey(const std::string &key_r) const
Whether key_r is in data.
Definition UserData.h:98
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:226
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
const std::string & asString() const
String representation.
Definition Pathname.h:93
std::string alias() const
unique identifier for this source.
Impl(RW_pointer< PluginRepoverification::Impl > parent_r, Pathname &&sigpathLocal_r, Pathname &&keypathLocal_r, RepoInfo &&repo_r)
FileChecker checking all repoverification plugins.
void operator()(const Pathname &file_r) const
Check the downloaded master index file.
RW_pointer< Impl > _pimpl
Pointer to implementation (ref).
void pluginVerify(std::string plugin_r, const Pathname &file_r, const PluginRepoverification::Checker::Impl &data_r) const
friend std::ostream & operator<<(std::ostream &str, const Impl &obj)
Impl(Pathname &&plugindir_r, Pathname &&chroot_r)
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.
bool isNeeded() const
Whether the last checkIfNeeded found plugins to execute at all.
bool checkIfNeeded()
Checks whether there are plugins to execute at all.
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.
RW_pointer< Impl > _pimpl
Implementation class.
PluginRepoverificationCheckException ExceptionType
Definition Arch.h:364
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
std::pair< ReceiveUpToResult, std::string > receiveUpto(FILE *file, char c, timeout_type timeout, bool failOnUnblockError)
Definition IOTools.cc:85
@ Timeout
Definition IOTools.h:72
@ Success
Definition IOTools.h:71
@ Error
Definition IOTools.h:74
@ EndOfFile
Definition IOTools.h:73
static constexpr timeout_type no_timeout
Definition IOTools.h:78
size_t timeout_type
Definition IOTools.h:77
std::ostream & operator<<(std::ostream &str, const DeltaCandidates &obj)
bool operator==(const RepoType &obj1, const RepoType &obj2)
Definition RepoType.h:62
std::string numstring(char n, int w=0)
Definition String.h:290
Easy-to use interface to the ZYPP dependency resolver.
std::ostream & dumpOn(std::ostream &str, const Capability &obj)
Wrapper for const correct access via Smart pointer types.
Definition PtrTypes.h:293
JobReport convenience sending this instance of UserData with each message.
bool data(const std::string &msg_r)
bool debug(const std::string &msg_r)
Convenient building of std::string with boost::format.
Definition String.h:254
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:459
#define DBG
Definition Logger.h:99
#define WAR
Definition Logger.h:101
#define INT
Definition Logger.h:104