libzypp 17.38.7
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-core/Globals.h>
18#include <zypp/PathInfo.h>
19#include <zypp/ZYppCallbacks.h>
22#include <zypp-core/fs/WatchFile>
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
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition Exception.h:459
Provides API related macros.
#define DBG
Definition Logger.h:102
#define WAR
Definition Logger.h:104
#define INT
Definition Logger.h:107
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:94
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)
relates: PluginRepoverification::Impl Stream output
Impl(Pathname &&plugindir_r, Pathname &&chroot_r)
void verifyWorkflow(const Pathname &file_r, RW_pointer< PluginRepoverification::Checker::Impl > datap_r) const
friend std::ostream & dumpOn(std::ostream &str, const Impl &obj)
relates: PluginRepoverification::Impl 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 ansi.h:855
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::Impl &obj)
relates: DeltaCandidates::Impl Stream output
bool operator==(const RepoInfoBase &lhs, const RepoInfoBase &rhs)
relates: RepoInfoBase
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)
relates: Capability Detailed stream output
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.