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