libzypp  17.36.1
RpmDb.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
12 #include "librpm.h"
13 extern "C"
14 {
15 #include <rpm/rpmcli.h>
16 #include <rpm/rpmlog.h>
17 }
18 #include <cstdlib>
19 #include <cstdio>
20 #include <ctime>
21 
22 #include <iostream>
23 #include <fstream>
24 #include <sstream>
25 #include <list>
26 #include <map>
27 #include <set>
28 #include <string>
29 #include <utility>
30 #include <vector>
31 #include <algorithm>
32 
33 #include <zypp-core/base/StringV.h>
34 #include <zypp/base/Logger.h>
35 #include <zypp/base/String.h>
36 #include <zypp/base/Gettext.h>
37 #include <zypp/base/LocaleGuard.h>
38 #include <zypp-core/base/DtorReset>
39 
40 #include <zypp/Date.h>
41 #include <zypp/Pathname.h>
42 #include <zypp/PathInfo.h>
43 #include <zypp-common/PublicKey.h>
44 #include <zypp-core/ui/ProgressData>
45 
46 #include <zypp/target/rpm/RpmDb.h>
49 
50 #include <zypp/HistoryLog.h>
53 #include <zypp/TmpPath.h>
54 #include <zypp/KeyRing.h>
55 #include <zypp-common/KeyManager.h>
56 #include <zypp/ZYppFactory.h>
57 #include <zypp/ZConfig.h>
58 #include <zypp/base/IOTools.h>
59 
60 using std::endl;
61 using namespace zypp::filesystem;
62 
63 #define WARNINGMAILPATH "/var/log/YaST2/"
64 #define FILEFORBACKUPFILES "YaSTBackupModifiedFiles"
65 #define MAXRPMMESSAGELINES 10000
66 
67 #define WORKAROUNDRPMPWDBUG
68 
69 #undef ZYPP_BASE_LOGGER_LOGGROUP
70 #define ZYPP_BASE_LOGGER_LOGGROUP "librpmDb"
71 
72 namespace zypp
73 {
74  namespace zypp_readonly_hack
75  {
76  bool IGotIt(); // in readonly-mode
77  }
78  namespace env
79  {
80  inline bool ZYPP_RPM_DEBUG()
81  {
82  static bool val = [](){
83  const char * env = getenv("ZYPP_RPM_DEBUG");
84  return( env && str::strToBool( env, true ) );
85  }();
86  return val;
87  }
88  } // namespace env
89 namespace target
90 {
91 namespace rpm
92 {
93  const callback::UserData::ContentType InstallResolvableReport::contentRpmout( "rpmout","installpkg" );
94  const callback::UserData::ContentType RemoveResolvableReport::contentRpmout( "rpmout","removepkg" );
95 
96 namespace
97 {
98 const char* quoteInFilename_m = "\'\"";
99 inline std::string rpmQuoteFilename( const Pathname & path_r )
100 {
101  std::string path( path_r.asString() );
102  for ( std::string::size_type pos = path.find_first_of( quoteInFilename_m );
103  pos != std::string::npos;
104  pos = path.find_first_of( quoteInFilename_m, pos ) )
105  {
106  path.insert( pos, "\\" );
107  pos += 2; // skip '\\' and the quoted char.
108  }
109  return path;
110 }
111 
112 
117  inline Pathname workaroundRpmPwdBug( Pathname path_r )
118  {
119 #if defined(WORKAROUNDRPMPWDBUG)
120  if ( path_r.relative() )
121  {
122  // try to prepend cwd
123  AutoDispose<char*> cwd( ::get_current_dir_name(), ::free );
124  if ( cwd )
125  return Pathname( cwd ) / path_r;
126  WAR << "Can't get cwd!" << endl;
127  }
128 #endif
129  return path_r; // no problem with absolute pathnames
130  }
131 }
132 
134 {
135  KeyRingSignalReceiver(RpmDb &rpmdb) : _rpmdb(rpmdb) { connect(); }
138  KeyRingSignalReceiver &operator=(const KeyRingSignalReceiver &) = delete;
139  KeyRingSignalReceiver &operator=(KeyRingSignalReceiver &&) = delete;
140 
142  {
143  disconnect();
144  }
145 
146  void trustedKeyAdded( const PublicKey &key ) override
147  {
148  MIL << "trusted key added to zypp Keyring. Importing..." << endl;
149  _rpmdb.importPubkey( key );
150  }
151 
152  void trustedKeyRemoved( const PublicKey &key ) override
153  {
154  MIL << "Trusted key removed from zypp Keyring. Removing..." << endl;
155  _rpmdb.removePubkey( key );
156  }
157 
159 };
160 
161 static shared_ptr<KeyRingSignalReceiver> sKeyRingReceiver;
162 
163 unsigned diffFiles(const std::string& file1, const std::string& file2, std::string& out, int maxlines)
164 {
165  const char* argv[] =
166  {
167  "diff",
168  "-u",
169  file1.c_str(),
170  file2.c_str(),
171  NULL
172  };
173  ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
174 
175  //if(!prog)
176  //return 2;
177 
178  std::string line;
179  int count = 0;
180  for (line = prog.receiveLine(), count=0;
181  !line.empty();
182  line = prog.receiveLine(), count++ )
183  {
184  if (maxlines<0?true:count<maxlines)
185  out+=line;
186  }
187 
188  return prog.close();
189 }
190 
192 //
193 // CLASS NAME : RpmDb
194 //
196 
197 #define FAILIFNOTINITIALIZED if( ! initialized() ) { ZYPP_THROW(RpmDbNotOpenException()); }
198 
200 
202 //
203 //
204 // METHOD NAME : RpmDb::RpmDb
205 // METHOD TYPE : Constructor
206 //
207 RpmDb::RpmDb()
208  : _backuppath ("/var/adm/backup")
209  , _packagebackups(false)
210 {
211  process = 0;
212  exit_code = -1;
214  // Some rpm versions are patched not to abort installation if
215  // symlink creation failed.
216  setenv( "RPM_IgnoreFailedSymlinks", "1", 1 );
217  sKeyRingReceiver.reset(new KeyRingSignalReceiver(*this));
218 }
219 
221 //
222 //
223 // METHOD NAME : RpmDb::~RpmDb
224 // METHOD TYPE : Destructor
225 //
227 {
228  MIL << "~RpmDb()" << endl;
229  closeDatabase();
230  delete process;
231  MIL << "~RpmDb() end" << endl;
232  sKeyRingReceiver.reset();
233 }
234 
236 //
237 //
238 // METHOD NAME : RpmDb::dumpOn
239 // METHOD TYPE : std::ostream &
240 //
241 std::ostream & RpmDb::dumpOn( std::ostream & str ) const
242 {
243  return str << "RpmDb[" << dumpPath( _root, _dbPath ) << "]";
244 }
245 
248 {
249  if ( initialized() )
250  return db_const_iterator( root(), dbPath() );
251  return db_const_iterator();
252 }
253 
255 //
256 //
257 // METHOD NAME : RpmDb::initDatabase
258 // METHOD TYPE : PMError
259 //
260 void RpmDb::initDatabase( Pathname root_r, bool doRebuild_r )
261 {
263  // Check arguments
265  if ( root_r.empty() )
266  root_r = "/";
267 
268  const Pathname & dbPath_r { librpmDb::suggestedDbPath( root_r ) }; // also asserts root_r is absolute
269 
270  // The rpmdb compat symlink.
271  // Required at least until rpmdb2solv takes a dppath argument.
272  // Otherwise it creates a db at "/var/lib/rpm".
273  if ( dbPath_r != "/var/lib/rpm" && ! PathInfo( root_r/"/var/lib/rpm" ).isExist() )
274  {
275  WAR << "Inject missing /var/lib/rpm compat symlink to " << dbPath_r << endl;
276  filesystem::assert_dir( root_r/"/var/lib" );
277  filesystem::symlink( "../../"/dbPath_r, root_r/"/var/lib/rpm" );
278  }
279 
281  // Check whether already initialized
283  if ( initialized() )
284  {
285  // Just check for a changing root because the librpmDb::suggestedDbPath
286  // may indeed change: rpm %post moving the db from /var/lib/rpm
287  // to /usr/lib/sysimage/rpm. We continue to use the old dbpath
288  // (via the compat symlink) until a re-init.
289  if ( root_r == _root ) {
290  MIL << "Calling initDatabase: already initialized at " << dumpPath( _root, _dbPath ) << endl;
291  return;
292  }
293  else
294  ZYPP_THROW(RpmDbAlreadyOpenException(_root, _dbPath, root_r, dbPath_r));
295  }
296 
297  MIL << "Calling initDatabase: " << dumpPath( root_r, dbPath_r )
298  << ( doRebuild_r ? " (rebuilddb)" : "" ) << endl;
299 
301  // init database
303  // creates dbdir and empty rpm database if not present
304  // or throws RpmException
305  librpmDb::dbOpenCreate( root_r, dbPath_r );
306  _root = root_r;
307  _dbPath = dbPath_r;
308 
309  if ( doRebuild_r )
310  rebuildDatabase();
311 
312  MIL << "Synchronizing keys with zypp keyring" << endl;
313  syncTrustedKeys();
314 
315 #if 0 // if this is needed we need to forcefully close the db of running db_const_iterators
316  // Close the database in case any write acces (create/convert)
317  // happened during init. This should drop any lock acquired
318  // by librpm. On demand it will be reopened readonly and should
319  // not hold any lock.
320  librpmDb::dbRelease( true );
321 #endif
322  MIL << "InitDatabase: " << *this << endl;
323 }
324 
326 //
327 //
328 // METHOD NAME : RpmDb::closeDatabase
329 // METHOD TYPE : PMError
330 //
332 {
333  if ( ! initialized() )
334  {
335  return;
336  }
337 
338  // NOTE: There are no persistent librpmDb handles to invalidate.
339  // Running db_const_iterator may keep the DB physically open until they
340  // go out of scope too.
341  MIL << "closeDatabase: " << *this << endl;
342  _root = _dbPath = Pathname();
343 }
344 
346 //
347 //
348 // METHOD NAME : RpmDb::rebuildDatabase
349 // METHOD TYPE : PMError
350 //
352 {
354 
355  report->start( root() + dbPath() );
356 
357  try
358  {
359  doRebuildDatabase(report);
360  }
361  catch (RpmException & excpt_r)
362  {
363  report->finish(root() + dbPath(), RebuildDBReport::FAILED, excpt_r.asUserHistory());
364  ZYPP_RETHROW(excpt_r);
365  }
366  report->finish(root() + dbPath(), RebuildDBReport::NO_ERROR, "");
367 }
368 
370 {
372  MIL << "RpmDb::rebuildDatabase" << *this << endl;
373 
374  const Pathname mydbpath { root()/dbPath() }; // the configured path used in reports
375  {
376  // For --rebuilddb take care we're using the real db directory
377  // and not a symlink. Otherwise rpm will rename the symlink and
378  // replace it with a real directory containing the converted db.
379  DtorReset guardRoot { _root };
380  DtorReset guardDbPath{ _dbPath };
381  _root = "/";
382  _dbPath = filesystem::expandlink( mydbpath );
383 
384  // run rpm
385  RpmArgVec opts;
386  opts.push_back("--rebuilddb");
387  opts.push_back("-vv");
389  }
390 
391  // generate and report progress
392  ProgressData tics;
393  {
394  ProgressData::value_type hdrTotal = 0;
395  for ( auto it = dbConstIterator(); *it; ++it, ++hdrTotal )
396  {;}
397  tics.range( hdrTotal );
398  }
399  tics.sendTo( [&report,&mydbpath]( const ProgressData & tics_r ) -> bool {
400  return report->progress( tics_r.reportValue(), mydbpath );
401  } );
402  tics.toMin();
403 
404  std::string line;
405  std::string errmsg;
406  while ( systemReadLine( line ) )
407  {
408  static const std::string debugPrefix { "D:" };
409  static const std::string progressPrefix { "D: read h#" };
410  static const std::string ignoreSuffix { "digest: OK" };
411 
412  if ( ! str::startsWith( line, debugPrefix ) )
413  {
414  if ( ! str::endsWith( line, ignoreSuffix ) )
415  {
416  errmsg += line;
417  errmsg += '\n';
418  WAR << line << endl;
419  }
420  }
421  else if ( str::startsWith( line, progressPrefix ) )
422  {
423  if ( ! tics.incr() )
424  {
425  WAR << "User requested abort." << endl;
426  systemKill();
427  }
428  }
429  }
430 
431  if ( systemStatus() != 0 )
432  {
433  //TranslatorExplanation after semicolon is error message
434  ZYPP_THROW(RpmSubprocessException(std::string(_("RPM failed: ")) + (errmsg.empty() ? error_message: errmsg) ) );
435  }
436  else
437  {
438  tics.toMax();
439  }
440 }
441 
443 namespace
444 {
449  void computeKeyRingSync( std::set<Edition> & rpmKeys_r, std::list<PublicKeyData> & zyppKeys_r )
450  {
452  // Remember latest release and where it ocurred
453  struct Key
454  {
455  Key()
456  : _inRpmKeys( nullptr )
457  , _inZyppKeys( nullptr )
458  {}
459 
460  void updateIf( const Edition & rpmKey_r )
461  {
462  std::string keyRelease( rpmKey_r.release() );
463  int comp = _release.compare( keyRelease );
464  if ( comp < 0 )
465  {
466  // update to newer release
467  _release.swap( keyRelease );
468  _inRpmKeys = &rpmKey_r;
469  _inZyppKeys = nullptr;
470  if ( !keyRelease.empty() )
471  DBG << "Old key in Z: gpg-pubkey-" << rpmKey_r.version() << "-" << keyRelease << endl;
472  }
473  else if ( comp == 0 )
474  {
475  // stay with this release
476  if ( ! _inRpmKeys )
477  _inRpmKeys = &rpmKey_r;
478  }
479  // else: this is an old release
480  else
481  DBG << "Old key in R: gpg-pubkey-" << rpmKey_r.version() << "-" << keyRelease << endl;
482  }
483 
484  void updateIf( const PublicKeyData & zyppKey_r )
485  {
486  std::string keyRelease( zyppKey_r.gpgPubkeyRelease() );
487  int comp = _release.compare( keyRelease );
488  if ( comp < 0 )
489  {
490  // update to newer release
491  _release.swap( keyRelease );
492  _inRpmKeys = nullptr;
493  _inZyppKeys = &zyppKey_r;
494  if ( !keyRelease.empty() )
495  DBG << "Old key in R: gpg-pubkey-" << zyppKey_r.gpgPubkeyVersion() << "-" << keyRelease << endl;
496  }
497  else if ( comp == 0 )
498  {
499  // stay with this release
500  if ( ! _inZyppKeys )
501  _inZyppKeys = &zyppKey_r;
502  }
503  // else: this is an old release
504  else
505  DBG << "Old key in Z: gpg-pubkey-" << zyppKey_r.gpgPubkeyVersion() << "-" << keyRelease << endl;
506  }
507 
508  std::string _release;
509  const Edition * _inRpmKeys;
510  const PublicKeyData * _inZyppKeys;
511  };
513 
514  // collect keys by ID(version) and latest creation(release)
515  std::map<std::string,Key> _keymap;
516 
517  for_( it, rpmKeys_r.begin(), rpmKeys_r.end() )
518  {
519  _keymap[(*it).version()].updateIf( *it );
520  }
521 
522  for_( it, zyppKeys_r.begin(), zyppKeys_r.end() )
523  {
524  _keymap[(*it).gpgPubkeyVersion()].updateIf( *it );
525  }
526 
527  // compute missing keys
528  std::set<Edition> rpmKeys;
529  std::list<PublicKeyData> zyppKeys;
530  for_( it, _keymap.begin(), _keymap.end() )
531  {
532  DBG << "gpg-pubkey-" << (*it).first << "-" << (*it).second._release << " "
533  << ( (*it).second._inRpmKeys ? "R" : "_" )
534  << ( (*it).second._inZyppKeys ? "Z" : "_" ) << endl;
535  if ( ! (*it).second._inRpmKeys )
536  {
537  zyppKeys.push_back( *(*it).second._inZyppKeys );
538  }
539  if ( ! (*it).second._inZyppKeys )
540  {
541  rpmKeys.insert( *(*it).second._inRpmKeys );
542  }
543  }
544  rpmKeys_r.swap( rpmKeys );
545  zyppKeys_r.swap( zyppKeys );
546  }
547 } // namespace
549 
551 {
552  MIL << "Going to sync trusted keys..." << endl;
553  std::set<Edition> rpmKeys( pubkeyEditions() );
554  std::list<PublicKeyData> zyppKeys( getZYpp()->keyRing()->trustedPublicKeyData() );
555 
556  if ( ! ( mode_r & SYNC_FROM_KEYRING ) )
557  {
558  // bsc#1064380: We relief PK from removing excess keys in the zypp keyring
559  // when re-acquiring the zyppp lock. For now we remove all excess keys.
560  // TODO: Once we can safely assume that all PK versions are updated we
561  // can think about re-importing newer key versions found in the zypp keyring and
562  // removing only excess ones (but case is not very likely). Unfixed PK versions
563  // however will remove the newer version found in the zypp keyring and by doing
564  // this, the key here will be removed via callback as well (keys are deleted
565  // via gpg id, regardless of the edition).
566  MIL << "Removing excess keys in zypp trusted keyring" << std::endl;
567  // Temporarily disconnect to prevent the attempt to pass back the delete request.
569  bool dirty = false;
570  for ( const PublicKeyData & keyData : zyppKeys )
571  {
572  if ( ! rpmKeys.count( keyData.gpgPubkeyEdition() ) )
573  {
574  DBG << "Excess key in Z to delete: gpg-pubkey-" << keyData.gpgPubkeyEdition() << endl;
575  getZYpp()->keyRing()->deleteKey( keyData.id(), /*trusted*/true );
576  if ( !dirty ) dirty = true;
577  }
578  }
579  if ( dirty )
580  zyppKeys = getZYpp()->keyRing()->trustedPublicKeyData();
581  }
582 
583  computeKeyRingSync( rpmKeys, zyppKeys );
584  MIL << (mode_r & SYNC_TO_KEYRING ? "" : "(skip) ") << "Rpm keys to export into zypp trusted keyring: " << rpmKeys.size() << endl;
585  MIL << (mode_r & SYNC_FROM_KEYRING ? "" : "(skip) ") << "Zypp trusted keys to import into rpm database: " << zyppKeys.size() << endl;
586 
588  if ( (mode_r & SYNC_TO_KEYRING) && ! rpmKeys.empty() )
589  {
590  // export to zypp keyring
591  MIL << "Exporting rpm keyring into zypp trusted keyring" <<endl;
592  // Temporarily disconnect to prevent the attempt to re-import the exported keys.
594  auto keepDbOpen = dbConstIterator(); // just to keep a ref.
595 
596  TmpFile tmpfile( getZYpp()->tmpPath() );
597  {
598  std::ofstream tmpos( tmpfile.path().c_str() );
599  for_( it, rpmKeys.begin(), rpmKeys.end() )
600  {
601  // we export the rpm key into a file
602  RpmHeader::constPtr result;
603  getData( "gpg-pubkey", *it, result );
604  tmpos << result->tag_description() << endl;
605  }
606  }
607  try
608  {
609  getZYpp()->keyRing()->multiKeyImport( tmpfile.path(), true /*trusted*/);
610  // bsc#1096217: Try to spot and report legacy V3 keys found in the rpm database.
611  // Modern rpm does not import those keys, but when migrating a pre SLE12 system
612  // we may find them. rpm>4.13 even complains on sderr if sucha key is present.
613  std::set<Edition> missingKeys;
614  for ( const Edition & key : rpmKeys )
615  {
616  if ( getZYpp()->keyRing()->isKeyTrusted( key.version() ) ) // key.version is the gpgkeys short ID
617  continue;
618  ERR << "Could not import key:" << str::Format("gpg-pubkey-%s") % key << " into zypp keyring (V3 key?)" << endl;
619  missingKeys.insert( key );
620  }
621  if ( ! missingKeys.empty() )
622  callback::SendReport<KeyRingReport>()->reportNonImportedKeys(missingKeys);
623  }
624  catch ( const Exception & excpt )
625  {
626  ZYPP_CAUGHT( excpt );
627  ERR << "Could not import keys into zypp keyring: " << endl;
628  }
629  }
630 
632  if ( (mode_r & SYNC_FROM_KEYRING) && ! zyppKeys.empty() )
633  {
634  // import from zypp keyring
635  MIL << "Importing zypp trusted keyring" << std::endl;
636  for_( it, zyppKeys.begin(), zyppKeys.end() )
637  {
638  try
639  {
640  importPubkey( getZYpp()->keyRing()->exportTrustedPublicKey( *it ) );
641  }
642  catch ( const RpmException & exp )
643  {
644  ZYPP_CAUGHT( exp );
645  }
646  }
647  }
648  MIL << "Trusted keys synced." << endl;
649 }
650 
653 
656 
658 //
659 //
660 // METHOD NAME : RpmDb::importPubkey
661 // METHOD TYPE : PMError
662 //
663 void RpmDb::importPubkey( const PublicKey & pubkey_r )
664 {
666 
667  // bnc#828672: On the fly key import in READONLY
669  {
670  WAR << "Key " << pubkey_r << " can not be imported. (READONLY MODE)" << endl;
671  return;
672  }
673 
674  // check if the key is already in the rpm database
675  Edition keyEd( pubkey_r.gpgPubkeyVersion(), pubkey_r.gpgPubkeyRelease() );
676  std::set<Edition> rpmKeys = pubkeyEditions();
677  bool hasOldkeys = false;
678 
679  for_( it, rpmKeys.begin(), rpmKeys.end() )
680  {
681  // bsc#1008325: Keys using subkeys for signing don't get a higher release
682  // if new subkeys are added, because the primary key remains unchanged.
683  // For now always re-import keys with subkeys. Here we don't want to export the
684  // keys in the rpm database to check whether the subkeys are the same. The calling
685  // code should take care, we don't re-import the same kesy over and over again.
686  if ( keyEd == *it && !pubkey_r.hasSubkeys() ) // quick test (Edition is IdStringType!)
687  {
688  MIL << "Key " << pubkey_r << " is already in the rpm trusted keyring. (skip import)" << endl;
689  return;
690  }
691 
692  if ( keyEd.version() != (*it).version() )
693  continue; // different key ID (version)
694 
695  if ( keyEd.release() < (*it).release() )
696  {
697  MIL << "Key " << pubkey_r << " is older than one in the rpm trusted keyring. (skip import)" << endl;
698  return;
699  }
700  else
701  {
702  hasOldkeys = true;
703  }
704  }
705  MIL << "Key " << pubkey_r << " will be imported into the rpm trusted keyring." << (hasOldkeys?"(update)":"(new)") << endl;
706 
707  if ( hasOldkeys )
708  {
709  // We must explicitly delete old key IDs first (all releases,
710  // that's why we don't call removePubkey here).
711  std::string keyName( "gpg-pubkey-" + keyEd.version() );
712  RpmArgVec opts;
713  opts.push_back ( "-e" );
714  opts.push_back ( "--allmatches" );
715  opts.push_back ( "--" );
716  opts.push_back ( keyName.c_str() );
718 
719  std::string line;
720  while ( systemReadLine( line ) )
721  {
722  ( str::startsWith( line, "error:" ) ? WAR : DBG ) << line << endl;
723  }
724 
725  if ( systemStatus() != 0 )
726  {
727  ERR << "Failed to remove key " << pubkey_r << " from RPM trusted keyring (ignored)" << endl;
728  }
729  else
730  {
731  MIL << "Key " << pubkey_r << " has been removed from RPM trusted keyring" << endl;
732  }
733  }
734 
735  // import the new key
736  RpmArgVec opts;
737  opts.push_back ( "--import" );
738  opts.push_back ( "--" );
739  std::string pubkeypath( pubkey_r.path().asString() );
740  opts.push_back ( pubkeypath.c_str() );
742 
743  std::string line;
744  std::vector<std::string> excplines;
745  while ( systemReadLine( line ) )
746  {
747  if ( str::startsWith( line, "error:" ) )
748  {
749  WAR << line << endl;
750  excplines.push_back( std::move(line) );
751  }
752  else
753  DBG << line << endl;
754  }
755 
756  if ( systemStatus() != 0 )
757  {
758  // Translator: %1% is a gpg public key
759  RpmSubprocessException excp( str::Format(_("Failed to import public key %1%") ) % pubkey_r.asString() );
760  excp.moveToHistory( excplines );
761  excp.addHistory( std::move(error_message) );
762  ZYPP_THROW( excp );
763  }
764  else
765  {
766  MIL << "Key " << pubkey_r << " imported in rpm trusted keyring." << endl;
767  }
768 }
769 
771 //
772 //
773 // METHOD NAME : RpmDb::removePubkey
774 // METHOD TYPE : PMError
775 //
776 void RpmDb::removePubkey( const PublicKey & pubkey_r )
777 {
779 
780  // check if the key is in the rpm database and just
781  // return if it does not.
782  std::set<Edition> rpm_keys = pubkeyEditions();
783  std::set<Edition>::const_iterator found_edition = rpm_keys.end();
784  std::string pubkeyVersion( pubkey_r.gpgPubkeyVersion() );
785 
786  for_( it, rpm_keys.begin(), rpm_keys.end() )
787  {
788  if ( (*it).version() == pubkeyVersion )
789  {
790  found_edition = it;
791  break;
792  }
793  }
794 
795  // the key does not exist, cannot be removed
796  if (found_edition == rpm_keys.end())
797  {
798  WAR << "Key " << pubkey_r.id() << " is not in rpm db" << endl;
799  return;
800  }
801 
802  std::string rpm_name("gpg-pubkey-" + found_edition->asString());
803 
804  RpmArgVec opts;
805  opts.push_back ( "-e" );
806  opts.push_back ( "--" );
807  opts.push_back ( rpm_name.c_str() );
809 
810  std::string line;
811  std::vector<std::string> excplines;
812  while ( systemReadLine( line ) )
813  {
814  if ( str::startsWith( line, "error:" ) )
815  {
816  WAR << line << endl;
817  excplines.push_back( std::move(line) );
818  }
819  else
820  DBG << line << endl;
821  }
822 
823  if ( systemStatus() != 0 )
824  {
825  // Translator: %1% is a gpg public key
826  RpmSubprocessException excp( str::Format(_("Failed to remove public key %1%") ) % pubkey_r.asString() );
827  excp.moveToHistory( excplines );
828  excp.addHistory( std::move(error_message) );
829  ZYPP_THROW( excp );
830  }
831  else
832  {
833  MIL << "Key " << pubkey_r << " has been removed from RPM trusted keyring" << endl;
834  }
835 }
836 
838 //
839 //
840 // METHOD NAME : RpmDb::pubkeys
841 // METHOD TYPE : std::set<Edition>
842 //
843 std::list<PublicKey> RpmDb::pubkeys() const
844 {
845  std::list<PublicKey> ret;
846 
847  auto it = dbConstIterator();
848  for ( it.findByName( "gpg-pubkey" ); *it; ++it )
849  {
850  Edition edition = it->tag_edition();
851  if (edition != Edition::noedition)
852  {
853  // we export the rpm key into a file
854  RpmHeader::constPtr result;
855  getData( "gpg-pubkey", edition, result );
856  TmpFile file(getZYpp()->tmpPath());
857  std::ofstream os;
858  try
859  {
860  os.open(file.path().asString().c_str());
861  // dump rpm key into the tmp file
862  os << result->tag_description();
863  //MIL << "-----------------------------------------------" << endl;
864  //MIL << result->tag_description() <<endl;
865  //MIL << "-----------------------------------------------" << endl;
866  os.close();
867  // read the public key from the dumped file
868  PublicKey key(file);
869  ret.push_back(key);
870  }
871  catch ( std::exception & e )
872  {
873  ERR << "Could not dump key " << edition.asString() << " in tmp file " << file.path() << endl;
874  // just ignore the key
875  }
876  }
877  }
878  return ret;
879 }
880 
881 std::set<Edition> RpmDb::pubkeyEditions() const
882  {
883  std::set<Edition> ret;
884 
885  auto it = dbConstIterator();
886  for ( it.findByName( "gpg-pubkey" ); *it; ++it )
887  {
888  Edition edition = it->tag_edition();
889  if (edition != Edition::noedition)
890  ret.insert( edition );
891  }
892  return ret;
893  }
894 
895 
897 //
898 //
899 // METHOD NAME : RpmDb::fileList
900 // METHOD TYPE : bool
901 //
902 // DESCRIPTION :
903 //
904 std::list<FileInfo>
905 RpmDb::fileList( const std::string & name_r, const Edition & edition_r ) const
906 {
907  std::list<FileInfo> result;
908 
909  auto it = dbConstIterator();
910  bool found = false;
911  if (edition_r == Edition::noedition)
912  {
913  found = it.findPackage( name_r );
914  }
915  else
916  {
917  found = it.findPackage( name_r, edition_r );
918  }
919  if (!found)
920  return result;
921 
922  return result;
923 }
924 
925 
927 //
928 //
929 // METHOD NAME : RpmDb::hasFile
930 // METHOD TYPE : bool
931 //
932 // DESCRIPTION :
933 //
934 bool RpmDb::hasFile( const std::string & file_r, const std::string & name_r ) const
935 {
936  auto it = dbConstIterator();
937  bool res = false;
938  do
939  {
940  res = it.findByFile( file_r );
941  if (!res) break;
942  if (!name_r.empty())
943  {
944  res = (it->tag_name() == name_r);
945  }
946  ++it;
947  }
948  while (res && *it);
949  return res;
950 }
951 
953 //
954 //
955 // METHOD NAME : RpmDb::whoOwnsFile
956 // METHOD TYPE : std::string
957 //
958 // DESCRIPTION :
959 //
960 std::string RpmDb::whoOwnsFile( const std::string & file_r) const
961 {
962  auto it = dbConstIterator();
963  if (it.findByFile( file_r ))
964  {
965  return it->tag_name();
966  }
967  return "";
968 }
969 
971 //
972 //
973 // METHOD NAME : RpmDb::hasProvides
974 // METHOD TYPE : bool
975 //
976 // DESCRIPTION :
977 //
978 bool RpmDb::hasProvides( const std::string & tag_r ) const
979 {
980  auto it = dbConstIterator();
981  return it.findByProvides( tag_r );
982 }
983 
985 //
986 //
987 // METHOD NAME : RpmDb::hasRequiredBy
988 // METHOD TYPE : bool
989 //
990 // DESCRIPTION :
991 //
992 bool RpmDb::hasRequiredBy( const std::string & tag_r ) const
993 {
994  auto it = dbConstIterator();
995  return it.findByRequiredBy( tag_r );
996 }
997 
999 //
1000 //
1001 // METHOD NAME : RpmDb::hasConflicts
1002 // METHOD TYPE : bool
1003 //
1004 // DESCRIPTION :
1005 //
1006 bool RpmDb::hasConflicts( const std::string & tag_r ) const
1007 {
1008  auto it = dbConstIterator();
1009  return it.findByConflicts( tag_r );
1010 }
1011 
1013 //
1014 //
1015 // METHOD NAME : RpmDb::hasPackage
1016 // METHOD TYPE : bool
1017 //
1018 // DESCRIPTION :
1019 //
1020 bool RpmDb::hasPackage( const std::string & name_r ) const
1021 {
1022  auto it = dbConstIterator();
1023  return it.findPackage( name_r );
1024 }
1025 
1027 //
1028 //
1029 // METHOD NAME : RpmDb::hasPackage
1030 // METHOD TYPE : bool
1031 //
1032 // DESCRIPTION :
1033 //
1034 bool RpmDb::hasPackage( const std::string & name_r, const Edition & ed_r ) const
1035 {
1036  auto it = dbConstIterator();
1037  return it.findPackage( name_r, ed_r );
1038 }
1039 
1041 //
1042 //
1043 // METHOD NAME : RpmDb::getData
1044 // METHOD TYPE : PMError
1045 //
1046 // DESCRIPTION :
1047 //
1048 void RpmDb::getData( const std::string & name_r,
1049  RpmHeader::constPtr & result_r ) const
1050 {
1051  auto it = dbConstIterator();
1052  it.findPackage( name_r );
1053  result_r = *it;
1054 #if 0 // if this is needed we need to forcefully close the db of running db_const_iterators
1055  if (it.dbError())
1056  ZYPP_THROW(*(it.dbError()));
1057 #endif
1058 }
1059 
1061 //
1062 //
1063 // METHOD NAME : RpmDb::getData
1064 // METHOD TYPE : void
1065 //
1066 // DESCRIPTION :
1067 //
1068 void RpmDb::getData( const std::string & name_r, const Edition & ed_r,
1069  RpmHeader::constPtr & result_r ) const
1070 {
1071  auto it = dbConstIterator();
1072  it.findPackage( name_r, ed_r );
1073  result_r = *it;
1074 #if 0 // if this is needed we need to forcefully close the db of running db_const_iterators
1075  if (it.dbError())
1076  ZYPP_THROW(*(it.dbError()));
1077 #endif
1078 }
1079 
1081 namespace
1082 {
1083  struct RpmlogCapture : public std::vector<std::string>
1084  {
1085  RpmlogCapture()
1086  {
1087  rpmlogSetCallback( rpmLogCB, this );
1088  _oldMask = rpmlogSetMask( RPMLOG_UPTO( RPMLOG_PRI(RPMLOG_INFO) ) );
1089  }
1090 
1091  RpmlogCapture(const RpmlogCapture &) = delete;
1092  RpmlogCapture(RpmlogCapture &&) = delete;
1093  RpmlogCapture &operator=(const RpmlogCapture &) = delete;
1094  RpmlogCapture &operator=(RpmlogCapture &&) = delete;
1095 
1096  ~RpmlogCapture() {
1097  rpmlogSetCallback( nullptr, nullptr );
1098  rpmlogSetMask( _oldMask );
1099  }
1100 
1101  static int rpmLogCB( rpmlogRec rec_r, rpmlogCallbackData data_r )
1102  { return reinterpret_cast<RpmlogCapture*>(data_r)->rpmLog( rec_r ); }
1103 
1104  int rpmLog( rpmlogRec rec_r )
1105  {
1106  std::string l { ::rpmlogRecMessage( rec_r ) }; // NL terminated line!
1107  l.pop_back(); // strip trailing NL
1108  push_back( std::move(l) );
1109  return 0;
1110  }
1111 
1112  private:
1113  int _oldMask = 0;
1114  };
1115 
1116  std::ostream & operator<<( std::ostream & str, const RpmlogCapture & obj )
1117  {
1118  char sep = '\0';
1119  for ( const auto & l : obj ) {
1120  if ( sep ) str << sep; else sep = '\n';
1121  str << l;
1122  }
1123  return str;
1124  }
1125 
1126 
1127  RpmDb::CheckPackageResult doCheckPackageSig( const Pathname & path_r, // rpm file to check
1128  const Pathname & root_r, // target root
1129  bool requireGPGSig_r, // whether no gpg signature is to be reported
1130  RpmDb::CheckPackageDetail & detail_r ) // detailed result
1131  {
1132  PathInfo file( path_r );
1133  if ( ! file.isFile() )
1134  {
1135  ERR << "Not a file: " << file << endl;
1136  return RpmDb::CHK_ERROR;
1137  }
1138 
1139  FD_t fd = ::Fopen( file.asString().c_str(), "r.ufdio" );
1140  if ( fd == 0 || ::Ferror(fd) )
1141  {
1142  ERR << "Can't open file for reading: " << file << " (" << ::Fstrerror(fd) << ")" << endl;
1143  if ( fd )
1144  ::Fclose( fd );
1145  return RpmDb::CHK_ERROR;
1146  }
1147  rpmts ts = ::rpmtsCreate();
1148  ::rpmtsSetRootDir( ts, root_r.c_str() );
1149  ::rpmtsSetVSFlags( ts, RPMVSF_DEFAULT );
1150 #ifdef HAVE_RPM_VERIFY_TRANSACTION_STEP
1151  ::rpmtsSetVfyFlags( ts, RPMVSF_DEFAULT );
1152 #endif
1153 
1154  RpmlogCapture vresult;
1155  LocaleGuard guard( LC_ALL, "C" ); // bsc#1076415: rpm log output is localized, but we need to parse it :(
1156  static rpmQVKArguments_s qva = ([](){ rpmQVKArguments_s qva; memset( &qva, 0, sizeof(rpmQVKArguments_s) ); return qva; })();
1157  int res = ::rpmVerifySignatures( &qva, ts, fd, path_r.basename().c_str() );
1158  guard.restore();
1159 
1160  ts = rpmtsFree(ts);
1161  ::Fclose( fd );
1162 
1163  // Check the individual signature/disgest results:
1164 
1165  // To.map back known result strings to enum, everything else is CHK_ERROR.
1166  typedef std::map<std::string_view,RpmDb::CheckPackageResult> ResultMap;
1167  static const ResultMap resultMap {
1168  { "OK", RpmDb::CHK_OK },
1169  { "NOKEY", RpmDb::CHK_NOKEY },
1170  { "BAD", RpmDb::CHK_FAIL },
1171  { "UNKNOWN", RpmDb::CHK_NOTFOUND },
1172  { "NOTRUSTED", RpmDb::CHK_NOTTRUSTED },
1173  { "NOTFOUND", RpmDb::CHK_NOTFOUND },
1174  };
1175  auto getresult = []( const ResultMap & resultMap, ResultMap::key_type key )->ResultMap::mapped_type {
1176  auto it = resultMap.find( key );
1177  return it != resultMap.end() ? it->second : RpmDb::CHK_ERROR;
1178  };
1179 
1180  // To track the signature states we saw.
1181  unsigned count[7] = { 0, 0, 0, 0, 0, 0, 0 };
1182 
1183  // To track the kind off sigs we saw.
1184  enum Saw {
1185  SawNone = 0,
1186  SawHeaderSig = (1 << 0), // Header V3 RSA/SHA256 Signature, key ID 3dbdc284: OK
1187  SawHeaderDigest = (1 << 1), // Header SHA1 digest: OK (a60386347863affefef484ff1f26c889373eb094)
1188  SawPayloadDigest = (1 << 2), // Payload SHA256 digest: OK
1189  SawSig = (1 << 3), // V3 RSA/SHA256 Signature, key ID 3dbdc284: OK
1190  SawDigest = (1 << 4), // MD5 digest: OK (fd5259fe677a406951dcb2e9d08c4dcc)
1191  };
1192  unsigned saw = SawNone;
1193 
1194  static const str::regex rx( "^ *(Header|Payload)? .*(Signature, key|digest).*: ([A-Z]+)" );
1195  str::smatch what;
1196  for ( const std::string & line : vresult )
1197  {
1198  if ( line[0] != ' ' ) // result lines are indented
1199  continue;
1200 
1202  if ( str::regex_match( line, what, rx ) ) {
1203 
1204  lineres = getresult( resultMap, what[3] );
1205  if ( lineres == RpmDb::CHK_NOTFOUND )
1206  continue; // just collect details for signatures found (#229)
1207 
1208  if ( what[1][0] == 'H' ) {
1209  saw |= ( what[2][0] == 'S' ? SawHeaderSig :SawHeaderDigest );
1210  }
1211  else if ( what[1][0] == 'P' ) {
1212  if ( what[2][0] == 'd' ) saw |= SawPayloadDigest;
1213  }
1214  else {
1215  saw |= ( what[2][0] == 'S' ? SawSig : SawDigest );
1216  }
1217  }
1218 
1219  ++count[lineres];
1220  detail_r.push_back( RpmDb::CheckPackageDetail::value_type( lineres, line ) );
1221  }
1222 
1223  // Now combine the overall result:
1225 
1226  if ( count[RpmDb::CHK_FAIL] )
1227  ret = RpmDb::CHK_FAIL;
1228 
1229  else if ( count[RpmDb::CHK_NOTFOUND] )
1230  ret = RpmDb::CHK_NOTFOUND;
1231 
1232  else if ( count[RpmDb::CHK_NOKEY] )
1233  ret = RpmDb::CHK_NOKEY;
1234 
1235  else if ( count[RpmDb::CHK_NOTTRUSTED] )
1236  ret = RpmDb::CHK_NOTTRUSTED;
1237 
1238  else if ( ret == RpmDb::CHK_OK ) {
1239  // Everything is OK, so check whether it's sufficient.
1240  // bsc#1184501: To count as signed the package needs a header signature
1241  // and either a payload digest (secured by the header sig) or a content signature.
1242  bool isSigned = (saw & SawHeaderSig) && ( (saw & SawPayloadDigest) || (saw & SawSig) );
1243  if ( not isSigned ) {
1244  std::string message { " " };
1245  if ( not (saw & SawHeaderSig) )
1246  message += _("Package header is not signed!");
1247  else
1248  message += _("Package payload is not signed!");
1249 
1250  detail_r.push_back( RpmDb::CheckPackageDetail::value_type( RpmDb::CHK_NOSIG, std::move(message) ) );
1251  if ( requireGPGSig_r )
1252  ret = RpmDb::CHK_NOSIG;
1253  }
1254  }
1255 
1256  if ( ret != RpmDb::CHK_OK )
1257  {
1258  // In case of an error line results may be reported to the user. In case rpm printed
1259  // only 8byte key IDs to stdout we try to get longer IDs from the header.
1260  bool didReadHeader = false;
1261  std::unordered_map< std::string, std::string> fprs;
1262 
1263  // we replace the data only if the key IDs are actually only 8 bytes
1264  str::regex rxexpr( "key ID ([a-fA-F0-9]{8}):" );
1265  for ( auto &detail : detail_r ) {
1266  auto &line = detail.second;
1267  str::smatch what;
1268  if ( str::regex_match( line, what, rxexpr ) ) {
1269 
1270  if ( !didReadHeader ) {
1271  didReadHeader = true;
1272 
1273  // Get signature info from the package header, RPM always prints only the 8 byte ID
1274  auto header = RpmHeader::readPackage( path_r, RpmHeader::NOVERIFY );
1275  if ( header ) {
1276  auto keyMgr = zypp::KeyManagerCtx::createForOpenPGP();
1277  const auto &addFprs = [&]( auto tag ){
1278  const auto &list1 = keyMgr.readSignatureFingerprints( header->blob_val( tag ) );
1279  for ( const auto &id : list1 ) {
1280  if ( id.size() <= 8 )
1281  continue;
1282 
1283  const auto &lowerId = str::toLower( id );
1284  fprs.insert( std::make_pair( lowerId.substr( lowerId.size() - 8 ), lowerId ) );
1285  }
1286  };
1287 
1288  addFprs( RPMTAG_SIGGPG );
1289  addFprs( RPMTAG_SIGPGP );
1290  addFprs( RPMTAG_RSAHEADER );
1291  addFprs( RPMTAG_DSAHEADER );
1292 
1293  } else {
1294  ERR << "Failed to read package signatures." << std::endl;
1295  }
1296  }
1297 
1298  // if we have no keys we can substitute we can leave the loop right away
1299  if ( !fprs.size() )
1300  break;
1301 
1302  {
1303  // replace the short key ID with the long ones parsed from the header
1304  const auto &keyId = str::toLower( what[1] );
1305  if ( const auto &i = fprs.find( keyId ); i != fprs.end() ) {
1306  str::replaceAll( line, keyId, i->second );
1307  }
1308  }
1309  }
1310  }
1311 
1312  WAR << path_r << " (" << requireGPGSig_r << " -> " << ret << ")" << endl;
1313  WAR << vresult << endl;
1314  }
1315  else
1316  DBG << path_r << " [0-Signature is OK]" << endl;
1317  return ret;
1318  }
1319 
1320 } // namespace
1322 //
1323 // METHOD NAME : RpmDb::checkPackage
1324 // METHOD TYPE : RpmDb::CheckPackageResult
1325 //
1327 { return doCheckPackageSig( path_r, root(), false/*requireGPGSig_r*/, detail_r ); }
1328 
1330 { CheckPackageDetail dummy; return checkPackage( path_r, dummy ); }
1331 
1333 { return doCheckPackageSig( path_r, root(), true/*requireGPGSig_r*/, detail_r ); }
1334 
1335 
1336 // determine changed files of installed package
1337 bool
1338 RpmDb::queryChangedFiles(FileList & fileList, const std::string& packageName)
1339 {
1340  bool ok = true;
1341 
1342  fileList.clear();
1343 
1344  if ( ! initialized() ) return false;
1345 
1346  RpmArgVec opts;
1347 
1348  opts.push_back ("-V");
1349  opts.push_back ("--nodeps");
1350  opts.push_back ("--noscripts");
1351  opts.push_back ("--nomd5");
1352  opts.push_back ("--");
1353  opts.push_back (packageName.c_str());
1354 
1356 
1357  if ( process == NULL )
1358  return false;
1359 
1360  /* from rpm manpage
1361  5 MD5 sum
1362  S File size
1363  L Symlink
1364  T Mtime
1365  D Device
1366  U User
1367  G Group
1368  M Mode (includes permissions and file type)
1369  */
1370 
1371  std::string line;
1372  while (systemReadLine(line))
1373  {
1374  if (line.length() > 12 &&
1375  (line[0] == 'S' || line[0] == 's' ||
1376  (line[0] == '.' && line[7] == 'T')))
1377  {
1378  // file has been changed
1379  std::string filename;
1380 
1381  filename.assign(line, 11, line.length() - 11);
1382  fileList.insert(filename);
1383  }
1384  }
1385 
1386  systemStatus();
1387  // exit code ignored, rpm returns 1 no matter if package is installed or
1388  // not
1389 
1390  return ok;
1391 }
1392 
1393 
1394 /****************************************************************/
1395 /* private member-functions */
1396 /****************************************************************/
1397 
1398 /*--------------------------------------------------------------*/
1399 /* Run rpm with the specified arguments, handling stderr */
1400 /* as specified by disp */
1401 /*--------------------------------------------------------------*/
1402 void
1405 {
1406  if ( process )
1407  {
1408  delete process;
1409  process = NULL;
1410  }
1411  exit_code = -1;
1412 
1413  if ( ! initialized() )
1414  {
1416  }
1417 
1418  RpmArgVec args;
1419 
1420  // always set root and dbpath
1421 #if defined(WORKAROUNDRPMPWDBUG)
1422  args.push_back("#/"); // chdir to / to workaround bnc#819354
1423 #endif
1424  args.push_back("rpm");
1425  args.push_back("--root");
1426  args.push_back(_root.asString().c_str());
1427  args.push_back("--dbpath");
1428  args.push_back(_dbPath.asString().c_str());
1429  if ( env::ZYPP_RPM_DEBUG() )
1430  args.push_back("-vv");
1431  const char* argv[args.size() + opts.size() + 1];
1432 
1433  const char** p = argv;
1434  p = copy (args.begin (), args.end (), p);
1435  p = copy (opts.begin (), opts.end (), p);
1436  *p = 0;
1437 
1438 #if 0 // if this is needed we need to forcefully close the db of running db_const_iterators
1439  // Invalidate all outstanding database handles in case
1440  // the database gets modified.
1441  librpmDb::dbRelease( true );
1442 #endif
1443 
1444  // Launch the program with default locale
1445  process = new ExternalProgram(argv, disp, false, -1, true);
1446  return;
1447 }
1448 
1449 /*--------------------------------------------------------------*/
1450 /* Read a line from the rpm process */
1451 /*--------------------------------------------------------------*/
1452 bool RpmDb::systemReadLine( std::string & line )
1453 {
1454  line.erase();
1455 
1456  if ( process == NULL )
1457  return false;
1458 
1459  if ( process->inputFile() )
1460  {
1461  process->setBlocking( false );
1462  FILE * inputfile = process->inputFile();
1463  do {
1464  // Check every 5 seconds if the process is still running to prevent against
1465  // daemons launched in rpm %post that do not close their filedescriptors,
1466  // causing us to block for infinity. (bnc#174548)
1467  const auto &readResult = io::receiveUpto( inputfile, '\n', 5 * 1000, false );
1468  switch ( readResult.first ) {
1470  if ( !process->running() )
1471  return false;
1472 
1473  // we might have received a partial line, lets not forget about it
1474  line += readResult.second;
1475  break;
1476  }
1479  line += readResult.second;
1480  if ( line.size() && line.back() == '\n')
1481  line.pop_back();
1482  return line.size(); // in case of pending output
1483  }
1485  line += readResult.second;
1486 
1487  if ( line.size() && line.back() == '\n')
1488  line.pop_back();
1489 
1490  if ( env::ZYPP_RPM_DEBUG() )
1491  L_DBG("RPM_DEBUG") << line << endl;
1492  return true; // complete line
1493  }
1494  }
1495  } while( true );
1496  }
1497  return false;
1498 }
1499 
1500 /*--------------------------------------------------------------*/
1501 /* Return the exit status of the rpm process, closing the */
1502 /* connection if not already done */
1503 /*--------------------------------------------------------------*/
1504 int
1506 {
1507  if ( process == NULL )
1508  return -1;
1509 
1510  exit_code = process->close();
1511  if (exit_code == 0)
1512  error_message = "";
1513  else
1515  process->kill();
1516  delete process;
1517  process = 0;
1518 
1519  // DBG << "exit code " << exit_code << endl;
1520 
1521  return exit_code;
1522 }
1523 
1524 /*--------------------------------------------------------------*/
1525 /* Forcably kill the rpm process */
1526 /*--------------------------------------------------------------*/
1527 void
1529 {
1530  if (process) process->kill();
1531 }
1532 
1533 
1534 // generate diff mails for config files
1535 void RpmDb::processConfigFiles(const std::string& line, const std::string& name, const char* typemsg, const char* difffailmsg, const char* diffgenmsg)
1536 {
1537  std::string msg = line.substr(9);
1538  std::string::size_type pos1 = std::string::npos;
1539  std::string::size_type pos2 = std::string::npos;
1540  std::string file1s, file2s;
1541  Pathname file1;
1542  Pathname file2;
1543 
1544  pos1 = msg.find (typemsg);
1545  for (;;)
1546  {
1547  if ( pos1 == std::string::npos )
1548  break;
1549 
1550  pos2 = pos1 + strlen (typemsg);
1551 
1552  if (pos2 >= msg.length() )
1553  break;
1554 
1555  file1 = msg.substr (0, pos1);
1556  file2 = msg.substr (pos2);
1557 
1558  file1s = file1.asString();
1559  file2s = file2.asString();
1560 
1561  if (!_root.empty() && _root != "/")
1562  {
1563  file1 = _root + file1;
1564  file2 = _root + file2;
1565  }
1566 
1567  std::string out;
1568  int ret = diffFiles (file1.asString(), file2.asString(), out, 25);
1569  if (ret)
1570  {
1571  Pathname file = _root + WARNINGMAILPATH;
1572  if (filesystem::assert_dir(file) != 0)
1573  {
1574  ERR << "Could not create " << file.asString() << endl;
1575  break;
1576  }
1577  file += Date(Date::now()).form("config_diff_%Y_%m_%d.log");
1578  std::ofstream notify(file.asString().c_str(), std::ios::out|std::ios::app);
1579  if (!notify)
1580  {
1581  ERR << "Could not open " << file << endl;
1582  break;
1583  }
1584 
1585  // Translator: %s = name of an rpm package. A list of diffs follows
1586  // this message.
1587  notify << str::form(_("Changed configuration files for %s:"), name.c_str()) << endl;
1588  if (ret>1)
1589  {
1590  ERR << "diff failed" << endl;
1591  notify << str::form(difffailmsg,
1592  file1s.c_str(), file2s.c_str()) << endl;
1593  }
1594  else
1595  {
1596  notify << str::form(diffgenmsg,
1597  file1s.c_str(), file2s.c_str()) << endl;
1598 
1599  // remove root for the viewer's pleasure (#38240)
1600  if (!_root.empty() && _root != "/")
1601  {
1602  if (out.substr(0,4) == "--- ")
1603  {
1604  out.replace(4, file1.asString().length(), file1s);
1605  }
1606  std::string::size_type pos = out.find("\n+++ ");
1607  if (pos != std::string::npos)
1608  {
1609  out.replace(pos+5, file2.asString().length(), file2s);
1610  }
1611  }
1612  notify << out << endl;
1613  }
1614  notify.close();
1615  notify.open("/var/lib/update-messages/yast2-packagemanager.rpmdb.configfiles");
1616  notify.close();
1617  }
1618  else
1619  {
1620  WAR << "rpm created " << file2 << " but it is not different from " << file2 << endl;
1621  }
1622  break;
1623  }
1624 }
1625 
1627 //
1628 // METHOD NAME : RpmDb::installPackage
1629 //
1630 void RpmDb::installPackage( const Pathname & filename, RpmInstFlags flags )
1631 { installPackage( filename, flags, nullptr ); }
1632 
1633 void RpmDb::installPackage( const Pathname & filename, RpmInstFlags flags, RpmPostTransCollector* postTransCollector_r )
1634 {
1635  if ( postTransCollector_r && postTransCollector_r->hasPosttransScript( filename ) )
1636  flags |= rpm::RPMINST_NOPOSTTRANS; // Just set the flag here. In \ref doInstallPackage we collect what else is needed.
1637 
1639 
1640  report->start(filename);
1641 
1642  do
1643  try
1644  {
1645  doInstallPackage( filename, flags, postTransCollector_r, report );
1646  report->finish();
1647  break;
1648  }
1649  catch (RpmException & excpt_r)
1650  {
1651  RpmInstallReport::Action user = report->problem( excpt_r );
1652 
1653  if ( user == RpmInstallReport::ABORT )
1654  {
1655  report->finish( excpt_r );
1656  ZYPP_RETHROW(excpt_r);
1657  }
1658  else if ( user == RpmInstallReport::IGNORE )
1659  {
1660  break;
1661  }
1662  }
1663  while (true);
1664 }
1665 
1666 void RpmDb::doInstallPackage( const Pathname & filename, RpmInstFlags flags, RpmPostTransCollector* postTransCollector_r, callback::SendReport<RpmInstallReport> & report )
1667 {
1669  HistoryLog historylog;
1670 
1671  MIL << "RpmDb::installPackage(" << filename << "," << flags << ")" << endl;
1672 
1673  // backup
1674  if ( _packagebackups )
1675  {
1676  // FIXME report->progress( pd.init( -2, 100 ) ); // allow 1% for backup creation.
1677  if ( ! backupPackage( filename ) )
1678  {
1679  ERR << "backup of " << filename.asString() << " failed" << endl;
1680  }
1681  // FIXME status handling
1682  report->progress( 0 ); // allow 1% for backup creation.
1683  }
1684 
1685  // run rpm
1686  RpmArgVec opts;
1687  if ( postTransCollector_r ) {
1688  opts.push_back("--define"); // bsc#1041742: Attempt to delay %transfiletrigger(postun|in) execution iff rpm supports it.
1689  opts.push_back("_dump_posttrans 1"); // Old rpm ignores the --define, new rpm injects 'dump_posttrans:' lines to collect and execute later.
1690  }
1691  if (flags & RPMINST_NOUPGRADE)
1692  opts.push_back("-i");
1693  else
1694  opts.push_back("-U");
1695 
1696  opts.push_back("--percent");
1697  opts.push_back("--noglob");
1698 
1699  // ZConfig defines cross-arch installation
1700  if ( ! ZConfig::instance().systemArchitecture().compatibleWith( ZConfig::instance().defaultSystemArchitecture() ) )
1701  opts.push_back("--ignorearch");
1702 
1703  if (flags & RPMINST_NODIGEST)
1704  opts.push_back("--nodigest");
1705  if (flags & RPMINST_NOSIGNATURE)
1706  opts.push_back("--nosignature");
1707  if (flags & RPMINST_EXCLUDEDOCS)
1708  opts.push_back ("--excludedocs");
1709  if (flags & RPMINST_NOSCRIPTS)
1710  opts.push_back ("--noscripts");
1711  if (flags & RPMINST_FORCE)
1712  opts.push_back ("--force");
1713  if (flags & RPMINST_NODEPS)
1714  opts.push_back ("--nodeps");
1715  if (flags & RPMINST_IGNORESIZE)
1716  opts.push_back ("--ignoresize");
1717  if (flags & RPMINST_JUSTDB)
1718  opts.push_back ("--justdb");
1719  if (flags & RPMINST_TEST)
1720  opts.push_back ("--test");
1721  if (flags & RPMINST_NOPOSTTRANS)
1722  opts.push_back ("--noposttrans");
1723 
1724  opts.push_back("--");
1725 
1726  // rpm requires additional quoting of special chars:
1727  std::string quotedFilename( rpmQuoteFilename( workaroundRpmPwdBug( filename ) ) );
1728  opts.push_back ( quotedFilename.c_str() );
1730 
1731  // forward additional rpm output via report;
1732  std::string line;
1733  unsigned lineno = 0;
1734  callback::UserData cmdout( InstallResolvableReport::contentRpmout );
1735  // Key "solvable" injected by RpmInstallPackageReceiver
1736  cmdout.set( "line", std::cref(line) );
1737  cmdout.set( "lineno", lineno );
1738 
1739  // LEGACY: collect and forward additional rpm output in finish
1740  std::string rpmmsg;
1741  std::vector<std::string> configwarnings; // TODO: immediately process lines rather than collecting
1742  std::vector<std::string> runposttrans; // bsc#1041742: If rpm supports --runposttrans it injects 'dump_posttrans:' lines we do collect
1743 
1744  while ( systemReadLine( line ) )
1745  {
1746  if ( str::startsWith( line, "%%" ) )
1747  {
1748  int percent = 0;
1749  sscanf( line.c_str() + 2, "%d", &percent );
1750  report->progress( percent );
1751  continue;
1752  }
1753  if ( str::hasPrefix( line, "dump_posttrans:" ) ) {
1754  runposttrans.push_back( line );
1755  continue;
1756  }
1757  ++lineno;
1758  cmdout.set( "lineno", lineno );
1759  report->report( cmdout );
1760 
1761  if ( lineno >= MAXRPMMESSAGELINES ) {
1762  if ( line.find( " scriptlet failed, " ) == std::string::npos ) // always log %script errors
1763  continue;
1764  }
1765 
1766  rpmmsg += line+'\n';
1767 
1768  if ( str::startsWith( line, "warning:" ) )
1769  configwarnings.push_back(line);
1770  }
1771  if ( lineno >= MAXRPMMESSAGELINES )
1772  rpmmsg += "[truncated]\n";
1773 
1774  int rpm_status = systemStatus();
1775  if ( postTransCollector_r && rpm_status == 0 ) {
1776  // Before doing anything else, handle any pending %posttrans script or dump_posttrans lines.
1777  postTransCollector_r->collectPosttransInfo( filename, runposttrans );
1778  }
1779 
1780  // evaluate result
1781  for (std::vector<std::string>::iterator it = configwarnings.begin();
1782  it != configwarnings.end(); ++it)
1783  {
1784  processConfigFiles(*it, Pathname::basename(filename), " saved as ",
1785  // %s = filenames
1786  _("rpm saved %s as %s, but it was impossible to determine the difference"),
1787  // %s = filenames
1788  _("rpm saved %s as %s.\nHere are the first 25 lines of difference:\n"));
1789  processConfigFiles(*it, Pathname::basename(filename), " created as ",
1790  // %s = filenames
1791  _("rpm created %s as %s, but it was impossible to determine the difference"),
1792  // %s = filenames
1793  _("rpm created %s as %s.\nHere are the first 25 lines of difference:\n"));
1794  }
1795 
1796  if ( rpm_status != 0 )
1797  {
1798  historylog.comment(
1799  str::form("%s install failed", Pathname::basename(filename).c_str()),
1800  true /*timestamp*/);
1801  std::ostringstream sstr;
1802  sstr << "rpm output:" << endl << rpmmsg << endl;
1803  historylog.comment(sstr.str());
1804  // TranslatorExplanation the colon is followed by an error message
1805  auto excpt { RpmSubprocessException(_("RPM failed: ") + error_message ) };
1806  if ( not rpmmsg.empty() )
1807  excpt.addHistory( rpmmsg );
1808  ZYPP_THROW(excpt);
1809  }
1810  else if ( ! rpmmsg.empty() )
1811  {
1812  historylog.comment(
1813  str::form("%s installed ok", Pathname::basename(filename).c_str()),
1814  true /*timestamp*/);
1815  std::ostringstream sstr;
1816  sstr << "Additional rpm output:" << endl << rpmmsg << endl;
1817  historylog.comment(sstr.str());
1818 
1819  // report additional rpm output in finish (LEGACY! Lines are immediately reported as InstallResolvableReport::contentRpmout)
1820  // TranslatorExplanation Text is followed by a ':' and the actual output.
1821  report->finishInfo(str::form( "%s:\n%s\n", _("Additional rpm output"), rpmmsg.c_str() ));
1822  }
1823 }
1824 
1826 //
1827 // METHOD NAME : RpmDb::removePackage
1828 //
1829 void RpmDb::removePackage( Package::constPtr package, RpmInstFlags flags )
1830 { removePackage( std::move(package), flags, nullptr ); }
1831 
1832 void RpmDb::removePackage( const std::string & name_r, RpmInstFlags flags )
1833 { removePackage( name_r, flags, nullptr ); }
1834 
1835 void RpmDb::removePackage( const Package::constPtr& package, RpmInstFlags flags, RpmPostTransCollector* postTransCollector_r )
1836 { // 'rpm -e' does not like epochs
1837  removePackage( package->name()
1838  + "-" + package->edition().version()
1839  + "-" + package->edition().release()
1840  + "." + package->arch().asString(), flags, postTransCollector_r );
1841 }
1842 
1843 void RpmDb::removePackage( const std::string & name_r, RpmInstFlags flags, RpmPostTransCollector* postTransCollector_r )
1844 {
1846 
1847  report->start( name_r );
1848 
1849  do
1850  try
1851  {
1852  doRemovePackage( name_r, flags, postTransCollector_r, report );
1853  report->finish();
1854  break;
1855  }
1856  catch (RpmException & excpt_r)
1857  {
1858  RpmRemoveReport::Action user = report->problem( excpt_r );
1859 
1860  if ( user == RpmRemoveReport::ABORT )
1861  {
1862  report->finish( excpt_r );
1863  ZYPP_RETHROW(excpt_r);
1864  }
1865  else if ( user == RpmRemoveReport::IGNORE )
1866  {
1867  break;
1868  }
1869  }
1870  while (true);
1871 }
1872 
1873 void RpmDb::doRemovePackage( const std::string & name_r, RpmInstFlags flags, RpmPostTransCollector* postTransCollector_r, callback::SendReport<RpmRemoveReport> & report )
1874 {
1876  HistoryLog historylog;
1877 
1878  MIL << "RpmDb::doRemovePackage(" << name_r << "," << flags << ")" << endl;
1879 
1880  // backup
1881  if ( _packagebackups )
1882  {
1883  // FIXME solve this status report somehow
1884  // report->progress( pd.init( -2, 100 ) ); // allow 1% for backup creation.
1885  if ( ! backupPackage( name_r ) )
1886  {
1887  ERR << "backup of " << name_r << " failed" << endl;
1888  }
1889  report->progress( 0 );
1890  }
1891  else
1892  {
1893  report->progress( 100 );
1894  }
1895 
1896  // run rpm
1897  RpmArgVec opts;
1898  if ( postTransCollector_r ) {
1899  opts.push_back("--define"); // bsc#1041742: Attempt to delay %transfiletrigger(postun|in) execution iff rpm supports it.
1900  opts.push_back("_dump_posttrans 1"); // Old rpm ignores the --define, new rpm injects 'dump_posttrans:' lines to collect and execute later.
1901  }
1902  opts.push_back("-e");
1903  opts.push_back("--allmatches");
1904 
1905  if (flags & RPMINST_NOSCRIPTS)
1906  opts.push_back("--noscripts");
1907  if (flags & RPMINST_NODEPS)
1908  opts.push_back("--nodeps");
1909  if (flags & RPMINST_JUSTDB)
1910  opts.push_back("--justdb");
1911  if (flags & RPMINST_TEST)
1912  opts.push_back ("--test");
1913  if (flags & RPMINST_FORCE)
1914  {
1915  WAR << "IGNORE OPTION: 'rpm -e' does not support '--force'" << endl;
1916  }
1917 
1918  opts.push_back("--");
1919  opts.push_back(name_r.c_str());
1921 
1922  // forward additional rpm output via report;
1923  std::string line;
1924  unsigned lineno = 0;
1925  callback::UserData cmdout( RemoveResolvableReport::contentRpmout );
1926  // Key "solvable" injected by RpmInstallPackageReceiver
1927  cmdout.set( "line", std::cref(line) );
1928  cmdout.set( "lineno", lineno );
1929 
1930 
1931  // LEGACY: collect and forward additional rpm output in finish
1932  std::string rpmmsg;
1933  std::vector<std::string> runposttrans; // bsc#1041742: If rpm supports --runposttrans it injects 'dump_posttrans:' lines we do collect
1934 
1935  // got no progress from command, so we fake it:
1936  // 5 - command started
1937  // 50 - command completed
1938  // 100 if no error
1939  report->progress( 5 );
1940  while (systemReadLine(line))
1941  {
1942  if ( str::hasPrefix( line, "dump_posttrans:" ) ) {
1943  runposttrans.push_back( line );
1944  continue;
1945  }
1946  ++lineno;
1947  cmdout.set( "lineno", lineno );
1948  report->report( cmdout );
1949 
1950  if ( lineno >= MAXRPMMESSAGELINES ) {
1951  if ( line.find( " scriptlet failed, " ) == std::string::npos ) // always log %script errors
1952  continue;
1953  }
1954  rpmmsg += line+'\n';
1955  }
1956  if ( lineno >= MAXRPMMESSAGELINES )
1957  rpmmsg += "[truncated]\n";
1958  report->progress( 50 );
1959  int rpm_status = systemStatus();
1960  if ( postTransCollector_r && rpm_status == 0 ) {
1961  // Before doing anything else, handle any pending %posttrans script or dump_posttrans lines.
1962  // 'remove' does not trigger %posttrans, but it may trigger %transfiletriggers.
1963  postTransCollector_r->collectPosttransInfo( runposttrans );
1964  }
1965 
1966  if ( rpm_status != 0 )
1967  {
1968  historylog.comment(
1969  str::form("%s remove failed", name_r.c_str()), true /*timestamp*/);
1970  std::ostringstream sstr;
1971  sstr << "rpm output:" << endl << rpmmsg << endl;
1972  historylog.comment(sstr.str());
1973  // TranslatorExplanation the colon is followed by an error message
1974  auto excpt { RpmSubprocessException(_("RPM failed: ") + error_message ) };
1975  if ( not rpmmsg.empty() )
1976  excpt.addHistory( rpmmsg );
1977  ZYPP_THROW(excpt);
1978  }
1979  else if ( ! rpmmsg.empty() )
1980  {
1981  historylog.comment(
1982  str::form("%s removed ok", name_r.c_str()), true /*timestamp*/);
1983 
1984  std::ostringstream sstr;
1985  sstr << "Additional rpm output:" << endl << rpmmsg << endl;
1986  historylog.comment(sstr.str());
1987 
1988  // report additional rpm output in finish (LEGACY! Lines are immediately reported as RemoveResolvableReport::contentRpmout)
1989  // TranslatorExplanation Text is followed by a ':' and the actual output.
1990  report->finishInfo(str::form( "%s:\n%s\n", _("Additional rpm output"), rpmmsg.c_str() ));
1991  }
1992 }
1993 
1995 //
1996 // METHOD NAME : RpmDb::runposttrans
1997 //
1998 int RpmDb::runposttrans( const Pathname & filename_r, const std::function<void(const std::string&)>& output_r )
1999 {
2001  HistoryLog historylog;
2002 
2003  MIL << "RpmDb::runposttrans(" << filename_r << ")" << endl;
2004 
2005  RpmArgVec opts;
2006  opts.push_back("-vv"); // want vverbose output to see scriptlet execution in the log
2007  opts.push_back("--runposttrans");
2008  opts.push_back(filename_r.c_str());
2010 
2011  // Tailored to suit RpmPostTransCollector.
2012  // It's a pity, but we need all those verbose debug lines just
2013  // to figure out which script is currently executed. Otherwise we
2014  // can't tell which output belongs to which script.
2015  static const str::regex rx( "^D: (%.*): scriptlet start$" );
2016  str::smatch what;
2017  std::string line;
2018  bool silent = true; // discard everything before 1st scriptlet
2019  while ( systemReadLine(line) )
2020  {
2021  if ( not output_r )
2022  continue;
2023 
2024  if ( str::startsWith( line, "D:" ) ) { // rpm debug output
2025  if ( str::regex_match( line, what, rx ) ) {
2026  // forward ripoff header
2027  output_r( "RIPOFF:"+what[1] );
2028  if ( silent )
2029  silent = false;
2030  }
2031  continue;
2032  }
2033  if ( silent ) {
2034  continue;
2035  }
2036  if ( str::startsWith( line, "+ " ) ) { // shell -x debug output
2037  continue;
2038  }
2039  // forward output line
2040  output_r( line );
2041  }
2042 
2043  int rpm_status = systemStatus();
2044  if ( rpm_status != 0 ) {
2045  WAR << "rpm --runposttrans returned " << rpm_status << endl;
2046  }
2047  return rpm_status;
2048 }
2049 
2051 //
2052 //
2053 // METHOD NAME : RpmDb::backupPackage
2054 // METHOD TYPE : bool
2055 //
2056 bool RpmDb::backupPackage( const Pathname & filename )
2057 {
2059  if ( ! h )
2060  return false;
2061 
2062  return backupPackage( h->tag_name() );
2063 }
2064 
2066 //
2067 //
2068 // METHOD NAME : RpmDb::backupPackage
2069 // METHOD TYPE : bool
2070 //
2071 bool RpmDb::backupPackage(const std::string& packageName)
2072 {
2073  HistoryLog progresslog;
2074  bool ret = true;
2075  Pathname backupFilename;
2076  Pathname filestobackupfile = _root+_backuppath+FILEFORBACKUPFILES;
2077 
2078  if (_backuppath.empty())
2079  {
2080  INT << "_backuppath empty" << endl;
2081  return false;
2082  }
2083 
2085 
2086  if (!queryChangedFiles(fileList, packageName))
2087  {
2088  ERR << "Error while getting changed files for package " <<
2089  packageName << endl;
2090  return false;
2091  }
2092 
2093  if (fileList.size() <= 0)
2094  {
2095  DBG << "package " << packageName << " not changed -> no backup" << endl;
2096  return true;
2097  }
2098 
2100  {
2101  return false;
2102  }
2103 
2104  {
2105  // build up archive name
2106  time_t currentTime = time(0);
2107  struct tm *currentLocalTime = localtime(&currentTime);
2108 
2109  int date = (currentLocalTime->tm_year + 1900) * 10000
2110  + (currentLocalTime->tm_mon + 1) * 100
2111  + currentLocalTime->tm_mday;
2112 
2113  int num = 0;
2114  do
2115  {
2116  backupFilename = _root + _backuppath
2117  + str::form("%s-%d-%d.tar.gz",packageName.c_str(), date, num);
2118 
2119  }
2120  while ( PathInfo(backupFilename).isExist() && num++ < 1000);
2121 
2122  PathInfo pi(filestobackupfile);
2123  if (pi.isExist() && !pi.isFile())
2124  {
2125  ERR << filestobackupfile.asString() << " already exists and is no file" << endl;
2126  return false;
2127  }
2128 
2129  std::ofstream fp ( filestobackupfile.asString().c_str(), std::ios::out|std::ios::trunc );
2130 
2131  if (!fp)
2132  {
2133  ERR << "could not open " << filestobackupfile.asString() << endl;
2134  return false;
2135  }
2136 
2137  for (FileList::const_iterator cit = fileList.begin();
2138  cit != fileList.end(); ++cit)
2139  {
2140  std::string name = *cit;
2141  if ( name[0] == '/' )
2142  {
2143  // remove slash, file must be relative to -C parameter of tar
2144  name = name.substr( 1 );
2145  }
2146  DBG << "saving file "<< name << endl;
2147  fp << name << endl;
2148  }
2149  fp.close();
2150 
2151  const char* const argv[] =
2152  {
2153  "tar",
2154  "-czhP",
2155  "-C",
2156  _root.asString().c_str(),
2157  "--ignore-failed-read",
2158  "-f",
2159  backupFilename.asString().c_str(),
2160  "-T",
2161  filestobackupfile.asString().c_str(),
2162  NULL
2163  };
2164 
2165  // execute tar in inst-sys (we dont know if there is a tar below _root !)
2166  ExternalProgram tar(argv, ExternalProgram::Stderr_To_Stdout, false, -1, true);
2167 
2168  std::string tarmsg;
2169 
2170  // TODO: it is probably possible to start tar with -v and watch it adding
2171  // files to report progress
2172  for (std::string output = tar.receiveLine(); output.length() ;output = tar.receiveLine())
2173  {
2174  tarmsg+=output;
2175  }
2176 
2177  int ret = tar.close();
2178 
2179  if ( ret != 0)
2180  {
2181  ERR << "tar failed: " << tarmsg << endl;
2182  ret = false;
2183  }
2184  else
2185  {
2186  MIL << "tar backup ok" << endl;
2187  progresslog.comment(
2188  str::form(_("created backup %s"), backupFilename.asString().c_str())
2189  , /*timestamp*/true);
2190  }
2191 
2192  filesystem::unlink(filestobackupfile);
2193  }
2194 
2195  return ret;
2196 }
2197 
2199 {
2200  _backuppath = path;
2201 }
2202 
2203 std::ostream & operator<<( std::ostream & str, RpmDb::CheckPackageResult obj )
2204 {
2205  switch ( obj )
2206  {
2207 #define OUTS(E,S) case RpmDb::E: return str << "["<< (unsigned)obj << "-"<< S << "]"; break
2208  // translators: possible rpm package signature check result [brief]
2209  OUTS( CHK_OK, _("Signature is OK") );
2210  // translators: possible rpm package signature check result [brief]
2211  OUTS( CHK_NOTFOUND, _("Unknown type of signature") );
2212  // translators: possible rpm package signature check result [brief]
2213  OUTS( CHK_FAIL, _("Signature does not verify") );
2214  // translators: possible rpm package signature check result [brief]
2215  OUTS( CHK_NOTTRUSTED, _("Signature is OK, but key is not trusted") );
2216  // translators: possible rpm package signature check result [brief]
2217  OUTS( CHK_NOKEY, _("Signatures public key is not available") );
2218  // translators: possible rpm package signature check result [brief]
2219  OUTS( CHK_ERROR, _("File does not exist or signature can't be checked") );
2220  // translators: possible rpm package signature check result [brief]
2221  OUTS( CHK_NOSIG, _("File is unsigned") );
2222 #undef OUTS
2223  }
2224  return str << "UnknowSignatureCheckError("+str::numstring(obj)+")";
2225 }
2226 
2227 std::ostream & operator<<( std::ostream & str, const RpmDb::CheckPackageDetail & obj )
2228 {
2229  for ( const auto & el : obj )
2230  str << el.second << endl;
2231  return str;
2232 }
2233 
2234 } // namespace rpm
2235 } // namespace target
2236 } // namespace zypp
std::string toLower(const std::string &s)
Return lowercase version of s.
Definition: String.cc:178
Interface to gettext.
Interface to the rpm program.
Definition: RpmDb.h:50
#define MIL
Definition: Logger.h:100
TraitsType::constPtrType constPtr
Definition: Package.h:39
~RpmDb() override
Destructor.
Definition: RpmDb.cc:226
CheckPackageResult checkPackageSignature(const Pathname &path_r, CheckPackageDetail &detail_r)
Check signature of rpm file on disk (strict check returning CHK_NOSIG if file is unsigned).
Definition: RpmDb.cc:1332
bool hasRequiredBy(const std::string &tag_r) const
Return true if at least one package requires a certain tag.
Definition: RpmDb.cc:992
Namespace intended to collect all environment variables we use.
Definition: Env.h:22
zypp::ContentType ContentType
Definition: UserData.h:51
int assert_dir(const Pathname &path, unsigned mode)
Like &#39;mkdir -p&#39;.
Definition: PathInfo.cc:324
#define _(MSG)
Definition: Gettext.h:39
intrusive_ptr< const RpmHeader > constPtr
Definition: RpmHeader.h:65
void getData(const std::string &name_r, RpmHeader::constPtr &result_r) const
Get an installed packages data from rpmdb.
Definition: RpmDb.cc:1048
void sendTo(const ReceiverFnc &fnc_r)
Set ReceiverFnc.
Definition: progressdata.h:229
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:424
Regular expression.
Definition: Regex.h:94
bool kill()
Kill the program.
static ZConfig & instance()
Singleton ctor.
Definition: ZConfig.cc:925
Pathname _root
Root directory for all operations.
Definition: RpmDb.h:86
void trustedKeyRemoved(const PublicKey &key) override
Definition: RpmDb.cc:152
const std::string & execError() const
Some detail telling why the execution failed, if it failed.
void exportTrustedKeysInZyppKeyRing()
insert all rpm trusted keys into zypp trusted keyring
Definition: RpmDb.cc:654
#define INT
Definition: Logger.h:104
void doInstallPackage(const Pathname &filename, RpmInstFlags flags, RpmPostTransCollector *postTransCollector_r, callback::SendReport< RpmInstallReport > &report)
Definition: RpmDb.cc:1666
void rebuildDatabase()
Rebuild the rpm database (rpm –rebuilddb).
Definition: RpmDb.cc:351
void installPackage(const Pathname &filename, RpmInstFlags flags=RPMINST_NONE)
install rpm package
Definition: RpmDb.cc:1630
std::ostream & operator<<(std::ostream &str, const librpmDb::db_const_iterator &obj)
Definition: librpmDb.cc:412
void doRemovePackage(const std::string &name_r, RpmInstFlags flags, RpmPostTransCollector *postTransCollector_r, callback::SendReport< RpmRemoveReport > &report)
Definition: RpmDb.cc:1873
#define for_(IT, BEG, END)
Convenient for-loops using iterator.
Definition: Easy.h:27
const char * c_str() const
String representation.
Definition: Pathname.h:112
void addHistory(const std::string &msg_r)
Add some message text to the history.
Definition: Exception.cc:176
String related utilities and Regular expression matching.
bool toMax()
Set counter value to current max value (unless no range).
Definition: progressdata.h:276
static double currentTime()
std::vector< const char * > RpmArgVec
Definition: RpmDb.h:303
static librpmDb::constPtr dbOpenCreate(const Pathname &root_r, const Pathname &dbPath_r=Pathname())
Assert the rpmdb below the system at root_r exists.
Definition: librpmDb.cc:198
Pathname path() const
Definition: TmpPath.cc:152
Edition represents [epoch:]version[-release]
Definition: Edition.h:60
bool running()
Return whether program is running.
std::string receiveLine()
Read one line from the input stream.
long long value_type
Definition: progressdata.h:134
Convenient building of std::string with boost::format.
Definition: String.h:252
std::string basename() const
Return the last component of this path.
Definition: Pathname.h:130
Provide a new empty temporary file and delete it when no longer needed.
Definition: TmpPath.h:127
void importZyppKeyRingTrustedKeys()
iterates through zypp keyring and import all non-existent keys into rpm keyring
Definition: RpmDb.cc:651
std::string form(const char *format,...) __attribute__((format(printf
Printf style construction of std::string.
Definition: String.cc:37
bool backupPackage(const std::string &packageName)
create tar.gz of all changed files in a Package
Definition: RpmDb.cc:2071
Wrapper providing a librpmDb::db_const_iterator for this RpmDb.
Definition: RpmDb.h:64
void collectPosttransInfo(const Pathname &rpmPackage_r, const std::vector< std::string > &runposttrans_r)
Extract and remember a packages posttrans script or dump_posttrans lines for later execution...
std::string asString() const
Definition: String.h:262
#define ERR
Definition: Logger.h:102
CheckPackageResult checkPackage(const Pathname &path_r, CheckPackageDetail &detail_r)
Check signature of rpm file on disk (legacy version returning CHK_OK if file is unsigned, like &#39;rpm -K&#39;)
Definition: RpmDb.cc:1326
#define FILEFORBACKUPFILES
Definition: RpmDb.cc:64
void range(value_type max_r)
Set new [0,max].
Definition: progressdata.h:216
Extract and remember posttrans scripts for later execution.
Temporarily connect a ReceiveReport then restore the previous one.
Definition: Callback.h:284
void importPubkey(const PublicKey &pubkey_r)
Import ascii armored public key in file pubkey_r.
Definition: RpmDb.cc:663
bool hasPosttransScript(const Pathname &rpmPackage_r)
Test whether a package defines a posttrans script.
Assign a vaiable a certain value when going out of scope.
Definition: dtorreset.h:49
_dumpPath dumpPath(const Pathname &root_r, const Pathname &sub_r)
dumpPath iomaip to dump &#39;(root_r)sub_r&#39; output,
Definition: librpmDb.h:42
bool hasPackage(const std::string &name_r) const
Return true if package is installed.
Definition: RpmDb.cc:1020
void systemKill()
Forcably kill the system process.
Definition: RpmDb.cc:1528
bool empty() const
Test for an empty path.
Definition: Pathname.h:116
#define ZYPP_RETHROW(EXCPT)
Drops a logline and rethrows, updating the CodeLocation.
Definition: Exception.h:444
void moveToHistory(TContainer &&msgc_r)
addHistory from string container types (oldest first) moving
Definition: Exception.h:248
bool toMin()
Set counter value to current min value.
Definition: progressdata.h:272
void syncTrustedKeys(SyncTrustedKeyBits mode_r=SYNC_BOTH)
Sync trusted keys stored in rpm database and zypp trusted keyring.
Definition: RpmDb.cc:550
#define FAILIFNOTINITIALIZED
Definition: RpmDb.cc:197
Store and operate on date (time_t).
Definition: Date.h:32
Pathname _backuppath
/var/adm/backup
Definition: RpmDb.h:347
std::string version() const
Version.
Definition: Edition.cc:94
std::string form(const std::string &format_r) const
Return string representation according to format as localtime.
Definition: Date.h:112
std::string asString() const
Definition: IdStringType.h:108
int exit_code
The exit code of the rpm process, or -1 if not yet known.
Definition: RpmDb.h:338
std::list< PublicKey > pubkeys() const
Return the long ids of all installed public keys.
Definition: RpmDb.cc:843
void trustedKeyAdded(const PublicKey &key) override
Definition: RpmDb.cc:146
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:119
SyncTrustedKeyBits
Sync mode for syncTrustedKeys.
Definition: RpmDb.h:277
bool systemReadLine(std::string &line)
Read a line from the general rpm query.
Definition: RpmDb.cc:1452
const std::string & asString() const
String representation.
Definition: Pathname.h:93
#define WARNINGMAILPATH
Definition: RpmDb.cc:63
int systemStatus()
Return the exit status of the general rpm process, closing the connection if not already done...
Definition: RpmDb.cc:1505
std::set< Edition > pubkeyEditions() const
Return the edition of all installed public keys.
Definition: RpmDb.cc:881
bool isExist() const
Return whether valid stat info exists.
Definition: PathInfo.h:286
std::string asUserHistory() const
A single (multiline) string composed of asUserString and historyAsString.
Definition: Exception.cc:127
std::ostream & dumpOn(std::ostream &str) const override
Dump debug info.
Definition: RpmDb.cc:241
std::string release() const
Release.
Definition: Edition.cc:110
#define WAR
Definition: Logger.h:101
Detailed rpm signature check log messages A single multiline message if CHK_OK.
Definition: RpmDb.h:391
bool startsWith(const C_Str &str_r, const C_Str &prefix_r)
alias for hasPrefix
Definition: String.h:1085
Types and functions for filesystem operations.
Definition: Glob.cc:23
int close() override
Wait for the progamm to complete.
static shared_ptr< KeyRingSignalReceiver > sKeyRingReceiver
Definition: RpmDb.cc:161
Maintain [min,max] and counter (value) for progress counting.
Definition: progressdata.h:131
Pathname expandlink(const Pathname &path_r)
Recursively follows the symlink pointed to by path_r and returns the Pathname to the real file or dir...
Definition: PathInfo.cc:950
ExternalProgram * process
The connection to the rpm process.
Definition: RpmDb.h:301
Writing the zypp history fileReference counted signleton for writhing the zypp history file...
Definition: HistoryLog.h:56
void doRebuildDatabase(callback::SendReport< RebuildDBReport > &report)
Definition: RpmDb.cc:369
bool incr(value_type val_r=1)
Increment counter value (default by 1).
Definition: progressdata.h:264
void initDatabase(Pathname root_r=Pathname(), bool doRebuild_r=false)
Prepare access to the rpm database below root_r.
Definition: RpmDb.cc:260
void closeDatabase()
Block further access to the rpm database and go back to uninitialized state.
Definition: RpmDb.cc:331
Stderr_Disposition
Define symbols for different policies on the handling of stderr.
bool hasProvides(const std::string &tag_r) const
Return true if at least one package provides a certain tag.
Definition: RpmDb.cc:978
Just inherits Exception to separate media exceptions.
Definition: RpmException.h:38
static RpmHeader::constPtr readPackage(const Pathname &path, VERIFICATION verification=VERIFY)
Get an accessible packages data from disk.
Definition: RpmHeader.cc:212
bool endsWith(const C_Str &str_r, const C_Str &prefix_r)
alias for hasSuffix
Definition: String.h:1092
std::string numstring(char n, int w=0)
Definition: String.h:289
int unlink(const Pathname &path)
Like &#39;unlink&#39;.
Definition: PathInfo.cc:705
import zypp trusted keys into rpm database.
Definition: RpmDb.h:280
Editions with v-r setparator highlighted.
#define OUTS(E, S)
std::ostream & copy(std::istream &from_r, std::ostream &to_r)
Copy istream to ostream.
Definition: IOStream.h:51
void removePubkey(const PublicKey &pubkey_r)
Remove a public key from the rpm database.
Definition: RpmDb.cc:776
void processConfigFiles(const std::string &line, const std::string &name, const char *typemsg, const char *difffailmsg, const char *diffgenmsg)
handle rpm messages like "/etc/testrc saved as /etc/testrc.rpmorig"
Definition: RpmDb.cc:1535
#define L_DBG(GROUP)
Definition: Logger.h:108
bool _packagebackups
create package backups?
Definition: RpmDb.h:350
int symlink(const Pathname &oldpath, const Pathname &newpath)
Like &#39;symlink&#39;.
Definition: PathInfo.cc:860
#define ZYPP_CAUGHT(EXCPT)
Drops a logline telling the Exception was caught (in order to handle it).
Definition: Exception.h:440
bool ZYPP_RPM_DEBUG()
Definition: RpmDb.cc:80
Regular expression match result.
Definition: Regex.h:167
std::pair< ReceiveUpToResult, std::string > receiveUpto(FILE *file, char c, timeout_type timeout, bool failOnUnblockError)
Definition: IOTools.cc:85
constexpr std::string_view FILE("file")
unsigned diffFiles(const std::string &file1, const std::string &file2, std::string &out, int maxlines)
Definition: RpmDb.cc:163
Base class for Exception.
Definition: Exception.h:146
void setBackupPath(const Pathname &path)
set path where package backups are stored
Definition: RpmDb.cc:2198
const Pathname & root() const
Definition: RpmDb.h:109
bool hasConflicts(const std::string &tag_r) const
Return true if at least one package conflicts with a certain tag.
Definition: RpmDb.cc:1006
const Pathname & dbPath() const
Definition: RpmDb.h:117
static Date now()
Return the current time.
Definition: Date.h:78
std::string error_message
Error message from running rpm as external program.
Definition: RpmDb.h:344
std::string whoOwnsFile(const std::string &file_r) const
Return name of package owning file or empty string if no installed package owns file.
Definition: RpmDb.cc:960
void removePackage(const std::string &name_r, RpmInstFlags flags=RPMINST_NONE)
remove rpm package
Definition: RpmDb.cc:1832
static bool globalInit()
Initialize lib librpm (read configfiles etc.).
Definition: librpmDb.cc:139
std::list< FileInfo > fileList(const std::string &name_r, const Edition &edition_r) const
return complete file list for installed package name_r (in FileInfo.filename) if edition_r != Edition...
Definition: RpmDb.cc:905
Typesafe passing of user data via callbacks.
Definition: UserData.h:39
bool strToBool(const C_Str &str, bool default_r)
Parse str into a bool depending on the default value.
Definition: String.h:429
bool relative() const
Test for a relative path.
Definition: Pathname.h:120
value_type reportValue() const
Definition: progressdata.h:322
bool hasFile(const std::string &file_r, const std::string &name_r="") const
Return true if at least one package owns a certain file (name_r empty) Return true if package name_r ...
Definition: RpmDb.cc:934
void comment(const std::string &comment, bool timestamp=false)
Log a comment (even multiline).
Definition: HistoryLog.cc:190
Wrapper class for ::stat/::lstat.
Definition: PathInfo.h:225
void setBlocking(bool mode)
Set the blocking mode of the input stream.
CheckPackageResult
checkPackage result
Definition: RpmDb.h:376
bool regex_match(const std::string &s, smatch &matches, const regex &regex)
regex ZYPP_STR_REGEX regex ZYPP_STR_REGEX
Definition: Regex.h:70
int runposttrans(const Pathname &filename_r, const std::function< void(const std::string &)> &output_r)
Run collected posttrans and transfiletrigger(postun|in) if rpm --runposttrans is supported.
Definition: RpmDb.cc:1998
bool queryChangedFiles(FileList &fileList, const std::string &packageName)
determine which files of an installed package have been modified.
Definition: RpmDb.cc:1338
int _oldMask
Definition: RpmDb.cc:1113
std::set< std::string > FileList
Definition: RpmDb.h:370
FILE * inputFile() const
Return the input stream.
std::string & replaceAll(std::string &str_r, const std::string &from_r, const std::string &to_r)
Replace all occurrences of from_r with to_r in str_r (inplace).
Definition: String.cc:331
Easy-to use interface to the ZYPP dependency resolver.
Definition: Application.cc:19
static Pathname suggestedDbPath(const Pathname &root_r)
Definition: librpmDb.cc:171
SolvableIdType size_type
Definition: PoolMember.h:126
void run_rpm(const RpmArgVec &options, ExternalProgram::Stderr_Disposition stderr_disp=ExternalProgram::Stderr_To_Stdout)
Run rpm with the specified arguments and handle stderr.
Definition: RpmDb.cc:1403
bool hasPrefix(const C_Str &str_r, const C_Str &prefix_r)
Return whether str_r has prefix prefix_r.
Definition: String.h:1027
export rpm trusted keys into zypp trusted keyring
Definition: RpmDb.h:279
db_const_iterator dbConstIterator() const
Definition: RpmDb.cc:247
bool initialized() const
Definition: RpmDb.h:125
#define MAXRPMMESSAGELINES
Definition: RpmDb.cc:65
#define DBG
Definition: Logger.h:99
static const Edition noedition
Value representing noedition ("") This is in fact a valid Edition.
Definition: Edition.h:73
Pathname _dbPath
Directory that contains the rpmdb.
Definition: RpmDb.h:91