libzypp 17.31.23
ZYppFactory.cc
Go to the documentation of this file.
1/*---------------------------------------------------------------------\
2| ____ _ __ __ ___ |
3| |__ / \ / / . \ . \ |
4| / / \ V /| _/ _/ |
5| / /__ | | | | | | |
6| /_____||_| |_| |_| |
7| |
8\---------------------------------------------------------------------*/
12extern "C"
13{
14#include <sys/file.h>
15}
16#include <iostream>
17#include <fstream>
18#include <signal.h>
19
20#include <zypp/base/Logger.h>
21#include <zypp/base/LogControl.h>
22#include <zypp/base/Gettext.h>
23#include <zypp/base/IOStream.h>
25#include <zypp/base/Backtrace.h>
26#include <zypp/base/LogControl.h>
27#include <zypp/PathInfo.h>
28
29#include <zypp/ZYppFactory.h>
31
32#include <boost/interprocess/sync/file_lock.hpp>
33#include <boost/interprocess/sync/scoped_lock.hpp>
34#include <boost/interprocess/sync/sharable_lock.hpp>
35
36#include <iostream>
37
38using boost::interprocess::file_lock;
39using boost::interprocess::scoped_lock;
40using boost::interprocess::sharable_lock;
41
42using std::endl;
43
44namespace zyppintern { void repoVariablesReset(); } // upon re-acquiring the lock...
45
47namespace zypp
48{
49
50 namespace sighandler
51 {
53 template <int SIG>
55 {
56 static void backtraceHandler( int sig ) {
57 INT << "Error: signal " << SIG << endl << dumpBacktrace << endl;
59 ::signal( SIG, lastSigHandler );
60 }
61 static ::sighandler_t lastSigHandler;
62 };
63 template <int SIG>
65
66 // Explicit instantiation installs the handler:
67 template class SigBacktraceHandler<SIGSEGV>;
68 template class SigBacktraceHandler<SIGABRT>;
69 }
70
71 namespace env
72 {
75 { return getenv("ZYPP_LOCKFILE_ROOT") ? getenv("ZYPP_LOCKFILE_ROOT") : "/"; }
76 }
77
79 namespace zypp_readonly_hack
80 {
81
82 static bool active = getenv("ZYPP_READONLY_HACK");
83
84 void IWantIt() // see zypp/zypp_detail/ZYppReadOnlyHack.h
85 {
86 active = true;
87 MIL << "ZYPP_READONLY promised." << endl;
88 }
89
90 bool IGotIt()
91 {
92 return active;
93 }
94
96 } // namespace zypp_readonly_hack
98
105 {
106 public:
108 : _zyppLockFilePath( std::move(lFilePath) )
109 , _zyppLockFile( NULL )
110 , _lockerPid( 0 )
111 , _cleanLock( false )
112 {
113 filesystem::assert_dir(_zyppLockFilePath.dirname() );
114 }
115
117 {
118 if ( _cleanLock )
119 try {
120 // Exception safe access to the lockfile.
121 ScopedGuard closeOnReturn( accessLockFile() );
122 {
123 scoped_lock<file_lock> flock( _zyppLockFileLock ); // aquire write lock
124 // Truncate the file rather than deleting it. Other processes may
125 // still use it to synchronsize.
126 ftruncate( fileno(_zyppLockFile), 0 );
127 }
128 MIL << "Cleaned lock file. (" << getpid() << ")" << std::endl;
129 }
130 catch(...) {} // let no exception escape.
131 }
132
133 pid_t lockerPid() const
134 { return _lockerPid; }
135
136 const std::string & lockerName() const
137 { return _lockerName; }
138
140 { return _zyppLockFilePath; }
141
142
143 private:
147
149 std::string _lockerName;
151
152 private:
153 typedef shared_ptr<void> ScopedGuard;
154
162 {
163 _openLockFile();
164 return ScopedGuard( static_cast<void*>(0),
165 std::bind( std::mem_fn( &ZYppGlobalLock::_closeLockFile ), this ) );
166 }
167
170 {
171 if ( _zyppLockFile != NULL )
172 return; // is open
173
174 // open pid file rw so we are sure it exist when creating the flock
175 _zyppLockFile = fopen( _zyppLockFilePath.c_str(), "a+" );
176 if ( _zyppLockFile == NULL )
177 ZYPP_THROW( Exception( "Cant open " + _zyppLockFilePath.asString() ) );
178 _zyppLockFileLock = _zyppLockFilePath.c_str();
179 MIL << "Open lockfile " << _zyppLockFilePath << endl;
180 }
181
184 {
185 if ( _zyppLockFile == NULL )
186 return; // is closed
187
188 clearerr( _zyppLockFile );
189 fflush( _zyppLockFile );
190 // http://www.boost.org/doc/libs/1_50_0/doc/html/interprocess/synchronization_mechanisms.html
191 // If you are using a std::fstream/native file handle to write to the file
192 // while using file locks on that file, don't close the file before releasing
193 // all the locks of the file.
194 _zyppLockFileLock = file_lock();
195 fclose( _zyppLockFile );
196 _zyppLockFile = NULL;
197 MIL << "Close lockfile " << _zyppLockFilePath << endl;
198 }
199
200
201 bool isProcessRunning( pid_t pid_r )
202 {
203 // it is another program, not me, see if it is still running
204 Pathname procdir( Pathname("/proc")/str::numstring(pid_r) );
205 PathInfo status( procdir );
206 MIL << "Checking " << status << endl;
207
208 if ( ! status.isDir() )
209 {
210 DBG << "No such process." << endl;
211 return false;
212 }
213
214 static char buffer[513];
215 buffer[0] = buffer[512] = 0;
216 // man proc(5): /proc/[pid]/cmdline is empty if zombie.
217 if ( std::ifstream( (procdir/"cmdline").c_str() ).read( buffer, 512 ).gcount() > 0 )
218 {
219 _lockerName = buffer;
220 DBG << "Is running: " << _lockerName << endl;
221 return true;
222 }
223
224 DBG << "In zombie state." << endl;
225 return false;
226 }
227
229 {
230 clearerr( _zyppLockFile );
231 fseek( _zyppLockFile, 0, SEEK_SET );
232 long readpid = 0;
233 fscanf( _zyppLockFile, "%ld", &readpid );
234 MIL << "read: Lockfile " << _zyppLockFilePath << " has pid " << readpid << " (our pid: " << getpid() << ") "<< std::endl;
235 return (pid_t)readpid;
236 }
237
239 {
240 clearerr( _zyppLockFile );
241 fseek( _zyppLockFile, 0, SEEK_SET );
242 ftruncate( fileno(_zyppLockFile), 0 );
243 fprintf(_zyppLockFile, "%ld\n", (long)getpid() );
244 fflush( _zyppLockFile );
245 _cleanLock = true; // cleanup on exit
246 MIL << "write: Lockfile " << _zyppLockFilePath << " got pid " << getpid() << std::endl;
247 }
248
253 {
254 _lockerPid = readLockFile();
255 if ( _lockerPid == 0 ) {
256 // no or empty lock file
257 return false;
258 } else if ( _lockerPid == getpid() ) {
259 // keep my own lock
260 return false;
261 } else {
262 // a foreign pid in lock
263 if ( isProcessRunning( _lockerPid ) ) {
264 WAR << _lockerPid << " is running and has a ZYpp lock. Sorry." << std::endl;
265 return true;
266 } else {
267 MIL << _lockerPid << " is dead. Ignoring the existing lock file." << std::endl;
268 return false;
269 }
270 }
271 }
272
273 public:
274
276 {
277 if ( geteuid() != 0 )
278 return false; // no lock as non-root
279
280 // Exception safe access to the lockfile.
281 ScopedGuard closeOnReturn( accessLockFile() );
282 scoped_lock<file_lock> flock( _zyppLockFileLock ); // aquire write lock
283 return safeCheckIsLocked ();
284 }
285
290 {
291 if ( geteuid() != 0 )
292 return false; // no lock as non-root
293
294 // Exception safe access to the lockfile.
295 ScopedGuard closeOnReturn( accessLockFile() );
296 scoped_lock<file_lock> flock( _zyppLockFileLock ); // aquire write lock
297 if ( !safeCheckIsLocked() ) {
298 writeLockFile();
299 return false;
300 }
301 return true;
302 }
303
304 };
305
307 namespace
308 {
309 static weak_ptr<ZYpp> _theZYppInstance;
310 static scoped_ptr<ZYppGlobalLock> _theGlobalLock; // on/off in sync with _theZYppInstance
311
312 ZYppGlobalLock & globalLock()
313 {
314 if ( !_theGlobalLock )
315 _theGlobalLock.reset( new ZYppGlobalLock( ZYppFactory::lockfileDir() / "zypp.pid" ) );
316 return *_theGlobalLock;
317 }
318 } //namespace
320
322 //
323 // CLASS NAME : ZYpp
324 //
326
327 ZYpp::ZYpp( const Impl_Ptr & impl_r )
328 : _pimpl( impl_r )
329 {
330 ::zyppintern::repoVariablesReset(); // upon re-acquiring the lock...
331 MIL << "ZYpp is on..." << endl;
332 }
333
335 {
336 _theGlobalLock.reset();
337 MIL << "ZYpp is off..." << endl;
338 }
339
341 //
342 // CLASS NAME : ZYppFactoryException
343 //
345
346 ZYppFactoryException::ZYppFactoryException( const std::string & msg_r, pid_t lockerPid_r, const std::string & lockerName_r )
347 : Exception( msg_r )
348 , _lockerPid( lockerPid_r )
349 , _lockerName( lockerName_r )
350 {}
351
353 {}
354
356 //
357 // CLASS NAME : ZYppFactory
358 //
360
362 { return ZYppFactory(); }
363
365 {}
366
368 {}
369
371 //
373 {
374
375 const auto &makeLockedError = []( pid_t pid, const std::string &lockerName ){
376 const std::string &t = str::form(_("System management is locked by the application with pid %d (%s).\n"
377 "Close this application before trying again."), pid, lockerName.c_str() );
378 return ZYppFactoryException(t, pid, lockerName );
379 };
380
381 ZYpp::Ptr _instance = _theZYppInstance.lock();
382 if ( ! _instance )
383 {
384 if ( geteuid() != 0 )
385 {
386 MIL << "Running as user. Skip creating " << globalLock().zyppLockFilePath() << std::endl;
387 }
389 {
390 MIL << "ZYPP_READONLY active." << endl;
391 }
392 else if ( globalLock().zyppLocked() )
393 {
394 bool failed = true;
395 // bsc#1184399,1213231: A negative ZYPP_LOCK_TIMEOUT will wait forever.
396 const long LOCK_TIMEOUT = str::strtonum<long>( getenv( "ZYPP_LOCK_TIMEOUT" ) );
397 if ( LOCK_TIMEOUT != 0 )
398 {
399 Date logwait = Date::now();
400 Date giveup; /* 0 = forever */
401 if ( LOCK_TIMEOUT > 0 ) {
402 giveup = logwait+LOCK_TIMEOUT;
403 MIL << "$ZYPP_LOCK_TIMEOUT=" << LOCK_TIMEOUT << " sec. Waiting for the zypp lock until " << giveup << endl;
404 }
405 else
406 MIL << "$ZYPP_LOCK_TIMEOUT=" << LOCK_TIMEOUT << " sec. Waiting for the zypp lock..." << endl;
407
408 unsigned delay = 0;
409 do {
410 if ( delay < 60 )
411 delay += 1;
412 else {
413 Date now { Date::now() };
414 if ( now - logwait > Date::day ) {
415 WAR << "$ZYPP_LOCK_TIMEOUT=" << LOCK_TIMEOUT << " sec. Another day has passed waiting for the zypp lock..." << endl;
416 logwait = now;
417 }
418 }
419 sleep( delay );
420 {
421 zypp::base::LogControl::TmpLineWriter shutUp; // be quiet
422 failed = globalLock().zyppLocked();
423 }
424 } while ( failed && ( not giveup || Date::now() <= giveup ) );
425
426 if ( failed ) {
427 MIL << "$ZYPP_LOCK_TIMEOUT=" << LOCK_TIMEOUT << " sec. Gave up waiting for the zypp lock." << endl;
428 }
429 else {
430 MIL << "$ZYPP_LOCK_TIMEOUT=" << LOCK_TIMEOUT << " sec. Finally got the zypp lock." << endl;
431 }
432 }
433 if ( failed )
434 ZYPP_THROW( makeLockedError( globalLock().lockerPid(), globalLock().lockerName() ));
435
436 // we got the global lock, now make sure zypp-rpm is not still running
437 {
438 ZYppGlobalLock zyppRpmLock( ZYppFactory::lockfileDir() / "zypp-rpm.pid" );
439 if ( zyppRpmLock.isZyppLocked () ) {
440 // release global lock, we will exit now
441 _theGlobalLock.reset();
442 ZYPP_THROW( makeLockedError( zyppRpmLock.lockerPid(), zyppRpmLock.lockerName() ));
443 }
444 }
445 }
446
447 // Here we go...
448 static ZYpp::Impl_Ptr _theImplInstance; // for now created once
449 if ( !_theImplInstance )
450 _theImplInstance.reset( new ZYpp::Impl );
451 _instance.reset( new ZYpp( _theImplInstance ) );
452 _theZYppInstance = _instance;
453 }
454
455 return _instance;
456 }
457
459 //
461 { return !_theZYppInstance.expired(); }
462
464 {
465 return env::ZYPP_LOCKFILE_ROOT() / "run";
466 }
467
468 /******************************************************************
469 **
470 ** FUNCTION NAME : operator<<
471 ** FUNCTION TYPE : std::ostream &
472 */
473 std::ostream & operator<<( std::ostream & str, const ZYppFactory & obj )
474 {
475 return str << "ZYppFactory";
476 }
477
479} // namespace zypp
Store and operate on date (time_t).
Definition: Date.h:33
static const ValueType day
Definition: Date.h:44
static Date now()
Return the current time.
Definition: Date.h:78
Base class for Exception.
Definition: Exception.h:146
ZYppFactoryException(const std::string &msg_r, pid_t lockerPid_r, const std::string &lockerName_r)
Definition: ZYppFactory.cc:346
ZYpp factory class (Singleton)
Definition: ZYppFactory.h:44
static ZYppFactory instance()
Singleton ctor.
Definition: ZYppFactory.cc:361
bool haveZYpp() const
Whether the ZYpp instance is already created.
Definition: ZYppFactory.cc:460
ZYpp::Ptr getZYpp() const
Definition: ZYppFactory.cc:372
ZYppFactory()
Default ctor.
Definition: ZYppFactory.cc:364
static zypp::Pathname lockfileDir()
Definition: ZYppFactory.cc:463
Our broken global lock.
Definition: ZYppFactory.cc:105
const std::string & lockerName() const
Definition: ZYppFactory.cc:136
void _closeLockFile()
Use accessLockFile.
Definition: ZYppFactory.cc:183
std::string _lockerName
Definition: ZYppFactory.cc:149
file_lock _zyppLockFileLock
Definition: ZYppFactory.cc:145
void _openLockFile()
Use accessLockFile.
Definition: ZYppFactory.cc:169
shared_ptr< void > ScopedGuard
Definition: ZYppFactory.cc:153
pid_t lockerPid() const
Definition: ZYppFactory.cc:133
bool zyppLocked()
Try to aquire a lock.
Definition: ZYppFactory.cc:289
ScopedGuard accessLockFile()
Exception safe access to the lockfile.
Definition: ZYppFactory.cc:161
Pathname _zyppLockFilePath
Definition: ZYppFactory.cc:144
const Pathname & zyppLockFilePath() const
Definition: ZYppFactory.cc:139
bool isProcessRunning(pid_t pid_r)
Definition: ZYppFactory.cc:201
ZYppGlobalLock(Pathname &&lFilePath)
Definition: ZYppFactory.cc:107
shared_ptr< Impl > Impl_Ptr
Definition: ZYpp.h:151
~ZYpp()
Dtor.
Definition: ZYppFactory.cc:334
ZYpp(const Impl_Ptr &impl_r)
Factory ctor.
Definition: ZYppFactory.cc:327
::boost::shared_ptr< ZYpp > Ptr
Definition: ZYpp.h:64
void emergencyShutdown()
will cause the log thread to exit and flush all sockets
Definition: LogControl.cc:902
static LogControl instance()
Singleton access.
Definition: LogControl.h:102
Wrapper class for stat/lstat.
Definition: PathInfo.h:221
const char * c_str() const
String representation.
Definition: Pathname.h:110
const std::string & asString() const
String representation.
Definition: Pathname.h:91
Signal handler logging a stack trace.
Definition: ZYppFactory.cc:55
static void backtraceHandler(int sig)
Definition: ZYppFactory.cc:56
Definition: Arch.h:361
String related utilities and Regular expression matching.
Pathname ZYPP_LOCKFILE_ROOT()
Hack to circumvent the currently poor –root support.
Definition: ZYppFactory.cc:74
int assert_dir(const Pathname &path, unsigned mode)
Like 'mkdir -p'.
Definition: PathInfo.cc:319
std::string numstring(char n, int w=0)
Definition: String.h:289
std::string form(const char *format,...) __attribute__((format(printf
Printf style construction of std::string.
Definition: String.cc:36
void IWantIt() ZYPP_DEPRECATED
Definition: ZYppFactory.cc:84
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc:2
std::ostream & dumpBacktrace(std::ostream &stream_r)
Dump current stack trace to a stream.
Definition: Backtrace.cc:24
std::ostream & operator<<(std::ostream &str, const SerialNumber &obj)
Definition: SerialNumber.cc:52
void repoVariablesReset()
Exchange LineWriter for the lifetime of this object.
Definition: LogControl.h:191
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:428
#define _(MSG)
Definition: Gettext.h:37
#define DBG
Definition: Logger.h:95
#define MIL
Definition: Logger.h:96
#define WAR
Definition: Logger.h:97
#define INT
Definition: Logger.h:100