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 curr_pid = getpid();
00176 pid_t locked_pid = 0;
00177 long readpid = 0;
00178
00179 fscanf(_zypp_lockfile, "%ld", &readpid);
00180 MIL << "read: Lockfile " << ZYPP_LOCK_FILE << " has pid " << readpid << " (our pid: " << curr_pid << ") "<< std::endl;
00181 locked_pid = (pid_t) readpid;
00182 return locked_pid;
00183 }
00184
00185 public:
00186
00187 bool zyppLocked()
00188 {
00189 pid_t curr_pid = getpid();
00190 Pathname lock_file = Pathname(ZYPP_LOCK_FILE);
00191
00192 if ( lockFileExists() )
00193 {
00194 MIL << "found lockfile " << lock_file << std::endl;
00195 openLockFile("r");
00196 shLockFile();
00197
00198 pid_t locker_pid = lockerPid();
00199 if ( locker_pid == curr_pid )
00200 {
00201
00202
00203 return false;
00204 }
00205 else
00206 {
00207 if ( isProcessRunning(locker_pid) )
00208 {
00209 if ( geteuid() == 0 )
00210 {
00211
00212 MIL << locker_pid << " is running and has a ZYpp lock. Sorry" << std::endl;
00213 return true;
00214 }
00215 else
00216 {
00217 MIL << locker_pid << " is running and has a ZYpp lock. Access as normal user allowed." << std::endl;
00218 return false;
00219 }
00220 }
00221 else
00222 {
00223 if ( geteuid() == 0 )
00224 {
00225 MIL << locker_pid << " has a ZYpp lock, but process is not running. Cleaning lock file." << std::endl;
00226 if ( filesystem::unlink(lock_file) == 0 )
00227 {
00228 createLockFile();
00229
00230 openLockFile("r");
00231 shLockFile();
00232 return false;
00233 }
00234 else
00235 {
00236 ERR << "Can't clean lockfile. Sorry, can't create a new lock. Zypp still locked." << std::endl;
00237 return true;
00238 }
00239 }
00240 else
00241 {
00242 MIL << locker_pid << " is running and has a ZYpp lock. Access as normal user allowed." << std::endl;
00243 return false;
00244 }
00245 }
00246 }
00247 }
00248 else
00249 {
00250 MIL << "no lockfile " << lock_file << " found" << std::endl;
00251 if ( geteuid() == 0 )
00252 {
00253 MIL << "running as root. Will attempt to create " << lock_file << std::endl;
00254 createLockFile();
00255
00256 openLockFile("r");
00257 shLockFile();
00258 }
00259 else
00260 {
00261 MIL << "running as user. Skipping creating " << lock_file << std::endl;
00262 }
00263 return false;
00264 }
00265 return true;
00266 }
00267
00268 };
00269
00270 static ZYppGlobalLock globalLock;
00271
00273
00274
00275
00277
00278 ZYppFactoryException::ZYppFactoryException( const std::string & msg_r )
00279 : Exception(N_("Cannot aquire zypp lock."))
00280 {}
00281
00283
00284
00285
00287
00289
00290
00291
00292
00293 ZYppFactory ZYppFactory::instance()
00294 {
00295 return ZYppFactory();
00296 }
00297
00299
00300
00301
00302
00303 ZYppFactory::ZYppFactory()
00304 {
00305
00306 }
00307
00309
00310
00311
00312
00313 ZYppFactory::~ZYppFactory()
00314 {}
00315
00317
00318 ZYpp::Ptr ZYppFactory::getZYpp() const
00319 {
00320 static ZYpp::Ptr _instance;
00321
00322 if ( ! _instance )
00323 {
00324
00325 if ( zypp_readonly_hack::active )
00326 {
00327 _instance = new ZYpp( ZYpp::Impl_Ptr(new ZYpp::Impl) );
00328 MIL << "ZYPP_READONLY active." << endl;
00329 return _instance;
00330 }
00331
00332 if ( globalLock.zyppLocked() )
00333 {
00334 ZYPP_THROW( ZYppFactoryException(N_("Cannot aquire zypp lock.")) );
00335 }
00336 else
00337 {
00338 _instance = new ZYpp( ZYpp::Impl_Ptr(new ZYpp::Impl) );
00339 globalLock._clean_lock = true;
00340 }
00341 }
00342
00343 return _instance;
00344 }
00345
00346
00347
00348
00349
00350
00351 std::ostream & operator<<( std::ostream & str, const ZYppFactory & obj )
00352 {
00353 return str << "ZYppFactory";
00354 }
00355
00357 }