libzypp 17.35.16
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
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
1518 error_message = process->execError();
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
#define FAILIFNOTINITIALIZED
Definition RpmDb.cc:201
#define FILEFORBACKUPFILES
Definition RpmDb.cc:64
#define OUTS(V)
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.
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.
TraitsType::constPtrType constPtr
Definition Package.h:39
std::string basename() const
Return the last component of this path.
Definition Pathname.h:130
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
zypp::ContentType ContentType
Definition UserData.h:51
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:139
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:198
static Pathname suggestedDbPath(const Pathname &root_r)
Definition librpmDb.cc:171
String related utilities and Regular expression matching.
@ Edition
Editions with v-r setparator highlighted.
Definition Table.h:160
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:412
_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.