libzypp  17.31.31
ZYppImpl.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
13 #include <iostream>
14 #include <zypp/TmpPath.h>
15 #include <zypp/base/Logger.h>
16 #include <zypp/base/String.h>
17 #include <zypp/base/Env.h>
18 
20 #include <zypp/target/TargetImpl.h>
21 #include <zypp/ZYpp.h>
22 #include <zypp/DiskUsageCounter.h>
23 #include <zypp/ZConfig.h>
24 #include <zypp/sat/Pool.h>
25 #include <zypp/PoolItem.h>
26 
27 #include <zypp/ZYppCallbacks.h> // JobReport::instance
28 
29 using std::endl;
30 
31 #include <glib.h>
32 #include <zypp-core/zyppng/base/private/linuxhelpers_p.h>
34 
35 namespace {
36 
37  // Helper pipe to safely signal libzypp's poll code
38  // to stop polling and throw a user abort exception.
39  // Due to the pain that is unix signal handling we need
40  // to use atomics and be very careful about what we are calling.
41  //
42  // Not cleaned up, this happens when the application that is using libzypp
43  // exits.
44  volatile sig_atomic_t shutdownPipeRead{-1};
45  volatile sig_atomic_t shutdownPipeWrite{-1};
46 
47  bool makeShutdownPipe() {
48  int pipeFds[]{ -1, -1 };
49  #ifdef HAVE_PIPE2
50  if ( ::pipe2( pipeFds, O_CLOEXEC ) != 0 )
51  return false;
52  #else
53  if ( ::pipe( pipeFds ) != 0 )
54  return false;
55  ::fcntl( pipeFds[0], F_SETFD, O_CLOEXEC );
56  ::fcntl( pipeFds[1], F_SETFD, O_CLOEXEC );
57  #endif
58  shutdownPipeRead = pipeFds[0];
59  shutdownPipeWrite = pipeFds[1];
60  return true;
61  }
62 
63  const bool ensureShutdownPipe() {
64  static auto pipesInitialized = makeShutdownPipe();
65  return pipesInitialized;
66  }
67 
68  const int shutdownPipeReadFd() {
69  if ( !ensureShutdownPipe() )
70  return -1;
71  return static_cast<int>(shutdownPipeRead);
72  }
73 
74  const int shutdownPipeWriteFd() {
75  return static_cast<int>(shutdownPipeWrite);
76  }
77 
78 }
79 
81 namespace zypp
82 {
83 
85  namespace media
86  {
88  {
89  static weak_ptr<callback::TempConnect<media::MediaChangeReport> > globalguard;
90  if ( condition_r && ! (_guard = globalguard.lock()) )
91  {
92  // aquire a new one....
94  globalguard = _guard;
95  }
96  }
97  } // namespace media
99 
101  {
102  static callback::SendReport<JobReport> _report;
103  return _report;
104  }
105 
106 
108  namespace zypp_detail
109  {
110 
112  //
113  // METHOD NAME : ZYppImpl::ZYppImpl
114  // METHOD TYPE : Constructor
115  //
117  : _target( nullptr )
118  , _resolver( new Resolver( ResPool::instance()) )
119  {
120  // trigger creation of the shutdown pipe
121  if ( !ensureShutdownPipe() )
122  WAR << "Failed to create shutdown pipe" << std::endl;
123 
125  MIL << "Initializing keyring..." << std::endl;
126  _keyring = new KeyRing(tmpPath());
127  _keyring->allowPreload( true );
128  }
129 
131  //
132  // METHOD NAME : ZYppImpl::~ZYppImpl
133  // METHOD TYPE : Destructor
134  //
136  {}
137 
138  //------------------------------------------------------------------------
139  // add/remove resolvables
140 
142  {
143  if ( ! _disk_usage )
144  {
146  }
147  return _disk_usage->disk_usage(pool());
148  }
149 
151  {
152  _disk_usage.reset(new DiskUsageCounter());
153  _disk_usage->setMountPoints(mp);
154  }
155 
157  {
158  if (_disk_usage)
159  return _disk_usage->getMountPoints();
160  else
162  }
163 
164  //------------------------------------------------------------------------
165  // target
166 
168  {
169  if (! _target)
170  ZYPP_THROW(Exception("Target not initialized."));
171  return _target;
172  }
173 
175  {
176  if ( _target && newtarget_r ) // bsc#1203760: Make sure the old target is deleted before a new one is created!
177  INT << "2 active targets at the same time must not happen!" << endl;
178  _target = newtarget_r;
180  resolver()->setDefaultSolverFlags( /*all_r*/false ); // just changed defaults
181  }
182 
183  void ZYppImpl::initializeTarget( const Pathname & root, bool doRebuild_r )
184  {
185  MIL << "initTarget( " << root << (doRebuild_r?", rebuilddb":"") << ")" << endl;
186  if (_target) {
187  if (_target->root() == root) {
188  MIL << "Repeated call to initializeTarget()" << endl;
189  return;
190  }
191  _target->unload();
192  _target = nullptr; // bsc#1203760: Make sure the old target is deleted before a new one is created!
193  }
194  changeTargetTo( new Target( root, doRebuild_r ) );
195  _target->buildCache();
196  }
197 
199  {
200  if (_target)
201  _target->unload();
202 
203  changeTargetTo( nullptr );
204  }
205 
206  //------------------------------------------------------------------------
207  // commit
208 
212  {
213  if ( getenv("ZYPP_TESTSUITE_FAKE_ARCH") )
214  {
215  ZYPP_THROW( Exception("ZYPP_TESTSUITE_FAKE_ARCH set. Commit not allowed and disabled.") );
216  }
217 
218  MIL << "Attempt to commit (" << policy_r << ")" << endl;
219  if (! _target)
220  ZYPP_THROW( Exception("Target not initialized.") );
221 
222 
223  env::ScopedSet ea { "ZYPP_IS_RUNNING", str::numstring(getpid()).c_str() };
224  env::ScopedSet eb;
225  if ( _target->chrooted() )
226  eb = env::ScopedSet( "SYSTEMD_OFFLINE", "1" ); // bsc#1118758 - indicate no systemd if chrooted install
227 
228  ZYppCommitResult res = _target->_pimpl->commit( pool(), policy_r );
229 
230  if (! policy_r.dryRun() )
231  {
232  if ( policy_r.syncPoolAfterCommit() )
233  {
234  // reload new status from target
235  DBG << "reloading " << sat::Pool::instance().systemRepoAlias() << " repo to pool" << endl;
236  _target->load();
237  }
238  else
239  {
240  DBG << "unloading " << sat::Pool::instance().systemRepoAlias() << " repo from pool" << endl;
241  _target->unload();
242  }
243  }
244 
245  MIL << "Commit (" << policy_r << ") returned: "
246  << res << endl;
247  return res;
248  }
249 
250  void ZYppImpl::installSrcPackage( const SrcPackage_constPtr & srcPackage_r )
251  {
252  if (! _target)
253  ZYPP_THROW( Exception("Target not initialized.") );
254  _target->_pimpl->installSrcPackage( srcPackage_r );
255  }
256 
257  ManagedFile ZYppImpl::provideSrcPackage( const SrcPackage_constPtr & srcPackage_r )
258  {
259  if (! _target)
260  ZYPP_THROW( Exception("Target not initialized.") );
261  return _target->_pimpl->provideSrcPackage( srcPackage_r );
262  }
263 
264  //------------------------------------------------------------------------
265  // target store path
266 
268  { return _home_path.empty() ? Pathname("/var/lib/zypp") : _home_path; }
269 
270  void ZYppImpl::setHomePath( const Pathname & path )
271  { _home_path = path; }
272 
274  { return zypp::myTmpDir(); }
275 
277  {
278  // ONLY signal safe code here, that means no logging or anything else that is more than using atomics
279  // or writing a fd
280  int sigFd = shutdownPipeWriteFd();
281  if ( sigFd == -1 ) {
282  // we have no fd to set this
283  return;
284  }
285  zyppng::eintrSafeCall( write, sigFd, "1", 1 );
286  }
287 
289  {
290  // ONLY signal safe code here, that means no logging or anything else that is more than using atomics
291  // or writing a fd
292  int sigFd = shutdownPipeWriteFd();
293  if ( sigFd == -1 ) {
294  // we have no fd so nothing to clear
295  return;
296  }
297 
298  char buf;
299  while( zyppng::eintrSafeCall( read, sigFd, &buf, 1 ) > 0 )
300  continue;
301  }
302 
303  /******************************************************************
304  **
305  ** FUNCTION NAME : operator<<
306  ** FUNCTION TYPE : std::ostream &
307  */
308  std::ostream & operator<<( std::ostream & str, const ZYppImpl & obj )
309  {
310  return str << "ZYppImpl";
311  }
312 
313  int zypp_poll( std::vector<GPollFD> &fds, int timeout)
314  {
315  // request a shutdown fd we can use
316  const auto shutdownFd = shutdownPipeReadFd();
317  if (shutdownFd == -1) {
318  ZYPP_THROW( zypp::Exception("Failed to get shutdown pipe") );
319  }
320 
321  fds.push_back( GPollFD {
322  .fd = shutdownFd,
323  .events = G_IO_IN,
324  .revents = 0
325  });
326 
327  // make sure to remove our fd again
328  OnScopeExit removeShutdownFd( [&](){ fds.pop_back(); } );
329 
330  int r = zyppng::eintrSafeCall( g_poll, fds.data(), fds.size(), timeout );
331  if ( r > 0 ) {
332  // at least one fd triggered, if its our's we throw
333  if ( fds.back().revents )
334  ZYPP_THROW( UserRequestException( UserRequestException::ABORT, "Shutdown signal received during poll." ) );
335  }
336  return r;
337  }
338 
340  } // namespace zypp_detail
342 
343  Pathname myTmpDir() // from TmpPath.h
344  {
345  static filesystem::TmpDir _tmpdir( filesystem::TmpPath::defaultLocation(), "zypp." );
346  return _tmpdir.path();
347  }
348 
350 } // namespace zypp
Target_Ptr target() const
Definition: ZYppImpl.cc:167
#define MIL
Definition: Logger.h:96
std::ostream & about(std::ostream &str) const
Print some detail about the current libzypp version.
Definition: ZConfig.cc:1331
void setHomePath(const Pathname &path)
set the home, if you need to change it
Definition: ZYppImpl.cc:270
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:428
Result returned from ZYpp::commit.
static ZConfig & instance()
Singleton ctor.
Definition: ZConfig.cc:922
Gpg key handling.
Definition: KeyRing.h:186
#define INT
Definition: Logger.h:100
struct _GPollFD GPollFD
Definition: ZYppImpl.h:26
static void clearShutdownSignal()
Disable the shutdown signal for zypp_poll calls.
Definition: ZYppImpl.cc:288
ZYppCommitPolicy & dryRun(bool yesNo_r)
Set dry run (default: false).
String related utilities and Regular expression matching.
static const Pathname & defaultLocation()
Definition: TmpPath.cc:157
DiskUsageCounter::MountPointSet diskUsage()
Definition: ZYppImpl.cc:141
Pathname path() const
Definition: TmpPath.cc:146
Resolver_Ptr resolver() const
Definition: ZYppImpl.h:63
DiskUsageCounter::MountPointSet getPartitions() const
Definition: ZYppImpl.cc:156
std::map< std::string, std::string > read(const Pathname &_path)
Read sysconfig file path_r and return (key,valye) pairs.
Definition: sysconfig.cc:34
void initializeTarget(const Pathname &root, bool doRebuild_r)
Definition: ZYppImpl.cc:183
Temporarily connect a ReceiveReport then restore the previous one.
Definition: Callback.h:284
Temporarily set/unset an environment variable.
Definition: Env.h:28
bool write(const Pathname &path_r, const std::string &key_r, const std::string &val_r, const std::string &newcomment_r)
Add or change a value in sysconfig file path_r.
Definition: sysconfig.cc:80
void changeTargetTo(Target_Ptr newtarget_r)
Hook for actions to trigger if the Target changes (initialize/finish)
Definition: ZYppImpl.cc:174
std::set< MountPoint > MountPointSet
shared_ptr< DiskUsageCounter > _disk_usage
defined mount points, used for disk usage counting
Definition: ZYppImpl.h:138
ZYppCommitResult commit(const ZYppCommitPolicy &policy_r)
Commit changes and transactions.
Definition: ZYppImpl.cc:211
bool empty() const
Test for an empty path.
Definition: Pathname.h:114
static Pool instance()
Singleton ctor.
Definition: Pool.h:55
Dependency resolver interface.
Definition: Resolver.h:44
Provide a new empty temporary directory and recursively delete it when no longer needed.
Definition: TmpPath.h:177
static const std::string & systemRepoAlias()
Reserved system repository alias .
Definition: Pool.cc:46
ZYppImpl()
Default ctor.
Definition: ZYppImpl.cc:116
Options and policies for ZYpp::commit.
Pathname tmpPath() const
Get the path where zypp related plugins store tmp data.
Definition: ZYppImpl.cc:273
#define WAR
Definition: Logger.h:97
void installSrcPackage(const SrcPackage_constPtr &srcPackage_r)
Install a source package on the Target.
Definition: ZYppImpl.cc:250
#define nullptr
Definition: Easy.h:55
Pathname homePath() const
Get the path where zypp related plugins store persistent data and caches.
Definition: ZYppImpl.cc:267
Pathname myTmpDir()
Global access to the zypp.TMPDIR (created on demand, deleted when libzypp is unloaded) ...
Definition: ZYppImpl.cc:343
ZYppCommitPolicy & syncPoolAfterCommit(bool yesNo_r)
Kepp pool in sync with the Target databases after commit (default: true)
std::string numstring(char n, int w=0)
Definition: String.h:289
std::ostream & operator<<(std::ostream &str, const ZYppImpl &obj)
Definition: ZYppImpl.cc:308
ScopedDisableMediaChangeReport(bool condition_r=true)
Disbale MediaChangeReport if condition_r is true.
Definition: ZYppImpl.cc:87
Global ResObject pool.
Definition: ResPool.h:60
Base class for Exception.
Definition: Exception.h:145
Compute disk space occupied by packages across partitions/directories.
static void setShutdownSignal()
Enable the shutdown signal for zypp_poll calls.
Definition: ZYppImpl.cc:276
Base for exceptions caused by explicit user request.
shared_ptr< callback::TempConnect< media::MediaChangeReport > > _guard
ResPool pool() const
Definition: ZYppImpl.h:52
static callback::SendReport< JobReport > & instance()
Singleton sender instance.
Definition: ZYppImpl.cc:100
int zypp_poll(std::vector< GPollFD > &fds, int timeout)
Small wrapper around g_poll that additionally listens to the shutdown FD returned by ZYpp::shutdownSi...
Definition: ZYppImpl.cc:313
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc:1
void setPartitions(const DiskUsageCounter::MountPointSet &mp)
Definition: ZYppImpl.cc:150
void notifyTargetChanged()
internal
Definition: ZConfig.cc:947
ManagedFile provideSrcPackage(const SrcPackage_constPtr &srcPackage_r)
Install a source package on the Target.
Definition: ZYppImpl.cc:257
#define DBG
Definition: Logger.h:95
static MountPointSet detectMountPoints(const std::string &rootdir="/")
Get mountpoints of system below rootdir If we happen to detect snapshotting btrfs partitions...