1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/ZYppFactory.cc
19 #include "zypp/base/Logger.h"
20 #include "zypp/base/Gettext.h"
21 #include "zypp/base/IOStream.h"
22 #include "zypp/PathInfo.h"
24 #include "zypp/ZYppFactory.h"
25 #include "zypp/zypp_detail/ZYppImpl.h"
26 #include "zypp/zypp_detail/ZYppReadOnlyHack.h"
28 #define ZYPP_LOCK_FILE "/var/run/zypp.pid"
32 ///////////////////////////////////////////////////////////////////
34 { /////////////////////////////////////////////////////////////////
36 ///////////////////////////////////////////////////////////////////
37 namespace zypp_readonly_hack
38 { /////////////////////////////////////////////////////////////////
40 static bool active = false;
45 MIL << "ZYPP_READONLY promised." << endl;
48 /////////////////////////////////////////////////////////////////
49 } // namespace zypp_readonly_hack
50 ///////////////////////////////////////////////////////////////////
52 ///////////////////////////////////////////////////////////////////
54 // CLASS NAME : ZYppGlobalLock
56 ///////////////////////////////////////////////////////////////////
72 pid_t curr_pid = getpid();
75 Pathname lock_file = Pathname(ZYPP_LOCK_FILE);
81 MIL << "Cleaning lock file. (" << curr_pid << ")" << std::endl;
82 if ( filesystem::unlink(lock_file) == 0 )
83 MIL << "Lockfile cleaned. (" << curr_pid << ")" << std::endl;
85 ERR << "Cant clean lockfile. (" << curr_pid << ")" << std::endl;
89 catch(...) {} // let no exception escape.
92 pid_t locker_pid() const
93 { return _locker_pid; }
95 const std::string & locker_name() const
96 { return _locker_name; }
102 FILE *_zypp_lockfile;
104 std::string _locker_name;
106 void openLockFile(const char *mode)
108 Pathname lock_file = Pathname(ZYPP_LOCK_FILE);
109 _zypp_lockfile = fopen(lock_file.asString().c_str(), mode);
110 if (_zypp_lockfile == 0)
111 ZYPP_THROW (Exception( "Cant open " + lock_file.asString() + " in mode " + std::string(mode) ) );
116 fclose(_zypp_lockfile);
121 int fd = fileno(_zypp_lockfile);
122 int lock_error = flock(fd, LOCK_SH);
124 ZYPP_THROW (Exception( "Cant get shared lock"));
126 MIL << "locked (shared)" << std::endl;
131 int fd = fileno(_zypp_lockfile);
132 // lock access to the file
133 int lock_error = flock(fd, LOCK_EX);
135 ZYPP_THROW (Exception( "Cant get exclusive lock" ));
137 MIL << "locked (exclusive)" << std::endl;
142 int fd = fileno(_zypp_lockfile);
143 // lock access to the file
144 int lock_error = flock(fd, LOCK_UN);
146 ZYPP_THROW (Exception( "Cant release lock" ));
148 MIL << "unlocked" << std::endl;
151 bool lockFileExists()
153 Pathname lock_file = Pathname(ZYPP_LOCK_FILE);
154 // check if the file already existed.
155 bool exists = PathInfo(lock_file).isExist();
159 void createLockFile()
161 pid_t curr_pid = getpid();
164 fprintf(_zypp_lockfile, "%ld\n", (long) curr_pid);
165 fflush(_zypp_lockfile);
167 MIL << "written lockfile with pid " << curr_pid << std::endl;
171 bool isProcessRunning(pid_t pid_r)
173 // it is another program, not me, see if it is still running
174 Pathname procdir( "/proc"/str::numstring(pid_r) );
176 PathInfo status( procdir/"status" );
177 MIL << "Checking " << status << endl;
178 bool still_running = status.isExist();
182 Pathname p( procdir/"exe" );
183 _locker_name = filesystem::readlink( p ).asString();
184 MIL << p << " -> " << _locker_name << endl;
186 p = procdir/"cmdline";
188 std::ifstream infile( p.c_str() );
189 for( iostr::EachLine in( infile ); in; in.next() )
195 return still_running;
200 pid_t curr_pid = getpid();
201 pid_t locker_pid = 0;
204 fscanf(_zypp_lockfile, "%ld", &readpid);
205 MIL << "read: Lockfile " << ZYPP_LOCK_FILE << " has pid " << readpid << " (our pid: " << curr_pid << ") "<< std::endl;
206 locker_pid = (pid_t) readpid;
214 pid_t curr_pid = getpid();
215 Pathname lock_file = Pathname(ZYPP_LOCK_FILE);
217 if ( lockFileExists() )
219 MIL << "found lockfile " << lock_file << std::endl;
223 pid_t locker_pid = lockerPid();
224 _locker_pid = locker_pid;
225 if ( locker_pid == curr_pid )
227 // alles ok, we are requesting the instance again
228 //MIL << "Lockfile found, but it is myself. Assuming same process getting zypp instance again." << std::endl;
233 if ( isProcessRunning(locker_pid) )
235 if ( geteuid() == 0 )
238 MIL << locker_pid << " is running and has a ZYpp lock. Sorry" << std::endl;
243 MIL << locker_pid << " is running and has a ZYpp lock. Access as normal user allowed." << std::endl;
249 if ( geteuid() == 0 )
251 MIL << locker_pid << " has a ZYpp lock, but process is not running. Cleaning lock file." << std::endl;
252 if ( filesystem::unlink(lock_file) == 0 )
255 // now open it for reading
262 ERR << "Can't clean lockfile. Sorry, can't create a new lock. Zypp still locked." << std::endl;
268 MIL << locker_pid << " is running and has a ZYpp lock. Access as normal user allowed." << std::endl;
276 MIL << "no lockfile " << lock_file << " found" << std::endl;
277 if ( geteuid() == 0 )
279 MIL << "running as root. Will attempt to create " << lock_file << std::endl;
281 // now open it for reading
287 MIL << "running as user. Skipping creating " << lock_file << std::endl;
296 static ZYppGlobalLock globalLock;
298 ///////////////////////////////////////////////////////////////////
300 // CLASS NAME : ZYppFactoryException
302 ///////////////////////////////////////////////////////////////////
304 ZYppFactoryException::ZYppFactoryException( const std::string & msg_r, pid_t locker_pid )
306 _locker_pid (locker_pid)
309 ///////////////////////////////////////////////////////////////////
311 // CLASS NAME : ZYppFactory
313 ///////////////////////////////////////////////////////////////////
315 ///////////////////////////////////////////////////////////////////
317 // METHOD NAME : ZYppFactory::instance
318 // METHOD TYPE : ZYppFactory
320 ZYppFactory ZYppFactory::instance()
322 return ZYppFactory();
325 ///////////////////////////////////////////////////////////////////
327 // METHOD NAME : ZYppFactory::ZYppFactory
328 // METHOD TYPE : Ctor
330 ZYppFactory::ZYppFactory()
335 ///////////////////////////////////////////////////////////////////
337 // METHOD NAME : ZYppFactory::~ZYppFactory
338 // METHOD TYPE : Dtor
340 ZYppFactory::~ZYppFactory()
343 ///////////////////////////////////////////////////////////////////
345 ZYpp::Ptr ZYppFactory::getZYpp() const
347 static ZYpp::Ptr _instance;
351 /*--------------------------------------------------*/
352 if ( zypp_readonly_hack::active )
354 _instance = new ZYpp( ZYpp::Impl_Ptr(new ZYpp::Impl) );
355 MIL << "ZYPP_READONLY active." << endl;
358 /*--------------------------------------------------*/
359 if ( globalLock.zyppLocked() )
361 std::string t = str::form(_("System management is locked by the application with pid %d (%s).\n"
362 "Close this application before trying again."),
363 globalLock.locker_pid(),
364 globalLock.locker_name().c_str()
366 ZYPP_THROW(ZYppFactoryException(t, globalLock.locker_pid()));
370 _instance = new ZYpp( ZYpp::Impl_Ptr(new ZYpp::Impl) );
371 globalLock._clean_lock = true;
378 /******************************************************************
380 ** FUNCTION NAME : operator<<
381 ** FUNCTION TYPE : std::ostream &
383 std::ostream & operator<<( std::ostream & str, const ZYppFactory & obj )
385 return str << "ZYppFactory";
388 /////////////////////////////////////////////////////////////////
390 ///////////////////////////////////////////////////////////////////