libzypp  16.15.3
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  RpmDb::CheckPackageResult doCheckPackageSig( const Pathname & path_r, // rpm file to check
1488  const Pathname & root_r, // target root
1489  bool requireGPGSig_r, // whether no gpg signature is to be reported
1490  RpmDb::CheckPackageDetail & detail_r ) // detailed result
1491  {
1492  PathInfo file( path_r );
1493  if ( ! file.isFile() )
1494  {
1495  ERR << "Not a file: " << file << endl;
1496  return RpmDb::CHK_ERROR;
1497  }
1498 
1499  FD_t fd = ::Fopen( file.asString().c_str(), "r.ufdio" );
1500  if ( fd == 0 || ::Ferror(fd) )
1501  {
1502  ERR << "Can't open file for reading: " << file << " (" << ::Fstrerror(fd) << ")" << endl;
1503  if ( fd )
1504  ::Fclose( fd );
1505  return RpmDb::CHK_ERROR;
1506  }
1507  rpmts ts = ::rpmtsCreate();
1508  ::rpmtsSetRootDir( ts, root_r.c_str() );
1509  ::rpmtsSetVSFlags( ts, RPMVSF_DEFAULT );
1510 
1511  rpmQVKArguments_s qva;
1512  memset( &qva, 0, sizeof(rpmQVKArguments_s) );
1513  qva.qva_flags = (VERIFY_DIGEST|VERIFY_SIGNATURE);
1514 
1515  RpmlogCapture vresult;
1516  int res = ::rpmVerifySignatures( &qva, ts, fd, path_r.basename().c_str() );
1517 
1518  ts = rpmtsFree(ts);
1519  ::Fclose( fd );
1520 
1521  // results per line...
1522  // Header V3 RSA/SHA256 Signature, key ID 3dbdc284: OK
1523  // Header SHA1 digest: OK (a60386347863affefef484ff1f26c889373eb094)
1524  // V3 RSA/SHA256 Signature, key ID 3dbdc284: OK
1525  // MD5 digest: OK (fd5259fe677a406951dcb2e9d08c4dcc)
1526  //
1527  // TODO: try to get SIG info from the header rather than parsing the output
1528  std::vector<std::string> lines;
1529  str::split( vresult, std::back_inserter(lines), "\n" );
1530  unsigned count[7] = { 0, 0, 0, 0, 0, 0, 0 };
1531 
1532  for ( unsigned i = 1; i < lines.size(); ++i )
1533  {
1534  std::string & line( lines[i] );
1536  if ( line.find( ": OK" ) != std::string::npos )
1537  {
1538  lineres = RpmDb::CHK_OK;
1539  if ( line.find( "Signature, key ID" ) == std::string::npos )
1540  ++count[RpmDb::CHK_NOSIG]; // Valid but no gpg signature -> CHK_NOSIG
1541  }
1542  else if ( line.find( ": NOKEY" ) != std::string::npos )
1543  { lineres = RpmDb::CHK_NOKEY; }
1544  else if ( line.find( ": BAD" ) != std::string::npos )
1545  { lineres = RpmDb::CHK_FAIL; }
1546  else if ( line.find( ": UNKNOWN" ) != std::string::npos )
1547  { lineres = RpmDb::CHK_NOTFOUND; }
1548  else if ( line.find( ": NOTRUSTED" ) != std::string::npos )
1549  { lineres = RpmDb::CHK_NOTTRUSTED; }
1550 
1551  ++count[lineres];
1552  detail_r.push_back( RpmDb::CheckPackageDetail::value_type( lineres, std::move(line) ) );
1553  }
1554 
1556 
1557  if ( count[RpmDb::CHK_FAIL] )
1558  ret = RpmDb::CHK_FAIL;
1559 
1560  else if ( count[RpmDb::CHK_NOTFOUND] )
1561  ret = RpmDb::CHK_NOTFOUND;
1562 
1563  else if ( count[RpmDb::CHK_NOKEY] )
1564  ret = RpmDb::CHK_NOKEY;
1565 
1566  else if ( count[RpmDb::CHK_NOTTRUSTED] )
1567  ret = RpmDb::CHK_NOTTRUSTED;
1568 
1569  else if ( ret == RpmDb::CHK_OK )
1570  {
1571  if ( count[RpmDb::CHK_OK] == count[RpmDb::CHK_NOSIG] )
1572  {
1573  detail_r.push_back( RpmDb::CheckPackageDetail::value_type( RpmDb::CHK_NOSIG, std::string(" ")+_("Package is not signed!") ) );
1574  if ( requireGPGSig_r )
1575  ret = RpmDb::CHK_NOSIG;
1576  }
1577  }
1578 
1579  if ( ret != RpmDb::CHK_OK )
1580  {
1581  WAR << path_r << " (" << requireGPGSig_r << " -> " << ret << ")" << endl;
1582  WAR << vresult;
1583  }
1584  return ret;
1585  }
1586 
1587 } // namespace
1589 //
1590 // METHOD NAME : RpmDb::checkPackage
1591 // METHOD TYPE : RpmDb::CheckPackageResult
1592 //
1594 { return doCheckPackageSig( path_r, root(), false/*requireGPGSig_r*/, detail_r ); }
1595 
1597 { CheckPackageDetail dummy; return checkPackage( path_r, dummy ); }
1598 
1600 { return doCheckPackageSig( path_r, root(), true/*requireGPGSig_r*/, detail_r ); }
1601 
1602 
1603 // determine changed files of installed package
1604 bool
1605 RpmDb::queryChangedFiles(FileList & fileList, const std::string& packageName)
1606 {
1607  bool ok = true;
1608 
1609  fileList.clear();
1610 
1611  if ( ! initialized() ) return false;
1612 
1613  RpmArgVec opts;
1614 
1615  opts.push_back ("-V");
1616  opts.push_back ("--nodeps");
1617  opts.push_back ("--noscripts");
1618  opts.push_back ("--nomd5");
1619  opts.push_back ("--");
1620  opts.push_back (packageName.c_str());
1621 
1623 
1624  if ( process == NULL )
1625  return false;
1626 
1627  /* from rpm manpage
1628  5 MD5 sum
1629  S File size
1630  L Symlink
1631  T Mtime
1632  D Device
1633  U User
1634  G Group
1635  M Mode (includes permissions and file type)
1636  */
1637 
1638  std::string line;
1639  while (systemReadLine(line))
1640  {
1641  if (line.length() > 12 &&
1642  (line[0] == 'S' || line[0] == 's' ||
1643  (line[0] == '.' && line[7] == 'T')))
1644  {
1645  // file has been changed
1646  std::string filename;
1647 
1648  filename.assign(line, 11, line.length() - 11);
1649  fileList.insert(filename);
1650  }
1651  }
1652 
1653  systemStatus();
1654  // exit code ignored, rpm returns 1 no matter if package is installed or
1655  // not
1656 
1657  return ok;
1658 }
1659 
1660 
1661 
1662 /****************************************************************/
1663 /* private member-functions */
1664 /****************************************************************/
1665 
1666 /*--------------------------------------------------------------*/
1667 /* Run rpm with the specified arguments, handling stderr */
1668 /* as specified by disp */
1669 /*--------------------------------------------------------------*/
1670 void
1673 {
1674  if ( process )
1675  {
1676  delete process;
1677  process = NULL;
1678  }
1679  exit_code = -1;
1680 
1681  if ( ! initialized() )
1682  {
1684  }
1685 
1686  RpmArgVec args;
1687 
1688  // always set root and dbpath
1689 #if defined(WORKAROUNDRPMPWDBUG)
1690  args.push_back("#/"); // chdir to / to workaround bnc#819354
1691 #endif
1692  args.push_back("rpm");
1693  args.push_back("--root");
1694  args.push_back(_root.asString().c_str());
1695  args.push_back("--dbpath");
1696  args.push_back(_dbPath.asString().c_str());
1697 
1698  const char* argv[args.size() + opts.size() + 1];
1699 
1700  const char** p = argv;
1701  p = copy (args.begin (), args.end (), p);
1702  p = copy (opts.begin (), opts.end (), p);
1703  *p = 0;
1704 
1705  // Invalidate all outstanding database handles in case
1706  // the database gets modified.
1707  librpmDb::dbRelease( true );
1708 
1709  // Launch the program with default locale
1710  process = new ExternalProgram(argv, disp, false, -1, true);
1711  return;
1712 }
1713 
1714 /*--------------------------------------------------------------*/
1715 /* Read a line from the rpm process */
1716 /*--------------------------------------------------------------*/
1717 bool RpmDb::systemReadLine( std::string & line )
1718 {
1719  line.erase();
1720 
1721  if ( process == NULL )
1722  return false;
1723 
1724  if ( process->inputFile() )
1725  {
1726  process->setBlocking( false );
1727  FILE * inputfile = process->inputFile();
1728  int inputfileFd = ::fileno( inputfile );
1729  do
1730  {
1731  /* Watch inputFile to see when it has input. */
1732  fd_set rfds;
1733  FD_ZERO( &rfds );
1734  FD_SET( inputfileFd, &rfds );
1735 
1736  /* Wait up to 5 seconds. */
1737  struct timeval tv;
1738  tv.tv_sec = 5;
1739  tv.tv_usec = 0;
1740 
1741  int retval = select( inputfileFd+1, &rfds, NULL, NULL, &tv );
1742 
1743  if ( retval == -1 )
1744  {
1745  ERR << "select error: " << strerror(errno) << endl;
1746  if ( errno != EINTR )
1747  return false;
1748  }
1749  else if ( retval )
1750  {
1751  // Data is available now.
1752  static size_t linebuffer_size = 0; // static because getline allocs
1753  static char * linebuffer = 0; // and reallocs if buffer is too small
1754  ssize_t nread = getline( &linebuffer, &linebuffer_size, inputfile );
1755  if ( nread == -1 )
1756  {
1757  if ( ::feof( inputfile ) )
1758  return line.size(); // in case of pending output
1759  }
1760  else
1761  {
1762  if ( nread > 0 )
1763  {
1764  if ( linebuffer[nread-1] == '\n' )
1765  --nread;
1766  line += std::string( linebuffer, nread );
1767  }
1768 
1769  if ( ! ::ferror( inputfile ) || ::feof( inputfile ) )
1770  return true; // complete line
1771  }
1772  clearerr( inputfile );
1773  }
1774  else
1775  {
1776  // No data within time.
1777  if ( ! process->running() )
1778  return false;
1779  }
1780  } while ( true );
1781  }
1782 
1783  return false;
1784 }
1785 
1786 /*--------------------------------------------------------------*/
1787 /* Return the exit status of the rpm process, closing the */
1788 /* connection if not already done */
1789 /*--------------------------------------------------------------*/
1790 int
1792 {
1793  if ( process == NULL )
1794  return -1;
1795 
1796  exit_code = process->close();
1797  if (exit_code == 0)
1798  error_message = "";
1799  else
1801  process->kill();
1802  delete process;
1803  process = 0;
1804 
1805  // DBG << "exit code " << exit_code << endl;
1806 
1807  return exit_code;
1808 }
1809 
1810 /*--------------------------------------------------------------*/
1811 /* Forcably kill the rpm process */
1812 /*--------------------------------------------------------------*/
1813 void
1815 {
1816  if (process) process->kill();
1817 }
1818 
1819 
1820 // generate diff mails for config files
1821 void RpmDb::processConfigFiles(const std::string& line, const std::string& name, const char* typemsg, const char* difffailmsg, const char* diffgenmsg)
1822 {
1823  std::string msg = line.substr(9);
1824  std::string::size_type pos1 = std::string::npos;
1825  std::string::size_type pos2 = std::string::npos;
1826  std::string file1s, file2s;
1827  Pathname file1;
1828  Pathname file2;
1829 
1830  pos1 = msg.find (typemsg);
1831  for (;;)
1832  {
1833  if ( pos1 == std::string::npos )
1834  break;
1835 
1836  pos2 = pos1 + strlen (typemsg);
1837 
1838  if (pos2 >= msg.length() )
1839  break;
1840 
1841  file1 = msg.substr (0, pos1);
1842  file2 = msg.substr (pos2);
1843 
1844  file1s = file1.asString();
1845  file2s = file2.asString();
1846 
1847  if (!_root.empty() && _root != "/")
1848  {
1849  file1 = _root + file1;
1850  file2 = _root + file2;
1851  }
1852 
1853  std::string out;
1854  int ret = diffFiles (file1.asString(), file2.asString(), out, 25);
1855  if (ret)
1856  {
1857  Pathname file = _root + WARNINGMAILPATH;
1858  if (filesystem::assert_dir(file) != 0)
1859  {
1860  ERR << "Could not create " << file.asString() << endl;
1861  break;
1862  }
1863  file += Date(Date::now()).form("config_diff_%Y_%m_%d.log");
1864  std::ofstream notify(file.asString().c_str(), std::ios::out|std::ios::app);
1865  if (!notify)
1866  {
1867  ERR << "Could not open " << file << endl;
1868  break;
1869  }
1870 
1871  // Translator: %s = name of an rpm package. A list of diffs follows
1872  // this message.
1873  notify << str::form(_("Changed configuration files for %s:"), name.c_str()) << endl;
1874  if (ret>1)
1875  {
1876  ERR << "diff failed" << endl;
1877  notify << str::form(difffailmsg,
1878  file1s.c_str(), file2s.c_str()) << endl;
1879  }
1880  else
1881  {
1882  notify << str::form(diffgenmsg,
1883  file1s.c_str(), file2s.c_str()) << endl;
1884 
1885  // remove root for the viewer's pleasure (#38240)
1886  if (!_root.empty() && _root != "/")
1887  {
1888  if (out.substr(0,4) == "--- ")
1889  {
1890  out.replace(4, file1.asString().length(), file1s);
1891  }
1892  std::string::size_type pos = out.find("\n+++ ");
1893  if (pos != std::string::npos)
1894  {
1895  out.replace(pos+5, file2.asString().length(), file2s);
1896  }
1897  }
1898  notify << out << endl;
1899  }
1900  notify.close();
1901  notify.open("/var/lib/update-messages/yast2-packagemanager.rpmdb.configfiles");
1902  notify.close();
1903  }
1904  else
1905  {
1906  WAR << "rpm created " << file2 << " but it is not different from " << file2 << endl;
1907  }
1908  break;
1909  }
1910 }
1911 
1913 //
1914 //
1915 // METHOD NAME : RpmDb::installPackage
1916 // METHOD TYPE : PMError
1917 //
1918 void RpmDb::installPackage( const Pathname & filename, RpmInstFlags flags )
1919 {
1921 
1922  report->start(filename);
1923 
1924  do
1925  try
1926  {
1927  doInstallPackage(filename, flags, report);
1928  report->finish();
1929  break;
1930  }
1931  catch (RpmException & excpt_r)
1932  {
1933  RpmInstallReport::Action user = report->problem( excpt_r );
1934 
1935  if ( user == RpmInstallReport::ABORT )
1936  {
1937  report->finish( excpt_r );
1938  ZYPP_RETHROW(excpt_r);
1939  }
1940  else if ( user == RpmInstallReport::IGNORE )
1941  {
1942  break;
1943  }
1944  }
1945  while (true);
1946 }
1947 
1948 void RpmDb::doInstallPackage( const Pathname & filename, RpmInstFlags flags, callback::SendReport<RpmInstallReport> & report )
1949 {
1951  HistoryLog historylog;
1952 
1953  MIL << "RpmDb::installPackage(" << filename << "," << flags << ")" << endl;
1954 
1955 
1956  // backup
1957  if ( _packagebackups )
1958  {
1959  // FIXME report->progress( pd.init( -2, 100 ) ); // allow 1% for backup creation.
1960  if ( ! backupPackage( filename ) )
1961  {
1962  ERR << "backup of " << filename.asString() << " failed" << endl;
1963  }
1964  // FIXME status handling
1965  report->progress( 0 ); // allow 1% for backup creation.
1966  }
1967 
1968  // run rpm
1969  RpmArgVec opts;
1970  if (flags & RPMINST_NOUPGRADE)
1971  opts.push_back("-i");
1972  else
1973  opts.push_back("-U");
1974 
1975  opts.push_back("--percent");
1976  opts.push_back("--noglob");
1977 
1978  // ZConfig defines cross-arch installation
1979  if ( ! ZConfig::instance().systemArchitecture().compatibleWith( ZConfig::instance().defaultSystemArchitecture() ) )
1980  opts.push_back("--ignorearch");
1981 
1982  if (flags & RPMINST_NODIGEST)
1983  opts.push_back("--nodigest");
1984  if (flags & RPMINST_NOSIGNATURE)
1985  opts.push_back("--nosignature");
1986  if (flags & RPMINST_EXCLUDEDOCS)
1987  opts.push_back ("--excludedocs");
1988  if (flags & RPMINST_NOSCRIPTS)
1989  opts.push_back ("--noscripts");
1990  if (flags & RPMINST_FORCE)
1991  opts.push_back ("--force");
1992  if (flags & RPMINST_NODEPS)
1993  opts.push_back ("--nodeps");
1994  if (flags & RPMINST_IGNORESIZE)
1995  opts.push_back ("--ignoresize");
1996  if (flags & RPMINST_JUSTDB)
1997  opts.push_back ("--justdb");
1998  if (flags & RPMINST_TEST)
1999  opts.push_back ("--test");
2000  if (flags & RPMINST_NOPOSTTRANS)
2001  opts.push_back ("--noposttrans");
2002 
2003  opts.push_back("--");
2004 
2005  // rpm requires additional quoting of special chars:
2006  std::string quotedFilename( rpmQuoteFilename( workaroundRpmPwdBug( filename ) ) );
2007  opts.push_back ( quotedFilename.c_str() );
2008 
2009  modifyDatabase(); // BEFORE run_rpm
2011 
2012  std::string line;
2013  std::string rpmmsg;
2014  std::vector<std::string> configwarnings;
2015 
2016  unsigned linecnt = 0;
2017  while (systemReadLine(line))
2018  {
2019  if ( linecnt < MAXRPMMESSAGELINES )
2020  ++linecnt;
2021  else
2022  continue;
2023 
2024  if (line.substr(0,2)=="%%")
2025  {
2026  int percent;
2027  sscanf (line.c_str () + 2, "%d", &percent);
2028  report->progress( percent );
2029  }
2030  else
2031  rpmmsg += line+'\n';
2032 
2033  if ( line.substr(0,8) == "warning:" )
2034  {
2035  configwarnings.push_back(line);
2036  }
2037  }
2038  if ( linecnt > MAXRPMMESSAGELINES )
2039  rpmmsg += "[truncated]\n";
2040 
2041  int rpm_status = systemStatus();
2042 
2043  // evaluate result
2044  for (std::vector<std::string>::iterator it = configwarnings.begin();
2045  it != configwarnings.end(); ++it)
2046  {
2047  processConfigFiles(*it, Pathname::basename(filename), " saved as ",
2048  // %s = filenames
2049  _("rpm saved %s as %s, but it was impossible to determine the difference"),
2050  // %s = filenames
2051  _("rpm saved %s as %s.\nHere are the first 25 lines of difference:\n"));
2052  processConfigFiles(*it, Pathname::basename(filename), " created as ",
2053  // %s = filenames
2054  _("rpm created %s as %s, but it was impossible to determine the difference"),
2055  // %s = filenames
2056  _("rpm created %s as %s.\nHere are the first 25 lines of difference:\n"));
2057  }
2058 
2059  if ( rpm_status != 0 )
2060  {
2061  historylog.comment(
2062  str::form("%s install failed", Pathname::basename(filename).c_str()),
2063  true /*timestamp*/);
2064  std::ostringstream sstr;
2065  sstr << "rpm output:" << endl << rpmmsg << endl;
2066  historylog.comment(sstr.str());
2067  // TranslatorExplanation the colon is followed by an error message
2068  ZYPP_THROW(RpmSubprocessException(_("RPM failed: ") + (rpmmsg.empty() ? error_message : rpmmsg) ));
2069  }
2070  else if ( ! rpmmsg.empty() )
2071  {
2072  historylog.comment(
2073  str::form("%s installed ok", Pathname::basename(filename).c_str()),
2074  true /*timestamp*/);
2075  std::ostringstream sstr;
2076  sstr << "Additional rpm output:" << endl << rpmmsg << endl;
2077  historylog.comment(sstr.str());
2078 
2079  // report additional rpm output in finish
2080  // TranslatorExplanation Text is followed by a ':' and the actual output.
2081  report->finishInfo(str::form( "%s:\n%s\n", _("Additional rpm output"), rpmmsg.c_str() ));
2082  }
2083 }
2084 
2086 //
2087 //
2088 // METHOD NAME : RpmDb::removePackage
2089 // METHOD TYPE : PMError
2090 //
2091 void RpmDb::removePackage( Package::constPtr package, RpmInstFlags flags )
2092 {
2093  // 'rpm -e' does not like epochs
2094  return removePackage( package->name()
2095  + "-" + package->edition().version()
2096  + "-" + package->edition().release()
2097  + "." + package->arch().asString(), flags );
2098 }
2099 
2101 //
2102 //
2103 // METHOD NAME : RpmDb::removePackage
2104 // METHOD TYPE : PMError
2105 //
2106 void RpmDb::removePackage( const std::string & name_r, RpmInstFlags flags )
2107 {
2109 
2110  report->start( name_r );
2111 
2112  do
2113  try
2114  {
2115  doRemovePackage(name_r, flags, report);
2116  report->finish();
2117  break;
2118  }
2119  catch (RpmException & excpt_r)
2120  {
2121  RpmRemoveReport::Action user = report->problem( excpt_r );
2122 
2123  if ( user == RpmRemoveReport::ABORT )
2124  {
2125  report->finish( excpt_r );
2126  ZYPP_RETHROW(excpt_r);
2127  }
2128  else if ( user == RpmRemoveReport::IGNORE )
2129  {
2130  break;
2131  }
2132  }
2133  while (true);
2134 }
2135 
2136 
2137 void RpmDb::doRemovePackage( const std::string & name_r, RpmInstFlags flags, callback::SendReport<RpmRemoveReport> & report )
2138 {
2140  HistoryLog historylog;
2141 
2142  MIL << "RpmDb::doRemovePackage(" << name_r << "," << flags << ")" << endl;
2143 
2144  // backup
2145  if ( _packagebackups )
2146  {
2147  // FIXME solve this status report somehow
2148  // report->progress( pd.init( -2, 100 ) ); // allow 1% for backup creation.
2149  if ( ! backupPackage( name_r ) )
2150  {
2151  ERR << "backup of " << name_r << " failed" << endl;
2152  }
2153  report->progress( 0 );
2154  }
2155  else
2156  {
2157  report->progress( 100 );
2158  }
2159 
2160  // run rpm
2161  RpmArgVec opts;
2162  opts.push_back("-e");
2163  opts.push_back("--allmatches");
2164 
2165  if (flags & RPMINST_NOSCRIPTS)
2166  opts.push_back("--noscripts");
2167  if (flags & RPMINST_NODEPS)
2168  opts.push_back("--nodeps");
2169  if (flags & RPMINST_JUSTDB)
2170  opts.push_back("--justdb");
2171  if (flags & RPMINST_TEST)
2172  opts.push_back ("--test");
2173  if (flags & RPMINST_FORCE)
2174  {
2175  WAR << "IGNORE OPTION: 'rpm -e' does not support '--force'" << endl;
2176  }
2177 
2178  opts.push_back("--");
2179  opts.push_back(name_r.c_str());
2180 
2181  modifyDatabase(); // BEFORE run_rpm
2183 
2184  std::string line;
2185  std::string rpmmsg;
2186 
2187  // got no progress from command, so we fake it:
2188  // 5 - command started
2189  // 50 - command completed
2190  // 100 if no error
2191  report->progress( 5 );
2192  unsigned linecnt = 0;
2193  while (systemReadLine(line))
2194  {
2195  if ( linecnt < MAXRPMMESSAGELINES )
2196  ++linecnt;
2197  else
2198  continue;
2199  rpmmsg += line+'\n';
2200  }
2201  if ( linecnt > MAXRPMMESSAGELINES )
2202  rpmmsg += "[truncated]\n";
2203  report->progress( 50 );
2204  int rpm_status = systemStatus();
2205 
2206  if ( rpm_status != 0 )
2207  {
2208  historylog.comment(
2209  str::form("%s remove failed", name_r.c_str()), true /*timestamp*/);
2210  std::ostringstream sstr;
2211  sstr << "rpm output:" << endl << rpmmsg << endl;
2212  historylog.comment(sstr.str());
2213  // TranslatorExplanation the colon is followed by an error message
2214  ZYPP_THROW(RpmSubprocessException(_("RPM failed: ") + (rpmmsg.empty() ? error_message: rpmmsg) ));
2215  }
2216  else if ( ! rpmmsg.empty() )
2217  {
2218  historylog.comment(
2219  str::form("%s removed ok", name_r.c_str()), true /*timestamp*/);
2220 
2221  std::ostringstream sstr;
2222  sstr << "Additional rpm output:" << endl << rpmmsg << endl;
2223  historylog.comment(sstr.str());
2224 
2225  // report additional rpm output in finish
2226  // TranslatorExplanation Text is followed by a ':' and the actual output.
2227  report->finishInfo(str::form( "%s:\n%s\n", _("Additional rpm output"), rpmmsg.c_str() ));
2228  }
2229 }
2230 
2232 //
2233 //
2234 // METHOD NAME : RpmDb::backupPackage
2235 // METHOD TYPE : bool
2236 //
2237 bool RpmDb::backupPackage( const Pathname & filename )
2238 {
2240  if ( ! h )
2241  return false;
2242 
2243  return backupPackage( h->tag_name() );
2244 }
2245 
2247 //
2248 //
2249 // METHOD NAME : RpmDb::backupPackage
2250 // METHOD TYPE : bool
2251 //
2252 bool RpmDb::backupPackage(const std::string& packageName)
2253 {
2254  HistoryLog progresslog;
2255  bool ret = true;
2256  Pathname backupFilename;
2257  Pathname filestobackupfile = _root+_backuppath+FILEFORBACKUPFILES;
2258 
2259  if (_backuppath.empty())
2260  {
2261  INT << "_backuppath empty" << endl;
2262  return false;
2263  }
2264 
2266 
2267  if (!queryChangedFiles(fileList, packageName))
2268  {
2269  ERR << "Error while getting changed files for package " <<
2270  packageName << endl;
2271  return false;
2272  }
2273 
2274  if (fileList.size() <= 0)
2275  {
2276  DBG << "package " << packageName << " not changed -> no backup" << endl;
2277  return true;
2278  }
2279 
2281  {
2282  return false;
2283  }
2284 
2285  {
2286  // build up archive name
2287  time_t currentTime = time(0);
2288  struct tm *currentLocalTime = localtime(&currentTime);
2289 
2290  int date = (currentLocalTime->tm_year + 1900) * 10000
2291  + (currentLocalTime->tm_mon + 1) * 100
2292  + currentLocalTime->tm_mday;
2293 
2294  int num = 0;
2295  do
2296  {
2297  backupFilename = _root + _backuppath
2298  + str::form("%s-%d-%d.tar.gz",packageName.c_str(), date, num);
2299 
2300  }
2301  while ( PathInfo(backupFilename).isExist() && num++ < 1000);
2302 
2303  PathInfo pi(filestobackupfile);
2304  if (pi.isExist() && !pi.isFile())
2305  {
2306  ERR << filestobackupfile.asString() << " already exists and is no file" << endl;
2307  return false;
2308  }
2309 
2310  std::ofstream fp ( filestobackupfile.asString().c_str(), std::ios::out|std::ios::trunc );
2311 
2312  if (!fp)
2313  {
2314  ERR << "could not open " << filestobackupfile.asString() << endl;
2315  return false;
2316  }
2317 
2318  for (FileList::const_iterator cit = fileList.begin();
2319  cit != fileList.end(); ++cit)
2320  {
2321  std::string name = *cit;
2322  if ( name[0] == '/' )
2323  {
2324  // remove slash, file must be relative to -C parameter of tar
2325  name = name.substr( 1 );
2326  }
2327  DBG << "saving file "<< name << endl;
2328  fp << name << endl;
2329  }
2330  fp.close();
2331 
2332  const char* const argv[] =
2333  {
2334  "tar",
2335  "-czhP",
2336  "-C",
2337  _root.asString().c_str(),
2338  "--ignore-failed-read",
2339  "-f",
2340  backupFilename.asString().c_str(),
2341  "-T",
2342  filestobackupfile.asString().c_str(),
2343  NULL
2344  };
2345 
2346  // execute tar in inst-sys (we dont know if there is a tar below _root !)
2347  ExternalProgram tar(argv, ExternalProgram::Stderr_To_Stdout, false, -1, true);
2348 
2349  std::string tarmsg;
2350 
2351  // TODO: its probably possible to start tar with -v and watch it adding
2352  // files to report progress
2353  for (std::string output = tar.receiveLine(); output.length() ;output = tar.receiveLine())
2354  {
2355  tarmsg+=output;
2356  }
2357 
2358  int ret = tar.close();
2359 
2360  if ( ret != 0)
2361  {
2362  ERR << "tar failed: " << tarmsg << endl;
2363  ret = false;
2364  }
2365  else
2366  {
2367  MIL << "tar backup ok" << endl;
2368  progresslog.comment(
2369  str::form(_("created backup %s"), backupFilename.asString().c_str())
2370  , /*timestamp*/true);
2371  }
2372 
2373  filesystem::unlink(filestobackupfile);
2374  }
2375 
2376  return ret;
2377 }
2378 
2379 void RpmDb::setBackupPath(const Pathname& path)
2380 {
2381  _backuppath = path;
2382 }
2383 
2384 std::ostream & operator<<( std::ostream & str, RpmDb::CheckPackageResult obj )
2385 {
2386  switch ( obj )
2387  {
2388 #define OUTS(E,S) case RpmDb::E: return str << "["<< (unsigned)obj << "-"<< S << "]"; break
2389  // translators: possible rpm package signature check result [brief]
2390  OUTS( CHK_OK, _("Signature is OK") );
2391  // translators: possible rpm package signature check result [brief]
2392  OUTS( CHK_NOTFOUND, _("Unknown type of signature") );
2393  // translators: possible rpm package signature check result [brief]
2394  OUTS( CHK_FAIL, _("Signature does not verify") );
2395  // translators: possible rpm package signature check result [brief]
2396  OUTS( CHK_NOTTRUSTED, _("Signature is OK, but key is not trusted") );
2397  // translators: possible rpm package signature check result [brief]
2398  OUTS( CHK_NOKEY, _("Signatures public key is not available") );
2399  // translators: possible rpm package signature check result [brief]
2400  OUTS( CHK_ERROR, _("File does not exist or signature can't be checked") );
2401  // translators: possible rpm package signature check result [brief]
2402  OUTS( CHK_NOSIG, _("File is unsigned") );
2403 #undef OUTS
2404  }
2405  return str << "UnknowSignatureCheckError("+str::numstring(obj)+")";
2406 }
2407 
2408 std::ostream & operator<<( std::ostream & str, const RpmDb::CheckPackageDetail & obj )
2409 {
2410  for ( const auto & el : obj )
2411  str << el.second << endl;
2412  return str;
2413 }
2414 
2415 } // namespace rpm
2416 } // namespace target
2417 } // namespace zypp
int assert_dir(const Pathname &path, unsigned mode)
Like &#39;mkdir -p&#39;.
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
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:1599
intrusive_ptr< const RpmHeader > constPtr
Definition: RpmHeader.h:64
std::string gpgPubkeyRelease() const
Gpg-pubkey release as computed by rpm (hexencoded created)
Definition: PublicKey.cc:139
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
std::string basename() const
Return the last component of this path.
Definition: Pathname.h:124
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:125
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
Class representing one GPG Public Keys data.
Definition: PublicKey.h:74
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:1918
std::string asString() const
Definition: PublicKey.cc:490
void internal_initDatabase(const Pathname &root_r, const Pathname &dbPath_r, DbStateInfoBits &info_r)
Internal helper for initDatabase.
Definition: RpmDb.cc:449
String related utilities and Regular expression matching.
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
std::string gpgPubkeyVersion() const
Gpg-pubkey version as computed by rpm (trailing 8 byte id)
Definition: PublicKey.cc:136
#define for_(IT, BEG, END)
Convenient for-loops using iterator.
Definition: Easy.h:27
Edition represents [epoch:]version[-release]
Definition: Edition.h:60
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:248
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:2252
#define ERR
Definition: Logger.h:66
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:1593
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:484
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:460
void systemKill()
Forcably kill the system process.
Definition: RpmDb.cc:1814
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:454
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:519
const std::string & asString() const
Return current Pathname as String.
Definition: PathInfo.h:248
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 &#39;unlink&#39;.
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:1717
#define WARNINGMAILPATH
Definition: RpmDb.cc:55
int rename(const Pathname &oldpath, const Pathname &newpath)
Like &#39;rename&#39;.
Definition: PathInfo.cc:695
int systemStatus()
Return the exit status of the general rpm process, closing the connection if not already done...
Definition: RpmDb.cc:1791
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 &#39;rm -r DIR&#39;.
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:444
bool startsWith(const C_Str &str_r, const C_Str &prefix_r)
alias for hasPrefix
Definition: String.h:1086
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: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
bool isFile() const
Definition: PathInfo.h:289
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:305
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:1948
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:1821
int copy(const Pathname &file, const Pathname &dest)
Like &#39;cp file dest&#39;.
Definition: PathInfo.cc:773
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:2137
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:2379
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:199
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:2106
static bool globalInit()
Initialize lib librpm (read configfiles etc.).
Definition: librpmDb.cc:128
std::string * _cap
Definition: RpmDb.cc:1480
Reference counted access to a Tp object calling a custom Dispose function when the last AutoDispose h...
Definition: AutoDispose.h:92
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
Wrapper class for ::stat/::lstat.
Definition: PathInfo.h:220
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:1605
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
friend std::ostream & operator<<(std::ostream &str, const DbStateInfoBits &obj)
Definition: RpmDb.cc:205
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc:1
std::string gpgPubkeyRelease() const
Definition: PublicKey.cc:487
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:1671
std::string name() const
Definition: PublicKey.cc:463
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