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