libzypp  15.3.0
PackageProvider.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
12 #include <iostream>
13 #include <fstream>
14 #include <sstream>
15 #include "zypp/repo/PackageDelta.h"
16 #include "zypp/base/Logger.h"
17 #include "zypp/base/Gettext.h"
19 #include "zypp/base/NonCopyable.h"
22 #include "zypp/repo/PackageDelta.h"
23 
24 #include "zypp/TmpPath.h"
25 #include "zypp/ZConfig.h"
26 #include "zypp/RepoInfo.h"
27 #include "zypp/RepoManager.h"
28 
29 #include "zypp/ZYppFactory.h"
30 #include "zypp/Target.h"
31 #include "zypp/target/rpm/RpmDb.h"
32 #include "zypp/FileChecker.h"
33 
34 using std::endl;
35 
37 namespace zypp
38 {
40  namespace repo
41  {
43  // class PackageProviderPolicy
45 
46  bool PackageProviderPolicy::queryInstalled( const std::string & name_r,
47  const Edition & ed_r,
48  const Arch & arch_r ) const
49  {
50  if ( _queryInstalledCB )
51  return _queryInstalledCB( name_r, ed_r, arch_r );
52  return false;
53  }
54 
55 
61  {
63  public:
65  Impl( RepoMediaAccess & access_r,
66  const Package::constPtr & package_r,
67  const DeltaCandidates & deltas_r,
68  const PackageProviderPolicy & policy_r )
69  : _policy( policy_r )
70  , _package( package_r )
71  , _deltas( deltas_r )
72  , _access( access_r )
73  , _retry(false)
74  {}
75 
76  virtual ~Impl() {}
77 
82  static Impl * factoryMake( RepoMediaAccess & access_r,
83  const Package::constPtr & package_r,
84  const DeltaCandidates & deltas_r,
85  const PackageProviderPolicy & policy_r );
86 
87  public:
93 
96  {
98  if ( ! ( ret->empty() || _package->repoInfo().keepPackages() ) )
100  return ret;
101  }
102 
104  bool isCached() const
105  { return ! doProvidePackageFromCache()->empty(); }
106 
107  protected:
110 
121  virtual ManagedFile doProvidePackageFromCache() const = 0;
122 
140  virtual ManagedFile doProvidePackage() const = 0;
141 
142  protected:
144  Report & report() const
145  { return *_report; }
146 
148  bool progressPackageDownload( int value ) const
149  { return report()->progress( value, _package ); }
150 
152  bool failOnChecksumError() const
153  {
154  std::string package_str = _package->name() + "-" + _package->edition().asString();
155 
156  // TranslatorExplanation %s = package being checked for integrity
157  switch ( report()->problem( _package, repo::DownloadResolvableReport::INVALID, str::form(_("Package %s seems to be corrupted during transfer. Do you want to retry retrieval?"), package_str.c_str() ) ) )
158  {
160  _retry = true;
161  break;
163  ZYPP_THROW(SkipRequestException("User requested skip of corrupted file"));
164  break;
166  ZYPP_THROW(AbortRequestException("User requested to abort"));
167  break;
168  default:
169  break;
170  }
171  return true; // anyway a failure
172  }
173 
175 
176  RpmDb::CheckPackageResult packageSigCheck( const Pathname & path_r, UserData & userData ) const
177  {
178  if ( !_target )
179  _target = getZYpp()->getTarget();
180 
183  if ( _target )
184  ret = _target->rpmDb().checkPackage( path_r, detail );
185  else
186  detail.push_back( RpmDb::CheckPackageDetail::value_type( ret, "OOps. Target is not initialized!" ) );
187 
188  userData.set( "CheckPackageResult", ret );
189  userData.set( "CheckPackageDetail", std::move(detail) );
190  return ret;
191  }
192 
195  {
196  // TranslatorExplanation %s = package being checked for integrity
197  switch ( action_r )
198  {
200  _retry = true;
201  break;
203  WAR << _package->asUserString() << ": " << "User requested skip of insecure file" << endl;
204  break;
205  default:
207  ZYPP_THROW(AbortRequestException("User requested to abort"));
208  break;
209  }
210  }
211 
214  {
215  std::string msg( str::Str() << _package->asUserString() << ": " << _("Signature verification failed") << " " << ret );
217  }
218 
219  protected:
224 
225  private:
226  typedef shared_ptr<void> ScopedGuard;
227 
228  ScopedGuard newReport() const
229  {
230  _report.reset( new Report );
231  // Use a custom deleter calling _report.reset() when guard goes out of
232  // scope (cast required as reset is overloaded). We want report to end
233  // when leaving providePackage and not wait for *this going out of scope.
234  return shared_ptr<void>( static_cast<void*>(0),
235  bind( mem_fun_ref( static_cast<void (shared_ptr<Report>::*)()>(&shared_ptr<Report>::reset) ),
236  ref(_report) ) );
237  }
238 
239  mutable bool _retry;
240  mutable shared_ptr<Report> _report;
241  mutable Target_Ptr _target;
242  };
244 
247  { return ManagedFile(); }
248 
251  {
252  ManagedFile ret;
253  OnMediaLocation loc = _package->location();
254 
255  ProvideFilePolicy policy;
256  policy.progressCB( bind( &Base::progressPackageDownload, this, _1 ) );
257  policy.failOnChecksumErrorCB( bind( &Base::failOnChecksumError, this ) );
258  return _access.provideFile( _package->repoInfo(), loc, policy );
259  }
260 
262 
264  {
265  ScopedGuard guardReport( newReport() );
266 
267  // check for cache hit:
269  if ( ! ret->empty() )
270  {
271  MIL << "provided Package from cache " << _package << " at " << ret << endl;
272  report()->infoInCache( _package, ret );
273  return ret; // <-- cache hit
274  }
275 
276  // HERE: cache misss, check toplevel cache or do download:
277  RepoInfo info = _package->repoInfo();
278 
279  // Check toplevel cache
280  {
281  RepoManagerOptions topCache;
282  if ( info.packagesPath().dirname() != topCache.repoPackagesCachePath ) // not using toplevel cache
283  {
284  const OnMediaLocation & loc( _package->location() );
285  if ( ! loc.checksum().empty() ) // no cache hit without checksum
286  {
287  PathInfo pi( topCache.repoPackagesCachePath / info.packagesPath().basename() / loc.filename() );
288  if ( pi.isExist() && loc.checksum() == CheckSum( loc.checksum().type(), std::ifstream( pi.c_str() ) ) )
289  {
290  report()->start( _package, pi.path().asFileUrl() );
291  const Pathname & dest( info.packagesPath() / loc.filename() );
292  if ( filesystem::assert_dir( dest.dirname() ) == 0 && filesystem::hardlinkCopy( pi.path(), dest ) == 0 )
293  {
294  ret = ManagedFile( dest );
295  if ( ! info.keepPackages() )
297 
298  MIL << "provided Package from toplevel cache " << _package << " at " << ret << endl;
299  report()->finish( _package, repo::DownloadResolvableReport::NO_ERROR, std::string() );
300  return ret; // <-- toplevel cache hit
301  }
302  }
303  }
304  }
305  }
306 
307  // FIXME we only support the first url for now.
308  if ( info.baseUrlsEmpty() )
309  ZYPP_THROW(Exception("No url in repository."));
310 
311  MIL << "provide Package " << _package << endl;
312  Url url = * info.baseUrlsBegin();
313  do {
314  _retry = false;
315  if ( ! ret->empty() )
316  {
318  ret.reset();
319  }
320  report()->start( _package, url );
321  try // ELIMINATE try/catch by providing a log-guard
322  {
323  ret = doProvidePackage();
324 
325  if ( info.pkgGpgCheck() )
326  {
327  UserData userData( "pkgGpgCheck" );
328  userData.set( "Package", _package );
329  userData.set( "Localpath", ret.value() );
330  RpmDb::CheckPackageResult res = packageSigCheck( ret, userData );
331  // publish the checkresult, even if it is OK. Apps may want to report something...
332  report()->pkgGpgCheck( userData );
333 
334  if ( res != RpmDb::CHK_OK )
335  {
336  if ( userData.hasvalue( "Action" ) ) // pkgGpgCheck report provided an user error action
337  {
338  resolveSignatureErrorAction( userData.get( "Action", repo::DownloadResolvableReport::ABORT ) );
339  }
340  else if ( userData.haskey( "Action" ) ) // pkgGpgCheck requests the default problem report
341  {
342  defaultReportSignatureError( res );
343  }
344  else // no advice from user => usedefaults
345  {
346  switch ( res )
347  {
348  case RpmDb::CHK_OK: // Signature is OK
349  break;
350 
351  case RpmDb::CHK_NOKEY: // Public key is unavailable
352  case RpmDb::CHK_NOTFOUND: // Signature is unknown type
353  case RpmDb::CHK_FAIL: // Signature does not verify
354  case RpmDb::CHK_NOTTRUSTED: // Signature is OK, but key is not trusted
355  case RpmDb::CHK_ERROR: // File does not exist or can't be opened
356  default:
357  // report problem, throw if to abort, else retry/ignore
358  defaultReportSignatureError( res );
359  break;
360  }
361  }
362  }
363  }
364  }
365  catch ( const UserRequestException & excpt )
366  {
367  // UserRequestException e.g. from failOnChecksumError was already reported.
368  ERR << "Failed to provide Package " << _package << endl;
369  if ( ! _retry )
370  {
371  ZYPP_RETHROW( excpt );
372  }
373  }
374  catch ( const Exception & excpt )
375  {
376  ERR << "Failed to provide Package " << _package << endl;
377  if ( ! _retry )
378  {
379  // Aything else gets reported
380  std::string package_str = _package->name() + "-" + _package->edition().asString();
381 
382  // TranslatorExplanation %s = name of the package being processed.
383  std::string detail_str( str::form(_("Failed to provide Package %s. Do you want to retry retrieval?"), package_str.c_str() ) );
384  detail_str += str::form( "\n\n%s", excpt.asUserHistory().c_str() );
385 
386  switch ( report()->problem( _package, repo::DownloadResolvableReport::IO, detail_str.c_str() ) )
387  {
389  _retry = true;
390  break;
392  ZYPP_THROW(SkipRequestException("User requested skip of corrupted file", excpt));
393  break;
395  ZYPP_THROW(AbortRequestException("User requested to abort", excpt));
396  break;
397  default:
398  ZYPP_RETHROW( excpt );
399  break;
400  }
401  }
402  }
403  } while ( _retry );
404 
405  report()->finish( _package, repo::DownloadResolvableReport::NO_ERROR, std::string() );
406  MIL << "provided Package " << _package << " at " << ret << endl;
407  return ret;
408  }
409 
410 
416  {
417  public:
419  const Package::constPtr & package_r,
420  const DeltaCandidates & deltas_r,
421  const PackageProviderPolicy & policy_r )
422  : PackageProvider::Impl( access_r, package_r, deltas_r, policy_r )
423  {}
424 
425  protected:
426  virtual ManagedFile doProvidePackageFromCache() const;
427 
428  virtual ManagedFile doProvidePackage() const;
429 
430  private:
432 
433  ManagedFile tryDelta( const DeltaRpm & delta_r ) const;
434 
435  bool progressDeltaDownload( int value ) const
436  { return report()->progressDeltaDownload( value ); }
437 
438  void progressDeltaApply( int value ) const
439  { return report()->progressDeltaApply( value ); }
440 
441  bool queryInstalled( const Edition & ed_r = Edition() ) const
442  { return _policy.queryInstalled( _package->name(), ed_r, _package->arch() ); }
443  };
445 
447  {
448  return ManagedFile( _package->cachedLocation() );
449  }
450 
452  {
453  Url url;
454  RepoInfo info = _package->repoInfo();
455  // FIXME we only support the first url for now.
456  if ( info.baseUrlsEmpty() )
457  ZYPP_THROW(Exception("No url in repository."));
458  else
459  url = * info.baseUrlsBegin();
460 
461  // check whether to process patch/delta rpms
462  if ( ZConfig::instance().download_use_deltarpm()
464  {
465  std::list<DeltaRpm> deltaRpms;
466  _deltas.deltaRpms( _package ).swap( deltaRpms );
467 
468  if ( ! deltaRpms.empty() && queryInstalled() && applydeltarpm::haveApplydeltarpm() )
469  {
470  for_( it, deltaRpms.begin(), deltaRpms.end())
471  {
472  DBG << "tryDelta " << *it << endl;
473  ManagedFile ret( tryDelta( *it ) );
474  if ( ! ret->empty() )
475  return ret;
476  }
477  }
478  }
479 
480  // no patch/delta -> provide full package
481  return Base::doProvidePackage();
482  }
483 
484  ManagedFile RpmPackageProvider::tryDelta( const DeltaRpm & delta_r ) const
485  {
486  if ( delta_r.baseversion().edition() != Edition::noedition
487  && ! queryInstalled( delta_r.baseversion().edition() ) )
488  return ManagedFile();
489 
490  if ( ! applydeltarpm::quickcheck( delta_r.baseversion().sequenceinfo() ) )
491  return ManagedFile();
492 
493  report()->startDeltaDownload( delta_r.location().filename(),
494  delta_r.location().downloadSize() );
495  ManagedFile delta;
496  try
497  {
498  ProvideFilePolicy policy;
499  policy.progressCB( bind( &RpmPackageProvider::progressDeltaDownload, this, _1 ) );
500  delta = _access.provideFile( delta_r.repository().info(), delta_r.location(), policy );
501  }
502  catch ( const Exception & excpt )
503  {
504  report()->problemDeltaDownload( excpt.asUserHistory() );
505  return ManagedFile();
506  }
507  report()->finishDeltaDownload();
508 
509  report()->startDeltaApply( delta );
510  if ( ! applydeltarpm::check( delta_r.baseversion().sequenceinfo() ) )
511  {
512  report()->problemDeltaApply( _("applydeltarpm check failed.") );
513  return ManagedFile();
514  }
515 
516  // build the package and put it into the cache
517  Pathname destination( _package->repoInfo().packagesPath() / _package->location().filename() );
518 
519  if ( ! applydeltarpm::provide( delta, destination,
520  bind( &RpmPackageProvider::progressDeltaApply, this, _1 ) ) )
521  {
522  report()->problemDeltaApply( _("applydeltarpm failed.") );
523  return ManagedFile();
524  }
525  report()->finishDeltaApply();
526 
527  return ManagedFile( destination, filesystem::unlink );
528  }
529 
530 #if 0
531  class PluginPackageProvider : public PackageProvider::Impl
539  {
540  public:
541  PluginPackageProvider( const std::string & stem_r,
542  RepoMediaAccess & access_r,
543  const Package::constPtr & package_r,
544  const DeltaCandidates & deltas_r,
545  const PackageProviderPolicy & policy_r )
546  : Base( access_r, package_r, deltas_r, policy_r )
547  {}
548 
549  protected:
550  virtual ManagedFile doProvidePackageFromCache() const
551  {
552  return Base::doProvidePackageFromCache();
553  }
554 
555  virtual ManagedFile doProvidePackage() const
556  {
557  return Base::doProvidePackage();
558  }
559  };
561 #endif
562 
564  // class PackageProvider
566 
568  const Package::constPtr & package_r,
569  const DeltaCandidates & deltas_r,
570  const PackageProviderPolicy & policy_r )
571  {
572  return new RpmPackageProvider( access_r, package_r, deltas_r, policy_r );
573  }
574 
576  const Package::constPtr & package_r,
577  const DeltaCandidates & deltas_r,
578  const PackageProviderPolicy & policy_r )
579  : _pimpl( Impl::factoryMake( access_r, package_r, deltas_r, policy_r ) )
580  {}
581 
583  {}
584 
586  { return _pimpl->providePackage(); }
587 
589  { return _pimpl->providePackageFromCache(); }
590 
592  { return _pimpl->isCached(); }
593 
594  } // namespace repo
596 } // namespace zypp
Candidate delta and patches for a package.
int assert_dir(const Pathname &path, unsigned mode)
Like 'mkdir -p'.
Definition: PathInfo.cc:324
RepoInfo info() const
Return any associated RepoInfo.
Definition: Repository.cc:273
Interface to gettext.
Interface to the rpm program.
Definition: RpmDb.h:47
#define MIL
Definition: Logger.h:64
bool failOnChecksumError() const
Redirect ProvideFilePolicy failOnChecksumError to this if needed.
virtual ManagedFile doProvidePackageFromCache() const
Lookup the final rpm in cache.
RpmDb::CheckPackageResult packageSigCheck(const Pathname &path_r, UserData &userData) const
const Repository & repository() const
Definition: PackageDelta.h:70
PackageProvider implementation.
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:320
Describes a path on a certain media amongs as the information required to download it...
bool hasvalue(const std::string &key_r) const
Whether key_r is in data and value is not empty.
Definition: UserData.h:94
static ZConfig & instance()
Singleton ctor.
Definition: ZConfig.cc:679
const BaseVersion & baseversion() const
Definition: PackageDelta.h:69
ManagedFile providePackage() const
Provide the package.
bool isCached() const
Whether the package is cached.
Architecture.
Definition: Arch.h:36
ManagedFile tryDelta(const DeltaRpm &delta_r) const
reference value() const
Reference to the _Tp object.
Definition: AutoDispose.h:133
urls_const_iterator baseUrlsBegin() const
iterator that points at begin of repository urls
Definition: RepoInfo.cc:401
callback::SendReport< repo::DownloadResolvableReport > Report
bool isCached() const
Whether the package is cached.
Policies and options for PackageProvider.
bool haveApplydeltarpm()
Test whether an execuatble applydeltarpm program is available.
bool pkgGpgCheck() const
Whether the signature of rpm packages should be checked for this repo.
Definition: RepoInfo.cc:286
void reset()
Reset to default Ctor values.
Definition: AutoDispose.h:145
What is known about a repository.
Definition: RepoInfo.h:71
AutoDispose< const Pathname > ManagedFile
A Pathname plus associated cleanup code to be executed when path is no longer needed.
Definition: ManagedFile.h:27
#define for_(IT, BEG, END)
Convenient for-loops using iterator.
Definition: Easy.h:27
Edition represents [epoch:]version[-release]
Definition: Edition.h:60
void progressDeltaApply(int value) const
std::string form(const char *format,...) __attribute__((format(printf
Printf style construction of std::string.
Definition: String.cc:36
Report & report() const
Access to the DownloadResolvableReport.
Pathname packagesPath() const
Path where this repo packages are cached.
Definition: RepoInfo.cc:365
#define ERR
Definition: Logger.h:66
bool queryInstalled(const Edition &ed_r=Edition()) const
ManagedFile providePackageFromCache() const
Provide the package if it is cached.
Repo manager settings.
Definition: RepoManager.h:53
Policy for provideFile.
#define ZYPP_RETHROW(EXCPT)
Drops a logline and rethrows, updating the CodeLocation.
Definition: Exception.h:328
RW_pointer< Impl > _pimpl
Implementation class.
PackageProvider(RepoMediaAccess &access, const Package::constPtr &package, const DeltaCandidates &deltas, const PackageProviderPolicy &policy_r=PackageProviderPolicy())
Ctor taking the Package to provide.
const Tp & get(const std::string &key_r) const
Pass back a const Tp & reference to key_r value.
Definition: UserData.h:168
packagedelta::DeltaRpm DeltaRpm
boost::noncopyable NonCopyable
Ensure derived classes cannot be copied.
Definition: NonCopyable.h:26
bool keepPackages() const
Whether packages downloaded from this repository will be kept in local cache.
Definition: RepoInfo.cc:359
Convenient building of std::string via std::ostream::operator<<.
Definition: String.h:233
int unlink(const Pathname &path)
Like 'unlink'.
Definition: PathInfo.cc:663
ManagedFile providePackageFromCache() const
Provide the package if it is cached.
#define WAR
Definition: Logger.h:65
Detailed rpm signature check log messages A single multiline message if CHK_OK.
Definition: RpmDb.h:443
void defaultReportSignatureError(RpmDb::CheckPackageResult ret) const
Default signature verrification error handling.
int hardlinkCopy(const Pathname &oldpath, const Pathname &newpath)
Create newpath as hardlink or copy of oldpath.
Definition: PathInfo.cc:818
zypp::Url url
Definition: MediaCurl.cc:193
bool progressPackageDownload(int value) const
Redirect ProvideFilePolicy package download progress to this.
RpmPackageProvider(RepoMediaAccess &access_r, const Package::constPtr &package_r, const DeltaCandidates &deltas_r, const PackageProviderPolicy &policy_r)
#define _(MSG)
Definition: Gettext.h:29
const OnMediaLocation & location() const
Definition: PackageDelta.h:68
virtual ManagedFile doProvidePackage() const
Actually provide the final rpm.
Provides files from different repos.
void setDispose(const Dispose &dispose_r)
Set a new dispose function.
Definition: AutoDispose.h:158
bool baseUrlsEmpty() const
whether repository urls are available
Definition: RepoInfo.cc:410
ProvideFilePolicy & failOnChecksumErrorCB(FailOnChecksumErrorCB failOnChecksumErrorCB_r)
Set callback.
const std::string & sequenceinfo() const
Definition: PackageDelta.h:46
virtual ManagedFile doProvidePackageFromCache() const =0
Lookup the final rpm in cache.
Base class for Exception.
Definition: Exception.h:143
ProvideFilePolicy & progressCB(ProgressCB progressCB_r)
Set callback.
Provide a package from a Repo.
Impl(RepoMediaAccess &access_r, const Package::constPtr &package_r, const DeltaCandidates &deltas_r, const PackageProviderPolicy &policy_r)
Ctor taking the Package to provide.
callback::SendReport< DownloadProgressReport > * report
Definition: MediaCurl.cc:178
const Pathname & filename() const
The path to the resource relatve to the url and path.
ManagedFile providePackage() const
Provide the package.
Typesafe passing of user data via callbacks.
Definition: UserData.h:38
Reference counted access to a _Tp object calling a custom Dispose function when the last AutoDispose ...
Definition: AutoDispose.h:92
shared_ptr< MediaSetAccess > _access
RPM PackageProvider implementation.
Pathname repoPackagesCachePath
Definition: RepoManager.h:82
std::string asUserHistory() const
A single (multiline) string composed of asUserString and historyAsString.
Definition: Exception.cc:75
CheckPackageResult
checkPackage result
Definition: RpmDb.h:429
bool quickcheck(const std::string &sequenceinfo_r)
Quick via check sequence info.
Definition: Applydeltarpm.h:48
bool check(const std::string &sequenceinfo_r, bool quick_r)
Check via sequence info.
virtual ManagedFile doProvidePackage() const =0
Actually provide the final rpm.
bool queryInstalled(const std::string &name_r, const Edition &ed_r, const Arch &arch_r) const
Evaluate callback.
bool haskey(const std::string &key_r) const
Whether key_r is in data.
Definition: UserData.h:90
bool progressDeltaDownload(int value) const
Base for exceptions caused by explicit user request.
static bool schemeIsDownloading(const std::string &scheme_r)
http https ftp sftp tftp
Definition: Url.cc:474
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc:1
void resolveSignatureErrorAction(repo::DownloadResolvableReport::Action action_r) const
React on signature verrification error user action.
const ByteCount & downloadSize() const
The size of the resource on the server.
bool provide(const Pathname &delta_r, const Pathname &new_r, const Progress &report_r)
Apply a binary delta to on-disk data to re-create a new rpm.
Url manipulation class.
Definition: Url.h:87
TraitsType::constPtrType constPtr
Definition: Package.h:38
bool download_use_deltarpm_always() const
Whether to consider using a deltarpm even when rpm is local.
Definition: ZConfig.cc:863
#define DBG
Definition: Logger.h:63
static const Edition noedition
Value representing noedition ("") This is in fact a valid Edition.
Definition: Edition.h:73
static Impl * factoryMake(RepoMediaAccess &access_r, const Package::constPtr &package_r, const DeltaCandidates &deltas_r, const PackageProviderPolicy &policy_r)
Factory method providing the appropriate implementation.
bool set(const std::string &key_r, boost::any val_r)
Set the value for key (nonconst version always returns true).
Definition: UserData.h:111