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