libzypp  16.15.6
RpmDb.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
12 #include "librpm.h"
13 extern "C"
14 {
15 #include <rpm/rpmcli.h>
16 #include <rpm/rpmlog.h>
17 }
18 #include <cstdlib>
19 #include <cstdio>
20 #include <ctime>
21 
22 #include <iostream>
23 #include <fstream>
24 #include <sstream>
25 #include <list>
26 #include <map>
27 #include <set>
28 #include <string>
29 #include <vector>
30 #include <algorithm>
31 
32 #include "zypp/base/Logger.h"
33 #include "zypp/base/String.h"
34 #include "zypp/base/Gettext.h"
35 
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  // bsc#1008325: Keys using subkeys for signing don't get a higher release
1054  // if new subkeys are added, because the primary key remains unchanged.
1055  // For now always re-import keys with subkeys. Here we don't want to export the
1056  // keys in the rpm database to check whether the subkeys are the same. The calling
1057  // code should take care, we don't re-import the same kesy over and over again.
1058  if ( keyEd == *it && !pubkey_r.hasSubkeys() ) // quick test (Edition is IdStringType!)
1059  {
1060  MIL << "Key " << pubkey_r << " is already in the rpm trusted keyring. (skip import)" << endl;
1061  return;
1062  }
1063 
1064  if ( keyEd.version() != (*it).version() )
1065  continue; // different key ID (version)
1066 
1067  if ( keyEd.release() < (*it).release() )
1068  {
1069  MIL << "Key " << pubkey_r << " is older than one in the rpm trusted keyring. (skip import)" << endl;
1070  return;
1071  }
1072  else
1073  {
1074  hasOldkeys = true;
1075  }
1076  }
1077  MIL << "Key " << pubkey_r << " will be imported into the rpm trusted keyring." << (hasOldkeys?"(update)":"(new)") << endl;
1078 
1079  if ( hasOldkeys )
1080  {
1081  // We must explicitly delete old key IDs first (all releases,
1082  // that's why we don't call removePubkey here).
1083  std::string keyName( "gpg-pubkey-" + keyEd.version() );
1084  RpmArgVec opts;
1085  opts.push_back ( "-e" );
1086  opts.push_back ( "--allmatches" );
1087  opts.push_back ( "--" );
1088  opts.push_back ( keyName.c_str() );
1089  // don't call modifyDatabase because it would remove the old
1090  // rpm3 database, if the current database is a temporary one.
1092 
1093  std::string line;
1094  while ( systemReadLine( line ) )
1095  {
1096  ( str::startsWith( line, "error:" ) ? WAR : DBG ) << line << endl;
1097  }
1098 
1099  if ( systemStatus() != 0 )
1100  {
1101  ERR << "Failed to remove key " << pubkey_r << " from RPM trusted keyring (ignored)" << endl;
1102  }
1103  else
1104  {
1105  MIL << "Key " << pubkey_r << " has been removed from RPM trusted keyring" << endl;
1106  }
1107  }
1108 
1109  // import the new key
1110  RpmArgVec opts;
1111  opts.push_back ( "--import" );
1112  opts.push_back ( "--" );
1113  std::string pubkeypath( pubkey_r.path().asString() );
1114  opts.push_back ( pubkeypath.c_str() );
1115 
1116  // don't call modifyDatabase because it would remove the old
1117  // rpm3 database, if the current database is a temporary one.
1119 
1120  std::string line;
1121  while ( systemReadLine( line ) )
1122  {
1123  ( str::startsWith( line, "error:" ) ? WAR : DBG ) << line << endl;
1124  }
1125 
1126  if ( systemStatus() != 0 )
1127  {
1128  //TranslatorExplanation first %s is file name, second is error message
1129  ZYPP_THROW(RpmSubprocessException( str::Format(_("Failed to import public key from file %s: %s"))
1130  % pubkey_r.asString()
1131  % error_message ));
1132  }
1133  else
1134  {
1135  MIL << "Key " << pubkey_r << " imported in rpm trusted keyring." << endl;
1136  }
1137 }
1138 
1140 //
1141 //
1142 // METHOD NAME : RpmDb::removePubkey
1143 // METHOD TYPE : PMError
1144 //
1145 void RpmDb::removePubkey( const PublicKey & pubkey_r )
1146 {
1148 
1149  // check if the key is in the rpm database and just
1150  // return if it does not.
1151  std::set<Edition> rpm_keys = pubkeyEditions();
1152  std::set<Edition>::const_iterator found_edition = rpm_keys.end();
1153  std::string pubkeyVersion( pubkey_r.gpgPubkeyVersion() );
1154 
1155  for_( it, rpm_keys.begin(), rpm_keys.end() )
1156  {
1157  if ( (*it).version() == pubkeyVersion )
1158  {
1159  found_edition = it;
1160  break;
1161  }
1162  }
1163 
1164  // the key does not exist, cannot be removed
1165  if (found_edition == rpm_keys.end())
1166  {
1167  WAR << "Key " << pubkey_r.id() << " is not in rpm db" << endl;
1168  return;
1169  }
1170 
1171  std::string rpm_name("gpg-pubkey-" + found_edition->asString());
1172 
1173  RpmArgVec opts;
1174  opts.push_back ( "-e" );
1175  opts.push_back ( "--" );
1176  opts.push_back ( rpm_name.c_str() );
1177 
1178  // don't call modifyDatabase because it would remove the old
1179  // rpm3 database, if the current database is a temporary one.
1181 
1182  std::string line;
1183  while ( systemReadLine( line ) )
1184  {
1185  if ( line.substr( 0, 6 ) == "error:" )
1186  {
1187  WAR << line << endl;
1188  }
1189  else
1190  {
1191  DBG << line << endl;
1192  }
1193  }
1194 
1195  int rpm_status = systemStatus();
1196 
1197  if ( rpm_status != 0 )
1198  {
1199  //TranslatorExplanation first %s is key name, second is error message
1200  ZYPP_THROW(RpmSubprocessException( str::Format(_("Failed to remove public key %s: %s"))
1201  % pubkey_r.asString()
1202  % error_message ));
1203  }
1204  else
1205  {
1206  MIL << "Key " << pubkey_r << " has been removed from RPM trusted keyring" << endl;
1207  }
1208 }
1209 
1211 //
1212 //
1213 // METHOD NAME : RpmDb::pubkeys
1214 // METHOD TYPE : std::set<Edition>
1215 //
1216 std::list<PublicKey> RpmDb::pubkeys() const
1217 {
1218  std::list<PublicKey> ret;
1219 
1221  for ( it.findByName( "gpg-pubkey" ); *it; ++it )
1222  {
1223  Edition edition = it->tag_edition();
1224  if (edition != Edition::noedition)
1225  {
1226  // we export the rpm key into a file
1227  RpmHeader::constPtr result;
1228  getData( "gpg-pubkey", edition, result );
1229  TmpFile file(getZYpp()->tmpPath());
1230  std::ofstream os;
1231  try
1232  {
1233  os.open(file.path().asString().c_str());
1234  // dump rpm key into the tmp file
1235  os << result->tag_description();
1236  //MIL << "-----------------------------------------------" << endl;
1237  //MIL << result->tag_description() <<endl;
1238  //MIL << "-----------------------------------------------" << endl;
1239  os.close();
1240  // read the public key from the dumped file
1241  PublicKey key(file);
1242  ret.push_back(key);
1243  }
1244  catch ( std::exception & e )
1245  {
1246  ERR << "Could not dump key " << edition.asString() << " in tmp file " << file.path() << endl;
1247  // just ignore the key
1248  }
1249  }
1250  }
1251  return ret;
1252 }
1253 
1254 std::set<Edition> RpmDb::pubkeyEditions() const
1255  {
1256  std::set<Edition> ret;
1257 
1259  for ( it.findByName( "gpg-pubkey" ); *it; ++it )
1260  {
1261  Edition edition = it->tag_edition();
1262  if (edition != Edition::noedition)
1263  ret.insert( edition );
1264  }
1265  return ret;
1266  }
1267 
1268 
1270 //
1271 //
1272 // METHOD NAME : RpmDb::fileList
1273 // METHOD TYPE : bool
1274 //
1275 // DESCRIPTION :
1276 //
1277 std::list<FileInfo>
1278 RpmDb::fileList( const std::string & name_r, const Edition & edition_r ) const
1279 {
1280  std::list<FileInfo> result;
1281 
1283  bool found;
1284  if (edition_r == Edition::noedition)
1285  {
1286  found = it.findPackage( name_r );
1287  }
1288  else
1289  {
1290  found = it.findPackage( name_r, edition_r );
1291  }
1292  if (!found)
1293  return result;
1294 
1295  return result;
1296 }
1297 
1298 
1300 //
1301 //
1302 // METHOD NAME : RpmDb::hasFile
1303 // METHOD TYPE : bool
1304 //
1305 // DESCRIPTION :
1306 //
1307 bool RpmDb::hasFile( const std::string & file_r, const std::string & name_r ) const
1308 {
1310  bool res;
1311  do
1312  {
1313  res = it.findByFile( file_r );
1314  if (!res) break;
1315  if (!name_r.empty())
1316  {
1317  res = (it->tag_name() == name_r);
1318  }
1319  ++it;
1320  }
1321  while (res && *it);
1322  return res;
1323 }
1324 
1326 //
1327 //
1328 // METHOD NAME : RpmDb::whoOwnsFile
1329 // METHOD TYPE : std::string
1330 //
1331 // DESCRIPTION :
1332 //
1333 std::string RpmDb::whoOwnsFile( const std::string & file_r) const
1334 {
1336  if (it.findByFile( file_r ))
1337  {
1338  return it->tag_name();
1339  }
1340  return "";
1341 }
1342 
1344 //
1345 //
1346 // METHOD NAME : RpmDb::hasProvides
1347 // METHOD TYPE : bool
1348 //
1349 // DESCRIPTION :
1350 //
1351 bool RpmDb::hasProvides( const std::string & tag_r ) const
1352 {
1354  return it.findByProvides( tag_r );
1355 }
1356 
1358 //
1359 //
1360 // METHOD NAME : RpmDb::hasRequiredBy
1361 // METHOD TYPE : bool
1362 //
1363 // DESCRIPTION :
1364 //
1365 bool RpmDb::hasRequiredBy( const std::string & tag_r ) const
1366 {
1368  return it.findByRequiredBy( tag_r );
1369 }
1370 
1372 //
1373 //
1374 // METHOD NAME : RpmDb::hasConflicts
1375 // METHOD TYPE : bool
1376 //
1377 // DESCRIPTION :
1378 //
1379 bool RpmDb::hasConflicts( const std::string & tag_r ) const
1380 {
1382  return it.findByConflicts( tag_r );
1383 }
1384 
1386 //
1387 //
1388 // METHOD NAME : RpmDb::hasPackage
1389 // METHOD TYPE : bool
1390 //
1391 // DESCRIPTION :
1392 //
1393 bool RpmDb::hasPackage( const std::string & name_r ) const
1394 {
1396  return it.findPackage( name_r );
1397 }
1398 
1400 //
1401 //
1402 // METHOD NAME : RpmDb::hasPackage
1403 // METHOD TYPE : bool
1404 //
1405 // DESCRIPTION :
1406 //
1407 bool RpmDb::hasPackage( const std::string & name_r, const Edition & ed_r ) const
1408 {
1410  return it.findPackage( name_r, ed_r );
1411 }
1412 
1414 //
1415 //
1416 // METHOD NAME : RpmDb::getData
1417 // METHOD TYPE : PMError
1418 //
1419 // DESCRIPTION :
1420 //
1421 void RpmDb::getData( const std::string & name_r,
1422  RpmHeader::constPtr & result_r ) const
1423 {
1425  it.findPackage( name_r );
1426  result_r = *it;
1427  if (it.dbError())
1428  ZYPP_THROW(*(it.dbError()));
1429 }
1430 
1432 //
1433 //
1434 // METHOD NAME : RpmDb::getData
1435 // METHOD TYPE : void
1436 //
1437 // DESCRIPTION :
1438 //
1439 void RpmDb::getData( const std::string & name_r, const Edition & ed_r,
1440  RpmHeader::constPtr & result_r ) const
1441 {
1443  it.findPackage( name_r, ed_r );
1444  result_r = *it;
1445  if (it.dbError())
1446  ZYPP_THROW(*(it.dbError()));
1447 }
1448 
1450 namespace
1451 {
1452  struct RpmlogCapture : public std::string
1453  {
1454  RpmlogCapture()
1455  { rpmlog()._cap = this; }
1456 
1457  ~RpmlogCapture()
1458  { rpmlog()._cap = nullptr; }
1459 
1460  private:
1461  struct Rpmlog
1462  {
1463  Rpmlog()
1464  : _cap( nullptr )
1465  {
1466  rpmlogSetCallback( rpmLogCB, this );
1467  rpmSetVerbosity( RPMLOG_INFO );
1468  _f = ::fopen( "/dev/null","w");
1469  rpmlogSetFile( _f );
1470  }
1471 
1472  ~Rpmlog()
1473  { if ( _f ) ::fclose( _f ); }
1474 
1475  static int rpmLogCB( rpmlogRec rec_r, rpmlogCallbackData data_r )
1476  { return reinterpret_cast<Rpmlog*>(data_r)->rpmLog( rec_r ); }
1477 
1478  int rpmLog( rpmlogRec rec_r )
1479  {
1480  if ( _cap ) (*_cap) = rpmlogRecMessage( rec_r );
1481  return RPMLOG_DEFAULT;
1482  }
1483 
1484  FILE * _f;
1485  std::string * _cap;
1486  };
1487 
1488  static Rpmlog & rpmlog()
1489  { static Rpmlog _rpmlog; return _rpmlog; }
1490  };
1491 
1492  RpmDb::CheckPackageResult doCheckPackageSig( const Pathname & path_r, // rpm file to check
1493  const Pathname & root_r, // target root
1494  bool requireGPGSig_r, // whether no gpg signature is to be reported
1495  RpmDb::CheckPackageDetail & detail_r ) // detailed result
1496  {
1497  PathInfo file( path_r );
1498  if ( ! file.isFile() )
1499  {
1500  ERR << "Not a file: " << file << endl;
1501  return RpmDb::CHK_ERROR;
1502  }
1503 
1504  FD_t fd = ::Fopen( file.asString().c_str(), "r.ufdio" );
1505  if ( fd == 0 || ::Ferror(fd) )
1506  {
1507  ERR << "Can't open file for reading: " << file << " (" << ::Fstrerror(fd) << ")" << endl;
1508  if ( fd )
1509  ::Fclose( fd );
1510  return RpmDb::CHK_ERROR;
1511  }
1512  rpmts ts = ::rpmtsCreate();
1513  ::rpmtsSetRootDir( ts, root_r.c_str() );
1514  ::rpmtsSetVSFlags( ts, RPMVSF_DEFAULT );
1515 
1516  rpmQVKArguments_s qva;
1517  memset( &qva, 0, sizeof(rpmQVKArguments_s) );
1518  qva.qva_flags = (VERIFY_DIGEST|VERIFY_SIGNATURE);
1519 
1520  RpmlogCapture vresult;
1521  int res = ::rpmVerifySignatures( &qva, ts, fd, path_r.basename().c_str() );
1522 
1523  ts = rpmtsFree(ts);
1524  ::Fclose( fd );
1525 
1526  // results per line...
1527  // Header V3 RSA/SHA256 Signature, key ID 3dbdc284: OK
1528  // Header SHA1 digest: OK (a60386347863affefef484ff1f26c889373eb094)
1529  // V3 RSA/SHA256 Signature, key ID 3dbdc284: OK
1530  // MD5 digest: OK (fd5259fe677a406951dcb2e9d08c4dcc)
1531  //
1532  // TODO: try to get SIG info from the header rather than parsing the output
1533  std::vector<std::string> lines;
1534  str::split( vresult, std::back_inserter(lines), "\n" );
1535  unsigned count[7] = { 0, 0, 0, 0, 0, 0, 0 };
1536 
1537  for ( unsigned i = 1; i < lines.size(); ++i )
1538  {
1539  std::string & line( lines[i] );
1541  if ( line.find( ": OK" ) != std::string::npos )
1542  {
1543  lineres = RpmDb::CHK_OK;
1544  if ( line.find( "Signature, key ID" ) == std::string::npos )
1545  ++count[RpmDb::CHK_NOSIG]; // Valid but no gpg signature -> CHK_NOSIG
1546  }
1547  else if ( line.find( ": NOKEY" ) != std::string::npos )
1548  { lineres = RpmDb::CHK_NOKEY; }
1549  else if ( line.find( ": BAD" ) != std::string::npos )
1550  { lineres = RpmDb::CHK_FAIL; }
1551  else if ( line.find( ": UNKNOWN" ) != std::string::npos )
1552  { lineres = RpmDb::CHK_NOTFOUND; }
1553  else if ( line.find( ": NOTRUSTED" ) != std::string::npos )
1554  { lineres = RpmDb::CHK_NOTTRUSTED; }
1555 
1556  ++count[lineres];
1557  detail_r.push_back( RpmDb::CheckPackageDetail::value_type( lineres, std::move(line) ) );
1558  }
1559 
1561 
1562  if ( count[RpmDb::CHK_FAIL] )
1563  ret = RpmDb::CHK_FAIL;
1564 
1565  else if ( count[RpmDb::CHK_NOTFOUND] )
1566  ret = RpmDb::CHK_NOTFOUND;
1567 
1568  else if ( count[RpmDb::CHK_NOKEY] )
1569  ret = RpmDb::CHK_NOKEY;
1570 
1571  else if ( count[RpmDb::CHK_NOTTRUSTED] )
1572  ret = RpmDb::CHK_NOTTRUSTED;
1573 
1574  else if ( ret == RpmDb::CHK_OK )
1575  {
1576  if ( count[RpmDb::CHK_OK] == count[RpmDb::CHK_NOSIG] )
1577  {
1578  detail_r.push_back( RpmDb::CheckPackageDetail::value_type( RpmDb::CHK_NOSIG, std::string(" ")+_("Package is not signed!") ) );
1579  if ( requireGPGSig_r )
1580  ret = RpmDb::CHK_NOSIG;
1581  }
1582  }
1583 
1584  if ( ret != RpmDb::CHK_OK )
1585  {
1586  WAR << path_r << " (" << requireGPGSig_r << " -> " << ret << ")" << endl;
1587  WAR << vresult;
1588  }
1589  return ret;
1590  }
1591 
1592 } // namespace
1594 //
1595 // METHOD NAME : RpmDb::checkPackage
1596 // METHOD TYPE : RpmDb::CheckPackageResult
1597 //
1599 { return doCheckPackageSig( path_r, root(), false/*requireGPGSig_r*/, detail_r ); }
1600 
1602 { CheckPackageDetail dummy; return checkPackage( path_r, dummy ); }
1603 
1605 { return doCheckPackageSig( path_r, root(), true/*requireGPGSig_r*/, detail_r ); }
1606 
1607 
1608 // determine changed files of installed package
1609 bool
1610 RpmDb::queryChangedFiles(FileList & fileList, const std::string& packageName)
1611 {
1612  bool ok = true;
1613 
1614  fileList.clear();
1615 
1616  if ( ! initialized() ) return false;
1617 
1618  RpmArgVec opts;
1619 
1620  opts.push_back ("-V");
1621  opts.push_back ("--nodeps");
1622  opts.push_back ("--noscripts");
1623  opts.push_back ("--nomd5");
1624  opts.push_back ("--");
1625  opts.push_back (packageName.c_str());
1626 
1628 
1629  if ( process == NULL )
1630  return false;
1631 
1632  /* from rpm manpage
1633  5 MD5 sum
1634  S File size
1635  L Symlink
1636  T Mtime
1637  D Device
1638  U User
1639  G Group
1640  M Mode (includes permissions and file type)
1641  */
1642 
1643  std::string line;
1644  while (systemReadLine(line))
1645  {
1646  if (line.length() > 12 &&
1647  (line[0] == 'S' || line[0] == 's' ||
1648  (line[0] == '.' && line[7] == 'T')))
1649  {
1650  // file has been changed
1651  std::string filename;
1652 
1653  filename.assign(line, 11, line.length() - 11);
1654  fileList.insert(filename);
1655  }
1656  }
1657 
1658  systemStatus();
1659  // exit code ignored, rpm returns 1 no matter if package is installed or
1660  // not
1661 
1662  return ok;
1663 }
1664 
1665 
1666 
1667 /****************************************************************/
1668 /* private member-functions */
1669 /****************************************************************/
1670 
1671 /*--------------------------------------------------------------*/
1672 /* Run rpm with the specified arguments, handling stderr */
1673 /* as specified by disp */
1674 /*--------------------------------------------------------------*/
1675 void
1678 {
1679  if ( process )
1680  {
1681  delete process;
1682  process = NULL;
1683  }
1684  exit_code = -1;
1685 
1686  if ( ! initialized() )
1687  {
1689  }
1690 
1691  RpmArgVec args;
1692 
1693  // always set root and dbpath
1694 #if defined(WORKAROUNDRPMPWDBUG)
1695  args.push_back("#/"); // chdir to / to workaround bnc#819354
1696 #endif
1697  args.push_back("rpm");
1698  args.push_back("--root");
1699  args.push_back(_root.asString().c_str());
1700  args.push_back("--dbpath");
1701  args.push_back(_dbPath.asString().c_str());
1702 
1703  const char* argv[args.size() + opts.size() + 1];
1704 
1705  const char** p = argv;
1706  p = copy (args.begin (), args.end (), p);
1707  p = copy (opts.begin (), opts.end (), p);
1708  *p = 0;
1709 
1710  // Invalidate all outstanding database handles in case
1711  // the database gets modified.
1712  librpmDb::dbRelease( true );
1713 
1714  // Launch the program with default locale
1715  process = new ExternalProgram(argv, disp, false, -1, true);
1716  return;
1717 }
1718 
1719 /*--------------------------------------------------------------*/
1720 /* Read a line from the rpm process */
1721 /*--------------------------------------------------------------*/
1722 bool RpmDb::systemReadLine( std::string & line )
1723 {
1724  line.erase();
1725 
1726  if ( process == NULL )
1727  return false;
1728 
1729  if ( process->inputFile() )
1730  {
1731  process->setBlocking( false );
1732  FILE * inputfile = process->inputFile();
1733  int inputfileFd = ::fileno( inputfile );
1734  do
1735  {
1736  /* Watch inputFile to see when it has input. */
1737  fd_set rfds;
1738  FD_ZERO( &rfds );
1739  FD_SET( inputfileFd, &rfds );
1740 
1741  /* Wait up to 5 seconds. */
1742  struct timeval tv;
1743  tv.tv_sec = 5;
1744  tv.tv_usec = 0;
1745 
1746  int retval = select( inputfileFd+1, &rfds, NULL, NULL, &tv );
1747 
1748  if ( retval == -1 )
1749  {
1750  ERR << "select error: " << strerror(errno) << endl;
1751  if ( errno != EINTR )
1752  return false;
1753  }
1754  else if ( retval )
1755  {
1756  // Data is available now.
1757  static size_t linebuffer_size = 0; // static because getline allocs
1758  static char * linebuffer = 0; // and reallocs if buffer is too small
1759  ssize_t nread = getline( &linebuffer, &linebuffer_size, inputfile );
1760  if ( nread == -1 )
1761  {
1762  if ( ::feof( inputfile ) )
1763  return line.size(); // in case of pending output
1764  }
1765  else
1766  {
1767  if ( nread > 0 )
1768  {
1769  if ( linebuffer[nread-1] == '\n' )
1770  --nread;
1771  line += std::string( linebuffer, nread );
1772  }
1773 
1774  if ( ! ::ferror( inputfile ) || ::feof( inputfile ) )
1775  return true; // complete line
1776  }
1777  clearerr( inputfile );
1778  }
1779  else
1780  {
1781  // No data within time.
1782  if ( ! process->running() )
1783  return false;
1784  }
1785  } while ( true );
1786  }
1787 
1788  return false;
1789 }
1790 
1791 /*--------------------------------------------------------------*/
1792 /* Return the exit status of the rpm process, closing the */
1793 /* connection if not already done */
1794 /*--------------------------------------------------------------*/
1795 int
1797 {
1798  if ( process == NULL )
1799  return -1;
1800 
1801  exit_code = process->close();
1802  if (exit_code == 0)
1803  error_message = "";
1804  else
1806  process->kill();
1807  delete process;
1808  process = 0;
1809 
1810  // DBG << "exit code " << exit_code << endl;
1811 
1812  return exit_code;
1813 }
1814 
1815 /*--------------------------------------------------------------*/
1816 /* Forcably kill the rpm process */
1817 /*--------------------------------------------------------------*/
1818 void
1820 {
1821  if (process) process->kill();
1822 }
1823 
1824 
1825 // generate diff mails for config files
1826 void RpmDb::processConfigFiles(const std::string& line, const std::string& name, const char* typemsg, const char* difffailmsg, const char* diffgenmsg)
1827 {
1828  std::string msg = line.substr(9);
1829  std::string::size_type pos1 = std::string::npos;
1830  std::string::size_type pos2 = std::string::npos;
1831  std::string file1s, file2s;
1832  Pathname file1;
1833  Pathname file2;
1834 
1835  pos1 = msg.find (typemsg);
1836  for (;;)
1837  {
1838  if ( pos1 == std::string::npos )
1839  break;
1840 
1841  pos2 = pos1 + strlen (typemsg);
1842 
1843  if (pos2 >= msg.length() )
1844  break;
1845 
1846  file1 = msg.substr (0, pos1);
1847  file2 = msg.substr (pos2);
1848 
1849  file1s = file1.asString();
1850  file2s = file2.asString();
1851 
1852  if (!_root.empty() && _root != "/")
1853  {
1854  file1 = _root + file1;
1855  file2 = _root + file2;
1856  }
1857 
1858  std::string out;
1859  int ret = diffFiles (file1.asString(), file2.asString(), out, 25);
1860  if (ret)
1861  {
1862  Pathname file = _root + WARNINGMAILPATH;
1863  if (filesystem::assert_dir(file) != 0)
1864  {
1865  ERR << "Could not create " << file.asString() << endl;
1866  break;
1867  }
1868  file += Date(Date::now()).form("config_diff_%Y_%m_%d.log");
1869  std::ofstream notify(file.asString().c_str(), std::ios::out|std::ios::app);
1870  if (!notify)
1871  {
1872  ERR << "Could not open " << file << endl;
1873  break;
1874  }
1875 
1876  // Translator: %s = name of an rpm package. A list of diffs follows
1877  // this message.
1878  notify << str::form(_("Changed configuration files for %s:"), name.c_str()) << endl;
1879  if (ret>1)
1880  {
1881  ERR << "diff failed" << endl;
1882  notify << str::form(difffailmsg,
1883  file1s.c_str(), file2s.c_str()) << endl;
1884  }
1885  else
1886  {
1887  notify << str::form(diffgenmsg,
1888  file1s.c_str(), file2s.c_str()) << endl;
1889 
1890  // remove root for the viewer's pleasure (#38240)
1891  if (!_root.empty() && _root != "/")
1892  {
1893  if (out.substr(0,4) == "--- ")
1894  {
1895  out.replace(4, file1.asString().length(), file1s);
1896  }
1897  std::string::size_type pos = out.find("\n+++ ");
1898  if (pos != std::string::npos)
1899  {
1900  out.replace(pos+5, file2.asString().length(), file2s);
1901  }
1902  }
1903  notify << out << endl;
1904  }
1905  notify.close();
1906  notify.open("/var/lib/update-messages/yast2-packagemanager.rpmdb.configfiles");
1907  notify.close();
1908  }
1909  else
1910  {
1911  WAR << "rpm created " << file2 << " but it is not different from " << file2 << endl;
1912  }
1913  break;
1914  }
1915 }
1916 
1918 //
1919 //
1920 // METHOD NAME : RpmDb::installPackage
1921 // METHOD TYPE : PMError
1922 //
1923 void RpmDb::installPackage( const Pathname & filename, RpmInstFlags flags )
1924 {
1926 
1927  report->start(filename);
1928 
1929  do
1930  try
1931  {
1932  doInstallPackage(filename, flags, report);
1933  report->finish();
1934  break;
1935  }
1936  catch (RpmException & excpt_r)
1937  {
1938  RpmInstallReport::Action user = report->problem( excpt_r );
1939 
1940  if ( user == RpmInstallReport::ABORT )
1941  {
1942  report->finish( excpt_r );
1943  ZYPP_RETHROW(excpt_r);
1944  }
1945  else if ( user == RpmInstallReport::IGNORE )
1946  {
1947  break;
1948  }
1949  }
1950  while (true);
1951 }
1952 
1953 void RpmDb::doInstallPackage( const Pathname & filename, RpmInstFlags flags, callback::SendReport<RpmInstallReport> & report )
1954 {
1956  HistoryLog historylog;
1957 
1958  MIL << "RpmDb::installPackage(" << filename << "," << flags << ")" << endl;
1959 
1960 
1961  // backup
1962  if ( _packagebackups )
1963  {
1964  // FIXME report->progress( pd.init( -2, 100 ) ); // allow 1% for backup creation.
1965  if ( ! backupPackage( filename ) )
1966  {
1967  ERR << "backup of " << filename.asString() << " failed" << endl;
1968  }
1969  // FIXME status handling
1970  report->progress( 0 ); // allow 1% for backup creation.
1971  }
1972 
1973  // run rpm
1974  RpmArgVec opts;
1975  if (flags & RPMINST_NOUPGRADE)
1976  opts.push_back("-i");
1977  else
1978  opts.push_back("-U");
1979 
1980  opts.push_back("--percent");
1981  opts.push_back("--noglob");
1982 
1983  // ZConfig defines cross-arch installation
1984  if ( ! ZConfig::instance().systemArchitecture().compatibleWith( ZConfig::instance().defaultSystemArchitecture() ) )
1985  opts.push_back("--ignorearch");
1986 
1987  if (flags & RPMINST_NODIGEST)
1988  opts.push_back("--nodigest");
1989  if (flags & RPMINST_NOSIGNATURE)
1990  opts.push_back("--nosignature");
1991  if (flags & RPMINST_EXCLUDEDOCS)
1992  opts.push_back ("--excludedocs");
1993  if (flags & RPMINST_NOSCRIPTS)
1994  opts.push_back ("--noscripts");
1995  if (flags & RPMINST_FORCE)
1996  opts.push_back ("--force");
1997  if (flags & RPMINST_NODEPS)
1998  opts.push_back ("--nodeps");
1999  if (flags & RPMINST_IGNORESIZE)
2000  opts.push_back ("--ignoresize");
2001  if (flags & RPMINST_JUSTDB)
2002  opts.push_back ("--justdb");
2003  if (flags & RPMINST_TEST)
2004  opts.push_back ("--test");
2005  if (flags & RPMINST_NOPOSTTRANS)
2006  opts.push_back ("--noposttrans");
2007 
2008  opts.push_back("--");
2009 
2010  // rpm requires additional quoting of special chars:
2011  std::string quotedFilename( rpmQuoteFilename( workaroundRpmPwdBug( filename ) ) );
2012  opts.push_back ( quotedFilename.c_str() );
2013 
2014  modifyDatabase(); // BEFORE run_rpm
2016 
2017  std::string line;
2018  std::string rpmmsg;
2019  std::vector<std::string> configwarnings;
2020 
2021  unsigned linecnt = 0;
2022  while (systemReadLine(line))
2023  {
2024  if ( linecnt < MAXRPMMESSAGELINES )
2025  ++linecnt;
2026  else
2027  continue;
2028 
2029  if (line.substr(0,2)=="%%")
2030  {
2031  int percent;
2032  sscanf (line.c_str () + 2, "%d", &percent);
2033  report->progress( percent );
2034  }
2035  else
2036  rpmmsg += line+'\n';
2037 
2038  if ( line.substr(0,8) == "warning:" )
2039  {
2040  configwarnings.push_back(line);
2041  }
2042  }
2043  if ( linecnt > MAXRPMMESSAGELINES )
2044  rpmmsg += "[truncated]\n";
2045 
2046  int rpm_status = systemStatus();
2047 
2048  // evaluate result
2049  for (std::vector<std::string>::iterator it = configwarnings.begin();
2050  it != configwarnings.end(); ++it)
2051  {
2052  processConfigFiles(*it, Pathname::basename(filename), " saved as ",
2053  // %s = filenames
2054  _("rpm saved %s as %s, but it was impossible to determine the difference"),
2055  // %s = filenames
2056  _("rpm saved %s as %s.\nHere are the first 25 lines of difference:\n"));
2057  processConfigFiles(*it, Pathname::basename(filename), " created as ",
2058  // %s = filenames
2059  _("rpm created %s as %s, but it was impossible to determine the difference"),
2060  // %s = filenames
2061  _("rpm created %s as %s.\nHere are the first 25 lines of difference:\n"));
2062  }
2063 
2064  if ( rpm_status != 0 )
2065  {
2066  historylog.comment(
2067  str::form("%s install failed", Pathname::basename(filename).c_str()),
2068  true /*timestamp*/);
2069  std::ostringstream sstr;
2070  sstr << "rpm output:" << endl << rpmmsg << endl;
2071  historylog.comment(sstr.str());
2072  // TranslatorExplanation the colon is followed by an error message
2073  ZYPP_THROW(RpmSubprocessException(_("RPM failed: ") + (rpmmsg.empty() ? error_message : rpmmsg) ));
2074  }
2075  else if ( ! rpmmsg.empty() )
2076  {
2077  historylog.comment(
2078  str::form("%s installed ok", Pathname::basename(filename).c_str()),
2079  true /*timestamp*/);
2080  std::ostringstream sstr;
2081  sstr << "Additional rpm output:" << endl << rpmmsg << endl;
2082  historylog.comment(sstr.str());
2083 
2084  // report additional rpm output in finish
2085  // TranslatorExplanation Text is followed by a ':' and the actual output.
2086  report->finishInfo(str::form( "%s:\n%s\n", _("Additional rpm output"), rpmmsg.c_str() ));
2087  }
2088 }
2089 
2091 //
2092 //
2093 // METHOD NAME : RpmDb::removePackage
2094 // METHOD TYPE : PMError
2095 //
2096 void RpmDb::removePackage( Package::constPtr package, RpmInstFlags flags )
2097 {
2098  // 'rpm -e' does not like epochs
2099  return removePackage( package->name()
2100  + "-" + package->edition().version()
2101  + "-" + package->edition().release()
2102  + "." + package->arch().asString(), flags );
2103 }
2104 
2106 //
2107 //
2108 // METHOD NAME : RpmDb::removePackage
2109 // METHOD TYPE : PMError
2110 //
2111 void RpmDb::removePackage( const std::string & name_r, RpmInstFlags flags )
2112 {
2114 
2115  report->start( name_r );
2116 
2117  do
2118  try
2119  {
2120  doRemovePackage(name_r, flags, report);
2121  report->finish();
2122  break;
2123  }
2124  catch (RpmException & excpt_r)
2125  {
2126  RpmRemoveReport::Action user = report->problem( excpt_r );
2127 
2128  if ( user == RpmRemoveReport::ABORT )
2129  {
2130  report->finish( excpt_r );
2131  ZYPP_RETHROW(excpt_r);
2132  }
2133  else if ( user == RpmRemoveReport::IGNORE )
2134  {
2135  break;
2136  }
2137  }
2138  while (true);
2139 }
2140 
2141 
2142 void RpmDb::doRemovePackage( const std::string & name_r, RpmInstFlags flags, callback::SendReport<RpmRemoveReport> & report )
2143 {
2145  HistoryLog historylog;
2146 
2147  MIL << "RpmDb::doRemovePackage(" << name_r << "," << flags << ")" << endl;
2148 
2149  // backup
2150  if ( _packagebackups )
2151  {
2152  // FIXME solve this status report somehow
2153  // report->progress( pd.init( -2, 100 ) ); // allow 1% for backup creation.
2154  if ( ! backupPackage( name_r ) )
2155  {
2156  ERR << "backup of " << name_r << " failed" << endl;
2157  }
2158  report->progress( 0 );
2159  }
2160  else
2161  {
2162  report->progress( 100 );
2163  }
2164 
2165  // run rpm
2166  RpmArgVec opts;
2167  opts.push_back("-e");
2168  opts.push_back("--allmatches");
2169 
2170  if (flags & RPMINST_NOSCRIPTS)
2171  opts.push_back("--noscripts");
2172  if (flags & RPMINST_NODEPS)
2173  opts.push_back("--nodeps");
2174  if (flags & RPMINST_JUSTDB)
2175  opts.push_back("--justdb");
2176  if (flags & RPMINST_TEST)
2177  opts.push_back ("--test");
2178  if (flags & RPMINST_FORCE)
2179  {
2180  WAR << "IGNORE OPTION: 'rpm -e' does not support '--force'" << endl;
2181  }
2182 
2183  opts.push_back("--");
2184  opts.push_back(name_r.c_str());
2185 
2186  modifyDatabase(); // BEFORE run_rpm
2188 
2189  std::string line;
2190  std::string rpmmsg;
2191 
2192  // got no progress from command, so we fake it:
2193  // 5 - command started
2194  // 50 - command completed
2195  // 100 if no error
2196  report->progress( 5 );
2197  unsigned linecnt = 0;
2198  while (systemReadLine(line))
2199  {
2200  if ( linecnt < MAXRPMMESSAGELINES )
2201  ++linecnt;
2202  else
2203  continue;
2204  rpmmsg += line+'\n';
2205  }
2206  if ( linecnt > MAXRPMMESSAGELINES )
2207  rpmmsg += "[truncated]\n";
2208  report->progress( 50 );
2209  int rpm_status = systemStatus();
2210 
2211  if ( rpm_status != 0 )
2212  {
2213  historylog.comment(
2214  str::form("%s remove failed", name_r.c_str()), true /*timestamp*/);
2215  std::ostringstream sstr;
2216  sstr << "rpm output:" << endl << rpmmsg << endl;
2217  historylog.comment(sstr.str());
2218  // TranslatorExplanation the colon is followed by an error message
2219  ZYPP_THROW(RpmSubprocessException(_("RPM failed: ") + (rpmmsg.empty() ? error_message: rpmmsg) ));
2220  }
2221  else if ( ! rpmmsg.empty() )
2222  {
2223  historylog.comment(
2224  str::form("%s removed ok", name_r.c_str()), true /*timestamp*/);
2225 
2226  std::ostringstream sstr;
2227  sstr << "Additional rpm output:" << endl << rpmmsg << endl;
2228  historylog.comment(sstr.str());
2229 
2230  // report additional rpm output in finish
2231  // TranslatorExplanation Text is followed by a ':' and the actual output.
2232  report->finishInfo(str::form( "%s:\n%s\n", _("Additional rpm output"), rpmmsg.c_str() ));
2233  }
2234 }
2235 
2237 //
2238 //
2239 // METHOD NAME : RpmDb::backupPackage
2240 // METHOD TYPE : bool
2241 //
2242 bool RpmDb::backupPackage( const Pathname & filename )
2243 {
2245  if ( ! h )
2246  return false;
2247 
2248  return backupPackage( h->tag_name() );
2249 }
2250 
2252 //
2253 //
2254 // METHOD NAME : RpmDb::backupPackage
2255 // METHOD TYPE : bool
2256 //
2257 bool RpmDb::backupPackage(const std::string& packageName)
2258 {
2259  HistoryLog progresslog;
2260  bool ret = true;
2261  Pathname backupFilename;
2262  Pathname filestobackupfile = _root+_backuppath+FILEFORBACKUPFILES;
2263 
2264  if (_backuppath.empty())
2265  {
2266  INT << "_backuppath empty" << endl;
2267  return false;
2268  }
2269 
2271 
2272  if (!queryChangedFiles(fileList, packageName))
2273  {
2274  ERR << "Error while getting changed files for package " <<
2275  packageName << endl;
2276  return false;
2277  }
2278 
2279  if (fileList.size() <= 0)
2280  {
2281  DBG << "package " << packageName << " not changed -> no backup" << endl;
2282  return true;
2283  }
2284 
2286  {
2287  return false;
2288  }
2289 
2290  {
2291  // build up archive name
2292  time_t currentTime = time(0);
2293  struct tm *currentLocalTime = localtime(&currentTime);
2294 
2295  int date = (currentLocalTime->tm_year + 1900) * 10000
2296  + (currentLocalTime->tm_mon + 1) * 100
2297  + currentLocalTime->tm_mday;
2298 
2299  int num = 0;
2300  do
2301  {
2302  backupFilename = _root + _backuppath
2303  + str::form("%s-%d-%d.tar.gz",packageName.c_str(), date, num);
2304 
2305  }
2306  while ( PathInfo(backupFilename).isExist() && num++ < 1000);
2307 
2308  PathInfo pi(filestobackupfile);
2309  if (pi.isExist() && !pi.isFile())
2310  {
2311  ERR << filestobackupfile.asString() << " already exists and is no file" << endl;
2312  return false;
2313  }
2314 
2315  std::ofstream fp ( filestobackupfile.asString().c_str(), std::ios::out|std::ios::trunc );
2316 
2317  if (!fp)
2318  {
2319  ERR << "could not open " << filestobackupfile.asString() << endl;
2320  return false;
2321  }
2322 
2323  for (FileList::const_iterator cit = fileList.begin();
2324  cit != fileList.end(); ++cit)
2325  {
2326  std::string name = *cit;
2327  if ( name[0] == '/' )
2328  {
2329  // remove slash, file must be relative to -C parameter of tar
2330  name = name.substr( 1 );
2331  }
2332  DBG << "saving file "<< name << endl;
2333  fp << name << endl;
2334  }
2335  fp.close();
2336 
2337  const char* const argv[] =
2338  {
2339  "tar",
2340  "-czhP",
2341  "-C",
2342  _root.asString().c_str(),
2343  "--ignore-failed-read",
2344  "-f",
2345  backupFilename.asString().c_str(),
2346  "-T",
2347  filestobackupfile.asString().c_str(),
2348  NULL
2349  };
2350 
2351  // execute tar in inst-sys (we dont know if there is a tar below _root !)
2352  ExternalProgram tar(argv, ExternalProgram::Stderr_To_Stdout, false, -1, true);
2353 
2354  std::string tarmsg;
2355 
2356  // TODO: its probably possible to start tar with -v and watch it adding
2357  // files to report progress
2358  for (std::string output = tar.receiveLine(); output.length() ;output = tar.receiveLine())
2359  {
2360  tarmsg+=output;
2361  }
2362 
2363  int ret = tar.close();
2364 
2365  if ( ret != 0)
2366  {
2367  ERR << "tar failed: " << tarmsg << endl;
2368  ret = false;
2369  }
2370  else
2371  {
2372  MIL << "tar backup ok" << endl;
2373  progresslog.comment(
2374  str::form(_("created backup %s"), backupFilename.asString().c_str())
2375  , /*timestamp*/true);
2376  }
2377 
2378  filesystem::unlink(filestobackupfile);
2379  }
2380 
2381  return ret;
2382 }
2383 
2384 void RpmDb::setBackupPath(const Pathname& path)
2385 {
2386  _backuppath = path;
2387 }
2388 
2389 std::ostream & operator<<( std::ostream & str, RpmDb::CheckPackageResult obj )
2390 {
2391  switch ( obj )
2392  {
2393 #define OUTS(E,S) case RpmDb::E: return str << "["<< (unsigned)obj << "-"<< S << "]"; break
2394  // translators: possible rpm package signature check result [brief]
2395  OUTS( CHK_OK, _("Signature is OK") );
2396  // translators: possible rpm package signature check result [brief]
2397  OUTS( CHK_NOTFOUND, _("Unknown type of signature") );
2398  // translators: possible rpm package signature check result [brief]
2399  OUTS( CHK_FAIL, _("Signature does not verify") );
2400  // translators: possible rpm package signature check result [brief]
2401  OUTS( CHK_NOTTRUSTED, _("Signature is OK, but key is not trusted") );
2402  // translators: possible rpm package signature check result [brief]
2403  OUTS( CHK_NOKEY, _("Signatures public key is not available") );
2404  // translators: possible rpm package signature check result [brief]
2405  OUTS( CHK_ERROR, _("File does not exist or signature can't be checked") );
2406  // translators: possible rpm package signature check result [brief]
2407  OUTS( CHK_NOSIG, _("File is unsigned") );
2408 #undef OUTS
2409  }
2410  return str << "UnknowSignatureCheckError("+str::numstring(obj)+")";
2411 }
2412 
2413 std::ostream & operator<<( std::ostream & str, const RpmDb::CheckPackageDetail & obj )
2414 {
2415  for ( const auto & el : obj )
2416  str << el.second << endl;
2417  return str;
2418 }
2419 
2420 } // namespace rpm
2421 } // namespace target
2422 } // 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:1604
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:249
bool hasPackage(const std::string &name_r) const
Return true if package is installed.
Definition: RpmDb.cc:1393
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:1351
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:1421
bool hasSubkeys() const
!<
Definition: PublicKey.h:328
Class representing one GPG Public Keys data.
Definition: PublicKey.h:132
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:1923
std::string asString() const
Definition: PublicKey.cc:618
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:246
#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:1379
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:2257
#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:1598
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:1278
#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:612
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:588
void systemKill()
Forcably kill the system process.
Definition: RpmDb.cc:1819
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:582
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:1722
#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:1796
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:1484
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:1254
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:208
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:1953
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:1145
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:1826
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:1365
Class representing one GPG Public Key (PublicKeyData + ASCII armored in a tempfile).
Definition: PublicKey.h:277
void doRemovePackage(const std::string &name_r, RpmInstFlags flags, callback::SendReport< RpmRemoveReport > &report)
Definition: RpmDb.cc:2142
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:2384
static Date now()
Return the current time.
Definition: Date.h:78
void convertV3toV4(const Pathname &v3db_r, const librpmDb::constPtr &v4db_r)
Definition: librpmDb.cv3.cc:39
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:2111
static bool globalInit()
Initialize lib librpm (read configfiles etc.).
Definition: librpmDb.cc:128
std::string * _cap
Definition: RpmDb.cc:1485
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:1307
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:1216
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:1610
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:615
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:1676
std::string name() const
Definition: PublicKey.cc:591
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:1333
#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