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