libzypp  15.3.0
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 namespace std;
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 string rpmQuoteFilename( const Pathname & path_r )
81 {
82  string path( path_r.asString() );
83  for ( string::size_type pos = path.find_first_of( quoteInFilename_m );
84  pos != 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 string file1, const string file2, 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  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 string
195 */
196 inline 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 : ostream &
206 */
207 ostream & operator<<( 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 : ostream &
301 //
302 ostream & RpmDb::dumpOn( 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  string line;
822  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(string(_("RPM failed: ") +
851  (errmsg.empty() ? error_message: errmsg))));
852  }
853  else
854  {
855  report->progress( 100, root() + dbPath() ); // 100%
856  }
857 }
858 
860 namespace
861 {
866  void computeKeyRingSync( std::set<Edition> & rpmKeys_r, std::list<PublicKeyData> & zyppKeys_r )
867  {
869  // Remember latest release and where it ocurred
870  struct Key
871  {
872  Key()
873  : _inRpmKeys( nullptr )
874  , _inZyppKeys( nullptr )
875  {}
876 
877  void updateIf( const Edition & rpmKey_r )
878  {
879  std::string keyRelease( rpmKey_r.release() );
880  int comp = _release.compare( keyRelease );
881  if ( comp < 0 )
882  {
883  // update to newer release
884  _release.swap( keyRelease );
885  _inRpmKeys = &rpmKey_r;
886  _inZyppKeys = nullptr;
887  if ( !keyRelease.empty() )
888  DBG << "Old key in R: gpg-pubkey-" << rpmKey_r.version() << "-" << keyRelease << endl;
889  }
890  else if ( comp == 0 )
891  {
892  // stay with this release
893  if ( ! _inRpmKeys )
894  _inRpmKeys = &rpmKey_r;
895  }
896  // else: this is an old release
897  else
898  DBG << "Old key in R: gpg-pubkey-" << rpmKey_r.version() << "-" << keyRelease << endl;
899  }
900 
901  void updateIf( const PublicKeyData & zyppKey_r )
902  {
903  std::string keyRelease( zyppKey_r.gpgPubkeyRelease() );
904  int comp = _release.compare( keyRelease );
905  if ( comp < 0 )
906  {
907  // update to newer release
908  _release.swap( keyRelease );
909  _inRpmKeys = nullptr;
910  _inZyppKeys = &zyppKey_r;
911  if ( !keyRelease.empty() )
912  DBG << "Old key in Z: gpg-pubkey-" << zyppKey_r.gpgPubkeyVersion() << "-" << keyRelease << endl;
913  }
914  else if ( comp == 0 )
915  {
916  // stay with this release
917  if ( ! _inZyppKeys )
918  _inZyppKeys = &zyppKey_r;
919  }
920  // else: this is an old release
921  else
922  DBG << "Old key in Z: gpg-pubkey-" << zyppKey_r.gpgPubkeyVersion() << "-" << keyRelease << endl;
923  }
924 
925  std::string _release;
926  const Edition * _inRpmKeys;
927  const PublicKeyData * _inZyppKeys;
928  };
930 
931  // collect keys by ID(version) and latest creation(release)
932  std::map<std::string,Key> _keymap;
933 
934  for_( it, rpmKeys_r.begin(), rpmKeys_r.end() )
935  {
936  _keymap[(*it).version()].updateIf( *it );
937  }
938 
939  for_( it, zyppKeys_r.begin(), zyppKeys_r.end() )
940  {
941  _keymap[(*it).gpgPubkeyVersion()].updateIf( *it );
942  }
943 
944  // compute missing keys
945  std::set<Edition> rpmKeys;
946  std::list<PublicKeyData> zyppKeys;
947  for_( it, _keymap.begin(), _keymap.end() )
948  {
949  DBG << "gpg-pubkey-" << (*it).first << "-" << (*it).second._release << " "
950  << ( (*it).second._inRpmKeys ? "R" : "_" )
951  << ( (*it).second._inZyppKeys ? "Z" : "_" ) << endl;
952  if ( ! (*it).second._inRpmKeys )
953  {
954  zyppKeys.push_back( *(*it).second._inZyppKeys );
955  }
956  if ( ! (*it).second._inZyppKeys )
957  {
958  rpmKeys.insert( *(*it).second._inRpmKeys );
959  }
960  }
961  rpmKeys_r.swap( rpmKeys );
962  zyppKeys_r.swap( zyppKeys );
963  }
964 } // namespace
966 
968 {
969  MIL << "Going to sync trusted keys..." << endl;
970  std::set<Edition> rpmKeys( pubkeyEditions() );
971  std::list<PublicKeyData> zyppKeys( getZYpp()->keyRing()->trustedPublicKeyData() );
972  computeKeyRingSync( rpmKeys, zyppKeys );
973  MIL << (mode_r & SYNC_TO_KEYRING ? "" : "(skip) ") << "Rpm keys to export into zypp trusted keyring: " << rpmKeys.size() << endl;
974  MIL << (mode_r & SYNC_FROM_KEYRING ? "" : "(skip) ") << "Zypp trusted keys to import into rpm database: " << zyppKeys.size() << endl;
975 
977  if ( (mode_r & SYNC_TO_KEYRING) && ! rpmKeys.empty() )
978  {
979  // export to zypp keyring
980  MIL << "Exporting rpm keyring into zypp trusted keyring" <<endl;
981  // Temporarily disconnect to prevent the attemt to re-import the exported keys.
983  librpmDb::db_const_iterator keepDbOpen; // just to keep a ref.
984 
985  TmpFile tmpfile( getZYpp()->tmpPath() );
986  {
987  ofstream tmpos( tmpfile.path().c_str() );
988  for_( it, rpmKeys.begin(), rpmKeys.end() )
989  {
990  // we export the rpm key into a file
991  RpmHeader::constPtr result;
992  getData( string("gpg-pubkey"), *it, result );
993  tmpos << result->tag_description() << endl;
994  }
995  }
996  try
997  {
998  getZYpp()->keyRing()->multiKeyImport( tmpfile.path(), true /*trusted*/);
999  }
1000  catch (Exception &e)
1001  {
1002  ERR << "Could not import keys into in zypp keyring" << endl;
1003  }
1004  }
1005 
1007  if ( (mode_r & SYNC_FROM_KEYRING) && ! zyppKeys.empty() )
1008  {
1009  // import from zypp keyring
1010  MIL << "Importing zypp trusted keyring" << std::endl;
1011  for_( it, zyppKeys.begin(), zyppKeys.end() )
1012  {
1013  try
1014  {
1015  importPubkey( getZYpp()->keyRing()->exportTrustedPublicKey( *it ) );
1016  }
1017  catch ( const RpmException & exp )
1018  {
1019  ZYPP_CAUGHT( exp );
1020  }
1021  }
1022  }
1023  MIL << "Trusted keys synced." << endl;
1024 }
1025 
1028 
1031 
1033 //
1034 //
1035 // METHOD NAME : RpmDb::importPubkey
1036 // METHOD TYPE : PMError
1037 //
1038 void RpmDb::importPubkey( const PublicKey & pubkey_r )
1039 {
1041 
1042  // bnc#828672: On the fly key import in READONLY
1044  {
1045  WAR << "Key " << pubkey_r << " can not be imported. (READONLY MODE)" << endl;
1046  return;
1047  }
1048 
1049  // check if the key is already in the rpm database
1050  Edition keyEd( pubkey_r.gpgPubkeyVersion(), pubkey_r.gpgPubkeyRelease() );
1051  set<Edition> rpmKeys = pubkeyEditions();
1052  bool hasOldkeys = false;
1053 
1054  for_( it, rpmKeys.begin(), rpmKeys.end() )
1055  {
1056  if ( keyEd == *it ) // quick test (Edition is IdStringType!)
1057  {
1058  MIL << "Key " << pubkey_r << " is already in the rpm trusted keyring. (skip import)" << endl;
1059  return;
1060  }
1061 
1062  if ( keyEd.version() != (*it).version() )
1063  continue; // different key ID (version)
1064 
1065  if ( keyEd.release() < (*it).release() )
1066  {
1067  MIL << "Key " << pubkey_r << " is older than one in the rpm trusted keyring. (skip import)" << endl;
1068  return;
1069  }
1070  else
1071  {
1072  hasOldkeys = true;
1073  }
1074  }
1075  MIL << "Key " << pubkey_r << " will be imported into the rpm trusted keyring." << (hasOldkeys?"(update)":"(new)") << endl;
1076 
1077  if ( hasOldkeys )
1078  {
1079  // We must explicitly delete old key IDs first (all releases,
1080  // that's why we don't call removePubkey here).
1081  std::string keyName( "gpg-pubkey-" + keyEd.version() );
1082  RpmArgVec opts;
1083  opts.push_back ( "-e" );
1084  opts.push_back ( "--allmatches" );
1085  opts.push_back ( "--" );
1086  opts.push_back ( keyName.c_str() );
1087  // don't call modifyDatabase because it would remove the old
1088  // rpm3 database, if the current database is a temporary one.
1090 
1091  string line;
1092  while ( systemReadLine( line ) )
1093  {
1094  ( str::startsWith( line, "error:" ) ? WAR : DBG ) << line << endl;
1095  }
1096 
1097  if ( systemStatus() != 0 )
1098  {
1099  ERR << "Failed to remove key " << pubkey_r << " from RPM trusted keyring (ignored)" << endl;
1100  }
1101  else
1102  {
1103  MIL << "Key " << pubkey_r << " has been removed from RPM trusted keyring" << endl;
1104  }
1105  }
1106 
1107  // import the new key
1108  RpmArgVec opts;
1109  opts.push_back ( "--import" );
1110  opts.push_back ( "--" );
1111  opts.push_back ( pubkey_r.path().asString().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  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  set<Edition> rpm_keys = pubkeyEditions();
1149  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  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  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 : set<Edition>
1212 //
1213 list<PublicKey> RpmDb::pubkeys() const
1214 {
1215  list<PublicKey> ret;
1216 
1218  for ( it.findByName( string( "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( string("gpg-pubkey"), edition, result );
1226  TmpFile file(getZYpp()->tmpPath());
1227  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 (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 set<Edition> RpmDb::pubkeyEditions() const
1252  {
1253  set<Edition> ret;
1254 
1256  for ( it.findByName( string( "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 list<FileInfo>
1275 RpmDb::fileList( const string & name_r, const Edition & edition_r ) const
1276 {
1277  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 string & file_r, const 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 : string
1327 //
1328 // DESCRIPTION :
1329 //
1330 string RpmDb::whoOwnsFile( const 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 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 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 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 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 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 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 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 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  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  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( 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 += 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 string& line, const string& name, const char* typemsg, const char* difffailmsg, const char* diffgenmsg)
1798 {
1799  string msg = line.substr(9);
1800  string::size_type pos1 = string::npos;
1801  string::size_type pos2 = string::npos;
1802  string file1s, file2s;
1803  Pathname file1;
1804  Pathname file2;
1805 
1806  pos1 = msg.find (typemsg);
1807  for (;;)
1808  {
1809  if ( pos1 == 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  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  ofstream notify(file.asString().c_str(), ios::out|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  string::size_type pos = out.find("\n+++ ");
1869  if (pos != 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  string quotedFilename( rpmQuoteFilename( workaroundRpmPwdBug( filename ) ) );
1983  opts.push_back ( quotedFilename.c_str() );
1984 
1985  modifyDatabase(); // BEFORE run_rpm
1987 
1988  string line;
1989  string rpmmsg;
1990  vector<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 (vector<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  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(string(_("RPM failed: ")) +
2045  (rpmmsg.empty() ? error_message : rpmmsg)));
2046  }
2047  else if ( ! rpmmsg.empty() )
2048  {
2049  historylog.comment(
2050  str::form("%s installed ok", Pathname::basename(filename).c_str()),
2051  true /*timestamp*/);
2052  ostringstream sstr;
2053  sstr << "Additional rpm output:" << endl << rpmmsg << endl;
2054  historylog.comment(sstr.str());
2055 
2056  // report additional rpm output in finish
2057  // TranslatorExplanation Text is followed by a ':' and the actual output.
2058  report->finishInfo(str::form( "%s:\n%s\n", _("Additional rpm output"), rpmmsg.c_str() ));
2059  }
2060 }
2061 
2063 //
2064 //
2065 // METHOD NAME : RpmDb::removePackage
2066 // METHOD TYPE : PMError
2067 //
2068 void RpmDb::removePackage( Package::constPtr package, RpmInstFlags flags )
2069 {
2070  // 'rpm -e' does not like epochs
2071  return removePackage( package->name()
2072  + "-" + package->edition().version()
2073  + "-" + package->edition().release()
2074  + "." + package->arch().asString(), flags );
2075 }
2076 
2078 //
2079 //
2080 // METHOD NAME : RpmDb::removePackage
2081 // METHOD TYPE : PMError
2082 //
2083 void RpmDb::removePackage( const string & name_r, RpmInstFlags flags )
2084 {
2086 
2087  report->start( name_r );
2088 
2089  do
2090  try
2091  {
2092  doRemovePackage(name_r, flags, report);
2093  report->finish();
2094  break;
2095  }
2096  catch (RpmException & excpt_r)
2097  {
2098  RpmRemoveReport::Action user = report->problem( excpt_r );
2099 
2100  if ( user == RpmRemoveReport::ABORT )
2101  {
2102  report->finish( excpt_r );
2103  ZYPP_RETHROW(excpt_r);
2104  }
2105  else if ( user == RpmRemoveReport::IGNORE )
2106  {
2107  break;
2108  }
2109  }
2110  while (true);
2111 }
2112 
2113 
2114 void RpmDb::doRemovePackage( const string & name_r, RpmInstFlags flags, callback::SendReport<RpmRemoveReport> & report )
2115 {
2117  HistoryLog historylog;
2118 
2119  MIL << "RpmDb::doRemovePackage(" << name_r << "," << flags << ")" << endl;
2120 
2121  // backup
2122  if ( _packagebackups )
2123  {
2124  // FIXME solve this status report somehow
2125  // report->progress( pd.init( -2, 100 ) ); // allow 1% for backup creation.
2126  if ( ! backupPackage( name_r ) )
2127  {
2128  ERR << "backup of " << name_r << " failed" << endl;
2129  }
2130  report->progress( 0 );
2131  }
2132  else
2133  {
2134  report->progress( 100 );
2135  }
2136 
2137  // run rpm
2138  RpmArgVec opts;
2139  opts.push_back("-e");
2140  opts.push_back("--allmatches");
2141 
2142  if (flags & RPMINST_NOSCRIPTS)
2143  opts.push_back("--noscripts");
2144  if (flags & RPMINST_NODEPS)
2145  opts.push_back("--nodeps");
2146  if (flags & RPMINST_JUSTDB)
2147  opts.push_back("--justdb");
2148  if (flags & RPMINST_TEST)
2149  opts.push_back ("--test");
2150  if (flags & RPMINST_FORCE)
2151  {
2152  WAR << "IGNORE OPTION: 'rpm -e' does not support '--force'" << endl;
2153  }
2154 
2155  opts.push_back("--");
2156  opts.push_back(name_r.c_str());
2157 
2158  modifyDatabase(); // BEFORE run_rpm
2160 
2161  string line;
2162  string rpmmsg;
2163 
2164  // got no progress from command, so we fake it:
2165  // 5 - command started
2166  // 50 - command completed
2167  // 100 if no error
2168  report->progress( 5 );
2169  unsigned linecnt = 0;
2170  while (systemReadLine(line))
2171  {
2172  if ( linecnt < MAXRPMMESSAGELINES )
2173  ++linecnt;
2174  else
2175  continue;
2176  rpmmsg += line+'\n';
2177  }
2178  if ( linecnt > MAXRPMMESSAGELINES )
2179  rpmmsg += "[truncated]\n";
2180  report->progress( 50 );
2181  int rpm_status = systemStatus();
2182 
2183  if ( rpm_status != 0 )
2184  {
2185  historylog.comment(
2186  str::form("%s remove failed", name_r.c_str()), true /*timestamp*/);
2187  ostringstream sstr;
2188  sstr << "rpm output:" << endl << rpmmsg << endl;
2189  historylog.comment(sstr.str());
2190  // TranslatorExplanation the colon is followed by an error message
2191  ZYPP_THROW(RpmSubprocessException(string(_("RPM failed: ")) +
2192  (rpmmsg.empty() ? error_message: rpmmsg)));
2193  }
2194  else if ( ! rpmmsg.empty() )
2195  {
2196  historylog.comment(
2197  str::form("%s removed ok", name_r.c_str()), true /*timestamp*/);
2198 
2199  ostringstream sstr;
2200  sstr << "Additional rpm output:" << endl << rpmmsg << endl;
2201  historylog.comment(sstr.str());
2202 
2203  // report additional rpm output in finish
2204  // TranslatorExplanation Text is followed by a ':' and the actual output.
2205  report->finishInfo(str::form( "%s:\n%s\n", _("Additional rpm output"), rpmmsg.c_str() ));
2206  }
2207 }
2208 
2210 //
2211 //
2212 // METHOD NAME : RpmDb::backupPackage
2213 // METHOD TYPE : bool
2214 //
2215 bool RpmDb::backupPackage( const Pathname & filename )
2216 {
2218  if ( ! h )
2219  return false;
2220 
2221  return backupPackage( h->tag_name() );
2222 }
2223 
2225 //
2226 //
2227 // METHOD NAME : RpmDb::backupPackage
2228 // METHOD TYPE : bool
2229 //
2230 bool RpmDb::backupPackage(const string& packageName)
2231 {
2232  HistoryLog progresslog;
2233  bool ret = true;
2234  Pathname backupFilename;
2235  Pathname filestobackupfile = _root+_backuppath+FILEFORBACKUPFILES;
2236 
2237  if (_backuppath.empty())
2238  {
2239  INT << "_backuppath empty" << endl;
2240  return false;
2241  }
2242 
2244 
2245  if (!queryChangedFiles(fileList, packageName))
2246  {
2247  ERR << "Error while getting changed files for package " <<
2248  packageName << endl;
2249  return false;
2250  }
2251 
2252  if (fileList.size() <= 0)
2253  {
2254  DBG << "package " << packageName << " not changed -> no backup" << endl;
2255  return true;
2256  }
2257 
2259  {
2260  return false;
2261  }
2262 
2263  {
2264  // build up archive name
2265  time_t currentTime = time(0);
2266  struct tm *currentLocalTime = localtime(&currentTime);
2267 
2268  int date = (currentLocalTime->tm_year + 1900) * 10000
2269  + (currentLocalTime->tm_mon + 1) * 100
2270  + currentLocalTime->tm_mday;
2271 
2272  int num = 0;
2273  do
2274  {
2275  backupFilename = _root + _backuppath
2276  + str::form("%s-%d-%d.tar.gz",packageName.c_str(), date, num);
2277 
2278  }
2279  while ( PathInfo(backupFilename).isExist() && num++ < 1000);
2280 
2281  PathInfo pi(filestobackupfile);
2282  if (pi.isExist() && !pi.isFile())
2283  {
2284  ERR << filestobackupfile.asString() << " already exists and is no file" << endl;
2285  return false;
2286  }
2287 
2288  ofstream fp ( filestobackupfile.asString().c_str(), ios::out|ios::trunc );
2289 
2290  if (!fp)
2291  {
2292  ERR << "could not open " << filestobackupfile.asString() << endl;
2293  return false;
2294  }
2295 
2296  for (FileList::const_iterator cit = fileList.begin();
2297  cit != fileList.end(); ++cit)
2298  {
2299  string name = *cit;
2300  if ( name[0] == '/' )
2301  {
2302  // remove slash, file must be relative to -C parameter of tar
2303  name = name.substr( 1 );
2304  }
2305  DBG << "saving file "<< name << endl;
2306  fp << name << endl;
2307  }
2308  fp.close();
2309 
2310  const char* const argv[] =
2311  {
2312  "tar",
2313  "-czhP",
2314  "-C",
2315  _root.asString().c_str(),
2316  "--ignore-failed-read",
2317  "-f",
2318  backupFilename.asString().c_str(),
2319  "-T",
2320  filestobackupfile.asString().c_str(),
2321  NULL
2322  };
2323 
2324  // execute tar in inst-sys (we dont know if there is a tar below _root !)
2325  ExternalProgram tar(argv, ExternalProgram::Stderr_To_Stdout, false, -1, true);
2326 
2327  string tarmsg;
2328 
2329  // TODO: its probably possible to start tar with -v and watch it adding
2330  // files to report progress
2331  for (string output = tar.receiveLine(); output.length() ;output = tar.receiveLine())
2332  {
2333  tarmsg+=output;
2334  }
2335 
2336  int ret = tar.close();
2337 
2338  if ( ret != 0)
2339  {
2340  ERR << "tar failed: " << tarmsg << endl;
2341  ret = false;
2342  }
2343  else
2344  {
2345  MIL << "tar backup ok" << endl;
2346  progresslog.comment(
2347  str::form(_("created backup %s"), backupFilename.asString().c_str())
2348  , /*timestamp*/true);
2349  }
2350 
2351  filesystem::unlink(filestobackupfile);
2352  }
2353 
2354  return ret;
2355 }
2356 
2357 void RpmDb::setBackupPath(const Pathname& path)
2358 {
2359  _backuppath = path;
2360 }
2361 
2362 std::ostream & operator<<( std::ostream & str, RpmDb::CheckPackageResult obj )
2363 {
2364  switch ( obj )
2365  {
2366 #define OUTS(E,S) case RpmDb::E: return str << "["<< (unsigned)obj << "-"<< S << "]"; break
2367  // translators: possible rpm package signature check result [brief]
2368  OUTS( CHK_OK, _("Signature is OK") );
2369  // translators: possible rpm package signature check result [brief]
2370  OUTS( CHK_NOTFOUND, _("Unknown type of signature") );
2371  // translators: possible rpm package signature check result [brief]
2372  OUTS( CHK_FAIL, _("Signature does not verify") );
2373  // translators: possible rpm package signature check result [brief]
2374  OUTS( CHK_NOTTRUSTED, _("Signature is OK, but key is not trusted") );
2375  // translators: possible rpm package signature check result [brief]
2376  OUTS( CHK_NOKEY, _("Signatures public key is not available") );
2377  // translators: possible rpm package signature check result [brief]
2378  OUTS( CHK_ERROR, _("File does not exist or signature can't be checked") );
2379 #undef OUTS
2380  }
2381  return str << "UnknowSignatureCheckError("+str::numstring(obj)+")";
2382 }
2383 
2384 std::ostream & operator<<( std::ostream & str, const RpmDb::CheckPackageDetail & obj )
2385 {
2386  for ( const auto & el : obj )
2387  str << el.second << endl;
2388  return str;
2389 }
2390 
2391 } // namespace rpm
2392 } // namespace target
2393 } // namespace zypp
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:324
Interface to gettext.
Interface to the rpm program.
Definition: RpmDb.h:47
#define MIL
Definition: Logger.h:64
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:320
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: ZConfig.cc:679
Pathname path() const
Definition: TmpPath.cc:146
unsigned split(const C_Str &line_r, _OutputIterator result_r, const C_Str &sepchars_r=" \t")
Split line_r into words.
Definition: String.h:471
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:1029
#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
unsigned diffFiles(const string file1, const string file2, string &out, int maxlines)
Definition: RpmDb.cc:160
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
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()
Definition: Arch.h:330
void modifyDatabase()
Called before the database is modified by installPackage/removePackage.
Definition: RpmDb.cc:708
virtual std::ostream & dumpOn(std::ostream &str) const
Dump debug info.
Definition: RpmDb.cc:302
#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:1026
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:2230
#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
#define FILEFORBACKUPFILES
Definition: RpmDb.cc:58
string stringPath(const Pathname &root_r, const Pathname &sub_r)
Definition: RpmDb.cc:196
Subclass to retrieve database content.
Definition: librpmDb.h:490
Temporarily connect a ReceiveReport then restore the previous one.
Definition: Callback.h:270
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:1038
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:328
void syncTrustedKeys(SyncTrustedKeyBits mode_r=SYNC_BOTH)
Sync trusted keys stored in rpm database and zypp trusted keyring.
Definition: RpmDb.cc:967
#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
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
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
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:663
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:677
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:417
#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:1016
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: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
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:271
export rpm trusted keys into zypp trusted keyring
Definition: RpmDb.h:330
#define OUTS(E, S)
SolvableIdType size_type
Definition: PoolMember.h:99
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
std::ostream & operator<<(std::ostream &str, const zypp::shared_ptr< void > &obj)
Definition: PtrTypes.h:134
std::string asString(const Patch::SeverityFlag &obj)
Definition: Patch.cc:166
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
std::set< Edition > pubkeyEditions() const
Return the edition of all installed public keys.
Definition: RpmDb.cc:1251
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:755
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:324
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:2114
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:111
void setBackupPath(const Pathname &path)
set path where package backups are stored
Definition: RpmDb.cc:2357
static Date now()
Return the current time.
Definition: Date.h:77
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:2083
static bool globalInit()
Initialize lib librpm (read configfiles etc.).
Definition: librpmDb.cc:128
std::string * _cap
Definition: RpmDb.cc:1482
std::list< PublicKey > pubkeys() const
Return the long ids of all installed public keys.
Definition: RpmDb.cc:1213
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:156
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
void dbsi_set(DbStateInfoBits &val_r, const unsigned &bits_r) const
Definition: RpmDb.h:75
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
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
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
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc:1
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
#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