libzypp  17.27.0
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  needrebootSpec.addProvides( Capability("kernel") );
1195  needrebootSpec.addIdent( IdString("kernel-firmware") );
1196 
1197  Pathname needrebootFile { Pathname::assertprefix( root(), ZConfig::instance().needrebootFile() ) };
1198  if ( PathInfo( needrebootFile ).isFile() )
1199  needrebootSpec.parseFrom( needrebootFile );
1200 
1201  Pathname needrebootDir { Pathname::assertprefix( root(), ZConfig::instance().needrebootPath() ) };
1202  if ( PathInfo( needrebootDir ).isDir() )
1203  {
1204  static const StrMatcher isRpmConfigBackup( "\\.rpm(new|save|orig)$", Match::REGEX );
1205 
1207  [&]( const Pathname & dir_r, const char *const str_r )->bool
1208  {
1209  if ( ! isRpmConfigBackup( str_r ) )
1210  {
1211  Pathname needrebootFile { needrebootDir / str_r };
1212  if ( PathInfo( needrebootFile ).isFile() )
1213  needrebootSpec.parseFrom( needrebootFile );
1214  }
1215  return true;
1216  });
1217  }
1218  satpool.setNeedrebootSpec( std::move(needrebootSpec) );
1219  }
1220 
1221  if ( ZConfig::instance().apply_locks_file() )
1222  {
1223  const HardLocksFile::Data & hardLocks( _hardLocksFile.data() );
1224  if ( ! hardLocks.empty() )
1225  {
1226  ResPool::instance().setHardLockQueries( hardLocks );
1227  }
1228  }
1229 
1230  // now that the target is loaded, we can cache the flavor
1232 
1233  MIL << "Target loaded: " << system.solvablesSize() << " resolvables" << endl;
1234  }
1235 
1237  //
1238  // COMMIT
1239  //
1242  {
1243  // ----------------------------------------------------------------- //
1244  ZYppCommitPolicy policy_r( policy_rX );
1245  bool explicitDryRun = policy_r.dryRun(); // explicit dry run will trigger a fileconflict check, implicit (download-only) not.
1246 
1247  ShutdownLock lck("Zypp commit running.");
1248 
1249  // Fake outstanding YCP fix: Honour restriction to media 1
1250  // at installation, but install all remaining packages if post-boot.
1251  if ( policy_r.restrictToMedia() > 1 )
1252  policy_r.allMedia();
1253 
1254  if ( policy_r.downloadMode() == DownloadDefault ) {
1255  if ( root() == "/" )
1256  policy_r.downloadMode(DownloadInHeaps);
1257  else
1258  policy_r.downloadMode(DownloadAsNeeded);
1259  }
1260  // DownloadOnly implies dry-run.
1261  else if ( policy_r.downloadMode() == DownloadOnly )
1262  policy_r.dryRun( true );
1263  // ----------------------------------------------------------------- //
1264 
1265  MIL << "TargetImpl::commit(<pool>, " << policy_r << ")" << endl;
1266 
1268  // Compute transaction:
1270  ZYppCommitResult result( root() );
1271  result.rTransaction() = pool_r.resolver().getTransaction();
1272  result.rTransaction().order();
1273  // steps: this is our todo-list
1275  if ( policy_r.restrictToMedia() )
1276  {
1277  // Collect until the 1st package from an unwanted media occurs.
1278  // Further collection could violate install order.
1279  MIL << "Restrict to media number " << policy_r.restrictToMedia() << endl;
1280  for_( it, result.transaction().begin(), result.transaction().end() )
1281  {
1282  if ( makeResObject( *it )->mediaNr() > 1 )
1283  break;
1284  steps.push_back( *it );
1285  }
1286  }
1287  else
1288  {
1289  result.rTransactionStepList().insert( steps.end(), result.transaction().begin(), result.transaction().end() );
1290  }
1291  MIL << "Todo: " << result << endl;
1292 
1294  // Prepare execution of commit plugins:
1296  PluginExecutor commitPlugins;
1297  if ( root() == "/" && ! policy_r.dryRun() )
1298  {
1299  commitPlugins.load( ZConfig::instance().pluginsPath()/"commit" );
1300  }
1301  if ( commitPlugins )
1302  commitPlugins.send( transactionPluginFrame( "COMMITBEGIN", steps ) );
1303 
1305  // Write out a testcase if we're in dist upgrade mode.
1307  if ( pool_r.resolver().upgradeMode() || pool_r.resolver().upgradingRepos() )
1308  {
1309  if ( ! policy_r.dryRun() )
1310  {
1312  }
1313  else
1314  {
1315  DBG << "dryRun: Not writing upgrade testcase." << endl;
1316  }
1317  }
1318 
1320  // Store non-package data:
1322  if ( ! policy_r.dryRun() )
1323  {
1325  // requested locales
1327  // autoinstalled
1328  {
1329  SolvIdentFile::Data newdata;
1330  for ( sat::Queue::value_type id : result.rTransaction().autoInstalled() )
1331  newdata.insert( IdString(id) );
1332  _autoInstalledFile.setData( newdata );
1333  }
1334  // hard locks
1335  if ( ZConfig::instance().apply_locks_file() )
1336  {
1337  HardLocksFile::Data newdata;
1338  pool_r.getHardLockQueries( newdata );
1339  _hardLocksFile.setData( newdata );
1340  }
1341  }
1342  else
1343  {
1344  DBG << "dryRun: Not stroring non-package data." << endl;
1345  }
1346 
1348  // First collect and display all messages
1349  // associated with patches to be installed.
1351  if ( ! policy_r.dryRun() )
1352  {
1353  for_( it, steps.begin(), steps.end() )
1354  {
1355  if ( ! it->satSolvable().isKind<Patch>() )
1356  continue;
1357 
1358  PoolItem pi( *it );
1359  if ( ! pi.status().isToBeInstalled() )
1360  continue;
1361 
1362  Patch::constPtr patch( asKind<Patch>(pi.resolvable()) );
1363  if ( ! patch ||patch->message().empty() )
1364  continue;
1365 
1366  MIL << "Show message for " << patch << endl;
1368  if ( ! report->show( patch ) )
1369  {
1370  WAR << "commit aborted by the user" << endl;
1372  }
1373  }
1374  }
1375  else
1376  {
1377  DBG << "dryRun: Not checking patch messages." << endl;
1378  }
1379 
1381  // Remove/install packages.
1383  DBG << "commit log file is set to: " << HistoryLog::fname() << endl;
1384  if ( ! policy_r.dryRun() || policy_r.downloadMode() == DownloadOnly )
1385  {
1386  // Prepare the package cache. Pass all items requiring download.
1387  CommitPackageCache packageCache;
1388  packageCache.setCommitList( steps.begin(), steps.end() );
1389 
1390  bool miss = false;
1391  if ( policy_r.downloadMode() != DownloadAsNeeded )
1392  {
1393  // Preload the cache. Until now this means pre-loading all packages.
1394  // Once DownloadInHeaps is fully implemented, this will change and
1395  // we may actually have more than one heap.
1396  for_( it, steps.begin(), steps.end() )
1397  {
1398  switch ( it->stepType() )
1399  {
1402  // proceed: only install actionas may require download.
1403  break;
1404 
1405  default:
1406  // next: no download for or non-packages and delete actions.
1407  continue;
1408  break;
1409  }
1410 
1411  PoolItem pi( *it );
1412  if ( pi->isKind<Package>() || pi->isKind<SrcPackage>() )
1413  {
1414  ManagedFile localfile;
1415  try
1416  {
1417  localfile = packageCache.get( pi );
1418  localfile.resetDispose(); // keep the package file in the cache
1419  }
1420  catch ( const AbortRequestException & exp )
1421  {
1422  it->stepStage( sat::Transaction::STEP_ERROR );
1423  miss = true;
1424  WAR << "commit cache preload aborted by the user" << endl;
1426  break;
1427  }
1428  catch ( const SkipRequestException & exp )
1429  {
1430  ZYPP_CAUGHT( exp );
1431  it->stepStage( sat::Transaction::STEP_ERROR );
1432  miss = true;
1433  WAR << "Skipping cache preload package " << pi->asKind<Package>() << " in commit" << endl;
1434  continue;
1435  }
1436  catch ( const Exception & exp )
1437  {
1438  // bnc #395704: missing catch causes abort.
1439  // TODO see if packageCache fails to handle errors correctly.
1440  ZYPP_CAUGHT( exp );
1441  it->stepStage( sat::Transaction::STEP_ERROR );
1442  miss = true;
1443  INT << "Unexpected Error: Skipping cache preload package " << pi->asKind<Package>() << " in commit" << endl;
1444  continue;
1445  }
1446  }
1447  }
1448  packageCache.preloaded( true ); // try to avoid duplicate infoInCache CBs in commit
1449  }
1450 
1451  if ( miss )
1452  {
1453  ERR << "Some packages could not be provided. Aborting commit."<< endl;
1454  }
1455  else
1456  {
1457  if ( ! policy_r.dryRun() )
1458  {
1459  // if cache is preloaded, check for file conflicts
1460  commitFindFileConflicts( policy_r, result );
1461  commit( policy_r, packageCache, result );
1462  }
1463  else
1464  {
1465  DBG << "dryRun/downloadOnly: Not installing/deleting anything." << endl;
1466  if ( explicitDryRun ) {
1467  // if cache is preloaded, check for file conflicts
1468  commitFindFileConflicts( policy_r, result );
1469  }
1470  }
1471  }
1472  }
1473  else
1474  {
1475  DBG << "dryRun: Not downloading/installing/deleting anything." << endl;
1476  if ( explicitDryRun ) {
1477  // if cache is preloaded, check for file conflicts
1478  commitFindFileConflicts( policy_r, result );
1479  }
1480  }
1481 
1482  {
1483  // NOTE: Removing rpm in a transaction, rpm removes the /var/lib/rpm compat symlink.
1484  // We re-create it, in case it was lost to prevent legacy tools from accidentally
1485  // assuming no database is present.
1486  if ( ! PathInfo(_root/"/var/lib/rpm",PathInfo::LSTAT).isExist()
1487  && PathInfo(_root/"/usr/lib/sysimage/rpm").isDir() ) {
1488  WAR << "(rpm removed in commit?) Inject missing /var/lib/rpm compat symlink to /usr/lib/sysimage/rpm" << endl;
1489  filesystem::assert_dir( _root/"/var/lib" );
1490  filesystem::symlink( "../../usr/lib/sysimage/rpm", _root/"/var/lib/rpm" );
1491  }
1492  }
1493 
1495  // Send result to commit plugins:
1497  if ( commitPlugins )
1498  commitPlugins.send( transactionPluginFrame( "COMMITEND", steps ) );
1499 
1501  // Try to rebuild solv file while rpm database is still in cache
1503  if ( ! policy_r.dryRun() )
1504  {
1505  buildCache();
1506  }
1507 
1508  MIL << "TargetImpl::commit(<pool>, " << policy_r << ") returns: " << result << endl;
1509  return result;
1510  }
1511 
1513  //
1514  // COMMIT internal
1515  //
1517  namespace
1518  {
1519  struct NotifyAttemptToModify
1520  {
1521  NotifyAttemptToModify( ZYppCommitResult & result_r ) : _result( result_r ) {}
1522 
1523  void operator()()
1524  { if ( _guard ) { _result.attemptToModify( true ); _guard = false; } }
1525 
1526  TrueBool _guard;
1527  ZYppCommitResult & _result;
1528  };
1529  } // namespace
1530 
1531  void TargetImpl::commit( const ZYppCommitPolicy & policy_r,
1532  CommitPackageCache & packageCache_r,
1533  ZYppCommitResult & result_r )
1534  {
1535  // steps: this is our todo-list
1537  MIL << "TargetImpl::commit(<list>" << policy_r << ")" << steps.size() << endl;
1538 
1540 
1541  // Send notification once upon 1st call to rpm
1542  NotifyAttemptToModify attemptToModify( result_r );
1543 
1544  bool abort = false;
1545 
1546  // bsc#1181328: Some systemd tools require /proc to be mounted
1547  AssertProcMounted assertProcMounted( _root );
1548 
1549  RpmPostTransCollector postTransCollector( _root );
1550  std::vector<sat::Solvable> successfullyInstalledPackages;
1551  TargetImpl::PoolItemList remaining;
1552 
1553  for_( step, steps.begin(), steps.end() )
1554  {
1555  PoolItem citem( *step );
1556  if ( step->stepType() == sat::Transaction::TRANSACTION_IGNORE )
1557  {
1558  if ( citem->isKind<Package>() )
1559  {
1560  // for packages this means being obsoleted (by rpm)
1561  // thius no additional action is needed.
1562  step->stepStage( sat::Transaction::STEP_DONE );
1563  continue;
1564  }
1565  }
1566 
1567  if ( citem->isKind<Package>() )
1568  {
1569  Package::constPtr p = citem->asKind<Package>();
1570  if ( citem.status().isToBeInstalled() )
1571  {
1572  ManagedFile localfile;
1573  try
1574  {
1575  localfile = packageCache_r.get( citem );
1576  }
1577  catch ( const AbortRequestException &e )
1578  {
1579  WAR << "commit aborted by the user" << endl;
1580  abort = true;
1581  step->stepStage( sat::Transaction::STEP_ERROR );
1582  break;
1583  }
1584  catch ( const SkipRequestException &e )
1585  {
1586  ZYPP_CAUGHT( e );
1587  WAR << "Skipping package " << p << " in commit" << endl;
1588  step->stepStage( sat::Transaction::STEP_ERROR );
1589  continue;
1590  }
1591  catch ( const Exception &e )
1592  {
1593  // bnc #395704: missing catch causes abort.
1594  // TODO see if packageCache fails to handle errors correctly.
1595  ZYPP_CAUGHT( e );
1596  INT << "Unexpected Error: Skipping package " << p << " in commit" << endl;
1597  step->stepStage( sat::Transaction::STEP_ERROR );
1598  continue;
1599  }
1600 
1601  // create a installation progress report proxy
1602  RpmInstallPackageReceiver progress( citem.resolvable() );
1603  progress.connect(); // disconnected on destruction.
1604 
1605  bool success = false;
1606  rpm::RpmInstFlags flags( policy_r.rpmInstFlags() & rpm::RPMINST_JUSTDB );
1607  // Why force and nodeps?
1608  //
1609  // Because zypp builds the transaction and the resolver asserts that
1610  // everything is fine.
1611  // We use rpm just to unpack and register the package in the database.
1612  // We do this step by step, so rpm is not aware of the bigger context.
1613  // So we turn off rpms internal checks, because we do it inside zypp.
1614  flags |= rpm::RPMINST_NODEPS;
1615  flags |= rpm::RPMINST_FORCE;
1616  //
1617  if (p->multiversionInstall()) flags |= rpm::RPMINST_NOUPGRADE;
1618  if (policy_r.dryRun()) flags |= rpm::RPMINST_TEST;
1619  if (policy_r.rpmExcludeDocs()) flags |= rpm::RPMINST_EXCLUDEDOCS;
1620  if (policy_r.rpmNoSignature()) flags |= rpm::RPMINST_NOSIGNATURE;
1621 
1622  attemptToModify();
1623  try
1624  {
1626  if ( postTransCollector.collectScriptFromPackage( localfile ) )
1627  flags |= rpm::RPMINST_NOPOSTTRANS;
1628  rpm().installPackage( localfile, flags );
1629  HistoryLog().install(citem);
1630 
1631  if ( progress.aborted() )
1632  {
1633  WAR << "commit aborted by the user" << endl;
1634  localfile.resetDispose(); // keep the package file in the cache
1635  abort = true;
1636  step->stepStage( sat::Transaction::STEP_ERROR );
1637  break;
1638  }
1639  else
1640  {
1641  if ( citem.isNeedreboot() ) {
1642  auto rebootNeededFile = root() / "/run/reboot-needed";
1643  if ( filesystem::assert_file( rebootNeededFile ) == EEXIST)
1644  filesystem::touch( rebootNeededFile );
1645  }
1646 
1647  success = true;
1648  step->stepStage( sat::Transaction::STEP_DONE );
1649  }
1650  }
1651  catch ( Exception & excpt_r )
1652  {
1653  ZYPP_CAUGHT(excpt_r);
1654  localfile.resetDispose(); // keep the package file in the cache
1655 
1656  if ( policy_r.dryRun() )
1657  {
1658  WAR << "dry run failed" << endl;
1659  step->stepStage( sat::Transaction::STEP_ERROR );
1660  break;
1661  }
1662  // else
1663  if ( progress.aborted() )
1664  {
1665  WAR << "commit aborted by the user" << endl;
1666  abort = true;
1667  }
1668  else
1669  {
1670  WAR << "Install failed" << endl;
1671  }
1672  step->stepStage( sat::Transaction::STEP_ERROR );
1673  break; // stop
1674  }
1675 
1676  if ( success && !policy_r.dryRun() )
1677  {
1679  successfullyInstalledPackages.push_back( citem.satSolvable() );
1680  step->stepStage( sat::Transaction::STEP_DONE );
1681  }
1682  }
1683  else
1684  {
1685  RpmRemovePackageReceiver progress( citem.resolvable() );
1686  progress.connect(); // disconnected on destruction.
1687 
1688  bool success = false;
1689  rpm::RpmInstFlags flags( policy_r.rpmInstFlags() & rpm::RPMINST_JUSTDB );
1690  flags |= rpm::RPMINST_NODEPS;
1691  if (policy_r.dryRun()) flags |= rpm::RPMINST_TEST;
1692 
1693  attemptToModify();
1694  try
1695  {
1696  rpm().removePackage( p, flags );
1697  HistoryLog().remove(citem);
1698 
1699  if ( progress.aborted() )
1700  {
1701  WAR << "commit aborted by the user" << endl;
1702  abort = true;
1703  step->stepStage( sat::Transaction::STEP_ERROR );
1704  break;
1705  }
1706  else
1707  {
1708  success = true;
1709  step->stepStage( sat::Transaction::STEP_DONE );
1710  }
1711  }
1712  catch (Exception & excpt_r)
1713  {
1714  ZYPP_CAUGHT( excpt_r );
1715  if ( progress.aborted() )
1716  {
1717  WAR << "commit aborted by the user" << endl;
1718  abort = true;
1719  step->stepStage( sat::Transaction::STEP_ERROR );
1720  break;
1721  }
1722  // else
1723  WAR << "removal of " << p << " failed";
1724  step->stepStage( sat::Transaction::STEP_ERROR );
1725  }
1726  if ( success && !policy_r.dryRun() )
1727  {
1729  step->stepStage( sat::Transaction::STEP_DONE );
1730  }
1731  }
1732  }
1733  else if ( ! policy_r.dryRun() ) // other resolvables (non-Package)
1734  {
1735  // Status is changed as the buddy package buddy
1736  // gets installed/deleted. Handle non-buddies only.
1737  if ( ! citem.buddy() )
1738  {
1739  if ( citem->isKind<Product>() )
1740  {
1741  Product::constPtr p = citem->asKind<Product>();
1742  if ( citem.status().isToBeInstalled() )
1743  {
1744  ERR << "Can't install orphan product without release-package! " << citem << endl;
1745  }
1746  else
1747  {
1748  // Deleting the corresponding product entry is all we con do.
1749  // So the product will no longer be visible as installed.
1750  std::string referenceFilename( p->referenceFilename() );
1751  if ( referenceFilename.empty() )
1752  {
1753  ERR << "Can't remove orphan product without 'referenceFilename'! " << citem << endl;
1754  }
1755  else
1756  {
1757  Pathname referencePath { Pathname("/etc/products.d") / referenceFilename }; // no root prefix for rpmdb lookup!
1758  if ( ! rpm().hasFile( referencePath.asString() ) )
1759  {
1760  // If it's not owned by a package, we can delete it.
1761  referencePath = Pathname::assertprefix( _root, referencePath ); // now add a root prefix
1762  if ( filesystem::unlink( referencePath ) != 0 )
1763  ERR << "Delete orphan product failed: " << referencePath << endl;
1764  }
1765  else
1766  {
1767  WAR << "Won't remove orphan product: '/etc/products.d/" << referenceFilename << "' is owned by a package." << endl;
1768  }
1769  }
1770  }
1771  }
1772  else if ( citem->isKind<SrcPackage>() && citem.status().isToBeInstalled() )
1773  {
1774  // SrcPackage is install-only
1775  SrcPackage::constPtr p = citem->asKind<SrcPackage>();
1776  installSrcPackage( p );
1777  }
1778 
1780  step->stepStage( sat::Transaction::STEP_DONE );
1781  }
1782 
1783  } // other resolvables
1784 
1785  } // for
1786 
1787  // process all remembered posttrans scripts. If aborting,
1788  // at least log omitted scripts.
1789  if ( abort || (abort = !postTransCollector.executeScripts()) )
1790  postTransCollector.discardScripts();
1791 
1792  // Check presence of update scripts/messages. If aborting,
1793  // at least log omitted scripts.
1794  if ( ! successfullyInstalledPackages.empty() )
1795  {
1796  if ( ! RunUpdateScripts( _root, ZConfig::instance().update_scriptsPath(),
1797  successfullyInstalledPackages, abort ) )
1798  {
1799  WAR << "Commit aborted by the user" << endl;
1800  abort = true;
1801  }
1802  // send messages after scripts in case some script generates output,
1803  // that should be kept in t %ghost message file.
1804  RunUpdateMessages( _root, ZConfig::instance().update_messagesPath(),
1805  successfullyInstalledPackages,
1806  result_r );
1807  }
1808 
1809  // jsc#SLE-5116: Log patch status changes to history
1810  // NOTE: Should be the last action as it may need to reload
1811  // the Target in case of an incomplete transaction.
1812  logPatchStatusChanges( result_r.transaction(), *this );
1813 
1814  if ( abort )
1815  {
1816  HistoryLog().comment( "Commit was aborted." );
1818  }
1819  }
1820 
1822 
1824  {
1825  return _rpm;
1826  }
1827 
1828  bool TargetImpl::providesFile (const std::string & path_str, const std::string & name_str) const
1829  {
1830  return _rpm.hasFile(path_str, name_str);
1831  }
1832 
1834  namespace
1835  {
1836  parser::ProductFileData baseproductdata( const Pathname & root_r )
1837  {
1839  PathInfo baseproduct( Pathname::assertprefix( root_r, "/etc/products.d/baseproduct" ) );
1840 
1841  if ( baseproduct.isFile() )
1842  {
1843  try
1844  {
1845  ret = parser::ProductFileReader::scanFile( baseproduct.path() );
1846  }
1847  catch ( const Exception & excpt )
1848  {
1849  ZYPP_CAUGHT( excpt );
1850  }
1851  }
1852  else if ( PathInfo( Pathname::assertprefix( root_r, "/etc/products.d" ) ).isDir() )
1853  {
1854  ERR << "baseproduct symlink is dangling or missing: " << baseproduct << endl;
1855  }
1856  return ret;
1857  }
1858 
1859  inline Pathname staticGuessRoot( const Pathname & root_r )
1860  {
1861  if ( root_r.empty() )
1862  {
1863  // empty root: use existing Target or assume "/"
1864  Pathname ret ( ZConfig::instance().systemRoot() );
1865  if ( ret.empty() )
1866  return Pathname("/");
1867  return ret;
1868  }
1869  return root_r;
1870  }
1871 
1872  inline std::string firstNonEmptyLineIn( const Pathname & file_r )
1873  {
1874  std::ifstream idfile( file_r.c_str() );
1875  for( iostr::EachLine in( idfile ); in; in.next() )
1876  {
1877  std::string line( str::trim( *in ) );
1878  if ( ! line.empty() )
1879  return line;
1880  }
1881  return std::string();
1882  }
1883  } // namespace
1885 
1887  {
1888  ResPool pool(ResPool::instance());
1889  for_( it, pool.byKindBegin<Product>(), pool.byKindEnd<Product>() )
1890  {
1891  Product::constPtr p = (*it)->asKind<Product>();
1892  if ( p->isTargetDistribution() )
1893  return p;
1894  }
1895  return nullptr;
1896  }
1897 
1899  {
1900  const Pathname needroot( staticGuessRoot(root_r) );
1901  const Target_constPtr target( getZYpp()->getTarget() );
1902  if ( target && target->root() == needroot )
1903  return target->requestedLocales();
1904  return RequestedLocalesFile( home(needroot) / "RequestedLocales" ).locales();
1905  }
1906 
1908  {
1909  MIL << "updateAutoInstalled if changed..." << endl;
1910  SolvIdentFile::Data newdata;
1911  for ( auto id : sat::Pool::instance().autoInstalled() )
1912  newdata.insert( IdString(id) ); // explicit ctor!
1913  _autoInstalledFile.setData( std::move(newdata) );
1914  }
1915 
1917  { return baseproductdata( _root ).registerTarget(); }
1918  // static version:
1919  std::string TargetImpl::targetDistribution( const Pathname & root_r )
1920  { return baseproductdata( staticGuessRoot(root_r) ).registerTarget(); }
1921 
1923  { return baseproductdata( _root ).registerRelease(); }
1924  // static version:
1925  std::string TargetImpl::targetDistributionRelease( const Pathname & root_r )
1926  { return baseproductdata( staticGuessRoot(root_r) ).registerRelease();}
1927 
1929  { return baseproductdata( _root ).registerFlavor(); }
1930  // static version:
1931  std::string TargetImpl::targetDistributionFlavor( const Pathname & root_r )
1932  { return baseproductdata( staticGuessRoot(root_r) ).registerFlavor();}
1933 
1935  {
1937  parser::ProductFileData pdata( baseproductdata( _root ) );
1938  ret.shortName = pdata.shortName();
1939  ret.summary = pdata.summary();
1940  return ret;
1941  }
1942  // static version:
1944  {
1946  parser::ProductFileData pdata( baseproductdata( staticGuessRoot(root_r) ) );
1947  ret.shortName = pdata.shortName();
1948  ret.summary = pdata.summary();
1949  return ret;
1950  }
1951 
1953  {
1954  if ( _distributionVersion.empty() )
1955  {
1957  if ( !_distributionVersion.empty() )
1958  MIL << "Remember distributionVersion = '" << _distributionVersion << "'" << endl;
1959  }
1960  return _distributionVersion;
1961  }
1962  // static version
1963  std::string TargetImpl::distributionVersion( const Pathname & root_r )
1964  {
1965  std::string distributionVersion = baseproductdata( staticGuessRoot(root_r) ).edition().version();
1966  if ( distributionVersion.empty() )
1967  {
1968  // ...But the baseproduct method is not expected to work on RedHat derivatives.
1969  // On RHEL, Fedora and others the "product version" is determined by the first package
1970  // providing 'system-release'. This value is not hardcoded in YUM and can be configured
1971  // with the $distroverpkg variable.
1972  scoped_ptr<rpm::RpmDb> tmprpmdb;
1973  if ( ZConfig::instance().systemRoot() == Pathname() )
1974  {
1975  try
1976  {
1977  tmprpmdb.reset( new rpm::RpmDb );
1978  tmprpmdb->initDatabase( /*default ctor uses / but no additional keyring exports */ );
1979  }
1980  catch( ... )
1981  {
1982  return "";
1983  }
1984  }
1987  distributionVersion = it->tag_version();
1988  }
1989  return distributionVersion;
1990  }
1991 
1992 
1994  {
1995  return firstNonEmptyLineIn( home() / "LastDistributionFlavor" );
1996  }
1997  // static version:
1998  std::string TargetImpl::distributionFlavor( const Pathname & root_r )
1999  {
2000  return firstNonEmptyLineIn( staticGuessRoot(root_r) / "/var/lib/zypp/LastDistributionFlavor" );
2001  }
2002 
2004  namespace
2005  {
2006  std::string guessAnonymousUniqueId( const Pathname & root_r )
2007  {
2008  // bsc#1024741: Omit creating a new uid for chrooted systems (if it already has one, fine)
2009  std::string ret( firstNonEmptyLineIn( root_r / "/var/lib/zypp/AnonymousUniqueId" ) );
2010  if ( ret.empty() && root_r != "/" )
2011  {
2012  // if it has nonoe, use the outer systems one
2013  ret = firstNonEmptyLineIn( "/var/lib/zypp/AnonymousUniqueId" );
2014  }
2015  return ret;
2016  }
2017  }
2018 
2019  std::string TargetImpl::anonymousUniqueId() const
2020  {
2021  return guessAnonymousUniqueId( root() );
2022  }
2023  // static version:
2024  std::string TargetImpl::anonymousUniqueId( const Pathname & root_r )
2025  {
2026  return guessAnonymousUniqueId( staticGuessRoot(root_r) );
2027  }
2028 
2030 
2031  void TargetImpl::vendorAttr( VendorAttr vendorAttr_r )
2032  {
2033  MIL << "New VendorAttr: " << vendorAttr_r << endl;
2034  _vendorAttr = std::move(vendorAttr_r);
2035  }
2037 
2038  void TargetImpl::installSrcPackage( const SrcPackage_constPtr & srcPackage_r )
2039  {
2040  // provide on local disk
2041  ManagedFile localfile = provideSrcPackage(srcPackage_r);
2042  // create a installation progress report proxy
2043  RpmInstallPackageReceiver progress( srcPackage_r );
2044  progress.connect(); // disconnected on destruction.
2045  // install it
2046  rpm().installPackage ( localfile );
2047  }
2048 
2049  ManagedFile TargetImpl::provideSrcPackage( const SrcPackage_constPtr & srcPackage_r )
2050  {
2051  // provide on local disk
2052  repo::RepoMediaAccess access_r;
2053  repo::SrcPackageProvider prov( access_r );
2054  return prov.provideSrcPackage( srcPackage_r );
2055  }
2057  } // namespace target
2060 } // 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:95
#define MIL
Definition: Logger.h:96
#define ERR
Definition: Logger.h:98
#define WAR
Definition: Logger.h:97
#define INT
Definition: Logger.h:100
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:1527
TrueBool _guard
Definition: TargetImpl.cc:1526
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 addIdent(IdString ident_r)
Add all sat::Solvable with this ident_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:1922
std::string targetDistribution() const
This is register.target attribute of the installed base product.
Definition: TargetImpl.cc:1916
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:1907
ManagedFile provideSrcPackage(const SrcPackage_constPtr &srcPackage_r)
Provides a source package on the Target.
Definition: TargetImpl.cc:2049
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:1823
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:1952
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:1886
Target::DistributionLabel distributionLabel() const
This is shortName and summary attribute of the installed base product.
Definition: TargetImpl.cc:1934
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:1828
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:1993
void installSrcPackage(const SrcPackage_constPtr &srcPackage_r)
Install a source package on the Target.
Definition: TargetImpl.cc:2038
ZYppCommitResult commit(ResPool pool_r, const ZYppCommitPolicy &policy_r)
Commit changes in the pool.
Definition: TargetImpl.cc:1241
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:2019
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:1928
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