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