00001
00002
00003
00004
00005
00006
00007
00008
00013 #include <sys/file.h>
00014 #include <cstdio>
00015 #include <unistd.h>
00016 #include <fstream>
00017 #include <iostream>
00018 #include <sstream>
00019
00020 #include "zypp/base/Logger.h"
00021 #include "zypp/base/Gettext.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 #define ZYPP_LOCK_FILE "/var/run/zypp.pid"
00029
00030 using std::endl;
00031 using namespace std;
00032
00034 namespace zypp
00035 {
00036
00038 namespace zypp_readonly_hack
00039 {
00040
00041 static bool active = false;
00042
00043 void IWantIt()
00044 {
00045 active = true;
00046 MIL << "ZYPP_READONLY promised." << endl;
00047 }
00048
00050 }
00052
00054
00055
00056
00058
00059 class ZYppGlobalLock
00060 {
00061 public:
00062
00063 ZYppGlobalLock()
00064 : _clean_lock(false)
00065 , _zypp_lockfile(0)
00066 , _locker_pid(0)
00067 {}
00068
00069 ~ZYppGlobalLock()
00070 {
00071 try
00072 {
00073 pid_t curr_pid = getpid();
00074 if ( _zypp_lockfile )
00075 {
00076 Pathname lock_file = Pathname(ZYPP_LOCK_FILE);
00077 unLockFile();
00078 closeLockFile();
00079
00080 if ( _clean_lock )
00081 {
00082 MIL << "Cleaning lock file. (" << curr_pid << ")" << std::endl;
00083 if ( filesystem::unlink(lock_file) == 0 )
00084 MIL << "Lockfile cleaned. (" << curr_pid << ")" << std::endl;
00085 else
00086 ERR << "Cant clean lockfile. (" << curr_pid << ")" << std::endl;
00087 }
00088 }
00089 }
00090 catch(...) {}
00091 }
00092
00093 pid_t locker_pid() const { return _locker_pid; }
00094
00095 bool _clean_lock;
00096
00097 private:
00098 FILE *_zypp_lockfile;
00099 pid_t _locker_pid;
00100
00101 void openLockFile(const char *mode)
00102 {
00103 Pathname lock_file = Pathname(ZYPP_LOCK_FILE);
00104 _zypp_lockfile = fopen(lock_file.asString().c_str(), mode);
00105 if (_zypp_lockfile == 0)
00106 ZYPP_THROW (Exception( "Cant open " + lock_file.asString() + " in mode " + std::string(mode) ) );
00107 }
00108
00109 void closeLockFile()
00110 {
00111 fclose(_zypp_lockfile);
00112 }
00113
00114 void shLockFile()
00115 {
00116 int fd = fileno(_zypp_lockfile);
00117 int lock_error = flock(fd, LOCK_SH);
00118 if (lock_error != 0)
00119 ZYPP_THROW (Exception( "Cant get shared lock"));
00120 else
00121 MIL << "locked (shared)" << std::endl;
00122 }
00123
00124 void exLockFile()
00125 {
00126 int fd = fileno(_zypp_lockfile);
00127
00128 int lock_error = flock(fd, LOCK_EX);
00129 if (lock_error != 0)
00130 ZYPP_THROW (Exception( "Cant get exclusive lock" ));
00131 else
00132 MIL << "locked (exclusive)" << std::endl;
00133 }
00134
00135 void unLockFile()
00136 {
00137 int fd = fileno(_zypp_lockfile);
00138
00139 int lock_error = flock(fd, LOCK_UN);
00140 if (lock_error != 0)
00141 ZYPP_THROW (Exception( "Cant release lock" ));
00142 else
00143 MIL << "unlocked" << std::endl;
00144 }
00145
00146 bool lockFileExists()
00147 {
00148 Pathname lock_file = Pathname(ZYPP_LOCK_FILE);
00149
00150 bool exists = PathInfo(lock_file).isExist();
00151 return exists;
00152 }
00153
00154 void createLockFile()
00155 {
00156 pid_t curr_pid = getpid();
00157 openLockFile("w");
00158 exLockFile();
00159 fprintf(_zypp_lockfile, "%ld\n", (long) curr_pid);
00160 fflush(_zypp_lockfile);
00161 unLockFile();
00162 MIL << "written lockfile with pid " << curr_pid << std::endl;
00163 closeLockFile();
00164 }
00165
00166 bool isProcessRunning(pid_t pid)
00167 {
00168
00169 stringstream ss;
00170 ss << "/proc/" << pid << "/status";
00171 Pathname procfile = Pathname(ss.str());
00172 MIL << "Checking " << procfile << " to determine if pid is running: " << pid << std::endl;
00173 bool still_running = PathInfo(procfile).isExist();
00174 return still_running;
00175 }
00176
00177 pid_t lockerPid()
00178 {
00179 pid_t curr_pid = getpid();
00180 pid_t locker_pid = 0;
00181 long readpid = 0;
00182
00183 fscanf(_zypp_lockfile, "%ld", &readpid);
00184 MIL << "read: Lockfile " << ZYPP_LOCK_FILE << " has pid " << readpid << " (our pid: " << curr_pid << ") "<< std::endl;
00185 locker_pid = (pid_t) readpid;
00186 return locker_pid;
00187 }
00188
00189 public:
00190
00191 bool zyppLocked()
00192 {
00193 pid_t curr_pid = getpid();
00194 Pathname lock_file = Pathname(ZYPP_LOCK_FILE);
00195
00196 if ( lockFileExists() )
00197 {
00198 MIL << "found lockfile " << lock_file << std::endl;
00199 openLockFile("r");
00200 shLockFile();
00201
00202 pid_t locker_pid = lockerPid();
00203 _locker_pid = locker_pid;
00204 if ( locker_pid == curr_pid )
00205 {
00206
00207
00208 return false;
00209 }
00210 else
00211 {
00212 if ( isProcessRunning(locker_pid) )
00213 {
00214 if ( geteuid() == 0 )
00215 {
00216
00217 MIL << locker_pid << " is running and has a ZYpp lock. Sorry" << std::endl;
00218 return true;
00219 }
00220 else
00221 {
00222 MIL << locker_pid << " is running and has a ZYpp lock. Access as normal user allowed." << std::endl;
00223 return false;
00224 }
00225 }
00226 else
00227 {
00228 if ( geteuid() == 0 )
00229 {
00230 MIL << locker_pid << " has a ZYpp lock, but process is not running. Cleaning lock file." << std::endl;
00231 if ( filesystem::unlink(lock_file) == 0 )
00232 {
00233 createLockFile();
00234
00235 openLockFile("r");
00236 shLockFile();
00237 return false;
00238 }
00239 else
00240 {
00241 ERR << "Can't clean lockfile. Sorry, can't create a new lock. Zypp still locked." << std::endl;
00242 return true;
00243 }
00244 }
00245 else
00246 {
00247 MIL << locker_pid << " is running and has a ZYpp lock. Access as normal user allowed." << std::endl;
00248 return false;
00249 }
00250 }
00251 }
00252 }
00253 else
00254 {
00255 MIL << "no lockfile " << lock_file << " found" << std::endl;
00256 if ( geteuid() == 0 )
00257 {
00258 MIL << "running as root. Will attempt to create " << lock_file << std::endl;
00259 createLockFile();
00260
00261 openLockFile("r");
00262 shLockFile();
00263 }
00264 else
00265 {
00266 MIL << "running as user. Skipping creating " << lock_file << std::endl;
00267 }
00268 return false;
00269 }
00270 return true;
00271 }
00272
00273 };
00274
00275 static ZYppGlobalLock globalLock;
00276
00278
00279
00280
00282
00283 ZYppFactoryException::ZYppFactoryException( const std::string & msg_r )
00284 : Exception(msg_r)
00285 {}
00286
00288
00289
00290
00292
00294
00295
00296
00297
00298 ZYppFactory ZYppFactory::instance()
00299 {
00300 return ZYppFactory();
00301 }
00302
00304
00305
00306
00307
00308 ZYppFactory::ZYppFactory()
00309 {
00310
00311 }
00312
00314
00315
00316
00317
00318 ZYppFactory::~ZYppFactory()
00319 {}
00320
00322
00323 ZYpp::Ptr ZYppFactory::getZYpp() const
00324 {
00325 static ZYpp::Ptr _instance;
00326
00327 if ( ! _instance )
00328 {
00329
00330 if ( zypp_readonly_hack::active )
00331 {
00332 _instance = new ZYpp( ZYpp::Impl_Ptr(new ZYpp::Impl) );
00333 MIL << "ZYPP_READONLY active." << endl;
00334 return _instance;
00335 }
00336
00337 if ( globalLock.zyppLocked() )
00338 {
00339 string t = str::form(N_("System management is locked by the application with pid %d. "
00340 "Please close this application before trying again."),
00341 globalLock.locker_pid());
00342 ZYPP_THROW(ZYppFactoryException(t));
00343 }
00344 else
00345 {
00346 _instance = new ZYpp( ZYpp::Impl_Ptr(new ZYpp::Impl) );
00347 globalLock._clean_lock = true;
00348 }
00349 }
00350
00351 return _instance;
00352 }
00353
00354
00355
00356
00357
00358
00359 std::ostream & operator<<( std::ostream & str, const ZYppFactory & obj )
00360 {
00361 return str << "ZYppFactory";
00362 }
00363
00365 }