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