libzypp 17.38.14
RpmDb.cc
Go to the documentation of this file.
1/*---------------------------------------------------------------------\
2| ____ _ __ __ ___ |
3| |__ / \ / / . \ . \ |
4| / / \ V /| _/ _/ |
5| / /__ | | | | | | |
6| /_____||_| |_| |_| |
7| |
8\---------------------------------------------------------------------*/
12#include "librpm.h"
13extern "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 <utility>
30#include <vector>
31#include <algorithm>
32
38#include <zypp-core/base/DtorReset>
39
40#include <zypp-core/Date.h>
41#include <zypp-core/Pathname.h>
42#include <zypp/PathInfo.h>
44#include <zypp-core/ui/ProgressData>
45
49
50#include <zypp/HistoryLog.h>
53#include <zypp/TmpPath.h>
54#include <zypp/KeyRing.h>
56#include <zypp/ZYppFactory.h>
57#include <zypp/ZConfig.h>
59
60using std::endl;
61using namespace zypp::filesystem;
62
63#define WARNINGMAILPATH "/var/log/YaST2/"
64#define FILEFORBACKUPFILES "YaSTBackupModifiedFiles"
65#define MAXRPMMESSAGELINES 10000
66
67#define WORKAROUNDRPMPWDBUG
68
69#undef ZYPP_BASE_LOGGER_LOGGROUP
70#define ZYPP_BASE_LOGGER_LOGGROUP "librpmDb"
71
72namespace zypp
73{
74 namespace zypp_readonly_hack
75 {
76 bool IGotIt(); // in readonly-mode
77 }
78 namespace env
79 {
80 inline bool ZYPP_RPM_DEBUG()
81 {
82 static bool val = [](){
83 const char * env = getenv("ZYPP_RPM_DEBUG");
84 return( env && str::strToBool( env, true ) );
85 }();
86 return val;
87 }
88 } // namespace env
89namespace target
90{
91namespace rpm
92{
93namespace
94{
95const char* quoteInFilename_m = "\'\"";
96inline std::string rpmQuoteFilename( const Pathname & path_r )
97{
98 std::string path( path_r.asString() );
99 for ( std::string::size_type pos = path.find_first_of( quoteInFilename_m );
100 pos != std::string::npos;
101 pos = path.find_first_of( quoteInFilename_m, pos ) )
102 {
103 path.insert( pos, "\\" );
104 pos += 2; // skip '\\' and the quoted char.
105 }
106 return path;
107}
108
109
114 inline Pathname workaroundRpmPwdBug( Pathname path_r )
115 {
116#if defined(WORKAROUNDRPMPWDBUG)
117 if ( path_r.relative() )
118 {
119 // try to prepend cwd
120 AutoDispose<char*> cwd( ::get_current_dir_name(), ::free );
121 if ( cwd )
122 return Pathname( cwd ) / path_r;
123 WAR << "Can't get cwd!" << endl;
124 }
125#endif
126 return path_r; // no problem with absolute pathnames
127 }
128
133 inline bool workaroundDUMPPOSTTRANS_BUG_1216091( bool checkit_r=false )
134 {
135 auto checkit = []()->bool {
136 bool broken = false;
138 if ( it.findPackage( "rpm" )
139 && Edition::match( it->tag_edition(), "4.18.0" ) == 0
140 && not it->tag_provides().count( Capability("rpm_fixed_runposttrans") ) ) {
141 WAR << "Workaround broken rpm --runposttrans" << endl;
142 broken = true;
143 }
144 return broken;
145 };
146
147 static bool broken = false;
148 if ( checkit_r )
149 broken = checkit();
150 return broken;
151 }
152}
153
155{
161
163 {
164 disconnect();
165 }
166
167 void trustedKeyAdded( const PublicKey &key ) override
168 {
169 MIL << "trusted key added to zypp Keyring. Importing..." << endl;
170 _rpmdb.importPubkey( key );
171 }
172
173 void trustedKeyRemoved( const PublicKey &key ) override
174 {
175 MIL << "Trusted key removed from zypp Keyring. Removing..." << endl;
176 _rpmdb.removePubkey( key );
177 }
178
180};
181
183
184unsigned diffFiles(const std::string& file1, const std::string& file2, std::string& out, int maxlines)
185{
186 const char* argv[] =
187 {
188 "diff",
189 "-u",
190 file1.c_str(),
191 file2.c_str(),
192 NULL
193 };
194 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
195
196 //if(!prog)
197 //return 2;
198
199 std::string line;
200 int count = 0;
201 for (line = prog.receiveLine(), count=0;
202 !line.empty();
203 line = prog.receiveLine(), count++ )
204 {
205 if (maxlines<0?true:count<maxlines)
206 out+=line;
207 }
208
209 return prog.close();
210}
211
213//
214// CLASS NAME : RpmDb
215//
217
218#define FAILIFNOTINITIALIZED if( ! initialized() ) { ZYPP_THROW(RpmDbNotOpenException()); }
219
221
223//
224//
225// METHOD NAME : RpmDb::RpmDb
226// METHOD TYPE : Constructor
227//
229 : _backuppath ("/var/adm/backup")
230 , _packagebackups(false)
231{
232 process = 0;
233 exit_code = -1;
235 // Some rpm versions are patched not to abort installation if
236 // symlink creation failed.
237 setenv( "RPM_IgnoreFailedSymlinks", "1", 1 );
238 sKeyRingReceiver.reset(new KeyRingSignalReceiver(*this));
239}
240
242//
243//
244// METHOD NAME : RpmDb::~RpmDb
245// METHOD TYPE : Destructor
246//
248{
249 MIL << "~RpmDb()" << endl;
251 delete process;
252 MIL << "~RpmDb() end" << endl;
253 sKeyRingReceiver.reset();
254}
255
257//
258//
259// METHOD NAME : RpmDb::dumpOn
260// METHOD TYPE : std::ostream &
261//
262std::ostream & RpmDb::dumpOn( std::ostream & str ) const
263{
264 return str << "RpmDb[" << dumpPath( _root, _dbPath ) << "]";
265}
266
269{
270 if ( initialized() )
271 return db_const_iterator( root(), dbPath() );
272 return db_const_iterator();
273}
274
276//
277//
278// METHOD NAME : RpmDb::initDatabase
279// METHOD TYPE : PMError
280//
281void RpmDb::initDatabase( Pathname root_r, bool doRebuild_r )
282{
283 workaroundDUMPPOSTTRANS_BUG_1216091( /*checkit_r*/true );
285 // Check arguments
287 if ( root_r.empty() )
288 root_r = "/";
289
290 const Pathname & dbPath_r { librpmDb::suggestedDbPath( root_r ) }; // also asserts root_r is absolute
291
292 // The rpmdb compat symlink.
293 // Required at least until rpmdb2solv takes a dppath argument.
294 // Otherwise it creates a db at "/var/lib/rpm".
295 if ( dbPath_r != "/var/lib/rpm" && ! PathInfo( root_r/"/var/lib/rpm" ).isExist() )
296 {
297 WAR << "Inject missing /var/lib/rpm compat symlink to " << dbPath_r << endl;
298 filesystem::assert_dir( root_r/"/var/lib" );
299 filesystem::symlink( "../../"/dbPath_r, root_r/"/var/lib/rpm" );
300 }
301
303 // Check whether already initialized
305 if ( initialized() )
306 {
307 // Just check for a changing root because the librpmDb::suggestedDbPath
308 // may indeed change: rpm %post moving the db from /var/lib/rpm
309 // to /usr/lib/sysimage/rpm. We continue to use the old dbpath
310 // (via the compat symlink) until a re-init.
311 if ( root_r == _root ) {
312 MIL << "Calling initDatabase: already initialized at " << dumpPath( _root, _dbPath ) << endl;
313 return;
314 }
315 else
317 }
318
319 MIL << "Calling initDatabase: " << dumpPath( root_r, dbPath_r )
320 << ( doRebuild_r ? " (rebuilddb)" : "" ) << endl;
321
323 // init database
325 // creates dbdir and empty rpm database if not present
326 // or throws RpmException
327 librpmDb::dbOpenCreate( root_r, dbPath_r );
328 _root = root_r;
329 _dbPath = dbPath_r;
330
331 if ( doRebuild_r )
333
334 MIL << "Synchronizing keys with zypp keyring" << endl;
336
337#if 0 // if this is needed we need to forcefully close the db of running db_const_iterators
338 // Close the database in case any write acces (create/convert)
339 // happened during init. This should drop any lock acquired
340 // by librpm. On demand it will be reopened readonly and should
341 // not hold any lock.
342 librpmDb::dbRelease( true );
343#endif
344 MIL << "InitDatabase: " << *this << endl;
345}
346
348//
349//
350// METHOD NAME : RpmDb::closeDatabase
351// METHOD TYPE : PMError
352//
354{
355 if ( ! initialized() )
356 {
357 return;
358 }
359
360 // NOTE: There are no persistent librpmDb handles to invalidate.
361 // Running db_const_iterator may keep the DB physically open until they
362 // go out of scope too.
363 MIL << "closeDatabase: " << *this << endl;
364 _root = _dbPath = Pathname();
365}
366
368//
369//
370// METHOD NAME : RpmDb::rebuildDatabase
371// METHOD TYPE : PMError
372//
374{
376
377 report->start( root() + dbPath() );
378
379 try
380 {
381 doRebuildDatabase(report);
382 }
383 catch (RpmException & excpt_r)
384 {
385 report->finish(root() + dbPath(), RebuildDBReport::FAILED, excpt_r.asUserHistory());
386 ZYPP_RETHROW(excpt_r);
387 }
388 report->finish(root() + dbPath(), RebuildDBReport::NO_ERROR, "");
389}
390
392{
394 MIL << "RpmDb::rebuildDatabase" << *this << endl;
395
396 const Pathname mydbpath { root()/dbPath() }; // the configured path used in reports
397 {
398 // For --rebuilddb take care we're using the real db directory
399 // and not a symlink. Otherwise rpm will rename the symlink and
400 // replace it with a real directory containing the converted db.
401 DtorReset guardRoot { _root };
402 DtorReset guardDbPath{ _dbPath };
403 _root = "/";
404 _dbPath = filesystem::expandlink( mydbpath );
405
406 // run rpm
407 RpmArgVec opts;
408 opts.push_back("--rebuilddb");
409 opts.push_back("-vv");
411 }
412
413 // generate and report progress
414 ProgressData tics;
415 {
416 ProgressData::value_type hdrTotal = 0;
417 for ( auto it = dbConstIterator(); *it; ++it, ++hdrTotal )
418 {;}
419 tics.range( hdrTotal );
420 }
421 tics.sendTo( [&report,&mydbpath]( const ProgressData & tics_r ) -> bool {
422 return report->progress( tics_r.reportValue(), mydbpath );
423 } );
424 tics.toMin();
425
426 std::string line;
427 std::string errmsg;
428 while ( systemReadLine( line ) )
429 {
430 static const std::string debugPrefix { "D:" };
431 static const std::string progressPrefix { "D: read h#" };
432 static const std::string ignoreSuffix { "digest: OK" };
433
434 if ( ! str::startsWith( line, debugPrefix ) )
435 {
436 if ( ! str::endsWith( line, ignoreSuffix ) )
437 {
438 errmsg += line;
439 errmsg += '\n';
440 WAR << line << endl;
441 }
442 }
443 else if ( str::startsWith( line, progressPrefix ) )
444 {
445 if ( ! tics.incr() )
446 {
447 WAR << "User requested abort." << endl;
448 systemKill();
449 }
450 }
451 }
452
453 if ( systemStatus() != 0 )
454 {
455 //TranslatorExplanation after semicolon is error message
456 ZYPP_THROW(RpmSubprocessException(std::string(_("RPM failed: ")) + (errmsg.empty() ? error_message: errmsg) ) );
457 }
458 else
459 {
460 tics.toMax();
461 }
462}
463
465namespace
466{
471 void computeKeyRingSync( std::set<Edition> & rpmKeys_r, std::list<PublicKeyData> & zyppKeys_r )
472 {
474 // Remember latest release and where it occurred
475 struct Key
476 {
477 Key()
478 : _inRpmKeys( nullptr )
479 , _inZyppKeys( nullptr )
480 {}
481
482 void updateIf( const Edition & rpmKey_r )
483 {
484 std::string keyRelease( rpmKey_r.release() );
485 int comp = _release.compare( keyRelease );
486 if ( comp < 0 )
487 {
488 // update to newer release
489 _release.swap( keyRelease );
490 _inRpmKeys = &rpmKey_r;
491 _inZyppKeys = nullptr;
492 if ( !keyRelease.empty() )
493 DBG << "Old key in Z: gpg-pubkey-" << rpmKey_r.version() << "-" << keyRelease << endl;
494 }
495 else if ( comp == 0 )
496 {
497 // stay with this release
498 if ( ! _inRpmKeys )
499 _inRpmKeys = &rpmKey_r;
500 }
501 // else: this is an old release
502 else
503 DBG << "Old key in R: gpg-pubkey-" << rpmKey_r.version() << "-" << keyRelease << endl;
504 }
505
506 void updateIf( const PublicKeyData & zyppKey_r )
507 {
508 std::string keyRelease( zyppKey_r.gpgPubkeyRelease() );
509 int comp = _release.compare( keyRelease );
510 if ( comp < 0 )
511 {
512 // update to newer release
513 _release.swap( keyRelease );
514 _inRpmKeys = nullptr;
515 _inZyppKeys = &zyppKey_r;
516 if ( !keyRelease.empty() )
517 DBG << "Old key in R: gpg-pubkey-" << zyppKey_r.gpgPubkeyVersion() << "-" << keyRelease << endl;
518 }
519 else if ( comp == 0 )
520 {
521 // stay with this release
522 if ( ! _inZyppKeys )
523 _inZyppKeys = &zyppKey_r;
524 }
525 // else: this is an old release
526 else
527 DBG << "Old key in Z: gpg-pubkey-" << zyppKey_r.gpgPubkeyVersion() << "-" << keyRelease << endl;
528 }
529
530 std::string _release;
531 const Edition * _inRpmKeys;
532 const PublicKeyData * _inZyppKeys;
533 };
535
536 // collect keys by ID(version) and latest creation(release)
537 std::map<std::string,Key> _keymap;
538
539 for_( it, rpmKeys_r.begin(), rpmKeys_r.end() )
540 {
541 _keymap[(*it).version()].updateIf( *it );
542 }
543
544 for_( it, zyppKeys_r.begin(), zyppKeys_r.end() )
545 {
546 _keymap[(*it).gpgPubkeyVersion()].updateIf( *it );
547 }
548
549 // compute missing keys
550 std::set<Edition> rpmKeys;
551 std::list<PublicKeyData> zyppKeys;
552 for_( it, _keymap.begin(), _keymap.end() )
553 {
554 DBG << "gpg-pubkey-" << (*it).first << "-" << (*it).second._release << " "
555 << ( (*it).second._inRpmKeys ? "R" : "_" )
556 << ( (*it).second._inZyppKeys ? "Z" : "_" ) << endl;
557 if ( ! (*it).second._inRpmKeys )
558 {
559 zyppKeys.push_back( *(*it).second._inZyppKeys );
560 }
561 if ( ! (*it).second._inZyppKeys )
562 {
563 rpmKeys.insert( *(*it).second._inRpmKeys );
564 }
565 }
566 rpmKeys_r.swap( rpmKeys );
567 zyppKeys_r.swap( zyppKeys );
568 }
569} // namespace
571
573{
574 MIL << "Going to sync trusted keys..." << endl;
575 std::set<Edition> rpmKeys( pubkeyEditions() );
576 std::list<PublicKeyData> zyppKeys( getZYpp()->keyRing()->trustedPublicKeyData() );
577
578 if ( ! ( mode_r & SYNC_FROM_KEYRING ) )
579 {
580 // bsc#1064380: We relief PK from removing excess keys in the zypp keyring
581 // when re-acquiring the zyppp lock. For now we remove all excess keys.
582 // TODO: Once we can safely assume that all PK versions are updated we
583 // can think about re-importing newer key versions found in the zypp keyring and
584 // removing only excess ones (but case is not very likely). Unfixed PK versions
585 // however will remove the newer version found in the zypp keyring and by doing
586 // this, the key here will be removed via callback as well (keys are deleted
587 // via gpg id, regardless of the edition).
588 MIL << "Removing excess keys in zypp trusted keyring" << std::endl;
589 // Temporarily disconnect to prevent the attempt to pass back the delete request.
591 bool dirty = false;
592 for ( const PublicKeyData & keyData : zyppKeys )
593 {
594 if ( ! rpmKeys.count( keyData.gpgPubkeyEdition() ) )
595 {
596 DBG << "Excess key in Z to delete: gpg-pubkey-" << keyData.gpgPubkeyEdition() << endl;
597 getZYpp()->keyRing()->deleteKey( keyData.id(), /*trusted*/true );
598 if ( !dirty ) dirty = true;
599 }
600 }
601 if ( dirty )
602 zyppKeys = getZYpp()->keyRing()->trustedPublicKeyData();
603 }
604
605 computeKeyRingSync( rpmKeys, zyppKeys );
606 MIL << (mode_r & SYNC_TO_KEYRING ? "" : "(skip) ") << "Rpm keys to export into zypp trusted keyring: " << rpmKeys.size() << endl;
607 MIL << (mode_r & SYNC_FROM_KEYRING ? "" : "(skip) ") << "Zypp trusted keys to import into rpm database: " << zyppKeys.size() << endl;
608
610 if ( (mode_r & SYNC_TO_KEYRING) && ! rpmKeys.empty() )
611 {
612 // export to zypp keyring
613 MIL << "Exporting rpm keyring into zypp trusted keyring" <<endl;
614 // Temporarily disconnect to prevent the attempt to re-import the exported keys.
616 auto keepDbOpen = dbConstIterator(); // just to keep a ref.
617
618 TmpFile tmpfile( getZYpp()->tmpPath() );
619 {
620 std::ofstream tmpos( tmpfile.path().c_str() );
621 for_( it, rpmKeys.begin(), rpmKeys.end() )
622 {
623 // we export the rpm key into a file
624 RpmHeader::constPtr result;
625 getData( "gpg-pubkey", *it, result );
626 tmpos << result->tag_description() << endl;
627 }
628 }
629 try
630 {
631 getZYpp()->keyRing()->multiKeyImport( tmpfile.path(), true /*trusted*/);
632 // bsc#1096217: Try to spot and report legacy V3 keys found in the rpm database.
633 // Modern rpm does not import those keys, but when migrating a pre SLE12 system
634 // we may find them. rpm>4.13 even complains on sderr if sucha key is present.
635 std::set<Edition> missingKeys;
636 for ( const Edition & key : rpmKeys )
637 {
638 if ( getZYpp()->keyRing()->isKeyTrusted( key.version() ) ) // key.version is the gpgkeys short ID
639 continue;
640 ERR << "Could not import key:" << str::Format("gpg-pubkey-%s") % key << " into zypp keyring (V3 key?)" << endl;
641 missingKeys.insert( key );
642 }
643 if ( ! missingKeys.empty() )
644 callback::SendReport<KeyRingReport>()->reportNonImportedKeys(missingKeys);
645 }
646 catch ( const Exception & excpt )
647 {
648 ZYPP_CAUGHT( excpt );
649 ERR << "Could not import keys into zypp keyring: " << endl;
650 }
651 }
652
654 if ( (mode_r & SYNC_FROM_KEYRING) && ! zyppKeys.empty() )
655 {
656 // import from zypp keyring
657 MIL << "Importing zypp trusted keyring" << std::endl;
658 for_( it, zyppKeys.begin(), zyppKeys.end() )
659 {
660 try
661 {
662 importPubkey( getZYpp()->keyRing()->exportTrustedPublicKey( *it ) );
663 }
664 catch ( const RpmException & exp )
665 {
666 ZYPP_CAUGHT( exp );
667 }
668 }
669 }
670 MIL << "Trusted keys synced." << endl;
671}
672
675
678
680//
681//
682// METHOD NAME : RpmDb::importPubkey
683// METHOD TYPE : PMError
684//
685void RpmDb::importPubkey( const PublicKey & pubkey_r )
686{
688
689 // bnc#828672: On the fly key import in READONLY
691 {
692 WAR << "Key " << pubkey_r << " can not be imported. (READONLY MODE)" << endl;
693 return;
694 }
695
696 // check if the key is already in the rpm database
697 Edition keyEd( pubkey_r.gpgPubkeyVersion(), pubkey_r.gpgPubkeyRelease() );
698 std::set<Edition> rpmKeys = pubkeyEditions();
699 bool hasOldkeys = false;
700
701 for_( it, rpmKeys.begin(), rpmKeys.end() )
702 {
703 // bsc#1008325: Keys using subkeys for signing don't get a higher release
704 // if new subkeys are added, because the primary key remains unchanged.
705 // For now always re-import keys with subkeys. Here we don't want to export the
706 // keys in the rpm database to check whether the subkeys are the same. The calling
707 // code should take care, we don't re-import the same kesy over and over again.
708 if ( keyEd == *it && !pubkey_r.hasSubkeys() ) // quick test (Edition is IdStringType!)
709 {
710 MIL << "Key " << pubkey_r << " is already in the rpm trusted keyring. (skip import)" << endl;
711 return;
712 }
713
714 if ( keyEd.version() != (*it).version() )
715 continue; // different key ID (version)
716
717 if ( keyEd.release() < (*it).release() )
718 {
719 MIL << "Key " << pubkey_r << " is older than one in the rpm trusted keyring. (skip import)" << endl;
720 return;
721 }
722 else
723 {
724 hasOldkeys = true;
725 }
726 }
727 MIL << "Key " << pubkey_r << " will be imported into the rpm trusted keyring." << (hasOldkeys?"(update)":"(new)") << endl;
728
729 if ( hasOldkeys )
730 {
731 // We must explicitly delete old key IDs first (all releases,
732 // that's why we don't call removePubkey here).
733 std::string keyName( "gpg-pubkey-" + keyEd.version() );
734 RpmArgVec opts;
735 opts.push_back ( "-e" );
736 opts.push_back ( "--allmatches" );
737 opts.push_back ( "--" );
738 opts.push_back ( keyName.c_str() );
740
741 std::string line;
742 while ( systemReadLine( line ) )
743 {
744 ( str::startsWith( line, "error:" ) ? WAR : DBG ) << line << endl;
745 }
746
747 if ( systemStatus() != 0 )
748 {
749 ERR << "Failed to remove key " << pubkey_r << " from RPM trusted keyring (ignored)" << endl;
750 }
751 else
752 {
753 MIL << "Key " << pubkey_r << " has been removed from RPM trusted keyring" << endl;
754 }
755 }
756
757 // import the new key
758 RpmArgVec opts;
759 opts.push_back ( "--import" );
760 opts.push_back ( "--" );
761 std::string pubkeypath( pubkey_r.path().asString() );
762 opts.push_back ( pubkeypath.c_str() );
764
765 std::string line;
766 std::vector<std::string> excplines;
767 while ( systemReadLine( line ) )
768 {
769 if ( str::startsWith( line, "error:" ) )
770 {
771 WAR << line << endl;
772 excplines.push_back( std::move(line) );
773 }
774 else
775 DBG << line << endl;
776 }
777
778 if ( systemStatus() != 0 )
779 {
780 // Translator: %1% is a gpg public key
781 RpmSubprocessException excp( str::Format(_("Failed to import public key %1%") ) % pubkey_r.asString() );
782 excp.moveToHistory( excplines );
783 excp.addHistory( std::move(error_message) );
784 ZYPP_THROW( excp );
785 }
786 else
787 {
788 MIL << "Key " << pubkey_r << " imported in rpm trusted keyring." << endl;
789 }
790}
791
793//
794//
795// METHOD NAME : RpmDb::removePubkey
796// METHOD TYPE : PMError
797//
798void RpmDb::removePubkey( const PublicKey & pubkey_r )
799{
801
802 // check if the key is in the rpm database and just
803 // return if it does not.
804 std::set<Edition> rpm_keys = pubkeyEditions();
805 std::set<Edition>::const_iterator found_edition = rpm_keys.end();
806 std::string pubkeyVersion( pubkey_r.gpgPubkeyVersion() );
807
808 for_( it, rpm_keys.begin(), rpm_keys.end() )
809 {
810 if ( (*it).version() == pubkeyVersion )
811 {
812 found_edition = it;
813 break;
814 }
815 }
816
817 // the key does not exist, cannot be removed
818 if (found_edition == rpm_keys.end())
819 {
820 WAR << "Key " << pubkey_r.id() << " is not in rpm db" << endl;
821 return;
822 }
823
824 std::string rpm_name("gpg-pubkey-" + found_edition->asString());
825
826 RpmArgVec opts;
827 opts.push_back ( "-e" );
828 opts.push_back ( "--" );
829 opts.push_back ( rpm_name.c_str() );
831
832 std::string line;
833 std::vector<std::string> excplines;
834 while ( systemReadLine( line ) )
835 {
836 if ( str::startsWith( line, "error:" ) )
837 {
838 WAR << line << endl;
839 excplines.push_back( std::move(line) );
840 }
841 else
842 DBG << line << endl;
843 }
844
845 if ( systemStatus() != 0 )
846 {
847 // Translator: %1% is a gpg public key
848 RpmSubprocessException excp( str::Format(_("Failed to remove public key %1%") ) % pubkey_r.asString() );
849 excp.moveToHistory( excplines );
850 excp.addHistory( std::move(error_message) );
851 ZYPP_THROW( excp );
852 }
853 else
854 {
855 MIL << "Key " << pubkey_r << " has been removed from RPM trusted keyring" << endl;
856 }
857}
858
860//
861//
862// METHOD NAME : RpmDb::pubkeys
863// METHOD TYPE : std::set<Edition>
864//
865std::list<PublicKey> RpmDb::pubkeys() const
866{
867 std::list<PublicKey> ret;
868
869 auto it = dbConstIterator();
870 for ( it.findByName( "gpg-pubkey" ); *it; ++it )
871 {
872 Edition edition = it->tag_edition();
873 if (edition != Edition::noedition)
874 {
875 // we export the rpm key into a file
876 RpmHeader::constPtr result;
877 getData( "gpg-pubkey", edition, result );
878 TmpFile file(getZYpp()->tmpPath());
879 std::ofstream os;
880 try
881 {
882 os.open(file.path().asString().c_str());
883 // dump rpm key into the tmp file
884 os << result->tag_description();
885 //MIL << "-----------------------------------------------" << endl;
886 //MIL << result->tag_description() <<endl;
887 //MIL << "-----------------------------------------------" << endl;
888 os.close();
889 // read the public key from the dumped file
890 PublicKey key(file);
891 ret.push_back(key);
892 }
893 catch ( std::exception & e )
894 {
895 ERR << "Could not dump key " << edition.asString() << " in tmp file " << file.path() << endl;
896 // just ignore the key
897 }
898 }
899 }
900 return ret;
901}
902
903std::set<Edition> RpmDb::pubkeyEditions() const
904 {
905 std::set<Edition> ret;
906
907 auto it = dbConstIterator();
908 for ( it.findByName( "gpg-pubkey" ); *it; ++it )
909 {
910 Edition edition = it->tag_edition();
911 if (edition != Edition::noedition)
912 ret.insert( edition );
913 }
914 return ret;
915 }
916
917
919//
920//
921// METHOD NAME : RpmDb::fileList
922// METHOD TYPE : bool
923//
924// DESCRIPTION :
925//
926std::list<FileInfo>
927RpmDb::fileList( const std::string & name_r, const Edition & edition_r ) const
928{
929 std::list<FileInfo> result;
930
931 auto it = dbConstIterator();
932 bool found = false;
933 if (edition_r == Edition::noedition)
934 {
935 found = it.findPackage( name_r );
936 }
937 else
938 {
939 found = it.findPackage( name_r, edition_r );
940 }
941 if (!found)
942 return result;
943
944 return result;
945}
946
947
949//
950//
951// METHOD NAME : RpmDb::hasFile
952// METHOD TYPE : bool
953//
954// DESCRIPTION :
955//
956bool RpmDb::hasFile( const std::string & file_r, const std::string & name_r ) const
957{
958 auto it = dbConstIterator();
959 bool res = false;
960 do
961 {
962 res = it.findByFile( file_r );
963 if (!res) break;
964 if (!name_r.empty())
965 {
966 res = (it->tag_name() == name_r);
967 }
968 ++it;
969 }
970 while (res && *it);
971 return res;
972}
973
975//
976//
977// METHOD NAME : RpmDb::whoOwnsFile
978// METHOD TYPE : std::string
979//
980// DESCRIPTION :
981//
982std::string RpmDb::whoOwnsFile( const std::string & file_r) const
983{
984 auto it = dbConstIterator();
985 if (it.findByFile( file_r ))
986 {
987 return it->tag_name();
988 }
989 return "";
990}
991
993//
994//
995// METHOD NAME : RpmDb::hasProvides
996// METHOD TYPE : bool
997//
998// DESCRIPTION :
999//
1000bool RpmDb::hasProvides( const std::string & tag_r ) const
1001{
1002 auto it = dbConstIterator();
1003 return it.findByProvides( tag_r );
1004}
1005
1007//
1008//
1009// METHOD NAME : RpmDb::hasRequiredBy
1010// METHOD TYPE : bool
1011//
1012// DESCRIPTION :
1013//
1014bool RpmDb::hasRequiredBy( const std::string & tag_r ) const
1015{
1016 auto it = dbConstIterator();
1017 return it.findByRequiredBy( tag_r );
1018}
1019
1021//
1022//
1023// METHOD NAME : RpmDb::hasConflicts
1024// METHOD TYPE : bool
1025//
1026// DESCRIPTION :
1027//
1028bool RpmDb::hasConflicts( const std::string & tag_r ) const
1029{
1030 auto it = dbConstIterator();
1031 return it.findByConflicts( tag_r );
1032}
1033
1035//
1036//
1037// METHOD NAME : RpmDb::hasPackage
1038// METHOD TYPE : bool
1039//
1040// DESCRIPTION :
1041//
1042bool RpmDb::hasPackage( const std::string & name_r ) const
1043{
1044 auto it = dbConstIterator();
1045 return it.findPackage( name_r );
1046}
1047
1049//
1050//
1051// METHOD NAME : RpmDb::hasPackage
1052// METHOD TYPE : bool
1053//
1054// DESCRIPTION :
1055//
1056bool RpmDb::hasPackage( const std::string & name_r, const Edition & ed_r ) const
1057{
1058 auto it = dbConstIterator();
1059 return it.findPackage( name_r, ed_r );
1060}
1061
1063//
1064//
1065// METHOD NAME : RpmDb::getData
1066// METHOD TYPE : PMError
1067//
1068// DESCRIPTION :
1069//
1070void RpmDb::getData( const std::string & name_r,
1071 RpmHeader::constPtr & result_r ) const
1072{
1073 auto it = dbConstIterator();
1074 it.findPackage( name_r );
1075 result_r = *it;
1076#if 0 // if this is needed we need to forcefully close the db of running db_const_iterators
1077 if (it.dbError())
1078 ZYPP_THROW(*(it.dbError()));
1079#endif
1080}
1081
1083//
1084//
1085// METHOD NAME : RpmDb::getData
1086// METHOD TYPE : void
1087//
1088// DESCRIPTION :
1089//
1090void RpmDb::getData( const std::string & name_r, const Edition & ed_r,
1091 RpmHeader::constPtr & result_r ) const
1092{
1093 auto it = dbConstIterator();
1094 it.findPackage( name_r, ed_r );
1095 result_r = *it;
1096#if 0 // if this is needed we need to forcefully close the db of running db_const_iterators
1097 if (it.dbError())
1098 ZYPP_THROW(*(it.dbError()));
1099#endif
1100}
1101
1103namespace
1104{
1105 struct RpmlogCapture : public std::vector<std::string>
1106 {
1107 RpmlogCapture()
1108 {
1109 rpmlogSetCallback( rpmLogCB, this );
1110 _oldMask = rpmlogSetMask( RPMLOG_UPTO( RPMLOG_PRI(RPMLOG_INFO) ) );
1111 }
1112
1113 RpmlogCapture(const RpmlogCapture &) = delete;
1114 RpmlogCapture(RpmlogCapture &&) = delete;
1115 RpmlogCapture &operator=(const RpmlogCapture &) = delete;
1116 RpmlogCapture &operator=(RpmlogCapture &&) = delete;
1117
1118 ~RpmlogCapture() {
1119 rpmlogSetCallback( nullptr, nullptr );
1120 rpmlogSetMask( _oldMask );
1121 }
1122
1123 static int rpmLogCB( rpmlogRec rec_r, rpmlogCallbackData data_r )
1124 { return reinterpret_cast<RpmlogCapture*>(data_r)->rpmLog( rec_r ); }
1125
1126 int rpmLog( rpmlogRec rec_r )
1127 {
1128 std::string l { ::rpmlogRecMessage( rec_r ) }; // NL terminated line!
1129 l.pop_back(); // strip trailing NL
1130 push_back( std::move(l) );
1131 return 0;
1132 }
1133
1134 private:
1135 int _oldMask = 0;
1136 };
1137
1138 std::ostream & operator<<( std::ostream & str, const RpmlogCapture & obj )
1139 {
1140 char sep = '\0';
1141 for ( const auto & l : obj ) {
1142 if ( sep ) str << sep; else sep = '\n';
1143 str << l;
1144 }
1145 return str;
1146 }
1147
1148
1149 RpmDb::CheckPackageResult doCheckPackageSig( const Pathname & path_r, // rpm file to check
1150 const Pathname & root_r, // target root
1151 bool requireGPGSig_r, // whether no gpg signature is to be reported
1152 RpmDb::CheckPackageDetail & detail_r ) // detailed result
1153 {
1154 PathInfo file( path_r );
1155 if ( ! file.isFile() )
1156 {
1157 ERR << "Not a file: " << file << endl;
1158 return RpmDb::CHK_ERROR;
1159 }
1160
1161 FD_t fd = ::Fopen( file.asString().c_str(), "r.ufdio" );
1162 if ( fd == 0 || ::Ferror(fd) )
1163 {
1164 ERR << "Can't open file for reading: " << file << " (" << ::Fstrerror(fd) << ")" << endl;
1165 if ( fd )
1166 ::Fclose( fd );
1167 return RpmDb::CHK_ERROR;
1168 }
1169 rpmts ts = ::rpmtsCreate();
1170 ::rpmtsSetRootDir( ts, root_r.c_str() );
1171 ::rpmtsSetVSFlags( ts, RPMVSF_DEFAULT );
1172#ifdef HAVE_RPM_VERIFY_TRANSACTION_STEP
1173 ::rpmtsSetVfyFlags( ts, RPMVSF_DEFAULT );
1174#endif
1175
1176 RpmlogCapture vresult;
1177 LocaleGuard guard( LC_ALL, "C" ); // bsc#1076415: rpm log output is localized, but we need to parse it :(
1178 static rpmQVKArguments_s qva = ([](){ rpmQVKArguments_s qva; memset( &qva, 0, sizeof(rpmQVKArguments_s) ); return qva; })();
1179 int res = ::rpmVerifySignatures( &qva, ts, fd, path_r.basename().c_str() );
1180 guard.restore();
1181
1182 ts = rpmtsFree(ts);
1183 ::Fclose( fd );
1184
1185 // Check the individual signature/disgest results:
1186
1187 // To.map back known result strings to enum, everything else is CHK_ERROR.
1188 typedef std::map<std::string_view,RpmDb::CheckPackageResult> ResultMap;
1189 static const ResultMap resultMap {
1190 { "OK", RpmDb::CHK_OK },
1191 { "NOKEY", RpmDb::CHK_NOKEY },
1192 { "BAD", RpmDb::CHK_FAIL },
1193 { "UNKNOWN", RpmDb::CHK_NOTFOUND },
1194 { "NOTRUSTED", RpmDb::CHK_NOTTRUSTED },
1195 { "NOTFOUND", RpmDb::CHK_NOTFOUND },
1196 };
1197 auto getresult = []( const ResultMap & resultMap, ResultMap::key_type key )->ResultMap::mapped_type {
1198 auto it = resultMap.find( key );
1199 return it != resultMap.end() ? it->second : RpmDb::CHK_ERROR;
1200 };
1201
1202 // To track the signature states we saw.
1203 unsigned count[7] = { 0, 0, 0, 0, 0, 0, 0 };
1204
1205 // To track the kind off sigs we saw.
1206 enum Saw {
1207 SawNone = 0,
1208 SawHeaderSig = (1 << 0), // Header V3 RSA/SHA256 Signature, key ID 3dbdc284: OK
1209 SawHeaderDigest = (1 << 1), // Header SHA1 digest: OK (a60386347863affefef484ff1f26c889373eb094)
1210 SawPayloadDigest = (1 << 2), // Payload SHA256 digest: OK
1211 SawSig = (1 << 3), // V3 RSA/SHA256 Signature, key ID 3dbdc284: OK
1212 SawDigest = (1 << 4), // MD5 digest: OK (fd5259fe677a406951dcb2e9d08c4dcc)
1213 };
1214 unsigned saw = SawNone;
1215
1216 static const str::regex rx( "^ *(Header|Payload)? .*(Signature, key|digest).*: ([A-Z]+)" );
1217 str::smatch what;
1218 for ( const std::string & line : vresult )
1219 {
1220 if ( line[0] != ' ' ) // result lines are indented
1221 continue;
1222
1224 if ( str::regex_match( line, what, rx ) ) {
1225
1226 lineres = getresult( resultMap, what[3] );
1227 if ( lineres == RpmDb::CHK_NOTFOUND )
1228 continue; // just collect details for signatures found (#229)
1229
1230 if ( what[1][0] == 'H' ) {
1231 saw |= ( what[2][0] == 'S' ? SawHeaderSig :SawHeaderDigest );
1232 }
1233 else if ( what[1][0] == 'P' ) {
1234 if ( what[2][0] == 'd' ) saw |= SawPayloadDigest;
1235 }
1236 else {
1237 saw |= ( what[2][0] == 'S' ? SawSig : SawDigest );
1238 }
1239 }
1240
1241 ++count[lineres];
1242 detail_r.push_back( RpmDb::CheckPackageDetail::value_type( lineres, line ) );
1243 }
1244
1245 // Now combine the overall result:
1247
1248 if ( count[RpmDb::CHK_FAIL] )
1249 ret = RpmDb::CHK_FAIL;
1250
1251 else if ( count[RpmDb::CHK_NOTFOUND] )
1252 ret = RpmDb::CHK_NOTFOUND;
1253
1254 else if ( count[RpmDb::CHK_NOKEY] )
1255 ret = RpmDb::CHK_NOKEY;
1256
1257 else if ( count[RpmDb::CHK_NOTTRUSTED] )
1259
1260 else if ( ret == RpmDb::CHK_OK ) {
1261 // Everything is OK, so check whether it's sufficient.
1262 // bsc#1184501: To count as signed the package needs a header signature
1263 // and either a payload digest (secured by the header sig) or a content signature.
1264 bool isSigned = (saw & SawHeaderSig) && ( (saw & SawPayloadDigest) || (saw & SawSig) );
1265 if ( not isSigned ) {
1266 std::string message { " " };
1267 if ( not (saw & SawHeaderSig) )
1268 message += _("Package header is not signed!");
1269 else
1270 message += _("Package payload is not signed!");
1271
1272 detail_r.push_back( RpmDb::CheckPackageDetail::value_type( RpmDb::CHK_NOSIG, std::move(message) ) );
1273 if ( requireGPGSig_r )
1274 ret = RpmDb::CHK_NOSIG;
1275 }
1276 }
1277
1278 if ( ret != RpmDb::CHK_OK )
1279 {
1280 // In case of an error line results may be reported to the user. In case rpm printed
1281 // only 8byte key IDs to stdout we try to get longer IDs from the header.
1282 bool didReadHeader = false;
1283 std::unordered_map< std::string, std::string> fprs;
1284
1285 // we replace the data only if the key IDs are actually only 8 bytes
1286 str::regex rxexpr( "key ID ([a-fA-F0-9]{8}):" );
1287 for ( auto &detail : detail_r ) {
1288 auto &line = detail.second;
1289 str::smatch what;
1290 if ( str::regex_match( line, what, rxexpr ) ) {
1291
1292 if ( !didReadHeader ) {
1293 didReadHeader = true;
1294
1295 // Get signature info from the package header, RPM always prints only the 8 byte ID
1296 auto header = RpmHeader::readPackage( path_r, RpmHeader::NOVERIFY );
1297 if ( header ) {
1299 const auto &addFprs = [&]( auto tag ){
1300 const auto &list1 = keyMgr.readSignatureFingerprints( header->blob_val( tag ) );
1301 for ( const auto &id : list1 ) {
1302 if ( id.size() <= 8 )
1303 continue;
1304
1305 const auto &lowerId = str::toLower( id );
1306 fprs.insert( std::make_pair( lowerId.substr( lowerId.size() - 8 ), lowerId ) );
1307 }
1308 };
1309
1310 addFprs( RPMTAG_SIGGPG );
1311 addFprs( RPMTAG_SIGPGP );
1312 addFprs( RPMTAG_RSAHEADER );
1313 addFprs( RPMTAG_DSAHEADER );
1314
1315 } else {
1316 ERR << "Failed to read package signatures." << std::endl;
1317 }
1318 }
1319
1320 // if we have no keys we can substitute we can leave the loop right away
1321 if ( !fprs.size() )
1322 break;
1323
1324 {
1325 // replace the short key ID with the long ones parsed from the header
1326 const auto &keyId = str::toLower( what[1] );
1327 if ( const auto &i = fprs.find( keyId ); i != fprs.end() ) {
1328 str::replaceAll( line, keyId, i->second );
1329 }
1330 }
1331 }
1332 }
1333
1334 WAR << path_r << " (" << requireGPGSig_r << " -> " << ret << ")" << endl;
1335 WAR << vresult << endl;
1336 }
1337 else
1338 DBG << path_r << " [0-Signature is OK]" << endl;
1339 return ret;
1340 }
1341
1342} // namespace
1344//
1345// METHOD NAME : RpmDb::checkPackage
1346// METHOD TYPE : RpmDb::CheckPackageResult
1347//
1349{ return doCheckPackageSig( path_r, root(), false/*requireGPGSig_r*/, detail_r ); }
1350
1352{ CheckPackageDetail dummy; return checkPackage( path_r, dummy ); }
1353
1355{ return doCheckPackageSig( path_r, root(), true/*requireGPGSig_r*/, detail_r ); }
1356
1357
1358// determine changed files of installed package
1359bool
1360RpmDb::queryChangedFiles(FileList & fileList, const std::string& packageName)
1361{
1362 bool ok = true;
1363
1364 fileList.clear();
1365
1366 if ( ! initialized() ) return false;
1367
1368 RpmArgVec opts;
1369
1370 opts.push_back ("-V");
1371 opts.push_back ("--nodeps");
1372 opts.push_back ("--noscripts");
1373 opts.push_back ("--nomd5");
1374 opts.push_back ("--");
1375 opts.push_back (packageName.c_str());
1376
1378
1379 if ( process == NULL )
1380 return false;
1381
1382 /* from rpm manpage
1383 5 MD5 sum
1384 S File size
1385 L Symlink
1386 T Mtime
1387 D Device
1388 U User
1389 G Group
1390 M Mode (includes permissions and file type)
1391 */
1392
1393 std::string line;
1394 while (systemReadLine(line))
1395 {
1396 if (line.length() > 12 &&
1397 (line[0] == 'S' || line[0] == 's' ||
1398 (line[0] == '.' && line[7] == 'T')))
1399 {
1400 // file has been changed
1401 std::string filename;
1402
1403 filename.assign(line, 11, line.length() - 11);
1404 fileList.insert(filename);
1405 }
1406 }
1407
1408 systemStatus();
1409 // exit code ignored, rpm returns 1 no matter if package is installed or
1410 // not
1411
1412 return ok;
1413}
1414
1415
1416/****************************************************************/
1417/* private member-functions */
1418/****************************************************************/
1419
1420/*--------------------------------------------------------------*/
1421/* Run rpm with the specified arguments, handling stderr */
1422/* as specified by disp */
1423/*--------------------------------------------------------------*/
1424void
1427{
1428 if ( process )
1429 {
1430 delete process;
1431 process = NULL;
1432 }
1433 exit_code = -1;
1434
1435 if ( ! initialized() )
1436 {
1438 }
1439
1440 RpmArgVec args;
1441
1442 // always set root and dbpath
1443#if defined(WORKAROUNDRPMPWDBUG)
1444 args.push_back("#/"); // chdir to / to workaround bnc#819354
1445#endif
1446 args.push_back("rpm");
1447 args.push_back("--root");
1448 args.push_back(_root.asString().c_str());
1449 args.push_back("--dbpath");
1450 args.push_back(_dbPath.asString().c_str());
1451 if ( env::ZYPP_RPM_DEBUG() )
1452 args.push_back("-vv");
1453 const char* argv[args.size() + opts.size() + 1];
1454
1455 const char** p = argv;
1456 p = copy (args.begin (), args.end (), p);
1457 p = copy (opts.begin (), opts.end (), p);
1458 *p = 0;
1459
1460#if 0 // if this is needed we need to forcefully close the db of running db_const_iterators
1461 // Invalidate all outstanding database handles in case
1462 // the database gets modified.
1463 librpmDb::dbRelease( true );
1464#endif
1465
1466 // Launch the program with default locale
1467 process = new ExternalProgram(argv, disp, false, -1, true);
1468 return;
1469}
1470
1471/*--------------------------------------------------------------*/
1472/* Read a line from the rpm process */
1473/*--------------------------------------------------------------*/
1474bool RpmDb::systemReadLine( std::string & line )
1475{
1476 line.erase();
1477
1478 if ( process == NULL )
1479 return false;
1480
1481 if ( process->inputFile() )
1482 {
1483 process->setBlocking( false );
1484 FILE * inputfile = process->inputFile();
1485 do {
1486 // Check every 5 seconds if the process is still running to prevent against
1487 // daemons launched in rpm %post that do not close their filedescriptors,
1488 // causing us to block for infinity. (bnc#174548)
1489 const auto &readResult = io::receiveUpto( inputfile, '\n', 5 * 1000, false );
1490 switch ( readResult.first ) {
1492 if ( !process->running() )
1493 return false;
1494
1495 // we might have received a partial line, lets not forget about it
1496 line += readResult.second;
1497 break;
1498 }
1501 line += readResult.second;
1502 if ( line.size() && line.back() == '\n')
1503 line.pop_back();
1504 return line.size(); // in case of pending output
1505 }
1507 line += readResult.second;
1508
1509 if ( line.size() && line.back() == '\n')
1510 line.pop_back();
1511
1512 if ( env::ZYPP_RPM_DEBUG() )
1513 L_DBG("RPM_DEBUG") << line << endl;
1514 return true; // complete line
1515 }
1516 }
1517 } while( true );
1518 }
1519 return false;
1520}
1521
1522/*--------------------------------------------------------------*/
1523/* Return the exit status of the rpm process, closing the */
1524/* connection if not already done */
1525/*--------------------------------------------------------------*/
1526int
1528{
1529 if ( process == NULL )
1530 return -1;
1531
1532 exit_code = process->close();
1533 if (exit_code == 0)
1534 error_message = "";
1535 else
1537 process->kill();
1538 delete process;
1539 process = 0;
1540
1541 // DBG << "exit code " << exit_code << endl;
1542
1543 return exit_code;
1544}
1545
1546/*--------------------------------------------------------------*/
1547/* Forcably kill the rpm process */
1548/*--------------------------------------------------------------*/
1549void
1551{
1552 if (process) process->kill();
1553}
1554
1555
1556// generate diff mails for config files
1557void RpmDb::processConfigFiles(const std::string& line, const std::string& name, const char* typemsg, const char* difffailmsg, const char* diffgenmsg)
1558{
1559 std::string msg = line.substr(9);
1560 std::string::size_type pos1 = std::string::npos;
1561 std::string::size_type pos2 = std::string::npos;
1562 std::string file1s, file2s;
1563 Pathname file1;
1564 Pathname file2;
1565
1566 pos1 = msg.find (typemsg);
1567 for (;;)
1568 {
1569 if ( pos1 == std::string::npos )
1570 break;
1571
1572 pos2 = pos1 + strlen (typemsg);
1573
1574 if (pos2 >= msg.length() )
1575 break;
1576
1577 file1 = msg.substr (0, pos1);
1578 file2 = msg.substr (pos2);
1579
1580 file1s = file1.asString();
1581 file2s = file2.asString();
1582
1583 if (!_root.empty() && _root != "/")
1584 {
1585 file1 = _root + file1;
1586 file2 = _root + file2;
1587 }
1588
1589 std::string out;
1590 int ret = diffFiles (file1.asString(), file2.asString(), out, 25);
1591 if (ret)
1592 {
1594 if (filesystem::assert_dir(file) != 0)
1595 {
1596 ERR << "Could not create " << file.asString() << endl;
1597 break;
1598 }
1599 file += Date(Date::now()).form("config_diff_%Y_%m_%d.log");
1600 std::ofstream notify(file.asString().c_str(), std::ios::out|std::ios::app);
1601 if (!notify)
1602 {
1603 ERR << "Could not open " << file << endl;
1604 break;
1605 }
1606
1607 // Translator: %s = name of an rpm package. A list of diffs follows
1608 // this message.
1609 notify << str::form(_("Changed configuration files for %s:"), name.c_str()) << endl;
1610 if (ret>1)
1611 {
1612 ERR << "diff failed" << endl;
1613 notify << str::form(difffailmsg,
1614 file1s.c_str(), file2s.c_str()) << endl;
1615 }
1616 else
1617 {
1618 notify << str::form(diffgenmsg,
1619 file1s.c_str(), file2s.c_str()) << endl;
1620
1621 // remove root for the viewer's pleasure (#38240)
1622 if (!_root.empty() && _root != "/")
1623 {
1624 if (out.substr(0,4) == "--- ")
1625 {
1626 out.replace(4, file1.asString().length(), file1s);
1627 }
1628 std::string::size_type pos = out.find("\n+++ ");
1629 if (pos != std::string::npos)
1630 {
1631 out.replace(pos+5, file2.asString().length(), file2s);
1632 }
1633 }
1634 notify << out << endl;
1635 }
1636 notify.close();
1637 notify.open("/var/lib/update-messages/yast2-packagemanager.rpmdb.configfiles");
1638 notify.close();
1639 }
1640 else
1641 {
1642 WAR << "rpm created " << file2 << " but it is not different from " << file2 << endl;
1643 }
1644 break;
1645 }
1646}
1647
1649//
1650// METHOD NAME : RpmDb::installPackage
1651//
1652void RpmDb::installPackage( const Pathname & filename, RpmInstFlags flags )
1653{ installPackage( filename, flags, nullptr ); }
1654
1655void RpmDb::installPackage( const Pathname & filename, RpmInstFlags flags, RpmPostTransCollector* postTransCollector_r )
1656{
1657 if ( postTransCollector_r && postTransCollector_r->hasPosttransScript( filename ) )
1658 flags |= rpm::RPMINST_NOPOSTTRANS; // Just set the flag here. In \ref doInstallPackage we collect what else is needed.
1659
1661
1662 report->start(filename);
1663
1664 do
1665 try
1666 {
1667 doInstallPackage( filename, flags, postTransCollector_r, report );
1668 report->finish();
1669 break;
1670 }
1671 catch (RpmException & excpt_r)
1672 {
1673 RpmInstallReport::Action user = report->problem( excpt_r );
1674
1675 if ( user == RpmInstallReport::ABORT )
1676 {
1677 report->finish( excpt_r );
1678 ZYPP_RETHROW(excpt_r);
1679 }
1680 else if ( user == RpmInstallReport::IGNORE )
1681 {
1682 break;
1683 }
1684 }
1685 while (true);
1686}
1687
1688void RpmDb::doInstallPackage( const Pathname & filename, RpmInstFlags flags, RpmPostTransCollector* postTransCollector_r, callback::SendReport<RpmInstallReport> & report )
1689{
1691 HistoryLog historylog;
1692
1693 MIL << "RpmDb::installPackage(" << filename << "," << flags << ")" << endl;
1694
1695 // backup
1696 if ( _packagebackups )
1697 {
1698 // FIXME report->progress( pd.init( -2, 100 ) ); // allow 1% for backup creation.
1699 if ( ! backupPackage( filename ) )
1700 {
1701 ERR << "backup of " << filename.asString() << " failed" << endl;
1702 }
1703 // FIXME status handling
1704 report->progress( 0 ); // allow 1% for backup creation.
1705 }
1706
1707 // run rpm
1708 RpmArgVec opts;
1709 if ( postTransCollector_r && ( _root == "/" || not workaroundDUMPPOSTTRANS_BUG_1216091() ) ) {
1710 opts.push_back("--define"); // bsc#1041742: Attempt to delay %transfiletrigger(postun|in) execution iff rpm supports it.
1711 opts.push_back("_dump_posttrans 1"); // Old rpm ignores the --define, new rpm injects 'dump_posttrans:' lines to collect and execute later.
1712 }
1713 if (flags & RPMINST_NOUPGRADE)
1714 opts.push_back("-i");
1715 else
1716 opts.push_back("-U");
1717
1718 opts.push_back("--percent");
1719 opts.push_back("--noglob");
1720
1721 // ZConfig defines cross-arch installation
1722 if ( ! ZConfig::instance().systemArchitecture().compatibleWith( ZConfig::instance().defaultSystemArchitecture() ) )
1723 opts.push_back("--ignorearch");
1724
1725 if (flags & RPMINST_NODIGEST)
1726 opts.push_back("--nodigest");
1727 if (flags & RPMINST_NOSIGNATURE)
1728 opts.push_back("--nosignature");
1729 if (flags & RPMINST_EXCLUDEDOCS)
1730 opts.push_back ("--excludedocs");
1731 if (flags & RPMINST_NOSCRIPTS)
1732 opts.push_back ("--noscripts");
1733 if (flags & RPMINST_FORCE)
1734 opts.push_back ("--force");
1735 if (flags & RPMINST_NODEPS)
1736 opts.push_back ("--nodeps");
1737 if (flags & RPMINST_IGNORESIZE)
1738 opts.push_back ("--ignoresize");
1739 if (flags & RPMINST_JUSTDB)
1740 opts.push_back ("--justdb");
1741 if (flags & RPMINST_TEST)
1742 opts.push_back ("--test");
1743 if (flags & RPMINST_NOPOSTTRANS)
1744 opts.push_back ("--noposttrans");
1745
1746 opts.push_back("--");
1747
1748 // rpm requires additional quoting of special chars:
1749 std::string quotedFilename( rpmQuoteFilename( workaroundRpmPwdBug( filename ) ) );
1750 opts.push_back ( quotedFilename.c_str() );
1752
1753 // forward additional rpm output via report;
1754 std::string line;
1755 unsigned lineno = 0;
1756 callback::UserData cmdout( InstallResolvableReport::contentRpmout );
1757 // Key "solvable" injected by RpmInstallPackageReceiver
1758 cmdout.set( "line", std::cref(line) );
1759 cmdout.set( "lineno", lineno );
1760
1761 // LEGACY: collect and forward additional rpm output in finish
1762 std::string rpmmsg;
1763 std::vector<std::string> configwarnings; // TODO: immediately process lines rather than collecting
1764 std::vector<std::string> runposttrans; // bsc#1041742: If rpm supports --runposttrans it injects 'dump_posttrans:' lines we do collect
1765
1766 while ( systemReadLine( line ) )
1767 {
1768 if ( str::startsWith( line, "%%" ) )
1769 {
1770 int percent = 0;
1771 sscanf( line.c_str() + 2, "%d", &percent );
1772 report->progress( percent );
1773 continue;
1774 }
1775 if ( str::hasPrefix( line, "dump_posttrans:" ) ) {
1776 runposttrans.push_back( line );
1777 continue;
1778 }
1779 ++lineno;
1780 cmdout.set( "lineno", lineno );
1781 report->report( cmdout );
1782
1783 if ( lineno >= MAXRPMMESSAGELINES ) {
1784 if ( line.find( " scriptlet failed, " ) == std::string::npos ) // always log %script errors
1785 continue;
1786 }
1787
1788 rpmmsg += line+'\n';
1789
1790 if ( str::startsWith( line, "warning:" ) )
1791 configwarnings.push_back(line);
1792 }
1793 if ( lineno >= MAXRPMMESSAGELINES )
1794 rpmmsg += "[truncated]\n";
1795
1796 int rpm_status = systemStatus();
1797 if ( postTransCollector_r && rpm_status == 0 ) {
1798 // Before doing anything else, handle any pending %posttrans script or dump_posttrans lines.
1799 postTransCollector_r->collectPosttransInfo( filename, runposttrans );
1800 }
1801
1802 // evaluate result
1803 for (std::vector<std::string>::iterator it = configwarnings.begin();
1804 it != configwarnings.end(); ++it)
1805 {
1806 processConfigFiles(*it, Pathname::basename(filename), " saved as ",
1807 // %s = filenames
1808 _("rpm saved %s as %s, but it was impossible to determine the difference"),
1809 // %s = filenames
1810 _("rpm saved %s as %s.\nHere are the first 25 lines of difference:\n"));
1811 processConfigFiles(*it, Pathname::basename(filename), " created as ",
1812 // %s = filenames
1813 _("rpm created %s as %s, but it was impossible to determine the difference"),
1814 // %s = filenames
1815 _("rpm created %s as %s.\nHere are the first 25 lines of difference:\n"));
1816 }
1817
1818 if ( rpm_status != 0 )
1819 {
1820 historylog.comment(
1821 str::form("%s install failed", Pathname::basename(filename).c_str()),
1822 true /*timestamp*/);
1823 std::ostringstream sstr;
1824 sstr << "rpm output:" << endl << rpmmsg << endl;
1825 historylog.comment(sstr.str());
1826 // TranslatorExplanation the colon is followed by an error message
1827 auto excpt { RpmSubprocessException(_("RPM failed: ") + error_message ) };
1828 if ( not rpmmsg.empty() )
1829 excpt.addHistory( rpmmsg );
1830 ZYPP_THROW(excpt);
1831 }
1832 else if ( ! rpmmsg.empty() )
1833 {
1834 historylog.comment(
1835 str::form("%s installed ok", Pathname::basename(filename).c_str()),
1836 true /*timestamp*/);
1837 std::ostringstream sstr;
1838 sstr << "Additional rpm output:" << endl << rpmmsg << endl;
1839 historylog.comment(sstr.str());
1840
1841 // report additional rpm output in finish (LEGACY! Lines are immediately reported as InstallResolvableReport::contentRpmout)
1842 // TranslatorExplanation Text is followed by a ':' and the actual output.
1843 report->finishInfo(str::form( "%s:\n%s\n", _("Additional rpm output"), rpmmsg.c_str() ));
1844 }
1845}
1846
1848//
1849// METHOD NAME : RpmDb::removePackage
1850//
1851void RpmDb::removePackage( Package::constPtr package, RpmInstFlags flags )
1852{ removePackage( std::move(package), flags, nullptr ); }
1853
1854void RpmDb::removePackage( const std::string & name_r, RpmInstFlags flags )
1855{ removePackage( name_r, flags, nullptr ); }
1856
1857void RpmDb::removePackage( const Package::constPtr& package, RpmInstFlags flags, RpmPostTransCollector* postTransCollector_r )
1858{ // 'rpm -e' does not like epochs
1859 removePackage( package->name()
1860 + "-" + package->edition().version()
1861 + "-" + package->edition().release()
1862 + "." + package->arch().asString(), flags, postTransCollector_r );
1863}
1864
1865void RpmDb::removePackage( const std::string & name_r, RpmInstFlags flags, RpmPostTransCollector* postTransCollector_r )
1866{
1868
1869 report->start( name_r );
1870
1871 do
1872 try
1873 {
1874 doRemovePackage( name_r, flags, postTransCollector_r, report );
1875 report->finish();
1876 break;
1877 }
1878 catch (RpmException & excpt_r)
1879 {
1880 RpmRemoveReport::Action user = report->problem( excpt_r );
1881
1882 if ( user == RpmRemoveReport::ABORT )
1883 {
1884 report->finish( excpt_r );
1885 ZYPP_RETHROW(excpt_r);
1886 }
1887 else if ( user == RpmRemoveReport::IGNORE )
1888 {
1889 break;
1890 }
1891 }
1892 while (true);
1893}
1894
1895void RpmDb::doRemovePackage( const std::string & name_r, RpmInstFlags flags, RpmPostTransCollector* postTransCollector_r, callback::SendReport<RpmRemoveReport> & report )
1896{
1898 HistoryLog historylog;
1899
1900 MIL << "RpmDb::doRemovePackage(" << name_r << "," << flags << ")" << endl;
1901
1902 // backup
1903 if ( _packagebackups )
1904 {
1905 // FIXME solve this status report somehow
1906 // report->progress( pd.init( -2, 100 ) ); // allow 1% for backup creation.
1907 if ( ! backupPackage( name_r ) )
1908 {
1909 ERR << "backup of " << name_r << " failed" << endl;
1910 }
1911 report->progress( 0 );
1912 }
1913 else
1914 {
1915 report->progress( 100 );
1916 }
1917
1918 // run rpm
1919 RpmArgVec opts;
1920 if ( postTransCollector_r && ( _root == "/" || not workaroundDUMPPOSTTRANS_BUG_1216091() ) ) {
1921 opts.push_back("--define"); // bsc#1041742: Attempt to delay %transfiletrigger(postun|in) execution iff rpm supports it.
1922 opts.push_back("_dump_posttrans 1"); // Old rpm ignores the --define, new rpm injects 'dump_posttrans:' lines to collect and execute later.
1923 }
1924 opts.push_back("-e");
1925 opts.push_back("--allmatches");
1926
1927 if (flags & RPMINST_NOSCRIPTS)
1928 opts.push_back("--noscripts");
1929 if (flags & RPMINST_NODEPS)
1930 opts.push_back("--nodeps");
1931 if (flags & RPMINST_JUSTDB)
1932 opts.push_back("--justdb");
1933 if (flags & RPMINST_TEST)
1934 opts.push_back ("--test");
1935 if (flags & RPMINST_FORCE)
1936 {
1937 WAR << "IGNORE OPTION: 'rpm -e' does not support '--force'" << endl;
1938 }
1939
1940 opts.push_back("--");
1941 opts.push_back(name_r.c_str());
1943
1944 // forward additional rpm output via report;
1945 std::string line;
1946 unsigned lineno = 0;
1947 callback::UserData cmdout( RemoveResolvableReport::contentRpmout );
1948 // Key "solvable" injected by RpmInstallPackageReceiver
1949 cmdout.set( "line", std::cref(line) );
1950 cmdout.set( "lineno", lineno );
1951
1952
1953 // LEGACY: collect and forward additional rpm output in finish
1954 std::string rpmmsg;
1955 std::vector<std::string> runposttrans; // bsc#1041742: If rpm supports --runposttrans it injects 'dump_posttrans:' lines we do collect
1956
1957 // got no progress from command, so we fake it:
1958 // 5 - command started
1959 // 50 - command completed
1960 // 100 if no error
1961 report->progress( 5 );
1962 while (systemReadLine(line))
1963 {
1964 if ( str::hasPrefix( line, "dump_posttrans:" ) ) {
1965 runposttrans.push_back( line );
1966 continue;
1967 }
1968 ++lineno;
1969 cmdout.set( "lineno", lineno );
1970 report->report( cmdout );
1971
1972 if ( lineno >= MAXRPMMESSAGELINES ) {
1973 if ( line.find( " scriptlet failed, " ) == std::string::npos ) // always log %script errors
1974 continue;
1975 }
1976 rpmmsg += line+'\n';
1977 }
1978 if ( lineno >= MAXRPMMESSAGELINES )
1979 rpmmsg += "[truncated]\n";
1980 report->progress( 50 );
1981 int rpm_status = systemStatus();
1982 if ( postTransCollector_r && rpm_status == 0 ) {
1983 // Before doing anything else, handle any pending %posttrans script or dump_posttrans lines.
1984 // 'remove' does not trigger %posttrans, but it may trigger %transfiletriggers.
1985 postTransCollector_r->collectPosttransInfo( runposttrans );
1986 }
1987
1988 if ( rpm_status != 0 )
1989 {
1990 historylog.comment(
1991 str::form("%s remove failed", name_r.c_str()), true /*timestamp*/);
1992 std::ostringstream sstr;
1993 sstr << "rpm output:" << endl << rpmmsg << endl;
1994 historylog.comment(sstr.str());
1995 // TranslatorExplanation the colon is followed by an error message
1996 auto excpt { RpmSubprocessException(_("RPM failed: ") + error_message ) };
1997 if ( not rpmmsg.empty() )
1998 excpt.addHistory( rpmmsg );
1999 ZYPP_THROW(excpt);
2000 }
2001 else if ( ! rpmmsg.empty() )
2002 {
2003 historylog.comment(
2004 str::form("%s removed ok", name_r.c_str()), true /*timestamp*/);
2005
2006 std::ostringstream sstr;
2007 sstr << "Additional rpm output:" << endl << rpmmsg << endl;
2008 historylog.comment(sstr.str());
2009
2010 // report additional rpm output in finish (LEGACY! Lines are immediately reported as RemoveResolvableReport::contentRpmout)
2011 // TranslatorExplanation Text is followed by a ':' and the actual output.
2012 report->finishInfo(str::form( "%s:\n%s\n", _("Additional rpm output"), rpmmsg.c_str() ));
2013 }
2014}
2015
2017//
2018// METHOD NAME : RpmDb::runposttrans
2019//
2020int RpmDb::runposttrans( const Pathname & filename_r, const std::function<void(const std::string&)>& output_r )
2021{
2023 HistoryLog historylog;
2024
2025 MIL << "RpmDb::runposttrans(" << filename_r << ")" << endl;
2026
2027 RpmArgVec opts;
2028#if 1
2029 // Bug 1218459 rpm scriptlets left over after snapshot updates
2030 // Until 'rpm --runposttrans' is fixed to properly indicate script
2031 // execution without -vv we redirect rpm's tmpdir. This will wipe
2032 // the rpm-tmp.* files 'rpm -vv' otherwise leaves in /var/tmp.
2033 std::string _tmppath { "_tmppath " + Pathname::stripprefix( _root, filename_r.dirname() ).asString() };
2034 opts.push_back("--define");
2035 opts.push_back(_tmppath.c_str());
2036#endif
2037 opts.push_back("-vv"); // want vverbose output to see scriptlet execution in the log
2038 opts.push_back("--runposttrans");
2039 opts.push_back(filename_r.c_str());
2041
2042 // Tailored to suit RpmPostTransCollector.
2043 // It's a pity, but we need all those verbose debug lines just
2044 // to figure out which script is currently executed. Otherwise we
2045 // can't tell which output belongs to which script.
2046 static const str::regex rx( "^D: (%.*): (scriptlet start|running .* scriptlet)" );
2047 static const str::regex rx2( "^Running (%[^)]*[)])$" );
2048 str::smatch what;
2049 std::string line;
2050 bool silent = true; // discard everything before 1st scriptlet
2051 while ( systemReadLine(line) )
2052 {
2053 if ( not output_r )
2054 continue;
2055
2056 if ( str::startsWith( line, "D:" ) ) { // rpm debug output
2057 if ( str::regex_match( line, what, rx ) ) {
2058 // forward ripoff header
2059 DBG << "Verbose RIPOFF:"+what[1] << endl;
2060 output_r( "RIPOFF:"+what[1] );
2061 if ( silent )
2062 silent = false;
2063 }
2064 continue;
2065 }
2066 if ( str::regex_match( line, what, rx2 ) ) { // preliminary for 1218459, but rpm needs fixing
2067 // forward ripoff header
2068 DBG << "NonVerbose RIPOFF:"+what[1] << endl;
2069 // output_r( "RIPOFF:"+what[1] );
2070 // if ( silent )
2071 // silent = false;
2072 continue;
2073 }
2074 if ( silent ) {
2075 continue;
2076 }
2077 if ( str::startsWith( line, "+ " ) ) { // shell -x debug output
2078 continue;
2079 }
2080 // forward output line
2081 output_r( line );
2082 }
2083
2084 int rpm_status = systemStatus();
2085 if ( rpm_status != 0 ) {
2086 WAR << "rpm --runposttrans returned " << rpm_status << endl;
2087 }
2088 return rpm_status;
2089}
2090
2092//
2093//
2094// METHOD NAME : RpmDb::backupPackage
2095// METHOD TYPE : bool
2096//
2097bool RpmDb::backupPackage( const Pathname & filename )
2098{
2100 if ( ! h )
2101 return false;
2102
2103 return backupPackage( h->tag_name() );
2104}
2105
2107//
2108//
2109// METHOD NAME : RpmDb::backupPackage
2110// METHOD TYPE : bool
2111//
2112bool RpmDb::backupPackage(const std::string& packageName)
2113{
2114 HistoryLog progresslog;
2115 bool ret = true;
2116 Pathname backupFilename;
2117 Pathname filestobackupfile = _root+_backuppath+FILEFORBACKUPFILES;
2118
2119 if (_backuppath.empty())
2120 {
2121 INT << "_backuppath empty" << endl;
2122 return false;
2123 }
2124
2126
2127 if (!queryChangedFiles(fileList, packageName))
2128 {
2129 ERR << "Error while getting changed files for package " <<
2130 packageName << endl;
2131 return false;
2132 }
2133
2134 if (fileList.size() <= 0)
2135 {
2136 DBG << "package " << packageName << " not changed -> no backup" << endl;
2137 return true;
2138 }
2139
2141 {
2142 return false;
2143 }
2144
2145 {
2146 // build up archive name
2147 time_t currentTime = time(0);
2148 struct tm *currentLocalTime = localtime(&currentTime);
2149
2150 int date = (currentLocalTime->tm_year + 1900) * 10000
2151 + (currentLocalTime->tm_mon + 1) * 100
2152 + currentLocalTime->tm_mday;
2153
2154 int num = 0;
2155 do
2156 {
2157 backupFilename = _root + _backuppath
2158 + str::form("%s-%d-%d.tar.gz",packageName.c_str(), date, num);
2159
2160 }
2161 while ( PathInfo(backupFilename).isExist() && num++ < 1000);
2162
2163 PathInfo pi(filestobackupfile);
2164 if (pi.isExist() && !pi.isFile())
2165 {
2166 ERR << filestobackupfile.asString() << " already exists and is no file" << endl;
2167 return false;
2168 }
2169
2170 std::ofstream fp ( filestobackupfile.asString().c_str(), std::ios::out|std::ios::trunc );
2171
2172 if (!fp)
2173 {
2174 ERR << "could not open " << filestobackupfile.asString() << endl;
2175 return false;
2176 }
2177
2178 for (FileList::const_iterator cit = fileList.begin();
2179 cit != fileList.end(); ++cit)
2180 {
2181 std::string name = *cit;
2182 if ( name[0] == '/' )
2183 {
2184 // remove slash, file must be relative to -C parameter of tar
2185 name = name.substr( 1 );
2186 }
2187 DBG << "saving file "<< name << endl;
2188 fp << name << endl;
2189 }
2190 fp.close();
2191
2192 const char* const argv[] =
2193 {
2194 "tar",
2195 "-czhP",
2196 "-C",
2197 _root.asString().c_str(),
2198 "--ignore-failed-read",
2199 "-f",
2200 backupFilename.asString().c_str(),
2201 "-T",
2202 filestobackupfile.asString().c_str(),
2203 NULL
2204 };
2205
2206 // execute tar in inst-sys (we dont know if there is a tar below _root !)
2207 ExternalProgram tar(argv, ExternalProgram::Stderr_To_Stdout, false, -1, true);
2208
2209 std::string tarmsg;
2210
2211 // TODO: it is probably possible to start tar with -v and watch it adding
2212 // files to report progress
2213 for (std::string output = tar.receiveLine(); output.length() ;output = tar.receiveLine())
2214 {
2215 tarmsg+=output;
2216 }
2217
2218 int ret = tar.close();
2219
2220 if ( ret != 0)
2221 {
2222 ERR << "tar failed: " << tarmsg << endl;
2223 ret = false;
2224 }
2225 else
2226 {
2227 MIL << "tar backup ok" << endl;
2228 progresslog.comment(
2229 str::form(_("created backup %s"), backupFilename.asString().c_str())
2230 , /*timestamp*/true);
2231 }
2232
2233 filesystem::unlink(filestobackupfile);
2234 }
2235
2236 return ret;
2237}
2238
2240{
2241 _backuppath = path;
2242}
2243
2244std::ostream & operator<<( std::ostream & str, RpmDb::CheckPackageResult obj )
2245{
2246 switch ( obj )
2247 {
2248#define OUTS(E,S) case RpmDb::E: return str << "["<< (unsigned)obj << "-"<< S << "]"; break
2249 // translators: possible rpm package signature check result [brief]
2250 OUTS( CHK_OK, _("Signature is OK") );
2251 // translators: possible rpm package signature check result [brief]
2252 OUTS( CHK_NOTFOUND, _("Unknown type of signature") );
2253 // translators: possible rpm package signature check result [brief]
2254 OUTS( CHK_FAIL, _("Signature does not verify") );
2255 // translators: possible rpm package signature check result [brief]
2256 OUTS( CHK_NOTTRUSTED, _("Signature is OK, but key is not trusted") );
2257 // translators: possible rpm package signature check result [brief]
2258 OUTS( CHK_NOKEY, _("Signatures public key is not available") );
2259 // translators: possible rpm package signature check result [brief]
2260 OUTS( CHK_ERROR, _("File does not exist or signature can't be checked") );
2261 // translators: possible rpm package signature check result [brief]
2262 OUTS( CHK_NOSIG, _("File is unsigned") );
2263#undef OUTS
2264 }
2265 return str << "UnknowSignatureCheckError("+str::numstring(obj)+")";
2266}
2267
2268std::ostream & operator<<( std::ostream & str, const RpmDb::CheckPackageDetail & obj )
2269{
2270 for ( const auto & el : obj )
2271 str << el.second << endl;
2272 return str;
2273}
2274
2275} // namespace rpm
2276} // namespace target
2277} // namespace zypp
#define OUTS(VAL)
#define for_(IT, BEG, END)
Convenient for-loops using iterator.
Definition Easy.h:27
#define ZYPP_RETHROW(EXCPT)
Drops a logline and rethrows, updating the CodeLocation.
Definition Exception.h:479
#define ZYPP_CAUGHT(EXCPT)
Drops a logline telling the Exception was caught (in order to handle it).
Definition Exception.h:475
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition Exception.h:459
#define _(MSG)
Definition Gettext.h:39
#define DBG
Definition Logger.h:102
#define MIL
Definition Logger.h:103
#define ERR
Definition Logger.h:105
#define WAR
Definition Logger.h:104
#define L_DBG(GROUP)
Definition Logger.h:111
#define INT
Definition Logger.h:107
#define MAXRPMMESSAGELINES
Definition RpmDb.cc:65
#define WARNINGMAILPATH
Definition RpmDb.cc:63
#define FAILIFNOTINITIALIZED
Definition RpmDb.cc:218
#define FILEFORBACKUPFILES
Definition RpmDb.cc:64
Date()
Default ctor: 0.
Definition Date.h:57
static Date now()
Return the current time.
Definition Date.h:78
Assign a vaiable a certain value when going out of scope.
Definition dtorreset.h:50
Edition represents [epoch:]version[-release].
Definition Edition.h:60
static int match(const Edition &lhs, const Edition &rhs)
Definition Edition.h:129
std::string version() const
Version.
Definition Edition.cc:96
std::string release() const
Release.
Definition Edition.cc:112
static const Edition noedition
Value representing noedition ("") This is in fact a valid Edition.
Definition Edition.h:72
Base class for Exception.
Definition Exception.h:153
std::string asUserHistory() const
A single (multiline) string composed of asUserString and historyAsString.
Definition Exception.cc:140
void addHistory(const std::string &msg_r)
Add some message text to the history.
Definition Exception.cc:189
void moveToHistory(TContainer &&msgc_r)
addHistory from string container types (oldest first) moving
Definition Exception.h:258
Execute a program and give access to its io An object of this class encapsulates the execution of an ...
ExternalProgram()
Start an external program by giving the arguments as an arry of char *pointers.
int close() override
Wait for the progamm to complete.
bool kill()
Kill the program.
const std::string & execError() const
Some detail telling why the execution failed, if it failed.
bool running()
Return whether program is running.
Stderr_Disposition
Define symbols for different policies on the handling of stderr.
Writing the zypp history file.
Definition HistoryLog.h:57
void comment(const std::string &comment, bool timestamp=false)
Log a comment (even multiline).
static KeyManagerCtx createForOpenPGP()
Creates a new KeyManagerCtx for PGP using a volatile temp.
TraitsType::constPtrType constPtr
Definition Package.h:39
static Pathname stripprefix(const Pathname &root_r, const Pathname &path_r)
Return path_r with any root_r dir prefix striped.
Definition Pathname.cc:293
Pathname()
Default ctor: an empty path.
Definition Pathname.h:51
std::string basename() const
Return the last component of this path.
Definition Pathname.h:137
Maintain [min,max] and counter (value) for progress counting.
value_type reportValue() const
void sendTo(const ReceiverFnc &fnc_r)
Set ReceiverFnc.
bool toMax()
Set counter value to current max value (unless no range).
bool incr(value_type val_r=1)
Increment counter value (default by 1).
bool toMin()
Set counter value to current min value.
void range(value_type max_r)
Set new [0,max].
Class representing one GPG Public Keys data.
Definition PublicKey.h:201
std::string gpgPubkeyRelease() const
Gpg-pubkey release as computed by rpm (hexencoded created).
Definition PublicKey.cc:442
std::string gpgPubkeyVersion() const
Gpg-pubkey version as computed by rpm (trailing 8 byte id).
Definition PublicKey.cc:439
Class representing one GPG Public Key (PublicKeyData + ASCII armored in a tempfile).
Definition PublicKey.h:375
Pathname path() const
File containing the ASCII armored key.
Definition PublicKey.cc:640
std::string gpgPubkeyRelease() const
Definition PublicKey.cc:687
std::string asString() const
Definition PublicKey.cc:690
std::string id() const
Definition PublicKey.cc:657
std::string gpgPubkeyVersion() const
Definition PublicKey.cc:684
bool hasSubkeys() const
!<
Definition PublicKey.h:433
static ZConfig & instance()
Singleton ctor.
Definition ZConfig.cc:794
Typesafe passing of user data via callbacks.
Definition UserData.h:40
bool set(const std::string &key_r, AnyType val_r)
Set the value for key (nonconst version always returns true).
Definition UserData.h:119
void setBlocking(bool mode)
Set the blocking mode of the input stream.
FILE * inputFile() const
Return the input stream.
std::string receiveLine()
Read one line from the input stream.
Wrapper class for stat/lstat.
Definition PathInfo.h:226
bool isExist() const
Return whether valid stat info exists.
Definition PathInfo.h:286
Pathname dirname() const
Return all but the last component od this path.
Definition Pathname.h:133
const char * c_str() const
String representation.
Definition Pathname.h:113
const std::string & asString() const
String representation.
Definition Pathname.h:94
std::string basename() const
Return the last component of this path.
Definition Pathname.h:137
bool empty() const
Test for an empty path.
Definition Pathname.h:117
bool relative() const
Test for a relative path.
Definition Pathname.h:121
Provide a new empty temporary file and delete it when no longer needed.
Definition TmpPath.h:118
Pathname path() const
Definition TmpPath.cc:124
Regular expression.
Definition Regex.h:95
Regular expression match result.
Definition Regex.h:168
Extract and remember posttrans scripts for later execution.
void collectPosttransInfo(const Pathname &rpmPackage_r, const std::vector< std::string > &runposttrans_r)
Extract and remember a packages posttrans script or dump_posttrans lines for later execution.
bool hasPosttransScript(const Pathname &rpmPackage_r)
Test whether a package defines a posttrans script.
RpmDbAlreadyOpenException(const Pathname &old_root_r, const Pathname &old_dbpath_r, const Pathname &new_root_r, const Pathname &new_dbpath_r)
Interface to the rpm program.
Definition RpmDb.h:51
void getData(const std::string &name_r, RpmHeader::constPtr &result_r) const
Get an installed packages data from rpmdb.
Definition RpmDb.cc:1070
void doRebuildDatabase(callback::SendReport< RebuildDBReport > &report)
Definition RpmDb.cc:391
bool queryChangedFiles(FileList &fileList, const std::string &packageName)
determine which files of an installed package have been modified.
Definition RpmDb.cc:1360
std::string error_message
Error message from running rpm as external program.
Definition RpmDb.h:344
bool hasRequiredBy(const std::string &tag_r) const
Return true if at least one package requires a certain tag.
Definition RpmDb.cc:1014
std::vector< const char * > RpmArgVec
Definition RpmDb.h:303
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:982
void exportTrustedKeysInZyppKeyRing()
insert all rpm trusted keys into zypp trusted keyring
Definition RpmDb.cc:676
void importPubkey(const PublicKey &pubkey_r)
Import ascii armored public key in file pubkey_r.
Definition RpmDb.cc:685
void installPackage(const Pathname &filename, RpmInstFlags flags=RPMINST_NONE)
install rpm package
Definition RpmDb.cc:1652
Pathname _backuppath
/var/adm/backup
Definition RpmDb.h:347
std::ostream & dumpOn(std::ostream &str) const override
Dump debug info.
Definition RpmDb.cc:262
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:1425
void initDatabase(Pathname root_r=Pathname(), bool doRebuild_r=false)
Prepare access to the rpm database below root_r.
Definition RpmDb.cc:281
int runposttrans(const Pathname &filename_r, const std::function< void(const std::string &)> &output_r)
Run collected posttrans and transfiletrigger(postun|in) if rpm --runposttrans is supported.
Definition RpmDb.cc:2020
bool initialized() const
Definition RpmDb.h:125
ExternalProgram * process
The connection to the rpm process.
Definition RpmDb.h:301
SyncTrustedKeyBits
Sync mode for syncTrustedKeys.
Definition RpmDb.h:278
@ SYNC_TO_KEYRING
export rpm trusted keys into zypp trusted keyring
Definition RpmDb.h:279
@ SYNC_FROM_KEYRING
import zypp trusted keys into rpm database.
Definition RpmDb.h:280
~RpmDb() override
Destructor.
Definition RpmDb.cc:247
std::list< PublicKey > pubkeys() const
Return the long ids of all installed public keys.
Definition RpmDb.cc:865
std::set< Edition > pubkeyEditions() const
Return the edition of all installed public keys.
Definition RpmDb.cc:903
int systemStatus()
Return the exit status of the general rpm process, closing the connection if not already done.
Definition RpmDb.cc:1527
std::set< std::string > FileList
Definition RpmDb.h:370
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:1354
bool backupPackage(const std::string &packageName)
create tar.gz of all changed files in a Package
Definition RpmDb.cc:2112
bool hasProvides(const std::string &tag_r) const
Return true if at least one package provides a certain tag.
Definition RpmDb.cc:1000
void systemKill()
Forcably kill the system process.
Definition RpmDb.cc:1550
const Pathname & root() const
Definition RpmDb.h:109
void removePubkey(const PublicKey &pubkey_r)
Remove a public key from the rpm database.
Definition RpmDb.cc:798
RpmDb()
Constructor.
Definition RpmDb.cc:228
void removePackage(const std::string &name_r, RpmInstFlags flags=RPMINST_NONE)
remove rpm package
Definition RpmDb.cc:1854
db_const_iterator dbConstIterator() const
Definition RpmDb.cc:268
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 !...
Definition RpmDb.cc:927
const Pathname & dbPath() const
Definition RpmDb.h:117
Pathname _dbPath
Directory that contains the rpmdb.
Definition RpmDb.h:91
void closeDatabase()
Block further access to the rpm database and go back to uninitialized state.
Definition RpmDb.cc:353
void setBackupPath(const Pathname &path)
set path where package backups are stored
Definition RpmDb.cc:2239
bool _packagebackups
create package backups?
Definition RpmDb.h:350
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,...
Definition RpmDb.cc:1348
void importZyppKeyRingTrustedKeys()
iterates through zypp keyring and import all non-existent keys into rpm keyring
Definition RpmDb.cc:673
void doInstallPackage(const Pathname &filename, RpmInstFlags flags, RpmPostTransCollector *postTransCollector_r, callback::SendReport< RpmInstallReport > &report)
Definition RpmDb.cc:1688
Pathname _root
Root directory for all operations.
Definition RpmDb.h:86
bool hasConflicts(const std::string &tag_r) const
Return true if at least one package conflicts with a certain tag.
Definition RpmDb.cc:1028
int exit_code
The exit code of the rpm process, or -1 if not yet known.
Definition RpmDb.h:338
void syncTrustedKeys(SyncTrustedKeyBits mode_r=SYNC_BOTH)
Sync trusted keys stored in rpm database and zypp trusted keyring.
Definition RpmDb.cc:572
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:1557
CheckPackageResult
checkPackage result
Definition RpmDb.h:377
bool hasPackage(const std::string &name_r) const
Return true if package is installed.
Definition RpmDb.cc:1042
void doRemovePackage(const std::string &name_r, RpmInstFlags flags, RpmPostTransCollector *postTransCollector_r, callback::SendReport< RpmRemoveReport > &report)
Definition RpmDb.cc:1895
bool systemReadLine(std::string &line)
Read a line from the general rpm query.
Definition RpmDb.cc:1474
void rebuildDatabase()
Rebuild the rpm database (rpm –rebuilddb).
Definition RpmDb.cc:373
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:956
Just inherits Exception to separate media exceptions.
intrusive_ptr< const RpmHeader > constPtr
Definition RpmHeader.h:65
static RpmHeader::constPtr readPackage(const Pathname &path, VERIFICATION verification=VERIFY)
Get an accessible packages data from disk.
Definition RpmHeader.cc:212
Subclass to retrieve rpm database content.
Definition librpmDb.h:198
static bool globalInit()
Initialize lib librpm (read configfiles etc.).
Definition librpmDb.cc:139
static librpmDb::constPtr dbOpenCreate(const Pathname &root_r, const Pathname &dbPath_r=Pathname())
Assert the rpmdb below the system at root_r exists.
Definition librpmDb.cc:198
static Pathname suggestedDbPath(const Pathname &root_r)
Definition librpmDb.cc:171
std::string asString() const
bool regex_match(const char *s, smatch &matches, const regex &regex) ZYPP_API
Regular expression matching.
Definition Regex.cc:80
String related utilities and Regular expression matching.
@ Edition
Editions with v-r setparator highlighted.
Definition Table.h:160
Namespace intended to collect all environment variables we use.
bool ZYPP_RPM_DEBUG()
Definition RpmDb.cc:80
Types and functions for filesystem operations.
Definition Glob.cc:24
int symlink(const Pathname &oldpath, const Pathname &newpath)
Like 'symlink'.
Definition PathInfo.cc:874
int copy(const Pathname &file, const Pathname &dest)
Like 'cp file dest'.
Definition PathInfo.cc:839
Pathname expandlink(const Pathname &path_r)
Recursively follows the symlink pointed to by path_r and returns the Pathname to the real file or dir...
Definition PathInfo.cc:964
int unlink(const Pathname &path)
Like 'unlink'.
Definition PathInfo.cc:719
int assert_dir(const Pathname &path, unsigned mode)
Like 'mkdir -p'.
Definition PathInfo.cc:338
std::pair< ReceiveUpToResult, std::string > receiveUpto(FILE *file, char c, timeout_type timeout, bool failOnUnblockError)
Definition IOTools.cc:85
@ Timeout
Definition IOTools.h:72
@ Success
Definition IOTools.h:71
@ Error
Definition IOTools.h:74
@ EndOfFile
Definition IOTools.h:73
std::string & replaceAll(std::string &str_r, const std::string &from_r, const std::string &to_r)
Replace all occurrences of from_r with to_r in str_r (inplace).
Definition String.cc:333
std::string numstring(char n, int w=0)
Definition String.h:290
bool hasPrefix(const C_Str &str_r, const C_Str &prefix_r)
Return whether str_r has prefix prefix_r.
Definition String.h:1097
std::string toLower(const std::string &s)
Return lowercase version of s.
Definition String.cc:180
bool startsWith(const C_Str &str_r, const C_Str &prefix_r)
alias for hasPrefix
Definition String.h:1155
bool endsWith(const C_Str &str_r, const C_Str &prefix_r)
alias for hasSuffix
Definition String.h:1162
std::string form(const char *format,...) __attribute__((format(printf
Printf style construction of std::string.
Definition String.cc:39
bool strToBool(const C_Str &str, bool default_r)
Parse str into a bool depending on the default value.
Definition String.h:500
unsigned diffFiles(const std::string &file1, const std::string &file2, std::string &out, int maxlines)
Definition RpmDb.cc:184
std::ostream & operator<<(std::ostream &str, const librpmDb::db_const_iterator &obj)
relates: librpmDb::db_const_iterator stream output
Definition librpmDb.cc:412
_dumpPath dumpPath(const Pathname &root_r, const Pathname &sub_r)
dumpPath iomaip to dump '(root_r)sub_r' output,
Definition librpmDb.h:42
static shared_ptr< KeyRingSignalReceiver > sKeyRingReceiver
Definition RpmDb.cc:182
Easy-to use interface to the ZYPP dependency resolver.
ZYpp::Ptr getZYpp()
relates: ZYppFactory Convenience to get the Pointer to the ZYpp instance.
Definition ZYppFactory.h:77
Temporarily connect a ReceiveReport then restore the previous one.
Definition Callback.h:285
Convenient building of std::string with boost::format.
Definition String.h:254
KeyRingSignalReceiver & operator=(const KeyRingSignalReceiver &)=delete
void trustedKeyRemoved(const PublicKey &key) override
Definition RpmDb.cc:173
KeyRingSignalReceiver & operator=(KeyRingSignalReceiver &&)=delete
KeyRingSignalReceiver(const KeyRingSignalReceiver &)=delete
void trustedKeyAdded(const PublicKey &key) override
Definition RpmDb.cc:167
KeyRingSignalReceiver(KeyRingSignalReceiver &&)=delete
Detailed rpm signature check log messages A single multiline message if CHK_OK.
Definition RpmDb.h:392
Wrapper providing a librpmDb::db_const_iterator for this RpmDb.
Definition RpmDb.h:65