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