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 INT << PathInfo(lock_file) << endl;
156 bool exists = PathInfo(lock_file).isExist();
160 void createLockFile()
162 pid_t curr_pid = getpid();
165 fprintf(_zypp_lockfile, "%ld\n", (long) curr_pid);
166 fflush(_zypp_lockfile);
168 MIL << "written lockfile with pid " << curr_pid << std::endl;
172 bool isProcessRunning(pid_t pid_r)
174 // it is another program, not me, see if it is still running
175 Pathname procdir( "/proc"/str::numstring(pid_r) );
176 PathInfo status( procdir );
177 MIL << "Checking " << status << endl;
179 if ( ! status.isDir() )
181 DBG << "No such process." << endl;
185 static char buffer[513];
186 buffer[0] = buffer[512] = 0;
187 // man proc(5): /proc/[pid]/cmdline is empty if zombie.
188 if ( std::ifstream( (procdir/"cmdline").c_str() ).read( buffer, 512 ).gcount() > 0 )
190 _locker_name = buffer;
191 DBG << "Is running: " << _locker_name << endl;
195 DBG << "In zombie state." << endl;
201 pid_t curr_pid = getpid();
202 pid_t locker_pid = 0;
205 fscanf(_zypp_lockfile, "%ld", &readpid);
206 MIL << "read: Lockfile " << ZYPP_LOCK_FILE << " has pid " << readpid << " (our pid: " << curr_pid << ") "<< std::endl;
207 locker_pid = (pid_t) readpid;
215 pid_t curr_pid = getpid();
216 Pathname lock_file = Pathname(ZYPP_LOCK_FILE);
218 if ( lockFileExists() )
220 MIL << "found lockfile " << lock_file << std::endl;
224 pid_t locker_pid = lockerPid();
225 _locker_pid = locker_pid;
226 if ( locker_pid == curr_pid )
228 // alles ok, we are requesting the instance again
229 //MIL << "Lockfile found, but it is myself. Assuming same process getting zypp instance again." << std::endl;
234 if ( isProcessRunning(locker_pid) )
236 if ( geteuid() == 0 )
239 MIL << locker_pid << " is running and has a ZYpp lock. Sorry" << std::endl;
244 MIL << locker_pid << " is running and has a ZYpp lock. Access as normal user allowed." << std::endl;
250 if ( geteuid() == 0 )
252 MIL << locker_pid << " has a ZYpp lock, but process is not running. Cleaning lock file." << std::endl;
253 if ( filesystem::unlink(lock_file) == 0 )
256 // now open it for reading
263 ERR << "Can't clean lockfile. Sorry, can't create a new lock. Zypp still locked." << std::endl;
269 MIL << locker_pid << " is running and has a ZYpp lock. Access as normal user allowed." << std::endl;
277 MIL << "no lockfile " << lock_file << " found" << std::endl;
278 if ( geteuid() == 0 )
280 MIL << "running as root. Will attempt to create " << lock_file << std::endl;
282 // now open it for reading
288 MIL << "running as user. Skipping creating " << lock_file << std::endl;
299 ZYppGlobalLock globalLock;
300 bool _haveZYpp = false;
303 ///////////////////////////////////////////////////////////////////
305 // CLASS NAME : ZYppFactoryException
307 ///////////////////////////////////////////////////////////////////
309 ZYppFactoryException::ZYppFactoryException( const std::string & msg_r, pid_t locker_pid )
311 _locker_pid (locker_pid)
314 ///////////////////////////////////////////////////////////////////
316 // CLASS NAME : ZYppFactory
318 ///////////////////////////////////////////////////////////////////
320 ///////////////////////////////////////////////////////////////////
322 // METHOD NAME : ZYppFactory::instance
323 // METHOD TYPE : ZYppFactory
325 ZYppFactory ZYppFactory::instance()
327 return ZYppFactory();
330 ///////////////////////////////////////////////////////////////////
332 // METHOD NAME : ZYppFactory::ZYppFactory
333 // METHOD TYPE : Ctor
335 ZYppFactory::ZYppFactory()
340 ///////////////////////////////////////////////////////////////////
342 // METHOD NAME : ZYppFactory::~ZYppFactory
343 // METHOD TYPE : Dtor
345 ZYppFactory::~ZYppFactory()
348 ///////////////////////////////////////////////////////////////////
350 ZYpp::Ptr ZYppFactory::getZYpp() const
352 static ZYpp::Ptr _instance;
356 /*--------------------------------------------------*/
357 if ( zypp_readonly_hack::active )
359 _instance = new ZYpp( ZYpp::Impl_Ptr(new ZYpp::Impl) );
360 MIL << "ZYPP_READONLY active." << endl;
362 /*--------------------------------------------------*/
363 else if ( globalLock.zyppLocked() )
365 std::string t = str::form(_("System management is locked by the application with pid %d (%s).\n"
366 "Close this application before trying again."),
367 globalLock.locker_pid(),
368 globalLock.locker_name().c_str()
370 ZYPP_THROW(ZYppFactoryException(t, globalLock.locker_pid()));
374 _instance = new ZYpp( ZYpp::Impl_Ptr(new ZYpp::Impl) );
375 globalLock._clean_lock = true;
385 ///////////////////////////////////////////////////////////////////
387 bool ZYppFactory::haveZYpp() const
388 { return _haveZYpp; }
390 /******************************************************************
392 ** FUNCTION NAME : operator<<
393 ** FUNCTION TYPE : std::ostream &
395 std::ostream & operator<<( std::ostream & str, const ZYppFactory & obj )
397 return str << "ZYppFactory";
400 /////////////////////////////////////////////////////////////////
402 ///////////////////////////////////////////////////////////////////