libzypp  15.21.4
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 
36 #include "zypp/Date.h"
37 #include "zypp/Pathname.h"
38 #include "zypp/PathInfo.h"
39 #include "zypp/PublicKey.h"
40 
41 #include "zypp/target/rpm/RpmDb.h"
43 
44 #include "zypp/HistoryLog.h"
47 #include "zypp/TmpPath.h"
48 #include "zypp/KeyRing.h"
49 #include "zypp/ZYppFactory.h"
50 #include "zypp/ZConfig.h"
51 
52 using std::endl;
53 using namespace zypp::filesystem;
54 
55 #define WARNINGMAILPATH "/var/log/YaST2/"
56 #define FILEFORBACKUPFILES "YaSTBackupModifiedFiles"
57 #define MAXRPMMESSAGELINES 10000
58 
59 #define WORKAROUNDRPMPWDBUG
60 
61 namespace zypp
62 {
63  namespace zypp_readonly_hack
64  {
65  bool IGotIt(); // in readonly-mode
66  }
67 namespace target
68 {
69 namespace rpm
70 {
71 namespace
72 {
73 #if 1 // No more need to escape whitespace since rpm-4.4.2.3
74 const char* quoteInFilename_m = "\'\"";
75 #else
76 const char* quoteInFilename_m = " \t\'\"";
77 #endif
78 inline std::string rpmQuoteFilename( const Pathname & path_r )
79 {
80  std::string path( path_r.asString() );
81  for ( std::string::size_type pos = path.find_first_of( quoteInFilename_m );
82  pos != std::string::npos;
83  pos = path.find_first_of( quoteInFilename_m, pos ) )
84  {
85  path.insert( pos, "\\" );
86  pos += 2; // skip '\\' and the quoted char.
87  }
88  return path;
89 }
90 
91 
96  inline Pathname workaroundRpmPwdBug( Pathname path_r )
97  {
98 #if defined(WORKAROUNDRPMPWDBUG)
99  if ( path_r.relative() )
100  {
101  // try to prepend cwd
102  AutoDispose<char*> cwd( ::get_current_dir_name(), ::free );
103  if ( cwd )
104  return Pathname( cwd ) / path_r;
105  WAR << "Can't get cwd!" << endl;
106  }
107 #endif
108  return path_r; // no problem with absolute pathnames
109  }
110 }
111 
113 {
114  KeyRingSignalReceiver(RpmDb &rpmdb) : _rpmdb(rpmdb)
115  {
116  connect();
117  }
118 
120  {
121  disconnect();
122  }
123 
124  virtual void trustedKeyAdded( const PublicKey &key )
125  {
126  MIL << "trusted key added to zypp Keyring. Importing" << endl;
127  // now import the key in rpm
128  try
129  {
130  _rpmdb.importPubkey( key );
131  }
132  catch (RpmException &e)
133  {
134  ERR << "Could not import key " << key.id() << " (" << key.name() << " from " << key.path() << " in rpm database" << endl;
135  }
136  }
137 
138  virtual void trustedKeyRemoved( const PublicKey &key )
139  {
140  MIL << "Trusted key removed from zypp Keyring. Removing..." << endl;
141 
142  // remove the key from rpm
143  try
144  {
145  _rpmdb.removePubkey( key );
146  }
147  catch (RpmException &e)
148  {
149  ERR << "Could not remove key " << key.id() << " (" << key.name() << ") from rpm database" << endl;
150  }
151  }
152 
154 };
155 
156 static shared_ptr<KeyRingSignalReceiver> sKeyRingReceiver;
157 
158 unsigned diffFiles(const std::string file1, const std::string file2, std::string& out, int maxlines)
159 {
160  const char* argv[] =
161  {
162  "diff",
163  "-u",
164  file1.c_str(),
165  file2.c_str(),
166  NULL
167  };
168  ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
169 
170  //if(!prog)
171  //return 2;
172 
173  std::string line;
174  int count = 0;
175  for (line = prog.receiveLine(), count=0;
176  !line.empty();
177  line = prog.receiveLine(), count++ )
178  {
179  if (maxlines<0?true:count<maxlines)
180  out+=line;
181  }
182 
183  return prog.close();
184 }
185 
186 
187 
188 /******************************************************************
189  **
190  **
191  ** FUNCTION NAME : stringPath
192  ** FUNCTION TYPE : inline std::string
193 */
194 inline std::string stringPath( const Pathname & root_r, const Pathname & sub_r )
195 {
196  return librpmDb::stringPath( root_r, sub_r );
197 }
198 
199 /******************************************************************
200  **
201  **
202  ** FUNCTION NAME : operator<<
203  ** FUNCTION TYPE : std::ostream &
204 */
205 std::ostream & operator<<( std::ostream & str, const RpmDb::DbStateInfoBits & obj )
206 {
207  if ( obj == RpmDb::DbSI_NO_INIT )
208  {
209  str << "NO_INIT";
210  }
211  else
212  {
213 #define ENUM_OUT(B,C) str << ( obj & RpmDb::B ? C : '-' )
214  str << "V4(";
215  ENUM_OUT( DbSI_HAVE_V4, 'X' );
216  ENUM_OUT( DbSI_MADE_V4, 'c' );
217  ENUM_OUT( DbSI_MODIFIED_V4, 'm' );
218  str << ")V3(";
219  ENUM_OUT( DbSI_HAVE_V3, 'X' );
220  ENUM_OUT( DbSI_HAVE_V3TOV4, 'B' );
221  ENUM_OUT( DbSI_MADE_V3TOV4, 'c' );
222  str << ")";
223 #undef ENUM_OUT
224  }
225  return str;
226 }
227 
228 
229 
231 //
232 // CLASS NAME : RpmDb
233 //
235 
236 #define FAILIFNOTINITIALIZED if( ! initialized() ) { ZYPP_THROW(RpmDbNotOpenException()); }
237 
239 
241 //
242 //
243 // METHOD NAME : RpmDb::RpmDb
244 // METHOD TYPE : Constructor
245 //
246 RpmDb::RpmDb()
247  : _dbStateInfo( DbSI_NO_INIT )
248 #warning Check for obsolete memebers
249  , _backuppath ("/var/adm/backup")
250  , _packagebackups(false)
251  , _warndirexists(false)
252 {
253  process = 0;
254  exit_code = -1;
256  // Some rpm versions are patched not to abort installation if
257  // symlink creation failed.
258  setenv( "RPM_IgnoreFailedSymlinks", "1", 1 );
259  sKeyRingReceiver.reset(new KeyRingSignalReceiver(*this));
260 }
261 
263 //
264 //
265 // METHOD NAME : RpmDb::~RpmDb
266 // METHOD TYPE : Destructor
267 //
269 {
270  MIL << "~RpmDb()" << endl;
271  closeDatabase();
272  delete process;
273  MIL << "~RpmDb() end" << endl;
274  sKeyRingReceiver.reset();
275 }
276 
278 {
279  Date ts_rpm;
280 
281  Pathname db_path;
282  if ( dbPath().empty() )
283  db_path = "/var/lib/rpm";
284  else
285  db_path = dbPath();
286 
287  PathInfo rpmdb_info(root() + db_path + "/Packages");
288 
289  if ( rpmdb_info.isExist() )
290  return rpmdb_info.mtime();
291  else
292  return Date::now();
293 }
295 //
296 //
297 // METHOD NAME : RpmDb::dumpOn
298 // METHOD TYPE : std::ostream &
299 //
300 std::ostream & RpmDb::dumpOn( std::ostream & str ) const
301 {
302  str << "RpmDb[";
303 
304  if ( _dbStateInfo == DbSI_NO_INIT )
305  {
306  str << "NO_INIT";
307  }
308  else
309  {
310 #define ENUM_OUT(B,C) str << ( _dbStateInfo & B ? C : '-' )
311  str << "V4(";
312  ENUM_OUT( DbSI_HAVE_V4, 'X' );
313  ENUM_OUT( DbSI_MADE_V4, 'c' );
314  ENUM_OUT( DbSI_MODIFIED_V4, 'm' );
315  str << ")V3(";
316  ENUM_OUT( DbSI_HAVE_V3, 'X' );
317  ENUM_OUT( DbSI_HAVE_V3TOV4, 'B' );
318  ENUM_OUT( DbSI_MADE_V3TOV4, 'c' );
319  str << "): " << stringPath( _root, _dbPath );
320 #undef ENUM_OUT
321  }
322  return str << "]";
323 }
324 
326 //
327 //
328 // METHOD NAME : RpmDb::initDatabase
329 // METHOD TYPE : PMError
330 //
331 void RpmDb::initDatabase( Pathname root_r, Pathname dbPath_r, bool doRebuild_r )
332 {
334  // Check arguments
336  bool quickinit( root_r.empty() );
337 
338  if ( root_r.empty() )
339  root_r = "/";
340 
341  if ( dbPath_r.empty() )
342  dbPath_r = "/var/lib/rpm";
343 
344  if ( ! (root_r.absolute() && dbPath_r.absolute()) )
345  {
346  ERR << "Illegal root or dbPath: " << stringPath( root_r, dbPath_r ) << endl;
347  ZYPP_THROW(RpmInvalidRootException(root_r, dbPath_r));
348  }
349 
350  MIL << "Calling initDatabase: " << stringPath( root_r, dbPath_r )
351  << ( doRebuild_r ? " (rebuilddb)" : "" )
352  << ( quickinit ? " (quickinit)" : "" ) << endl;
353 
355  // Check whether already initialized
357  if ( initialized() )
358  {
359  if ( root_r == _root && dbPath_r == _dbPath )
360  {
361  return;
362  }
363  else
364  {
365  ZYPP_THROW(RpmDbAlreadyOpenException(_root, _dbPath, root_r, dbPath_r));
366  }
367  }
368 
370  // init database
373 
374  if ( quickinit )
375  {
376  MIL << "QUICK initDatabase (no systemRoot set)" << endl;
377  return;
378  }
379 
381  try
382  {
383  internal_initDatabase( root_r, dbPath_r, info );
384  }
385  catch (const RpmException & excpt_r)
386  {
387  ZYPP_CAUGHT(excpt_r);
389  ERR << "Cleanup on error: state " << info << endl;
390 
391  if ( dbsi_has( info, DbSI_MADE_V4 ) )
392  {
393  // remove the newly created rpm4 database and
394  // any backup created on conversion.
395  removeV4( root_r + dbPath_r, dbsi_has( info, DbSI_MADE_V3TOV4 ) );
396  }
397  ZYPP_RETHROW(excpt_r);
398  }
399  if ( dbsi_has( info, DbSI_HAVE_V3 ) )
400  {
401  if ( root_r == "/" || dbsi_has( info, DbSI_MODIFIED_V4 ) )
402  {
403  // Move obsolete rpm3 database beside.
404  MIL << "Cleanup: state " << info << endl;
405  removeV3( root_r + dbPath_r, dbsi_has( info, DbSI_MADE_V3TOV4 ) );
406  dbsi_clr( info, DbSI_HAVE_V3 );
407  }
408  else
409  {
410  // Performing an update: Keep the original rpm3 database
411  // and wait if the rpm4 database gets modified by installing
412  // or removing packages. Cleanup in modifyDatabase or closeDatabase.
413  MIL << "Update mode: Cleanup delayed until closeOldDatabase." << endl;
414  }
415  }
416 #warning CHECK: notify root about conversion backup.
417 
418  _root = root_r;
419  _dbPath = dbPath_r;
420  _dbStateInfo = info;
421 
422  if ( doRebuild_r )
423  {
424  if ( dbsi_has( info, DbSI_HAVE_V4 )
425  && ! dbsi_has( info, DbSI_MADE_V4 ) )
426  {
427  rebuildDatabase();
428  }
429  }
430 
431  MIL << "Synchronizing keys with zypp keyring" << endl;
432  syncTrustedKeys();
433 
434  // Close the database in case any write acces (create/convert)
435  // happened during init. This should drop any lock acquired
436  // by librpm. On demand it will be reopened readonly and should
437  // not hold any lock.
438  librpmDb::dbRelease( true );
439 
440  MIL << "InitDatabase: " << *this << endl;
441 }
442 
444 //
445 //
446 // METHOD NAME : RpmDb::internal_initDatabase
447 // METHOD TYPE : PMError
448 //
449 void RpmDb::internal_initDatabase( const Pathname & root_r, const Pathname & dbPath_r,
450  DbStateInfoBits & info_r )
451 {
452  info_r = DbSI_NO_INIT;
453 
455  // Get info about the desired database dir
457  librpmDb::DbDirInfo dbInfo( root_r, dbPath_r );
458 
459  if ( dbInfo.illegalArgs() )
460  {
461  // should not happen (checked in initDatabase)
462  ZYPP_THROW(RpmInvalidRootException(root_r, dbPath_r));
463  }
464  if ( ! dbInfo.usableArgs() )
465  {
466  ERR << "Bad database directory: " << dbInfo.dbDir() << endl;
467  ZYPP_THROW(RpmInvalidRootException(root_r, dbPath_r));
468  }
469 
470  if ( dbInfo.hasDbV4() )
471  {
472  dbsi_set( info_r, DbSI_HAVE_V4 );
473  MIL << "Found rpm4 database in " << dbInfo.dbDir() << endl;
474  }
475  else
476  {
477  MIL << "Creating new rpm4 database in " << dbInfo.dbDir() << endl;
478  }
479 
480  if ( dbInfo.hasDbV3() )
481  {
482  dbsi_set( info_r, DbSI_HAVE_V3 );
483  }
484  if ( dbInfo.hasDbV3ToV4() )
485  {
486  dbsi_set( info_r, DbSI_HAVE_V3TOV4 );
487  }
488 
489  DBG << "Initial state: " << info_r << ": " << stringPath( root_r, dbPath_r );
490  librpmDb::dumpState( DBG ) << endl;
491 
493  // Access database, create if needed
495 
496  // creates dbdir and empty rpm4 database if not present
497  librpmDb::dbAccess( root_r, dbPath_r );
498 
499  if ( ! dbInfo.hasDbV4() )
500  {
501  dbInfo.restat();
502  if ( dbInfo.hasDbV4() )
503  {
504  dbsi_set( info_r, DbSI_HAVE_V4 | DbSI_MADE_V4 );
505  }
506  }
507 
508  DBG << "Access state: " << info_r << ": " << stringPath( root_r, dbPath_r );
509  librpmDb::dumpState( DBG ) << endl;
510 
512  // Check whether to convert something. Create backup but do
513  // not remove anything here
515  librpmDb::constPtr dbptr;
516  librpmDb::dbAccess( dbptr );
517  bool dbEmpty = dbptr->empty();
518  if ( dbEmpty )
519  {
520  MIL << "Empty rpm4 database " << dbInfo.dbV4() << endl;
521  }
522 
523  if ( dbInfo.hasDbV3() )
524  {
525  MIL << "Found rpm3 database " << dbInfo.dbV3() << endl;
526 
527  if ( dbEmpty )
528  {
529  extern void convertV3toV4( const Pathname & v3db_r, const librpmDb::constPtr & v4db_r );
530  convertV3toV4( dbInfo.dbV3().path(), dbptr );
531 
532  // create a backup copy
533  int res = filesystem::copy( dbInfo.dbV3().path(), dbInfo.dbV3ToV4().path() );
534  if ( res )
535  {
536  WAR << "Backup converted rpm3 database failed: error(" << res << ")" << endl;
537  }
538  else
539  {
540  dbInfo.restat();
541  if ( dbInfo.hasDbV3ToV4() )
542  {
543  MIL << "Backup converted rpm3 database: " << dbInfo.dbV3ToV4() << endl;
545  }
546  }
547 
548  }
549  else
550  {
551 
552  WAR << "Non empty rpm3 and rpm4 database found: using rpm4" << endl;
553  // set DbSI_MODIFIED_V4 as it's not a temporary which can be removed.
554  dbsi_set( info_r, DbSI_MODIFIED_V4 );
555 
556  }
557 
558  DBG << "Convert state: " << info_r << ": " << stringPath( root_r, dbPath_r );
559  librpmDb::dumpState( DBG ) << endl;
560  }
561 
562  if ( dbInfo.hasDbV3ToV4() )
563  {
564  MIL << "Rpm3 database backup: " << dbInfo.dbV3ToV4() << endl;
565  }
566 }
567 
569 //
570 //
571 // METHOD NAME : RpmDb::removeV4
572 // METHOD TYPE : void
573 //
574 void RpmDb::removeV4( const Pathname & dbdir_r, bool v3backup_r )
575 {
576  const char * v3backup = "packages.rpm3";
577  const char * master = "Packages";
578  const char * index[] =
579  {
580  "Basenames",
581  "Conflictname",
582  "Depends",
583  "Dirnames",
584  "Filemd5s",
585  "Group",
586  "Installtid",
587  "Name",
588  "Providename",
589  "Provideversion",
590  "Pubkeys",
591  "Requirename",
592  "Requireversion",
593  "Sha1header",
594  "Sigmd5",
595  "Triggername",
596  // last entry!
597  NULL
598  };
599 
600  PathInfo pi( dbdir_r );
601  if ( ! pi.isDir() )
602  {
603  ERR << "Can't remove rpm4 database in non directory: " << dbdir_r << endl;
604  return;
605  }
606 
607  for ( const char ** f = index; *f; ++f )
608  {
609  pi( dbdir_r + *f );
610  if ( pi.isFile() )
611  {
612  filesystem::unlink( pi.path() );
613  }
614  }
615 
616  pi( dbdir_r + master );
617  if ( pi.isFile() )
618  {
619  MIL << "Removing rpm4 database " << pi << endl;
620  filesystem::unlink( pi.path() );
621  }
622 
623  if ( v3backup_r )
624  {
625  pi( dbdir_r + v3backup );
626  if ( pi.isFile() )
627  {
628  MIL << "Removing converted rpm3 database backup " << pi << endl;
629  filesystem::unlink( pi.path() );
630  }
631  }
632 }
633 
635 //
636 //
637 // METHOD NAME : RpmDb::removeV3
638 // METHOD TYPE : void
639 //
640 void RpmDb::removeV3( const Pathname & dbdir_r, bool v3backup_r )
641 {
642  const char * master = "packages.rpm";
643  const char * index[] =
644  {
645  "conflictsindex.rpm",
646  "fileindex.rpm",
647  "groupindex.rpm",
648  "nameindex.rpm",
649  "providesindex.rpm",
650  "requiredby.rpm",
651  "triggerindex.rpm",
652  // last entry!
653  NULL
654  };
655 
656  PathInfo pi( dbdir_r );
657  if ( ! pi.isDir() )
658  {
659  ERR << "Can't remove rpm3 database in non directory: " << dbdir_r << endl;
660  return;
661  }
662 
663  for ( const char ** f = index; *f; ++f )
664  {
665  pi( dbdir_r + *f );
666  if ( pi.isFile() )
667  {
668  filesystem::unlink( pi.path() );
669  }
670  }
671 
672 #warning CHECK: compare vs existing v3 backup. notify root
673  pi( dbdir_r + master );
674  if ( pi.isFile() )
675  {
676  Pathname m( pi.path() );
677  if ( v3backup_r )
678  {
679  // backup was already created
680  filesystem::unlink( m );
681  Pathname b( m.extend( "3" ) );
682  pi( b ); // stat backup
683  }
684  else
685  {
686  Pathname b( m.extend( ".deleted" ) );
687  pi( b );
688  if ( pi.isFile() )
689  {
690  // rempve existing backup
691  filesystem::unlink( b );
692  }
693  filesystem::rename( m, b );
694  pi( b ); // stat backup
695  }
696  MIL << "(Re)moved rpm3 database to " << pi << endl;
697  }
698 }
699 
701 //
702 //
703 // METHOD NAME : RpmDb::modifyDatabase
704 // METHOD TYPE : void
705 //
707 {
708  if ( ! initialized() )
709  return;
710 
711  // tag database as modified
713 
714  // Move outdated rpm3 database beside.
716  {
717  MIL << "Update mode: Delayed cleanup: state " << _dbStateInfo << endl;
720  }
721 }
722 
724 //
725 //
726 // METHOD NAME : RpmDb::closeDatabase
727 // METHOD TYPE : PMError
728 //
730 {
731  if ( ! initialized() )
732  {
733  return;
734  }
735 
736  MIL << "Calling closeDatabase: " << *this << endl;
737 
739  // Block further database access
742 
744  // Check fate if old version database still present
747  {
748  MIL << "Update mode: Delayed cleanup: state " << _dbStateInfo << endl;
750  {
751  // Move outdated rpm3 database beside.
753  }
754  else
755  {
756  // Remove unmodified rpm4 database
758  }
759  }
760 
762  // Uninit
764  _root = _dbPath = Pathname();
766 
767  MIL << "closeDatabase: " << *this << endl;
768 }
769 
771 //
772 //
773 // METHOD NAME : RpmDb::rebuildDatabase
774 // METHOD TYPE : PMError
775 //
777 {
779 
780  report->start( root() + dbPath() );
781 
782  try
783  {
784  doRebuildDatabase(report);
785  }
786  catch (RpmException & excpt_r)
787  {
788  report->finish(root() + dbPath(), RebuildDBReport::FAILED, excpt_r.asUserHistory());
789  ZYPP_RETHROW(excpt_r);
790  }
791  report->finish(root() + dbPath(), RebuildDBReport::NO_ERROR, "");
792 }
793 
795 {
797 
798  MIL << "RpmDb::rebuildDatabase" << *this << endl;
799  // FIXME Timecount _t( "RpmDb::rebuildDatabase" );
800 
801  PathInfo dbMaster( root() + dbPath() + "Packages" );
802  PathInfo dbMasterBackup( dbMaster.path().extend( ".y2backup" ) );
803 
804  // run rpm
805  RpmArgVec opts;
806  opts.push_back("--rebuilddb");
807  opts.push_back("-vv");
808 
809  // don't call modifyDatabase because it would remove the old
810  // rpm3 database, if the current database is a temporary one.
812 
813  // progress report: watch this file growing
814  PathInfo newMaster( root()
815  + dbPath().extend( str::form( "rebuilddb.%d",
816  process?process->getpid():0) )
817  + "Packages" );
818 
819  std::string line;
820  std::string errmsg;
821 
822  while ( systemReadLine( line ) )
823  {
824  if ( newMaster() )
825  { // file is removed at the end of rebuild.
826  // current size should be upper limit for new db
827  if ( ! report->progress( (100 * newMaster.size()) / dbMaster.size(), root() + dbPath()) )
828  {
829  WAR << "User requested abort." << endl;
830  systemKill();
831  filesystem::recursive_rmdir( newMaster.path().dirname() );
832  }
833  }
834 
835  if ( line.compare( 0, 2, "D:" ) )
836  {
837  errmsg += line + '\n';
838  // report.notify( line );
839  WAR << line << endl;
840  }
841  }
842 
843  int rpm_status = systemStatus();
844 
845  if ( rpm_status != 0 )
846  {
847  //TranslatorExplanation after semicolon is error message
848  ZYPP_THROW(RpmSubprocessException(std::string(_("RPM failed: ")) + (errmsg.empty() ? error_message: errmsg) ) );
849  }
850  else
851  {
852  report->progress( 100, root() + dbPath() ); // 100%
853  }
854 }
855 
857 namespace
858 {
863  void computeKeyRingSync( std::set<Edition> & rpmKeys_r, std::list<PublicKeyData> & zyppKeys_r )
864  {
866  // Remember latest release and where it ocurred
867  struct Key
868  {
869  Key()
870  : _inRpmKeys( nullptr )
871  , _inZyppKeys( nullptr )
872  {}
873 
874  void updateIf( const Edition & rpmKey_r )
875  {
876  std::string keyRelease( rpmKey_r.release() );
877  int comp = _release.compare( keyRelease );
878  if ( comp < 0 )
879  {
880  // update to newer release
881  _release.swap( keyRelease );
882  _inRpmKeys = &rpmKey_r;
883  _inZyppKeys = nullptr;
884  if ( !keyRelease.empty() )
885  DBG << "Old key in R: gpg-pubkey-" << rpmKey_r.version() << "-" << keyRelease << endl;
886  }
887  else if ( comp == 0 )
888  {
889  // stay with this release
890  if ( ! _inRpmKeys )
891  _inRpmKeys = &rpmKey_r;
892  }
893  // else: this is an old release
894  else
895  DBG << "Old key in R: gpg-pubkey-" << rpmKey_r.version() << "-" << keyRelease << endl;
896  }
897 
898  void updateIf( const PublicKeyData & zyppKey_r )
899  {
900  std::string keyRelease( zyppKey_r.gpgPubkeyRelease() );
901  int comp = _release.compare( keyRelease );
902  if ( comp < 0 )
903  {
904  // update to newer release
905  _release.swap( keyRelease );
906  _inRpmKeys = nullptr;
907  _inZyppKeys = &zyppKey_r;
908  if ( !keyRelease.empty() )
909  DBG << "Old key in Z: gpg-pubkey-" << zyppKey_r.gpgPubkeyVersion() << "-" << keyRelease << endl;
910  }
911  else if ( comp == 0 )
912  {
913  // stay with this release
914  if ( ! _inZyppKeys )
915  _inZyppKeys = &zyppKey_r;
916  }
917  // else: this is an old release
918  else
919  DBG << "Old key in Z: gpg-pubkey-" << zyppKey_r.gpgPubkeyVersion() << "-" << keyRelease << endl;
920  }
921 
922  std::string _release;
923  const Edition * _inRpmKeys;
924  const PublicKeyData * _inZyppKeys;
925  };
927 
928  // collect keys by ID(version) and latest creation(release)
929  std::map<std::string,Key> _keymap;
930 
931  for_( it, rpmKeys_r.begin(), rpmKeys_r.end() )
932  {
933  _keymap[(*it).version()].updateIf( *it );
934  }
935 
936  for_( it, zyppKeys_r.begin(), zyppKeys_r.end() )
937  {
938  _keymap[(*it).gpgPubkeyVersion()].updateIf( *it );
939  }
940 
941  // compute missing keys
942  std::set<Edition> rpmKeys;
943  std::list<PublicKeyData> zyppKeys;
944  for_( it, _keymap.begin(), _keymap.end() )
945  {
946  DBG << "gpg-pubkey-" << (*it).first << "-" << (*it).second._release << " "
947  << ( (*it).second._inRpmKeys ? "R" : "_" )
948  << ( (*it).second._inZyppKeys ? "Z" : "_" ) << endl;
949  if ( ! (*it).second._inRpmKeys )
950  {
951  zyppKeys.push_back( *(*it).second._inZyppKeys );
952  }
953  if ( ! (*it).second._inZyppKeys )
954  {
955  rpmKeys.insert( *(*it).second._inRpmKeys );
956  }
957  }
958  rpmKeys_r.swap( rpmKeys );
959  zyppKeys_r.swap( zyppKeys );
960  }
961 } // namespace
963 
965 {
966  MIL << "Going to sync trusted keys..." << endl;
967  std::set<Edition> rpmKeys( pubkeyEditions() );
968  std::list<PublicKeyData> zyppKeys( getZYpp()->keyRing()->trustedPublicKeyData() );
969  computeKeyRingSync( rpmKeys, zyppKeys );
970  MIL << (mode_r & SYNC_TO_KEYRING ? "" : "(skip) ") << "Rpm keys to export into zypp trusted keyring: " << rpmKeys.size() << endl;
971  MIL << (mode_r & SYNC_FROM_KEYRING ? "" : "(skip) ") << "Zypp trusted keys to import into rpm database: " << zyppKeys.size() << endl;
972 
974  if ( (mode_r & SYNC_TO_KEYRING) && ! rpmKeys.empty() )
975  {
976  // export to zypp keyring
977  MIL << "Exporting rpm keyring into zypp trusted keyring" <<endl;
978  // Temporarily disconnect to prevent the attemt to re-import the exported keys.
980  librpmDb::db_const_iterator keepDbOpen; // just to keep a ref.
981 
982  TmpFile tmpfile( getZYpp()->tmpPath() );
983  {
984  std::ofstream tmpos( tmpfile.path().c_str() );
985  for_( it, rpmKeys.begin(), rpmKeys.end() )
986  {
987  // we export the rpm key into a file
988  RpmHeader::constPtr result;
989  getData( "gpg-pubkey", *it, result );
990  tmpos << result->tag_description() << endl;
991  }
992  }
993  try
994  {
995  getZYpp()->keyRing()->multiKeyImport( tmpfile.path(), true /*trusted*/);
996  }
997  catch (Exception &e)
998  {
999  ERR << "Could not import keys into in zypp keyring" << endl;
1000  }
1001  }
1002 
1004  if ( (mode_r & SYNC_FROM_KEYRING) && ! zyppKeys.empty() )
1005  {
1006  // import from zypp keyring
1007  MIL << "Importing zypp trusted keyring" << std::endl;
1008  for_( it, zyppKeys.begin(), zyppKeys.end() )
1009  {
1010  try
1011  {
1012  importPubkey( getZYpp()->keyRing()->exportTrustedPublicKey( *it ) );
1013  }
1014  catch ( const RpmException & exp )
1015  {
1016  ZYPP_CAUGHT( exp );
1017  }
1018  }
1019  }
1020  MIL << "Trusted keys synced." << endl;
1021 }
1022 
1025 
1028 
1030 //
1031 //
1032 // METHOD NAME : RpmDb::importPubkey
1033 // METHOD TYPE : PMError
1034 //
1035 void RpmDb::importPubkey( const PublicKey & pubkey_r )
1036 {
1038 
1039  // bnc#828672: On the fly key import in READONLY
1041  {
1042  WAR << "Key " << pubkey_r << " can not be imported. (READONLY MODE)" << endl;
1043  return;
1044  }
1045 
1046  // check if the key is already in the rpm database
1047  Edition keyEd( pubkey_r.gpgPubkeyVersion(), pubkey_r.gpgPubkeyRelease() );
1048  std::set<Edition> rpmKeys = pubkeyEditions();
1049  bool hasOldkeys = false;
1050 
1051  for_( it, rpmKeys.begin(), rpmKeys.end() )
1052  {
1053  if ( keyEd == *it ) // quick test (Edition is IdStringType!)
1054  {
1055  MIL << "Key " << pubkey_r << " is already in the rpm trusted keyring. (skip import)" << endl;
1056  return;
1057  }
1058 
1059  if ( keyEd.version() != (*it).version() )
1060  continue; // different key ID (version)
1061 
1062  if ( keyEd.release() < (*it).release() )
1063  {
1064  MIL << "Key " << pubkey_r << " is older than one in the rpm trusted keyring. (skip import)" << endl;
1065  return;
1066  }
1067  else
1068  {
1069  hasOldkeys = true;
1070  }
1071  }
1072  MIL << "Key " << pubkey_r << " will be imported into the rpm trusted keyring." << (hasOldkeys?"(update)":"(new)") << endl;
1073 
1074  if ( hasOldkeys )
1075  {
1076  // We must explicitly delete old key IDs first (all releases,
1077  // that's why we don't call removePubkey here).
1078  std::string keyName( "gpg-pubkey-" + keyEd.version() );
1079  RpmArgVec opts;
1080  opts.push_back ( "-e" );
1081  opts.push_back ( "--allmatches" );
1082  opts.push_back ( "--" );
1083  opts.push_back ( keyName.c_str() );
1084  // don't call modifyDatabase because it would remove the old
1085  // rpm3 database, if the current database is a temporary one.
1087 
1088  std::string line;
1089  while ( systemReadLine( line ) )
1090  {
1091  ( str::startsWith( line, "error:" ) ? WAR : DBG ) << line << endl;
1092  }
1093 
1094  if ( systemStatus() != 0 )
1095  {
1096  ERR << "Failed to remove key " << pubkey_r << " from RPM trusted keyring (ignored)" << endl;
1097  }
1098  else
1099  {
1100  MIL << "Key " << pubkey_r << " has been removed from RPM trusted keyring" << endl;
1101  }
1102  }
1103 
1104  // import the new key
1105  RpmArgVec opts;
1106  opts.push_back ( "--import" );
1107  opts.push_back ( "--" );
1108  std::string pubkeypath( pubkey_r.path().asString() );
1109  opts.push_back ( pubkeypath.c_str() );
1110 
1111  // don't call modifyDatabase because it would remove the old
1112  // rpm3 database, if the current database is a temporary one.
1114 
1115  std::string line;
1116  while ( systemReadLine( line ) )
1117  {
1118  ( str::startsWith( line, "error:" ) ? WAR : DBG ) << line << endl;
1119  }
1120 
1121  if ( systemStatus() != 0 )
1122  {
1123  //TranslatorExplanation first %s is file name, second is error message
1124  ZYPP_THROW(RpmSubprocessException( str::Format(_("Failed to import public key from file %s: %s"))
1125  % pubkey_r.asString()
1126  % error_message ));
1127  }
1128  else
1129  {
1130  MIL << "Key " << pubkey_r << " imported in rpm trusted keyring." << endl;
1131  }
1132 }
1133 
1135 //
1136 //
1137 // METHOD NAME : RpmDb::removePubkey
1138 // METHOD TYPE : PMError
1139 //
1140 void RpmDb::removePubkey( const PublicKey & pubkey_r )
1141 {
1143 
1144  // check if the key is in the rpm database and just
1145  // return if it does not.
1146  std::set<Edition> rpm_keys = pubkeyEditions();
1147  std::set<Edition>::const_iterator found_edition = rpm_keys.end();
1148  std::string pubkeyVersion( pubkey_r.gpgPubkeyVersion() );
1149 
1150  for_( it, rpm_keys.begin(), rpm_keys.end() )
1151  {
1152  if ( (*it).version() == pubkeyVersion )
1153  {
1154  found_edition = it;
1155  break;
1156  }
1157  }
1158 
1159  // the key does not exist, cannot be removed
1160  if (found_edition == rpm_keys.end())
1161  {
1162  WAR << "Key " << pubkey_r.id() << " is not in rpm db" << endl;
1163  return;
1164  }
1165 
1166  std::string rpm_name("gpg-pubkey-" + found_edition->asString());
1167 
1168  RpmArgVec opts;
1169  opts.push_back ( "-e" );
1170  opts.push_back ( "--" );
1171  opts.push_back ( rpm_name.c_str() );
1172 
1173  // don't call modifyDatabase because it would remove the old
1174  // rpm3 database, if the current database is a temporary one.
1176 
1177  std::string line;
1178  while ( systemReadLine( line ) )
1179  {
1180  if ( line.substr( 0, 6 ) == "error:" )
1181  {
1182  WAR << line << endl;
1183  }
1184  else
1185  {
1186  DBG << line << endl;
1187  }
1188  }
1189 
1190  int rpm_status = systemStatus();
1191 
1192  if ( rpm_status != 0 )
1193  {
1194  //TranslatorExplanation first %s is key name, second is error message
1195  ZYPP_THROW(RpmSubprocessException( str::Format(_("Failed to remove public key %s: %s"))
1196  % pubkey_r.asString()
1197  % error_message ));
1198  }
1199  else
1200  {
1201  MIL << "Key " << pubkey_r << " has been removed from RPM trusted keyring" << endl;
1202  }
1203 }
1204 
1206 //
1207 //
1208 // METHOD NAME : RpmDb::pubkeys
1209 // METHOD TYPE : std::set<Edition>
1210 //
1211 std::list<PublicKey> RpmDb::pubkeys() const
1212 {
1213  std::list<PublicKey> ret;
1214 
1216  for ( it.findByName( "gpg-pubkey" ); *it; ++it )
1217  {
1218  Edition edition = it->tag_edition();
1219  if (edition != Edition::noedition)
1220  {
1221  // we export the rpm key into a file
1222  RpmHeader::constPtr result;
1223  getData( "gpg-pubkey", edition, result );
1224  TmpFile file(getZYpp()->tmpPath());
1225  std::ofstream os;
1226  try
1227  {
1228  os.open(file.path().asString().c_str());
1229  // dump rpm key into the tmp file
1230  os << result->tag_description();
1231  //MIL << "-----------------------------------------------" << endl;
1232  //MIL << result->tag_description() <<endl;
1233  //MIL << "-----------------------------------------------" << endl;
1234  os.close();
1235  // read the public key from the dumped file
1236  PublicKey key(file);
1237  ret.push_back(key);
1238  }
1239  catch ( std::exception & e )
1240  {
1241  ERR << "Could not dump key " << edition.asString() << " in tmp file " << file.path() << endl;
1242  // just ignore the key
1243  }
1244  }
1245  }
1246  return ret;
1247 }
1248 
1249 std::set<Edition> RpmDb::pubkeyEditions() const
1250  {
1251  std::set<Edition> ret;
1252 
1254  for ( it.findByName( "gpg-pubkey" ); *it; ++it )
1255  {
1256  Edition edition = it->tag_edition();
1257  if (edition != Edition::noedition)
1258  ret.insert( edition );
1259  }
1260  return ret;
1261  }
1262 
1263 
1265 //
1266 //
1267 // METHOD NAME : RpmDb::fileList
1268 // METHOD TYPE : bool
1269 //
1270 // DESCRIPTION :
1271 //
1272 std::list<FileInfo>
1273 RpmDb::fileList( const std::string & name_r, const Edition & edition_r ) const
1274 {
1275  std::list<FileInfo> result;
1276 
1278  bool found;
1279  if (edition_r == Edition::noedition)
1280  {
1281  found = it.findPackage( name_r );
1282  }
1283  else
1284  {
1285  found = it.findPackage( name_r, edition_r );
1286  }
1287  if (!found)
1288  return result;
1289 
1290  return result;
1291 }
1292 
1293 
1295 //
1296 //
1297 // METHOD NAME : RpmDb::hasFile
1298 // METHOD TYPE : bool
1299 //
1300 // DESCRIPTION :
1301 //
1302 bool RpmDb::hasFile( const std::string & file_r, const std::string & name_r ) const
1303 {
1305  bool res;
1306  do
1307  {
1308  res = it.findByFile( file_r );
1309  if (!res) break;
1310  if (!name_r.empty())
1311  {
1312  res = (it->tag_name() == name_r);
1313  }
1314  ++it;
1315  }
1316  while (res && *it);
1317  return res;
1318 }
1319 
1321 //
1322 //
1323 // METHOD NAME : RpmDb::whoOwnsFile
1324 // METHOD TYPE : std::string
1325 //
1326 // DESCRIPTION :
1327 //
1328 std::string RpmDb::whoOwnsFile( const std::string & file_r) const
1329 {
1331  if (it.findByFile( file_r ))
1332  {
1333  return it->tag_name();
1334  }
1335  return "";
1336 }
1337 
1339 //
1340 //
1341 // METHOD NAME : RpmDb::hasProvides
1342 // METHOD TYPE : bool
1343 //
1344 // DESCRIPTION :
1345 //
1346 bool RpmDb::hasProvides( const std::string & tag_r ) const
1347 {
1349  return it.findByProvides( tag_r );
1350 }
1351 
1353 //
1354 //
1355 // METHOD NAME : RpmDb::hasRequiredBy
1356 // METHOD TYPE : bool
1357 //
1358 // DESCRIPTION :
1359 //
1360 bool RpmDb::hasRequiredBy( const std::string & tag_r ) const
1361 {
1363  return it.findByRequiredBy( tag_r );
1364 }
1365 
1367 //
1368 //
1369 // METHOD NAME : RpmDb::hasConflicts
1370 // METHOD TYPE : bool
1371 //
1372 // DESCRIPTION :
1373 //
1374 bool RpmDb::hasConflicts( const std::string & tag_r ) const
1375 {
1377  return it.findByConflicts( tag_r );
1378 }
1379 
1381 //
1382 //
1383 // METHOD NAME : RpmDb::hasPackage
1384 // METHOD TYPE : bool
1385 //
1386 // DESCRIPTION :
1387 //
1388 bool RpmDb::hasPackage( const std::string & name_r ) const
1389 {
1391  return it.findPackage( name_r );
1392 }
1393 
1395 //
1396 //
1397 // METHOD NAME : RpmDb::hasPackage
1398 // METHOD TYPE : bool
1399 //
1400 // DESCRIPTION :
1401 //
1402 bool RpmDb::hasPackage( const std::string & name_r, const Edition & ed_r ) const
1403 {
1405  return it.findPackage( name_r, ed_r );
1406 }
1407 
1409 //
1410 //
1411 // METHOD NAME : RpmDb::getData
1412 // METHOD TYPE : PMError
1413 //
1414 // DESCRIPTION :
1415 //
1416 void RpmDb::getData( const std::string & name_r,
1417  RpmHeader::constPtr & result_r ) const
1418 {
1420  it.findPackage( name_r );
1421  result_r = *it;
1422  if (it.dbError())
1423  ZYPP_THROW(*(it.dbError()));
1424 }
1425 
1427 //
1428 //
1429 // METHOD NAME : RpmDb::getData
1430 // METHOD TYPE : void
1431 //
1432 // DESCRIPTION :
1433 //
1434 void RpmDb::getData( const std::string & name_r, const Edition & ed_r,
1435  RpmHeader::constPtr & result_r ) const
1436 {
1438  it.findPackage( name_r, ed_r );
1439  result_r = *it;
1440  if (it.dbError())
1441  ZYPP_THROW(*(it.dbError()));
1442 }
1443 
1445 namespace
1446 {
1447  struct RpmlogCapture : public std::string
1448  {
1449  RpmlogCapture()
1450  { rpmlog()._cap = this; }
1451 
1452  ~RpmlogCapture()
1453  { rpmlog()._cap = nullptr; }
1454 
1455  private:
1456  struct Rpmlog
1457  {
1458  Rpmlog()
1459  : _cap( nullptr )
1460  {
1461  rpmlogSetCallback( rpmLogCB, this );
1462  rpmSetVerbosity( RPMLOG_INFO );
1463  _f = ::fopen( "/dev/null","w");
1464  rpmlogSetFile( _f );
1465  }
1466 
1467  ~Rpmlog()
1468  { if ( _f ) ::fclose( _f ); }
1469 
1470  static int rpmLogCB( rpmlogRec rec_r, rpmlogCallbackData data_r )
1471  { return reinterpret_cast<Rpmlog*>(data_r)->rpmLog( rec_r ); }
1472 
1473  int rpmLog( rpmlogRec rec_r )
1474  {
1475  if ( _cap ) (*_cap) = rpmlogRecMessage( rec_r );
1476  return RPMLOG_DEFAULT;
1477  }
1478 
1479  FILE * _f;
1480  std::string * _cap;
1481  };
1482 
1483  static Rpmlog & rpmlog()
1484  { static Rpmlog _rpmlog; return _rpmlog; }
1485  };
1486 
1487 
1488 } // namespace
1490 //
1491 // METHOD NAME : RpmDb::checkPackage
1492 // METHOD TYPE : RpmDb::CheckPackageResult
1493 //
1495 {
1496  PathInfo file( path_r );
1497  if ( ! file.isFile() )
1498  {
1499  ERR << "Not a file: " << file << endl;
1500  return CHK_ERROR;
1501  }
1502 
1503  FD_t fd = ::Fopen( file.asString().c_str(), "r.ufdio" );
1504  if ( fd == 0 || ::Ferror(fd) )
1505  {
1506  ERR << "Can't open file for reading: " << file << " (" << ::Fstrerror(fd) << ")" << endl;
1507  if ( fd )
1508  ::Fclose( fd );
1509  return CHK_ERROR;
1510  }
1511  rpmts ts = ::rpmtsCreate();
1512  ::rpmtsSetRootDir( ts, root().asString().c_str() );
1513  ::rpmtsSetVSFlags( ts, RPMVSF_DEFAULT );
1514 
1515  rpmQVKArguments_s qva;
1516  memset( &qva, 0, sizeof(rpmQVKArguments_s) );
1517  qva.qva_flags = (VERIFY_DIGEST|VERIFY_SIGNATURE);
1518 
1519  RpmlogCapture vresult;
1520  int res = ::rpmVerifySignatures( &qva, ts, fd, path_r.basename().c_str() );
1521 
1522  ts = rpmtsFree(ts);
1523  ::Fclose( fd );
1524 
1525 
1526  if ( res == 0 )
1527  {
1528  detail_r.push_back( CheckPackageDetail::value_type( CHK_OK, std::move(vresult) ) );
1529  return CHK_OK;
1530  }
1531 
1532  // results per line...
1533  WAR << vresult;
1534  std::vector<std::string> lines;
1535  str::split( vresult, std::back_inserter(lines), "\n" );
1536  unsigned count[6] = { 0, 0, 0, 0, 0, 0 };
1537 
1538  for ( unsigned i = 1; i < lines.size(); ++i )
1539  {
1540  std::string & line( lines[i] );
1541  CheckPackageResult lineres = CHK_ERROR;
1542  if ( line.find( ": OK" ) != std::string::npos )
1543  { lineres = CHK_OK; }
1544  else if ( line.find( ": NOKEY" ) != std::string::npos )
1545  { lineres = CHK_NOKEY; }
1546  else if ( line.find( ": BAD" ) != std::string::npos )
1547  { lineres = CHK_FAIL; }
1548  else if ( line.find( ": UNKNOWN" ) != std::string::npos )
1549  { lineres = CHK_NOTFOUND; }
1550  else if ( line.find( ": NOTRUSTED" ) != std::string::npos )
1551  { lineres = CHK_NOTTRUSTED; }
1552 
1553  ++count[lineres];
1554  detail_r.push_back( CheckPackageDetail::value_type( lineres, std::move(line) ) );
1555  }
1556 
1558  if ( count[CHK_FAIL] )
1559  ret = CHK_FAIL;
1560 
1561  else if ( count[CHK_NOTFOUND] )
1562  ret = CHK_NOTFOUND;
1563 
1564  else if ( count[CHK_NOKEY] )
1565  ret = CHK_NOKEY;
1566 
1567  else if ( count[CHK_NOTTRUSTED] )
1568  ret = CHK_NOTTRUSTED;
1569 
1570  return ret;
1571 }
1572 
1574 { CheckPackageDetail dummy; return checkPackage( path_r, dummy ); }
1575 
1576 
1577 // determine changed files of installed package
1578 bool
1579 RpmDb::queryChangedFiles(FileList & fileList, const std::string& packageName)
1580 {
1581  bool ok = true;
1582 
1583  fileList.clear();
1584 
1585  if ( ! initialized() ) return false;
1586 
1587  RpmArgVec opts;
1588 
1589  opts.push_back ("-V");
1590  opts.push_back ("--nodeps");
1591  opts.push_back ("--noscripts");
1592  opts.push_back ("--nomd5");
1593  opts.push_back ("--");
1594  opts.push_back (packageName.c_str());
1595 
1597 
1598  if ( process == NULL )
1599  return false;
1600 
1601  /* from rpm manpage
1602  5 MD5 sum
1603  S File size
1604  L Symlink
1605  T Mtime
1606  D Device
1607  U User
1608  G Group
1609  M Mode (includes permissions and file type)
1610  */
1611 
1612  std::string line;
1613  while (systemReadLine(line))
1614  {
1615  if (line.length() > 12 &&
1616  (line[0] == 'S' || line[0] == 's' ||
1617  (line[0] == '.' && line[7] == 'T')))
1618  {
1619  // file has been changed
1620  std::string filename;
1621 
1622  filename.assign(line, 11, line.length() - 11);
1623  fileList.insert(filename);
1624  }
1625  }
1626 
1627  systemStatus();
1628  // exit code ignored, rpm returns 1 no matter if package is installed or
1629  // not
1630 
1631  return ok;
1632 }
1633 
1634 
1635 
1636 /****************************************************************/
1637 /* private member-functions */
1638 /****************************************************************/
1639 
1640 /*--------------------------------------------------------------*/
1641 /* Run rpm with the specified arguments, handling stderr */
1642 /* as specified by disp */
1643 /*--------------------------------------------------------------*/
1644 void
1647 {
1648  if ( process )
1649  {
1650  delete process;
1651  process = NULL;
1652  }
1653  exit_code = -1;
1654 
1655  if ( ! initialized() )
1656  {
1658  }
1659 
1660  RpmArgVec args;
1661 
1662  // always set root and dbpath
1663 #if defined(WORKAROUNDRPMPWDBUG)
1664  args.push_back("#/"); // chdir to / to workaround bnc#819354
1665 #endif
1666  args.push_back("rpm");
1667  args.push_back("--root");
1668  args.push_back(_root.asString().c_str());
1669  args.push_back("--dbpath");
1670  args.push_back(_dbPath.asString().c_str());
1671 
1672  const char* argv[args.size() + opts.size() + 1];
1673 
1674  const char** p = argv;
1675  p = copy (args.begin (), args.end (), p);
1676  p = copy (opts.begin (), opts.end (), p);
1677  *p = 0;
1678 
1679  // Invalidate all outstanding database handles in case
1680  // the database gets modified.
1681  librpmDb::dbRelease( true );
1682 
1683  // Launch the program with default locale
1684  process = new ExternalProgram(argv, disp, false, -1, true);
1685  return;
1686 }
1687 
1688 /*--------------------------------------------------------------*/
1689 /* Read a line from the rpm process */
1690 /*--------------------------------------------------------------*/
1691 bool RpmDb::systemReadLine( std::string & line )
1692 {
1693  line.erase();
1694 
1695  if ( process == NULL )
1696  return false;
1697 
1698  if ( process->inputFile() )
1699  {
1700  process->setBlocking( false );
1701  FILE * inputfile = process->inputFile();
1702  int inputfileFd = ::fileno( inputfile );
1703  do
1704  {
1705  /* Watch inputFile to see when it has input. */
1706  fd_set rfds;
1707  FD_ZERO( &rfds );
1708  FD_SET( inputfileFd, &rfds );
1709 
1710  /* Wait up to 5 seconds. */
1711  struct timeval tv;
1712  tv.tv_sec = 5;
1713  tv.tv_usec = 0;
1714 
1715  int retval = select( inputfileFd+1, &rfds, NULL, NULL, &tv );
1716 
1717  if ( retval == -1 )
1718  {
1719  ERR << "select error: " << strerror(errno) << endl;
1720  if ( errno != EINTR )
1721  return false;
1722  }
1723  else if ( retval )
1724  {
1725  // Data is available now.
1726  static size_t linebuffer_size = 0; // static because getline allocs
1727  static char * linebuffer = 0; // and reallocs if buffer is too small
1728  ssize_t nread = getline( &linebuffer, &linebuffer_size, inputfile );
1729  if ( nread == -1 )
1730  {
1731  if ( ::feof( inputfile ) )
1732  return line.size(); // in case of pending output
1733  }
1734  else
1735  {
1736  if ( nread > 0 )
1737  {
1738  if ( linebuffer[nread-1] == '\n' )
1739  --nread;
1740  line += std::string( linebuffer, nread );
1741  }
1742 
1743  if ( ! ::ferror( inputfile ) || ::feof( inputfile ) )
1744  return true; // complete line
1745  }
1746  clearerr( inputfile );
1747  }
1748  else
1749  {
1750  // No data within time.
1751  if ( ! process->running() )
1752  return false;
1753  }
1754  } while ( true );
1755  }
1756 
1757  return false;
1758 }
1759 
1760 /*--------------------------------------------------------------*/
1761 /* Return the exit status of the rpm process, closing the */
1762 /* connection if not already done */
1763 /*--------------------------------------------------------------*/
1764 int
1766 {
1767  if ( process == NULL )
1768  return -1;
1769 
1770  exit_code = process->close();
1771  if (exit_code == 0)
1772  error_message = "";
1773  else
1775  process->kill();
1776  delete process;
1777  process = 0;
1778 
1779  // DBG << "exit code " << exit_code << endl;
1780 
1781  return exit_code;
1782 }
1783 
1784 /*--------------------------------------------------------------*/
1785 /* Forcably kill the rpm process */
1786 /*--------------------------------------------------------------*/
1787 void
1789 {
1790  if (process) process->kill();
1791 }
1792 
1793 
1794 // generate diff mails for config files
1795 void RpmDb::processConfigFiles(const std::string& line, const std::string& name, const char* typemsg, const char* difffailmsg, const char* diffgenmsg)
1796 {
1797  std::string msg = line.substr(9);
1798  std::string::size_type pos1 = std::string::npos;
1799  std::string::size_type pos2 = std::string::npos;
1800  std::string file1s, file2s;
1801  Pathname file1;
1802  Pathname file2;
1803 
1804  pos1 = msg.find (typemsg);
1805  for (;;)
1806  {
1807  if ( pos1 == std::string::npos )
1808  break;
1809 
1810  pos2 = pos1 + strlen (typemsg);
1811 
1812  if (pos2 >= msg.length() )
1813  break;
1814 
1815  file1 = msg.substr (0, pos1);
1816  file2 = msg.substr (pos2);
1817 
1818  file1s = file1.asString();
1819  file2s = file2.asString();
1820 
1821  if (!_root.empty() && _root != "/")
1822  {
1823  file1 = _root + file1;
1824  file2 = _root + file2;
1825  }
1826 
1827  std::string out;
1828  int ret = diffFiles (file1.asString(), file2.asString(), out, 25);
1829  if (ret)
1830  {
1831  Pathname file = _root + WARNINGMAILPATH;
1832  if (filesystem::assert_dir(file) != 0)
1833  {
1834  ERR << "Could not create " << file.asString() << endl;
1835  break;
1836  }
1837  file += Date(Date::now()).form("config_diff_%Y_%m_%d.log");
1838  std::ofstream notify(file.asString().c_str(), std::ios::out|std::ios::app);
1839  if (!notify)
1840  {
1841  ERR << "Could not open " << file << endl;
1842  break;
1843  }
1844 
1845  // Translator: %s = name of an rpm package. A list of diffs follows
1846  // this message.
1847  notify << str::form(_("Changed configuration files for %s:"), name.c_str()) << endl;
1848  if (ret>1)
1849  {
1850  ERR << "diff failed" << endl;
1851  notify << str::form(difffailmsg,
1852  file1s.c_str(), file2s.c_str()) << endl;
1853  }
1854  else
1855  {
1856  notify << str::form(diffgenmsg,
1857  file1s.c_str(), file2s.c_str()) << endl;
1858 
1859  // remove root for the viewer's pleasure (#38240)
1860  if (!_root.empty() && _root != "/")
1861  {
1862  if (out.substr(0,4) == "--- ")
1863  {
1864  out.replace(4, file1.asString().length(), file1s);
1865  }
1866  std::string::size_type pos = out.find("\n+++ ");
1867  if (pos != std::string::npos)
1868  {
1869  out.replace(pos+5, file2.asString().length(), file2s);
1870  }
1871  }
1872  notify << out << endl;
1873  }
1874  notify.close();
1875  notify.open("/var/lib/update-messages/yast2-packagemanager.rpmdb.configfiles");
1876  notify.close();
1877  }
1878  else
1879  {
1880  WAR << "rpm created " << file2 << " but it is not different from " << file2 << endl;
1881  }
1882  break;
1883  }
1884 }
1885 
1887 //
1888 //
1889 // METHOD NAME : RpmDb::installPackage
1890 // METHOD TYPE : PMError
1891 //
1892 void RpmDb::installPackage( const Pathname & filename, RpmInstFlags flags )
1893 {
1895 
1896  report->start(filename);
1897 
1898  do
1899  try
1900  {
1901  doInstallPackage(filename, flags, report);
1902  report->finish();
1903  break;
1904  }
1905  catch (RpmException & excpt_r)
1906  {
1907  RpmInstallReport::Action user = report->problem( excpt_r );
1908 
1909  if ( user == RpmInstallReport::ABORT )
1910  {
1911  report->finish( excpt_r );
1912  ZYPP_RETHROW(excpt_r);
1913  }
1914  else if ( user == RpmInstallReport::IGNORE )
1915  {
1916  break;
1917  }
1918  }
1919  while (true);
1920 }
1921 
1922 void RpmDb::doInstallPackage( const Pathname & filename, RpmInstFlags flags, callback::SendReport<RpmInstallReport> & report )
1923 {
1925  HistoryLog historylog;
1926 
1927  MIL << "RpmDb::installPackage(" << filename << "," << flags << ")" << endl;
1928 
1929 
1930  // backup
1931  if ( _packagebackups )
1932  {
1933  // FIXME report->progress( pd.init( -2, 100 ) ); // allow 1% for backup creation.
1934  if ( ! backupPackage( filename ) )
1935  {
1936  ERR << "backup of " << filename.asString() << " failed" << endl;
1937  }
1938  // FIXME status handling
1939  report->progress( 0 ); // allow 1% for backup creation.
1940  }
1941 
1942  // run rpm
1943  RpmArgVec opts;
1944  if (flags & RPMINST_NOUPGRADE)
1945  opts.push_back("-i");
1946  else
1947  opts.push_back("-U");
1948 
1949  opts.push_back("--percent");
1950  opts.push_back("--noglob");
1951 
1952  // ZConfig defines cross-arch installation
1953  if ( ! ZConfig::instance().systemArchitecture().compatibleWith( ZConfig::instance().defaultSystemArchitecture() ) )
1954  opts.push_back("--ignorearch");
1955 
1956  if (flags & RPMINST_NODIGEST)
1957  opts.push_back("--nodigest");
1958  if (flags & RPMINST_NOSIGNATURE)
1959  opts.push_back("--nosignature");
1960  if (flags & RPMINST_EXCLUDEDOCS)
1961  opts.push_back ("--excludedocs");
1962  if (flags & RPMINST_NOSCRIPTS)
1963  opts.push_back ("--noscripts");
1964  if (flags & RPMINST_FORCE)
1965  opts.push_back ("--force");
1966  if (flags & RPMINST_NODEPS)
1967  opts.push_back ("--nodeps");
1968  if (flags & RPMINST_IGNORESIZE)
1969  opts.push_back ("--ignoresize");
1970  if (flags & RPMINST_JUSTDB)
1971  opts.push_back ("--justdb");
1972  if (flags & RPMINST_TEST)
1973  opts.push_back ("--test");
1974  if (flags & RPMINST_NOPOSTTRANS)
1975  opts.push_back ("--noposttrans");
1976 
1977  opts.push_back("--");
1978 
1979  // rpm requires additional quoting of special chars:
1980  std::string quotedFilename( rpmQuoteFilename( workaroundRpmPwdBug( filename ) ) );
1981  opts.push_back ( quotedFilename.c_str() );
1982 
1983  modifyDatabase(); // BEFORE run_rpm
1985 
1986  std::string line;
1987  std::string rpmmsg;
1988  std::vector<std::string> configwarnings;
1989 
1990  unsigned linecnt = 0;
1991  while (systemReadLine(line))
1992  {
1993  if ( linecnt < MAXRPMMESSAGELINES )
1994  ++linecnt;
1995  else
1996  continue;
1997 
1998  if (line.substr(0,2)=="%%")
1999  {
2000  int percent;
2001  sscanf (line.c_str () + 2, "%d", &percent);
2002  report->progress( percent );
2003  }
2004  else
2005  rpmmsg += line+'\n';
2006 
2007  if ( line.substr(0,8) == "warning:" )
2008  {
2009  configwarnings.push_back(line);
2010  }
2011  }
2012  if ( linecnt > MAXRPMMESSAGELINES )
2013  rpmmsg += "[truncated]\n";
2014 
2015  int rpm_status = systemStatus();
2016 
2017  // evaluate result
2018  for (std::vector<std::string>::iterator it = configwarnings.begin();
2019  it != configwarnings.end(); ++it)
2020  {
2021  processConfigFiles(*it, Pathname::basename(filename), " saved as ",
2022  // %s = filenames
2023  _("rpm saved %s as %s, but it was impossible to determine the difference"),
2024  // %s = filenames
2025  _("rpm saved %s as %s.\nHere are the first 25 lines of difference:\n"));
2026  processConfigFiles(*it, Pathname::basename(filename), " created as ",
2027  // %s = filenames
2028  _("rpm created %s as %s, but it was impossible to determine the difference"),
2029  // %s = filenames
2030  _("rpm created %s as %s.\nHere are the first 25 lines of difference:\n"));
2031  }
2032 
2033  if ( rpm_status != 0 )
2034  {
2035  historylog.comment(
2036  str::form("%s install failed", Pathname::basename(filename).c_str()),
2037  true /*timestamp*/);
2038  std::ostringstream sstr;
2039  sstr << "rpm output:" << endl << rpmmsg << endl;
2040  historylog.comment(sstr.str());
2041  // TranslatorExplanation the colon is followed by an error message
2042  ZYPP_THROW(RpmSubprocessException(_("RPM failed: ") + (rpmmsg.empty() ? error_message : rpmmsg) ));
2043  }
2044  else if ( ! rpmmsg.empty() )
2045  {
2046  historylog.comment(
2047  str::form("%s installed ok", Pathname::basename(filename).c_str()),
2048  true /*timestamp*/);
2049  std::ostringstream sstr;
2050  sstr << "Additional rpm output:" << endl << rpmmsg << endl;
2051  historylog.comment(sstr.str());
2052 
2053  // report additional rpm output in finish
2054  // TranslatorExplanation Text is followed by a ':' and the actual output.
2055  report->finishInfo(str::form( "%s:\n%s\n", _("Additional rpm output"), rpmmsg.c_str() ));
2056  }
2057 }
2058 
2060 //
2061 //
2062 // METHOD NAME : RpmDb::removePackage
2063 // METHOD TYPE : PMError
2064 //
2065 void RpmDb::removePackage( Package::constPtr package, RpmInstFlags flags )
2066 {
2067  // 'rpm -e' does not like epochs
2068  return removePackage( package->name()
2069  + "-" + package->edition().version()
2070  + "-" + package->edition().release()
2071  + "." + package->arch().asString(), flags );
2072 }
2073 
2075 //
2076 //
2077 // METHOD NAME : RpmDb::removePackage
2078 // METHOD TYPE : PMError
2079 //
2080 void RpmDb::removePackage( const std::string & name_r, RpmInstFlags flags )
2081 {
2083 
2084  report->start( name_r );
2085 
2086  do
2087  try
2088  {
2089  doRemovePackage(name_r, flags, report);
2090  report->finish();
2091  break;
2092  }
2093  catch (RpmException & excpt_r)
2094  {
2095  RpmRemoveReport::Action user = report->problem( excpt_r );
2096 
2097  if ( user == RpmRemoveReport::ABORT )
2098  {
2099  report->finish( excpt_r );
2100  ZYPP_RETHROW(excpt_r);
2101  }
2102  else if ( user == RpmRemoveReport::IGNORE )
2103  {
2104  break;
2105  }
2106  }
2107  while (true);
2108 }
2109 
2110 
2111 void RpmDb::doRemovePackage( const std::string & name_r, RpmInstFlags flags, callback::SendReport<RpmRemoveReport> & report )
2112 {
2114  HistoryLog historylog;
2115 
2116  MIL << "RpmDb::doRemovePackage(" << name_r << "," << flags << ")" << endl;
2117 
2118  // backup
2119  if ( _packagebackups )
2120  {
2121  // FIXME solve this status report somehow
2122  // report->progress( pd.init( -2, 100 ) ); // allow 1% for backup creation.
2123  if ( ! backupPackage( name_r ) )
2124  {
2125  ERR << "backup of " << name_r << " failed" << endl;
2126  }
2127  report->progress( 0 );
2128  }
2129  else
2130  {
2131  report->progress( 100 );
2132  }
2133 
2134  // run rpm
2135  RpmArgVec opts;
2136  opts.push_back("-e");
2137  opts.push_back("--allmatches");
2138 
2139  if (flags & RPMINST_NOSCRIPTS)
2140  opts.push_back("--noscripts");
2141  if (flags & RPMINST_NODEPS)
2142  opts.push_back("--nodeps");
2143  if (flags & RPMINST_JUSTDB)
2144  opts.push_back("--justdb");
2145  if (flags & RPMINST_TEST)
2146  opts.push_back ("--test");
2147  if (flags & RPMINST_FORCE)
2148  {
2149  WAR << "IGNORE OPTION: 'rpm -e' does not support '--force'" << endl;
2150  }
2151 
2152  opts.push_back("--");
2153  opts.push_back(name_r.c_str());
2154 
2155  modifyDatabase(); // BEFORE run_rpm
2157 
2158  std::string line;
2159  std::string rpmmsg;
2160 
2161  // got no progress from command, so we fake it:
2162  // 5 - command started
2163  // 50 - command completed
2164  // 100 if no error
2165  report->progress( 5 );
2166  unsigned linecnt = 0;
2167  while (systemReadLine(line))
2168  {
2169  if ( linecnt < MAXRPMMESSAGELINES )
2170  ++linecnt;
2171  else
2172  continue;
2173  rpmmsg += line+'\n';
2174  }
2175  if ( linecnt > MAXRPMMESSAGELINES )
2176  rpmmsg += "[truncated]\n";
2177  report->progress( 50 );
2178  int rpm_status = systemStatus();
2179 
2180  if ( rpm_status != 0 )
2181  {
2182  historylog.comment(
2183  str::form("%s remove failed", name_r.c_str()), true /*timestamp*/);
2184  std::ostringstream sstr;
2185  sstr << "rpm output:" << endl << rpmmsg << endl;
2186  historylog.comment(sstr.str());
2187  // TranslatorExplanation the colon is followed by an error message
2188  ZYPP_THROW(RpmSubprocessException(_("RPM failed: ") + (rpmmsg.empty() ? error_message: rpmmsg) ));
2189  }
2190  else if ( ! rpmmsg.empty() )
2191  {
2192  historylog.comment(
2193  str::form("%s removed ok", name_r.c_str()), true /*timestamp*/);
2194 
2195  std::ostringstream sstr;
2196  sstr << "Additional rpm output:" << endl << rpmmsg << endl;
2197  historylog.comment(sstr.str());
2198 
2199  // report additional rpm output in finish
2200  // TranslatorExplanation Text is followed by a ':' and the actual output.
2201  report->finishInfo(str::form( "%s:\n%s\n", _("Additional rpm output"), rpmmsg.c_str() ));
2202  }
2203 }
2204 
2206 //
2207 //
2208 // METHOD NAME : RpmDb::backupPackage
2209 // METHOD TYPE : bool
2210 //
2211 bool RpmDb::backupPackage( const Pathname & filename )
2212 {
2214  if ( ! h )
2215  return false;
2216 
2217  return backupPackage( h->tag_name() );
2218 }
2219 
2221 //
2222 //
2223 // METHOD NAME : RpmDb::backupPackage
2224 // METHOD TYPE : bool
2225 //
2226 bool RpmDb::backupPackage(const std::string& packageName)
2227 {
2228  HistoryLog progresslog;
2229  bool ret = true;
2230  Pathname backupFilename;
2231  Pathname filestobackupfile = _root+_backuppath+FILEFORBACKUPFILES;
2232 
2233  if (_backuppath.empty())
2234  {
2235  INT << "_backuppath empty" << endl;
2236  return false;
2237  }
2238 
2240 
2241  if (!queryChangedFiles(fileList, packageName))
2242  {
2243  ERR << "Error while getting changed files for package " <<
2244  packageName << endl;
2245  return false;
2246  }
2247 
2248  if (fileList.size() <= 0)
2249  {
2250  DBG << "package " << packageName << " not changed -> no backup" << endl;
2251  return true;
2252  }
2253 
2255  {
2256  return false;
2257  }
2258 
2259  {
2260  // build up archive name
2261  time_t currentTime = time(0);
2262  struct tm *currentLocalTime = localtime(&currentTime);
2263 
2264  int date = (currentLocalTime->tm_year + 1900) * 10000
2265  + (currentLocalTime->tm_mon + 1) * 100
2266  + currentLocalTime->tm_mday;
2267 
2268  int num = 0;
2269  do
2270  {
2271  backupFilename = _root + _backuppath
2272  + str::form("%s-%d-%d.tar.gz",packageName.c_str(), date, num);
2273 
2274  }
2275  while ( PathInfo(backupFilename).isExist() && num++ < 1000);
2276 
2277  PathInfo pi(filestobackupfile);
2278  if (pi.isExist() && !pi.isFile())
2279  {
2280  ERR << filestobackupfile.asString() << " already exists and is no file" << endl;
2281  return false;
2282  }
2283 
2284  std::ofstream fp ( filestobackupfile.asString().c_str(), std::ios::out|std::ios::trunc );
2285 
2286  if (!fp)
2287  {
2288  ERR << "could not open " << filestobackupfile.asString() << endl;
2289  return false;
2290  }
2291 
2292  for (FileList::const_iterator cit = fileList.begin();
2293  cit != fileList.end(); ++cit)
2294  {
2295  std::string name = *cit;
2296  if ( name[0] == '/' )
2297  {
2298  // remove slash, file must be relative to -C parameter of tar
2299  name = name.substr( 1 );
2300  }
2301  DBG << "saving file "<< name << endl;
2302  fp << name << endl;
2303  }
2304  fp.close();
2305 
2306  const char* const argv[] =
2307  {
2308  "tar",
2309  "-czhP",
2310  "-C",
2311  _root.asString().c_str(),
2312  "--ignore-failed-read",
2313  "-f",
2314  backupFilename.asString().c_str(),
2315  "-T",
2316  filestobackupfile.asString().c_str(),
2317  NULL
2318  };
2319 
2320  // execute tar in inst-sys (we dont know if there is a tar below _root !)
2321  ExternalProgram tar(argv, ExternalProgram::Stderr_To_Stdout, false, -1, true);
2322 
2323  std::string tarmsg;
2324 
2325  // TODO: its probably possible to start tar with -v and watch it adding
2326  // files to report progress
2327  for (std::string output = tar.receiveLine(); output.length() ;output = tar.receiveLine())
2328  {
2329  tarmsg+=output;
2330  }
2331 
2332  int ret = tar.close();
2333 
2334  if ( ret != 0)
2335  {
2336  ERR << "tar failed: " << tarmsg << endl;
2337  ret = false;
2338  }
2339  else
2340  {
2341  MIL << "tar backup ok" << endl;
2342  progresslog.comment(
2343  str::form(_("created backup %s"), backupFilename.asString().c_str())
2344  , /*timestamp*/true);
2345  }
2346 
2347  filesystem::unlink(filestobackupfile);
2348  }
2349 
2350  return ret;
2351 }
2352 
2353 void RpmDb::setBackupPath(const Pathname& path)
2354 {
2355  _backuppath = path;
2356 }
2357 
2358 std::ostream & operator<<( std::ostream & str, RpmDb::CheckPackageResult obj )
2359 {
2360  switch ( obj )
2361  {
2362 #define OUTS(E,S) case RpmDb::E: return str << "["<< (unsigned)obj << "-"<< S << "]"; break
2363  // translators: possible rpm package signature check result [brief]
2364  OUTS( CHK_OK, _("Signature is OK") );
2365  // translators: possible rpm package signature check result [brief]
2366  OUTS( CHK_NOTFOUND, _("Unknown type of signature") );
2367  // translators: possible rpm package signature check result [brief]
2368  OUTS( CHK_FAIL, _("Signature does not verify") );
2369  // translators: possible rpm package signature check result [brief]
2370  OUTS( CHK_NOTTRUSTED, _("Signature is OK, but key is not trusted") );
2371  // translators: possible rpm package signature check result [brief]
2372  OUTS( CHK_NOKEY, _("Signatures public key is not available") );
2373  // translators: possible rpm package signature check result [brief]
2374  OUTS( CHK_ERROR, _("File does not exist or signature can't be checked") );
2375 #undef OUTS
2376  }
2377  return str << "UnknowSignatureCheckError("+str::numstring(obj)+")";
2378 }
2379 
2380 std::ostream & operator<<( std::ostream & str, const RpmDb::CheckPackageDetail & obj )
2381 {
2382  for ( const auto & el : obj )
2383  str << el.second << endl;
2384  return str;
2385 }
2386 
2387 } // namespace rpm
2388 } // namespace target
2389 } // namespace zypp
std::string asString(const Patch::Category &obj)
Definition: Patch.cc:117
std::ostream & operator<<(std::ostream &str, const librpmDb::DbDirInfo &obj)
Definition: librpmDb.cc:544
int assert_dir(const Pathname &path, unsigned mode)
Like 'mkdir -p'.
Definition: PathInfo.cc:320
Interface to gettext.
Interface to the rpm program.
Definition: RpmDb.h:47
#define MIL
Definition: Logger.h:64
unsigned diffFiles(const std::string file1, const std::string file2, std::string &out, int maxlines)
Definition: RpmDb.cc:158
bool hasDbV3ToV4() const
Whether dbV3ToV4 file exists.
Definition: librpmDb.h:474
intrusive_ptr< const RpmHeader > constPtr
Definition: RpmHeader.h:64
bool hasPackage(const std::string &name_r) const
Return true if package is installed.
Definition: RpmDb.cc:1388
static unsigned blockAccess()
Blocks further access to rpmdb.
Definition: librpmDb.cc:326
static std::ostream & dumpState(std::ostream &str)
Dump debug info.
Definition: librpmDb.cc:351
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:321
bool hasProvides(const std::string &tag_r) const
Return true if at least one package provides a certain tag.
Definition: RpmDb.cc:1346
virtual void trustedKeyAdded(const PublicKey &key)
Definition: RpmDb.cc:124
bool kill()
Kill the program.
#define ENUM_OUT(B, C)
static ZConfig & instance()
Singleton ctor.
Definition: Resolver.cc:121
Pathname path() const
Definition: TmpPath.cc:146
Pathname _root
Root directory for all operations.
Definition: RpmDb.h:96
bool findByProvides(const std::string &tag_r)
Reset to iterate all packages that provide a certain tag.
Definition: librpmDb.cc:826
std::string release() const
Release.
Definition: Edition.cc:110
void getData(const std::string &name_r, RpmHeader::constPtr &result_r) const
Get an installed packages data from rpmdb.
Definition: RpmDb.cc:1416
const std::string & asString() const
String representation.
Definition: Pathname.h:90
const std::string & execError() const
Some detail telling why the execution failed, if it failed.
Collect info about what kind of rpmdb seems to be present by looking at paths and filenames...
Definition: librpmDb.h:327
void exportTrustedKeysInZyppKeyRing()
insert all rpm trusted keys into zypp trusted keyring
Definition: RpmDb.cc:1026
#define INT
Definition: Logger.h:68
static void dbAccess()
Access the database at the current default location.
Definition: librpmDb.cc:248
void rebuildDatabase()
Rebuild the rpm database (rpm –rebuilddb).
Definition: RpmDb.cc:776
void installPackage(const Pathname &filename, RpmInstFlags flags=RPMINST_NONE)
install rpm package
Definition: RpmDb.cc:1892
std::string asString() const
Definition: PublicKey.cc:491
void internal_initDatabase(const Pathname &root_r, const Pathname &dbPath_r, DbStateInfoBits &info_r)
Internal helper for initDatabase.
Definition: RpmDb.cc:449
bool findByRequiredBy(const std::string &tag_r)
Reset to iterate all packages that require a certain tag.
Definition: librpmDb.cc:837
static double currentTime()
void modifyDatabase()
Called before the database is modified by installPackage/removePackage.
Definition: RpmDb.cc:706
#define for_(IT, BEG, END)
Convenient for-loops using iterator.
Definition: Easy.h:27
Edition represents [epoch:]version[-release]
Definition: Edition.h:60
bool relative() const
Test for a relative path.
Definition: Pathname.h:117
bool running()
Return whether program is running.
bool illegalArgs() const
Whether constructor arguments were illegal.
Definition: librpmDb.h:433
Convenient building of std::string with boost::format.
Definition: String.h:247
bool hasConflicts(const std::string &tag_r) const
Return true if at least one package conflicts with a certain tag.
Definition: RpmDb.cc:1374
Provide a new empty temporary file and delete it when no longer needed.
Definition: TmpPath.h:126
void importZyppKeyRingTrustedKeys()
iterates through zypp keyring and import all non existant keys into rpm keyring
Definition: RpmDb.cc:1023
std::string form(const char *format,...) __attribute__((format(printf
Printf style construction of std::string.
Definition: String.cc:36
~RpmDb()
Destructor.
Definition: RpmDb.cc:268
bool backupPackage(const std::string &packageName)
create tar.gz of all changed files in a Package
Definition: RpmDb.cc:2226
#define ERR
Definition: Logger.h:66
CheckPackageResult checkPackage(const Pathname &path_r, CheckPackageDetail &detail_r)
Check signature of rpm file on disk.
Definition: RpmDb.cc:1494
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:1273
#define FILEFORBACKUPFILES
Definition: RpmDb.cc:56
Subclass to retrieve database content.
Definition: librpmDb.h:490
Temporarily connect a ReceiveReport then restore the previous one.
Definition: Callback.h:284
std::string gpgPubkeyVersion() const
Definition: PublicKey.cc:485
bool hasDbV4() const
Whether dbV4 file exists.
Definition: librpmDb.h:458
void importPubkey(const PublicKey &pubkey_r)
Import ascii armored public key in file pubkey_r.
Definition: RpmDb.cc:1035
std::string id() const
Definition: PublicKey.cc:461
void systemKill()
Forcably kill the system process.
Definition: RpmDb.cc:1788
bool dbsi_has(const DbStateInfoBits &val_r, const unsigned &bits_r) const
Definition: RpmDb.h:83
#define ZYPP_RETHROW(EXCPT)
Drops a logline and rethrows, updating the CodeLocation.
Definition: Exception.h:329
void syncTrustedKeys(SyncTrustedKeyBits mode_r=SYNC_BOTH)
Sync trusted keys stored in rpm database and zypp trusted keyring.
Definition: RpmDb.cc:964
#define FAILIFNOTINITIALIZED
Definition: RpmDb.cc:236
Pathname path() const
File containig the ASCII armored key.
Definition: PublicKey.cc:455
std::string getline(std::istream &str)
Read one line from stream.
Definition: IOStream.cc:33
virtual std::ostream & dumpOn(std::ostream &str) const
Dump debug info.
Definition: RpmDb.cc:300
Store and operate on date (time_t).
Definition: Date.h:32
Pathname _backuppath
/var/adm/backup
Definition: RpmDb.h:397
const PathInfo & dbV3ToV4() const
rpmV3 database backup created on conversion to rpmV4 (_dbDir/packages.rpm3)
Definition: librpmDb.h:416
unsigned split(const C_Str &line_r, TOutputIterator result_r, const C_Str &sepchars_r=" \t")
Split line_r into words.
Definition: String.h:518
int exit_code
The exit code of the rpm process, or -1 if not yet known.
Definition: RpmDb.h:388
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 'unlink'.
Definition: PathInfo.cc:653
std::string asString() const
Definition: IdStringType.h:106
shared_ptr< RpmException > dbError() const
Return any database error.
Definition: librpmDb.cc:775
SyncTrustedKeyBits
Sync mode for syncTrustedKeys.
Definition: RpmDb.h:327
bool systemReadLine(std::string &line)
Read a line from the general rpm query.
Definition: RpmDb.cc:1691
#define WARNINGMAILPATH
Definition: RpmDb.cc:55
int rename(const Pathname &oldpath, const Pathname &newpath)
Like 'rename'.
Definition: PathInfo.cc:667
int systemStatus()
Return the exit status of the general rpm process, closing the connection if not already done...
Definition: RpmDb.cc:1765
bool findByName(const std::string &name_r)
Reset to iterate all packages with a certain name.
Definition: librpmDb.cc:859
const char * c_str() const
String representation.
Definition: Pathname.h:109
int recursive_rmdir(const Pathname &path)
Like 'rm -r DIR'.
Definition: PathInfo.cc:413
#define WAR
Definition: Logger.h:65
Detailed rpm signature check log messages A single multiline message if CHK_OK.
Definition: RpmDb.h:443
bool startsWith(const C_Str &str_r, const C_Str &prefix_r)
alias for hasPrefix
Definition: String.h:1057
static unsigned dbRelease(bool force_r=false)
If there are no outstanding references to the database (e.g.
Definition: librpmDb.cc:289
static shared_ptr< KeyRingSignalReceiver > sKeyRingReceiver
Definition: RpmDb.cc:156
bool hasDbV3() const
Whether dbV3 file exists.
Definition: librpmDb.h:466
FILE * _f
Definition: RpmDb.cc:1479
std::string version() const
Version.
Definition: Edition.cc:94
ExternalProgram * process
The connection to the rpm process.
Definition: RpmDb.h:351
#define nullptr
Definition: Easy.h:54
Writing the zypp history fileReference counted signleton for writhing the zypp history file...
Definition: HistoryLog.h:55
void doRebuildDatabase(callback::SendReport< RebuildDBReport > &report)
Definition: RpmDb.cc:794
#define _(MSG)
Definition: Gettext.h:29
std::set< Edition > pubkeyEditions() const
Return the edition of all installed public keys.
Definition: RpmDb.cc:1249
bool findByFile(const std::string &file_r)
Reset to iterate all packages that own a certain file.
Definition: librpmDb.cc:815
std::string receiveLine()
Read one line from the input stream.
const Pathname & root() const
Definition: RpmDb.h:151
void closeDatabase()
Block further access to the rpm database and go back to uninitialized state.
Definition: RpmDb.cc:729
Stderr_Disposition
Define symbols for different policies on the handling of stderr.
DbStateInfoBits _dbStateInfo
Internal state info.
Definition: RpmDb.h:91
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:211
FILE * inputFile() const
Return the input stream.
std::string numstring(char n, int w=0)
Definition: String.h:304
export rpm trusted keys into zypp trusted keyring
Definition: RpmDb.h:330
#define OUTS(E, S)
SolvableIdType size_type
Definition: PoolMember.h:126
virtual void trustedKeyRemoved(const PublicKey &key)
Definition: RpmDb.cc:138
bool findPackage(const std::string &name_r)
Find package by name.
static void unblockAccess()
Allow access to rpmdb e.g.
Definition: librpmDb.cc:339
std::ostream & copy(std::istream &from_r, std::ostream &to_r)
Copy istream to ostream.
Definition: IOStream.h:50
void doInstallPackage(const Pathname &filename, RpmInstFlags flags, callback::SendReport< RpmInstallReport > &report)
Definition: RpmDb.cc:1922
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:1140
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:1795
int copy(const Pathname &file, const Pathname &dest)
Like 'cp file dest'.
Definition: PathInfo.cc:745
const PathInfo & dbV4() const
rpmV4 database (_dbDir/Packages)
Definition: librpmDb.h:400
bool _packagebackups
create package backups?
Definition: RpmDb.h:400
#define ZYPP_CAUGHT(EXCPT)
Drops a logline telling the Exception was caught (in order to handle it).
Definition: Exception.h:325
bool hasRequiredBy(const std::string &tag_r) const
Return true if at least one package requires a certain tag.
Definition: RpmDb.cc:1360
Class representing one GPG Public Key (PublicKeyData + ASCII armored in a tempfile).
Definition: PublicKey.h:208
void doRemovePackage(const std::string &name_r, RpmInstFlags flags, callback::SendReport< RpmRemoveReport > &report)
Definition: RpmDb.cc:2111
Base class for Exception.
Definition: Exception.h:143
std::string form(const std::string &format_r) const
Return string representation according to format as localtime.
Definition: Date.h:112
void setBackupPath(const Pathname &path)
set path where package backups are stored
Definition: RpmDb.cc:2353
static Date now()
Return the current time.
Definition: Date.h:78
void convertV3toV4(const Pathname &v3db_r, const librpmDb::constPtr &v4db_r)
callback::SendReport< DownloadProgressReport > * report
Definition: MediaCurl.cc:177
void initDatabase(Pathname root_r=Pathname(), Pathname dbPath_r=Pathname(), bool doRebuild_r=false)
Prepare access to the rpm database.
Definition: RpmDb.cc:331
std::string error_message
Error message from running rpm as external program.
Definition: RpmDb.h:394
void removePackage(const std::string &name_r, RpmInstFlags flags=RPMINST_NONE)
remove rpm package
Definition: RpmDb.cc:2080
static bool globalInit()
Initialize lib librpm (read configfiles etc.).
Definition: librpmDb.cc:128
std::string * _cap
Definition: RpmDb.cc:1480
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:1302
void comment(const std::string &comment, bool timestamp=false)
Log a comment (even multiline).
Definition: HistoryLog.cc:188
std::string asUserHistory() const
A single (multiline) string composed of asUserString and historyAsString.
Definition: Exception.cc:75
Date timestamp() const
timestamp of the rpm database (last modification)
Definition: RpmDb.cc:277
const Pathname & dbPath() const
Definition: RpmDb.h:159
bool findByConflicts(const std::string &tag_r)
Reset to iterate all packages that conflict with a certain tag.
Definition: librpmDb.cc:848
const PathInfo & dbDir() const
database directory (unset on illegal constructor arguments)
Definition: librpmDb.h:392
void setBlocking(bool mode)
Set the blocking mode of the input stream.
CheckPackageResult
checkPackage result
Definition: RpmDb.h:429
std::list< PublicKey > pubkeys() const
Return the long ids of all installed public keys.
Definition: RpmDb.cc:1211
void dbsi_set(DbStateInfoBits &val_r, const unsigned &bits_r) const
Definition: RpmDb.h:75
std::string stringPath(const Pathname &root_r, const Pathname &sub_r)
Definition: RpmDb.cc:194
static void removeV3(const Pathname &dbdir_r, bool v3backup_r)
Remove the rpm3 database in dbdir_r.
Definition: RpmDb.cc:640
bool queryChangedFiles(FileList &fileList, const std::string &packageName)
determine which files of an installed package have been modified.
Definition: RpmDb.cc:1579
pid_t getpid()
return pid
void dbsi_clr(DbStateInfoBits &val_r, const unsigned &bits_r) const
Definition: RpmDb.h:79
static void removeV4(const Pathname &dbdir_r, bool v3backup_r)
Remove the rpm4 database in dbdir_r and optionally any backup created on conversion.
Definition: RpmDb.cc:574
bool initialized() const
Definition: RpmDb.h:167
std::string strerror(int errno_r)
Return string describing the error_r code.
Definition: String.cc:53
std::ostream & operator<<(std::ostream &str, const Glob &obj)
Definition: Glob.cc:53
bool usableArgs() const
Whether constructor arguments were llegal and dbDir either is a directory or may be created (path doe...
Definition: librpmDb.h:442
const PathInfo & dbV3() const
rpmV3 database (_dbDir/packages.rpm)
Definition: librpmDb.h:408
intrusive_ptr< const librpmDb > constPtr
Definition: librpmDb.h:42
std::string gpgPubkeyRelease() const
Definition: PublicKey.cc:488
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:1645
std::string name() const
Definition: PublicKey.cc:464
void restat()
Restat all paths.
Definition: librpmDb.cc:529
TraitsType::constPtrType constPtr
Definition: Package.h:38
#define MAXRPMMESSAGELINES
Definition: RpmDb.cc:57
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:1328
#define DBG
Definition: Logger.h:63
static const Edition noedition
Value representing noedition ("") This is in fact a valid Edition.
Definition: Edition.h:73
Pathname _dbPath
Directory that contains the rpmdb.
Definition: RpmDb.h:101
std::set< std::string > FileList
Definition: RpmDb.h:423
std::vector< const char * > RpmArgVec
Definition: RpmDb.h:353