*
*/
#include "librpm.h"
-
+extern "C"
+{
+#include <rpm/rpmcli.h>
+#include <rpm/rpmlog.h>
+}
#include <cstdlib>
#include <cstdio>
#include <ctime>
#include <vector>
#include <algorithm>
-#include <boost/format.hpp>
-
#include "zypp/base/Logger.h"
#include "zypp/base/String.h"
#include "zypp/base/Gettext.h"
+#include "zypp/base/LocaleGuard.h"
#include "zypp/Date.h"
#include "zypp/Pathname.h"
#include "zypp/ZYppFactory.h"
#include "zypp/ZConfig.h"
-using namespace std;
+using std::endl;
using namespace zypp::filesystem;
#define WARNINGMAILPATH "/var/log/YaST2/"
#define WORKAROUNDRPMPWDBUG
+#undef ZYPP_BASE_LOGGER_LOGGROUP
+#define ZYPP_BASE_LOGGER_LOGGROUP "librpmDb"
+
namespace zypp
{
namespace zypp_readonly_hack
#else
const char* quoteInFilename_m = " \t\'\"";
#endif
-inline string rpmQuoteFilename( const Pathname & path_r )
+inline std::string rpmQuoteFilename( const Pathname & path_r )
{
- string path( path_r.asString() );
- for ( string::size_type pos = path.find_first_of( quoteInFilename_m );
- pos != string::npos;
+ std::string path( path_r.asString() );
+ for ( std::string::size_type pos = path.find_first_of( quoteInFilename_m );
+ pos != std::string::npos;
pos = path.find_first_of( quoteInFilename_m, pos ) )
{
path.insert( pos, "\\" );
virtual void trustedKeyAdded( const PublicKey &key )
{
- MIL << "trusted key added to zypp Keyring. Importing" << endl;
- // now import the key in rpm
- try
- {
- _rpmdb.importPubkey( key );
- }
- catch (RpmException &e)
- {
- ERR << "Could not import key " << key.id() << " (" << key.name() << " from " << key.path() << " in rpm database" << endl;
- }
+ MIL << "trusted key added to zypp Keyring. Importing..." << endl;
+ _rpmdb.importPubkey( key );
}
virtual void trustedKeyRemoved( const PublicKey &key )
{
MIL << "Trusted key removed from zypp Keyring. Removing..." << endl;
-
- // remove the key from rpm
- try
- {
- _rpmdb.removePubkey( key );
- }
- catch (RpmException &e)
- {
- ERR << "Could not remove key " << key.id() << " (" << key.name() << ") from rpm database" << endl;
- }
+ _rpmdb.removePubkey( key );
}
RpmDb &_rpmdb;
static shared_ptr<KeyRingSignalReceiver> sKeyRingReceiver;
-unsigned diffFiles(const string file1, const string file2, string& out, int maxlines)
+unsigned diffFiles(const std::string file1, const std::string file2, std::string& out, int maxlines)
{
const char* argv[] =
{
//if(!prog)
//return 2;
- string line;
+ std::string line;
int count = 0;
for (line = prog.receiveLine(), count=0;
!line.empty();
**
**
** FUNCTION NAME : stringPath
- ** FUNCTION TYPE : inline string
+ ** FUNCTION TYPE : inline std::string
*/
-inline string stringPath( const Pathname & root_r, const Pathname & sub_r )
+inline std::string stringPath( const Pathname & root_r, const Pathname & sub_r )
{
return librpmDb::stringPath( root_r, sub_r );
}
**
**
** FUNCTION NAME : operator<<
- ** FUNCTION TYPE : ostream &
+ ** FUNCTION TYPE : std::ostream &
*/
-ostream & operator<<( ostream & str, const RpmDb::DbStateInfoBits & obj )
+std::ostream & operator<<( std::ostream & str, const RpmDb::DbStateInfoBits & obj )
{
if ( obj == RpmDb::DbSI_NO_INIT )
{
//
//
// METHOD NAME : RpmDb::dumpOn
-// METHOD TYPE : ostream &
+// METHOD TYPE : std::ostream &
//
-ostream & RpmDb::dumpOn( ostream & str ) const
+std::ostream & RpmDb::dumpOn( std::ostream & str ) const
{
str << "RpmDb[";
ZYPP_THROW(RpmInvalidRootException(root_r, dbPath_r));
}
+ if ( dbPath_r == "/var/lib/rpm"
+ && ! PathInfo( root_r/"/var/lib/rpm" ).isExist()
+ && PathInfo( root_r/"/usr/lib/sysimage/rpm" ).isDir() )
+ {
+ WAR << "Rpm package was deleted? Injecting missing rpmdb compat symlink." << endl;
+ filesystem::symlink( "../../usr/lib/sysimage/rpm", root_r/"/var/lib/rpm" );
+ }
+
MIL << "Calling initDatabase: " << stringPath( root_r, dbPath_r )
<< ( doRebuild_r ? " (rebuilddb)" : "" )
<< ( quickinit ? " (quickinit)" : "" ) << endl;
}
}
- MIL << "Syncronizing keys with zypp keyring" << endl;
+ MIL << "Synchronizing keys with zypp keyring" << endl;
syncTrustedKeys();
// Close the database in case any write acces (create/convert)
process?process->getpid():0) )
+ "Packages" );
- string line;
- string errmsg;
+ std::string line;
+ std::string errmsg;
while ( systemReadLine( line ) )
{
if ( rpm_status != 0 )
{
//TranslatorExplanation after semicolon is error message
- ZYPP_THROW(RpmSubprocessException(string(_("RPM failed: ") +
- (errmsg.empty() ? error_message: errmsg))));
+ ZYPP_THROW(RpmSubprocessException(std::string(_("RPM failed: ")) + (errmsg.empty() ? error_message: errmsg) ) );
}
else
{
_inRpmKeys = &rpmKey_r;
_inZyppKeys = nullptr;
if ( !keyRelease.empty() )
- DBG << "Old key in R: gpg-pubkey-" << rpmKey_r.version() << "-" << keyRelease << endl;
+ DBG << "Old key in Z: gpg-pubkey-" << rpmKey_r.version() << "-" << keyRelease << endl;
}
else if ( comp == 0 )
{
_inRpmKeys = nullptr;
_inZyppKeys = &zyppKey_r;
if ( !keyRelease.empty() )
- DBG << "Old key in Z: gpg-pubkey-" << zyppKey_r.gpgPubkeyVersion() << "-" << keyRelease << endl;
+ DBG << "Old key in R: gpg-pubkey-" << zyppKey_r.gpgPubkeyVersion() << "-" << keyRelease << endl;
}
else if ( comp == 0 )
{
MIL << "Going to sync trusted keys..." << endl;
std::set<Edition> rpmKeys( pubkeyEditions() );
std::list<PublicKeyData> zyppKeys( getZYpp()->keyRing()->trustedPublicKeyData() );
+
+ if ( ! ( mode_r & SYNC_FROM_KEYRING ) )
+ {
+ // bsc#1064380: We relief PK from removing excess keys in the zypp keyring
+ // when re-acquiring the zyppp lock. For now we remove all excess keys.
+ // TODO: Once we can safely assume that all PK versions are updated we
+ // can think about re-importing newer key versions found in the zypp keyring and
+ // removing only excess ones (but case is not very likely). Unfixed PK versions
+ // however will remove the newer version found in the zypp keyring and by doing
+ // this, the key here will be removed via callback as well (keys are deleted
+ // via gpg id, regardless of the edition).
+ MIL << "Removing excess keys in zypp trusted keyring" << std::endl;
+ // Temporarily disconnect to prevent the attempt to pass back the delete request.
+ callback::TempConnect<KeyRingSignals> tempDisconnect;
+ bool dirty = false;
+ for ( const PublicKeyData & keyData : zyppKeys )
+ {
+ if ( ! rpmKeys.count( keyData.gpgPubkeyEdition() ) )
+ {
+ DBG << "Excess key in Z to delete: gpg-pubkey-" << keyData.gpgPubkeyEdition() << endl;
+ getZYpp()->keyRing()->deleteKey( keyData.id(), /*trusted*/true );
+ if ( !dirty ) dirty = true;
+ }
+ }
+ if ( dirty )
+ zyppKeys = getZYpp()->keyRing()->trustedPublicKeyData();
+ }
+
computeKeyRingSync( rpmKeys, zyppKeys );
MIL << (mode_r & SYNC_TO_KEYRING ? "" : "(skip) ") << "Rpm keys to export into zypp trusted keyring: " << rpmKeys.size() << endl;
MIL << (mode_r & SYNC_FROM_KEYRING ? "" : "(skip) ") << "Zypp trusted keys to import into rpm database: " << zyppKeys.size() << endl;
{
// export to zypp keyring
MIL << "Exporting rpm keyring into zypp trusted keyring" <<endl;
- // Temporarily disconnect to prevent the attemt to re-import the exported keys.
+ // Temporarily disconnect to prevent the attempt to re-import the exported keys.
callback::TempConnect<KeyRingSignals> tempDisconnect;
librpmDb::db_const_iterator keepDbOpen; // just to keep a ref.
TmpFile tmpfile( getZYpp()->tmpPath() );
{
- ofstream tmpos( tmpfile.path().c_str() );
+ std::ofstream tmpos( tmpfile.path().c_str() );
for_( it, rpmKeys.begin(), rpmKeys.end() )
{
// we export the rpm key into a file
RpmHeader::constPtr result;
- getData( string("gpg-pubkey"), *it, result );
+ getData( "gpg-pubkey", *it, result );
tmpos << result->tag_description() << endl;
}
}
try
{
getZYpp()->keyRing()->multiKeyImport( tmpfile.path(), true /*trusted*/);
+ // bsc#1096217: Try to spot and report legacy V3 keys found in the rpm database.
+ // Modern rpm does not import those keys, but when migrating a pre SLE12 system
+ // we may find them. rpm>4.13 even complains on sderr if sucha key is present.
+ std::set<Edition> missingKeys;
+ for ( const Edition & key : rpmKeys )
+ {
+ if ( getZYpp()->keyRing()->isKeyTrusted( key.version() ) ) // key.version is the gpgkeys short ID
+ continue;
+ ERR << "Could not import key:" << str::Format("gpg-pubkey-%s") % key << " into zypp keyring (V3 key?)" << endl;
+ missingKeys.insert( key );
+ }
+ if ( ! missingKeys.empty() )
+ callback::SendReport<KeyRingReport>()->reportNonImportedKeys(missingKeys);
}
- catch (Exception &e)
+ catch ( const Exception & excpt )
{
- ERR << "Could not import keys into in zypp keyring" << endl;
+ ZYPP_CAUGHT( excpt );
+ ERR << "Could not import keys into zypp keyring: " << endl;
}
}
// check if the key is already in the rpm database
Edition keyEd( pubkey_r.gpgPubkeyVersion(), pubkey_r.gpgPubkeyRelease() );
- set<Edition> rpmKeys = pubkeyEditions();
+ std::set<Edition> rpmKeys = pubkeyEditions();
bool hasOldkeys = false;
for_( it, rpmKeys.begin(), rpmKeys.end() )
{
- if ( keyEd == *it ) // quick test (Edition is IdStringType!)
+ // bsc#1008325: Keys using subkeys for signing don't get a higher release
+ // if new subkeys are added, because the primary key remains unchanged.
+ // For now always re-import keys with subkeys. Here we don't want to export the
+ // keys in the rpm database to check whether the subkeys are the same. The calling
+ // code should take care, we don't re-import the same kesy over and over again.
+ if ( keyEd == *it && !pubkey_r.hasSubkeys() ) // quick test (Edition is IdStringType!)
{
MIL << "Key " << pubkey_r << " is already in the rpm trusted keyring. (skip import)" << endl;
return;
// rpm3 database, if the current database is a temporary one.
run_rpm( opts, ExternalProgram::Stderr_To_Stdout );
- string line;
+ std::string line;
while ( systemReadLine( line ) )
{
( str::startsWith( line, "error:" ) ? WAR : DBG ) << line << endl;
RpmArgVec opts;
opts.push_back ( "--import" );
opts.push_back ( "--" );
- opts.push_back ( pubkey_r.path().asString().c_str() );
+ std::string pubkeypath( pubkey_r.path().asString() );
+ opts.push_back ( pubkeypath.c_str() );
// don't call modifyDatabase because it would remove the old
// rpm3 database, if the current database is a temporary one.
run_rpm( opts, ExternalProgram::Stderr_To_Stdout );
- string line;
+ std::string line;
+ std::vector<std::string> excplines;
while ( systemReadLine( line ) )
{
- ( str::startsWith( line, "error:" ) ? WAR : DBG ) << line << endl;
+ if ( str::startsWith( line, "error:" ) )
+ {
+ WAR << line << endl;
+ excplines.push_back( std::move(line) );
+ }
+ else
+ DBG << line << endl;
}
if ( systemStatus() != 0 )
{
- //TranslatorExplanation first %s is file name, second is error message
- ZYPP_THROW(RpmSubprocessException(boost::str(boost::format(
- _("Failed to import public key from file %s: %s"))
- % pubkey_r.asString() % error_message)));
+ // Translator: %1% is a gpg public key
+ RpmSubprocessException excp( str::Format(_("Failed to import public key %1%") ) % pubkey_r.asString() );
+ excp.moveToHistory( excplines );
+ excp.addHistory( std::move(error_message) );
+ ZYPP_THROW( std::move(excp) );
}
else
{
// check if the key is in the rpm database and just
// return if it does not.
- set<Edition> rpm_keys = pubkeyEditions();
- set<Edition>::const_iterator found_edition = rpm_keys.end();
+ std::set<Edition> rpm_keys = pubkeyEditions();
+ std::set<Edition>::const_iterator found_edition = rpm_keys.end();
std::string pubkeyVersion( pubkey_r.gpgPubkeyVersion() );
for_( it, rpm_keys.begin(), rpm_keys.end() )
return;
}
- string rpm_name("gpg-pubkey-" + found_edition->asString());
+ std::string rpm_name("gpg-pubkey-" + found_edition->asString());
RpmArgVec opts;
opts.push_back ( "-e" );
// rpm3 database, if the current database is a temporary one.
run_rpm( opts, ExternalProgram::Stderr_To_Stdout );
- string line;
+ std::string line;
+ std::vector<std::string> excplines;
while ( systemReadLine( line ) )
{
- if ( line.substr( 0, 6 ) == "error:" )
+ if ( str::startsWith( line, "error:" ) )
{
WAR << line << endl;
+ excplines.push_back( std::move(line) );
}
else
- {
DBG << line << endl;
- }
}
- int rpm_status = systemStatus();
-
- if ( rpm_status != 0 )
+ if ( systemStatus() != 0 )
{
- //TranslatorExplanation first %s is key name, second is error message
- ZYPP_THROW(RpmSubprocessException(boost::str(boost::format(
- _("Failed to remove public key %s: %s")) % pubkey_r.asString()
- % error_message)));
+ // Translator: %1% is a gpg public key
+ RpmSubprocessException excp( str::Format(_("Failed to remove public key %1%") ) % pubkey_r.asString() );
+ excp.moveToHistory( excplines );
+ excp.addHistory( std::move(error_message) );
+ ZYPP_THROW( std::move(excp) );
}
else
{
//
//
// METHOD NAME : RpmDb::pubkeys
-// METHOD TYPE : set<Edition>
+// METHOD TYPE : std::set<Edition>
//
-list<PublicKey> RpmDb::pubkeys() const
+std::list<PublicKey> RpmDb::pubkeys() const
{
- list<PublicKey> ret;
+ std::list<PublicKey> ret;
librpmDb::db_const_iterator it;
- for ( it.findByName( string( "gpg-pubkey" ) ); *it; ++it )
+ for ( it.findByName( "gpg-pubkey" ); *it; ++it )
{
Edition edition = it->tag_edition();
if (edition != Edition::noedition)
{
// we export the rpm key into a file
RpmHeader::constPtr result;
- getData( string("gpg-pubkey"), edition, result );
+ getData( "gpg-pubkey", edition, result );
TmpFile file(getZYpp()->tmpPath());
- ofstream os;
+ std::ofstream os;
try
{
os.open(file.path().asString().c_str());
PublicKey key(file);
ret.push_back(key);
}
- catch (exception &e)
+ catch ( std::exception & e )
{
ERR << "Could not dump key " << edition.asString() << " in tmp file " << file.path() << endl;
// just ignore the key
return ret;
}
-set<Edition> RpmDb::pubkeyEditions() const
+std::set<Edition> RpmDb::pubkeyEditions() const
{
- set<Edition> ret;
+ std::set<Edition> ret;
librpmDb::db_const_iterator it;
- for ( it.findByName( string( "gpg-pubkey" ) ); *it; ++it )
+ for ( it.findByName( "gpg-pubkey" ); *it; ++it )
{
Edition edition = it->tag_edition();
if (edition != Edition::noedition)
//
// DESCRIPTION :
//
-list<FileInfo>
-RpmDb::fileList( const string & name_r, const Edition & edition_r ) const
+std::list<FileInfo>
+RpmDb::fileList( const std::string & name_r, const Edition & edition_r ) const
{
- list<FileInfo> result;
+ std::list<FileInfo> result;
librpmDb::db_const_iterator it;
bool found;
//
// DESCRIPTION :
//
-bool RpmDb::hasFile( const string & file_r, const string & name_r ) const
+bool RpmDb::hasFile( const std::string & file_r, const std::string & name_r ) const
{
librpmDb::db_const_iterator it;
bool res;
//
//
// METHOD NAME : RpmDb::whoOwnsFile
-// METHOD TYPE : string
+// METHOD TYPE : std::string
//
// DESCRIPTION :
//
-string RpmDb::whoOwnsFile( const string & file_r) const
+std::string RpmDb::whoOwnsFile( const std::string & file_r) const
{
librpmDb::db_const_iterator it;
if (it.findByFile( file_r ))
//
// DESCRIPTION :
//
-bool RpmDb::hasProvides( const string & tag_r ) const
+bool RpmDb::hasProvides( const std::string & tag_r ) const
{
librpmDb::db_const_iterator it;
return it.findByProvides( tag_r );
//
// DESCRIPTION :
//
-bool RpmDb::hasRequiredBy( const string & tag_r ) const
+bool RpmDb::hasRequiredBy( const std::string & tag_r ) const
{
librpmDb::db_const_iterator it;
return it.findByRequiredBy( tag_r );
//
// DESCRIPTION :
//
-bool RpmDb::hasConflicts( const string & tag_r ) const
+bool RpmDb::hasConflicts( const std::string & tag_r ) const
{
librpmDb::db_const_iterator it;
return it.findByConflicts( tag_r );
//
// DESCRIPTION :
//
-bool RpmDb::hasPackage( const string & name_r ) const
+bool RpmDb::hasPackage( const std::string & name_r ) const
{
librpmDb::db_const_iterator it;
return it.findPackage( name_r );
//
// DESCRIPTION :
//
-bool RpmDb::hasPackage( const string & name_r, const Edition & ed_r ) const
+bool RpmDb::hasPackage( const std::string & name_r, const Edition & ed_r ) const
{
librpmDb::db_const_iterator it;
return it.findPackage( name_r, ed_r );
//
// DESCRIPTION :
//
-void RpmDb::getData( const string & name_r,
+void RpmDb::getData( const std::string & name_r,
RpmHeader::constPtr & result_r ) const
{
librpmDb::db_const_iterator it;
//
// DESCRIPTION :
//
-void RpmDb::getData( const string & name_r, const Edition & ed_r,
+void RpmDb::getData( const std::string & name_r, const Edition & ed_r,
RpmHeader::constPtr & result_r ) const
{
librpmDb::db_const_iterator it;
}
///////////////////////////////////////////////////////////////////
-//
-// METHOD NAME : RpmDb::checkPackage
-// METHOD TYPE : RpmDb::checkPackageResult
-//
-RpmDb::checkPackageResult RpmDb::checkPackage( const Pathname & path_r )
+namespace
{
- PathInfo file( path_r );
- if ( ! file.isFile() )
+ struct RpmlogCapture : public std::string
{
- ERR << "Not a file: " << file << endl;
- return CHK_ERROR;
- }
+ RpmlogCapture()
+ { rpmlog()._cap = this; }
- FD_t fd = ::Fopen( file.asString().c_str(), "r.ufdio" );
- if ( fd == 0 || ::Ferror(fd) )
- {
- ERR << "Can't open file for reading: " << file << " (" << ::Fstrerror(fd) << ")" << endl;
- if ( fd )
- ::Fclose( fd );
- return CHK_ERROR;
- }
+ ~RpmlogCapture()
+ { rpmlog()._cap = nullptr; }
+
+ private:
+ struct Rpmlog
+ {
+ Rpmlog()
+ : _cap( nullptr )
+ {
+ rpmlogSetCallback( rpmLogCB, this );
+ rpmSetVerbosity( RPMLOG_INFO );
+ _f = ::fopen( "/dev/null","w");
+ rpmlogSetFile( _f );
+ }
+
+ ~Rpmlog()
+ { if ( _f ) ::fclose( _f ); }
- rpmts ts = ::rpmtsCreate();
- ::rpmtsSetRootDir( ts, root().asString().c_str() );
- ::rpmtsSetVSFlags( ts, RPMVSF_DEFAULT );
- int res = ::rpmReadPackageFile( ts, fd, path_r.asString().c_str(), NULL );
- ts = rpmtsFree(ts);
+ static int rpmLogCB( rpmlogRec rec_r, rpmlogCallbackData data_r )
+ { return reinterpret_cast<Rpmlog*>(data_r)->rpmLog( rec_r ); }
- ::Fclose( fd );
+ int rpmLog( rpmlogRec rec_r )
+ {
+ if ( _cap ) (*_cap) += rpmlogRecMessage( rec_r );
+ return RPMLOG_DEFAULT;
+ }
- switch ( res )
+ FILE * _f;
+ std::string * _cap;
+ };
+
+ static Rpmlog & rpmlog()
+ { static Rpmlog _rpmlog; return _rpmlog; }
+ };
+
+ RpmDb::CheckPackageResult doCheckPackageSig( const Pathname & path_r, // rpm file to check
+ const Pathname & root_r, // target root
+ bool requireGPGSig_r, // whether no gpg signature is to be reported
+ RpmDb::CheckPackageDetail & detail_r ) // detailed result
{
- case RPMRC_OK:
- return CHK_OK;
- break;
- case RPMRC_NOTFOUND:
- WAR << "Signature is unknown type. " << file << endl;
- return CHK_NOTFOUND;
- break;
- case RPMRC_FAIL:
- WAR << "Signature does not verify. " << file << endl;
- return CHK_FAIL;
- break;
- case RPMRC_NOTTRUSTED:
- WAR << "Signature is OK, but key is not trusted. " << file << endl;
- return CHK_NOTTRUSTED;
- break;
- case RPMRC_NOKEY:
- WAR << "Public key is unavailable. " << file << endl;
- return CHK_NOKEY;
- break;
+ PathInfo file( path_r );
+ if ( ! file.isFile() )
+ {
+ ERR << "Not a file: " << file << endl;
+ return RpmDb::CHK_ERROR;
+ }
+
+ FD_t fd = ::Fopen( file.asString().c_str(), "r.ufdio" );
+ if ( fd == 0 || ::Ferror(fd) )
+ {
+ ERR << "Can't open file for reading: " << file << " (" << ::Fstrerror(fd) << ")" << endl;
+ if ( fd )
+ ::Fclose( fd );
+ return RpmDb::CHK_ERROR;
+ }
+ rpmts ts = ::rpmtsCreate();
+ ::rpmtsSetRootDir( ts, root_r.c_str() );
+ ::rpmtsSetVSFlags( ts, RPMVSF_DEFAULT );
+
+ rpmQVKArguments_s qva;
+ memset( &qva, 0, sizeof(rpmQVKArguments_s) );
+#ifdef HAVE_NO_RPMTSSETVFYFLAGS
+ // Legacy: In rpm >= 4.15 qva_flags symbols don't exist
+ // and qva_flags is not used in signature checking at all.
+ qva.qva_flags = (VERIFY_DIGEST|VERIFY_SIGNATURE);
+#else
+ ::rpmtsSetVfyFlags( ts, RPMVSF_DEFAULT );
+#endif
+ RpmlogCapture vresult;
+ LocaleGuard guard( LC_ALL, "C" ); // bsc#1076415: rpm log output is localized, but we need to parse it :(
+ int res = ::rpmVerifySignatures( &qva, ts, fd, path_r.basename().c_str() );
+ guard.restore();
+
+ ts = rpmtsFree(ts);
+ ::Fclose( fd );
+
+ // results per line...
+ // Header V3 RSA/SHA256 Signature, key ID 3dbdc284: OK
+ // Header SHA1 digest: OK (a60386347863affefef484ff1f26c889373eb094)
+ // V3 RSA/SHA256 Signature, key ID 3dbdc284: OK
+ // MD5 digest: OK (fd5259fe677a406951dcb2e9d08c4dcc)
+ //
+ // TODO: try to get SIG info from the header rather than parsing the output
+ std::vector<std::string> lines;
+ str::split( vresult, std::back_inserter(lines), "\n" );
+ unsigned count[7] = { 0, 0, 0, 0, 0, 0, 0 };
+
+ for ( unsigned i = 1; i < lines.size(); ++i )
+ {
+ std::string & line( lines[i] );
+ RpmDb::CheckPackageResult lineres = RpmDb::CHK_ERROR;
+ if ( line.find( ": OK" ) != std::string::npos )
+ {
+ lineres = RpmDb::CHK_OK;
+ if ( line.find( "Signature, key ID" ) == std::string::npos )
+ ++count[RpmDb::CHK_NOSIG]; // Valid but no gpg signature -> CHK_NOSIG
+ }
+ else if ( line.find( ": NOKEY" ) != std::string::npos )
+ { lineres = RpmDb::CHK_NOKEY; }
+ else if ( line.find( ": BAD" ) != std::string::npos )
+ { lineres = RpmDb::CHK_FAIL; }
+ else if ( line.find( ": UNKNOWN" ) != std::string::npos )
+ { lineres = RpmDb::CHK_NOTFOUND; }
+ else if ( line.find( ": NOTRUSTED" ) != std::string::npos )
+ { lineres = RpmDb::CHK_NOTTRUSTED; }
+
+ ++count[lineres];
+ detail_r.push_back( RpmDb::CheckPackageDetail::value_type( lineres, std::move(line) ) );
+ }
+
+ RpmDb::CheckPackageResult ret = ( res ? RpmDb::CHK_ERROR : RpmDb::CHK_OK );
+
+ if ( count[RpmDb::CHK_FAIL] )
+ ret = RpmDb::CHK_FAIL;
+
+ else if ( count[RpmDb::CHK_NOTFOUND] )
+ ret = RpmDb::CHK_NOTFOUND;
+
+ else if ( count[RpmDb::CHK_NOKEY] )
+ ret = RpmDb::CHK_NOKEY;
+
+ else if ( count[RpmDb::CHK_NOTTRUSTED] )
+ ret = RpmDb::CHK_NOTTRUSTED;
+
+ else if ( ret == RpmDb::CHK_OK )
+ {
+ if ( count[RpmDb::CHK_OK] == count[RpmDb::CHK_NOSIG] )
+ {
+ detail_r.push_back( RpmDb::CheckPackageDetail::value_type( RpmDb::CHK_NOSIG, std::string(" ")+_("Package is not signed!") ) );
+ if ( requireGPGSig_r )
+ ret = RpmDb::CHK_NOSIG;
+ }
+ }
+
+ if ( ret != RpmDb::CHK_OK )
+ {
+ WAR << path_r << " (" << requireGPGSig_r << " -> " << ret << ")" << endl;
+ WAR << vresult;
+ }
+ return ret;
}
- ERR << "Error reading header." << file << endl;
- return CHK_ERROR;
-}
+
+} // namespace
+///////////////////////////////////////////////////////////////////
+//
+// METHOD NAME : RpmDb::checkPackage
+// METHOD TYPE : RpmDb::CheckPackageResult
+//
+RpmDb::CheckPackageResult RpmDb::checkPackage( const Pathname & path_r, CheckPackageDetail & detail_r )
+{ return doCheckPackageSig( path_r, root(), false/*requireGPGSig_r*/, detail_r ); }
+
+RpmDb::CheckPackageResult RpmDb::checkPackage( const Pathname & path_r )
+{ CheckPackageDetail dummy; return checkPackage( path_r, dummy ); }
+
+RpmDb::CheckPackageResult RpmDb::checkPackageSignature( const Pathname & path_r, RpmDb::CheckPackageDetail & detail_r )
+{ return doCheckPackageSig( path_r, root(), true/*requireGPGSig_r*/, detail_r ); }
+
// determine changed files of installed package
bool
-RpmDb::queryChangedFiles(FileList & fileList, const string& packageName)
+RpmDb::queryChangedFiles(FileList & fileList, const std::string& packageName)
{
bool ok = true;
M Mode (includes permissions and file type)
*/
- string line;
+ std::string line;
while (systemReadLine(line))
{
if (line.length() > 12 &&
(line[0] == '.' && line[7] == 'T')))
{
// file has been changed
- string filename;
+ std::string filename;
filename.assign(line, 11, line.length() - 11);
fileList.insert(filename);
/*--------------------------------------------------------------*/
/* Read a line from the rpm process */
/*--------------------------------------------------------------*/
-bool RpmDb::systemReadLine( string & line )
+bool RpmDb::systemReadLine( std::string & line )
{
line.erase();
{
if ( linebuffer[nread-1] == '\n' )
--nread;
- line += string( linebuffer, nread );
+ line += std::string( linebuffer, nread );
}
if ( ! ::ferror( inputfile ) || ::feof( inputfile ) )
// generate diff mails for config files
-void RpmDb::processConfigFiles(const string& line, const string& name, const char* typemsg, const char* difffailmsg, const char* diffgenmsg)
+void RpmDb::processConfigFiles(const std::string& line, const std::string& name, const char* typemsg, const char* difffailmsg, const char* diffgenmsg)
{
- string msg = line.substr(9);
- string::size_type pos1 = string::npos;
- string::size_type pos2 = string::npos;
- string file1s, file2s;
+ std::string msg = line.substr(9);
+ std::string::size_type pos1 = std::string::npos;
+ std::string::size_type pos2 = std::string::npos;
+ std::string file1s, file2s;
Pathname file1;
Pathname file2;
pos1 = msg.find (typemsg);
for (;;)
{
- if ( pos1 == string::npos )
+ if ( pos1 == std::string::npos )
break;
pos2 = pos1 + strlen (typemsg);
file2 = _root + file2;
}
- string out;
+ std::string out;
int ret = diffFiles (file1.asString(), file2.asString(), out, 25);
if (ret)
{
break;
}
file += Date(Date::now()).form("config_diff_%Y_%m_%d.log");
- ofstream notify(file.asString().c_str(), ios::out|ios::app);
+ std::ofstream notify(file.asString().c_str(), std::ios::out|std::ios::app);
if (!notify)
{
ERR << "Could not open " << file << endl;
{
out.replace(4, file1.asString().length(), file1s);
}
- string::size_type pos = out.find("\n+++ ");
- if (pos != string::npos)
+ std::string::size_type pos = out.find("\n+++ ");
+ if (pos != std::string::npos)
{
out.replace(pos+5, file2.asString().length(), file2s);
}
opts.push_back("-U");
opts.push_back("--percent");
+ opts.push_back("--noglob");
// ZConfig defines cross-arch installation
if ( ! ZConfig::instance().systemArchitecture().compatibleWith( ZConfig::instance().defaultSystemArchitecture() ) )
opts.push_back ("--justdb");
if (flags & RPMINST_TEST)
opts.push_back ("--test");
+ if (flags & RPMINST_NOPOSTTRANS)
+ opts.push_back ("--noposttrans");
opts.push_back("--");
// rpm requires additional quoting of special chars:
- string quotedFilename( rpmQuoteFilename( workaroundRpmPwdBug( filename ) ) );
+ std::string quotedFilename( rpmQuoteFilename( workaroundRpmPwdBug( filename ) ) );
opts.push_back ( quotedFilename.c_str() );
modifyDatabase(); // BEFORE run_rpm
run_rpm( opts, ExternalProgram::Stderr_To_Stdout );
- string line;
- string rpmmsg;
- vector<string> configwarnings;
+ std::string line;
+ std::string rpmmsg; // TODO: immediately forward lines via Callback::report rather than collecting
+ std::vector<std::string> configwarnings; // TODO: immediately process lines rather than collecting
unsigned linecnt = 0;
- while (systemReadLine(line))
+ while ( systemReadLine( line ) )
{
- if ( linecnt < MAXRPMMESSAGELINES )
- ++linecnt;
- else
- continue;
-
- if (line.substr(0,2)=="%%")
+ if ( str::startsWith( line, "%%" ) )
{
int percent;
- sscanf (line.c_str () + 2, "%d", &percent);
+ sscanf( line.c_str() + 2, "%d", &percent );
report->progress( percent );
+ continue;
}
- else
- rpmmsg += line+'\n';
- if ( line.substr(0,8) == "warning:" )
- {
+ if ( linecnt < MAXRPMMESSAGELINES )
+ ++linecnt;
+ else if ( line.find( " scriptlet failed, " ) == std::string::npos ) // always log %script errors
+ continue;
+
+ rpmmsg += line+'\n';
+
+ if ( str::startsWith( line, "warning:" ) )
configwarnings.push_back(line);
- }
}
- if ( linecnt > MAXRPMMESSAGELINES )
+ if ( linecnt >= MAXRPMMESSAGELINES )
rpmmsg += "[truncated]\n";
int rpm_status = systemStatus();
// evaluate result
- for (vector<string>::iterator it = configwarnings.begin();
+ for (std::vector<std::string>::iterator it = configwarnings.begin();
it != configwarnings.end(); ++it)
{
processConfigFiles(*it, Pathname::basename(filename), " saved as ",
historylog.comment(
str::form("%s install failed", Pathname::basename(filename).c_str()),
true /*timestamp*/);
- ostringstream sstr;
+ std::ostringstream sstr;
sstr << "rpm output:" << endl << rpmmsg << endl;
historylog.comment(sstr.str());
// TranslatorExplanation the colon is followed by an error message
- ZYPP_THROW(RpmSubprocessException(string(_("RPM failed: ")) +
- (rpmmsg.empty() ? error_message : rpmmsg)));
+ ZYPP_THROW(RpmSubprocessException(_("RPM failed: ") + (rpmmsg.empty() ? error_message : rpmmsg) ));
}
else if ( ! rpmmsg.empty() )
{
historylog.comment(
str::form("%s installed ok", Pathname::basename(filename).c_str()),
true /*timestamp*/);
- ostringstream sstr;
+ std::ostringstream sstr;
sstr << "Additional rpm output:" << endl << rpmmsg << endl;
historylog.comment(sstr.str());
// METHOD NAME : RpmDb::removePackage
// METHOD TYPE : PMError
//
-void RpmDb::removePackage( const string & name_r, RpmInstFlags flags )
+void RpmDb::removePackage( const std::string & name_r, RpmInstFlags flags )
{
callback::SendReport<RpmRemoveReport> report;
}
-void RpmDb::doRemovePackage( const string & name_r, RpmInstFlags flags, callback::SendReport<RpmRemoveReport> & report )
+void RpmDb::doRemovePackage( const std::string & name_r, RpmInstFlags flags, callback::SendReport<RpmRemoveReport> & report )
{
FAILIFNOTINITIALIZED;
HistoryLog historylog;
modifyDatabase(); // BEFORE run_rpm
run_rpm (opts, ExternalProgram::Stderr_To_Stdout);
- string line;
- string rpmmsg;
+ std::string line;
+ std::string rpmmsg; // TODO: immediately forward lines via Callback::report rather than collecting
// got no progress from command, so we fake it:
// 5 - command started
{
if ( linecnt < MAXRPMMESSAGELINES )
++linecnt;
- else
+ else if ( line.find( " scriptlet failed, " ) == std::string::npos ) // always log %script errors
continue;
rpmmsg += line+'\n';
}
- if ( linecnt > MAXRPMMESSAGELINES )
+ if ( linecnt >= MAXRPMMESSAGELINES )
rpmmsg += "[truncated]\n";
report->progress( 50 );
int rpm_status = systemStatus();
{
historylog.comment(
str::form("%s remove failed", name_r.c_str()), true /*timestamp*/);
- ostringstream sstr;
+ std::ostringstream sstr;
sstr << "rpm output:" << endl << rpmmsg << endl;
historylog.comment(sstr.str());
// TranslatorExplanation the colon is followed by an error message
- ZYPP_THROW(RpmSubprocessException(string(_("RPM failed: ")) +
- (rpmmsg.empty() ? error_message: rpmmsg)));
+ ZYPP_THROW(RpmSubprocessException(_("RPM failed: ") + (rpmmsg.empty() ? error_message: rpmmsg) ));
}
else if ( ! rpmmsg.empty() )
{
historylog.comment(
str::form("%s removed ok", name_r.c_str()), true /*timestamp*/);
- ostringstream sstr;
+ std::ostringstream sstr;
sstr << "Additional rpm output:" << endl << rpmmsg << endl;
historylog.comment(sstr.str());
// METHOD NAME : RpmDb::backupPackage
// METHOD TYPE : bool
//
-bool RpmDb::backupPackage(const string& packageName)
+bool RpmDb::backupPackage(const std::string& packageName)
{
HistoryLog progresslog;
bool ret = true;
return false;
}
- ofstream fp ( filestobackupfile.asString().c_str(), ios::out|ios::trunc );
+ std::ofstream fp ( filestobackupfile.asString().c_str(), std::ios::out|std::ios::trunc );
if (!fp)
{
for (FileList::const_iterator cit = fileList.begin();
cit != fileList.end(); ++cit)
{
- string name = *cit;
+ std::string name = *cit;
if ( name[0] == '/' )
{
// remove slash, file must be relative to -C parameter of tar
// execute tar in inst-sys (we dont know if there is a tar below _root !)
ExternalProgram tar(argv, ExternalProgram::Stderr_To_Stdout, false, -1, true);
- string tarmsg;
+ std::string tarmsg;
// TODO: its probably possible to start tar with -v and watch it adding
// files to report progress
- for (string output = tar.receiveLine(); output.length() ;output = tar.receiveLine())
+ for (std::string output = tar.receiveLine(); output.length() ;output = tar.receiveLine())
{
tarmsg+=output;
}
_backuppath = path;
}
+std::ostream & operator<<( std::ostream & str, RpmDb::CheckPackageResult obj )
+{
+ switch ( obj )
+ {
+#define OUTS(E,S) case RpmDb::E: return str << "["<< (unsigned)obj << "-"<< S << "]"; break
+ // translators: possible rpm package signature check result [brief]
+ OUTS( CHK_OK, _("Signature is OK") );
+ // translators: possible rpm package signature check result [brief]
+ OUTS( CHK_NOTFOUND, _("Unknown type of signature") );
+ // translators: possible rpm package signature check result [brief]
+ OUTS( CHK_FAIL, _("Signature does not verify") );
+ // translators: possible rpm package signature check result [brief]
+ OUTS( CHK_NOTTRUSTED, _("Signature is OK, but key is not trusted") );
+ // translators: possible rpm package signature check result [brief]
+ OUTS( CHK_NOKEY, _("Signatures public key is not available") );
+ // translators: possible rpm package signature check result [brief]
+ OUTS( CHK_ERROR, _("File does not exist or signature can't be checked") );
+ // translators: possible rpm package signature check result [brief]
+ OUTS( CHK_NOSIG, _("File is unsigned") );
+#undef OUTS
+ }
+ return str << "UnknowSignatureCheckError("+str::numstring(obj)+")";
+}
+
+std::ostream & operator<<( std::ostream & str, const RpmDb::CheckPackageDetail & obj )
+{
+ for ( const auto & el : obj )
+ str << el.second << endl;
+ return str;
+}
+
} // namespace rpm
} // namespace target
} // namespace zypp