libzypp 17.37.17
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
34#include <zypp/base/Logger.h>
35#include <zypp/base/String.h>
36#include <zypp/base/Gettext.h>
38#include <zypp-core/base/DtorReset>
39
40#include <zypp/Date.h>
41#include <zypp/Pathname.h>
42#include <zypp/PathInfo.h>
43#include <zypp-common/PublicKey.h>
44#include <zypp-core/ui/ProgressData>
45
49
50#include <zypp/HistoryLog.h>
53#include <zypp/TmpPath.h>
54#include <zypp/KeyRing.h>
55#include <zypp-common/KeyManager.h>
56#include <zypp/ZYppFactory.h>
57#include <zypp/ZConfig.h>
58#include <zypp/base/IOTools.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 && it->tag_edition() == Edition("4.18.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 ) {
1298 auto keyMgr = zypp::KeyManagerCtx::createForOpenPGP();
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
1536 error_message = process->execError();
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 " + 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 MAXRPMMESSAGELINES
Definition RpmDb.cc:65
#define WARNINGMAILPATH
Definition RpmDb.cc:63
#define FAILIFNOTINITIALIZED
Definition RpmDb.cc:218
#define FILEFORBACKUPFILES
Definition RpmDb.cc:64
#define OUTS(V)
Store and operate on date (time_t).
Definition Date.h:33
std::string form(const std::string &format_r) const
Return string representation according to format as localtime.
Definition Date.h:112
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:61
std::string version() const
Version.
Definition Edition.cc:94
std::string release() const
Release.
Definition Edition.cc:110
static const Edition noedition
Value representing noedition ("") This is in fact a valid Edition.
Definition Edition.h:73
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 ...
int close() override
Wait for the progamm to complete.
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
TraitsType::constPtrType constPtr
Definition Package.h:39
std::string basename() const
Return the last component of this path.
Definition Pathname.h:130
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].
static ZConfig & instance()
Singleton ctor.
Definition ZConfig.cc:940
ZYpp::Ptr getZYpp()
Convenience to get the Pointer to the ZYpp instance.
Definition ZYppFactory.h:77
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
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:126
const char * c_str() const
String representation.
Definition Pathname.h:112
const std::string & asString() const
String representation.
Definition Pathname.h:93
std::string basename() const
Return the last component of this path.
Definition Pathname.h:130
bool empty() const
Test for an empty path.
Definition Pathname.h:116
bool relative() const
Test for a relative path.
Definition Pathname.h:120
Provide a new empty temporary file and delete it when no longer needed.
Definition TmpPath.h:128
Pathname path() const
Definition TmpPath.cc:152
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.
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
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.
Definition Env.h:25
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:860
int copy(const Pathname &file, const Pathname &dest)
Like 'cp file dest'.
Definition PathInfo.cc:825
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:950
int unlink(const Pathname &path)
Like 'unlink'.
Definition PathInfo.cc:705
int assert_dir(const Pathname &path, unsigned mode)
Like 'mkdir -p'.
Definition PathInfo.cc:324
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
bool regex_match(const std::string &s, smatch &matches, const regex &regex)
\relates regex \ingroup ZYPP_STR_REGEX \relates regex \ingroup ZYPP_STR_REGEX
Definition Regex.h:70
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)
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.
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
std::string asString() const
Definition String.h:263
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
#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:99
#define MIL
Definition Logger.h:100
#define ERR
Definition Logger.h:102
#define WAR
Definition Logger.h:101
#define L_DBG(GROUP)
Definition Logger.h:108
#define INT
Definition Logger.h:104
Interface to gettext.