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 {}
00067
00068 ~ZYppGlobalLock()
00069 {
00070 try
00071 {
00072 pid_t curr_pid = getpid();
00073 if ( _zypp_lockfile )
00074 {
00075 Pathname lock_file = Pathname(ZYPP_LOCK_FILE);
00076 unLockFile();
00077 closeLockFile();
00078
00079 if ( _clean_lock )
00080 {
00081 MIL << "Cleaning lock file. (" << curr_pid << ")" << std::endl;
00082 if ( filesystem::unlink(lock_file) == 0 )
00083 MIL << "Lockfile cleaned. (" << curr_pid << ")" << std::endl;
00084 else
00085 ERR << "Cant clean lockfile. (" << curr_pid << ")" << std::endl;
00086 }
00087 }
00088 }
00089 catch(...) {}
00090 }
00091
00092 bool _clean_lock;
00093
00094 private:
00095 FILE *_zypp_lockfile;
00096
00097 void openLockFile(const char *mode)
00098 {
00099 Pathname lock_file = Pathname(ZYPP_LOCK_FILE);
00100 _zypp_lockfile = fopen(lock_file.asString().c_str(), mode);
00101 if (_zypp_lockfile == 0)
00102 ZYPP_THROW (Exception( "Cant open " + lock_file.asString() + " in mode " + std::string(mode) ) );
00103 }
00104
00105 void closeLockFile()
00106 {
00107 fclose(_zypp_lockfile);
00108 }
00109
00110 void shLockFile()
00111 {
00112 int fd = fileno(_zypp_lockfile);
00113 int lock_error = flock(fd, LOCK_SH);
00114 if (lock_error != 0)
00115 ZYPP_THROW (Exception( "Cant get shared lock"));
00116 else
00117 MIL << "locked (shared)" << std::endl;
00118 }
00119
00120 void exLockFile()
00121 {
00122 int fd = fileno(_zypp_lockfile);
00123
00124 int lock_error = flock(fd, LOCK_EX);
00125 if (lock_error != 0)
00126 ZYPP_THROW (Exception( "Cant get exclusive lock" ));
00127 else
00128 MIL << "locked (exclusive)" << std::endl;
00129 }
00130
00131 void unLockFile()
00132 {
00133 int fd = fileno(_zypp_lockfile);
00134
00135 int lock_error = flock(fd, LOCK_UN);
00136 if (lock_error != 0)
00137 ZYPP_THROW (Exception( "Cant release lock" ));
00138 else
00139 MIL << "unlocked" << std::endl;
00140 }
00141
00142 bool lockFileExists()
00143 {
00144 Pathname lock_file = Pathname(ZYPP_LOCK_FILE);
00145
00146 bool exists = PathInfo(lock_file).isExist();
00147 return exists;
00148 }
00149
00150 void createLockFile()
00151 {
00152 pid_t curr_pid = getpid();
00153 openLockFile("w");
00154 exLockFile();
00155 fprintf(_zypp_lockfile, "%ld\n", (long) curr_pid);
00156 fflush(_zypp_lockfile);
00157 unLockFile();
00158 MIL << "written lockfile with pid " << curr_pid << std::endl;
00159 closeLockFile();
00160 }
00161
00162 bool isProcessRunning(pid_t pid)
00163 {
00164
00165 stringstream ss;
00166 ss << "/proc/" << pid << "/status";
00167 Pathname procfile = Pathname(ss.str());
00168 MIL << "Checking " << procfile << " to determine if pid is running: " << pid << std::endl;
00169 bool still_running = PathInfo(procfile).isExist();
00170 return still_running;
00171 }
00172
00173 pid_t lockerPid()
00174 {
00175 pid_t locked_pid = 0;
00176 long readpid = 0;
00177
00178 fscanf(_zypp_lockfile, "%ld", &readpid);
00179 MIL << "read: Lockfile " << ZYPP_LOCK_FILE << " has pid " << readpid << std::endl;
00180 locked_pid = (pid_t) readpid;
00181 return locked_pid;
00182 }
00183
00184 public:
00185
00186 bool zyppLocked()
00187 {
00188 pid_t curr_pid = getpid();
00189 Pathname lock_file = Pathname(ZYPP_LOCK_FILE);
00190
00191 if ( lockFileExists() )
00192 {
00193 openLockFile("r");
00194 shLockFile();
00195
00196 pid_t locker_pid = lockerPid();
00197 if ( locker_pid == curr_pid )
00198 {
00199
00200
00201 return false;
00202 }
00203 else
00204 {
00205 if ( isProcessRunning(locker_pid) )
00206 {
00207 if ( geteuid() == 0 )
00208 {
00209
00210 MIL << locker_pid << " is running and has a ZYpp lock. Sorry" << std::endl;
00211 return true;
00212 }
00213 else
00214 {
00215 MIL << locker_pid << " is running and has a ZYpp lock. Access as normal user allowed." << std::endl;
00216 return false;
00217 }
00218 }
00219 else
00220 {
00221 if ( geteuid() == 0 )
00222 {
00223 MIL << locker_pid << " has a ZYpp lock, but process is not running. Cleaning lock file." << std::endl;
00224 if ( filesystem::unlink(lock_file) == 0 )
00225 {
00226 createLockFile();
00227
00228 openLockFile("r");
00229 shLockFile();
00230 return false;
00231 }
00232 else
00233 {
00234 ERR << "Can't clean lockfile. Sorry, can't create a new lock. Zypp still locked." << std::endl;
00235 return true;
00236 }
00237 }
00238 else
00239 {
00240 MIL << locker_pid << " is running and has a ZYpp lock. Access as normal user allowed." << std::endl;
00241 return false;
00242 }
00243 }
00244 }
00245 }
00246 else
00247 {
00248 if ( geteuid() == 0 )
00249 {
00250 createLockFile();
00251
00252 openLockFile("r");
00253 shLockFile();
00254 }
00255 return false;
00256 }
00257 return true;
00258 }
00259
00260 };
00261
00262 static ZYppGlobalLock globalLock;
00263
00265
00266
00267
00269
00270 ZYppFactoryException::ZYppFactoryException( const std::string & msg_r )
00271 : Exception(N_("Cannot aquire zypp lock."))
00272 {}
00273
00275
00276
00277
00279
00281
00282
00283
00284
00285 ZYppFactory ZYppFactory::instance()
00286 {
00287 return ZYppFactory();
00288 }
00289
00291
00292
00293
00294
00295 ZYppFactory::ZYppFactory()
00296 {
00297
00298 }
00299
00301
00302
00303
00304
00305 ZYppFactory::~ZYppFactory()
00306 {}
00307
00309
00310 ZYpp::Ptr ZYppFactory::getZYpp() const
00311 {
00312 static ZYpp::Ptr _instance;
00313
00314 if ( ! _instance )
00315 {
00316
00317 if ( zypp_readonly_hack::active )
00318 {
00319 _instance = new ZYpp( ZYpp::Impl_Ptr(new ZYpp::Impl) );
00320 MIL << "ZYPP_READONLY active." << endl;
00321 return _instance;
00322 }
00323
00324 if ( globalLock.zyppLocked() )
00325 {
00326 ZYPP_THROW( ZYppFactoryException(N_("Cannot aquire zypp lock.")) );
00327 }
00328 else
00329 {
00330 _instance = new ZYpp( ZYpp::Impl_Ptr(new ZYpp::Impl) );
00331 globalLock._clean_lock = true;
00332 }
00333 }
00334
00335 return _instance;
00336 }
00337
00338
00339
00340
00341
00342
00343 std::ostream & operator<<( std::ostream & str, const ZYppFactory & obj )
00344 {
00345 return str << "ZYppFactory";
00346 }
00347
00349 }