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