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