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