}
#include <iostream>
#include <fstream>
+#include <signal.h>
#include "zypp/base/Logger.h"
#include "zypp/base/Gettext.h"
#include "zypp/base/IOStream.h"
#include "zypp/base/Functional.h"
+#include "zypp/base/Backtrace.h"
#include "zypp/PathInfo.h"
#include "zypp/ZYppFactory.h"
namespace zypp
{ /////////////////////////////////////////////////////////////////
+ namespace
+ {
+ void sigsegvHandler( int sig );
+ ::sighandler_t lastSigsegvHandler = ::signal( SIGSEGV, sigsegvHandler );
+
+ /** SIGSEGV handler to log stack trace */
+ void sigsegvHandler( int sig )
+ {
+ INT << "Error: signal " << sig << endl << dumpBacktrace << endl;
+ ::signal( SIGSEGV, lastSigsegvHandler );
+ }
+ }
+
namespace env
{
/** Hack to circumvent the currently poor --root support. */
namespace zypp_readonly_hack
{ /////////////////////////////////////////////////////////////////
- static bool active = false;
+ static bool active = getenv("ZYPP_READONLY_HACK");
void IWantIt()
{
MIL << "ZYPP_READONLY promised." << endl;
}
+ bool IGotIt()
+ {
+ return active;
+ }
+
/////////////////////////////////////////////////////////////////
} // namespace zypp_readonly_hack
///////////////////////////////////////////////////////////////////
{
public:
ZYppGlobalLock()
- : _cleanLock( false )
- , _zyppLockFilePath( env::ZYPP_LOCKFILE_ROOT() / "/var/run/zypp.pid" )
+ : _zyppLockFilePath( env::ZYPP_LOCKFILE_ROOT() / "/var/run/zypp.pid" )
, _zyppLockFile( NULL )
, _lockerPid( 0 )
+ , _cleanLock( false )
{
filesystem::assert_dir(_zyppLockFilePath.dirname() );
}
};
+ ///////////////////////////////////////////////////////////////////
namespace
{
- static ZYppGlobalLock & globalLock()
+ static weak_ptr<ZYpp> _theZYppInstance;
+ static scoped_ptr<ZYppGlobalLock> _theGlobalLock; // on/off in sync with _theZYppInstance
+
+ ZYppGlobalLock & globalLock()
{
- static ZYppGlobalLock lock;
- return lock;
+ if ( !_theGlobalLock )
+ _theGlobalLock.reset( new ZYppGlobalLock );
+ return *_theGlobalLock;
}
- bool _haveZYpp = false;
+ } //namespace
+ ///////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////
+ //
+ // CLASS NAME : ZYpp
+ //
+ ///////////////////////////////////////////////////////////////////
+
+ ZYpp::ZYpp( const Impl_Ptr & impl_r )
+ : _pimpl( impl_r )
+ {
+ }
+
+ ZYpp::~ZYpp()
+ {
+ _theGlobalLock.reset();
}
///////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////
- //
- // METHOD NAME : ZYppFactory::instance
- // METHOD TYPE : ZYppFactory
- //
ZYppFactory ZYppFactory::instance()
- {
- return ZYppFactory();
- }
+ { return ZYppFactory(); }
- ///////////////////////////////////////////////////////////////////
- //
- // METHOD NAME : ZYppFactory::ZYppFactory
- // METHOD TYPE : Ctor
- //
ZYppFactory::ZYppFactory()
- {
-
- }
+ {}
- ///////////////////////////////////////////////////////////////////
- //
- // METHOD NAME : ZYppFactory::~ZYppFactory
- // METHOD TYPE : Dtor
- //
ZYppFactory::~ZYppFactory()
{}
//
ZYpp::Ptr ZYppFactory::getZYpp() const
{
- static ZYpp::Ptr _instance;
-
+ ZYpp::Ptr _instance = _theZYppInstance.lock();
if ( ! _instance )
{
if ( geteuid() != 0 )
}
else if ( globalLock().zyppLocked() )
{
- std::string t = str::form(_("System management is locked by the application with pid %d (%s).\n"
- "Close this application before trying again."),
- globalLock().lockerPid(),
- globalLock().lockerName().c_str()
- );
- ZYPP_THROW(ZYppFactoryException(t, globalLock().lockerPid(), globalLock().lockerName() ));
+ bool failed = true;
+ const long LOCK_TIMEOUT = str::strtonum<long>( getenv( "ZYPP_LOCK_TIMEOUT" ) );
+ if ( LOCK_TIMEOUT > 0 )
+ {
+ MIL << "Waiting whether pid " << globalLock().lockerPid() << " ends within $LOCK_TIMEOUT=" << LOCK_TIMEOUT << " sec." << endl;
+ unsigned delay = 1;
+ Pathname procdir( "/proc"/str::numstring(globalLock().lockerPid()) );
+ for ( long i = 0; i < LOCK_TIMEOUT; i += delay )
+ {
+ if ( PathInfo( procdir ).isDir() ) // wait for /proc/pid to disapear
+ sleep( delay );
+ else
+ {
+ MIL << "Retry after " << i << " sec." << endl;
+ failed = globalLock().zyppLocked();
+ if ( failed )
+ {
+ // another proc locked faster. maybe it ends fast as well....
+ MIL << "Waiting whether pid " << globalLock().lockerPid() << " ends within " << (LOCK_TIMEOUT-i) << " sec." << endl;
+ procdir = Pathname( "/proc"/str::numstring(globalLock().lockerPid()) );
+ }
+ else
+ {
+ MIL << "Finally got the lock!" << endl;
+ break; // gotcha
+ }
+ }
+ }
+ }
+ if ( failed )
+ {
+ std::string t = str::form(_("System management is locked by the application with pid %d (%s).\n"
+ "Close this application before trying again."),
+ globalLock().lockerPid(),
+ globalLock().lockerName().c_str()
+ );
+ ZYPP_THROW(ZYppFactoryException(t, globalLock().lockerPid(), globalLock().lockerName() ));
+ }
}
// Here we go...
- _instance = new ZYpp( ZYpp::Impl_Ptr(new ZYpp::Impl) );
- if ( _instance )
- _haveZYpp = true;
+ static ZYpp::Impl_Ptr _theImplInstance; // for now created once
+ if ( !_theImplInstance )
+ _theImplInstance.reset( new ZYpp::Impl );
+ _instance.reset( new ZYpp( _theImplInstance ) );
+ _theZYppInstance = _instance;
}
return _instance;
///////////////////////////////////////////////////////////////////
//
bool ZYppFactory::haveZYpp() const
- { return _haveZYpp; }
+ { return !_theZYppInstance.expired(); }
/******************************************************************
**