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 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         // alles ok, we are requesting the instance again
00200           //MIL << "Lockfile found, but it is myself. Assuming same process getting zypp instance again." << std::endl;
00201           return false;
00202         }
00203         else
00204         {
00205           if ( isProcessRunning(locker_pid) )
00206           {
00207             if ( geteuid() == 0 )
00208             {
00209               // i am root
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               // now open it for reading
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         // now open it for reading
00252           openLockFile("r");
00253           shLockFile();
00254         }
00255         return false;
00256       }
00257       return true;
00258     }
00259 
00260   };
00261 
00262   static ZYppGlobalLock globalLock;
00263 
00265   //
00266   //    CLASS NAME : ZYppFactoryException
00267   //
00269 
00270   ZYppFactoryException::ZYppFactoryException( const std::string & msg_r )
00271   : Exception(N_("Cannot aquire zypp lock."))
00272   {}
00273 
00275   //
00276   //    CLASS NAME : ZYppFactory
00277   //
00279 
00281   //
00282   //    METHOD NAME : ZYppFactory::instance
00283   //    METHOD TYPE : ZYppFactory
00284   //
00285   ZYppFactory ZYppFactory::instance()
00286   {
00287     return ZYppFactory();
00288   }
00289 
00291   //
00292   //    METHOD NAME : ZYppFactory::ZYppFactory
00293   //    METHOD TYPE : Ctor
00294   //
00295   ZYppFactory::ZYppFactory()
00296   {
00297 
00298   }
00299 
00301   //
00302   //    METHOD NAME : ZYppFactory::~ZYppFactory
00303   //    METHOD TYPE : Dtor
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   **    FUNCTION NAME : operator<<
00341   **    FUNCTION TYPE : std::ostream &
00342   */
00343   std::ostream & operator<<( std::ostream & str, const ZYppFactory & obj )
00344   {
00345     return str << "ZYppFactory";
00346   }
00347 
00349 } // namespace zypp

Generated on Thu May 4 16:03:33 2006 for zypp by  doxygen 1.4.6