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