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