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