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