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