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 { return _locker_pid; }
100 void openLockFile(const char *mode)
102 Pathname lock_file = Pathname(ZYPP_LOCK_FILE);
103 _zypp_lockfile = fopen(lock_file.asString().c_str(), mode);
104 if (_zypp_lockfile == 0)
105 ZYPP_THROW (Exception( "Cant open " + lock_file.asString() + " in mode " + std::string(mode) ) );
110 fclose(_zypp_lockfile);
115 int fd = fileno(_zypp_lockfile);
116 int lock_error = flock(fd, LOCK_SH);
118 ZYPP_THROW (Exception( "Cant get shared lock"));
120 MIL << "locked (shared)" << std::endl;
125 int fd = fileno(_zypp_lockfile);
126 // lock access to the file
127 int lock_error = flock(fd, LOCK_EX);
129 ZYPP_THROW (Exception( "Cant get exclusive lock" ));
131 MIL << "locked (exclusive)" << std::endl;
136 int fd = fileno(_zypp_lockfile);
137 // lock access to the file
138 int lock_error = flock(fd, LOCK_UN);
140 ZYPP_THROW (Exception( "Cant release lock" ));
142 MIL << "unlocked" << std::endl;
145 bool lockFileExists()
147 Pathname lock_file = Pathname(ZYPP_LOCK_FILE);
148 // check if the file already existed.
149 bool exists = PathInfo(lock_file).isExist();
153 void createLockFile()
155 pid_t curr_pid = getpid();
158 fprintf(_zypp_lockfile, "%ld\n", (long) curr_pid);
159 fflush(_zypp_lockfile);
161 MIL << "written lockfile with pid " << curr_pid << std::endl;
165 bool isProcessRunning(pid_t pid_r)
167 // it is another program, not me, see if it is still running
168 Pathname procdir( "/proc"/str::numstring(pid_r) );
170 PathInfo status( procdir/"status" );
171 MIL << "Checking " << status << endl;
172 bool still_running = status.isExist();
176 Pathname p( procdir/"exe" );
177 MIL << p << " -> " << filesystem::readlink( p ) << endl;
179 p = procdir/"cmdline";
181 std::ifstream infile( p.c_str() );
182 for( iostr::EachLine in( infile ); in; in.next() )
188 return still_running;
193 pid_t curr_pid = getpid();
194 pid_t locker_pid = 0;
197 fscanf(_zypp_lockfile, "%ld", &readpid);
198 MIL << "read: Lockfile " << ZYPP_LOCK_FILE << " has pid " << readpid << " (our pid: " << curr_pid << ") "<< std::endl;
199 locker_pid = (pid_t) readpid;
207 pid_t curr_pid = getpid();
208 Pathname lock_file = Pathname(ZYPP_LOCK_FILE);
210 if ( lockFileExists() )
212 MIL << "found lockfile " << lock_file << std::endl;
216 pid_t locker_pid = lockerPid();
217 _locker_pid = locker_pid;
218 if ( locker_pid == curr_pid )
220 // alles ok, we are requesting the instance again
221 //MIL << "Lockfile found, but it is myself. Assuming same process getting zypp instance again." << std::endl;
226 if ( isProcessRunning(locker_pid) )
228 if ( geteuid() == 0 )
231 MIL << locker_pid << " is running and has a ZYpp lock. Sorry" << std::endl;
236 MIL << locker_pid << " is running and has a ZYpp lock. Access as normal user allowed." << std::endl;
242 if ( geteuid() == 0 )
244 MIL << locker_pid << " has a ZYpp lock, but process is not running. Cleaning lock file." << std::endl;
245 if ( filesystem::unlink(lock_file) == 0 )
248 // now open it for reading
255 ERR << "Can't clean lockfile. Sorry, can't create a new lock. Zypp still locked." << std::endl;
261 MIL << locker_pid << " is running and has a ZYpp lock. Access as normal user allowed." << std::endl;
269 MIL << "no lockfile " << lock_file << " found" << std::endl;
270 if ( geteuid() == 0 )
272 MIL << "running as root. Will attempt to create " << lock_file << std::endl;
274 // now open it for reading
280 MIL << "running as user. Skipping creating " << lock_file << std::endl;
289 static ZYppGlobalLock globalLock;
291 ///////////////////////////////////////////////////////////////////
293 // CLASS NAME : ZYppFactoryException
295 ///////////////////////////////////////////////////////////////////
297 ZYppFactoryException::ZYppFactoryException( const std::string & msg_r, pid_t locker_pid )
299 _locker_pid (locker_pid)
302 ///////////////////////////////////////////////////////////////////
304 // CLASS NAME : ZYppFactory
306 ///////////////////////////////////////////////////////////////////
308 ///////////////////////////////////////////////////////////////////
310 // METHOD NAME : ZYppFactory::instance
311 // METHOD TYPE : ZYppFactory
313 ZYppFactory ZYppFactory::instance()
315 return ZYppFactory();
318 ///////////////////////////////////////////////////////////////////
320 // METHOD NAME : ZYppFactory::ZYppFactory
321 // METHOD TYPE : Ctor
323 ZYppFactory::ZYppFactory()
328 ///////////////////////////////////////////////////////////////////
330 // METHOD NAME : ZYppFactory::~ZYppFactory
331 // METHOD TYPE : Dtor
333 ZYppFactory::~ZYppFactory()
336 ///////////////////////////////////////////////////////////////////
338 ZYpp::Ptr ZYppFactory::getZYpp() const
340 static ZYpp::Ptr _instance;
344 /*--------------------------------------------------*/
345 if ( zypp_readonly_hack::active )
347 _instance = new ZYpp( ZYpp::Impl_Ptr(new ZYpp::Impl) );
348 MIL << "ZYPP_READONLY active." << endl;
351 /*--------------------------------------------------*/
352 if ( globalLock.zyppLocked() )
354 std::string t = str::form(N_("System management is locked by the application with pid %d. "
355 "Please close this application before trying again."),
356 globalLock.locker_pid());
357 ZYPP_THROW(ZYppFactoryException(t, globalLock.locker_pid()));
361 _instance = new ZYpp( ZYpp::Impl_Ptr(new ZYpp::Impl) );
362 globalLock._clean_lock = true;
369 /******************************************************************
371 ** FUNCTION NAME : operator<<
372 ** FUNCTION TYPE : std::ostream &
374 std::ostream & operator<<( std::ostream & str, const ZYppFactory & obj )
376 return str << "ZYppFactory";
379 /////////////////////////////////////////////////////////////////
381 ///////////////////////////////////////////////////////////////////