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"
30 ///////////////////////////////////////////////////////////////////
32 { /////////////////////////////////////////////////////////////////
36 /** Hack to circumvent the currently poor --root support. */
37 inline Pathname ZYPP_LOCKFILE_ROOT()
38 { return getenv("ZYPP_LOCKFILE_ROOT") ? getenv("ZYPP_LOCKFILE_ROOT") : "/"; }
41 ///////////////////////////////////////////////////////////////////
42 namespace zypp_readonly_hack
43 { /////////////////////////////////////////////////////////////////
45 static bool active = false;
50 MIL << "ZYPP_READONLY promised." << endl;
53 /////////////////////////////////////////////////////////////////
54 } // namespace zypp_readonly_hack
55 ///////////////////////////////////////////////////////////////////
57 ///////////////////////////////////////////////////////////////////
59 // CLASS NAME : ZYppGlobalLock
61 ///////////////////////////////////////////////////////////////////
69 , _zyppLockFilePath( env::ZYPP_LOCKFILE_ROOT() / "/var/run/zypp.pid" )
73 filesystem::assert_dir(_zyppLockFilePath.dirname());
80 pid_t curr_pid = getpid();
88 MIL << "Cleaning lock file. (" << curr_pid << ")" << std::endl;
89 if ( filesystem::unlink(_zyppLockFilePath) == 0 )
90 MIL << "Lockfile cleaned. (" << curr_pid << ")" << std::endl;
92 ERR << "Cant clean lockfile. (" << curr_pid << ")" << std::endl;
96 catch(...) {} // let no exception escape.
99 pid_t locker_pid() const
100 { return _locker_pid; }
102 const std::string & locker_name() const
103 { return _locker_name; }
109 Pathname _zyppLockFilePath;
110 FILE *_zypp_lockfile;
112 std::string _locker_name;
114 void openLockFile(const char *mode)
117 _zypp_lockfile = fopen(_zyppLockFilePath.asString().c_str(), mode);
118 if (_zypp_lockfile == 0)
119 ZYPP_THROW (Exception( "Cant open " + _zyppLockFilePath.asString() + " in mode " + std::string(mode) ) );
124 fclose(_zypp_lockfile);
129 int fd = fileno(_zypp_lockfile);
130 int lock_error = flock(fd, LOCK_SH);
132 ZYPP_THROW (Exception( "Cant get shared lock"));
134 MIL << "locked (shared)" << std::endl;
139 int fd = fileno(_zypp_lockfile);
140 // lock access to the file
141 int lock_error = flock(fd, LOCK_EX);
143 ZYPP_THROW (Exception( "Cant get exclusive lock" ));
145 MIL << "locked (exclusive)" << std::endl;
150 int fd = fileno(_zypp_lockfile);
151 // lock access to the file
152 int lock_error = flock(fd, LOCK_UN);
154 ZYPP_THROW (Exception( "Cant release lock" ));
156 MIL << "unlocked" << std::endl;
159 bool lockFileExists()
161 // check if the file already existed.
162 PathInfo pi(_zyppLockFilePath);
167 void createLockFile()
169 pid_t curr_pid = getpid();
172 fprintf(_zypp_lockfile, "%ld\n", (long) curr_pid);
173 fflush(_zypp_lockfile);
175 MIL << "written lockfile with pid " << curr_pid << std::endl;
179 bool isProcessRunning(pid_t pid_r)
181 // it is another program, not me, see if it is still running
182 Pathname procdir( "/proc"/str::numstring(pid_r) );
183 PathInfo status( procdir );
184 MIL << "Checking " << status << endl;
186 if ( ! status.isDir() )
188 DBG << "No such process." << endl;
192 static char buffer[513];
193 buffer[0] = buffer[512] = 0;
194 // man proc(5): /proc/[pid]/cmdline is empty if zombie.
195 if ( std::ifstream( (procdir/"cmdline").c_str() ).read( buffer, 512 ).gcount() > 0 )
197 _locker_name = buffer;
198 DBG << "Is running: " << _locker_name << endl;
202 DBG << "In zombie state." << endl;
208 pid_t curr_pid = getpid();
209 pid_t locker_pid = 0;
212 fscanf(_zypp_lockfile, "%ld", &readpid);
213 MIL << "read: Lockfile " << _zyppLockFilePath << " has pid " << readpid << " (our pid: " << curr_pid << ") "<< std::endl;
214 locker_pid = (pid_t) readpid;
222 pid_t curr_pid = getpid();
224 if ( lockFileExists() )
226 MIL << "found lockfile " << _zyppLockFilePath << std::endl;
230 pid_t locker_pid = lockerPid();
231 _locker_pid = locker_pid;
232 if ( locker_pid == curr_pid )
234 // alles ok, we are requesting the instance again
235 //MIL << "Lockfile found, but it is myself. Assuming same process getting zypp instance again." << std::endl;
240 if ( isProcessRunning(locker_pid) )
242 if ( geteuid() == 0 )
245 MIL << locker_pid << " is running and has a ZYpp lock. Sorry" << std::endl;
250 MIL << locker_pid << " is running and has a ZYpp lock. Access as normal user allowed." << std::endl;
256 if ( geteuid() == 0 )
258 MIL << locker_pid << " has a ZYpp lock, but process is not running. Cleaning lock file." << std::endl;
259 if ( filesystem::unlink(_zyppLockFilePath) == 0 )
262 // now open it for reading
269 ERR << "Can't clean lockfile. Sorry, can't create a new lock. Zypp still locked." << std::endl;
275 MIL << locker_pid << " is running and has a ZYpp lock. Access as normal user allowed." << std::endl;
283 MIL << "no lockfile " << _zyppLockFilePath << " found" << std::endl;
284 if ( geteuid() == 0 )
286 MIL << "running as root. Will attempt to create " << _zyppLockFilePath << std::endl;
288 // now open it for reading
294 MIL << "running as user. Skipping creating " << _zyppLockFilePath << std::endl;
305 ZYppGlobalLock globalLock;
306 bool _haveZYpp = false;
309 ///////////////////////////////////////////////////////////////////
311 // CLASS NAME : ZYppFactoryException
313 ///////////////////////////////////////////////////////////////////
315 ZYppFactoryException::ZYppFactoryException( const std::string & msg_r, pid_t lockerPid_r, const std::string & lockerName_r )
317 , _lockerPid( lockerPid_r )
318 , _lockerName( lockerName_r )
321 ZYppFactoryException::~ZYppFactoryException() throw ()
324 ///////////////////////////////////////////////////////////////////
326 // CLASS NAME : ZYppFactory
328 ///////////////////////////////////////////////////////////////////
330 ///////////////////////////////////////////////////////////////////
332 // METHOD NAME : ZYppFactory::instance
333 // METHOD TYPE : ZYppFactory
335 ZYppFactory ZYppFactory::instance()
337 return ZYppFactory();
340 ///////////////////////////////////////////////////////////////////
342 // METHOD NAME : ZYppFactory::ZYppFactory
343 // METHOD TYPE : Ctor
345 ZYppFactory::ZYppFactory()
350 ///////////////////////////////////////////////////////////////////
352 // METHOD NAME : ZYppFactory::~ZYppFactory
353 // METHOD TYPE : Dtor
355 ZYppFactory::~ZYppFactory()
358 ///////////////////////////////////////////////////////////////////
360 ZYpp::Ptr ZYppFactory::getZYpp() const
362 static ZYpp::Ptr _instance;
366 /*--------------------------------------------------*/
367 if ( zypp_readonly_hack::active )
369 _instance = new ZYpp( ZYpp::Impl_Ptr(new ZYpp::Impl) );
370 MIL << "ZYPP_READONLY active." << endl;
372 /*--------------------------------------------------*/
373 else if ( globalLock.zyppLocked() )
375 std::string t = str::form(_("System management is locked by the application with pid %d (%s).\n"
376 "Close this application before trying again."),
377 globalLock.locker_pid(),
378 globalLock.locker_name().c_str()
380 ZYPP_THROW(ZYppFactoryException(t, globalLock.locker_pid(),globalLock.locker_name() ));
384 _instance = new ZYpp( ZYpp::Impl_Ptr(new ZYpp::Impl) );
385 globalLock._clean_lock = true;
395 ///////////////////////////////////////////////////////////////////
397 bool ZYppFactory::haveZYpp() const
398 { return _haveZYpp; }
400 /******************************************************************
402 ** FUNCTION NAME : operator<<
403 ** FUNCTION TYPE : std::ostream &
405 std::ostream & operator<<( std::ostream & str, const ZYppFactory & obj )
407 return str << "ZYppFactory";
410 /////////////////////////////////////////////////////////////////
412 ///////////////////////////////////////////////////////////////////