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