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     {}
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(...) {} // let no exception escape.
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     // lock access to the file
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     // lock access to the file
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     // check if the file already existed.
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     // it is another program, not me, see if it is still running
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         // alles ok, we are requesting the instance again
00202           //MIL << "Lockfile found, but it is myself. Assuming same process getting zypp instance again." << std::endl;
00203           return false;
00204         }
00205         else
00206         {
00207           if ( isProcessRunning(locker_pid) )
00208           {
00209             if ( geteuid() == 0 )
00210             {
00211               // i am root
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               // now open it for reading
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         // now open it for reading
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   //    CLASS NAME : ZYppFactoryException
00275   //
00277 
00278   ZYppFactoryException::ZYppFactoryException( const std::string & msg_r )
00279   : Exception(N_("Cannot aquire zypp lock."))
00280   {}
00281 
00283   //
00284   //    CLASS NAME : ZYppFactory
00285   //
00287 
00289   //
00290   //    METHOD NAME : ZYppFactory::instance
00291   //    METHOD TYPE : ZYppFactory
00292   //
00293   ZYppFactory ZYppFactory::instance()
00294   {
00295     return ZYppFactory();
00296   }
00297 
00299   //
00300   //    METHOD NAME : ZYppFactory::ZYppFactory
00301   //    METHOD TYPE : Ctor
00302   //
00303   ZYppFactory::ZYppFactory()
00304   {
00305 
00306   }
00307 
00309   //
00310   //    METHOD NAME : ZYppFactory::~ZYppFactory
00311   //    METHOD TYPE : Dtor
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   **    FUNCTION NAME : operator<<
00349   **    FUNCTION TYPE : std::ostream &
00350   */
00351   std::ostream & operator<<( std::ostream & str, const ZYppFactory & obj )
00352   {
00353     return str << "ZYppFactory";
00354   }
00355 
00357 } // namespace zypp

Generated on Thu Jul 6 00:07:29 2006 for zypp by  doxygen 1.4.6