libzypp
10.5.0
|
00001 /*---------------------------------------------------------------------\ 00002 | ____ _ __ __ ___ | 00003 | |__ / \ / / . \ . \ | 00004 | / / \ V /| _/ _/ | 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 } // namespace zypp_readonly_hack 00056 00058 // 00059 // CLASS NAME : ZYppGlobalLock 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(...) {} // let no exception escape. 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 // lock access to the file 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 // lock access to the file 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 // check if the file already existed. 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 // it is another program, not me, see if it is still running 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 // man proc(5): /proc/[pid]/cmdline is empty if zombie. 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 // alles ok, we are requesting the instance again 00235 //MIL << "Lockfile found, but it is myself. Assuming same process getting zypp instance again." << std::endl; 00236 return false; 00237 } 00238 else 00239 { 00240 if ( isProcessRunning(locker_pid) ) 00241 { 00242 if ( geteuid() == 0 ) 00243 { 00244 // i am root 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 // now open it for reading 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 // now open it for reading 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 // CLASS NAME : ZYppFactoryException 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 // CLASS NAME : ZYppFactory 00327 // 00329 00331 // 00332 // METHOD NAME : ZYppFactory::instance 00333 // METHOD TYPE : ZYppFactory 00334 // 00335 ZYppFactory ZYppFactory::instance() 00336 { 00337 return ZYppFactory(); 00338 } 00339 00341 // 00342 // METHOD NAME : ZYppFactory::ZYppFactory 00343 // METHOD TYPE : Ctor 00344 // 00345 ZYppFactory::ZYppFactory() 00346 { 00347 00348 } 00349 00351 // 00352 // METHOD NAME : ZYppFactory::~ZYppFactory 00353 // METHOD TYPE : Dtor 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 ** FUNCTION NAME : operator<< 00403 ** FUNCTION TYPE : std::ostream & 00404 */ 00405 std::ostream & operator<<( std::ostream & str, const ZYppFactory & obj ) 00406 { 00407 return str << "ZYppFactory"; 00408 } 00409 00411 } // namespace zypp