ZYppFactory.cc
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00012 extern "C"
00013 {
00014 #include <sys/file.h>
00015 }
00016 #include <iostream>
00017 #include <fstream>
00018
00019 #include "zypp/base/Logger.h"
00020 #include "zypp/base/Gettext.h"
00021 #include "zypp/base/IOStream.h"
00022 #include "zypp/PathInfo.h"
00023
00024 #include "zypp/ZYppFactory.h"
00025 #include "zypp/zypp_detail/ZYppImpl.h"
00026 #include "zypp/zypp_detail/ZYppReadOnlyHack.h"
00027
00028 using std::endl;
00029
00031 namespace zypp
00032 {
00033
00034 namespace env
00035 {
00037 inline Pathname ZYPP_LOCKFILE_ROOT()
00038 { return getenv("ZYPP_LOCKFILE_ROOT") ? getenv("ZYPP_LOCKFILE_ROOT") : "/"; }
00039 }
00040
00042 namespace zypp_readonly_hack
00043 {
00044
00045 static bool active = false;
00046
00047 void IWantIt()
00048 {
00049 active = true;
00050 MIL << "ZYPP_READONLY promised." << endl;
00051 }
00052
00054 }
00056
00058
00059
00060
00062
00063 class ZYppGlobalLock
00064 {
00065 public:
00066
00067 ZYppGlobalLock()
00068 : _clean_lock(false)
00069 , _zyppLockFilePath( env::ZYPP_LOCKFILE_ROOT() / "/var/run/zypp.pid" )
00070 , _zypp_lockfile(0)
00071 , _locker_pid(0)
00072 {
00073 filesystem::assert_dir(_zyppLockFilePath.dirname());
00074 }
00075
00076 ~ZYppGlobalLock()
00077 {
00078 try
00079 {
00080 pid_t curr_pid = getpid();
00081 if ( _zypp_lockfile )
00082 {
00083 unLockFile();
00084 closeLockFile();
00085
00086 if ( _clean_lock )
00087 {
00088 MIL << "Cleaning lock file. (" << curr_pid << ")" << std::endl;
00089 if ( filesystem::unlink(_zyppLockFilePath) == 0 )
00090 MIL << "Lockfile cleaned. (" << curr_pid << ")" << std::endl;
00091 else
00092 ERR << "Cant clean lockfile. (" << curr_pid << ")" << std::endl;
00093 }
00094 }
00095 }
00096 catch(...) {}
00097 }
00098
00099 pid_t locker_pid() const
00100 { return _locker_pid; }
00101
00102 const std::string & locker_name() const
00103 { return _locker_name; }
00104
00105
00106 bool _clean_lock;
00107
00108 private:
00109 Pathname _zyppLockFilePath;
00110 FILE *_zypp_lockfile;
00111 pid_t _locker_pid;
00112 std::string _locker_name;
00113
00114 void openLockFile(const char *mode)
00115 {
00116
00117 _zypp_lockfile = fopen(_zyppLockFilePath.asString().c_str(), mode);
00118 if (_zypp_lockfile == 0)
00119 ZYPP_THROW (Exception( "Cant open " + _zyppLockFilePath.asString() + " in mode " + std::string(mode) ) );
00120 }
00121
00122 void closeLockFile()
00123 {
00124 fclose(_zypp_lockfile);
00125 }
00126
00127 void shLockFile()
00128 {
00129 int fd = fileno(_zypp_lockfile);
00130 int lock_error = flock(fd, LOCK_SH);
00131 if (lock_error != 0)
00132 ZYPP_THROW (Exception( "Cant get shared lock"));
00133 else
00134 MIL << "locked (shared)" << std::endl;
00135 }
00136
00137 void exLockFile()
00138 {
00139 int fd = fileno(_zypp_lockfile);
00140
00141 int lock_error = flock(fd, LOCK_EX);
00142 if (lock_error != 0)
00143 ZYPP_THROW (Exception( "Cant get exclusive lock" ));
00144 else
00145 MIL << "locked (exclusive)" << std::endl;
00146 }
00147
00148 void unLockFile()
00149 {
00150 int fd = fileno(_zypp_lockfile);
00151
00152 int lock_error = flock(fd, LOCK_UN);
00153 if (lock_error != 0)
00154 ZYPP_THROW (Exception( "Cant release lock" ));
00155 else
00156 MIL << "unlocked" << std::endl;
00157 }
00158
00159 bool lockFileExists()
00160 {
00161
00162 PathInfo pi(_zyppLockFilePath);
00163 DBG << pi << endl;
00164 return pi.isExist();
00165 }
00166
00167 void createLockFile()
00168 {
00169 pid_t curr_pid = getpid();
00170 openLockFile("w");
00171 exLockFile();
00172 fprintf(_zypp_lockfile, "%ld\n", (long) curr_pid);
00173 fflush(_zypp_lockfile);
00174 unLockFile();
00175 MIL << "written lockfile with pid " << curr_pid << std::endl;
00176 closeLockFile();
00177 }
00178
00179 bool isProcessRunning(pid_t pid_r)
00180 {
00181
00182 Pathname procdir( "/proc"/str::numstring(pid_r) );
00183 PathInfo status( procdir );
00184 MIL << "Checking " << status << endl;
00185
00186 if ( ! status.isDir() )
00187 {
00188 DBG << "No such process." << endl;
00189 return false;
00190 }
00191
00192 static char buffer[513];
00193 buffer[0] = buffer[512] = 0;
00194
00195 if ( std::ifstream( (procdir/"cmdline").c_str() ).read( buffer, 512 ).gcount() > 0 )
00196 {
00197 _locker_name = buffer;
00198 DBG << "Is running: " << _locker_name << endl;
00199 return true;
00200 }
00201
00202 DBG << "In zombie state." << endl;
00203 return false;
00204 }
00205
00206 pid_t lockerPid()
00207 {
00208 pid_t curr_pid = getpid();
00209 pid_t locker_pid = 0;
00210 long readpid = 0;
00211
00212 fscanf(_zypp_lockfile, "%ld", &readpid);
00213 MIL << "read: Lockfile " << _zyppLockFilePath << " has pid " << readpid << " (our pid: " << curr_pid << ") "<< std::endl;
00214 locker_pid = (pid_t) readpid;
00215 return locker_pid;
00216 }
00217
00218 public:
00219
00220 bool zyppLocked()
00221 {
00222 pid_t curr_pid = getpid();
00223
00224 if ( lockFileExists() )
00225 {
00226 MIL << "found lockfile " << _zyppLockFilePath << std::endl;
00227 openLockFile("r");
00228 shLockFile();
00229
00230 pid_t locker_pid = lockerPid();
00231 _locker_pid = locker_pid;
00232 if ( locker_pid == curr_pid )
00233 {
00234
00235
00236 return false;
00237 }
00238 else
00239 {
00240 if ( isProcessRunning(locker_pid) )
00241 {
00242 if ( geteuid() == 0 )
00243 {
00244
00245 MIL << locker_pid << " is running and has a ZYpp lock. Sorry" << std::endl;
00246 return true;
00247 }
00248 else
00249 {
00250 MIL << locker_pid << " is running and has a ZYpp lock. Access as normal user allowed." << std::endl;
00251 return false;
00252 }
00253 }
00254 else
00255 {
00256 if ( geteuid() == 0 )
00257 {
00258 MIL << locker_pid << " has a ZYpp lock, but process is not running. Cleaning lock file." << std::endl;
00259 if ( filesystem::unlink(_zyppLockFilePath) == 0 )
00260 {
00261 createLockFile();
00262
00263 openLockFile("r");
00264 shLockFile();
00265 return false;
00266 }
00267 else
00268 {
00269 ERR << "Can't clean lockfile. Sorry, can't create a new lock. Zypp still locked." << std::endl;
00270 return true;
00271 }
00272 }
00273 else
00274 {
00275 MIL << locker_pid << " is running and has a ZYpp lock. Access as normal user allowed." << std::endl;
00276 return false;
00277 }
00278 }
00279 }
00280 }
00281 else
00282 {
00283 MIL << "no lockfile " << _zyppLockFilePath << " found" << std::endl;
00284 if ( geteuid() == 0 )
00285 {
00286 MIL << "running as root. Will attempt to create " << _zyppLockFilePath << std::endl;
00287 createLockFile();
00288
00289 openLockFile("r");
00290 shLockFile();
00291 }
00292 else
00293 {
00294 MIL << "running as user. Skipping creating " << _zyppLockFilePath << std::endl;
00295 }
00296 return false;
00297 }
00298 return true;
00299 }
00300
00301 };
00302
00303 namespace
00304 {
00305 ZYppGlobalLock globalLock;
00306 bool _haveZYpp = false;
00307 }
00308
00310
00311
00312
00314
00315 ZYppFactoryException::ZYppFactoryException( const std::string & msg_r, pid_t lockerPid_r, const std::string & lockerName_r )
00316 : Exception( msg_r )
00317 , _lockerPid( lockerPid_r )
00318 , _lockerName( lockerName_r )
00319 {}
00320
00321 ZYppFactoryException::~ZYppFactoryException() throw ()
00322 {}
00323
00325
00326
00327
00329
00331
00332
00333
00334
00335 ZYppFactory ZYppFactory::instance()
00336 {
00337 return ZYppFactory();
00338 }
00339
00341
00342
00343
00344
00345 ZYppFactory::ZYppFactory()
00346 {
00347
00348 }
00349
00351
00352
00353
00354
00355 ZYppFactory::~ZYppFactory()
00356 {}
00357
00359
00360 ZYpp::Ptr ZYppFactory::getZYpp() const
00361 {
00362 static ZYpp::Ptr _instance;
00363
00364 if ( ! _instance )
00365 {
00366
00367 if ( zypp_readonly_hack::active )
00368 {
00369 _instance = new ZYpp( ZYpp::Impl_Ptr(new ZYpp::Impl) );
00370 MIL << "ZYPP_READONLY active." << endl;
00371 }
00372
00373 else if ( globalLock.zyppLocked() )
00374 {
00375 std::string t = str::form(_("System management is locked by the application with pid %d (%s).\n"
00376 "Close this application before trying again."),
00377 globalLock.locker_pid(),
00378 globalLock.locker_name().c_str()
00379 );
00380 ZYPP_THROW(ZYppFactoryException(t, globalLock.locker_pid(),globalLock.locker_name() ));
00381 }
00382 else
00383 {
00384 _instance = new ZYpp( ZYpp::Impl_Ptr(new ZYpp::Impl) );
00385 globalLock._clean_lock = true;
00386 }
00387
00388 if ( _instance )
00389 _haveZYpp = true;
00390 }
00391
00392 return _instance;
00393 }
00394
00396
00397 bool ZYppFactory::haveZYpp() const
00398 { return _haveZYpp; }
00399
00400
00401
00402
00403
00404
00405 std::ostream & operator<<( std::ostream & str, const ZYppFactory & obj )
00406 {
00407 return str << "ZYppFactory";
00408 }
00409
00411 }