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