Fix dumb bug I introduced when allowing the arch to be set from
[platform/upstream/libzypp.git] / zypp / ZYppFactory.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/ZYppFactory.cc
10  *
11 */
12
13 #include <sys/file.h>
14 #include <cstdio>
15 #include <unistd.h>
16 #include <fstream>
17 #include <iostream>
18 #include <sstream>
19
20 #include "zypp/base/Logger.h"
21 #include "zypp/base/Gettext.h"
22 #include "zypp/PathInfo.h"
23
24 #include "zypp/ZYppFactory.h"
25 #include "zypp/zypp_detail/ZYppImpl.h"
26 #include "zypp/zypp_detail/ZYppReadOnlyHack.h"
27
28 #define ZYPP_LOCK_FILE "/var/run/zypp.pid"
29
30 using std::endl;
31 using namespace std;
32
33 ///////////////////////////////////////////////////////////////////
34 namespace zypp
35 { /////////////////////////////////////////////////////////////////
36
37   ///////////////////////////////////////////////////////////////////
38   namespace zypp_readonly_hack
39   { /////////////////////////////////////////////////////////////////
40
41     static bool active = false;
42
43     void IWantIt()
44     {
45       active = true;
46       MIL << "ZYPP_READONLY promised." <<  endl;
47     }
48
49     /////////////////////////////////////////////////////////////////
50   } // namespace zypp_readonly_hack
51   ///////////////////////////////////////////////////////////////////
52
53   ///////////////////////////////////////////////////////////////////
54   //
55   //    CLASS NAME : ZYppGlobalLock
56   //
57   ///////////////////////////////////////////////////////////////////
58
59   class ZYppGlobalLock
60   {
61     public:
62
63       ZYppGlobalLock()
64       : _clean_lock(false)
65       , _zypp_lockfile(0)
66     {}
67
68     ~ZYppGlobalLock()
69     {
70       try
71         {
72           pid_t curr_pid = getpid();
73           if ( _zypp_lockfile )
74             {
75               Pathname lock_file = Pathname(ZYPP_LOCK_FILE);
76               unLockFile();
77               closeLockFile();
78
79               if ( _clean_lock )
80               {
81                 MIL << "Cleaning lock file. (" << curr_pid << ")" << std::endl;
82                 if ( filesystem::unlink(lock_file) == 0 )
83                   MIL << "Lockfile cleaned. (" << curr_pid << ")" << std::endl;
84                 else
85                   ERR << "Cant clean lockfile. (" << curr_pid << ")" << std::endl;
86               }
87             }
88         }
89       catch(...) {} // let no exception escape.
90     }
91
92     bool _clean_lock;
93
94     private:
95     FILE *_zypp_lockfile;
96
97     void openLockFile(const char *mode)
98     {
99       Pathname lock_file = Pathname(ZYPP_LOCK_FILE);
100       _zypp_lockfile = fopen(lock_file.asString().c_str(), mode);
101       if (_zypp_lockfile == 0)
102         ZYPP_THROW (Exception( "Cant open " + lock_file.asString() + " in mode " + std::string(mode) ) );
103     }
104
105     void closeLockFile()
106     {
107       fclose(_zypp_lockfile);
108     }
109
110     void shLockFile()
111     {
112       int fd = fileno(_zypp_lockfile);
113       int lock_error = flock(fd, LOCK_SH);
114       if (lock_error != 0)
115         ZYPP_THROW (Exception( "Cant get shared lock"));
116       else
117         MIL << "locked (shared)" << std::endl;
118     }
119
120     void exLockFile()
121     {
122       int fd = fileno(_zypp_lockfile);
123     // lock access to the file
124       int lock_error = flock(fd, LOCK_EX);
125       if (lock_error != 0)
126         ZYPP_THROW (Exception( "Cant get exclusive lock" ));
127       else
128         MIL << "locked (exclusive)" << std::endl;
129     }
130
131     void unLockFile()
132     {
133       int fd = fileno(_zypp_lockfile);
134     // lock access to the file
135       int lock_error = flock(fd, LOCK_UN);
136       if (lock_error != 0)
137         ZYPP_THROW (Exception( "Cant release lock" ));
138       else
139         MIL << "unlocked" << std::endl;
140     }
141
142     bool lockFileExists()
143     {
144       Pathname lock_file = Pathname(ZYPP_LOCK_FILE);
145     // check if the file already existed.
146       bool exists = PathInfo(lock_file).isExist();
147       return exists;
148     }
149
150     void createLockFile()
151     {
152       pid_t curr_pid = getpid();
153       openLockFile("w");
154       exLockFile();
155       fprintf(_zypp_lockfile, "%ld\n", (long) curr_pid);
156       fflush(_zypp_lockfile);
157       unLockFile();
158       MIL << "written lockfile with pid " << curr_pid << std::endl;
159       closeLockFile();
160     }
161
162     bool isProcessRunning(pid_t pid)
163     {
164     // it is another program, not me, see if it is still running
165       stringstream ss;
166       ss << "/proc/" << pid << "/status";
167       Pathname procfile = Pathname(ss.str());
168       MIL << "Checking " << procfile << " to determine if pid is running: " << pid << std::endl;
169       bool still_running = PathInfo(procfile).isExist();
170       return still_running;
171     }
172
173     pid_t lockerPid()
174     {
175       pid_t curr_pid = getpid();
176       pid_t locked_pid = 0;
177       long readpid = 0;
178
179       fscanf(_zypp_lockfile, "%ld", &readpid);
180       MIL << "read: Lockfile " << ZYPP_LOCK_FILE << " has pid " << readpid << " (our pid: " << curr_pid << ") "<< std::endl;
181       locked_pid = (pid_t) readpid;
182       return locked_pid;
183     }
184
185   public:
186
187     bool zyppLocked()
188     {
189       pid_t curr_pid = getpid();
190       Pathname lock_file = Pathname(ZYPP_LOCK_FILE);
191
192       if ( lockFileExists() )
193       {
194         MIL << "found lockfile " << lock_file << std::endl;
195         openLockFile("r");
196         shLockFile();
197
198         pid_t locker_pid = lockerPid();
199         if ( locker_pid == curr_pid )
200         {
201         // alles ok, we are requesting the instance again
202           //MIL << "Lockfile found, but it is myself. Assuming same process getting zypp instance again." << std::endl;
203           return false;
204         }
205         else
206         {
207           if ( isProcessRunning(locker_pid) )
208           {
209             if ( geteuid() == 0 )
210             {
211               // i am root
212               MIL << locker_pid << " is running and has a ZYpp lock. Sorry" << std::endl;
213               return true;
214             }
215             else
216             {
217               MIL << locker_pid << " is running and has a ZYpp lock. Access as normal user allowed." << std::endl;
218               return false;
219             }
220           }
221           else
222           {
223             if ( geteuid() == 0 )
224             {
225               MIL << locker_pid << " has a ZYpp lock, but process is not running. Cleaning lock file." << std::endl;
226               if ( filesystem::unlink(lock_file) == 0 )
227               {
228                 createLockFile();
229               // now open it for reading
230                 openLockFile("r");
231                 shLockFile();
232                 return false;
233               }
234               else
235               {
236                 ERR << "Can't clean lockfile. Sorry, can't create a new lock. Zypp still locked." << std::endl;
237                 return true;
238               }
239             }
240             else
241             {
242               MIL << locker_pid << " is running and has a ZYpp lock. Access as normal user allowed." << std::endl;
243               return false;
244             }
245           }
246         }
247       }
248       else
249       {
250         MIL << "no lockfile " << lock_file << " found" << std::endl;
251         if ( geteuid() == 0 )
252         {
253           MIL << "running as root. Will attempt to create " << lock_file << std::endl;
254           createLockFile();
255         // now open it for reading
256           openLockFile("r");
257           shLockFile();
258         }
259         else
260         {
261           MIL << "running as user. Skipping creating " << lock_file << std::endl;
262         }
263         return false;
264       }
265       return true;
266     }
267
268   };
269
270   static ZYppGlobalLock globalLock;
271
272   ///////////////////////////////////////////////////////////////////
273   //
274   //    CLASS NAME : ZYppFactoryException
275   //
276   ///////////////////////////////////////////////////////////////////
277
278   ZYppFactoryException::ZYppFactoryException( const std::string & msg_r )
279   : Exception(N_("Cannot aquire zypp lock."))
280   {}
281
282   ///////////////////////////////////////////////////////////////////
283   //
284   //    CLASS NAME : ZYppFactory
285   //
286   ///////////////////////////////////////////////////////////////////
287
288   ///////////////////////////////////////////////////////////////////
289   //
290   //    METHOD NAME : ZYppFactory::instance
291   //    METHOD TYPE : ZYppFactory
292   //
293   ZYppFactory ZYppFactory::instance()
294   {
295     return ZYppFactory();
296   }
297
298   ///////////////////////////////////////////////////////////////////
299   //
300   //    METHOD NAME : ZYppFactory::ZYppFactory
301   //    METHOD TYPE : Ctor
302   //
303   ZYppFactory::ZYppFactory()
304   {
305
306   }
307
308   ///////////////////////////////////////////////////////////////////
309   //
310   //    METHOD NAME : ZYppFactory::~ZYppFactory
311   //    METHOD TYPE : Dtor
312   //
313   ZYppFactory::~ZYppFactory()
314   {}
315
316   ///////////////////////////////////////////////////////////////////
317   //
318   ZYpp::Ptr ZYppFactory::getZYpp() const
319   {
320     static ZYpp::Ptr _instance;
321
322     if ( ! _instance )
323     {
324       /*--------------------------------------------------*/
325       if ( zypp_readonly_hack::active )
326         {
327           _instance = new ZYpp( ZYpp::Impl_Ptr(new ZYpp::Impl) );
328           MIL << "ZYPP_READONLY active." << endl;
329           return _instance;
330         }
331       /*--------------------------------------------------*/
332       if ( globalLock.zyppLocked() )
333       {
334         ZYPP_THROW( ZYppFactoryException(N_("Cannot aquire zypp lock.")) );
335       }
336       else
337       {
338         _instance = new ZYpp( ZYpp::Impl_Ptr(new ZYpp::Impl) );
339         globalLock._clean_lock = true;
340       }
341     }
342
343     return _instance;
344   }
345
346   /******************************************************************
347   **
348   **    FUNCTION NAME : operator<<
349   **    FUNCTION TYPE : std::ostream &
350   */
351   std::ostream & operator<<( std::ostream & str, const ZYppFactory & obj )
352   {
353     return str << "ZYppFactory";
354   }
355
356   /////////////////////////////////////////////////////////////////
357 } // namespace zypp
358 ///////////////////////////////////////////////////////////////////