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