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