libzypp 17.25.10
TargetImpl.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
12 #include <iostream>
13 #include <fstream>
14 #include <sstream>
15 #include <string>
16 #include <list>
17 #include <set>
18 
19 #include <sys/types.h>
20 #include <dirent.h>
21 
22 #include <zypp/base/LogTools.h>
23 #include <zypp/base/Exception.h>
24 #include <zypp/base/Iterator.h>
25 #include <zypp/base/Gettext.h>
26 #include <zypp/base/IOStream.h>
27 #include <zypp/base/Functional.h>
29 #include <zypp/base/Json.h>
30 
31 #include <zypp/ZConfig.h>
32 #include <zypp/ZYppFactory.h>
33 #include <zypp/PathInfo.h>
34 
35 #include <zypp/PoolItem.h>
36 #include <zypp/ResObjects.h>
37 #include <zypp/Url.h>
38 #include <zypp/TmpPath.h>
39 #include <zypp/RepoStatus.h>
40 #include <zypp/ExternalProgram.h>
41 #include <zypp/Repository.h>
42 #include <zypp/ShutdownLock_p.h>
43 
44 #include <zypp/ResFilters.h>
45 #include <zypp/HistoryLog.h>
46 #include <zypp/target/TargetImpl.h>
51 
54 
55 #include <zypp/sat/Pool.h>
57 #include <zypp/sat/SolvableSpec.h>
58 #include <zypp/sat/Transaction.h>
59 
60 #include <zypp/PluginExecutor.h>
61 
62 using std::endl;
63 
65 extern "C"
66 {
67 #include <solv/repo_rpmdb.h>
68 }
69 namespace zypp
70 {
71  namespace target
72  {
73  inline std::string rpmDbStateHash( const Pathname & root_r )
74  {
75  std::string ret;
76  AutoDispose<void*> state { ::rpm_state_create( sat::Pool::instance().get(), root_r.c_str() ), ::rpm_state_free };
77  AutoDispose<Chksum*> chk { ::solv_chksum_create( REPOKEY_TYPE_SHA1 ), []( Chksum *chk ) -> void {
78  ::solv_chksum_free( chk, nullptr );
79  } };
80  if ( ::rpm_hash_database_state( state, chk ) == 0 )
81  {
82  int md5l;
83  const unsigned char * md5 = ::solv_chksum_get( chk, &md5l );
84  ret = ::pool_bin2hex( sat::Pool::instance().get(), md5, md5l );
85  }
86  else
87  WAR << "rpm_hash_database_state failed" << endl;
88  return ret;
89  }
90 
91  inline RepoStatus rpmDbRepoStatus( const Pathname & root_r )
92  { return RepoStatus( rpmDbStateHash( root_r ), Date() ); }
93 
94  } // namespace target
95 } // namespace
97 
99 namespace zypp
100 {
102  namespace
103  {
104  // HACK for bnc#906096: let pool re-evaluate multiversion spec
105  // if target root changes. ZConfig returns data sensitive to
106  // current target root.
107  inline void sigMultiversionSpecChanged()
108  {
110  }
111  } //namespace
113 
115  namespace json
116  {
117  // Lazy via template specialisation / should switch to overloading
118 
119  template<>
120  inline std::string toJSON( const ZYppCommitResult::TransactionStepList & steps_r )
121  {
122  using sat::Transaction;
123  json::Array ret;
124 
125  for ( const Transaction::Step & step : steps_r )
126  // ignore implicit deletes due to obsoletes and non-package actions
127  if ( step.stepType() != Transaction::TRANSACTION_IGNORE )
128  ret.add( step );
129 
130  return ret.asJSON();
131  }
132 
134  template<>
135  inline std::string toJSON( const sat::Transaction::Step & step_r )
136  {
137  static const std::string strType( "type" );
138  static const std::string strStage( "stage" );
139  static const std::string strSolvable( "solvable" );
140 
141  static const std::string strTypeDel( "-" );
142  static const std::string strTypeIns( "+" );
143  static const std::string strTypeMul( "M" );
144 
145  static const std::string strStageDone( "ok" );
146  static const std::string strStageFailed( "err" );
147 
148  static const std::string strSolvableN( "n" );
149  static const std::string strSolvableE( "e" );
150  static const std::string strSolvableV( "v" );
151  static const std::string strSolvableR( "r" );
152  static const std::string strSolvableA( "a" );
153 
154  using sat::Transaction;
155  json::Object ret;
156 
157  switch ( step_r.stepType() )
158  {
159  case Transaction::TRANSACTION_IGNORE: /*empty*/ break;
160  case Transaction::TRANSACTION_ERASE: ret.add( strType, strTypeDel ); break;
161  case Transaction::TRANSACTION_INSTALL: ret.add( strType, strTypeIns ); break;
162  case Transaction::TRANSACTION_MULTIINSTALL: ret.add( strType, strTypeMul ); break;
163  }
164 
165  switch ( step_r.stepStage() )
166  {
167  case Transaction::STEP_TODO: /*empty*/ break;
168  case Transaction::STEP_DONE: ret.add( strStage, strStageDone ); break;
169  case Transaction::STEP_ERROR: ret.add( strStage, strStageFailed ); break;
170  }
171 
172  {
173  IdString ident;
174  Edition ed;
175  Arch arch;
176  if ( sat::Solvable solv = step_r.satSolvable() )
177  {
178  ident = solv.ident();
179  ed = solv.edition();
180  arch = solv.arch();
181  }
182  else
183  {
184  // deleted package; post mortem data stored in Transaction::Step
185  ident = step_r.ident();
186  ed = step_r.edition();
187  arch = step_r.arch();
188  }
189 
190  json::Object s {
191  { strSolvableN, ident.asString() },
192  { strSolvableV, ed.version() },
193  { strSolvableR, ed.release() },
194  { strSolvableA, arch.asString() }
195  };
196  if ( Edition::epoch_t epoch = ed.epoch() )
197  s.add( strSolvableE, epoch );
198 
199  ret.add( strSolvable, s );
200  }
201 
202  return ret.asJSON();
203  }
204  } // namespace json
206 
208  namespace target
209  {
211  namespace
212  {
215  class AssertProcMounted
216  {
217  NON_COPYABLE(AssertProcMounted);
218  NON_MOVABLE(AssertProcMounted);
219  public:
220 
221  AssertProcMounted( Pathname root_r )
222  {
223  root_r /= "/proc";
224  if ( ! PathInfo(root_r/"self").isDir() ) {
225  MIL << "Try to make sure proc is mounted at" << _mountpoint << endl;
226  if ( filesystem::assert_dir(root_r) == 0
227  && execute({ "mount", "-t", "proc", "proc", root_r.asString() }) == 0 ) {
228  _mountpoint = std::move(root_r); // so we'll later unmount it
229  }
230  else {
231  WAR << "Mounting proc at " << _mountpoint << " failed" << endl;
232  }
233  }
234  }
235 
236  ~~AssertProcMounted( )
237  {
238  if ( ! _mountpoint.empty() ) {
239  // we mounted it so we unmount...
240  MIL << "We mounted " << _mountpoint << " so we unmount it" << endl;
241  execute({ "umount", "-l", _mountpoint.asString() });
242  }
243  }
244 
245  private:
246  int execute( ExternalProgram::Arguments && cmd_r ) const
247  {
248  ExternalProgram prog( cmd_r, ExternalProgram::Stderr_To_Stdout );
249  for( std::string line = prog.receiveLine(); ! line.empty(); line = prog.receiveLine() )
250  { DBG << line; }
251  return prog.close();
252  }
253 
254  private:
255  Pathname _mountpoint;
256  };
257  } // namespace
259 
261  namespace
262  {
263  SolvIdentFile::Data getUserInstalledFromHistory( const Pathname & historyFile_r )
264  {
265  SolvIdentFile::Data onSystemByUserList;
266  // go and parse it: 'who' must constain an '@', then it was installed by user request.
267  // 2009-09-29 07:25:19|install|lirc-remotes|0.8.5-3.2|x86_64|root@opensuse|InstallationImage|a204211eb0...
268  std::ifstream infile( historyFile_r.c_str() );
269  for( iostr::EachLine in( infile ); in; in.next() )
270  {
271  const char * ch( (*in).c_str() );
272  // start with year
273  if ( *ch < '1' || '9' < *ch )
274  continue;
275  const char * sep1 = ::strchr( ch, '|' ); // | after date
276  if ( !sep1 )
277  continue;
278  ++sep1;
279  // if logs an install or delete
280  bool installs = true;
281  if ( ::strncmp( sep1, "install|", 8 ) )
282  {
283  if ( ::strncmp( sep1, "remove |", 8 ) )
284  continue; // no install and no remove
285  else
286  installs = false; // remove
287  }
288  sep1 += 8; // | after what
289  // get the package name
290  const char * sep2 = ::strchr( sep1, '|' ); // | after name
291  if ( !sep2 || sep1 == sep2 )
292  continue;
293  (*in)[sep2-ch] = '\0';
294  IdString pkg( sep1 );
295  // we're done, if a delete
296  if ( !installs )
297  {
298  onSystemByUserList.erase( pkg );
299  continue;
300  }
301  // now guess whether user installed or not (3rd next field contains 'user@host')
302  if ( (sep1 = ::strchr( sep2+1, '|' )) // | after version
303  && (sep1 = ::strchr( sep1+1, '|' )) // | after arch
304  && (sep2 = ::strchr( sep1+1, '|' )) ) // | after who
305  {
306  (*in)[sep2-ch] = '\0';
307  if ( ::strchr( sep1+1, '@' ) )
308  {
309  // by user
310  onSystemByUserList.insert( pkg );
311  continue;
312  }
313  }
314  }
315  MIL << "onSystemByUserList found: " << onSystemByUserList.size() << endl;
316  return onSystemByUserList;
317  }
318  } // namespace
320 
322  namespace
323  {
324  inline PluginFrame transactionPluginFrame( const std::string & command_r, ZYppCommitResult::TransactionStepList & steps_r )
325  {
326  return PluginFrame( command_r, json::Object {
327  { "TransactionStepList", steps_r }
328  }.asJSON() );
329  }
330  } // namespace
332 
335  {
336  unsigned toKeep( ZConfig::instance().solver_upgradeTestcasesToKeep() );
337  MIL << "Testcases to keep: " << toKeep << endl;
338  if ( !toKeep )
339  return;
340  Target_Ptr target( getZYpp()->getTarget() );
341  if ( ! target )
342  {
343  WAR << "No Target no Testcase!" << endl;
344  return;
345  }
346 
347  std::string stem( "updateTestcase" );
348  Pathname dir( target->assertRootPrefix("/var/log/") );
349  Pathname next( dir / Date::now().form( stem+"-%Y-%m-%d-%H-%M-%S" ) );
350 
351  {
352  std::list<std::string> content;
353  filesystem::readdir( content, dir, /*dots*/false );
354  std::set<std::string> cases;
355  for_( c, content.begin(), content.end() )
356  {
357  if ( str::startsWith( *c, stem ) )
358  cases.insert( *c );
359  }
360  if ( cases.size() >= toKeep )
361  {
362  unsigned toDel = cases.size() - toKeep + 1; // +1 for the new one
363  for_( c, cases.begin(), cases.end() )
364  {
365  filesystem::recursive_rmdir( dir/(*c) );
366  if ( ! --toDel )
367  break;
368  }
369  }
370  }
371 
372  MIL << "Write new testcase " << next << endl;
373  getZYpp()->resolver()->createSolverTestcase( next.asString(), false/*no solving*/ );
374  }
375 
377  namespace
378  {
379 
390  std::pair<bool,PatchScriptReport::Action> doExecuteScript( const Pathname & root_r,
391  const Pathname & script_r,
393  {
394  MIL << "Execute script " << PathInfo(Pathname::assertprefix( root_r,script_r)) << endl;
395 
396  HistoryLog historylog;
397  historylog.comment(script_r.asString() + _(" executed"), /*timestamp*/true);
398  ExternalProgram prog( script_r.asString(), ExternalProgram::Stderr_To_Stdout, false, -1, true, root_r );
399 
400  for ( std::string output = prog.receiveLine(); output.length(); output = prog.receiveLine() )
401  {
402  historylog.comment(output);
403  if ( ! report_r->progress( PatchScriptReport::OUTPUT, output ) )
404  {
405  WAR << "User request to abort script " << script_r << endl;
406  prog.kill();
407  // the rest is handled by exit code evaluation
408  // in case the script has meanwhile finished.
409  }
410  }
411 
412  std::pair<bool,PatchScriptReport::Action> ret( std::make_pair( false, PatchScriptReport::ABORT ) );
413 
414  if ( prog.close() != 0 )
415  {
416  ret.second = report_r->problem( prog.execError() );
417  WAR << "ACTION" << ret.second << "(" << prog.execError() << ")" << endl;
418  std::ostringstream sstr;
419  sstr << script_r << _(" execution failed") << " (" << prog.execError() << ")" << endl;
420  historylog.comment(sstr.str(), /*timestamp*/true);
421  return ret;
422  }
423 
424  report_r->finish();
425  ret.first = true;
426  return ret;
427  }
428 
432  bool executeScript( const Pathname & root_r,
433  const Pathname & script_r,
434  callback::SendReport<PatchScriptReport> & report_r )
435  {
436  std::pair<bool,PatchScriptReport::Action> action( std::make_pair( false, PatchScriptReport::ABORT ) );
437 
438  do {
439  action = doExecuteScript( root_r, script_r, report_r );
440  if ( action.first )
441  return true; // success
442 
443  switch ( action.second )
444  {
446  WAR << "User request to abort at script " << script_r << endl;
447  return false; // requested abort.
448  break;
449 
451  WAR << "User request to skip script " << script_r << endl;
452  return true; // requested skip.
453  break;
454 
456  break; // again
457  }
458  } while ( action.second == PatchScriptReport::RETRY );
459 
460  // THIS is not intended to be reached:
461  INT << "Abort on unknown ACTION request " << action.second << " returned" << endl;
462  return false; // abort.
463  }
464 
470  bool RunUpdateScripts( const Pathname & root_r,
471  const Pathname & scriptsPath_r,
472  const std::vector<sat::Solvable> & checkPackages_r,
473  bool aborting_r )
474  {
475  if ( checkPackages_r.empty() )
476  return true; // no installed packages to check
477 
478  MIL << "Looking for new update scripts in (" << root_r << ")" << scriptsPath_r << endl;
479  Pathname scriptsDir( Pathname::assertprefix( root_r, scriptsPath_r ) );
480  if ( ! PathInfo( scriptsDir ).isDir() )
481  return true; // no script dir
482 
483  std::list<std::string> scripts;
484  filesystem::readdir( scripts, scriptsDir, /*dots*/false );
485  if ( scripts.empty() )
486  return true; // no scripts in script dir
487 
488  // Now collect and execute all matching scripts.
489  // On ABORT: at least log all outstanding scripts.
490  // - "name-version-release"
491  // - "name-version-release-*"
492  bool abort = false;
493  std::map<std::string, Pathname> unify; // scripts <md5,path>
494  for_( it, checkPackages_r.begin(), checkPackages_r.end() )
495  {
496  std::string prefix( str::form( "%s-%s", it->name().c_str(), it->edition().c_str() ) );
497  for_( sit, scripts.begin(), scripts.end() )
498  {
499  if ( ! str::hasPrefix( *sit, prefix ) )
500  continue;
501 
502  if ( (*sit)[prefix.size()] != '\0' && (*sit)[prefix.size()] != '-' )
503  continue; // if not exact match it had to continue with '-'
504 
505  PathInfo script( scriptsDir / *sit );
506  Pathname localPath( scriptsPath_r/(*sit) ); // without root prefix
507  std::string unifytag; // must not stay empty
508 
509  if ( script.isFile() )
510  {
511  // Assert it's set executable, unify by md5sum.
512  filesystem::addmod( script.path(), 0500 );
513  unifytag = filesystem::md5sum( script.path() );
514  }
515  else if ( ! script.isExist() )
516  {
517  // Might be a dangling symlink, might be ok if we are in
518  // instsys (absolute symlink within the system below /mnt).
519  // readlink will tell....
520  unifytag = filesystem::readlink( script.path() ).asString();
521  }
522 
523  if ( unifytag.empty() )
524  continue;
525 
526  // Unify scripts
527  if ( unify[unifytag].empty() )
528  {
529  unify[unifytag] = localPath;
530  }
531  else
532  {
533  // translators: We may find the same script content in files with different names.
534  // Only the first occurence is executed, subsequent ones are skipped. It's a one-line
535  // message for a log file. Preferably start translation with "%s"
536  std::string msg( str::form(_("%s already executed as %s)"), localPath.asString().c_str(), unify[unifytag].c_str() ) );
537  MIL << "Skip update script: " << msg << endl;
538  HistoryLog().comment( msg, /*timestamp*/true );
539  continue;
540  }
541 
542  if ( abort || aborting_r )
543  {
544  WAR << "Aborting: Skip update script " << *sit << endl;
545  HistoryLog().comment(
546  localPath.asString() + _(" execution skipped while aborting"),
547  /*timestamp*/true);
548  }
549  else
550  {
551  MIL << "Found update script " << *sit << endl;
552  callback::SendReport<PatchScriptReport> report;
553  report->start( make<Package>( *it ), script.path() );
554 
555  if ( ! executeScript( root_r, localPath, report ) ) // script path without root prefix!
556  abort = true; // requested abort.
557  }
558  }
559  }
560  return !abort;
561  }
562 
564  //
566 
567  inline void copyTo( std::ostream & out_r, const Pathname & file_r )
568  {
569  std::ifstream infile( file_r.c_str() );
570  for( iostr::EachLine in( infile ); in; in.next() )
571  {
572  out_r << *in << endl;
573  }
574  }
575 
576  inline std::string notificationCmdSubst( const std::string & cmd_r, const UpdateNotificationFile & notification_r )
577  {
578  std::string ret( cmd_r );
579 #define SUBST_IF(PAT,VAL) if ( ret.find( PAT ) != std::string::npos ) ret = str::gsub( ret, PAT, VAL )
580  SUBST_IF( "%p", notification_r.solvable().asString() );
581  SUBST_IF( "%P", notification_r.file().asString() );
582 #undef SUBST_IF
583  return ret;
584  }
585 
586  void sendNotification( const Pathname & root_r,
587  const UpdateNotifications & notifications_r )
588  {
589  if ( notifications_r.empty() )
590  return;
591 
592  std::string cmdspec( ZConfig::instance().updateMessagesNotify() );
593  MIL << "Notification command is '" << cmdspec << "'" << endl;
594  if ( cmdspec.empty() )
595  return;
596 
597  std::string::size_type pos( cmdspec.find( '|' ) );
598  if ( pos == std::string::npos )
599  {
600  ERR << "Can't send Notification: Missing 'format |' in command spec." << endl;
601  HistoryLog().comment( str::Str() << _("Error sending update message notification."), /*timestamp*/true );
602  return;
603  }
604 
605  std::string formatStr( str::toLower( str::trim( cmdspec.substr( 0, pos ) ) ) );
606  std::string commandStr( str::trim( cmdspec.substr( pos + 1 ) ) );
607 
608  enum Format { UNKNOWN, NONE, SINGLE, DIGEST, BULK };
609  Format format = UNKNOWN;
610  if ( formatStr == "none" )
611  format = NONE;
612  else if ( formatStr == "single" )
613  format = SINGLE;
614  else if ( formatStr == "digest" )
615  format = DIGEST;
616  else if ( formatStr == "bulk" )
617  format = BULK;
618  else
619  {
620  ERR << "Can't send Notification: Unknown format '" << formatStr << " |' in command spec." << endl;
621  HistoryLog().comment( str::Str() << _("Error sending update message notification."), /*timestamp*/true );
622  return;
623  }
624 
625  // Take care: commands are ececuted chroot(root_r). The message file
626  // pathnames in notifications_r are local to root_r. For physical access
627  // to the file they need to be prefixed.
628 
629  if ( format == NONE || format == SINGLE )
630  {
631  for_( it, notifications_r.begin(), notifications_r.end() )
632  {
633  std::vector<std::string> command;
634  if ( format == SINGLE )
635  command.push_back( "<"+Pathname::assertprefix( root_r, it->file() ).asString() );
636  str::splitEscaped( notificationCmdSubst( commandStr, *it ), std::back_inserter( command ) );
637 
638  ExternalProgram prog( command, ExternalProgram::Stderr_To_Stdout, false, -1, true, root_r );
639  if ( true ) // Wait for feedback
640  {
641  for( std::string line = prog.receiveLine(); ! line.empty(); line = prog.receiveLine() )
642  {
643  DBG << line;
644  }
645  int ret = prog.close();
646  if ( ret != 0 )
647  {
648  ERR << "Notification command returned with error (" << ret << ")." << endl;
649  HistoryLog().comment( str::Str() << _("Error sending update message notification."), /*timestamp*/true );
650  return;
651  }
652  }
653  }
654  }
655  else if ( format == DIGEST || format == BULK )
656  {
657  filesystem::TmpFile tmpfile;
658  std::ofstream out( tmpfile.path().c_str() );
659  for_( it, notifications_r.begin(), notifications_r.end() )
660  {
661  if ( format == DIGEST )
662  {
663  out << it->file() << endl;
664  }
665  else if ( format == BULK )
666  {
667  copyTo( out << '\f', Pathname::assertprefix( root_r, it->file() ) );
668  }
669  }
670 
671  std::vector<std::string> command;
672  command.push_back( "<"+tmpfile.path().asString() ); // redirect input
673  str::splitEscaped( notificationCmdSubst( commandStr, *notifications_r.begin() ), std::back_inserter( command ) );
674 
675  ExternalProgram prog( command, ExternalProgram::Stderr_To_Stdout, false, -1, true, root_r );
676  if ( true ) // Wait for feedback otherwise the TmpFile goes out of scope.
677  {
678  for( std::string line = prog.receiveLine(); ! line.empty(); line = prog.receiveLine() )
679  {
680  DBG << line;
681  }
682  int ret = prog.close();
683  if ( ret != 0 )
684  {
685  ERR << "Notification command returned with error (" << ret << ")." << endl;
686  HistoryLog().comment( str::Str() << _("Error sending update message notification."), /*timestamp*/true );
687  return;
688  }
689  }
690  }
691  else
692  {
693  INT << "Can't send Notification: Missing handler for 'format |' in command spec." << endl;
694  HistoryLog().comment( str::Str() << _("Error sending update message notification."), /*timestamp*/true );
695  return;
696  }
697  }
698 
699 
705  void RunUpdateMessages( const Pathname & root_r,
706  const Pathname & messagesPath_r,
707  const std::vector<sat::Solvable> & checkPackages_r,
708  ZYppCommitResult & result_r )
709  {
710  if ( checkPackages_r.empty() )
711  return; // no installed packages to check
712 
713  MIL << "Looking for new update messages in (" << root_r << ")" << messagesPath_r << endl;
714  Pathname messagesDir( Pathname::assertprefix( root_r, messagesPath_r ) );
715  if ( ! PathInfo( messagesDir ).isDir() )
716  return; // no messages dir
717 
718  std::list<std::string> messages;
719  filesystem::readdir( messages, messagesDir, /*dots*/false );
720  if ( messages.empty() )
721  return; // no messages in message dir
722 
723  // Now collect all matching messages in result and send them
724  // - "name-version-release"
725  // - "name-version-release-*"
726  HistoryLog historylog;
727  for_( it, checkPackages_r.begin(), checkPackages_r.end() )
728  {
729  std::string prefix( str::form( "%s-%s", it->name().c_str(), it->edition().c_str() ) );
730  for_( sit, messages.begin(), messages.end() )
731  {
732  if ( ! str::hasPrefix( *sit, prefix ) )
733  continue;
734 
735  if ( (*sit)[prefix.size()] != '\0' && (*sit)[prefix.size()] != '-' )
736  continue; // if not exact match it had to continue with '-'
737 
738  PathInfo message( messagesDir / *sit );
739  if ( ! message.isFile() || message.size() == 0 )
740  continue;
741 
742  MIL << "Found update message " << *sit << endl;
743  Pathname localPath( messagesPath_r/(*sit) ); // without root prefix
744  result_r.rUpdateMessages().push_back( UpdateNotificationFile( *it, localPath ) );
745  historylog.comment( str::Str() << _("New update message") << " " << localPath, /*timestamp*/true );
746  }
747  }
748  sendNotification( root_r, result_r.updateMessages() );
749  }
750 
754  void logPatchStatusChanges( const sat::Transaction & transaction_r, TargetImpl & target_r )
755  {
757  if ( changedPseudoInstalled.empty() )
758  return;
759 
760  if ( ! transaction_r.actionEmpty( ~sat::Transaction::STEP_DONE ) )
761  {
762  // Need to recompute the patch list if commit is incomplete!
763  // We remember the initially established status, then reload the
764  // Target to get the current patch status. Then compare.
765  WAR << "Need to recompute the patch status changes as commit is incomplete!" << endl;
766  ResPool::EstablishedStates establishedStates{ ResPool::instance().establishedStates() };
767  target_r.load();
768  changedPseudoInstalled = establishedStates.changedPseudoInstalled();
769  }
770 
771  HistoryLog historylog;
772  for ( const auto & el : changedPseudoInstalled )
773  historylog.patchStateChange( el.first, el.second );
774  }
775 
777  } // namespace
779 
780  void XRunUpdateMessages( const Pathname & root_r,
781  const Pathname & messagesPath_r,
782  const std::vector<sat::Solvable> & checkPackages_r,
783  ZYppCommitResult & result_r )
784  { RunUpdateMessages( root_r, messagesPath_r, checkPackages_r, result_r ); }
785 
787 
789 
791  //
792  // METHOD NAME : TargetImpl::TargetImpl
793  // METHOD TYPE : Ctor
794  //
795  TargetImpl::TargetImpl( const Pathname & root_r, bool doRebuild_r )
796  : _root( root_r )
797  , _requestedLocalesFile( home() / "RequestedLocales" )
798  , _autoInstalledFile( home() / "AutoInstalled" )
799  , _hardLocksFile( Pathname::assertprefix( _root, ZConfig::instance().locksFile() ) )
800  , _vendorAttr( Pathname::assertprefix( _root, ZConfig::instance().vendorPath() ) )
801  {
802  _rpm.initDatabase( root_r, doRebuild_r );
803 
805 
807  sigMultiversionSpecChanged(); // HACK: see sigMultiversionSpecChanged
808  MIL << "Initialized target on " << _root << endl;
809  }
810 
814  static std::string generateRandomId()
815  {
816  std::ifstream uuidprovider( "/proc/sys/kernel/random/uuid" );
817  return iostr::getline( uuidprovider );
818  }
819 
825  void updateFileContent( const Pathname &filename,
826  boost::function<bool ()> condition,
827  boost::function<std::string ()> value )
828  {
829  std::string val = value();
830  // if the value is empty, then just dont
831  // do anything, regardless of the condition
832  if ( val.empty() )
833  return;
834 
835  if ( condition() )
836  {
837  MIL << "updating '" << filename << "' content." << endl;
838 
839  // if the file does not exist we need to generate the uuid file
840 
841  std::ofstream filestr;
842  // make sure the path exists
843  filesystem::assert_dir( filename.dirname() );
844  filestr.open( filename.c_str() );
845 
846  if ( filestr.good() )
847  {
848  filestr << val;
849  filestr.close();
850  }
851  else
852  {
853  // FIXME, should we ignore the error?
854  ZYPP_THROW(Exception("Can't openfile '" + filename.asString() + "' for writing"));
855  }
856  }
857  }
858 
860  static bool fileMissing( const Pathname &pathname )
861  {
862  return ! PathInfo(pathname).isExist();
863  }
864 
866  {
867  // bsc#1024741: Omit creating a new uid for chrooted systems (if it already has one, fine)
868  if ( root() != "/" )
869  return;
870 
871  // Create the anonymous unique id, used for download statistics
872  Pathname idpath( home() / "AnonymousUniqueId");
873 
874  try
875  {
876  updateFileContent( idpath,
877  boost::bind(fileMissing, idpath),
879  }
880  catch ( const Exception &e )
881  {
882  WAR << "Can't create anonymous id file" << endl;
883  }
884 
885  }
886 
888  {
889  // create the anonymous unique id
890  // this value is used for statistics
891  Pathname flavorpath( home() / "LastDistributionFlavor");
892 
893  // is there a product
895  if ( ! p )
896  {
897  WAR << "No base product, I won't create flavor cache" << endl;
898  return;
899  }
900 
901  std::string flavor = p->flavor();
902 
903  try
904  {
905 
906  updateFileContent( flavorpath,
907  // only if flavor is not empty
908  functor::Constant<bool>( ! flavor.empty() ),
910  }
911  catch ( const Exception &e )
912  {
913  WAR << "Can't create flavor cache" << endl;
914  return;
915  }
916  }
917 
919  //
920  // METHOD NAME : TargetImpl::~TargetImpl
921  // METHOD TYPE : Dtor
922  //
924  {
926  sigMultiversionSpecChanged(); // HACK: see sigMultiversionSpecChanged
927  MIL << "Targets closed" << endl;
928  }
929 
931  //
932  // solv file handling
933  //
935 
937  {
938  return Pathname::assertprefix( _root, ZConfig::instance().repoSolvfilesPath() / sat::Pool::instance().systemRepoAlias() );
939  }
940 
942  {
943  Pathname base = solvfilesPath();
945  }
946 
948  {
949  Pathname base = solvfilesPath();
950  Pathname rpmsolv = base/"solv";
951  Pathname rpmsolvcookie = base/"cookie";
952 
953  bool build_rpm_solv = true;
954  // lets see if the rpm solv cache exists
955 
956  RepoStatus rpmstatus( rpmDbRepoStatus(_root) && RepoStatus(_root/"etc/products.d") );
957 
958  bool solvexisted = PathInfo(rpmsolv).isExist();
959  if ( solvexisted )
960  {
961  // see the status of the cache
962  PathInfo cookie( rpmsolvcookie );
963  MIL << "Read cookie: " << cookie << endl;
964  if ( cookie.isExist() )
965  {
966  RepoStatus status = RepoStatus::fromCookieFile(rpmsolvcookie);
967  // now compare it with the rpm database
968  if ( status == rpmstatus )
969  build_rpm_solv = false;
970  MIL << "Read cookie: " << rpmsolvcookie << " says: "
971  << (build_rpm_solv ? "outdated" : "uptodate") << endl;
972  }
973  }
974 
975  if ( build_rpm_solv )
976  {
977  // if the solvfile dir does not exist yet, we better create it
978  filesystem::assert_dir( base );
979 
980  Pathname oldSolvFile( solvexisted ? rpmsolv : Pathname() ); // to speedup rpmdb2solv
981 
983  if ( !tmpsolv )
984  {
985  // Can't create temporary solv file, usually due to insufficient permission
986  // (user query while @System solv needs refresh). If so, try switching
987  // to a location within zypps temp. space (will be cleaned at application end).
988 
989  bool switchingToTmpSolvfile = false;
990  Exception ex("Failed to cache rpm database.");
991  ex.remember(str::form("Cannot create temporary file under %s.", base.c_str()));
992 
993  if ( ! solvfilesPathIsTemp() )
994  {
995  base = getZYpp()->tmpPath() / sat::Pool::instance().systemRepoAlias();
996  rpmsolv = base/"solv";
997  rpmsolvcookie = base/"cookie";
998 
999  filesystem::assert_dir( base );
1000  tmpsolv = filesystem::TmpFile::makeSibling( rpmsolv );
1001 
1002  if ( tmpsolv )
1003  {
1004  WAR << "Using a temporary solv file at " << base << endl;
1005  switchingToTmpSolvfile = true;
1006  _tmpSolvfilesPath = base;
1007  }
1008  else
1009  {
1010  ex.remember(str::form("Cannot create temporary file under %s.", base.c_str()));
1011  }
1012  }
1013 
1014  if ( ! switchingToTmpSolvfile )
1015  {
1016  ZYPP_THROW(ex);
1017  }
1018  }
1019 
1020  // Take care we unlink the solvfile on exception
1022 
1024  cmd.push_back( "rpmdb2solv" );
1025  if ( ! _root.empty() ) {
1026  cmd.push_back( "-r" );
1027  cmd.push_back( _root.asString() );
1028  }
1029  cmd.push_back( "-D" );
1030  cmd.push_back( rpm().dbPath().asString() );
1031  cmd.push_back( "-X" ); // autogenerate pattern/product/... from -package
1032  // bsc#1104415: no more application support // cmd.push_back( "-A" ); // autogenerate application pseudo packages
1033  cmd.push_back( "-p" );
1034  cmd.push_back( Pathname::assertprefix( _root, "/etc/products.d" ).asString() );
1035 
1036  if ( ! oldSolvFile.empty() )
1037  cmd.push_back( oldSolvFile.asString() );
1038 
1039  cmd.push_back( "-o" );
1040  cmd.push_back( tmpsolv.path().asString() );
1041 
1043  std::string errdetail;
1044 
1045  for ( std::string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
1046  WAR << " " << output;
1047  if ( errdetail.empty() ) {
1048  errdetail = prog.command();
1049  errdetail += '\n';
1050  }
1051  errdetail += output;
1052  }
1053 
1054  int ret = prog.close();
1055  if ( ret != 0 )
1056  {
1057  Exception ex(str::form("Failed to cache rpm database (%d).", ret));
1058  ex.remember( errdetail );
1059  ZYPP_THROW(ex);
1060  }
1061 
1062  ret = filesystem::rename( tmpsolv, rpmsolv );
1063  if ( ret != 0 )
1064  ZYPP_THROW(Exception("Failed to move cache to final destination"));
1065  // if this fails, don't bother throwing exceptions
1066  filesystem::chmod( rpmsolv, 0644 );
1067 
1068  rpmstatus.saveToCookieFile(rpmsolvcookie);
1069 
1070  // We keep it.
1071  guard.resetDispose();
1072  sat::updateSolvFileIndex( rpmsolv ); // content digest for zypper bash completion
1073 
1074  // system-hook: Finally send notification to plugins
1075  if ( root() == "/" )
1076  {
1077  PluginExecutor plugins;
1078  plugins.load( ZConfig::instance().pluginsPath()/"system" );
1079  if ( plugins )
1080  plugins.send( PluginFrame( "PACKAGESETCHANGED" ) );
1081  }
1082  }
1083  else
1084  {
1085  // On the fly add missing solv.idx files for bash completion.
1086  if ( ! PathInfo(base/"solv.idx").isExist() )
1087  sat::updateSolvFileIndex( rpmsolv );
1088  }
1089  return build_rpm_solv;
1090  }
1091 
1093  {
1094  load( false );
1095  }
1096 
1098  {
1099  Repository system( sat::Pool::instance().findSystemRepo() );
1100  if ( system )
1101  system.eraseFromPool();
1102  }
1103 
1104  void TargetImpl::load( bool force )
1105  {
1106  bool newCache = buildCache();
1107  MIL << "New cache built: " << (newCache?"true":"false") <<
1108  ", force loading: " << (force?"true":"false") << endl;
1109 
1110  // now add the repos to the pool
1111  sat::Pool satpool( sat::Pool::instance() );
1112  Pathname rpmsolv( solvfilesPath() / "solv" );
1113  MIL << "adding " << rpmsolv << " to pool(" << satpool.systemRepoAlias() << ")" << endl;
1114 
1115  // Providing an empty system repo, unload any old content
1116  Repository system( sat::Pool::instance().findSystemRepo() );
1117 
1118  if ( system && ! system.solvablesEmpty() )
1119  {
1120  if ( newCache || force )
1121  {
1122  system.eraseFromPool(); // invalidates system
1123  }
1124  else
1125  {
1126  return; // nothing to do
1127  }
1128  }
1129 
1130  if ( ! system )
1131  {
1132  system = satpool.systemRepo();
1133  }
1134 
1135  try
1136  {
1137  MIL << "adding " << rpmsolv << " to system" << endl;
1138  system.addSolv( rpmsolv );
1139  }
1140  catch ( const Exception & exp )
1141  {
1142  ZYPP_CAUGHT( exp );
1143  MIL << "Try to handle exception by rebuilding the solv-file" << endl;
1144  clearCache();
1145  buildCache();
1146 
1147  system.addSolv( rpmsolv );
1148  }
1149  satpool.rootDir( _root );
1150 
1151  // (Re)Load the requested locales et al.
1152  // If the requested locales are empty, we leave the pool untouched
1153  // to avoid undoing changes the application applied. We expect this
1154  // to happen on a bare metal installation only. An already existing
1155  // target should be loaded before its settings are changed.
1156  {
1158  if ( ! requestedLocales.empty() )
1159  {
1161  }
1162  }
1163  {
1164  if ( ! PathInfo( _autoInstalledFile.file() ).isExist() )
1165  {
1166  // Initialize from history, if it does not exist
1167  Pathname historyFile( Pathname::assertprefix( _root, ZConfig::instance().historyLogFile() ) );
1168  if ( PathInfo( historyFile ).isExist() )
1169  {
1170  SolvIdentFile::Data onSystemByUser( getUserInstalledFromHistory( historyFile ) );
1171  SolvIdentFile::Data onSystemByAuto;
1172  for_( it, system.solvablesBegin(), system.solvablesEnd() )
1173  {
1174  IdString ident( (*it).ident() );
1175  if ( onSystemByUser.find( ident ) == onSystemByUser.end() )
1176  onSystemByAuto.insert( ident );
1177  }
1178  _autoInstalledFile.setData( onSystemByAuto );
1179  }
1180  // on the fly removed any obsolete SoftLocks file
1181  filesystem::unlink( home() / "SoftLocks" );
1182  }
1183  // read from AutoInstalled file
1184  sat::StringQueue q;
1185  for ( const auto & idstr : _autoInstalledFile.data() )
1186  q.push( idstr.id() );
1187  satpool.setAutoInstalled( q );
1188  }
1189 
1190  // Load the needreboot package specs
1191  {
1192  sat::SolvableSpec needrebootSpec;
1193  needrebootSpec.addProvides( Capability("installhint(reboot-needed)") );
1194 
1195  Pathname needrebootFile { Pathname::assertprefix( root(), ZConfig::instance().needrebootFile() ) };
1196  if ( PathInfo( needrebootFile ).isFile() )
1197  needrebootSpec.parseFrom( needrebootFile );
1198 
1199  Pathname needrebootDir { Pathname::assertprefix( root(), ZConfig::instance().needrebootPath() ) };
1200  if ( PathInfo( needrebootDir ).isDir() )
1201  {
1202  static const StrMatcher isRpmConfigBackup( "\\.rpm(new|save|orig)$", Match::REGEX );
1203 
1205  [&]( const Pathname & dir_r, const char *const str_r )->bool
1206  {
1207  if ( ! isRpmConfigBackup( str_r ) )
1208  {
1209  Pathname needrebootFile { needrebootDir / str_r };
1210  if ( PathInfo( needrebootFile ).isFile() )
1211  needrebootSpec.parseFrom( needrebootFile );
1212  }
1213  return true;
1214  });
1215  }
1216  satpool.setNeedrebootSpec( std::move(needrebootSpec) );
1217  }
1218 
1219  if ( ZConfig::instance().apply_locks_file() )
1220  {
1221  const HardLocksFile::Data & hardLocks( _hardLocksFile.data() );
1222  if ( ! hardLocks.empty() )
1223  {
1224  ResPool::instance().setHardLockQueries( hardLocks );
1225  }
1226  }
1227 
1228  // now that the target is loaded, we can cache the flavor
1230 
1231  MIL << "Target loaded: " << system.solvablesSize() << " resolvables" << endl;
1232  }
1233 
1235  //
1236  // COMMIT
1237  //
1240  {
1241  // ----------------------------------------------------------------- //
1242  ZYppCommitPolicy policy_r( policy_rX );
1243  bool explicitDryRun = policy_r.dryRun(); // explicit dry run will trigger a fileconflict check, implicit (download-only) not.
1244 
1245  ShutdownLock lck("Zypp commit running.");
1246 
1247  // Fake outstanding YCP fix: Honour restriction to media 1
1248  // at installation, but install all remaining packages if post-boot.
1249  if ( policy_r.restrictToMedia() > 1 )
1250  policy_r.allMedia();
1251 
1252  if ( policy_r.downloadMode() == DownloadDefault ) {
1253  if ( root() == "/" )
1254  policy_r.downloadMode(DownloadInHeaps);
1255  else
1256  policy_r.downloadMode(DownloadAsNeeded);
1257  }
1258  // DownloadOnly implies dry-run.
1259  else if ( policy_r.downloadMode() == DownloadOnly )
1260  policy_r.dryRun( true );
1261  // ----------------------------------------------------------------- //
1262 
1263  MIL << "TargetImpl::commit(<pool>, " << policy_r << ")" << endl;
1264 
1266  // Compute transaction:
1268  ZYppCommitResult result( root() );
1269  result.rTransaction() = pool_r.resolver().getTransaction();
1270  result.rTransaction().order();
1271  // steps: this is our todo-list
1273  if ( policy_r.restrictToMedia() )
1274  {
1275  // Collect until the 1st package from an unwanted media occurs.
1276  // Further collection could violate install order.
1277  MIL << "Restrict to media number " << policy_r.restrictToMedia() << endl;
1278  for_( it, result.transaction().begin(), result.transaction().end() )
1279  {
1280  if ( makeResObject( *it )->mediaNr() > 1 )
1281  break;
1282  steps.push_back( *it );
1283  }
1284  }
1285  else
1286  {
1287  result.rTransactionStepList().insert( steps.end(), result.transaction().begin(), result.transaction().end() );
1288  }
1289  MIL << "Todo: " << result << endl;
1290 
1292  // Prepare execution of commit plugins:
1294  PluginExecutor commitPlugins;
1295  if ( root() == "/" && ! policy_r.dryRun() )
1296  {
1297  commitPlugins.load( ZConfig::instance().pluginsPath()/"commit" );
1298  }
1299  if ( commitPlugins )
1300  commitPlugins.send( transactionPluginFrame( "COMMITBEGIN", steps ) );
1301 
1303  // Write out a testcase if we're in dist upgrade mode.
1305  if ( pool_r.resolver().upgradeMode() || pool_r.resolver().upgradingRepos() )
1306  {
1307  if ( ! policy_r.dryRun() )
1308  {
1310  }
1311  else
1312  {
1313  DBG << "dryRun: Not writing upgrade testcase." << endl;
1314  }
1315  }
1316 
1318  // Store non-package data:
1320  if ( ! policy_r.dryRun() )
1321  {
1323  // requested locales
1325  // autoinstalled
1326  {
1327  SolvIdentFile::Data newdata;
1328  for ( sat::Queue::value_type id : result.rTransaction().autoInstalled() )
1329  newdata.insert( IdString(id) );
1330  _autoInstalledFile.setData( newdata );
1331  }
1332  // hard locks
1333  if ( ZConfig::instance().apply_locks_file() )
1334  {
1335  HardLocksFile::Data newdata;
1336  pool_r.getHardLockQueries( newdata );
1337  _hardLocksFile.setData( newdata );
1338  }
1339  }
1340  else
1341  {
1342  DBG << "dryRun: Not stroring non-package data." << endl;
1343  }
1344 
1346  // First collect and display all messages
1347  // associated with patches to be installed.
1349  if ( ! policy_r.dryRun() )
1350  {
1351  for_( it, steps.begin(), steps.end() )
1352  {
1353  if ( ! it->satSolvable().isKind<Patch>() )
1354  continue;
1355 
1356  PoolItem pi( *it );
1357  if ( ! pi.status().isToBeInstalled() )
1358  continue;
1359 
1360  Patch::constPtr patch( asKind<Patch>(pi.resolvable()) );
1361  if ( ! patch ||patch->message().empty() )
1362  continue;
1363 
1364  MIL << "Show message for " << patch << endl;
1366  if ( ! report->show( patch ) )
1367  {
1368  WAR << "commit aborted by the user" << endl;
1370  }
1371  }
1372  }
1373  else
1374  {
1375  DBG << "dryRun: Not checking patch messages." << endl;
1376  }
1377 
1379  // Remove/install packages.
1381  DBG << "commit log file is set to: " << HistoryLog::fname() << endl;
1382  if ( ! policy_r.dryRun() || policy_r.downloadMode() == DownloadOnly )
1383  {
1384  // Prepare the package cache. Pass all items requiring download.
1385  CommitPackageCache packageCache;
1386  packageCache.setCommitList( steps.begin(), steps.end() );
1387 
1388  bool miss = false;
1389  if ( policy_r.downloadMode() != DownloadAsNeeded )
1390  {
1391  // Preload the cache. Until now this means pre-loading all packages.
1392  // Once DownloadInHeaps is fully implemented, this will change and
1393  // we may actually have more than one heap.
1394  for_( it, steps.begin(), steps.end() )
1395  {
1396  switch ( it->stepType() )
1397  {
1400  // proceed: only install actionas may require download.
1401  break;
1402 
1403  default:
1404  // next: no download for or non-packages and delete actions.
1405  continue;
1406  break;
1407  }
1408 
1409  PoolItem pi( *it );
1410  if ( pi->isKind<Package>() || pi->isKind<SrcPackage>() )
1411  {
1412  ManagedFile localfile;
1413  try
1414  {
1415  localfile = packageCache.get( pi );
1416  localfile.resetDispose(); // keep the package file in the cache
1417  }
1418  catch ( const AbortRequestException & exp )
1419  {
1420  it->stepStage( sat::Transaction::STEP_ERROR );
1421  miss = true;
1422  WAR << "commit cache preload aborted by the user" << endl;
1424  break;
1425  }
1426  catch ( const SkipRequestException & exp )
1427  {
1428  ZYPP_CAUGHT( exp );
1429  it->stepStage( sat::Transaction::STEP_ERROR );
1430  miss = true;
1431  WAR << "Skipping cache preload package " << pi->asKind<Package>() << " in commit" << endl;
1432  continue;
1433  }
1434  catch ( const Exception & exp )
1435  {
1436  // bnc #395704: missing catch causes abort.
1437  // TODO see if packageCache fails to handle errors correctly.
1438  ZYPP_CAUGHT( exp );
1439  it->stepStage( sat::Transaction::STEP_ERROR );
1440  miss = true;
1441  INT << "Unexpected Error: Skipping cache preload package " << pi->asKind<Package>() << " in commit" << endl;
1442  continue;
1443  }
1444  }
1445  }
1446  packageCache.preloaded( true ); // try to avoid duplicate infoInCache CBs in commit
1447  }
1448 
1449  if ( miss )
1450  {
1451  ERR << "Some packages could not be provided. Aborting commit."<< endl;
1452  }
1453  else
1454  {
1455  if ( ! policy_r.dryRun() )
1456  {
1457  // if cache is preloaded, check for file conflicts
1458  commitFindFileConflicts( policy_r, result );
1459  commit( policy_r, packageCache, result );
1460  }
1461  else
1462  {
1463  DBG << "dryRun/downloadOnly: Not installing/deleting anything." << endl;
1464  if ( explicitDryRun ) {
1465  // if cache is preloaded, check for file conflicts
1466  commitFindFileConflicts( policy_r, result );
1467  }
1468  }
1469  }
1470  }
1471  else
1472  {
1473  DBG << "dryRun: Not downloading/installing/deleting anything." << endl;
1474  if ( explicitDryRun ) {
1475  // if cache is preloaded, check for file conflicts
1476  commitFindFileConflicts( policy_r, result );
1477  }
1478  }
1479 
1480  {
1481  // NOTE: Removing rpm in a transaction, rpm removes the /var/lib/rpm compat symlink.
1482  // We re-create it, in case it was lost to prevent legacy tools from accidentally
1483  // assuming no database is present.
1484  if ( ! PathInfo(_root/"/var/lib/rpm",PathInfo::LSTAT).isExist()
1485  && PathInfo(_root/"/usr/lib/sysimage/rpm").isDir() ) {
1486  WAR << "(rpm removed in commit?) Inject missing /var/lib/rpm compat symlink to /usr/lib/sysimage/rpm" << endl;
1487  filesystem::assert_dir( _root/"/var/lib" );
1488  filesystem::symlink( "../../usr/lib/sysimage/rpm", _root/"/var/lib/rpm" );
1489  }
1490  }
1491 
1493  // Send result to commit plugins:
1495  if ( commitPlugins )
1496  commitPlugins.send( transactionPluginFrame( "COMMITEND", steps ) );
1497 
1499  // Try to rebuild solv file while rpm database is still in cache
1501  if ( ! policy_r.dryRun() )
1502  {
1503  buildCache();
1504  }
1505 
1506  MIL << "TargetImpl::commit(<pool>, " << policy_r << ") returns: " << result << endl;
1507  return result;
1508  }
1509 
1511  //
1512  // COMMIT internal
1513  //
1515  namespace
1516  {
1517  struct NotifyAttemptToModify
1518  {
1519  NotifyAttemptToModify( ZYppCommitResult & result_r ) : _result( result_r ) {}
1520 
1521  void operator()()
1522  { if ( _guard ) { _result.attemptToModify( true ); _guard = false; } }
1523 
1524  TrueBool _guard;
1525  ZYppCommitResult & _result;
1526  };
1527  } // namespace
1528 
1529  void TargetImpl::commit( const ZYppCommitPolicy & policy_r,
1530  CommitPackageCache & packageCache_r,
1531  ZYppCommitResult & result_r )
1532  {
1533  // steps: this is our todo-list
1535  MIL << "TargetImpl::commit(<list>" << policy_r << ")" << steps.size() << endl;
1536 
1538 
1539  // Send notification once upon 1st call to rpm
1540  NotifyAttemptToModify attemptToModify( result_r );
1541 
1542  bool abort = false;
1543 
1544  // bsc#1181328: Some systemd tools require /proc to be mounted
1545  AssertProcMounted assertProcMounted( _root );
1546 
1547  RpmPostTransCollector postTransCollector( _root );
1548  std::vector<sat::Solvable> successfullyInstalledPackages;
1549  TargetImpl::PoolItemList remaining;
1550 
1551  for_( step, steps.begin(), steps.end() )
1552  {
1553  PoolItem citem( *step );
1554  if ( step->stepType() == sat::Transaction::TRANSACTION_IGNORE )
1555  {
1556  if ( citem->isKind<Package>() )
1557  {
1558  // for packages this means being obsoleted (by rpm)
1559  // thius no additional action is needed.
1560  step->stepStage( sat::Transaction::STEP_DONE );
1561  continue;
1562  }
1563  }
1564 
1565  if ( citem->isKind<Package>() )
1566  {
1567  Package::constPtr p = citem->asKind<Package>();
1568  if ( citem.status().isToBeInstalled() )
1569  {
1570  ManagedFile localfile;
1571  try
1572  {
1573  localfile = packageCache_r.get( citem );
1574  }
1575  catch ( const AbortRequestException &e )
1576  {
1577  WAR << "commit aborted by the user" << endl;
1578  abort = true;
1579  step->stepStage( sat::Transaction::STEP_ERROR );
1580  break;
1581  }
1582  catch ( const SkipRequestException &e )
1583  {
1584  ZYPP_CAUGHT( e );
1585  WAR << "Skipping package " << p << " in commit" << endl;
1586  step->stepStage( sat::Transaction::STEP_ERROR );
1587  continue;
1588  }
1589  catch ( const Exception &e )
1590  {
1591  // bnc #395704: missing catch causes abort.
1592  // TODO see if packageCache fails to handle errors correctly.
1593  ZYPP_CAUGHT( e );
1594  INT << "Unexpected Error: Skipping package " << p << " in commit" << endl;
1595  step->stepStage( sat::Transaction::STEP_ERROR );
1596  continue;
1597  }
1598 
1599  // create a installation progress report proxy
1600  RpmInstallPackageReceiver progress( citem.resolvable() );
1601  progress.connect(); // disconnected on destruction.
1602 
1603  bool success = false;
1604  rpm::RpmInstFlags flags( policy_r.rpmInstFlags() & rpm::RPMINST_JUSTDB );
1605  // Why force and nodeps?
1606  //
1607  // Because zypp builds the transaction and the resolver asserts that
1608  // everything is fine.
1609  // We use rpm just to unpack and register the package in the database.
1610  // We do this step by step, so rpm is not aware of the bigger context.
1611  // So we turn off rpms internal checks, because we do it inside zypp.
1612  flags |= rpm::RPMINST_NODEPS;
1613  flags |= rpm::RPMINST_FORCE;
1614  //
1615  if (p->multiversionInstall()) flags |= rpm::RPMINST_NOUPGRADE;
1616  if (policy_r.dryRun()) flags |= rpm::RPMINST_TEST;
1617  if (policy_r.rpmExcludeDocs()) flags |= rpm::RPMINST_EXCLUDEDOCS;
1618  if (policy_r.rpmNoSignature()) flags |= rpm::RPMINST_NOSIGNATURE;
1619 
1620  attemptToModify();
1621  try
1622  {
1624  if ( postTransCollector.collectScriptFromPackage( localfile ) )
1625  flags |= rpm::RPMINST_NOPOSTTRANS;
1626  rpm().installPackage( localfile, flags );
1627  HistoryLog().install(citem);
1628 
1629  if ( progress.aborted() )
1630  {
1631  WAR << "commit aborted by the user" << endl;
1632  localfile.resetDispose(); // keep the package file in the cache
1633  abort = true;
1634  step->stepStage( sat::Transaction::STEP_ERROR );
1635  break;
1636  }
1637  else
1638  {
1639  if ( citem.isNeedreboot() ) {
1640  auto rebootNeededFile = root() / "/run/reboot-needed";
1641  if ( filesystem::assert_file( rebootNeededFile ) == EEXIST)
1642  filesystem::touch( rebootNeededFile );
1643  }
1644 
1645  success = true;
1646  step->stepStage( sat::Transaction::STEP_DONE );
1647  }
1648  }
1649  catch ( Exception & excpt_r )
1650  {
1651  ZYPP_CAUGHT(excpt_r);
1652  localfile.resetDispose(); // keep the package file in the cache
1653 
1654  if ( policy_r.dryRun() )
1655  {
1656  WAR << "dry run failed" << endl;
1657  step->stepStage( sat::Transaction::STEP_ERROR );
1658  break;
1659  }
1660  // else
1661  if ( progress.aborted() )
1662  {
1663  WAR << "commit aborted by the user" << endl;
1664  abort = true;
1665  }
1666  else
1667  {
1668  WAR << "Install failed" << endl;
1669  }
1670  step->stepStage( sat::Transaction::STEP_ERROR );
1671  break; // stop
1672  }
1673 
1674  if ( success && !policy_r.dryRun() )
1675  {
1677  successfullyInstalledPackages.push_back( citem.satSolvable() );
1678  step->stepStage( sat::Transaction::STEP_DONE );
1679  }
1680  }
1681  else
1682  {
1683  RpmRemovePackageReceiver progress( citem.resolvable() );
1684  progress.connect(); // disconnected on destruction.
1685 
1686  bool success = false;
1687  rpm::RpmInstFlags flags( policy_r.rpmInstFlags() & rpm::RPMINST_JUSTDB );
1688  flags |= rpm::RPMINST_NODEPS;
1689  if (policy_r.dryRun()) flags |= rpm::RPMINST_TEST;
1690 
1691  attemptToModify();
1692  try
1693  {
1694  rpm().removePackage( p, flags );
1695  HistoryLog().remove(citem);
1696 
1697  if ( progress.aborted() )
1698  {
1699  WAR << "commit aborted by the user" << endl;
1700  abort = true;
1701  step->stepStage( sat::Transaction::STEP_ERROR );
1702  break;
1703  }
1704  else
1705  {
1706  success = true;
1707  step->stepStage( sat::Transaction::STEP_DONE );
1708  }
1709  }
1710  catch (Exception & excpt_r)
1711  {
1712  ZYPP_CAUGHT( excpt_r );
1713  if ( progress.aborted() )
1714  {
1715  WAR << "commit aborted by the user" << endl;
1716  abort = true;
1717  step->stepStage( sat::Transaction::STEP_ERROR );
1718  break;
1719  }
1720  // else
1721  WAR << "removal of " << p << " failed";
1722  step->stepStage( sat::Transaction::STEP_ERROR );
1723  }
1724  if ( success && !policy_r.dryRun() )
1725  {
1727  step->stepStage( sat::Transaction::STEP_DONE );
1728  }
1729  }
1730  }
1731  else if ( ! policy_r.dryRun() ) // other resolvables (non-Package)
1732  {
1733  // Status is changed as the buddy package buddy
1734  // gets installed/deleted. Handle non-buddies only.
1735  if ( ! citem.buddy() )
1736  {
1737  if ( citem->isKind<Product>() )
1738  {
1739  Product::constPtr p = citem->asKind<Product>();
1740  if ( citem.status().isToBeInstalled() )
1741  {
1742  ERR << "Can't install orphan product without release-package! " << citem << endl;
1743  }
1744  else
1745  {
1746  // Deleting the corresponding product entry is all we con do.
1747  // So the product will no longer be visible as installed.
1748  std::string referenceFilename( p->referenceFilename() );
1749  if ( referenceFilename.empty() )
1750  {
1751  ERR << "Can't remove orphan product without 'referenceFilename'! " << citem << endl;
1752  }
1753  else
1754  {
1755  Pathname referencePath { Pathname("/etc/products.d") / referenceFilename }; // no root prefix for rpmdb lookup!
1756  if ( ! rpm().hasFile( referencePath.asString() ) )
1757  {
1758  // If it's not owned by a package, we can delete it.
1759  referencePath = Pathname::assertprefix( _root, referencePath ); // now add a root prefix
1760  if ( filesystem::unlink( referencePath ) != 0 )
1761  ERR << "Delete orphan product failed: " << referencePath << endl;
1762  }
1763  else
1764  {
1765  WAR << "Won't remove orphan product: '/etc/products.d/" << referenceFilename << "' is owned by a package." << endl;
1766  }
1767  }
1768  }
1769  }
1770  else if ( citem->isKind<SrcPackage>() && citem.status().isToBeInstalled() )
1771  {
1772  // SrcPackage is install-only
1773  SrcPackage::constPtr p = citem->asKind<SrcPackage>();
1774  installSrcPackage( p );
1775  }
1776 
1778  step->stepStage( sat::Transaction::STEP_DONE );
1779  }
1780 
1781  } // other resolvables
1782 
1783  } // for
1784 
1785  // process all remembered posttrans scripts. If aborting,
1786  // at least log omitted scripts.
1787  if ( abort || (abort = !postTransCollector.executeScripts()) )
1788  postTransCollector.discardScripts();
1789 
1790  // Check presence of update scripts/messages. If aborting,
1791  // at least log omitted scripts.
1792  if ( ! successfullyInstalledPackages.empty() )
1793  {
1794  if ( ! RunUpdateScripts( _root, ZConfig::instance().update_scriptsPath(),
1795  successfullyInstalledPackages, abort ) )
1796  {
1797  WAR << "Commit aborted by the user" << endl;
1798  abort = true;
1799  }
1800  // send messages after scripts in case some script generates output,
1801  // that should be kept in t %ghost message file.
1802  RunUpdateMessages( _root, ZConfig::instance().update_messagesPath(),
1803  successfullyInstalledPackages,
1804  result_r );
1805  }
1806 
1807  // jsc#SLE-5116: Log patch status changes to history
1808  // NOTE: Should be the last action as it may need to reload
1809  // the Target in case of an incomplete transaction.
1810  logPatchStatusChanges( result_r.transaction(), *this );
1811 
1812  if ( abort )
1813  {
1814  HistoryLog().comment( "Commit was aborted." );
1816  }
1817  }
1818 
1820 
1822  {
1823  return _rpm;
1824  }
1825 
1826  bool TargetImpl::providesFile (const std::string & path_str, const std::string & name_str) const
1827  {
1828  return _rpm.hasFile(path_str, name_str);
1829  }
1830 
1832  namespace
1833  {
1834  parser::ProductFileData baseproductdata( const Pathname & root_r )
1835  {
1837  PathInfo baseproduct( Pathname::assertprefix( root_r, "/etc/products.d/baseproduct" ) );
1838 
1839  if ( baseproduct.isFile() )
1840  {
1841  try
1842  {
1843  ret = parser::ProductFileReader::scanFile( baseproduct.path() );
1844  }
1845  catch ( const Exception & excpt )
1846  {
1847  ZYPP_CAUGHT( excpt );
1848  }
1849  }
1850  else if ( PathInfo( Pathname::assertprefix( root_r, "/etc/products.d" ) ).isDir() )
1851  {
1852  ERR << "baseproduct symlink is dangling or missing: " << baseproduct << endl;
1853  }
1854  return ret;
1855  }
1856 
1857  inline Pathname staticGuessRoot( const Pathname & root_r )
1858  {
1859  if ( root_r.empty() )
1860  {
1861  // empty root: use existing Target or assume "/"
1862  Pathname ret ( ZConfig::instance().systemRoot() );
1863  if ( ret.empty() )
1864  return Pathname("/");
1865  return ret;
1866  }
1867  return root_r;
1868  }
1869 
1870  inline std::string firstNonEmptyLineIn( const Pathname & file_r )
1871  {
1872  std::ifstream idfile( file_r.c_str() );
1873  for( iostr::EachLine in( idfile ); in; in.next() )
1874  {
1875  std::string line( str::trim( *in ) );
1876  if ( ! line.empty() )
1877  return line;
1878  }
1879  return std::string();
1880  }
1881  } // namespace
1883 
1885  {
1886  ResPool pool(ResPool::instance());
1887  for_( it, pool.byKindBegin<Product>(), pool.byKindEnd<Product>() )
1888  {
1889  Product::constPtr p = (*it)->asKind<Product>();
1890  if ( p->isTargetDistribution() )
1891  return p;
1892  }
1893  return nullptr;
1894  }
1895 
1897  {
1898  const Pathname needroot( staticGuessRoot(root_r) );
1899  const Target_constPtr target( getZYpp()->getTarget() );
1900  if ( target && target->root() == needroot )
1901  return target->requestedLocales();
1902  return RequestedLocalesFile( home(needroot) / "RequestedLocales" ).locales();
1903  }
1904 
1906  {
1907  MIL << "updateAutoInstalled if changed..." << endl;
1908  SolvIdentFile::Data newdata;
1909  for ( auto id : sat::Pool::instance().autoInstalled() )
1910  newdata.insert( IdString(id) ); // explicit ctor!
1911  _autoInstalledFile.setData( std::move(newdata) );
1912  }
1913 
1915  { return baseproductdata( _root ).registerTarget(); }
1916  // static version:
1917  std::string TargetImpl::targetDistribution( const Pathname & root_r )
1918  { return baseproductdata( staticGuessRoot(root_r) ).registerTarget(); }
1919 
1921  { return baseproductdata( _root ).registerRelease(); }
1922  // static version:
1923  std::string TargetImpl::targetDistributionRelease( const Pathname & root_r )
1924  { return baseproductdata( staticGuessRoot(root_r) ).registerRelease();}
1925 
1927  { return baseproductdata( _root ).registerFlavor(); }
1928  // static version:
1929  std::string TargetImpl::targetDistributionFlavor( const Pathname & root_r )
1930  { return baseproductdata( staticGuessRoot(root_r) ).registerFlavor();}
1931 
1933  {
1935  parser::ProductFileData pdata( baseproductdata( _root ) );
1936  ret.shortName = pdata.shortName();
1937  ret.summary = pdata.summary();
1938  return ret;
1939  }
1940  // static version:
1942  {
1944  parser::ProductFileData pdata( baseproductdata( staticGuessRoot(root_r) ) );
1945  ret.shortName = pdata.shortName();
1946  ret.summary = pdata.summary();
1947  return ret;
1948  }
1949 
1951  {
1952  if ( _distributionVersion.empty() )
1953  {
1955  if ( !_distributionVersion.empty() )
1956  MIL << "Remember distributionVersion = '" << _distributionVersion << "'" << endl;
1957  }
1958  return _distributionVersion;
1959  }
1960  // static version
1961  std::string TargetImpl::distributionVersion( const Pathname & root_r )
1962  {
1963  std::string distributionVersion = baseproductdata( staticGuessRoot(root_r) ).edition().version();
1964  if ( distributionVersion.empty() )
1965  {
1966  // ...But the baseproduct method is not expected to work on RedHat derivatives.
1967  // On RHEL, Fedora and others the "product version" is determined by the first package
1968  // providing 'system-release'. This value is not hardcoded in YUM and can be configured
1969  // with the $distroverpkg variable.
1970  scoped_ptr<rpm::RpmDb> tmprpmdb;
1971  if ( ZConfig::instance().systemRoot() == Pathname() )
1972  {
1973  try
1974  {
1975  tmprpmdb.reset( new rpm::RpmDb );
1976  tmprpmdb->initDatabase( /*default ctor uses / but no additional keyring exports */ );
1977  }
1978  catch( ... )
1979  {
1980  return "";
1981  }
1982  }
1985  distributionVersion = it->tag_version();
1986  }
1987  return distributionVersion;
1988  }
1989 
1990 
1992  {
1993  return firstNonEmptyLineIn( home() / "LastDistributionFlavor" );
1994  }
1995  // static version:
1996  std::string TargetImpl::distributionFlavor( const Pathname & root_r )
1997  {
1998  return firstNonEmptyLineIn( staticGuessRoot(root_r) / "/var/lib/zypp/LastDistributionFlavor" );
1999  }
2000 
2002  namespace
2003  {
2004  std::string guessAnonymousUniqueId( const Pathname & root_r )
2005  {
2006  // bsc#1024741: Omit creating a new uid for chrooted systems (if it already has one, fine)
2007  std::string ret( firstNonEmptyLineIn( root_r / "/var/lib/zypp/AnonymousUniqueId" ) );
2008  if ( ret.empty() && root_r != "/" )
2009  {
2010  // if it has nonoe, use the outer systems one
2011  ret = firstNonEmptyLineIn( "/var/lib/zypp/AnonymousUniqueId" );
2012  }
2013  return ret;
2014  }
2015  }
2016 
2017  std::string TargetImpl::anonymousUniqueId() const
2018  {
2019  return guessAnonymousUniqueId( root() );
2020  }
2021  // static version:
2022  std::string TargetImpl::anonymousUniqueId( const Pathname & root_r )
2023  {
2024  return guessAnonymousUniqueId( staticGuessRoot(root_r) );
2025  }
2026 
2028 
2029  void TargetImpl::vendorAttr( VendorAttr vendorAttr_r )
2030  {
2031  MIL << "New VendorAttr: " << vendorAttr_r << endl;
2032  _vendorAttr = std::move(vendorAttr_r);
2033  }
2035 
2036  void TargetImpl::installSrcPackage( const SrcPackage_constPtr & srcPackage_r )
2037  {
2038  // provide on local disk
2039  ManagedFile localfile = provideSrcPackage(srcPackage_r);
2040  // create a installation progress report proxy
2041  RpmInstallPackageReceiver progress( srcPackage_r );
2042  progress.connect(); // disconnected on destruction.
2043  // install it
2044  rpm().installPackage ( localfile );
2045  }
2046 
2047  ManagedFile TargetImpl::provideSrcPackage( const SrcPackage_constPtr & srcPackage_r )
2048  {
2049  // provide on local disk
2050  repo::RepoMediaAccess access_r;
2051  repo::SrcPackageProvider prov( access_r );
2052  return prov.provideSrcPackage( srcPackage_r );
2053  }
2055  } // namespace target
2058 } // namespace zypp
#define NON_COPYABLE(CLASS)
Delete copy ctor and copy assign.
Definition: Easy.h:59
#define for_(IT, BEG, END)
Convenient for-loops using iterator.
Definition: Easy.h:28
#define NON_MOVABLE(CLASS)
Delete move ctor and move assign.
Definition: Easy.h:69
#define ZYPP_CAUGHT(EXCPT)
Drops a logline telling the Exception was caught (in order to handle it).
Definition: Exception.h:396
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:392
Interface to gettext.
#define _(MSG)
Definition: Gettext.h:37
#define DBG
Definition: Logger.h:90
#define MIL
Definition: Logger.h:91
#define ERR
Definition: Logger.h:93
#define WAR
Definition: Logger.h:92
#define INT
Definition: Logger.h:95
callback::SendReport< DownloadProgressReport > * report
Definition: MediaCurl.cc:70
#define idstr(V)
const Pathname & _root
Definition: RepoManager.cc:143
Pathname _mountpoint
Definition: TargetImpl.cc:255
#define SUBST_IF(PAT, VAL)
ZYppCommitResult & _result
Definition: TargetImpl.cc:1525
TrueBool _guard
Definition: TargetImpl.cc:1524
Architecture.
Definition: Arch.h:37
const std::string & asString() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: Arch.cc:485
void resetDispose()
Set no dispose function.
Definition: AutoDispose.h:162
A sat capability.
Definition: Capability.h:60
Store and operate on date (time_t).
Definition: Date.h:33
static Date now()
Return the current time.
Definition: Date.h:78
Edition represents [epoch:]version[-release]
Definition: Edition.h:61
unsigned epoch_t
Type of an epoch.
Definition: Edition.h:64
std::string version() const
Version.
Definition: Edition.cc:94
std::string release() const
Release.
Definition: Edition.cc:110
epoch_t epoch() const
Epoch.
Definition: Edition.cc:82
Base class for Exception.
Definition: Exception.h:146
void remember(const Exception &old_r)
Store an other Exception as history.
Definition: Exception.cc:105
Execute a program and give access to its io An object of this class encapsulates the execution of an ...
std::vector< std::string > Arguments
int close()
Wait for the progamm to complete.
const std::string & command() const
The command we're executing.
Writing the zypp history file.
Definition: HistoryLog.h:57
void stampCommand()
Log info about the current process.
Definition: HistoryLog.cc:220
static void setRoot(const Pathname &root)
Set new root directory to the default history log file path.
Definition: HistoryLog.cc:163
void remove(const PoolItem &pi)
Log removal of a package.
Definition: HistoryLog.cc:260
static const Pathname & fname()
Get the current log file path.
Definition: HistoryLog.cc:179
void install(const PoolItem &pi)
Log installation (or update) of a package.
Definition: HistoryLog.cc:232
void comment(const std::string &comment, bool timestamp=false)
Log a comment (even multiline).
Definition: HistoryLog.cc:188
Access to the sat-pools string space.
Definition: IdString.h:43
std::string asString() const
Conversion to std::string
Definition: IdString.h:98
@ REGEX
Regular Expression.
Definition: StrMatcher.h:48
Package interface.
Definition: Package.h:33
TraitsType::constPtrType constPtr
Definition: Package.h:38
Class representing a patch.
Definition: Patch.h:38
TraitsType::constPtrType constPtr
Definition: Patch.h:43
Parallel execution of stateful PluginScripts.
void load(const Pathname &path_r)
Find and launch plugins sending PLUGINBEGIN.
void send(const PluginFrame &frame_r)
Send PluginFrame to all open plugins.
Command frame for communication with PluginScript.
Definition: PluginFrame.h:41
Combining sat::Solvable and ResStatus.
Definition: PoolItem.h:51
ResObject::constPtr resolvable() const
Returns the ResObject::constPtr.
Definition: PoolItem.cc:218
ResStatus & status() const
Returns the current status.
Definition: PoolItem.cc:204
sat::Solvable buddy() const
Return the buddy we share our status object with.
Definition: PoolItem.cc:206
Product interface.
Definition: Product.h:33
TraitsType::constPtrType constPtr
Definition: Product.h:38
Track changing files or directories.
Definition: RepoStatus.h:41
static RepoStatus fromCookieFile(const Pathname &path)
Reads the status from a cookie file.
Definition: RepoStatus.cc:194
void saveToCookieFile(const Pathname &path_r) const
Save the status information to a cookie file.
Definition: RepoStatus.cc:212
bool solvablesEmpty() const
Whether Repository contains solvables.
Definition: Repository.cc:219
SolvableIterator solvablesEnd() const
Iterator behind the last Solvable.
Definition: Repository.cc:241
SolvableIterator solvablesBegin() const
Iterator to the first Solvable.
Definition: Repository.cc:231
size_type solvablesSize() const
Number of solvables in Repository.
Definition: Repository.cc:225
void addSolv(const Pathname &file_r)
Load Solvables from a solv-file.
Definition: Repository.cc:320
void eraseFromPool()
Remove this Repository from it's Pool.
Definition: Repository.cc:297
ChangedPseudoInstalled changedPseudoInstalled() const
Return all pseudo installed items whose current state differs from the established one.
Definition: PoolImpl.cc:26
Global ResObject pool.
Definition: ResPool.h:61
static ResPool instance()
Singleton ctor.
Definition: ResPool.cc:37
EstablishedStates::ChangedPseudoInstalled ChangedPseudoInstalled
Map holding pseudo installed items where current and established status differ.
Definition: ResPool.h:341
void setHardLockQueries(const HardLockQueries &newLocks_r)
Set a new set of queries.
Definition: ResPool.cc:103
Resolver & resolver() const
The Resolver.
Definition: ResPool.cc:61
const LocaleSet & getRequestedLocales() const
Return the requested locales.
Definition: ResPool.cc:130
ChangedPseudoInstalled changedPseudoInstalled() const
Return all pseudo installed items whose current state differs from their initial one.
Definition: ResPool.h:349
byKind_iterator byKindEnd(const ResKind &kind_r) const
Definition: ResPool.h:268
EstablishedStates establishedStates() const
Factory for EstablishedStates.
Definition: ResPool.cc:76
byKind_iterator byKindBegin(const ResKind &kind_r) const
Definition: ResPool.h:261
void getHardLockQueries(HardLockQueries &activeLocks_r)
Suggest a new set of queries based on the current selection.
Definition: ResPool.cc:106
bool isToBeInstalled() const
Definition: ResStatus.h:253
bool resetTransact(TransactByValue causer_r)
Not the same as setTransact( false ).
Definition: ResStatus.h:485
sat::Transaction getTransaction()
Return the Transaction computed by the last solver run.
Definition: Resolver.cc:74
bool upgradeMode() const
Definition: Resolver.cc:97
bool upgradingRepos() const
Whether there is at least one UpgradeRepo request pending.
Definition: Resolver.cc:136
Attempts to create a lock to prevent the system from going into hibernate/shutdown.
SrcPackage interface.
Definition: SrcPackage.h:30
TraitsType::constPtrType constPtr
Definition: SrcPackage.h:36
String matching (STRING|SUBSTRING|GLOB|REGEX).
Definition: StrMatcher.h:298
Definition of vendor equivalence.
Definition: VendorAttr.h:61
Interim helper class to collect global options and settings.
Definition: ZConfig.h:62
static ZConfig & instance()
Singleton ctor.
Definition: Resolver.cc:126
std::string distroverpkg() const
Package telling the "product version" on systems not using /etc/product.d/baseproduct.
Definition: ZConfig.cc:1194
Options and policies for ZYpp::commit.
ZYppCommitPolicy & rpmInstFlags(target::rpm::RpmInstFlags newFlags_r)
The default target::rpm::RpmInstFlags.
ZYppCommitPolicy & rpmExcludeDocs(bool yesNo_r)
Use rpm option –excludedocs (default: false)
ZYppCommitPolicy & dryRun(bool yesNo_r)
Set dry run (default: false).
ZYppCommitPolicy & restrictToMedia(unsigned mediaNr_r)
Restrict commit to media 1.
ZYppCommitPolicy & allMedia()
Process all media (default)
ZYppCommitPolicy & downloadMode(DownloadMode val_r)
Commit download policy to use.
ZYppCommitPolicy & rpmNoSignature(bool yesNo_r)
Use rpm option –nosignature (default: false)
Result returned from ZYpp::commit.
TransactionStepList & rTransactionStepList()
Manipulate transactionStepList.
std::vector< sat::Transaction::Step > TransactionStepList
const sat::Transaction & transaction() const
The full transaction list.
sat::Transaction & rTransaction()
Manipulate transaction.
std::string receiveLine()
Read one line from the input stream.
Wrapper class for ::stat/::lstat.
Definition: PathInfo.h:221
bool isExist() const
Return whether valid stat info exists.
Definition: PathInfo.h:281
Pathname dirname() const
Return all but the last component od this path.
Definition: Pathname.h:124
const std::string & asString() const
String representation.
Definition: Pathname.h:91
bool empty() const
Test for an empty path.
Definition: Pathname.h:114
static Pathname assertprefix(const Pathname &root_r, const Pathname &path_r)
Return path_r prefixed with root_r, unless it is already prefixed.
Definition: Pathname.cc:235
const char * c_str() const
String representation.
Definition: Pathname.h:110
Provide a new empty temporary file and delete it when no longer needed.
Definition: TmpPath.h:128
static TmpFile makeSibling(const Pathname &sibling_r)
Provide a new empty temporary directory as sibling.
Definition: TmpPath.cc:218
Pathname path() const
Definition: TmpPath.cc:146
Data returned by ProductFileReader.
bool empty() const
Whether this is an empty object without valid data.
static ProductFileData scanFile(const Pathname &file_r)
Parse one file (or symlink) and return the ProductFileData parsed.
Provides files from different repos.
ManagedFile provideSrcPackage(const SrcPackage_constPtr &srcPackage_r) const
Provide SrcPackage in a local file.
Global sat-pool.
Definition: Pool.h:47
void setAutoInstalled(const Queue &autoInstalled_r)
Set ident list of all autoinstalled solvables.
Definition: Pool.cc:265
Pathname rootDir() const
Get rootdir (for file conflicts check)
Definition: Pool.cc:64
static Pool instance()
Singleton ctor.
Definition: Pool.h:55
static const std::string & systemRepoAlias()
Reserved system repository alias @System .
Definition: Pool.cc:46
void setNeedrebootSpec(sat::SolvableSpec needrebootSpec_r)
Solvables which should trigger the reboot-needed hint if installed/updated.
Definition: Pool.cc:267
Repository systemRepo()
Return the system repository, create it if missing.
Definition: Pool.cc:178
void initRequestedLocales(const LocaleSet &locales_r)
Start tracking changes based on this locales_r.
Definition: Pool.cc:251
Libsolv Id queue wrapper.
Definition: Queue.h:35
detail::IdType value_type
Definition: Queue.h:38
void push(value_type val_r)
Push a value to the end off the Queue.
Definition: Queue.cc:103
Define a set of Solvables by ident and provides.
Definition: SolvableSpec.h:45
void addProvides(Capability provides_r)
A all sat::Solvable matching this provides_r.
void parseFrom(const InputStream &istr_r)
Parse file istr_r and add it's specs (one per line, #-comments).
A Solvable object within the sat Pool.
Definition: Solvable.h:54
A single step within a Transaction.
Definition: Transaction.h:219
StepType stepType() const
Type of action to perform in this step.
Definition: Transaction.cc:388
StepStage stepStage() const
Step action result.
Definition: Transaction.cc:391
Solvable satSolvable() const
Return the corresponding Solvable.
Definition: Transaction.h:243
Libsolv transaction wrapper.
Definition: Transaction.h:52
const_iterator end() const
Iterator behind the last TransactionStep.
Definition: Transaction.cc:343
StringQueue autoInstalled() const
Return the ident strings of all packages that would be auto-installed after the transaction is run.
Definition: Transaction.cc:358
const_iterator begin() const
Iterator to the first TransactionStep.
Definition: Transaction.cc:337
bool order()
Order transaction steps for commit.
Definition: Transaction.cc:328
@ TRANSACTION_MULTIINSTALL
[M] Install(multiversion) item (
Definition: Transaction.h:67
@ TRANSACTION_INSTALL
[+] Install(update) item
Definition: Transaction.h:66
@ TRANSACTION_IGNORE
[ ] Nothing (includes implicit deletes due to obsoletes and non-package actions)
Definition: Transaction.h:64
@ STEP_DONE
[OK] success
Definition: Transaction.h:74
@ STEP_ERROR
[**] error
Definition: Transaction.h:75
Target::commit helper optimizing package provision.
void setCommitList(std::vector< sat::Solvable > commitList_r)
Download(commit) sequence of solvables to compute read ahead.
bool preloaded() const
Whether preloaded hint is set.
ManagedFile get(const PoolItem &citem_r)
Provide a package.
void setData(const Data &data_r)
Store new Data.
Definition: HardLocksFile.h:73
const Data & data() const
Return the data.
Definition: HardLocksFile.h:57
pool::PoolTraits::HardLockQueries Data
Definition: HardLocksFile.h:41
Save and restore locale set from file.
void setLocales(const LocaleSet &locales_r)
Store a new locale set.
const LocaleSet & locales() const
Return the loacale set.
void tryLevel(target::rpm::InstallResolvableReport::RpmLevel level_r)
Extract and remember posttrans scripts for later execution.
bool collectScriptFromPackage(ManagedFile rpmPackage_r)
Extract and remember a packages posttrans script for later execution.
bool executeScripts()
Execute the remembered scripts.
void discardScripts()
Discard all remembered scrips.
bool aborted() const
Returns true if removing is aborted during progress.
const Pathname & file() const
Return the file path.
Definition: SolvIdentFile.h:46
std::unordered_set< IdString > Data
Definition: SolvIdentFile.h:37
const Data & data() const
Return the data.
Definition: SolvIdentFile.h:53
void setData(const Data &data_r)
Store new Data.
Definition: SolvIdentFile.h:69
Base class for concrete Target implementations.
Definition: TargetImpl.h:55
std::string targetDistributionRelease() const
This is register.release attribute of the installed base product.
Definition: TargetImpl.cc:1920
std::string targetDistribution() const
This is register.target attribute of the installed base product.
Definition: TargetImpl.cc:1914
LocaleSet requestedLocales() const
Languages to be supported by the system.
Definition: TargetImpl.h:158
void updateAutoInstalled()
Update the database of autoinstalled packages.
Definition: TargetImpl.cc:1905
ManagedFile provideSrcPackage(const SrcPackage_constPtr &srcPackage_r)
Provides a source package on the Target.
Definition: TargetImpl.cc:2047
Pathname _root
Path to the target.
Definition: TargetImpl.h:219
RequestedLocalesFile _requestedLocalesFile
Requested Locales database.
Definition: TargetImpl.h:223
void createLastDistributionFlavorCache() const
generates a cache of the last product flavor
Definition: TargetImpl.cc:887
std::string _distributionVersion
Cache distributionVersion.
Definition: TargetImpl.h:229
std::list< PoolItem > PoolItemList
list of pool items
Definition: TargetImpl.h:60
rpm::RpmDb _rpm
RPM database.
Definition: TargetImpl.h:221
rpm::RpmDb & rpm()
The RPM database.
Definition: TargetImpl.cc:1821
Pathname solvfilesPath() const
The solv file location actually in use (default or temp).
Definition: TargetImpl.h:93
std::string distributionVersion() const
This is version attribute of the installed base product.
Definition: TargetImpl.cc:1950
const VendorAttr & vendorAttr() const
The targets current vendor equivalence settings.
Definition: TargetImpl.h:202
void createAnonymousId() const
generates the unique anonymous id which is called when creating the target
Definition: TargetImpl.cc:865
SolvIdentFile _autoInstalledFile
user/auto installed database
Definition: TargetImpl.h:225
Product::constPtr baseProduct() const
returns the target base installed product, also known as the distribution or platform.
Definition: TargetImpl.cc:1884
Target::DistributionLabel distributionLabel() const
This is shortName and summary attribute of the installed base product.
Definition: TargetImpl.cc:1932
virtual ~TargetImpl()
Dtor.
Definition: TargetImpl.cc:923
bool providesFile(const std::string &path_str, const std::string &name_str) const
If the package is installed and provides the file Needed to evaluate split provides during Resolver::...
Definition: TargetImpl.cc:1826
HardLocksFile _hardLocksFile
Hard-Locks database.
Definition: TargetImpl.h:227
Pathname root() const
The root set for this target.
Definition: TargetImpl.h:117
void load(bool force=true)
Definition: TargetImpl.cc:1104
std::string distributionFlavor() const
This is flavor attribute of the installed base product but does not require the target to be loaded a...
Definition: TargetImpl.cc:1991
void installSrcPackage(const SrcPackage_constPtr &srcPackage_r)
Install a source package on the Target.
Definition: TargetImpl.cc:2036
ZYppCommitResult commit(ResPool pool_r, const ZYppCommitPolicy &policy_r)
Commit changes in the pool.
Definition: TargetImpl.cc:1239
VendorAttr _vendorAttr
vendor equivalence settings.
Definition: TargetImpl.h:231
Pathname home() const
The directory to store things.
Definition: TargetImpl.h:121
void commitFindFileConflicts(const ZYppCommitPolicy &policy_r, ZYppCommitResult &result_r)
Commit helper checking for file conflicts after download.
Pathname defaultSolvfilesPath() const
The systems default solv file location.
Definition: TargetImpl.cc:936
std::string anonymousUniqueId() const
anonymous unique id
Definition: TargetImpl.cc:2017
TargetImpl(const Pathname &root_r="/", bool doRebuild_r=false)
Ctor.
Definition: TargetImpl.cc:795
bool solvfilesPathIsTemp() const
Whether we're using a temp.
Definition: TargetImpl.h:97
std::string targetDistributionFlavor() const
This is register.flavor attribute of the installed base product.
Definition: TargetImpl.cc:1926
Interface to the rpm program.
Definition: RpmDb.h:48
void installPackage(const Pathname &filename, RpmInstFlags flags=RPMINST_NONE)
install rpm package
Definition: RpmDb.cc:1571
void initDatabase(Pathname root_r=Pathname(), bool doRebuild_r=false)
Prepare access to the rpm database below root_r.
Definition: RpmDb.cc:264
void removePackage(const std::string &name_r, RpmInstFlags flags=RPMINST_NONE)
remove rpm package
Definition: RpmDb.cc:1766
void closeDatabase()
Block further access to the rpm database and go back to uninitialized state.
Definition: RpmDb.cc:354
bool hasFile(const std::string &file_r, const std::string &name_r="") const
Return true if at least one package owns a certain file (name_r empty) Return true if package name_r ...
Definition: RpmDb.cc:965
Subclass to retrieve database content.
Definition: librpmDb.h:337
bool findByProvides(const std::string &tag_r)
Reset to iterate all packages that provide a certain tag.
Definition: librpmDb.cc:743
int chmod(const Pathname &path, mode_t mode)
Like 'chmod'.
Definition: PathInfo.cc:1054
const StrMatcher & matchNoDots()
Convenience returning StrMatcher( "[^.]*", Match::GLOB )
Definition: PathInfo.cc:545
int readdir(std::list< std::string > &retlist_r, const Pathname &path_r, bool dots_r)
Return content of directory via retlist.
Definition: PathInfo.cc:598
int unlink(const Pathname &path)
Like 'unlink'.
Definition: PathInfo.cc:662
int rename(const Pathname &oldpath, const Pathname &newpath)
Like 'rename'.
Definition: PathInfo.cc:704
int dirForEach(const Pathname &dir_r, function< bool(const Pathname &, const char *const)> fnc_r)
Invoke callback function fnc_r for each entry in directory dir_r.
Definition: PathInfo.cc:551
int assert_file(const Pathname &path, unsigned mode)
Create an empty file if it does not yet exist.
Definition: PathInfo.cc:1145
int recursive_rmdir(const Pathname &path)
Like 'rm -r DIR'.
Definition: PathInfo.cc:413
int addmod(const Pathname &path, mode_t mode)
Add the mode bits to the file given by path.
Definition: PathInfo.cc:1063
int readlink(const Pathname &symlink_r, Pathname &target_r)
Like 'readlink'.
Definition: PathInfo.cc:886
int assert_dir(const Pathname &path, unsigned mode)
Like 'mkdir -p'.
Definition: PathInfo.cc:320
int touch(const Pathname &path)
Change file's modification and access times.
Definition: PathInfo.cc:1196
std::string md5sum(const Pathname &file)
Compute a files md5sum.
Definition: PathInfo.cc:986
int symlink(const Pathname &oldpath, const Pathname &newpath)
Like 'symlink'.
Definition: PathInfo.cc:817
std::string getline(std::istream &str)
Read one line from stream.
Definition: IOStream.cc:33
std::string toJSON(void)
Definition: Json.h:136
SolvableIdType size_type
Definition: PoolMember.h:126
void updateSolvFileIndex(const Pathname &solvfile_r)
Create solv file content digest for zypper bash completion.
Definition: Pool.cc:286
bool hasPrefix(const C_Str &str_r, const C_Str &prefix_r)
Return whether str_r has prefix prefix_r.
Definition: String.h:1023
bool startsWith(const C_Str &str_r, const C_Str &prefix_r)
alias for hasPrefix
Definition: String.h:1081
std::string form(const char *format,...) __attribute__((format(printf
Printf style construction of std::string.
Definition: String.cc:36
std::string toLower(const std::string &s)
Return lowercase version of s.
Definition: String.cc:177
unsigned splitEscaped(const C_Str &line_r, TOutputIterator result_r, const C_Str &sepchars_r=" \t", bool withEmpty=false)
Split line_r into words with respect to escape delimeters.
Definition: String.h:591
std::string trim(const std::string &s, const Trim trim_r)
Definition: String.cc:223
IMPL_PTR_TYPE(TargetImpl)
void XRunUpdateMessages(const Pathname &root_r, const Pathname &messagesPath_r, const std::vector< sat::Solvable > &checkPackages_r, ZYppCommitResult &result_r)
Definition: TargetImpl.cc:780
std::string rpmDbStateHash(const Pathname &root_r)
Definition: TargetImpl.cc:73
void writeUpgradeTestcase()
Definition: TargetImpl.cc:334
static bool fileMissing(const Pathname &pathname)
helper functor
Definition: TargetImpl.cc:860
void updateFileContent(const Pathname &filename, boost::function< bool()> condition, boost::function< std::string()> value)
updates the content of filename if condition is true, setting the content the the value returned by v...
Definition: TargetImpl.cc:825
RepoStatus rpmDbRepoStatus(const Pathname &root_r)
Definition: TargetImpl.cc:91
static std::string generateRandomId()
generates a random id using uuidgen
Definition: TargetImpl.cc:814
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc:2
std::string asString(const DefaultIntegral< Tp, TInitial > &obj)
std::unordered_set< Locale > LocaleSet
Definition: Locale.h:27
ResObject::Ptr makeResObject(const sat::Solvable &solvable_r)
Create ResObject from sat::Solvable.
Definition: ResObject.cc:43
std::list< UpdateNotificationFile > UpdateNotifications
@ DownloadInHeaps
Similar to DownloadInAdvance, but try to split the transaction into heaps, where at the end of each h...
Definition: DownloadMode.h:29
@ DownloadOnly
Just download all packages to the local cache.
Definition: DownloadMode.h:25
@ DownloadAsNeeded
Alternating download and install.
Definition: DownloadMode.h:32
@ DownloadDefault
libzypp will decide what to do.
Definition: DownloadMode.h:24
JSON array.
Definition: Json.h:257
std::string asJSON() const
JSON representation.
Definition: Json.h:279
void add(const Value &val_r)
Push JSON Value to Array.
Definition: Json.h:271
JSON object.
Definition: Json.h:322
void add(const String &key_r, const Value &val_r)
Add key/value pair.
Definition: Json.h:336
std::string asJSON() const
JSON representation.
Definition: Json.h:344
bool isKind(const ResKind &kind_r) const
Definition: SolvableType.h:64
Solvable satSolvable() const
Return the corresponding sat::Solvable.
Definition: SolvableType.h:57
bool isNeedreboot() const
Definition: SolvableType.h:83
static PoolImpl & myPool()
Definition: PoolImpl.cc:178