libzypp  17.25.7
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  {
213  SolvIdentFile::Data getUserInstalledFromHistory( const Pathname & historyFile_r )
214  {
215  SolvIdentFile::Data onSystemByUserList;
216  // go and parse it: 'who' must constain an '@', then it was installed by user request.
217  // 2009-09-29 07:25:19|install|lirc-remotes|0.8.5-3.2|x86_64|root@opensuse|InstallationImage|a204211eb0...
218  std::ifstream infile( historyFile_r.c_str() );
219  for( iostr::EachLine in( infile ); in; in.next() )
220  {
221  const char * ch( (*in).c_str() );
222  // start with year
223  if ( *ch < '1' || '9' < *ch )
224  continue;
225  const char * sep1 = ::strchr( ch, '|' ); // | after date
226  if ( !sep1 )
227  continue;
228  ++sep1;
229  // if logs an install or delete
230  bool installs = true;
231  if ( ::strncmp( sep1, "install|", 8 ) )
232  {
233  if ( ::strncmp( sep1, "remove |", 8 ) )
234  continue; // no install and no remove
235  else
236  installs = false; // remove
237  }
238  sep1 += 8; // | after what
239  // get the package name
240  const char * sep2 = ::strchr( sep1, '|' ); // | after name
241  if ( !sep2 || sep1 == sep2 )
242  continue;
243  (*in)[sep2-ch] = '\0';
244  IdString pkg( sep1 );
245  // we're done, if a delete
246  if ( !installs )
247  {
248  onSystemByUserList.erase( pkg );
249  continue;
250  }
251  // now guess whether user installed or not (3rd next field contains 'user@host')
252  if ( (sep1 = ::strchr( sep2+1, '|' )) // | after version
253  && (sep1 = ::strchr( sep1+1, '|' )) // | after arch
254  && (sep2 = ::strchr( sep1+1, '|' )) ) // | after who
255  {
256  (*in)[sep2-ch] = '\0';
257  if ( ::strchr( sep1+1, '@' ) )
258  {
259  // by user
260  onSystemByUserList.insert( pkg );
261  continue;
262  }
263  }
264  }
265  MIL << "onSystemByUserList found: " << onSystemByUserList.size() << endl;
266  return onSystemByUserList;
267  }
268  } // namespace
270 
272  namespace
273  {
274  inline PluginFrame transactionPluginFrame( const std::string & command_r, ZYppCommitResult::TransactionStepList & steps_r )
275  {
276  return PluginFrame( command_r, json::Object {
277  { "TransactionStepList", steps_r }
278  }.asJSON() );
279  }
280  } // namespace
282 
285  {
286  unsigned toKeep( ZConfig::instance().solver_upgradeTestcasesToKeep() );
287  MIL << "Testcases to keep: " << toKeep << endl;
288  if ( !toKeep )
289  return;
290  Target_Ptr target( getZYpp()->getTarget() );
291  if ( ! target )
292  {
293  WAR << "No Target no Testcase!" << endl;
294  return;
295  }
296 
297  std::string stem( "updateTestcase" );
298  Pathname dir( target->assertRootPrefix("/var/log/") );
299  Pathname next( dir / Date::now().form( stem+"-%Y-%m-%d-%H-%M-%S" ) );
300 
301  {
302  std::list<std::string> content;
303  filesystem::readdir( content, dir, /*dots*/false );
304  std::set<std::string> cases;
305  for_( c, content.begin(), content.end() )
306  {
307  if ( str::startsWith( *c, stem ) )
308  cases.insert( *c );
309  }
310  if ( cases.size() >= toKeep )
311  {
312  unsigned toDel = cases.size() - toKeep + 1; // +1 for the new one
313  for_( c, cases.begin(), cases.end() )
314  {
315  filesystem::recursive_rmdir( dir/(*c) );
316  if ( ! --toDel )
317  break;
318  }
319  }
320  }
321 
322  MIL << "Write new testcase " << next << endl;
323  getZYpp()->resolver()->createSolverTestcase( next.asString(), false/*no solving*/ );
324  }
325 
327  namespace
328  {
329 
340  std::pair<bool,PatchScriptReport::Action> doExecuteScript( const Pathname & root_r,
341  const Pathname & script_r,
343  {
344  MIL << "Execute script " << PathInfo(Pathname::assertprefix( root_r,script_r)) << endl;
345 
346  HistoryLog historylog;
347  historylog.comment(script_r.asString() + _(" executed"), /*timestamp*/true);
348  ExternalProgram prog( script_r.asString(), ExternalProgram::Stderr_To_Stdout, false, -1, true, root_r );
349 
350  for ( std::string output = prog.receiveLine(); output.length(); output = prog.receiveLine() )
351  {
352  historylog.comment(output);
353  if ( ! report_r->progress( PatchScriptReport::OUTPUT, output ) )
354  {
355  WAR << "User request to abort script " << script_r << endl;
356  prog.kill();
357  // the rest is handled by exit code evaluation
358  // in case the script has meanwhile finished.
359  }
360  }
361 
362  std::pair<bool,PatchScriptReport::Action> ret( std::make_pair( false, PatchScriptReport::ABORT ) );
363 
364  if ( prog.close() != 0 )
365  {
366  ret.second = report_r->problem( prog.execError() );
367  WAR << "ACTION" << ret.second << "(" << prog.execError() << ")" << endl;
368  std::ostringstream sstr;
369  sstr << script_r << _(" execution failed") << " (" << prog.execError() << ")" << endl;
370  historylog.comment(sstr.str(), /*timestamp*/true);
371  return ret;
372  }
373 
374  report_r->finish();
375  ret.first = true;
376  return ret;
377  }
378 
382  bool executeScript( const Pathname & root_r,
383  const Pathname & script_r,
384  callback::SendReport<PatchScriptReport> & report_r )
385  {
386  std::pair<bool,PatchScriptReport::Action> action( std::make_pair( false, PatchScriptReport::ABORT ) );
387 
388  do {
389  action = doExecuteScript( root_r, script_r, report_r );
390  if ( action.first )
391  return true; // success
392 
393  switch ( action.second )
394  {
396  WAR << "User request to abort at script " << script_r << endl;
397  return false; // requested abort.
398  break;
399 
401  WAR << "User request to skip script " << script_r << endl;
402  return true; // requested skip.
403  break;
404 
406  break; // again
407  }
408  } while ( action.second == PatchScriptReport::RETRY );
409 
410  // THIS is not intended to be reached:
411  INT << "Abort on unknown ACTION request " << action.second << " returned" << endl;
412  return false; // abort.
413  }
414 
420  bool RunUpdateScripts( const Pathname & root_r,
421  const Pathname & scriptsPath_r,
422  const std::vector<sat::Solvable> & checkPackages_r,
423  bool aborting_r )
424  {
425  if ( checkPackages_r.empty() )
426  return true; // no installed packages to check
427 
428  MIL << "Looking for new update scripts in (" << root_r << ")" << scriptsPath_r << endl;
429  Pathname scriptsDir( Pathname::assertprefix( root_r, scriptsPath_r ) );
430  if ( ! PathInfo( scriptsDir ).isDir() )
431  return true; // no script dir
432 
433  std::list<std::string> scripts;
434  filesystem::readdir( scripts, scriptsDir, /*dots*/false );
435  if ( scripts.empty() )
436  return true; // no scripts in script dir
437 
438  // Now collect and execute all matching scripts.
439  // On ABORT: at least log all outstanding scripts.
440  // - "name-version-release"
441  // - "name-version-release-*"
442  bool abort = false;
443  std::map<std::string, Pathname> unify; // scripts <md5,path>
444  for_( it, checkPackages_r.begin(), checkPackages_r.end() )
445  {
446  std::string prefix( str::form( "%s-%s", it->name().c_str(), it->edition().c_str() ) );
447  for_( sit, scripts.begin(), scripts.end() )
448  {
449  if ( ! str::hasPrefix( *sit, prefix ) )
450  continue;
451 
452  if ( (*sit)[prefix.size()] != '\0' && (*sit)[prefix.size()] != '-' )
453  continue; // if not exact match it had to continue with '-'
454 
455  PathInfo script( scriptsDir / *sit );
456  Pathname localPath( scriptsPath_r/(*sit) ); // without root prefix
457  std::string unifytag; // must not stay empty
458 
459  if ( script.isFile() )
460  {
461  // Assert it's set executable, unify by md5sum.
462  filesystem::addmod( script.path(), 0500 );
463  unifytag = filesystem::md5sum( script.path() );
464  }
465  else if ( ! script.isExist() )
466  {
467  // Might be a dangling symlink, might be ok if we are in
468  // instsys (absolute symlink within the system below /mnt).
469  // readlink will tell....
470  unifytag = filesystem::readlink( script.path() ).asString();
471  }
472 
473  if ( unifytag.empty() )
474  continue;
475 
476  // Unify scripts
477  if ( unify[unifytag].empty() )
478  {
479  unify[unifytag] = localPath;
480  }
481  else
482  {
483  // translators: We may find the same script content in files with different names.
484  // Only the first occurence is executed, subsequent ones are skipped. It's a one-line
485  // message for a log file. Preferably start translation with "%s"
486  std::string msg( str::form(_("%s already executed as %s)"), localPath.asString().c_str(), unify[unifytag].c_str() ) );
487  MIL << "Skip update script: " << msg << endl;
488  HistoryLog().comment( msg, /*timestamp*/true );
489  continue;
490  }
491 
492  if ( abort || aborting_r )
493  {
494  WAR << "Aborting: Skip update script " << *sit << endl;
495  HistoryLog().comment(
496  localPath.asString() + _(" execution skipped while aborting"),
497  /*timestamp*/true);
498  }
499  else
500  {
501  MIL << "Found update script " << *sit << endl;
502  callback::SendReport<PatchScriptReport> report;
503  report->start( make<Package>( *it ), script.path() );
504 
505  if ( ! executeScript( root_r, localPath, report ) ) // script path without root prefix!
506  abort = true; // requested abort.
507  }
508  }
509  }
510  return !abort;
511  }
512 
514  //
516 
517  inline void copyTo( std::ostream & out_r, const Pathname & file_r )
518  {
519  std::ifstream infile( file_r.c_str() );
520  for( iostr::EachLine in( infile ); in; in.next() )
521  {
522  out_r << *in << endl;
523  }
524  }
525 
526  inline std::string notificationCmdSubst( const std::string & cmd_r, const UpdateNotificationFile & notification_r )
527  {
528  std::string ret( cmd_r );
529 #define SUBST_IF(PAT,VAL) if ( ret.find( PAT ) != std::string::npos ) ret = str::gsub( ret, PAT, VAL )
530  SUBST_IF( "%p", notification_r.solvable().asString() );
531  SUBST_IF( "%P", notification_r.file().asString() );
532 #undef SUBST_IF
533  return ret;
534  }
535 
536  void sendNotification( const Pathname & root_r,
537  const UpdateNotifications & notifications_r )
538  {
539  if ( notifications_r.empty() )
540  return;
541 
542  std::string cmdspec( ZConfig::instance().updateMessagesNotify() );
543  MIL << "Notification command is '" << cmdspec << "'" << endl;
544  if ( cmdspec.empty() )
545  return;
546 
547  std::string::size_type pos( cmdspec.find( '|' ) );
548  if ( pos == std::string::npos )
549  {
550  ERR << "Can't send Notification: Missing 'format |' in command spec." << endl;
551  HistoryLog().comment( str::Str() << _("Error sending update message notification."), /*timestamp*/true );
552  return;
553  }
554 
555  std::string formatStr( str::toLower( str::trim( cmdspec.substr( 0, pos ) ) ) );
556  std::string commandStr( str::trim( cmdspec.substr( pos + 1 ) ) );
557 
558  enum Format { UNKNOWN, NONE, SINGLE, DIGEST, BULK };
559  Format format = UNKNOWN;
560  if ( formatStr == "none" )
561  format = NONE;
562  else if ( formatStr == "single" )
563  format = SINGLE;
564  else if ( formatStr == "digest" )
565  format = DIGEST;
566  else if ( formatStr == "bulk" )
567  format = BULK;
568  else
569  {
570  ERR << "Can't send Notification: Unknown format '" << formatStr << " |' in command spec." << endl;
571  HistoryLog().comment( str::Str() << _("Error sending update message notification."), /*timestamp*/true );
572  return;
573  }
574 
575  // Take care: commands are ececuted chroot(root_r). The message file
576  // pathnames in notifications_r are local to root_r. For physical access
577  // to the file they need to be prefixed.
578 
579  if ( format == NONE || format == SINGLE )
580  {
581  for_( it, notifications_r.begin(), notifications_r.end() )
582  {
583  std::vector<std::string> command;
584  if ( format == SINGLE )
585  command.push_back( "<"+Pathname::assertprefix( root_r, it->file() ).asString() );
586  str::splitEscaped( notificationCmdSubst( commandStr, *it ), std::back_inserter( command ) );
587 
588  ExternalProgram prog( command, ExternalProgram::Stderr_To_Stdout, false, -1, true, root_r );
589  if ( true ) // Wait for feedback
590  {
591  for( std::string line = prog.receiveLine(); ! line.empty(); line = prog.receiveLine() )
592  {
593  DBG << line;
594  }
595  int ret = prog.close();
596  if ( ret != 0 )
597  {
598  ERR << "Notification command returned with error (" << ret << ")." << endl;
599  HistoryLog().comment( str::Str() << _("Error sending update message notification."), /*timestamp*/true );
600  return;
601  }
602  }
603  }
604  }
605  else if ( format == DIGEST || format == BULK )
606  {
607  filesystem::TmpFile tmpfile;
608  std::ofstream out( tmpfile.path().c_str() );
609  for_( it, notifications_r.begin(), notifications_r.end() )
610  {
611  if ( format == DIGEST )
612  {
613  out << it->file() << endl;
614  }
615  else if ( format == BULK )
616  {
617  copyTo( out << '\f', Pathname::assertprefix( root_r, it->file() ) );
618  }
619  }
620 
621  std::vector<std::string> command;
622  command.push_back( "<"+tmpfile.path().asString() ); // redirect input
623  str::splitEscaped( notificationCmdSubst( commandStr, *notifications_r.begin() ), std::back_inserter( command ) );
624 
625  ExternalProgram prog( command, ExternalProgram::Stderr_To_Stdout, false, -1, true, root_r );
626  if ( true ) // Wait for feedback otherwise the TmpFile goes out of scope.
627  {
628  for( std::string line = prog.receiveLine(); ! line.empty(); line = prog.receiveLine() )
629  {
630  DBG << line;
631  }
632  int ret = prog.close();
633  if ( ret != 0 )
634  {
635  ERR << "Notification command returned with error (" << ret << ")." << endl;
636  HistoryLog().comment( str::Str() << _("Error sending update message notification."), /*timestamp*/true );
637  return;
638  }
639  }
640  }
641  else
642  {
643  INT << "Can't send Notification: Missing handler for 'format |' in command spec." << endl;
644  HistoryLog().comment( str::Str() << _("Error sending update message notification."), /*timestamp*/true );
645  return;
646  }
647  }
648 
649 
655  void RunUpdateMessages( const Pathname & root_r,
656  const Pathname & messagesPath_r,
657  const std::vector<sat::Solvable> & checkPackages_r,
658  ZYppCommitResult & result_r )
659  {
660  if ( checkPackages_r.empty() )
661  return; // no installed packages to check
662 
663  MIL << "Looking for new update messages in (" << root_r << ")" << messagesPath_r << endl;
664  Pathname messagesDir( Pathname::assertprefix( root_r, messagesPath_r ) );
665  if ( ! PathInfo( messagesDir ).isDir() )
666  return; // no messages dir
667 
668  std::list<std::string> messages;
669  filesystem::readdir( messages, messagesDir, /*dots*/false );
670  if ( messages.empty() )
671  return; // no messages in message dir
672 
673  // Now collect all matching messages in result and send them
674  // - "name-version-release"
675  // - "name-version-release-*"
676  HistoryLog historylog;
677  for_( it, checkPackages_r.begin(), checkPackages_r.end() )
678  {
679  std::string prefix( str::form( "%s-%s", it->name().c_str(), it->edition().c_str() ) );
680  for_( sit, messages.begin(), messages.end() )
681  {
682  if ( ! str::hasPrefix( *sit, prefix ) )
683  continue;
684 
685  if ( (*sit)[prefix.size()] != '\0' && (*sit)[prefix.size()] != '-' )
686  continue; // if not exact match it had to continue with '-'
687 
688  PathInfo message( messagesDir / *sit );
689  if ( ! message.isFile() || message.size() == 0 )
690  continue;
691 
692  MIL << "Found update message " << *sit << endl;
693  Pathname localPath( messagesPath_r/(*sit) ); // without root prefix
694  result_r.rUpdateMessages().push_back( UpdateNotificationFile( *it, localPath ) );
695  historylog.comment( str::Str() << _("New update message") << " " << localPath, /*timestamp*/true );
696  }
697  }
698  sendNotification( root_r, result_r.updateMessages() );
699  }
700 
704  void logPatchStatusChanges( const sat::Transaction & transaction_r, TargetImpl & target_r )
705  {
707  if ( changedPseudoInstalled.empty() )
708  return;
709 
710  if ( ! transaction_r.actionEmpty( ~sat::Transaction::STEP_DONE ) )
711  {
712  // Need to recompute the patch list if commit is incomplete!
713  // We remember the initially established status, then reload the
714  // Target to get the current patch status. Then compare.
715  WAR << "Need to recompute the patch status changes as commit is incomplete!" << endl;
716  ResPool::EstablishedStates establishedStates{ ResPool::instance().establishedStates() };
717  target_r.load();
718  changedPseudoInstalled = establishedStates.changedPseudoInstalled();
719  }
720 
721  HistoryLog historylog;
722  for ( const auto & el : changedPseudoInstalled )
723  historylog.patchStateChange( el.first, el.second );
724  }
725 
727  } // namespace
729 
730  void XRunUpdateMessages( const Pathname & root_r,
731  const Pathname & messagesPath_r,
732  const std::vector<sat::Solvable> & checkPackages_r,
733  ZYppCommitResult & result_r )
734  { RunUpdateMessages( root_r, messagesPath_r, checkPackages_r, result_r ); }
735 
737 
739 
741  //
742  // METHOD NAME : TargetImpl::TargetImpl
743  // METHOD TYPE : Ctor
744  //
745  TargetImpl::TargetImpl( const Pathname & root_r, bool doRebuild_r )
746  : _root( root_r )
747  , _requestedLocalesFile( home() / "RequestedLocales" )
748  , _autoInstalledFile( home() / "AutoInstalled" )
749  , _hardLocksFile( Pathname::assertprefix( _root, ZConfig::instance().locksFile() ) )
750  , _vendorAttr( Pathname::assertprefix( _root, ZConfig::instance().vendorPath() ) )
751  {
752  _rpm.initDatabase( root_r, doRebuild_r );
753 
755 
757  sigMultiversionSpecChanged(); // HACK: see sigMultiversionSpecChanged
758  MIL << "Initialized target on " << _root << endl;
759  }
760 
764  static std::string generateRandomId()
765  {
766  std::ifstream uuidprovider( "/proc/sys/kernel/random/uuid" );
767  return iostr::getline( uuidprovider );
768  }
769 
775  void updateFileContent( const Pathname &filename,
776  boost::function<bool ()> condition,
777  boost::function<std::string ()> value )
778  {
779  std::string val = value();
780  // if the value is empty, then just dont
781  // do anything, regardless of the condition
782  if ( val.empty() )
783  return;
784 
785  if ( condition() )
786  {
787  MIL << "updating '" << filename << "' content." << endl;
788 
789  // if the file does not exist we need to generate the uuid file
790 
791  std::ofstream filestr;
792  // make sure the path exists
793  filesystem::assert_dir( filename.dirname() );
794  filestr.open( filename.c_str() );
795 
796  if ( filestr.good() )
797  {
798  filestr << val;
799  filestr.close();
800  }
801  else
802  {
803  // FIXME, should we ignore the error?
804  ZYPP_THROW(Exception("Can't openfile '" + filename.asString() + "' for writing"));
805  }
806  }
807  }
808 
810  static bool fileMissing( const Pathname &pathname )
811  {
812  return ! PathInfo(pathname).isExist();
813  }
814 
816  {
817  // bsc#1024741: Omit creating a new uid for chrooted systems (if it already has one, fine)
818  if ( root() != "/" )
819  return;
820 
821  // Create the anonymous unique id, used for download statistics
822  Pathname idpath( home() / "AnonymousUniqueId");
823 
824  try
825  {
826  updateFileContent( idpath,
827  boost::bind(fileMissing, idpath),
829  }
830  catch ( const Exception &e )
831  {
832  WAR << "Can't create anonymous id file" << endl;
833  }
834 
835  }
836 
838  {
839  // create the anonymous unique id
840  // this value is used for statistics
841  Pathname flavorpath( home() / "LastDistributionFlavor");
842 
843  // is there a product
845  if ( ! p )
846  {
847  WAR << "No base product, I won't create flavor cache" << endl;
848  return;
849  }
850 
851  std::string flavor = p->flavor();
852 
853  try
854  {
855 
856  updateFileContent( flavorpath,
857  // only if flavor is not empty
858  functor::Constant<bool>( ! flavor.empty() ),
860  }
861  catch ( const Exception &e )
862  {
863  WAR << "Can't create flavor cache" << endl;
864  return;
865  }
866  }
867 
869  //
870  // METHOD NAME : TargetImpl::~TargetImpl
871  // METHOD TYPE : Dtor
872  //
874  {
876  sigMultiversionSpecChanged(); // HACK: see sigMultiversionSpecChanged
877  MIL << "Targets closed" << endl;
878  }
879 
881  //
882  // solv file handling
883  //
885 
887  {
888  return Pathname::assertprefix( _root, ZConfig::instance().repoSolvfilesPath() / sat::Pool::instance().systemRepoAlias() );
889  }
890 
892  {
893  Pathname base = solvfilesPath();
895  }
896 
898  {
899  Pathname base = solvfilesPath();
900  Pathname rpmsolv = base/"solv";
901  Pathname rpmsolvcookie = base/"cookie";
902 
903  bool build_rpm_solv = true;
904  // lets see if the rpm solv cache exists
905 
906  RepoStatus rpmstatus( rpmDbRepoStatus(_root) && RepoStatus(_root/"etc/products.d") );
907 
908  bool solvexisted = PathInfo(rpmsolv).isExist();
909  if ( solvexisted )
910  {
911  // see the status of the cache
912  PathInfo cookie( rpmsolvcookie );
913  MIL << "Read cookie: " << cookie << endl;
914  if ( cookie.isExist() )
915  {
916  RepoStatus status = RepoStatus::fromCookieFile(rpmsolvcookie);
917  // now compare it with the rpm database
918  if ( status == rpmstatus )
919  build_rpm_solv = false;
920  MIL << "Read cookie: " << rpmsolvcookie << " says: "
921  << (build_rpm_solv ? "outdated" : "uptodate") << endl;
922  }
923  }
924 
925  if ( build_rpm_solv )
926  {
927  // if the solvfile dir does not exist yet, we better create it
928  filesystem::assert_dir( base );
929 
930  Pathname oldSolvFile( solvexisted ? rpmsolv : Pathname() ); // to speedup rpmdb2solv
931 
933  if ( !tmpsolv )
934  {
935  // Can't create temporary solv file, usually due to insufficient permission
936  // (user query while @System solv needs refresh). If so, try switching
937  // to a location within zypps temp. space (will be cleaned at application end).
938 
939  bool switchingToTmpSolvfile = false;
940  Exception ex("Failed to cache rpm database.");
941  ex.remember(str::form("Cannot create temporary file under %s.", base.c_str()));
942 
943  if ( ! solvfilesPathIsTemp() )
944  {
945  base = getZYpp()->tmpPath() / sat::Pool::instance().systemRepoAlias();
946  rpmsolv = base/"solv";
947  rpmsolvcookie = base/"cookie";
948 
949  filesystem::assert_dir( base );
950  tmpsolv = filesystem::TmpFile::makeSibling( rpmsolv );
951 
952  if ( tmpsolv )
953  {
954  WAR << "Using a temporary solv file at " << base << endl;
955  switchingToTmpSolvfile = true;
956  _tmpSolvfilesPath = base;
957  }
958  else
959  {
960  ex.remember(str::form("Cannot create temporary file under %s.", base.c_str()));
961  }
962  }
963 
964  if ( ! switchingToTmpSolvfile )
965  {
966  ZYPP_THROW(ex);
967  }
968  }
969 
970  // Take care we unlink the solvfile on exception
972 
974  cmd.push_back( "rpmdb2solv" );
975  if ( ! _root.empty() ) {
976  cmd.push_back( "-r" );
977  cmd.push_back( _root.asString() );
978  }
979  cmd.push_back( "-D" );
980  cmd.push_back( rpm().dbPath().asString() );
981  cmd.push_back( "-X" ); // autogenerate pattern/product/... from -package
982  // bsc#1104415: no more application support // cmd.push_back( "-A" ); // autogenerate application pseudo packages
983  cmd.push_back( "-p" );
984  cmd.push_back( Pathname::assertprefix( _root, "/etc/products.d" ).asString() );
985 
986  if ( ! oldSolvFile.empty() )
987  cmd.push_back( oldSolvFile.asString() );
988 
989  cmd.push_back( "-o" );
990  cmd.push_back( tmpsolv.path().asString() );
991 
993  std::string errdetail;
994 
995  for ( std::string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
996  WAR << " " << output;
997  if ( errdetail.empty() ) {
998  errdetail = prog.command();
999  errdetail += '\n';
1000  }
1001  errdetail += output;
1002  }
1003 
1004  int ret = prog.close();
1005  if ( ret != 0 )
1006  {
1007  Exception ex(str::form("Failed to cache rpm database (%d).", ret));
1008  ex.remember( errdetail );
1009  ZYPP_THROW(ex);
1010  }
1011 
1012  ret = filesystem::rename( tmpsolv, rpmsolv );
1013  if ( ret != 0 )
1014  ZYPP_THROW(Exception("Failed to move cache to final destination"));
1015  // if this fails, don't bother throwing exceptions
1016  filesystem::chmod( rpmsolv, 0644 );
1017 
1018  rpmstatus.saveToCookieFile(rpmsolvcookie);
1019 
1020  // We keep it.
1021  guard.resetDispose();
1022  sat::updateSolvFileIndex( rpmsolv ); // content digest for zypper bash completion
1023 
1024  // system-hook: Finally send notification to plugins
1025  if ( root() == "/" )
1026  {
1027  PluginExecutor plugins;
1028  plugins.load( ZConfig::instance().pluginsPath()/"system" );
1029  if ( plugins )
1030  plugins.send( PluginFrame( "PACKAGESETCHANGED" ) );
1031  }
1032  }
1033  else
1034  {
1035  // On the fly add missing solv.idx files for bash completion.
1036  if ( ! PathInfo(base/"solv.idx").isExist() )
1037  sat::updateSolvFileIndex( rpmsolv );
1038  }
1039  return build_rpm_solv;
1040  }
1041 
1043  {
1044  load( false );
1045  }
1046 
1048  {
1049  Repository system( sat::Pool::instance().findSystemRepo() );
1050  if ( system )
1051  system.eraseFromPool();
1052  }
1053 
1054  void TargetImpl::load( bool force )
1055  {
1056  bool newCache = buildCache();
1057  MIL << "New cache built: " << (newCache?"true":"false") <<
1058  ", force loading: " << (force?"true":"false") << endl;
1059 
1060  // now add the repos to the pool
1061  sat::Pool satpool( sat::Pool::instance() );
1062  Pathname rpmsolv( solvfilesPath() / "solv" );
1063  MIL << "adding " << rpmsolv << " to pool(" << satpool.systemRepoAlias() << ")" << endl;
1064 
1065  // Providing an empty system repo, unload any old content
1066  Repository system( sat::Pool::instance().findSystemRepo() );
1067 
1068  if ( system && ! system.solvablesEmpty() )
1069  {
1070  if ( newCache || force )
1071  {
1072  system.eraseFromPool(); // invalidates system
1073  }
1074  else
1075  {
1076  return; // nothing to do
1077  }
1078  }
1079 
1080  if ( ! system )
1081  {
1082  system = satpool.systemRepo();
1083  }
1084 
1085  try
1086  {
1087  MIL << "adding " << rpmsolv << " to system" << endl;
1088  system.addSolv( rpmsolv );
1089  }
1090  catch ( const Exception & exp )
1091  {
1092  ZYPP_CAUGHT( exp );
1093  MIL << "Try to handle exception by rebuilding the solv-file" << endl;
1094  clearCache();
1095  buildCache();
1096 
1097  system.addSolv( rpmsolv );
1098  }
1099  satpool.rootDir( _root );
1100 
1101  // (Re)Load the requested locales et al.
1102  // If the requested locales are empty, we leave the pool untouched
1103  // to avoid undoing changes the application applied. We expect this
1104  // to happen on a bare metal installation only. An already existing
1105  // target should be loaded before its settings are changed.
1106  {
1108  if ( ! requestedLocales.empty() )
1109  {
1111  }
1112  }
1113  {
1114  if ( ! PathInfo( _autoInstalledFile.file() ).isExist() )
1115  {
1116  // Initialize from history, if it does not exist
1117  Pathname historyFile( Pathname::assertprefix( _root, ZConfig::instance().historyLogFile() ) );
1118  if ( PathInfo( historyFile ).isExist() )
1119  {
1120  SolvIdentFile::Data onSystemByUser( getUserInstalledFromHistory( historyFile ) );
1121  SolvIdentFile::Data onSystemByAuto;
1122  for_( it, system.solvablesBegin(), system.solvablesEnd() )
1123  {
1124  IdString ident( (*it).ident() );
1125  if ( onSystemByUser.find( ident ) == onSystemByUser.end() )
1126  onSystemByAuto.insert( ident );
1127  }
1128  _autoInstalledFile.setData( onSystemByAuto );
1129  }
1130  // on the fly removed any obsolete SoftLocks file
1131  filesystem::unlink( home() / "SoftLocks" );
1132  }
1133  // read from AutoInstalled file
1134  sat::StringQueue q;
1135  for ( const auto & idstr : _autoInstalledFile.data() )
1136  q.push( idstr.id() );
1137  satpool.setAutoInstalled( q );
1138  }
1139 
1140  // Load the needreboot package specs
1141  {
1142  sat::SolvableSpec needrebootSpec;
1143  needrebootSpec.addProvides( Capability("installhint(reboot-needed)") );
1144 
1145  Pathname needrebootFile { Pathname::assertprefix( root(), ZConfig::instance().needrebootFile() ) };
1146  if ( PathInfo( needrebootFile ).isFile() )
1147  needrebootSpec.parseFrom( needrebootFile );
1148 
1149  Pathname needrebootDir { Pathname::assertprefix( root(), ZConfig::instance().needrebootPath() ) };
1150  if ( PathInfo( needrebootDir ).isDir() )
1151  {
1152  static const StrMatcher isRpmConfigBackup( "\\.rpm(new|save|orig)$", Match::REGEX );
1153 
1155  [&]( const Pathname & dir_r, const char *const str_r )->bool
1156  {
1157  if ( ! isRpmConfigBackup( str_r ) )
1158  {
1159  Pathname needrebootFile { needrebootDir / str_r };
1160  if ( PathInfo( needrebootFile ).isFile() )
1161  needrebootSpec.parseFrom( needrebootFile );
1162  }
1163  return true;
1164  });
1165  }
1166  satpool.setNeedrebootSpec( std::move(needrebootSpec) );
1167  }
1168 
1169  if ( ZConfig::instance().apply_locks_file() )
1170  {
1171  const HardLocksFile::Data & hardLocks( _hardLocksFile.data() );
1172  if ( ! hardLocks.empty() )
1173  {
1174  ResPool::instance().setHardLockQueries( hardLocks );
1175  }
1176  }
1177 
1178  // now that the target is loaded, we can cache the flavor
1180 
1181  MIL << "Target loaded: " << system.solvablesSize() << " resolvables" << endl;
1182  }
1183 
1185  //
1186  // COMMIT
1187  //
1190  {
1191  // ----------------------------------------------------------------- //
1192  ZYppCommitPolicy policy_r( policy_rX );
1193  bool explicitDryRun = policy_r.dryRun(); // explicit dry run will trigger a fileconflict check, implicit (download-only) not.
1194 
1195  ShutdownLock lck("Zypp commit running.");
1196 
1197  // Fake outstanding YCP fix: Honour restriction to media 1
1198  // at installation, but install all remaining packages if post-boot.
1199  if ( policy_r.restrictToMedia() > 1 )
1200  policy_r.allMedia();
1201 
1202  if ( policy_r.downloadMode() == DownloadDefault ) {
1203  if ( root() == "/" )
1204  policy_r.downloadMode(DownloadInHeaps);
1205  else
1206  policy_r.downloadMode(DownloadAsNeeded);
1207  }
1208  // DownloadOnly implies dry-run.
1209  else if ( policy_r.downloadMode() == DownloadOnly )
1210  policy_r.dryRun( true );
1211  // ----------------------------------------------------------------- //
1212 
1213  MIL << "TargetImpl::commit(<pool>, " << policy_r << ")" << endl;
1214 
1216  // Compute transaction:
1218  ZYppCommitResult result( root() );
1219  result.rTransaction() = pool_r.resolver().getTransaction();
1220  result.rTransaction().order();
1221  // steps: this is our todo-list
1223  if ( policy_r.restrictToMedia() )
1224  {
1225  // Collect until the 1st package from an unwanted media occurs.
1226  // Further collection could violate install order.
1227  MIL << "Restrict to media number " << policy_r.restrictToMedia() << endl;
1228  for_( it, result.transaction().begin(), result.transaction().end() )
1229  {
1230  if ( makeResObject( *it )->mediaNr() > 1 )
1231  break;
1232  steps.push_back( *it );
1233  }
1234  }
1235  else
1236  {
1237  result.rTransactionStepList().insert( steps.end(), result.transaction().begin(), result.transaction().end() );
1238  }
1239  MIL << "Todo: " << result << endl;
1240 
1242  // Prepare execution of commit plugins:
1244  PluginExecutor commitPlugins;
1245  if ( root() == "/" && ! policy_r.dryRun() )
1246  {
1247  commitPlugins.load( ZConfig::instance().pluginsPath()/"commit" );
1248  }
1249  if ( commitPlugins )
1250  commitPlugins.send( transactionPluginFrame( "COMMITBEGIN", steps ) );
1251 
1253  // Write out a testcase if we're in dist upgrade mode.
1255  if ( pool_r.resolver().upgradeMode() || pool_r.resolver().upgradingRepos() )
1256  {
1257  if ( ! policy_r.dryRun() )
1258  {
1260  }
1261  else
1262  {
1263  DBG << "dryRun: Not writing upgrade testcase." << endl;
1264  }
1265  }
1266 
1268  // Store non-package data:
1270  if ( ! policy_r.dryRun() )
1271  {
1273  // requested locales
1275  // autoinstalled
1276  {
1277  SolvIdentFile::Data newdata;
1278  for ( sat::Queue::value_type id : result.rTransaction().autoInstalled() )
1279  newdata.insert( IdString(id) );
1280  _autoInstalledFile.setData( newdata );
1281  }
1282  // hard locks
1283  if ( ZConfig::instance().apply_locks_file() )
1284  {
1285  HardLocksFile::Data newdata;
1286  pool_r.getHardLockQueries( newdata );
1287  _hardLocksFile.setData( newdata );
1288  }
1289  }
1290  else
1291  {
1292  DBG << "dryRun: Not storing non-package data." << endl;
1293  }
1294 
1296  // First collect and display all messages
1297  // associated with patches to be installed.
1299  if ( ! policy_r.dryRun() )
1300  {
1301  for_( it, steps.begin(), steps.end() )
1302  {
1303  if ( ! it->satSolvable().isKind<Patch>() )
1304  continue;
1305 
1306  PoolItem pi( *it );
1307  if ( ! pi.status().isToBeInstalled() )
1308  continue;
1309 
1310  Patch::constPtr patch( asKind<Patch>(pi.resolvable()) );
1311  if ( ! patch ||patch->message().empty() )
1312  continue;
1313 
1314  MIL << "Show message for " << patch << endl;
1316  if ( ! report->show( patch ) )
1317  {
1318  WAR << "commit aborted by the user" << endl;
1320  }
1321  }
1322  }
1323  else
1324  {
1325  DBG << "dryRun: Not checking patch messages." << endl;
1326  }
1327 
1329  // Remove/install packages.
1331  DBG << "commit log file is set to: " << HistoryLog::fname() << endl;
1332  if ( ! policy_r.dryRun() || policy_r.downloadMode() == DownloadOnly )
1333  {
1334  // Prepare the package cache. Pass all items requiring download.
1335  CommitPackageCache packageCache;
1336  packageCache.setCommitList( steps.begin(), steps.end() );
1337 
1338  bool miss = false;
1339  if ( policy_r.downloadMode() != DownloadAsNeeded )
1340  {
1341  // Preload the cache. Until now this means pre-loading all packages.
1342  // Once DownloadInHeaps is fully implemented, this will change and
1343  // we may actually have more than one heap.
1344  for_( it, steps.begin(), steps.end() )
1345  {
1346  switch ( it->stepType() )
1347  {
1350  // proceed: only install actionas may require download.
1351  break;
1352 
1353  default:
1354  // next: no download for or non-packages and delete actions.
1355  continue;
1356  break;
1357  }
1358 
1359  PoolItem pi( *it );
1360  if ( pi->isKind<Package>() || pi->isKind<SrcPackage>() )
1361  {
1362  ManagedFile localfile;
1363  try
1364  {
1365  localfile = packageCache.get( pi );
1366  localfile.resetDispose(); // keep the package file in the cache
1367  }
1368  catch ( const AbortRequestException & exp )
1369  {
1370  it->stepStage( sat::Transaction::STEP_ERROR );
1371  miss = true;
1372  WAR << "commit cache preload aborted by the user" << endl;
1374  break;
1375  }
1376  catch ( const SkipRequestException & exp )
1377  {
1378  ZYPP_CAUGHT( exp );
1379  it->stepStage( sat::Transaction::STEP_ERROR );
1380  miss = true;
1381  WAR << "Skipping cache preload package " << pi->asKind<Package>() << " in commit" << endl;
1382  continue;
1383  }
1384  catch ( const Exception & exp )
1385  {
1386  // bnc #395704: missing catch causes abort.
1387  // TODO see if packageCache fails to handle errors correctly.
1388  ZYPP_CAUGHT( exp );
1389  it->stepStage( sat::Transaction::STEP_ERROR );
1390  miss = true;
1391  INT << "Unexpected Error: Skipping cache preload package " << pi->asKind<Package>() << " in commit" << endl;
1392  continue;
1393  }
1394  }
1395  }
1396  packageCache.preloaded( true ); // try to avoid duplicate infoInCache CBs in commit
1397  }
1398 
1399  if ( miss )
1400  {
1401  ERR << "Some packages could not be provided. Aborting commit."<< endl;
1402  }
1403  else
1404  {
1405  if ( ! policy_r.dryRun() )
1406  {
1407  // if cache is preloaded, check for file conflicts
1408  commitFindFileConflicts( policy_r, result );
1409  commit( policy_r, packageCache, result );
1410  }
1411  else
1412  {
1413  DBG << "dryRun/downloadOnly: Not installing/deleting anything." << endl;
1414  if ( explicitDryRun ) {
1415  // if cache is preloaded, check for file conflicts
1416  commitFindFileConflicts( policy_r, result );
1417  }
1418  }
1419  }
1420  }
1421  else
1422  {
1423  DBG << "dryRun: Not downloading/installing/deleting anything." << endl;
1424  if ( explicitDryRun ) {
1425  // if cache is preloaded, check for file conflicts
1426  commitFindFileConflicts( policy_r, result );
1427  }
1428  }
1429 
1430  {
1431  // NOTE: Removing rpm in a transaction, rpm removes the /var/lib/rpm compat symlink.
1432  // We re-create it, in case it was lost to prevent legacy tools from accidentally
1433  // assuming no database is present.
1434  if ( ! PathInfo(_root/"/var/lib/rpm",PathInfo::LSTAT).isExist()
1435  && PathInfo(_root/"/usr/lib/sysimage/rpm").isDir() ) {
1436  WAR << "(rpm removed in commit?) Inject missing /var/lib/rpm compat symlink to /usr/lib/sysimage/rpm" << endl;
1437  filesystem::assert_dir( _root/"/var/lib" );
1438  filesystem::symlink( "../../usr/lib/sysimage/rpm", _root/"/var/lib/rpm" );
1439  }
1440  }
1441 
1443  // Send result to commit plugins:
1445  if ( commitPlugins )
1446  commitPlugins.send( transactionPluginFrame( "COMMITEND", steps ) );
1447 
1449  // Try to rebuild solv file while rpm database is still in cache
1451  if ( ! policy_r.dryRun() )
1452  {
1453  buildCache();
1454  }
1455 
1456  MIL << "TargetImpl::commit(<pool>, " << policy_r << ") returns: " << result << endl;
1457  return result;
1458  }
1459 
1461  //
1462  // COMMIT internal
1463  //
1465  namespace
1466  {
1467  struct NotifyAttemptToModify
1468  {
1469  NotifyAttemptToModify( ZYppCommitResult & result_r ) : _result( result_r ) {}
1470 
1471  void operator()()
1472  { if ( _guard ) { _result.attemptToModify( true ); _guard = false; } }
1473 
1474  TrueBool _guard;
1475  ZYppCommitResult & _result;
1476  };
1477  } // namespace
1478 
1479  void TargetImpl::commit( const ZYppCommitPolicy & policy_r,
1480  CommitPackageCache & packageCache_r,
1481  ZYppCommitResult & result_r )
1482  {
1483  // steps: this is our todo-list
1485  MIL << "TargetImpl::commit(<list>" << policy_r << ")" << steps.size() << endl;
1486 
1488 
1489  // Send notification once upon 1st call to rpm
1490  NotifyAttemptToModify attemptToModify( result_r );
1491 
1492  bool abort = false;
1493 
1494  RpmPostTransCollector postTransCollector( _root );
1495  std::vector<sat::Solvable> successfullyInstalledPackages;
1496  TargetImpl::PoolItemList remaining;
1497 
1498  for_( step, steps.begin(), steps.end() )
1499  {
1500  PoolItem citem( *step );
1501  if ( step->stepType() == sat::Transaction::TRANSACTION_IGNORE )
1502  {
1503  if ( citem->isKind<Package>() )
1504  {
1505  // for packages this means being obsoleted (by rpm)
1506  // thius no additional action is needed.
1507  step->stepStage( sat::Transaction::STEP_DONE );
1508  continue;
1509  }
1510  }
1511 
1512  if ( citem->isKind<Package>() )
1513  {
1514  Package::constPtr p = citem->asKind<Package>();
1515  if ( citem.status().isToBeInstalled() )
1516  {
1517  ManagedFile localfile;
1518  try
1519  {
1520  localfile = packageCache_r.get( citem );
1521  }
1522  catch ( const AbortRequestException &e )
1523  {
1524  WAR << "commit aborted by the user" << endl;
1525  abort = true;
1526  step->stepStage( sat::Transaction::STEP_ERROR );
1527  break;
1528  }
1529  catch ( const SkipRequestException &e )
1530  {
1531  ZYPP_CAUGHT( e );
1532  WAR << "Skipping package " << p << " in commit" << endl;
1533  step->stepStage( sat::Transaction::STEP_ERROR );
1534  continue;
1535  }
1536  catch ( const Exception &e )
1537  {
1538  // bnc #395704: missing catch causes abort.
1539  // TODO see if packageCache fails to handle errors correctly.
1540  ZYPP_CAUGHT( e );
1541  INT << "Unexpected Error: Skipping package " << p << " in commit" << endl;
1542  step->stepStage( sat::Transaction::STEP_ERROR );
1543  continue;
1544  }
1545 
1546  // create a installation progress report proxy
1547  RpmInstallPackageReceiver progress( citem.resolvable() );
1548  progress.connect(); // disconnected on destruction.
1549 
1550  bool success = false;
1551  rpm::RpmInstFlags flags( policy_r.rpmInstFlags() & rpm::RPMINST_JUSTDB );
1552  // Why force and nodeps?
1553  //
1554  // Because zypp builds the transaction and the resolver asserts that
1555  // everything is fine.
1556  // We use rpm just to unpack and register the package in the database.
1557  // We do this step by step, so rpm is not aware of the bigger context.
1558  // So we turn off rpms internal checks, because we do it inside zypp.
1559  flags |= rpm::RPMINST_NODEPS;
1560  flags |= rpm::RPMINST_FORCE;
1561  //
1562  if (p->multiversionInstall()) flags |= rpm::RPMINST_NOUPGRADE;
1563  if (policy_r.dryRun()) flags |= rpm::RPMINST_TEST;
1564  if (policy_r.rpmExcludeDocs()) flags |= rpm::RPMINST_EXCLUDEDOCS;
1565  if (policy_r.rpmNoSignature()) flags |= rpm::RPMINST_NOSIGNATURE;
1566 
1567  attemptToModify();
1568  try
1569  {
1571  if ( postTransCollector.collectScriptFromPackage( localfile ) )
1572  flags |= rpm::RPMINST_NOPOSTTRANS;
1573  rpm().installPackage( localfile, flags );
1574  HistoryLog().install(citem);
1575 
1576  if ( progress.aborted() )
1577  {
1578  WAR << "commit aborted by the user" << endl;
1579  localfile.resetDispose(); // keep the package file in the cache
1580  abort = true;
1581  step->stepStage( sat::Transaction::STEP_ERROR );
1582  break;
1583  }
1584  else
1585  {
1586  if ( citem.isNeedreboot() ) {
1587  auto rebootNeededFile = root() / "/run/reboot-needed";
1588  if ( filesystem::assert_file( rebootNeededFile ) == EEXIST)
1589  filesystem::touch( rebootNeededFile );
1590  }
1591 
1592  success = true;
1593  step->stepStage( sat::Transaction::STEP_DONE );
1594  }
1595  }
1596  catch ( Exception & excpt_r )
1597  {
1598  ZYPP_CAUGHT(excpt_r);
1599  localfile.resetDispose(); // keep the package file in the cache
1600 
1601  if ( policy_r.dryRun() )
1602  {
1603  WAR << "dry run failed" << endl;
1604  step->stepStage( sat::Transaction::STEP_ERROR );
1605  break;
1606  }
1607  // else
1608  if ( progress.aborted() )
1609  {
1610  WAR << "commit aborted by the user" << endl;
1611  abort = true;
1612  }
1613  else
1614  {
1615  WAR << "Install failed" << endl;
1616  }
1617  step->stepStage( sat::Transaction::STEP_ERROR );
1618  break; // stop
1619  }
1620 
1621  if ( success && !policy_r.dryRun() )
1622  {
1624  successfullyInstalledPackages.push_back( citem.satSolvable() );
1625  step->stepStage( sat::Transaction::STEP_DONE );
1626  }
1627  }
1628  else
1629  {
1630  RpmRemovePackageReceiver progress( citem.resolvable() );
1631  progress.connect(); // disconnected on destruction.
1632 
1633  bool success = false;
1634  rpm::RpmInstFlags flags( policy_r.rpmInstFlags() & rpm::RPMINST_JUSTDB );
1635  flags |= rpm::RPMINST_NODEPS;
1636  if (policy_r.dryRun()) flags |= rpm::RPMINST_TEST;
1637 
1638  attemptToModify();
1639  try
1640  {
1641  rpm().removePackage( p, flags );
1642  HistoryLog().remove(citem);
1643 
1644  if ( progress.aborted() )
1645  {
1646  WAR << "commit aborted by the user" << endl;
1647  abort = true;
1648  step->stepStage( sat::Transaction::STEP_ERROR );
1649  break;
1650  }
1651  else
1652  {
1653  success = true;
1654  step->stepStage( sat::Transaction::STEP_DONE );
1655  }
1656  }
1657  catch (Exception & excpt_r)
1658  {
1659  ZYPP_CAUGHT( excpt_r );
1660  if ( progress.aborted() )
1661  {
1662  WAR << "commit aborted by the user" << endl;
1663  abort = true;
1664  step->stepStage( sat::Transaction::STEP_ERROR );
1665  break;
1666  }
1667  // else
1668  WAR << "removal of " << p << " failed";
1669  step->stepStage( sat::Transaction::STEP_ERROR );
1670  }
1671  if ( success && !policy_r.dryRun() )
1672  {
1674  step->stepStage( sat::Transaction::STEP_DONE );
1675  }
1676  }
1677  }
1678  else if ( ! policy_r.dryRun() ) // other resolvables (non-Package)
1679  {
1680  // Status is changed as the buddy package buddy
1681  // gets installed/deleted. Handle non-buddies only.
1682  if ( ! citem.buddy() )
1683  {
1684  if ( citem->isKind<Product>() )
1685  {
1686  Product::constPtr p = citem->asKind<Product>();
1687  if ( citem.status().isToBeInstalled() )
1688  {
1689  ERR << "Can't install orphan product without release-package! " << citem << endl;
1690  }
1691  else
1692  {
1693  // Deleting the corresponding product entry is all we con do.
1694  // So the product will no longer be visible as installed.
1695  std::string referenceFilename( p->referenceFilename() );
1696  if ( referenceFilename.empty() )
1697  {
1698  ERR << "Can't remove orphan product without 'referenceFilename'! " << citem << endl;
1699  }
1700  else
1701  {
1702  Pathname referencePath { Pathname("/etc/products.d") / referenceFilename }; // no root prefix for rpmdb lookup!
1703  if ( ! rpm().hasFile( referencePath.asString() ) )
1704  {
1705  // If it's not owned by a package, we can delete it.
1706  referencePath = Pathname::assertprefix( _root, referencePath ); // now add a root prefix
1707  if ( filesystem::unlink( referencePath ) != 0 )
1708  ERR << "Delete orphan product failed: " << referencePath << endl;
1709  }
1710  else
1711  {
1712  WAR << "Won't remove orphan product: '/etc/products.d/" << referenceFilename << "' is owned by a package." << endl;
1713  }
1714  }
1715  }
1716  }
1717  else if ( citem->isKind<SrcPackage>() && citem.status().isToBeInstalled() )
1718  {
1719  // SrcPackage is install-only
1720  SrcPackage::constPtr p = citem->asKind<SrcPackage>();
1721  installSrcPackage( p );
1722  }
1723 
1725  step->stepStage( sat::Transaction::STEP_DONE );
1726  }
1727 
1728  } // other resolvables
1729 
1730  } // for
1731 
1732  // process all remembered posttrans scripts. If aborting,
1733  // at least log omitted scripts.
1734  if ( abort || (abort = !postTransCollector.executeScripts()) )
1735  postTransCollector.discardScripts();
1736 
1737  // Check presence of update scripts/messages. If aborting,
1738  // at least log omitted scripts.
1739  if ( ! successfullyInstalledPackages.empty() )
1740  {
1741  if ( ! RunUpdateScripts( _root, ZConfig::instance().update_scriptsPath(),
1742  successfullyInstalledPackages, abort ) )
1743  {
1744  WAR << "Commit aborted by the user" << endl;
1745  abort = true;
1746  }
1747  // send messages after scripts in case some script generates output,
1748  // that should be kept in t %ghost message file.
1749  RunUpdateMessages( _root, ZConfig::instance().update_messagesPath(),
1750  successfullyInstalledPackages,
1751  result_r );
1752  }
1753 
1754  // jsc#SLE-5116: Log patch status changes to history
1755  // NOTE: Should be the last action as it may need to reload
1756  // the Target in case of an incomplete transaction.
1757  logPatchStatusChanges( result_r.transaction(), *this );
1758 
1759  if ( abort )
1760  {
1761  HistoryLog().comment( "Commit was aborted." );
1763  }
1764  }
1765 
1767 
1769  {
1770  return _rpm;
1771  }
1772 
1773  bool TargetImpl::providesFile (const std::string & path_str, const std::string & name_str) const
1774  {
1775  return _rpm.hasFile(path_str, name_str);
1776  }
1777 
1779  namespace
1780  {
1781  parser::ProductFileData baseproductdata( const Pathname & root_r )
1782  {
1784  PathInfo baseproduct( Pathname::assertprefix( root_r, "/etc/products.d/baseproduct" ) );
1785 
1786  if ( baseproduct.isFile() )
1787  {
1788  try
1789  {
1790  ret = parser::ProductFileReader::scanFile( baseproduct.path() );
1791  }
1792  catch ( const Exception & excpt )
1793  {
1794  ZYPP_CAUGHT( excpt );
1795  }
1796  }
1797  else if ( PathInfo( Pathname::assertprefix( root_r, "/etc/products.d" ) ).isDir() )
1798  {
1799  ERR << "baseproduct symlink is dangling or missing: " << baseproduct << endl;
1800  }
1801  return ret;
1802  }
1803 
1804  inline Pathname staticGuessRoot( const Pathname & root_r )
1805  {
1806  if ( root_r.empty() )
1807  {
1808  // empty root: use existing Target or assume "/"
1809  Pathname ret ( ZConfig::instance().systemRoot() );
1810  if ( ret.empty() )
1811  return Pathname("/");
1812  return ret;
1813  }
1814  return root_r;
1815  }
1816 
1817  inline std::string firstNonEmptyLineIn( const Pathname & file_r )
1818  {
1819  std::ifstream idfile( file_r.c_str() );
1820  for( iostr::EachLine in( idfile ); in; in.next() )
1821  {
1822  std::string line( str::trim( *in ) );
1823  if ( ! line.empty() )
1824  return line;
1825  }
1826  return std::string();
1827  }
1828  } // namespace
1830 
1832  {
1833  ResPool pool(ResPool::instance());
1834  for_( it, pool.byKindBegin<Product>(), pool.byKindEnd<Product>() )
1835  {
1836  Product::constPtr p = (*it)->asKind<Product>();
1837  if ( p->isTargetDistribution() )
1838  return p;
1839  }
1840  return nullptr;
1841  }
1842 
1844  {
1845  const Pathname needroot( staticGuessRoot(root_r) );
1846  const Target_constPtr target( getZYpp()->getTarget() );
1847  if ( target && target->root() == needroot )
1848  return target->requestedLocales();
1849  return RequestedLocalesFile( home(needroot) / "RequestedLocales" ).locales();
1850  }
1851 
1853  {
1854  MIL << "updateAutoInstalled if changed..." << endl;
1855  SolvIdentFile::Data newdata;
1856  for ( auto id : sat::Pool::instance().autoInstalled() )
1857  newdata.insert( IdString(id) ); // explicit ctor!
1858  _autoInstalledFile.setData( std::move(newdata) );
1859  }
1860 
1862  { return baseproductdata( _root ).registerTarget(); }
1863  // static version:
1864  std::string TargetImpl::targetDistribution( const Pathname & root_r )
1865  { return baseproductdata( staticGuessRoot(root_r) ).registerTarget(); }
1866 
1868  { return baseproductdata( _root ).registerRelease(); }
1869  // static version:
1870  std::string TargetImpl::targetDistributionRelease( const Pathname & root_r )
1871  { return baseproductdata( staticGuessRoot(root_r) ).registerRelease();}
1872 
1874  { return baseproductdata( _root ).registerFlavor(); }
1875  // static version:
1876  std::string TargetImpl::targetDistributionFlavor( const Pathname & root_r )
1877  { return baseproductdata( staticGuessRoot(root_r) ).registerFlavor();}
1878 
1880  {
1882  parser::ProductFileData pdata( baseproductdata( _root ) );
1883  ret.shortName = pdata.shortName();
1884  ret.summary = pdata.summary();
1885  return ret;
1886  }
1887  // static version:
1889  {
1891  parser::ProductFileData pdata( baseproductdata( staticGuessRoot(root_r) ) );
1892  ret.shortName = pdata.shortName();
1893  ret.summary = pdata.summary();
1894  return ret;
1895  }
1896 
1898  {
1899  if ( _distributionVersion.empty() )
1900  {
1902  if ( !_distributionVersion.empty() )
1903  MIL << "Remember distributionVersion = '" << _distributionVersion << "'" << endl;
1904  }
1905  return _distributionVersion;
1906  }
1907  // static version
1908  std::string TargetImpl::distributionVersion( const Pathname & root_r )
1909  {
1910  std::string distributionVersion = baseproductdata( staticGuessRoot(root_r) ).edition().version();
1911  if ( distributionVersion.empty() )
1912  {
1913  // ...But the baseproduct method is not expected to work on RedHat derivatives.
1914  // On RHEL, Fedora and others the "product version" is determined by the first package
1915  // providing 'system-release'. This value is not hardcoded in YUM and can be configured
1916  // with the $distroverpkg variable.
1917  scoped_ptr<rpm::RpmDb> tmprpmdb;
1918  if ( ZConfig::instance().systemRoot() == Pathname() )
1919  {
1920  try
1921  {
1922  tmprpmdb.reset( new rpm::RpmDb );
1923  tmprpmdb->initDatabase( /*default ctor uses / but no additional keyring exports */ );
1924  }
1925  catch( ... )
1926  {
1927  return "";
1928  }
1929  }
1932  distributionVersion = it->tag_version();
1933  }
1934  return distributionVersion;
1935  }
1936 
1937 
1939  {
1940  return firstNonEmptyLineIn( home() / "LastDistributionFlavor" );
1941  }
1942  // static version:
1943  std::string TargetImpl::distributionFlavor( const Pathname & root_r )
1944  {
1945  return firstNonEmptyLineIn( staticGuessRoot(root_r) / "/var/lib/zypp/LastDistributionFlavor" );
1946  }
1947 
1949  namespace
1950  {
1951  std::string guessAnonymousUniqueId( const Pathname & root_r )
1952  {
1953  // bsc#1024741: Omit creating a new uid for chrooted systems (if it already has one, fine)
1954  std::string ret( firstNonEmptyLineIn( root_r / "/var/lib/zypp/AnonymousUniqueId" ) );
1955  if ( ret.empty() && root_r != "/" )
1956  {
1957  // if it has nonoe, use the outer systems one
1958  ret = firstNonEmptyLineIn( "/var/lib/zypp/AnonymousUniqueId" );
1959  }
1960  return ret;
1961  }
1962  }
1963 
1964  std::string TargetImpl::anonymousUniqueId() const
1965  {
1966  return guessAnonymousUniqueId( root() );
1967  }
1968  // static version:
1969  std::string TargetImpl::anonymousUniqueId( const Pathname & root_r )
1970  {
1971  return guessAnonymousUniqueId( staticGuessRoot(root_r) );
1972  }
1973 
1975 
1976  void TargetImpl::vendorAttr( VendorAttr vendorAttr_r )
1977  {
1978  MIL << "New VendorAttr: " << vendorAttr_r << endl;
1979  _vendorAttr = std::move(vendorAttr_r);
1980  }
1982 
1983  void TargetImpl::installSrcPackage( const SrcPackage_constPtr & srcPackage_r )
1984  {
1985  // provide on local disk
1986  ManagedFile localfile = provideSrcPackage(srcPackage_r);
1987  // create a installation progress report proxy
1988  RpmInstallPackageReceiver progress( srcPackage_r );
1989  progress.connect(); // disconnected on destruction.
1990  // install it
1991  rpm().installPackage ( localfile );
1992  }
1993 
1994  ManagedFile TargetImpl::provideSrcPackage( const SrcPackage_constPtr & srcPackage_r )
1995  {
1996  // provide on local disk
1997  repo::RepoMediaAccess access_r;
1998  repo::SrcPackageProvider prov( access_r );
1999  return prov.provideSrcPackage( srcPackage_r );
2000  }
2002  } // namespace target
2005 } // namespace zypp
#define for_(IT, BEG, END)
Convenient for-loops using iterator.
Definition: Easy.h:28
#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:78
#define MIL
Definition: Logger.h:79
#define ERR
Definition: Logger.h:81
#define WAR
Definition: Logger.h:80
#define INT
Definition: Logger.h:83
callback::SendReport< DownloadProgressReport > * report
Definition: MediaCurl.cc:70
#define idstr(V)
const Pathname & _root
Definition: RepoManager.cc:143
#define SUBST_IF(PAT, VAL)
ZYppCommitResult & _result
Definition: TargetImpl.cc:1475
TrueBool _guard
Definition: TargetImpl.cc:1474
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:60
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:1176
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:1867
std::string targetDistribution() const
This is register.target attribute of the installed base product.
Definition: TargetImpl.cc:1861
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:1852
ManagedFile provideSrcPackage(const SrcPackage_constPtr &srcPackage_r)
Provides a source package on the Target.
Definition: TargetImpl.cc:1994
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:837
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:1768
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:1897
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:815
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:1831
Target::DistributionLabel distributionLabel() const
This is shortName and summary attribute of the installed base product.
Definition: TargetImpl.cc:1879
virtual ~TargetImpl()
Dtor.
Definition: TargetImpl.cc:873
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:1773
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:1054
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:1938
void installSrcPackage(const SrcPackage_constPtr &srcPackage_r)
Install a source package on the Target.
Definition: TargetImpl.cc:1983
ZYppCommitResult commit(ResPool pool_r, const ZYppCommitPolicy &policy_r)
Commit changes in the pool.
Definition: TargetImpl.cc:1189
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:886
std::string anonymousUniqueId() const
anonymous unique id
Definition: TargetImpl.cc:1964
TargetImpl(const Pathname &root_r="/", bool doRebuild_r=false)
Ctor.
Definition: TargetImpl.cc:745
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:1873
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:730
std::string rpmDbStateHash(const Pathname &root_r)
Definition: TargetImpl.cc:73
void writeUpgradeTestcase()
Definition: TargetImpl.cc:284
static bool fileMissing(const Pathname &pathname)
helper functor
Definition: TargetImpl.cc:810
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:775
RepoStatus rpmDbRepoStatus(const Pathname &root_r)
Definition: TargetImpl.cc:91
static std::string generateRandomId()
generates a random id using uuidgen
Definition: TargetImpl.cc:764
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