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