ZYppFactory.cc

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
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   } // namespace zypp_readonly_hack
00052 
00054   //
00055   //    CLASS NAME : ZYppGlobalLock
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(...) {} // let no exception escape.
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     // lock access to the file
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     // lock access to the file
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     // check if the file already existed.
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     // it is another program, not me, see if it is still running
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         // alles ok, we are requesting the instance again
00207           //MIL << "Lockfile found, but it is myself. Assuming same process getting zypp instance again." << std::endl;
00208           return false;
00209         }
00210         else
00211         {
00212           if ( isProcessRunning(locker_pid) )
00213           {
00214             if ( geteuid() == 0 )
00215             {
00216               // i am root
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               // now open it for reading
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         // now open it for reading
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   //    CLASS NAME : ZYppFactoryException
00280   //
00282 
00283   ZYppFactoryException::ZYppFactoryException( const std::string & msg_r )
00284     : Exception(msg_r)
00285   {}
00286 
00288   //
00289   //    CLASS NAME : ZYppFactory
00290   //
00292 
00294   //
00295   //    METHOD NAME : ZYppFactory::instance
00296   //    METHOD TYPE : ZYppFactory
00297   //
00298   ZYppFactory ZYppFactory::instance()
00299   {
00300     return ZYppFactory();
00301   }
00302 
00304   //
00305   //    METHOD NAME : ZYppFactory::ZYppFactory
00306   //    METHOD TYPE : Ctor
00307   //
00308   ZYppFactory::ZYppFactory()
00309   {
00310 
00311   }
00312 
00314   //
00315   //    METHOD NAME : ZYppFactory::~ZYppFactory
00316   //    METHOD TYPE : Dtor
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   **    FUNCTION NAME : operator<<
00357   **    FUNCTION TYPE : std::ostream &
00358   */
00359   std::ostream & operator<<( std::ostream & str, const ZYppFactory & obj )
00360   {
00361     return str << "ZYppFactory";
00362   }
00363 
00365 } // namespace zypp

Generated on Thu Apr 24 02:25:05 2008 for zypp by  doxygen 1.4.6