libzypp: zypp/target/TargetImpl.cc Source File

libzypp 17.38.15

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 <map>
18#include <set>
19
20#include <sys/types.h>
21#include <dirent.h>
22
23#include <zypp-core/base/LogTools.h>
24#include <zypp-core/base/Exception.h>
25#include <zypp-core/base/Iterator.h>
26#include <zypp-core/base/Gettext.h>
27#include <zypp-core/base/IOStream.h>
28#include <zypp-core/base/Functional.h>
29#include <zypp-core/base/UserRequestException>
30#include <zypp/base/Json.h>
31#include <zypp-core/base/Env.h>
32
33#include <zypp/ZConfig.h>
34#include <zypp/ZYppFactory.h>
35#include <zypp/PathInfo.h>
36
37#include <zypp/PoolItem.h>
38#include <zypp/ResObjects.h>
39#include <zypp-core/Url.h>
40#include <zypp/TmpPath.h>
41#include <zypp/RepoStatus.h>
42#include <zypp-core/ExternalProgram.h>
43#include <zypp/Repository.h>
44#include <zypp-core/ShutdownLock_p.h>
45
46#include <zypp/ResFilters.h>
47#include <zypp/HistoryLog.h>
48#include <zypp/target/TargetImpl.h>
49#include <zypp/target/TargetCallbackReceiver.h>
50#include <zypp/target/rpm/librpmDb.h>
51#include <zypp/target/CommitPackageCache.h>
52#include <zypp/target/RpmPostTransCollector.h>
53#include <zypp/target/private/commitpackagepreloader_p.h>
54
55#include <zypp/parser/ProductFileReader.h>
56#include <zypp/repo/SrcPackageProvider.h>
57
58#include <zypp/sat/Pool.h>
59#include <zypp/sat/detail/PoolImpl.h>
60#include <zypp/sat/SolvableSpec.h>
61#include <zypp/sat/Transaction.h>
62
63#include <zypp-core/base/String.h>
64#include <zypp-core/base/StringV.h>
65#include <zypp-core/ng/base/EventLoop>
66#include <zypp-core/ng/base/UnixSignalSource>
67#include <zypp-core/ng/io/AsyncDataSource>
68#include <zypp-core/ng/io/Process>
69#include <zypp-core/base/IOTools.h>
70#include <zypp-core/ng/rpc/stompframestream.h>
71#include <zypp-core/ng/base/private/linuxhelpers_p.h>
72#include <zypp-core/ng/base/EventDispatcher>
73
74#include <shared/commit/CommitMessages.h>
75
76#include <zypp/target/rpm/RpmException.h>
77
78#include <zypp/PluginExecutor.h>
79
80// include the error codes from zypp-rpm
81#include "tools/zypp-rpm/errorcodes.h"
82#include <rpm/rpmlog.h>
83
84#include <optional>
85
86namespace zypp::env {
87 inline bool TRANSACTIONAL_UPDATE()
88 {
89 static bool val = [](){
90 const char * env = getenv("TRANSACTIONAL_UPDATE");
91 return( env && zypp::str::strToBool( env, true ) );
92 }();
93 return val;
94 }
95} // namespace zypp::env
96
97using std::endl;
98
100extern "C"
101{
102#include <solv/repo_rpmdb.h>
103#include <solv/chksum.h>
104}
105namespace zypp
106{
107 namespace target
108 {
109 inline std::string rpmDbStateHash( const Pathname & root_r )
110 {
111 std::string ret;
112 AutoDispose<void*> state { ::rpm_state_create( sat::Pool::instance().get(), root_r.c_str() ), ::rpm_state_free };
113 AutoDispose<Chksum*> chk { ::solv_chksum_create( REPOKEY_TYPE_SHA1 ), []( Chksum *chk ) -> void {
114 ::solv_chksum_free( chk, nullptr );
115 } };
116 if ( ::rpm_hash_database_state( state, chk ) == 0 )
117 {
118 int md5l;
119 const unsigned char * md5 = ::solv_chksum_get( chk, &md5l );
120 ret = ::pool_bin2hex( sat::Pool::instance().get(), md5, md5l );
121 }
122 else
123 WAR << "rpm_hash_database_state failed" << endl;
124 return ret;
125 }
126
127 inline RepoStatus rpmDbRepoStatus( const Pathname & root_r )
128 { return RepoStatus( rpmDbStateHash( root_r ), Date() ); }
129
130 } // namespace target
131} // namespace
133
135namespace zypp
136{
138 namespace
139 {
140 // HACK for bnc#906096: let pool re-evaluate multiversion spec
141 // if target root changes. ZConfig returns data sensitive to
142 // current target root.
143 inline void sigMultiversionSpecChanged()
144 {
145 if ( sat::detail::PoolMember::poolValid () )
146 sat::detail::PoolMember::myPool().multiversionSpecChanged();
147 }
148 } //namespace
150
152 namespace json
153 {
154 // Lazy via template specialisation / should switch to overloading
155
157 template<>
158 inline json::Value toJSON ( const sat::Transaction::Step & step_r )
159 {
160 static const std::string strType( "type" );
161 static const std::string strStage( "stage" );
162 static const std::string strSolvable( "solvable" );
163
164 static const std::string strTypeDel( "-" );
165 static const std::string strTypeIns( "+" );
166 static const std::string strTypeMul( "M" );
167
168 static const std::string strStageDone( "ok" );
169 static const std::string strStageFailed( "err" );
170
171 static const std::string strSolvableN( "n" );
172 static const std::string strSolvableE( "e" );
173 static const std::string strSolvableV( "v" );
174 static const std::string strSolvableR( "r" );
175 static const std::string strSolvableA( "a" );
176
177 using sat::Transaction;
178 json::Object ret;
179
180 switch ( step_r.stepType() )
181 {
182 case Transaction::TRANSACTION_IGNORE: /*empty*/ break;
183 case Transaction::TRANSACTION_ERASE: ret.add( strType, strTypeDel ); break;
184 case Transaction::TRANSACTION_INSTALL: ret.add( strType, strTypeIns ); break;
185 case Transaction::TRANSACTION_MULTIINSTALL: ret.add( strType, strTypeMul ); break;
186 }
187
188 switch ( step_r.stepStage() )
189 {
190 case Transaction::STEP_TODO: /*empty*/ break;
191 case Transaction::STEP_DONE: ret.add( strStage, strStageDone ); break;
192 case Transaction::STEP_ERROR: ret.add( strStage, strStageFailed ); break;
193 }
194
195 {
196 IdString ident;
197 Edition ed;
198 Arch arch;
199 if ( sat::Solvable solv = step_r.satSolvable() )
200 {
201 ident = solv.ident();
202 ed = solv.edition();
203 arch = solv.arch();
204 }
205 else
206 {
207 // deleted package; post mortem data stored in Transaction::Step
208 ident = step_r.ident();
209 ed = step_r.edition();
210 arch = step_r.arch();
211 }
212
213 json::Object s {
214 { strSolvableN, ident.asString() },
215 { strSolvableV, ed.version() },
216 { strSolvableR, ed.release() },
217 { strSolvableA, arch.asString() }
218 };
219 if ( Edition::epoch_t epoch = ed.epoch() )
220 s.add( strSolvableE, epoch );
221
222 ret.add( strSolvable, s );
223 }
224
225 return ret;
226 }
227
228 template<>
229 inline json::Value toJSON( const ZYppCommitResult::TransactionStepList & steps_r )
230 {
231 using sat::Transaction;
232 json::Array ret;
233
234 for ( const Transaction::Step & step : steps_r )
235 // ignore implicit deletes due to obsoletes and non-package actions
236 if ( step.stepType() != Transaction::TRANSACTION_IGNORE )
237 ret.add( toJSON(step) );
238
239 return ret;
240 }
241
242 } // namespace json
243
244
246 namespace target
247 {
249 namespace
250 {
251 struct InstallResolvableSAReportReceiver : public callback::ReceiveReport<rpm::InstallResolvableReportSA>
252 {
253 using ReportType = callback::SendReport<rpm::InstallResolvableReport>;
254
255 InstallResolvableSAReportReceiver()
256 : _report { std::make_unique<ReportType>() }
257 {}
258
259 void start( Resolvable::constPtr resolvable, const UserData & = UserData() /*userdata*/ ) override
260 { (*_report)->start( resolvable ); }
261
262 void progress( int value, Resolvable::constPtr resolvable, const UserData & = UserData() /*userdata*/ ) override
263 { (*_report)->progress( value, resolvable ); }
264
265 void finish( Resolvable::constPtr resolvable, Error error, const UserData & = UserData() /*userdata*/ ) override
266 { (*_report)->finish( resolvable, static_cast<rpm::InstallResolvableReport::Error>(error), "", rpm::InstallResolvableReport::RpmLevel::RPM/*unused legacy*/ ); }
267
268 private:
269 std::unique_ptr<ReportType> _report;
270 };
271
272 struct RemoveResolvableSAReportReceiver : public callback::ReceiveReport<rpm::RemoveResolvableReportSA>
273 {
274 using ReportType = callback::SendReport<rpm::RemoveResolvableReport>;
275
276 RemoveResolvableSAReportReceiver()
277 : _report { std::make_unique<ReportType>() }
278 {}
279
280 virtual void start( Resolvable::constPtr resolvable, const UserData & = UserData() /*userdata*/ )
281 { (*_report)->start( resolvable ); }
282
283 virtual void progress( int value, Resolvable::constPtr resolvable, const UserData & = UserData() /*userdata*/ )
284 { (*_report)->progress( value, resolvable ); }
285
286 virtual void finish( Resolvable::constPtr resolvable, Error error, const UserData & = UserData() /*userdata*/ )
287 { (*_report)->finish( resolvable, static_cast<rpm::RemoveResolvableReport::Error>(error), "" ); }
288
289 private:
290 std::unique_ptr<ReportType> _report;
291 };
292
298 struct SingleTransReportLegacyWrapper
299 {
300 NON_COPYABLE(SingleTransReportLegacyWrapper);
301 NON_MOVABLE(SingleTransReportLegacyWrapper);
302
303 SingleTransReportLegacyWrapper()
304 {
305 if ( not singleTransReportsConnected() and legacyReportsConnected() )
306 {
307 WAR << "Activating SingleTransReportLegacyWrapper! The application does not listen to the singletrans reports :(" << endl;
308 _installResolvableSAReportReceiver = InstallResolvableSAReportReceiver();
309 _removeResolvableSAReportReceiver = RemoveResolvableSAReportReceiver();
310 _installResolvableSAReportReceiver->connect();
311 _removeResolvableSAReportReceiver->connect();
312
313 }
314 }
315
316 ~SingleTransReportLegacyWrapper()
317 {
318 }
319
320 bool singleTransReportsConnected() const
321 {
322 return callback::SendReport<rpm::SingleTransReport>::connected()
323 || callback::SendReport<rpm::InstallResolvableReportSA>::connected()
324 || callback::SendReport<rpm::RemoveResolvableReportSA>::connected()
325 || callback::SendReport<rpm::CommitScriptReportSA>::connected()
326 || callback::SendReport<rpm::TransactionReportSA>::connected()
327 || callback::SendReport<rpm::CleanupPackageReportSA>::connected()
328 ;
329 }
330
331 bool legacyReportsConnected() const
332 {
333 return callback::SendReport<rpm::InstallResolvableReport>::connected()
334 || callback::SendReport<rpm::RemoveResolvableReport>::connected()
335 ;
336 }
337
338 private:
339 std::optional<InstallResolvableSAReportReceiver> _installResolvableSAReportReceiver;
340 std::optional<RemoveResolvableSAReportReceiver> _removeResolvableSAReportReceiver;
341 };
342 } //namespace
344
346 namespace
347 {
348 class AssertMountedBase
349 {
350 NON_COPYABLE(AssertMountedBase);
351 NON_MOVABLE(AssertMountedBase);
352 protected:
353 AssertMountedBase()
354 {}
355
356 ~AssertMountedBase()
357 {
358 if ( ! _mountpoint.empty() ) {
359 // we mounted it so we unmount...
360 MIL << "We mounted " << _mountpoint << " so we unmount it" << endl;
361 execute({ "umount", "-R", "-l", _mountpoint.asString() });
362 }
363 }
364
365 protected:
366 int execute( ExternalProgram::Arguments && cmd_r ) const
367 {
368 ExternalProgram prog( cmd_r, ExternalProgram::Stderr_To_Stdout );
369 for( std::string line = prog.receiveLine(); ! line.empty(); line = prog.receiveLine() )
370 { DBG << line; }
371 return prog.close();
372 }
373
374 protected:
375 Pathname _mountpoint;
376
377 };
378
381 class AssertProcMounted : private AssertMountedBase
382 {
383 public:
384 AssertProcMounted( Pathname root_r )
385 {
386 root_r /= "/proc";
387 if ( ! PathInfo(root_r/"self").isDir() ) {
388 MIL << "Try to make sure proc is mounted at" << root_r << endl;
389 if ( filesystem::assert_dir(root_r) == 0
390 && execute({ "mount", "-t", "proc", "/proc", root_r.asString() }) == 0 ) {
391 _mountpoint = std::move(root_r); // so we'll later unmount it
392 }
393 else {
394 WAR << "Mounting proc at " << root_r << " failed" << endl;
395 }
396 }
397 }
398 };
399
402 class AssertDevMounted : private AssertMountedBase
403 {
404 public:
405 AssertDevMounted( Pathname root_r )
406 {
407 root_r /= "/dev";
408 if ( ! PathInfo(root_r/"null").isChr() ) {
409 MIL << "Try to make sure dev is mounted at" << root_r << endl;
410 // https://unix.stackexchange.com/questions/263972/unmount-a-rbind-mount-without-affecting-the-original-mount
411 // Without --make-rslave unmounting <sandbox-root>/dev/pts
412 // may unmount /dev/pts and you're out of ptys.
413 if ( filesystem::assert_dir(root_r) == 0
414 && execute({ "mount", "--rbind", "--make-rslave", "/dev", root_r.asString() }) == 0 ) {
415 _mountpoint = std::move(root_r); // so we'll later unmount it
416 }
417 else {
418 WAR << "Mounting dev at " << root_r << " failed" << endl;
419 }
420 }
421 }
422 };
423
424 } // namespace
426
428 namespace
429 {
430 SolvIdentFile::Data getUserInstalledFromHistory( const Pathname & historyFile_r )
431 {
432 SolvIdentFile::Data onSystemByUserList;
433 // go and parse it: 'who' must constain an '@', then it was installed by user request.
434 // 2009-09-29 07:25:19|install|lirc-remotes|0.8.5-3.2|x86_64|root@opensuse|InstallationImage|a204211eb0...
435 std::ifstream infile( historyFile_r.c_str() );
436 for( iostr::EachLine in( infile ); in; in.next() )
437 {
438 const char * ch( (*in).c_str() );
439 // start with year
440 if ( *ch < '1' || '9' < *ch )
441 continue;
442 const char * sep1 = ::strchr( ch, '|' ); // | after date
443 if ( !sep1 )
444 continue;
445 ++sep1;
446 // if logs an install or delete
447 bool installs = true;
448 if ( ::strncmp( sep1, "install|", 8 ) )
449 {
450 if ( ::strncmp( sep1, "remove |", 8 ) )
451 continue; // no install and no remove
452 else
453 installs = false; // remove
454 }
455 sep1 += 8; // | after what
456 // get the package name
457 const char * sep2 = ::strchr( sep1, '|' ); // | after name
458 if ( !sep2 || sep1 == sep2 )
459 continue;
460 (*in)[sep2-ch] = '\0';
461 IdString pkg( sep1 );
462 // we're done, if a delete
463 if ( !installs )
464 {
465 onSystemByUserList.erase( pkg );
466 continue;
467 }
468 // now guess whether user installed or not (3rd next field contains 'user@host')
469 if ( (sep1 = ::strchr( sep2+1, '|' )) // | after version
470 && (sep1 = ::strchr( sep1+1, '|' )) // | after arch
471 && (sep2 = ::strchr( sep1+1, '|' )) ) // | after who
472 {
473 (*in)[sep2-ch] = '\0';
474 if ( ::strchr( sep1+1, '@' ) )
475 {
476 // by user
477 onSystemByUserList.insert( pkg );
478 continue;
479 }
480 }
481 }
482 MIL << "onSystemByUserList found: " << onSystemByUserList.size() << endl;
483 return onSystemByUserList;
484 }
485 } // namespace
487
489 namespace
490 {
491 inline PluginFrame transactionPluginFrame( const std::string & command_r, const ZYppCommitResult::TransactionStepList & steps_r )
492 {
493 return PluginFrame( command_r, json::Object {
494 { "TransactionStepList", json::toJSON(steps_r) }
495 }.asJSON() );
496 }
497 } // namespace
499
501 void writeUpgradeTestcase()
502 {
503 unsigned toKeep( ZConfig::instance().solver_upgradeTestcasesToKeep() );
504 MIL << "Testcases to keep: " << toKeep << endl;
505 if ( !toKeep )
506 return;
507 Target_Ptr target( getZYpp()->getTarget() );
508 if ( ! target )
509 {
510 WAR << "No Target no Testcase!" << endl;
511 return;
512 }
513
514 std::string stem( "updateTestcase" );
515 Pathname dir( target->assertRootPrefix("/var/log/") );
516 Pathname next( dir / Date::now().form( stem+"-%Y-%m-%d-%H-%M-%S" ) );
517
518 {
519 std::list<std::string> content;
520 filesystem::readdir( content, dir, /*dots*/false );
521 std::set<std::string> cases;
522 for_( c, content.begin(), content.end() )
523 {
524 if ( str::startsWith( *c, stem ) )
525 cases.insert( *c );
526 }
527 if ( cases.size() >= toKeep )
528 {
529 unsigned toDel = cases.size() - toKeep + 1; // +1 for the new one
530 for_( c, cases.begin(), cases.end() )
531 {
532 filesystem::recursive_rmdir( dir/(*c) );
533 if ( ! --toDel )
534 break;
535 }
536 }
537 }
538
539 MIL << "Write new testcase " << next << endl;
540 getZYpp()->resolver()->createSolverTestcase( next.asString(), false/*no solving*/ );
541 }
542
544 namespace
545 {
546
557 std::pair<bool,PatchScriptReport::Action> doExecuteScript( const Pathname & root_r,
558 const Pathname & script_r,
559 callback::SendReport<PatchScriptReport> & report_r )
560 {
561 MIL << "Execute script " << PathInfo(Pathname::assertprefix( root_r,script_r)) << endl;
562
563 HistoryLog historylog;
564 historylog.comment(script_r.asString() + _(" executed"), /*timestamp*/true);
565 ExternalProgram prog( script_r.asString(), ExternalProgram::Stderr_To_Stdout, false, -1, true, root_r );
566
567 for ( std::string output = prog.receiveLine(); output.length(); output = prog.receiveLine() )
568 {
569 historylog.comment(output);
570 if ( ! report_r->progress( PatchScriptReport::OUTPUT, output ) )
571 {
572 WAR << "User request to abort script " << script_r << endl;
573 prog.kill();
574 // the rest is handled by exit code evaluation
575 // in case the script has meanwhile finished.
576 }
577 }
578
579 std::pair<bool,PatchScriptReport::Action> ret( std::make_pair( false, PatchScriptReport::ABORT ) );
580
581 if ( prog.close() != 0 )
582 {
583 ret.second = report_r->problem( prog.execError() );
584 WAR << "ACTION" << ret.second << "(" << prog.execError() << ")" << endl;
585 std::ostringstream sstr;
586 sstr << script_r << _(" execution failed") << " (" << prog.execError() << ")" << endl;
587 historylog.comment(sstr.str(), /*timestamp*/true);
588 return ret;
589 }
590
591 report_r->finish();
592 ret.first = true;
593 return ret;
594 }
595
599 bool executeScript( const Pathname & root_r,
600 const Pathname & script_r,
601 callback::SendReport<PatchScriptReport> & report_r )
602 {
603 std::pair<bool,PatchScriptReport::Action> action( std::make_pair( false, PatchScriptReport::ABORT ) );
604
605 do {
606 action = doExecuteScript( root_r, script_r, report_r );
607 if ( action.first )
608 return true; // success
609
610 switch ( action.second )
611 {
612 case PatchScriptReport::ABORT:
613 WAR << "User request to abort at script " << script_r << endl;
614 return false; // requested abort.
615 break;
616
617 case PatchScriptReport::IGNORE:
618 WAR << "User request to skip script " << script_r << endl;
619 return true; // requested skip.
620 break;
621
622 case PatchScriptReport::RETRY:
623 break; // again
624 }
625 } while ( action.second == PatchScriptReport::RETRY );
626
627 // THIS is not intended to be reached:
628 INT << "Abort on unknown ACTION request " << action.second << " returned" << endl;
629 return false; // abort.
630 }
631
637 bool RunUpdateScripts( const Pathname & root_r,
638 const Pathname & scriptsPath_r,
639 const std::vector<sat::Solvable> & checkPackages_r,
640 bool aborting_r )
641 {
642 if ( checkPackages_r.empty() )
643 return true; // no installed packages to check
644
645 MIL << "Looking for new update scripts in (" << root_r << ")" << scriptsPath_r << endl;
646 Pathname scriptsDir( Pathname::assertprefix( root_r, scriptsPath_r ) );
647 if ( ! PathInfo( scriptsDir ).isDir() )
648 return true; // no script dir
649
650 std::list<std::string> scripts;
651 filesystem::readdir( scripts, scriptsDir, /*dots*/false );
652 if ( scripts.empty() )
653 return true; // no scripts in script dir
654
655 // Now collect and execute all matching scripts.
656 // On ABORT: at least log all outstanding scripts.
657 // - "name-version-release"
658 // - "name-version-release-*"
659 bool abort = false;
660 std::map<std::string, Pathname> unify; // scripts <md5,path>
661 for_( it, checkPackages_r.begin(), checkPackages_r.end() )
662 {
663 std::string prefix( str::form( "%s-%s", it->name().c_str(), it->edition().c_str() ) );
664 for_( sit, scripts.begin(), scripts.end() )
665 {
666 if ( ! str::hasPrefix( *sit, prefix ) )
667 continue;
668
669 if ( (*sit)[prefix.size()] != '\0' && (*sit)[prefix.size()] != '-' )
670 continue; // if not exact match it had to continue with '-'
671
672 PathInfo script( scriptsDir / *sit );
673 Pathname localPath( scriptsPath_r/(*sit) ); // without root prefix
674 std::string unifytag; // must not stay empty
675
676 if ( script.isFile() )
677 {
678 // Assert it's set as executable, unify by md5sum.
679 filesystem::addmod( script.path(), 0500 );
680 unifytag = filesystem::md5sum( script.path() );
681 }
682 else if ( ! script.isExist() )
683 {
684 // Might be a dangling symlink, might be ok if we are in
685 // instsys (absolute symlink within the system below /mnt).
686 // readlink will tell....
687 unifytag = filesystem::readlink( script.path() ).asString();
688 }
689
690 if ( unifytag.empty() )
691 continue;
692
693 // Unify scripts
694 if ( unify[unifytag].empty() )
695 {
696 unify[unifytag] = localPath;
697 }
698 else
699 {
700 // translators: We may find the same script content in files with different names.
701 // Only the first occurence is executed, subsequent ones are skipped. It's a one-line
702 // message for a log file. Preferably start translation with "%s"
703 std::string msg( str::form(_("%s already executed as %s)"), localPath.asString().c_str(), unify[unifytag].c_str() ) );
704 MIL << "Skip update script: " << msg << endl;
705 HistoryLog().comment( msg, /*timestamp*/true );
706 continue;
707 }
708
709 if ( abort || aborting_r )
710 {
711 WAR << "Aborting: Skip update script " << *sit << endl;
712 HistoryLog().comment(
713 localPath.asString() + _(" execution skipped while aborting"),
714 /*timestamp*/true);
715 }
716 else
717 {
718 MIL << "Found update script " << *sit << endl;
719 callback::SendReport<PatchScriptReport> report;
720 report->start( make<Package>( *it ), script.path() );
721
722 if ( ! executeScript( root_r, localPath, report ) ) // script path without root prefix!
723 abort = true; // requested abort.
724 }
725 }
726 }
727 return !abort;
728 }
729
731 //
733
734 inline void copyTo( std::ostream & out_r, const Pathname & file_r )
735 {
736 std::ifstream infile( file_r.c_str() );
737 for( iostr::EachLine in( infile ); in; in.next() )
738 {
739 out_r << *in << endl;
740 }
741 }
742
743 inline std::string notificationCmdSubst( const std::string & cmd_r, const UpdateNotificationFile & notification_r )
744 {
745 std::string ret( cmd_r );
746#define SUBST_IF(PAT,VAL) if ( ret.find( PAT ) != std::string::npos ) ret = str::gsub( ret, PAT, VAL )
747 SUBST_IF( "%p", notification_r.solvable().asString() );
748 SUBST_IF( "%P", notification_r.file().asString() );
749#undef SUBST_IF
750 return ret;
751 }
752
753 void sendNotification( const Pathname & root_r,
754 const UpdateNotifications & notifications_r )
755 {
756 if ( notifications_r.empty() )
757 return;
758
759 std::string cmdspec( ZConfig::instance().updateMessagesNotify() );
760 MIL << "Notification command is '" << cmdspec << "'" << endl;
761 if ( cmdspec.empty() )
762 return;
763
764 std::string::size_type pos( cmdspec.find( '|' ) );
765 if ( pos == std::string::npos )
766 {
767 ERR << "Can't send Notification: Missing 'format |' in command spec." << endl;
768 HistoryLog().comment( str::Str() << _("Error sending update message notification."), /*timestamp*/true );
769 return;
770 }
771
772 std::string formatStr( str::toLower( str::trim( cmdspec.substr( 0, pos ) ) ) );
773 std::string commandStr( str::trim( cmdspec.substr( pos + 1 ) ) );
774
775 enum Format { UNKNOWN, NONE, SINGLE, DIGEST, BULK };
776 Format format = UNKNOWN;
777 if ( formatStr == "none" )
778 format = NONE;
779 else if ( formatStr == "single" )
780 format = SINGLE;
781 else if ( formatStr == "digest" )
782 format = DIGEST;
783 else if ( formatStr == "bulk" )
784 format = BULK;
785 else
786 {
787 ERR << "Can't send Notification: Unknown format '" << formatStr << " |' in command spec." << endl;
788 HistoryLog().comment( str::Str() << _("Error sending update message notification."), /*timestamp*/true );
789 return;
790 }
791
792 // Take care: commands are ececuted chroot(root_r). The message file
793 // pathnames in notifications_r are local to root_r. For physical access
794 // to the file they need to be prefixed.
795
796 if ( format == NONE || format == SINGLE )
797 {
798 for_( it, notifications_r.begin(), notifications_r.end() )
799 {
800 std::vector<std::string> command;
801 if ( format == SINGLE )
802 command.push_back( "<"+Pathname::assertprefix( root_r, it->file() ).asString() );
803 str::splitEscaped( notificationCmdSubst( commandStr, *it ), std::back_inserter( command ) );
804
805 ExternalProgram prog( command, ExternalProgram::Stderr_To_Stdout, false, -1, true, root_r );
806 if ( true ) // Wait for feedback
807 {
808 for( std::string line = prog.receiveLine(); ! line.empty(); line = prog.receiveLine() )
809 {
810 DBG << line;
811 }
812 int ret = prog.close();
813 if ( ret != 0 )
814 {
815 ERR << "Notification command returned with error (" << ret << ")." << endl;
816 HistoryLog().comment( str::Str() << _("Error sending update message notification."), /*timestamp*/true );
817 return;
818 }
819 }
820 }
821 }
822 else if ( format == DIGEST || format == BULK )
823 {
824 filesystem::TmpFile tmpfile;
825 std::ofstream out( tmpfile.path().c_str() );
826 for_( it, notifications_r.begin(), notifications_r.end() )
827 {
828 if ( format == DIGEST )
829 {
830 out << it->file() << endl;
831 }
832 else if ( format == BULK )
833 {
834 copyTo( out << '\f', Pathname::assertprefix( root_r, it->file() ) );
835 }
836 }
837
838 std::vector<std::string> command;
839 command.push_back( "<"+tmpfile.path().asString() ); // redirect input
840 str::splitEscaped( notificationCmdSubst( commandStr, *notifications_r.begin() ), std::back_inserter( command ) );
841
842 ExternalProgram prog( command, ExternalProgram::Stderr_To_Stdout, false, -1, true, root_r );
843 if ( true ) // Wait for feedback otherwise the TmpFile goes out of scope.
844 {
845 for( std::string line = prog.receiveLine(); ! line.empty(); line = prog.receiveLine() )
846 {
847 DBG << line;
848 }
849 int ret = prog.close();
850 if ( ret != 0 )
851 {
852 ERR << "Notification command returned with error (" << ret << ")." << endl;
853 HistoryLog().comment( str::Str() << _("Error sending update message notification."), /*timestamp*/true );
854 return;
855 }
856 }
857 }
858 else
859 {
860 INT << "Can't send Notification: Missing handler for 'format |' in command spec." << endl;
861 HistoryLog().comment( str::Str() << _("Error sending update message notification."), /*timestamp*/true );
862 return;
863 }
864 }
865
866
872 void RunUpdateMessages( const Pathname & root_r,
873 const Pathname & messagesPath_r,
874 const std::vector<sat::Solvable> & checkPackages_r,
875 ZYppCommitResult & result_r )
876 {
877 if ( checkPackages_r.empty() )
878 return; // no installed packages to check
879
880 MIL << "Looking for new update messages in (" << root_r << ")" << messagesPath_r << endl;
881 Pathname messagesDir( Pathname::assertprefix( root_r, messagesPath_r ) );
882 if ( ! PathInfo( messagesDir ).isDir() )
883 return; // no messages dir
884
885 std::list<std::string> messages;
886 filesystem::readdir( messages, messagesDir, /*dots*/false );
887 if ( messages.empty() )
888 return; // no messages in message dir
889
890 // Now collect all matching messages in result and send them
891 // - "name-version-release"
892 // - "name-version-release-*"
893 HistoryLog historylog;
894 for_( it, checkPackages_r.begin(), checkPackages_r.end() )
895 {
896 std::string prefix( str::form( "%s-%s", it->name().c_str(), it->edition().c_str() ) );
897 for_( sit, messages.begin(), messages.end() )
898 {
899 if ( ! str::hasPrefix( *sit, prefix ) )
900 continue;
901
902 if ( (*sit)[prefix.size()] != '\0' && (*sit)[prefix.size()] != '-' )
903 continue; // if not exact match it had to continue with '-'
904
905 PathInfo message( messagesDir / *sit );
906 if ( ! message.isFile() || message.size() == 0 )
907 continue;
908
909 MIL << "Found update message " << *sit << endl;
910 Pathname localPath( messagesPath_r/(*sit) ); // without root prefix
911 result_r.rUpdateMessages().push_back( UpdateNotificationFile( *it, localPath ) );
912 historylog.comment( str::Str() << _("New update message") << " " << localPath, /*timestamp*/true );
913 }
914 }
915 sendNotification( root_r, result_r.updateMessages() );
916 }
917
921 void logPatchStatusChanges( const sat::Transaction & transaction_r, TargetImpl & target_r )
922 {
923 ResPool::ChangedPseudoInstalled changedPseudoInstalled { ResPool::instance().changedPseudoInstalled() };
924 if ( changedPseudoInstalled.empty() )
925 return;
926
927 if ( ! transaction_r.actionEmpty( ~sat::Transaction::STEP_DONE ) )
928 {
929 // Need to recompute the patch list if commit is incomplete!
930 // We remember the initially established status, then reload the
931 // Target to get the current patch status. Then compare.
932 WAR << "Need to recompute the patch status changes as commit is incomplete!" << endl;
933 ResPool::EstablishedStates establishedStates{ ResPool::instance().establishedStates() };
934 target_r.load();
935 changedPseudoInstalled = establishedStates.changedPseudoInstalled();
936 }
937
938 HistoryLog historylog;
939 for ( const auto & el : changedPseudoInstalled )
940 historylog.patchStateChange( el.first, el.second );
941 }
942
944 } // namespace
946
947 void XRunUpdateMessages( const Pathname & root_r,
948 const Pathname & messagesPath_r,
949 const std::vector<sat::Solvable> & checkPackages_r,
950 ZYppCommitResult & result_r )
951 { RunUpdateMessages( root_r, messagesPath_r, checkPackages_r, result_r ); }
952
954
955 IMPL_PTR_TYPE(TargetImpl);
956
958 //
959 // METHOD NAME : TargetImpl::TargetImpl
960 // METHOD TYPE : Ctor
961 //
962 TargetImpl::TargetImpl( const Pathname & root_r, bool doRebuild_r )
963 : _root( root_r )
964 , _requestedLocalesFile( home() / "RequestedLocales" )
965 , _autoInstalledFile( home() / "AutoInstalled" )
966 , _hardLocksFile( Pathname::assertprefix( _root, ZConfig::instance().locksFile() ) )
967 , _vendorAttr( Pathname::assertprefix( _root, ZConfig::instance().vendorPath() ) )
968 , _baseproductWatcher( Pathname::assertprefix( _root, "/etc/products.d/baseproduct" ), WatchFile::NO_INIT )
969 {
970 _rpm.initDatabase( root_r, doRebuild_r );
971
972 HistoryLog::setRoot(_root);
973
974 createAnonymousId();
975 sigMultiversionSpecChanged(); // HACK: see sigMultiversionSpecChanged
976 MIL << "Initialized target on " << _root << endl;
977 }
978
982 static std::string generateRandomId()
983 {
984 std::ifstream uuidprovider( "/proc/sys/kernel/random/uuid" );
985 return iostr::getline( uuidprovider );
986 }
987
993 void updateFileContent( const Pathname &filename,
994 boost::function<bool ()> condition,
995 boost::function<std::string ()> value )
996 {
997 std::string val = value();
998 // if the value is empty, then just dont
999 // do anything, regardless of the condition
1000 if ( val.empty() )
1001 return;
1002
1003 if ( condition() )
1004 {
1005 MIL << "updating '" << filename << "' content." << endl;
1006
1007 // if the file does not exist we need to generate the uuid file
1008
1009 std::ofstream filestr;
1010 // make sure the path exists
1011 filesystem::assert_dir( filename.dirname() );
1012 filestr.open( filename.c_str() );
1013
1014 if ( filestr.good() )
1015 {
1016 filestr << val;
1017 filestr.close();
1018 }
1019 else
1020 {
1021 // FIXME, should we ignore the error?
1022 ZYPP_THROW(Exception("Can't openfile '" + filename.asString() + "' for writing"));
1023 }
1024 }
1025 }
1026
1028 static bool fileMissing( const Pathname &pathname )
1029 {
1030 return ! PathInfo(pathname).isExist();
1031 }
1032
1033 void TargetImpl::createAnonymousId() const
1034 {
1035 // bsc#1024741: Omit creating a new uid for chrooted systems (if it already has one, fine)
1036 if ( root() != "/" )
1037 return;
1038
1039 // Create the anonymous unique id, used for download statistics
1040 Pathname idpath( home() / "AnonymousUniqueId");
1041
1042 try
1043 {
1044 updateFileContent( idpath,
1045 std::bind(fileMissing, idpath),
1046 generateRandomId );
1047 }
1048 catch ( const Exception &e )
1049 {
1050 WAR << "Can't create anonymous id file" << endl;
1051 }
1052
1053 }
1054
1055 void TargetImpl::createLastDistributionFlavorCache() const
1056 {
1057 // create the anonymous unique id
1058 // this value is used for statistics
1059 Pathname flavorpath( home() / "LastDistributionFlavor");
1060
1061 // is there a product
1062 Product::constPtr p = baseProduct();
1063 if ( ! p )
1064 {
1065 WAR << "No base product, I won't create flavor cache" << endl;
1066 return;
1067 }
1068
1069 std::string flavor = p->flavor();
1070
1071 try
1072 {
1073
1074 updateFileContent( flavorpath,
1075 // only if flavor is not empty
1076 functor::Constant<bool>( ! flavor.empty() ),
1077 functor::Constant<std::string>(flavor) );
1078 }
1079 catch ( const Exception &e )
1080 {
1081 WAR << "Can't create flavor cache" << endl;
1082 return;
1083 }
1084 }
1085
1087 //
1088 // METHOD NAME : TargetImpl::~TargetImpl
1089 // METHOD TYPE : Dtor
1090 //
1091 TargetImpl::~TargetImpl()
1092 {
1093 _rpm.closeDatabase();
1094 sigMultiversionSpecChanged(); // HACK: see sigMultiversionSpecChanged
1095 MIL << "Closed target on " << _root << endl;
1096 }
1097
1099 //
1100 // solv file handling
1101 //
1103
1104 Pathname TargetImpl::defaultSolvfilesPath() const
1105 {
1106 return Pathname::assertprefix( _root, ZConfig::instance().repoSolvfilesPath() / sat::Pool::instance().systemRepoAlias() );
1107 }
1108
1109 void TargetImpl::clearCache()
1110 {
1111 Pathname base = solvfilesPath();
1112 filesystem::recursive_rmdir( base );
1113 }
1114
1115 bool TargetImpl::buildCache()
1116 {
1117 Pathname base = solvfilesPath();
1118 Pathname rpmsolv = base/"solv";
1119 Pathname rpmsolvcookie = base/"cookie";
1120
1121 bool build_rpm_solv = true;
1122 // lets see if the rpm solv cache exists
1123
1124 RepoStatus rpmstatus( rpmDbRepoStatus(_root) && RepoStatus(_root/"etc/products.d") );
1125
1126 bool solvexisted = PathInfo(rpmsolv).isExist();
1127 if ( solvexisted )
1128 {
1129 // see the status of the cache
1130 PathInfo cookie( rpmsolvcookie );
1131 MIL << "Read cookie: " << cookie << endl;
1132 if ( cookie.isExist() )
1133 {
1134 RepoStatus status = RepoStatus::fromCookieFile(rpmsolvcookie);
1135 // now compare it with the rpm database
1136 if ( status == rpmstatus )
1137 build_rpm_solv = false;
1138 MIL << "Read cookie: " << rpmsolvcookie << " says: "
1139 << (build_rpm_solv ? "outdated" : "uptodate") << endl;
1140 }
1141 }
1142
1143 if ( build_rpm_solv )
1144 {
1145 // if the solvfile dir does not exist yet, we better create it
1146 filesystem::assert_dir( base );
1147
1148 Pathname oldSolvFile( solvexisted ? rpmsolv : Pathname() ); // to speedup rpmdb2solv
1149
1150 filesystem::TmpFile tmpsolv( filesystem::TmpFile::makeSibling( rpmsolv ) );
1151 if ( !tmpsolv )
1152 {
1153 // Can't create temporary solv file, usually due to insufficient permission
1154 // (user query while @System solv needs refresh). If so, try switching
1155 // to a location within zypps temp. space (will be cleaned at application end).
1156
1157 bool switchingToTmpSolvfile = false;
1158 Exception ex("Failed to cache rpm database.");
1159 ex.remember(str::form("Cannot create temporary file under %s.", base.c_str()));
1160
1161 if ( ! solvfilesPathIsTemp() )
1162 {
1163 base = getZYpp()->tmpPath() / sat::Pool::instance().systemRepoAlias();
1164 rpmsolv = base/"solv";
1165 rpmsolvcookie = base/"cookie";
1166
1167 filesystem::assert_dir( base );
1168 tmpsolv = filesystem::TmpFile::makeSibling( rpmsolv );
1169
1170 if ( tmpsolv )
1171 {
1172 WAR << "Using a temporary solv file at " << base << endl;
1173 switchingToTmpSolvfile = true;
1174 _tmpSolvfilesPath = base;
1175 }
1176 else
1177 {
1178 ex.remember(str::form("Cannot create temporary file under %s.", base.c_str()));
1179 }
1180 }
1181
1182 if ( ! switchingToTmpSolvfile )
1183 {
1184 ZYPP_THROW(ex);
1185 }
1186 }
1187
1188 // Take care we unlink the solvfile on exception
1189 ManagedFile guard( base, filesystem::recursive_rmdir );
1190
1191 ExternalProgram::Arguments cmd;
1192#ifdef ZYPP_RPMDB2SOLV_PATH
1193 cmd.push_back( ZYPP_RPMDB2SOLV_PATH );
1194#else
1195 cmd.push_back( "rpmdb2solv" );
1196#endif
1197 if ( ! _root.empty() ) {
1198 cmd.push_back( "-r" );
1199 cmd.push_back( _root.asString() );
1200 }
1201 cmd.push_back( "-D" );
1202 cmd.push_back( rpm().dbPath().asString() );
1203 cmd.push_back( "-X" ); // autogenerate pattern/product/... from -package
1204 // bsc#1104415: no more application support // cmd.push_back( "-A" ); // autogenerate application pseudo packages
1205 cmd.push_back( "-p" );
1206 cmd.push_back( Pathname::assertprefix( _root, "/etc/products.d" ).asString() );
1207
1208 if ( ! oldSolvFile.empty() )
1209 cmd.push_back( oldSolvFile.asString() );
1210
1211 cmd.push_back( "-o" );
1212 cmd.push_back( tmpsolv.path().asString() );
1213
1214 ExternalProgram prog( cmd, ExternalProgram::Stderr_To_Stdout );
1215 std::string errdetail;
1216
1217 for ( std::string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
1218 WAR << " " << output;
1219 if ( errdetail.empty() ) {
1220 errdetail = prog.command();
1221 errdetail += '\n';
1222 }
1223 errdetail += output;
1224 }
1225
1226 int ret = prog.close();
1227 if ( ret != 0 )
1228 {
1229 Exception ex(str::form("Failed to cache rpm database (%d).", ret));
1230 ex.remember( errdetail );
1231 ZYPP_THROW(ex);
1232 }
1233
1234 ret = filesystem::rename( tmpsolv, rpmsolv );
1235 if ( ret != 0 )
1236 ZYPP_THROW(Exception("Failed to move cache to final destination"));
1237 // if this fails, don't bother throwing exceptions
1238 filesystem::chmod( rpmsolv, 0644 );
1239
1240 rpmstatus.saveToCookieFile(rpmsolvcookie);
1241
1242 // We keep it.
1243 guard.resetDispose();
1244 sat::updateSolvFileIndex( rpmsolv ); // content digest for zypper bash completion
1245
1246 // system-hook: Finally send notification to plugins
1247 if ( root() == "/" )
1248 {
1249 PluginExecutor plugins;
1250 plugins.load( ZConfig::instance().pluginsPath()/"system" );
1251 if ( plugins )
1252 plugins.send( PluginFrame( "PACKAGESETCHANGED" ) );
1253 }
1254 }
1255 else
1256 {
1257 // On the fly add missing solv.idx files for bash completion.
1258 if ( ! PathInfo(base/"solv.idx").isExist() )
1259 sat::updateSolvFileIndex( rpmsolv );
1260 }
1261 return build_rpm_solv;
1262 }
1263
1264 void TargetImpl::reload()
1265 {
1266 load( false );
1267 }
1268
1269 void TargetImpl::unload()
1270 {
1271 Repository system( sat::Pool::instance().findSystemRepo() );
1272 if ( system )
1273 system.eraseFromPool();
1274 }
1275
1276 void TargetImpl::load( bool force )
1277 {
1278 bool newCache = buildCache();
1279 MIL << "New cache built: " << (newCache?"true":"false") <<
1280 ", force loading: " << (force?"true":"false") << endl;
1281
1282 // now add the repos to the pool
1283 sat::Pool satpool( sat::Pool::instance() );
1284 Pathname rpmsolv( solvfilesPath() / "solv" );
1285 MIL << "adding " << rpmsolv << " to pool(" << satpool.systemRepoAlias() << ")" << endl;
1286
1287 // Providing an empty system repo, unload any old content
1288 Repository system( sat::Pool::instance().findSystemRepo() );
1289
1290 if ( system && ! system.solvablesEmpty() )
1291 {
1292 if ( newCache || force )
1293 {
1294 system.eraseFromPool(); // invalidates system
1295 }
1296 else
1297 {
1298 return; // nothing to do
1299 }
1300 }
1301
1302 if ( ! system )
1303 {
1304 system = satpool.systemRepo();
1305 }
1306
1307 try
1308 {
1309 MIL << "adding " << rpmsolv << " to system" << endl;
1310 system.addSolv( rpmsolv );
1311 }
1312 catch ( const Exception & exp )
1313 {
1314 ZYPP_CAUGHT( exp );
1315 MIL << "Try to handle exception by rebuilding the solv-file" << endl;
1316 clearCache();
1317 buildCache();
1318
1319 system.addSolv( rpmsolv );
1320 }
1321 satpool.rootDir( _root );
1322
1323 // (Re)Load the requested locales et al.
1324 // If the requested locales are empty, we leave the pool untouched
1325 // to avoid undoing changes the application applied. We expect this
1326 // to happen on a bare metal installation only. An already existing
1327 // target should be loaded before its settings are changed.
1328 {
1329 const LocaleSet & requestedLocales( _requestedLocalesFile.locales() );
1330 if ( ! requestedLocales.empty() )
1331 {
1332 satpool.initRequestedLocales( requestedLocales );
1333 }
1334 }
1335 {
1336 if ( ! PathInfo( _autoInstalledFile.file() ).isExist() )
1337 {
1338 // Initialize from history, if it does not exist
1339 Pathname historyFile( Pathname::assertprefix( _root, ZConfig::instance().historyLogFile() ) );
1340 if ( PathInfo( historyFile ).isExist() )
1341 {
1342 SolvIdentFile::Data onSystemByUser( getUserInstalledFromHistory( historyFile ) );
1343 SolvIdentFile::Data onSystemByAuto;
1344 for_( it, system.solvablesBegin(), system.solvablesEnd() )
1345 {
1346 IdString ident( (*it).ident() );
1347 if ( onSystemByUser.find( ident ) == onSystemByUser.end() )
1348 onSystemByAuto.insert( ident );
1349 }
1350 _autoInstalledFile.setData( onSystemByAuto );
1351 }
1352 // on the fly removed any obsolete SoftLocks file
1353 filesystem::unlink( home() / "SoftLocks" );
1354 }
1355 // read from AutoInstalled file
1356 sat::StringQueue q;
1357 for ( const auto & idstr : _autoInstalledFile.data() )
1358 q.push( idstr.id() );
1359 satpool.setAutoInstalled( q );
1360 }
1361
1362 // Load the needreboot package specs
1363 {
1364 sat::SolvableSpec needrebootSpec;
1365 needrebootSpec.addProvides( Capability("installhint(reboot-needed)") );
1366 needrebootSpec.addProvides( Capability("kernel") );
1367
1368 Pathname needrebootFile { Pathname::assertprefix( root(), ZConfig::instance().needrebootFile() ) };
1369 if ( PathInfo( needrebootFile ).isFile() )
1370 needrebootSpec.parseFrom( needrebootFile );
1371
1372 Pathname needrebootDir { Pathname::assertprefix( root(), ZConfig::instance().needrebootPath() ) };
1373 if ( PathInfo( needrebootDir ).isDir() )
1374 {
1375 static const StrMatcher isRpmConfigBackup( "\\.rpm(new|save|orig)$", Match::REGEX );
1376
1377 filesystem::dirForEach( needrebootDir, filesystem::matchNoDots(),
1378 [&]( const Pathname & dir_r, const char *const str_r )->bool
1379 {
1380 if ( ! isRpmConfigBackup( str_r ) )
1381 {
1382 Pathname needrebootFile { needrebootDir / str_r };
1383 if ( PathInfo( needrebootFile ).isFile() )
1384 needrebootSpec.parseFrom( needrebootFile );
1385 }
1386 return true;
1387 });
1388 }
1389 satpool.setNeedrebootSpec( std::move(needrebootSpec) );
1390 }
1391
1392 if ( ZConfig::instance().apply_locks_file() )
1393 {
1394 const HardLocksFile::Data & hardLocks( _hardLocksFile.data() );
1395 if ( ! hardLocks.empty() )
1396 {
1397 ResPool::instance().setHardLockQueries( hardLocks );
1398 }
1399 }
1400
1401 // now that the target is loaded, we can cache the flavor
1402 createLastDistributionFlavorCache();
1403
1404 MIL << "Target loaded: " << system.solvablesSize() << " resolvables" << endl;
1405 }
1406
1408 //
1409 // COMMIT
1410 //
1412 ZYppCommitResult TargetImpl::commit( ResPool pool_r, const ZYppCommitPolicy & policy_rX )
1413 {
1414 // ----------------------------------------------------------------- //
1415 ZYppCommitPolicy policy_r( policy_rX );
1416 bool explicitDryRun = policy_r.dryRun(); // explicit dry run will trigger a fileconflict check, implicit (download-only) not.
1417
1418 ShutdownLockCommit lck("zypp");
1419
1420 // Fake outstanding YCP fix: Honour restriction to media 1
1421 // at installation, but install all remaining packages if post-boot.
1422 if ( policy_r.restrictToMedia() > 1 )
1423 policy_r.allMedia();
1424
1425 if ( policy_r.downloadMode() == DownloadDefault ) {
1426 if ( root() == "/" )
1427 policy_r.downloadMode(DownloadInHeaps);
1428 else {
1429 if ( policy_r.singleTransModeEnabled() )
1430 policy_r.downloadMode(DownloadInAdvance);
1431 else
1432 policy_r.downloadMode(DownloadAsNeeded);
1433 }
1434 }
1435 // DownloadOnly implies dry-run.
1436 else if ( policy_r.downloadMode() == DownloadOnly )
1437 policy_r.dryRun( true );
1438 // ----------------------------------------------------------------- //
1439
1440 MIL << "TargetImpl::commit(<pool>, " << policy_r << ")" << endl;
1441
1443 // Compute transaction:
1445 ZYppCommitResult result( root() );
1446 result.rTransaction() = pool_r.resolver().getTransaction();
1447 result.rTransaction().order();
1448 // steps: this is our todo-list
1449 ZYppCommitResult::TransactionStepList & steps( result.rTransactionStepList() );
1450 if ( policy_r.restrictToMedia() )
1451 {
1452 // Collect until the 1st package from an unwanted media occurs.
1453 // Further collection could violate install order.
1454 MIL << "Restrict to media number " << policy_r.restrictToMedia() << endl;
1455 for_( it, result.transaction().begin(), result.transaction().end() )
1456 {
1457 if ( makeResObject( *it )->mediaNr() > 1 )
1458 break;
1459 steps.push_back( *it );
1460 }
1461 }
1462 else
1463 {
1464 result.rTransactionStepList().insert( steps.end(), result.transaction().begin(), result.transaction().end() );
1465 }
1466
1467 MIL << "Todo: " << result << endl;
1468
1470 // Write out a testcase if we're in dist upgrade mode.
1472 if ( pool_r.resolver().upgradeMode() || pool_r.resolver().upgradingRepos() )
1473 {
1474 if ( ! policy_r.dryRun() )
1475 {
1476 writeUpgradeTestcase();
1477 }
1478 else
1479 {
1480 DBG << "dryRun: Not writing upgrade testcase." << endl;
1481 }
1482 }
1483
1485 // First collect and display all messages
1486 // associated with patches to be installed.
1488 if ( ! policy_r.dryRun() )
1489 {
1490 for_( it, steps.begin(), steps.end() )
1491 {
1492 if ( ! it->satSolvable().isKind<Patch>() )
1493 continue;
1494
1495 PoolItem pi( *it );
1496 if ( ! pi.status().isToBeInstalled() )
1497 continue;
1498
1499 Patch::constPtr patch( asKind<Patch>(pi.resolvable()) );
1500 if ( ! patch ||patch->message().empty() )
1501 continue;
1502
1503 MIL << "Show message for " << patch << endl;
1504 callback::SendReport<target::PatchMessageReport> report;
1505 if ( ! report->show( patch ) )
1506 {
1507 WAR << "commit aborted by the user" << endl;
1508 ZYPP_THROW( TargetAbortedException( ) );
1509 }
1510 }
1511 }
1512 else
1513 {
1514 DBG << "dryRun: Not checking patch messages." << endl;
1515 }
1516
1518 // Remove/install packages.
1520
1521 DBG << "commit log file is set to: " << HistoryLog::fname() << endl;
1522 if ( ! policy_r.dryRun() || policy_r.downloadMode() == DownloadOnly )
1523 {
1524 // Prepare the package cache. Pass all items requiring download.
1525 CommitPackageCache packageCache;
1526 packageCache.setCommitList( steps.begin(), steps.end() );
1527
1528 bool miss = false;
1529 std::unique_ptr<CommitPackagePreloader> preloader;
1530 if ( policy_r.downloadMode() != DownloadAsNeeded )
1531 {
1532 {
1533 // concurrently preload the download cache as a workaround until we have
1534 // migration to full async workflows ready
1535 preloader = std::make_unique<CommitPackagePreloader>();
1536 preloader->preloadTransaction( steps );
1537 miss = preloader->missed ();
1538 }
1539
1540 if ( !miss ) {
1541 // Preload the cache. Until now this means pre-loading all packages.
1542 // Once DownloadInHeaps is fully implemented, this will change and
1543 // we may actually have more than one heap.
1544 for_( it, steps.begin(), steps.end() )
1545 {
1546 switch ( it->stepType() )
1547 {
1548 case sat::Transaction::TRANSACTION_INSTALL:
1549 case sat::Transaction::TRANSACTION_MULTIINSTALL:
1550 // proceed: only install actionas may require download.
1551 break;
1552
1553 default:
1554 // next: no download for or non-packages and delete actions.
1555 continue;
1556 break;
1557 }
1558
1559 PoolItem pi( *it );
1560 if ( pi->isKind<Package>() || pi->isKind<SrcPackage>() )
1561 {
1562 ManagedFile localfile;
1563 try
1564 {
1565 localfile = packageCache.get( pi );
1566 localfile.resetDispose(); // keep the package file in the cache
1567 }
1568 catch ( const AbortRequestException & exp )
1569 {
1570 it->stepStage( sat::Transaction::STEP_ERROR );
1571 miss = true;
1572 WAR << "commit cache preload aborted by the user" << endl;
1573 ZYPP_THROW( TargetAbortedException( ) );
1574 break;
1575 }
1576 catch ( const SkipRequestException & exp )
1577 {
1578 ZYPP_CAUGHT( exp );
1579 it->stepStage( sat::Transaction::STEP_ERROR );
1580 miss = true;
1581 WAR << "Skipping cache preload package " << pi->asKind<Package>() << " in commit" << endl;
1582 continue;
1583 }
1584 catch ( const Exception & exp )
1585 {
1586 // bnc #395704: missing catch causes abort.
1587 // TODO see if packageCache fails to handle errors correctly.
1588 ZYPP_CAUGHT( exp );
1589 it->stepStage( sat::Transaction::STEP_ERROR );
1590 miss = true;
1591 INT << "Unexpected Error: Skipping cache preload package " << pi->asKind<Package>() << " in commit" << endl;
1592 continue;
1593 }
1594 }
1595 }
1596 packageCache.preloaded( true ); // try to avoid duplicate infoInCache CBs in commit
1597 }
1598 }
1599
1600 if ( miss )
1601 {
1602 ERR << "Some packages could not be provided. Aborting commit."<< endl;
1603 }
1604 else
1605 {
1606 // Commit starts
1607 callback::SendReport<target::CommitActiveReport> commitActiveReport;
1608 if ( ! commitActiveReport->start() )
1609 {
1610 WAR << "commit aborted: CommitActiveReport declined" << endl;
1611 ZYPP_THROW( TargetAbortedException( ) );
1612 }
1613
1615 // Prepare execution of commit plugins:
1617 PluginExecutor commitPlugins;
1618
1619 if ( ( root() == "/" || zypp::env::TRANSACTIONAL_UPDATE() ) && ! policy_r.dryRun() )
1620 {
1621 commitPlugins.load( ZConfig::instance().pluginsPath()/"commit" );
1622 }
1623 if ( commitPlugins )
1624 commitPlugins.send( transactionPluginFrame( "COMMITBEGIN", steps ) );
1625
1627 // Store non-package data:
1629 if ( ! policy_r.dryRun() )
1630 {
1631 filesystem::assert_dir( home() );
1632 // requested locales
1633 _requestedLocalesFile.setLocales( pool_r.getRequestedLocales() );
1634 // autoinstalled
1635 {
1636 SolvIdentFile::Data newdata;
1637 for ( sat::Queue::value_type id : result.rTransaction().autoInstalled() )
1638 newdata.insert( IdString(id) );
1639 _autoInstalledFile.setData( newdata );
1640 }
1641 // hard locks
1642 if ( ZConfig::instance().apply_locks_file() )
1643 {
1644 HardLocksFile::Data newdata;
1645 pool_r.getHardLockQueries( newdata );
1646 _hardLocksFile.setData( newdata );
1647 }
1648 }
1649 else
1650 {
1651 DBG << "dryRun: Not storing non-package data." << endl;
1652 }
1653
1654 if ( ! policy_r.dryRun() )
1655 {
1656 if ( policy_r.singleTransModeEnabled() ) {
1657 commitInSingleTransaction( policy_r, packageCache, result );
1658 } else {
1659 // if cache is preloaded, check for file conflicts
1660 commitFindFileConflicts( policy_r, result );
1661 commit( policy_r, packageCache, result );
1662 }
1663
1664 if ( preloader )
1665 preloader->cleanupCaches ();
1666 }
1667 else
1668 {
1669 DBG << "dryRun/downloadOnly: Not installing/deleting anything." << endl;
1670 if ( explicitDryRun ) {
1671 if ( policy_r.singleTransModeEnabled() ) {
1672 // single trans mode does a test install via rpm
1673 commitInSingleTransaction( policy_r, packageCache, result );
1674 } else {
1675 // if cache is preloaded, check for file conflicts
1676 commitFindFileConflicts( policy_r, result );
1677 }
1678 }
1679 }
1680
1682 // Send result to commit plugins:
1684 if ( commitPlugins )
1685 commitPlugins.send( transactionPluginFrame( "COMMITEND", steps ) );
1686
1688 // Try to rebuild solv file while rpm database is still in cache
1690 if ( ! policy_r.dryRun() )
1691 {
1692 buildCache();
1693 }
1694
1695 commitActiveReport->end();
1696 }
1697 }
1698 else
1699 {
1700 DBG << "dryRun: Not downloading/installing/deleting anything." << endl;
1701 if ( explicitDryRun ) {
1702 // if cache is preloaded, check for file conflicts
1703 commitFindFileConflicts( policy_r, result );
1704 }
1705 }
1706
1707 {
1708 // NOTE: Removing rpm in a transaction, rpm removes the /var/lib/rpm compat symlink.
1709 // We re-create it, in case it was lost to prevent legacy tools from accidentally
1710 // assuming no database is present.
1711 if ( ! PathInfo(_root/"/var/lib/rpm",PathInfo::LSTAT).isExist()
1712 && PathInfo(_root/"/usr/lib/sysimage/rpm").isDir() ) {
1713 WAR << "(rpm removed in commit?) Inject missing /var/lib/rpm compat symlink to /usr/lib/sysimage/rpm" << endl;
1714 filesystem::assert_dir( _root/"/var/lib" );
1715 filesystem::symlink( "../../usr/lib/sysimage/rpm", _root/"/var/lib/rpm" );
1716 }
1717 }
1718
1719 MIL << "TargetImpl::commit(<pool>, " << policy_r << ") returns: " << result << endl;
1720 return result;
1721 }
1722
1724 //
1725 // COMMIT internal
1726 //
1728 namespace
1729 {
1730 struct NotifyAttemptToModify
1731 {
1732 NotifyAttemptToModify( ZYppCommitResult & result_r ) : _result( result_r ) {}
1733
1734 void operator()()
1735 { if ( _guard ) { _result.attemptToModify( true ); _guard = false; } }
1736
1737 TrueBool _guard;
1738 ZYppCommitResult & _result;
1739 };
1740 } // namespace
1741
1742 void TargetImpl::commit( const ZYppCommitPolicy & policy_r,
1743 CommitPackageCache & packageCache_r,
1744 ZYppCommitResult & result_r )
1745 {
1746 env::ScopedSet envguard[] __attribute__ ((__unused__)) {
1747 { "ZYPP_SINGLE_RPMTRANS", nullptr },
1748 { "ZYPP_CLASSIC_RPMTRANS", "1" },
1749 };
1750
1751 // steps: this is our todo-list
1752 ZYppCommitResult::TransactionStepList & steps( result_r.rTransactionStepList() );
1753 MIL << "TargetImpl::commit(<list>" << policy_r << ")" << steps.size() << endl;
1754
1755 HistoryLog().stampCommand();
1756
1757 // Send notification once upon 1st call to rpm
1758 NotifyAttemptToModify attemptToModify( result_r );
1759
1760 bool abort = false;
1761
1762 // bsc#1181328: Some systemd tools require /proc to be mounted
1763 AssertProcMounted assertProcMounted( _root );
1764 AssertDevMounted assertDevMounted( _root ); // also /dev
1765
1766 RpmPostTransCollector postTransCollector( _root );
1767 // bsc#1243279: %posttrans needs to know whether the package was installed or updated.
1768 // we collect the names of obsoleted packages. If %posttrans of an obsoleted package
1769 // was collected, it was an upadte.
1770 IdStringSet obsoletedPackages;
1771 std::vector<sat::Solvable> successfullyInstalledPackages;
1772 TargetImpl::PoolItemList remaining;
1773
1774 for_( step, steps.begin(), steps.end() )
1775 {
1776 PoolItem citem( *step );
1777 if ( step->stepType() == sat::Transaction::TRANSACTION_IGNORE )
1778 {
1779 if ( citem->isKind<Package>() )
1780 {
1781 // for packages this means being obsoleted (by rpm)
1782 // thus no additional action is needed.
1783 obsoletedPackages.insert( citem->ident() );
1784 step->stepStage( sat::Transaction::STEP_DONE );
1785 continue;
1786 }
1787 }
1788
1789 if ( citem->isKind<Package>() )
1790 {
1791 Package::constPtr p = citem->asKind<Package>();
1792 if ( citem.status().isToBeInstalled() )
1793 {
1794 ManagedFile localfile;
1795 try
1796 {
1797 localfile = packageCache_r.get( citem );
1798 }
1799 catch ( const AbortRequestException &e )
1800 {
1801 WAR << "commit aborted by the user" << endl;
1802 abort = true;
1803 step->stepStage( sat::Transaction::STEP_ERROR );
1804 break;
1805 }
1806 catch ( const SkipRequestException &e )
1807 {
1808 ZYPP_CAUGHT( e );
1809 WAR << "Skipping package " << p << " in commit" << endl;
1810 step->stepStage( sat::Transaction::STEP_ERROR );
1811 continue;
1812 }
1813 catch ( const Exception &e )
1814 {
1815 // bnc #395704: missing catch causes abort.
1816 // TODO see if packageCache fails to handle errors correctly.
1817 ZYPP_CAUGHT( e );
1818 INT << "Unexpected Error: Skipping package " << p << " in commit" << endl;
1819 step->stepStage( sat::Transaction::STEP_ERROR );
1820 continue;
1821 }
1822
1823 // create a installation progress report proxy
1824 RpmInstallPackageReceiver progress( citem.resolvable() );
1825 progress.connect(); // disconnected on destruction.
1826
1827 bool success = false;
1828 rpm::RpmInstFlags flags( policy_r.rpmInstFlags() & rpm::RPMINST_JUSTDB );
1829 // Why force and nodeps?
1830 //
1831 // Because zypp builds the transaction and the resolver asserts that
1832 // everything is fine.
1833 // We use rpm just to unpack and register the package in the database.
1834 // We do this step by step, so rpm is not aware of the bigger context.
1835 // So we turn off rpms internal checks, because we do it inside zypp.
1836 flags |= rpm::RPMINST_NODEPS;
1837 flags |= rpm::RPMINST_FORCE;
1838 //
1839 if (p->multiversionInstall()) flags |= rpm::RPMINST_NOUPGRADE;
1840 if (policy_r.dryRun()) flags |= rpm::RPMINST_TEST;
1841 if (policy_r.rpmExcludeDocs()) flags |= rpm::RPMINST_EXCLUDEDOCS;
1842 if (policy_r.rpmNoSignature()) flags |= rpm::RPMINST_NOSIGNATURE;
1843
1844 attemptToModify();
1845 try
1846 {
1847 progress.tryLevel( target::rpm::InstallResolvableReport::RPM_NODEPS_FORCE );
1848 rpm().installPackage( localfile, flags, &postTransCollector );
1849 HistoryLog().install(citem);
1850
1851 if ( progress.aborted() )
1852 {
1853 WAR << "commit aborted by the user" << endl;
1854 localfile.resetDispose(); // keep the package file in the cache
1855 abort = true;
1856 step->stepStage( sat::Transaction::STEP_ERROR );
1857 break;
1858 }
1859 else
1860 {
1861 if ( citem.isNeedreboot() ) {
1862 auto rebootNeededFile = root() / "/run/reboot-needed";
1863 if ( filesystem::assert_file( rebootNeededFile ) == EEXIST)
1864 filesystem::touch( rebootNeededFile );
1865 }
1866
1867 success = true;
1868 step->stepStage( sat::Transaction::STEP_DONE );
1869 }
1870 }
1871 catch ( Exception & excpt_r )
1872 {
1873 ZYPP_CAUGHT(excpt_r);
1874 localfile.resetDispose(); // keep the package file in the cache
1875
1876 if ( policy_r.dryRun() )
1877 {
1878 WAR << "dry run failed" << endl;
1879 step->stepStage( sat::Transaction::STEP_ERROR );
1880 break;
1881 }
1882 // else
1883 if ( progress.aborted() )
1884 {
1885 WAR << "commit aborted by the user" << endl;
1886 abort = true;
1887 }
1888 else
1889 {
1890 WAR << "Install failed" << endl;
1891 }
1892 step->stepStage( sat::Transaction::STEP_ERROR );
1893 break; // stop
1894 }
1895
1896 if ( success && !policy_r.dryRun() )
1897 {
1898 citem.status().resetTransact( ResStatus::USER );
1899 successfullyInstalledPackages.push_back( citem.satSolvable() );
1900 step->stepStage( sat::Transaction::STEP_DONE );
1901 }
1902 }
1903 else
1904 {
1905 RpmRemovePackageReceiver progress( citem.resolvable() );
1906 progress.connect(); // disconnected on destruction.
1907
1908 bool success = false;
1909 rpm::RpmInstFlags flags( policy_r.rpmInstFlags() & rpm::RPMINST_JUSTDB );
1910 flags |= rpm::RPMINST_NODEPS;
1911 if (policy_r.dryRun()) flags |= rpm::RPMINST_TEST;
1912
1913 attemptToModify();
1914 try
1915 {
1916 rpm().removePackage( p, flags, &postTransCollector );
1917 HistoryLog().remove(citem);
1918
1919 if ( progress.aborted() )
1920 {
1921 WAR << "commit aborted by the user" << endl;
1922 abort = true;
1923 step->stepStage( sat::Transaction::STEP_ERROR );
1924 break;
1925 }
1926 else
1927 {
1928 success = true;
1929 step->stepStage( sat::Transaction::STEP_DONE );
1930 }
1931 }
1932 catch (Exception & excpt_r)
1933 {
1934 ZYPP_CAUGHT( excpt_r );
1935 if ( progress.aborted() )
1936 {
1937 WAR << "commit aborted by the user" << endl;
1938 abort = true;
1939 step->stepStage( sat::Transaction::STEP_ERROR );
1940 break;
1941 }
1942 // else
1943 WAR << "removal of " << p << " failed";
1944 step->stepStage( sat::Transaction::STEP_ERROR );
1945 }
1946 if ( success && !policy_r.dryRun() )
1947 {
1948 citem.status().resetTransact( ResStatus::USER );
1949 step->stepStage( sat::Transaction::STEP_DONE );
1950 }
1951 }
1952 }
1953 else if ( ! policy_r.dryRun() ) // other resolvables (non-Package)
1954 {
1955 // Status is changed as the buddy package buddy
1956 // gets installed/deleted. Handle non-buddies only.
1957 if ( ! citem.buddy() )
1958 {
1959 if ( citem->isKind<Product>() )
1960 {
1961 Product::constPtr p = citem->asKind<Product>();
1962 if ( citem.status().isToBeInstalled() )
1963 {
1964 ERR << "Can't install orphan product without release-package! " << citem << endl;
1965 }
1966 else
1967 {
1968 // Deleting the corresponding product entry is all we con do.
1969 // So the product will no longer be visible as installed.
1970 std::string referenceFilename( p->referenceFilename() );
1971 if ( referenceFilename.empty() )
1972 {
1973 ERR << "Can't remove orphan product without 'referenceFilename'! " << citem << endl;
1974 }
1975 else
1976 {
1977 Pathname referencePath { Pathname("/etc/products.d") / referenceFilename }; // no root prefix for rpmdb lookup!
1978 if ( ! rpm().hasFile( referencePath.asString() ) )
1979 {
1980 // If it's not owned by a package, we can delete it.
1981 referencePath = Pathname::assertprefix( _root, referencePath ); // now add a root prefix
1982 if ( filesystem::unlink( referencePath ) != 0 )
1983 ERR << "Delete orphan product failed: " << referencePath << endl;
1984 }
1985 else
1986 {
1987 WAR << "Won't remove orphan product: '/etc/products.d/" << referenceFilename << "' is owned by a package." << endl;
1988 }
1989 }
1990 }
1991 }
1992 else if ( citem->isKind<SrcPackage>() && citem.status().isToBeInstalled() )
1993 {
1994 // SrcPackage is install-only
1995 SrcPackage::constPtr p = citem->asKind<SrcPackage>();
1996 installSrcPackage( p );
1997 }
1998
1999 citem.status().resetTransact( ResStatus::USER );
2000 step->stepStage( sat::Transaction::STEP_DONE );
2001 }
2002
2003 } // other resolvables
2004
2005 } // for
2006
2007 // Process any remembered %posttrans and/or %transfiletrigger(postun|in)
2008 // scripts. If aborting, at least log if scripts were omitted.
2009 if ( not abort )
2010 postTransCollector.executeScripts( rpm(), obsoletedPackages );
2011 else
2012 postTransCollector.discardScripts();
2013
2014 // Check presence of update scripts/messages. If aborting,
2015 // at least log omitted scripts.
2016 if ( ! successfullyInstalledPackages.empty() )
2017 {
2018 if ( ! RunUpdateScripts( _root, ZConfig::instance().update_scriptsPath(),
2019 successfullyInstalledPackages, abort ) )
2020 {
2021 WAR << "Commit aborted by the user" << endl;
2022 abort = true;
2023 }
2024 // send messages after scripts in case some script generates output,
2025 // that should be kept in t %ghost message file.
2026 RunUpdateMessages( _root, ZConfig::instance().update_messagesPath(),
2027 successfullyInstalledPackages,
2028 result_r );
2029 }
2030
2031 // jsc#SLE-5116: Log patch status changes to history
2032 // NOTE: Should be the last action as it may need to reload
2033 // the Target in case of an incomplete transaction.
2034 logPatchStatusChanges( result_r.transaction(), *this );
2035
2036 if ( abort )
2037 {
2038 HistoryLog().comment( "Commit was aborted." );
2039 ZYPP_THROW( TargetAbortedException( ) );
2040 }
2041 }
2042
2043
2050 struct SendSingleTransReport : public callback::SendReport<rpm::SingleTransReport>
2051 {
2053 void sendLogline( const std::string & line_r, ReportType::loglevel level_r = ReportType::loglevel::msg )
2054 {
2055 callback::UserData data { ReportType::contentLogline };
2056 data.set( "line", std::cref(line_r) );
2057 data.set( "level", level_r );
2058 report( data );
2059 }
2060
2061 void sendLoglineRpm( const std::string & line_r, unsigned rpmlevel_r )
2062 {
2063 auto u2rpmlevel = []( unsigned rpmlevel_r ) -> ReportType::loglevel {
2064 switch ( rpmlevel_r ) {
2065 case RPMLOG_EMERG: [[fallthrough]]; // system is unusable
2066 case RPMLOG_ALERT: [[fallthrough]]; // action must be taken immediately
2067 case RPMLOG_CRIT: // critical conditions
2068 return ReportType::loglevel::crt;
2069 case RPMLOG_ERR: // error conditions
2070 return ReportType::loglevel::err;
2071 case RPMLOG_WARNING: // warning conditions
2072 return ReportType::loglevel::war;
2073 default: [[fallthrough]];
2074 case RPMLOG_NOTICE: [[fallthrough]]; // normal but significant condition
2075 case RPMLOG_INFO: // informational
2076 return ReportType::loglevel::msg;
2077 case RPMLOG_DEBUG:
2078 return ReportType::loglevel::dbg;
2079 }
2080 };
2081 sendLogline( line_r, u2rpmlevel( rpmlevel_r ) );
2082 }
2083
2084 private:
2085 void report( const callback::UserData & userData_r )
2086 { (*this)->report( userData_r ); }
2087 };
2088
2089 void TargetImpl::commitInSingleTransaction(const ZYppCommitPolicy &policy_r, CommitPackageCache &packageCache_r, ZYppCommitResult &result_r)
2090 {
2091 env::ScopedSet envguard[] __attribute__ ((__unused__)) {
2092 { "ZYPP_SINGLE_RPMTRANS", "1" },
2093 { "ZYPP_CLASSIC_RPMTRANS", nullptr },
2094 };
2095
2096 SingleTransReportLegacyWrapper _legacyWrapper; // just in case nobody listens on the SendSingleTransReports
2097 SendSingleTransReport report; // active throughout the whole rpm transaction
2098
2099 // steps: this is our todo-list
2100 ZYppCommitResult::TransactionStepList & steps( result_r.rTransactionStepList() );
2101 MIL << "TargetImpl::commit(<list>" << policy_r << ")" << steps.size() << endl;
2102
2103 HistoryLog().stampCommand();
2104
2105 // Send notification once upon calling rpm
2106 NotifyAttemptToModify attemptToModify( result_r );
2107
2108 // let zypper know we executed in one big transaction so in case of failures it can show extended error information
2109 result_r.setSingleTransactionMode( true );
2110
2111 // bsc#1181328: Some systemd tools require /proc to be mounted
2112 AssertProcMounted assertProcMounted( _root );
2113 AssertDevMounted assertDevMounted( _root ); // also /dev
2114
2115 // Why nodeps?
2116 //
2117 // Because zypp builds the transaction and the resolver asserts that
2118 // everything is fine, or the user decided to ignore problems.
2119 rpm::RpmInstFlags flags( policy_r.rpmInstFlags()
2120 | rpm::RPMINST_NODEPS
2121 // skip signature checks, we did that already
2122 | rpm::RPMINST_NODIGEST
2123 | rpm::RPMINST_NOSIGNATURE
2124 // ignore untrusted keys since we already checked those earlier
2125 | rpm::RPMINST_ALLOWUNTRUSTED );
2126
2127 proto::target::Commit commit;
2128 commit.flags = flags;
2129 commit.ignoreArch = ( !ZConfig::instance().systemArchitecture().compatibleWith( ZConfig::instance().defaultSystemArchitecture() ) );
2130 commit.arch = ZConfig::instance().systemArchitecture().asString();
2131 commit.dbPath = rpm().dbPath().asString();
2132 commit.root = rpm().root().asString();
2133 commit.lockFilePath = ZYppFactory::lockfileDir().asString();
2134
2135 bool abort = false;
2136 zypp::AutoDispose<std::unordered_map<int, ManagedFile>> locCache([]( std::unordered_map<int, ManagedFile> &data ){
2137 for ( auto &[_, value] : data ) {
2138 (void)_; // unsused; for older g++ versions
2139 value.resetDispose();
2140 }
2141 data.clear();
2142 });
2143
2144 // fill the transaction
2145 for ( int stepId = 0; (ZYppCommitResult::TransactionStepList::size_type)stepId < steps.size() && !abort ; ++stepId ) {
2146 auto &step = steps[stepId];
2147 PoolItem citem( step );
2148 if ( step.stepType() == sat::Transaction::TRANSACTION_IGNORE ) {
2149 if ( citem->isKind<Package>() )
2150 {
2151 // for packages this means being obsoleted (by rpm)
2152 // thius no additional action is needed.
2153 step.stepStage( sat::Transaction::STEP_DONE );
2154 continue;
2155 }
2156 }
2157
2158 if ( citem->isKind<Package>() ) {
2159 Package::constPtr p = citem->asKind<Package>();
2160 if ( citem.status().isToBeInstalled() )
2161 {
2162 try {
2163 locCache.value()[stepId] = packageCache_r.get( citem );
2164
2165 proto::target::InstallStep tStep;
2166 tStep.stepId = stepId;
2167 tStep.pathname = locCache.value()[stepId]->asString();
2168 tStep.multiversion = p->multiversionInstall() ;
2169
2170 commit.transactionSteps.push_back( std::move(tStep) );
2171 }
2172 catch ( const AbortRequestException &e )
2173 {
2174 WAR << "commit aborted by the user" << endl;
2175 abort = true;
2176 step.stepStage( sat::Transaction::STEP_ERROR );
2177 break;
2178 }
2179 catch ( const SkipRequestException &e )
2180 {
2181 ZYPP_CAUGHT( e );
2182 WAR << "Skipping package " << p << " in commit" << endl;
2183 step.stepStage( sat::Transaction::STEP_ERROR );
2184 continue;
2185 }
2186 catch ( const Exception &e )
2187 {
2188 // bnc #395704: missing catch causes abort.
2189 // TODO see if packageCache fails to handle errors correctly.
2190 ZYPP_CAUGHT( e );
2191 INT << "Unexpected Error: Skipping package " << p << " in commit" << endl;
2192 step.stepStage( sat::Transaction::STEP_ERROR );
2193 continue;
2194 }
2195 } else {
2196
2197 proto::target::RemoveStep tStep;
2198 tStep.stepId = stepId;
2199 tStep.name = p->name();
2200 tStep.version = p->edition().version();
2201 tStep.release = p->edition().release();
2202 tStep.arch = p->arch().asString();
2203 commit.transactionSteps.push_back(std::move(tStep));
2204
2205 }
2206 } else if ( citem->isKind<SrcPackage>() && citem.status().isToBeInstalled() ) {
2207 // SrcPackage is install-only
2208 SrcPackage::constPtr p = citem->asKind<SrcPackage>();
2209
2210 try {
2211 // provide on local disk
2212 locCache.value()[stepId] = provideSrcPackage( p );
2213
2214 proto::target::InstallStep tStep;
2215 tStep.stepId = stepId;
2216 tStep.pathname = locCache.value()[stepId]->asString();
2217 tStep.multiversion = false;
2218 commit.transactionSteps.push_back(std::move(tStep));
2219
2220 } catch ( const Exception &e ) {
2221 ZYPP_CAUGHT( e );
2222 INT << "Unexpected Error: Skipping package " << p << " in commit" << endl;
2223 step.stepStage( sat::Transaction::STEP_ERROR );
2224 continue;
2225 }
2226 }
2227 }
2228
2229 std::vector<sat::Solvable> successfullyInstalledPackages;
2230
2231 if ( commit.transactionSteps.size() ) {
2232
2233 // create the event loop early
2234 auto loop = zyppng::EventLoop::create();
2235
2236 attemptToModify();
2237
2238 const std::vector<int> interceptedSignals {
2239 SIGINT,
2240 SIGTERM,
2241 SIGHUP,
2242 SIGQUIT
2243 };
2244
2245 auto unixSignals = loop->eventDispatcher()->unixSignalSource();
2246 unixSignals->sigReceived ().connect ([]( int signum ){
2247 // translator: %1% is the received unix signal name, %2% is the numerical value of the received signal
2248 JobReport::error ( str::Format(_("Received signal :\"%1% (%2%)\", to ensure the consistency of the system it is not possible to cancel a running rpm transaction.") ) % strsignal(signum) % signum );
2249 });
2250 for( const auto &sig : interceptedSignals )
2251 unixSignals->addSignal ( sig );
2252
2253 Deferred cleanupSigs([&](){
2254 for( const auto &sig : interceptedSignals )
2255 unixSignals->removeSignal ( sig );
2256 });
2257
2258 // transaction related variables:
2259 //
2260 // the index of the step in the transaction list that we currenty execute.
2261 // this can be -1
2262 int currentStepId = -1;
2263
2264 // sync flag, every time zypp-rpm finishes executing a step it writes a tag into
2265 // the script fd, once we receive it we set this flag to true and ignore all output
2266 // that is written to the pipe ( aside from buffering it ) until we finalize the current report
2267 // and start a new one
2268 bool gotEndOfScript = false;
2269
2270 // the possible reports we emit during the transaction
2271 std::unique_ptr<callback::SendReport <rpm::TransactionReportSA>> transactionreport;
2272 std::unique_ptr<callback::SendReport <rpm::InstallResolvableReportSA>> installreport;
2273 std::unique_ptr<callback::SendReport <rpm::RemoveResolvableReportSA>> uninstallreport;
2274 std::unique_ptr<callback::SendReport <rpm::CommitScriptReportSA>> scriptreport;
2275 std::unique_ptr<callback::SendReport <rpm::CleanupPackageReportSA>> cleanupreport;
2276
2277 // this will be set if we receive a transaction error description
2278 std::optional<proto::target::TransactionError> transactionError;
2279
2280 // infos about the currently executed script, empty if no script is currently executed
2281 std::string currentScriptType;
2282 std::string currentScriptPackage;
2283
2284 // buffer to collect rpm output per report, this will be written to the log once the
2285 // report ends
2286 std::string rpmmsg;
2287
2288 // maximum number of lines that we are buffering in rpmmsg
2289 constexpr auto MAXRPMMESSAGELINES = 10000;
2290
2291 // current number of lines in the rpmmsg line buffer. This is capped to MAXRPMMESSAGELINES
2292 unsigned lineno = 0;
2293
2294 // the sources to communicate with zypp-rpm, we will associate pipes with them further down below
2295 auto msgSource = zyppng::AsyncDataSource::create();
2296 auto scriptSource = zyppng::AsyncDataSource::create();
2297
2298 // this will be the communication channel, will be created once the process starts and
2299 // we can receive data
2300 zyppng::StompFrameStreamRef msgStream;
2301
2302
2303 // helper function that sends RPM output to the currently active report, writing a warning to the log
2304 // if there is none
2305 const auto &sendRpmLineToReport = [&]( const std::string &line ){
2306
2307 const auto &sendLogRep = [&]( auto &report, const auto &cType ){
2308 callback::UserData cmdout(cType);
2309 if ( currentStepId >= 0 )
2310 cmdout.set( "solvable", steps.at(currentStepId).satSolvable() );
2311 cmdout.set( "line", line );
2312 report->report(cmdout);
2313 };
2314
2315 if ( installreport ) {
2316 sendLogRep( (*installreport), rpm::InstallResolvableReportSA::contentRpmout );
2317 } else if ( uninstallreport ) {
2318 sendLogRep( (*uninstallreport), rpm::RemoveResolvableReportSA::contentRpmout );
2319 } else if ( scriptreport ) {
2320 sendLogRep( (*scriptreport), rpm::CommitScriptReportSA::contentRpmout );
2321 } else if ( transactionreport ) {
2322 sendLogRep( (*transactionreport), rpm::TransactionReportSA::contentRpmout );
2323 } else if ( cleanupreport ) {
2324 sendLogRep( (*cleanupreport), rpm::CleanupPackageReportSA::contentRpmout );
2325 } else {
2326 WAR << "Got rpm output without active report " << line; // no endl! - readLine does not trim
2327 }
2328
2329 // remember rpm output
2330 if ( lineno >= MAXRPMMESSAGELINES ) {
2331 if ( line.find( " scriptlet failed, " ) == std::string::npos ) // always log %script errors
2332 return;
2333 }
2334 rpmmsg += line;
2335 if ( line.back() != '\n' )
2336 rpmmsg += '\n';
2337 };
2338
2339
2340 // callback and helper function to process data that is received on the script FD
2341 const auto &processDataFromScriptFd = [&](){
2342
2343 while ( scriptSource->canReadLine() ) {
2344
2345 if ( gotEndOfScript )
2346 return;
2347
2348 std::string l = scriptSource->readLine().asString();
2349 if( str::endsWith( l, endOfScriptTag ) ) {
2350 gotEndOfScript = true;
2351 std::string::size_type rawsize { l.size() - endOfScriptTag.size() };
2352 if ( not rawsize )
2353 return;
2354 l = l.substr( 0, rawsize );
2355 }
2356 L_DBG("zypp-rpm") << "[rpm> " << l; // no endl! - readLine does not trim
2357 sendRpmLineToReport( l );
2358 }
2359 };
2360 scriptSource->sigReadyRead().connect( processDataFromScriptFd );
2361
2362 // helper function that just waits until the end of script tag was received on the scriptSource
2363 const auto &waitForScriptEnd = [&]() {
2364
2365 // nothing to wait for
2366 if ( gotEndOfScript )
2367 return;
2368
2369 // we process all available data
2370 processDataFromScriptFd();
2371
2372 // end of script is always sent by zypp-rpm, we need to wait for it to keep order
2373 while ( scriptSource->readFdOpen() && scriptSource->canRead() && !gotEndOfScript ) {
2374 // readyRead will trigger processDataFromScriptFd so no need to call it again
2375 // we still got nothing, lets wait for more
2376 scriptSource->waitForReadyRead( 100 );
2377 }
2378 };
2379
2380 const auto &aboutToStartNewReport = [&](){
2381
2382 if ( transactionreport || installreport || uninstallreport || scriptreport || cleanupreport ) {
2383 ERR << "There is still a running report, this is a bug" << std::endl;
2384 assert(false);
2385 }
2386
2387 gotEndOfScript = false;
2388 };
2389
2390 const auto &writeRpmMsgToHistory = [&](){
2391 if ( rpmmsg.size() == 0 )
2392 return;
2393
2394 if ( lineno >= MAXRPMMESSAGELINES )
2395 rpmmsg += "[truncated]\n";
2396
2397 std::ostringstream sstr;
2398 sstr << "rpm output:" << endl << rpmmsg << endl;
2399 HistoryLog().comment(sstr.str());
2400 };
2401
2402 // helper function that closes the current report and cleans up the ressources
2403 const auto &finalizeCurrentReport = [&]() {
2404 sat::Transaction::Step *step = nullptr;
2405 Resolvable::constPtr resObj;
2406 if ( currentStepId >= 0 ) {
2407 step = &steps.at(currentStepId);
2408 resObj = makeResObject( step->satSolvable() );
2409 }
2410
2411 if ( installreport ) {
2412 waitForScriptEnd();
2413 if ( step->stepStage() == sat::Transaction::STEP_ERROR ) {
2414
2415 HistoryLog().comment(
2416 str::form("%s install failed", step->ident().c_str()),
2417 true /*timestamp*/);
2418
2419 writeRpmMsgToHistory();
2420
2421 ( *installreport)->finish( resObj, rpm::InstallResolvableReportSA::INVALID );
2422 } else {
2423 ( *installreport)->progress( 100, resObj );
2424 ( *installreport)->finish( resObj, rpm::InstallResolvableReportSA::NO_ERROR );
2425
2426 if ( currentStepId >= 0 )
2427 locCache.value().erase( currentStepId );
2428 successfullyInstalledPackages.push_back( step->satSolvable() );
2429
2430 PoolItem citem( *step );
2431 if ( !( flags & rpm::RPMINST_TEST ) ) {
2432 // @TODO are we really doing this just for install?
2433 if ( citem.isNeedreboot() ) {
2434 auto rebootNeededFile = root() / "/run/reboot-needed";
2435 if ( filesystem::assert_file( rebootNeededFile ) == EEXIST)
2436 filesystem::touch( rebootNeededFile );
2437 }
2438 citem.status().resetTransact( ResStatus::USER );
2439 HistoryLog().install(citem);
2440 }
2441
2442 HistoryLog().comment(
2443 str::form("%s installed ok", step->ident().c_str()),
2444 true /*timestamp*/);
2445
2446 writeRpmMsgToHistory();
2447 }
2448 }
2449 if ( uninstallreport ) {
2450 waitForScriptEnd();
2451 if ( step->stepStage() == sat::Transaction::STEP_ERROR ) {
2452
2453 HistoryLog().comment(
2454 str::form("%s uninstall failed", step->ident().c_str()),
2455 true /*timestamp*/);
2456
2457 writeRpmMsgToHistory();
2458
2459 ( *uninstallreport)->finish( resObj, rpm::RemoveResolvableReportSA::INVALID );
2460 } else {
2461 ( *uninstallreport)->progress( 100, resObj );
2462 ( *uninstallreport)->finish( resObj, rpm::RemoveResolvableReportSA::NO_ERROR );
2463
2464 PoolItem citem( *step );
2465 HistoryLog().remove(citem);
2466
2467 HistoryLog().comment(
2468 str::form("%s removed ok", step->ident().c_str()),
2469 true /*timestamp*/);
2470
2471 writeRpmMsgToHistory();
2472 }
2473 }
2474 if ( scriptreport ) {
2475 waitForScriptEnd();
2476 ( *scriptreport)->progress( 100, resObj );
2477 ( *scriptreport)->finish( resObj, rpm::CommitScriptReportSA::NO_ERROR );
2478 }
2479 if ( transactionreport ) {
2480 waitForScriptEnd();
2481 ( *transactionreport)->progress( 100 );
2482 ( *transactionreport)->finish( rpm::TransactionReportSA::NO_ERROR );
2483 }
2484 if ( cleanupreport ) {
2485 waitForScriptEnd();
2486 ( *cleanupreport)->progress( 100 );
2487 ( *cleanupreport)->finish( rpm::CleanupPackageReportSA::NO_ERROR );
2488 }
2489 currentStepId = -1;
2490 lineno = 0;
2491 rpmmsg.clear();
2492 currentScriptType.clear();
2493 currentScriptPackage.clear();
2494 installreport.reset();
2495 uninstallreport.reset();
2496 scriptreport.reset();
2497 transactionreport.reset();
2498 cleanupreport.reset();
2499 };
2500
2501 // This sets up the process and pushes the required transactions steps to it
2502 // careful when changing code here, zypp-rpm relies on the exact order data is transferred:
2503 //
2504 // 1) Size of the commit message , sizeof(zyppng::rpc::HeaderSizeType)
2505 // 2) The Commit Proto message, directly serialized to the FD, without Envelope
2506 // 3) 2 writeable FDs that are set up by the parent Process when forking. The first FD is to be used for message sending, the second one for script output
2507
2508 constexpr std::string_view zyppRpmBinary(ZYPP_RPM_BINARY);
2509
2510 const char *argv[] = {
2511 //"gdbserver",
2512 //"localhost:10001",
2513 zyppRpmBinary.data(),
2514 nullptr
2515 };
2516 auto prog = zyppng::Process::create();
2517
2518 // we set up a pipe to communicate with the process, it is too dangerous to use stdout since librpm
2519 // might print to it.
2520 auto messagePipe = zyppng::Pipe::create();
2521 if ( !messagePipe )
2522 ZYPP_THROW( target::rpm::RpmSubprocessException( "Failed to create message pipe" ) );
2523
2524 // open a pipe that we are going to use to receive script output, this is a librpm feature, there is no other
2525 // way than a FD to redirect that output
2526 auto scriptPipe = zyppng::Pipe::create();
2527 if ( !scriptPipe )
2528 ZYPP_THROW( target::rpm::RpmSubprocessException( "Failed to create scriptfd" ) );
2529
2530 prog->addFd( messagePipe->writeFd );
2531 prog->addFd( scriptPipe->writeFd );
2532
2533 // set up the AsyncDataSource to read script output
2534 if ( !scriptSource->openFds( std::vector<int>{ scriptPipe->readFd } ) )
2535 ZYPP_THROW( target::rpm::RpmSubprocessException( "Failed to open scriptFD to subprocess" ) );
2536
2537 const auto &processMessages = [&] ( ) {
2538
2539 // lambda function that parses the passed message type and checks if the stepId is a valid offset
2540 // in the steps list.
2541 const auto &checkMsgWithStepId = [&steps]( auto &p ){
2542 if ( !p ) {
2543 ERR << "Failed to parse message from zypp-rpm." << std::endl;
2544 return false;
2545 }
2546
2547 auto id = p->stepId;
2548 if ( id < 0 || id >= steps.size() ) {
2549 ERR << "Received invalid stepId: " << id << " in " << p->typeName << " message from zypp-rpm, ignoring." << std::endl;
2550 return false;
2551 }
2552 return true;
2553 };
2554
2555 while ( const auto &m = msgStream->nextMessage() ) {
2556
2557 // due to librpm behaviour we need to make sense of the order of messages we receive
2558 // because we first get a PackageFinished BEFORE getting a PackageError, same applies to
2559 // Script related messages. What we do is remember the current step we are in and only close
2560 // the step when we get the start of the next one
2561 const auto &mName = m->command();
2562 if ( mName == proto::target::RpmLog::typeName ) {
2563
2564 const auto &p = proto::target::RpmLog::fromStompMessage (*m);
2565 if ( !p ) {
2566 ERR << "Failed to parse " << proto::target::RpmLog::typeName << " message from zypp-rpm." << std::endl;
2567 continue;
2568 }
2569 ( p->level >= RPMLOG_ERR ? L_ERR("zypp-rpm")
2570 : p->level >= RPMLOG_WARNING ? L_WAR("zypp-rpm")
2571 : L_DBG("zypp-rpm") ) << "[rpm " << p->level << "> " << p->line; // no endl! - readLine does not trim
2572 report.sendLoglineRpm( p->line, p->level );
2573
2574 } else if ( mName == proto::target::PackageBegin::typeName ) {
2575 finalizeCurrentReport();
2576
2577 const auto &p = proto::target::PackageBegin::fromStompMessage(*m);
2578 if ( !checkMsgWithStepId( p ) )
2579 continue;
2580
2581 aboutToStartNewReport();
2582
2583 auto & step = steps.at( p->stepId );
2584 currentStepId = p->stepId;
2585 if ( step.stepType() == sat::Transaction::TRANSACTION_ERASE ) {
2586 uninstallreport = std::make_unique< callback::SendReport <rpm::RemoveResolvableReportSA> > ();
2587 ( *uninstallreport )->start( makeResObject( step.satSolvable() ) );
2588 } else {
2589 installreport = std::make_unique< callback::SendReport <rpm::InstallResolvableReportSA> > ();
2590 ( *installreport )->start( makeResObject( step.satSolvable() ) );
2591 }
2592
2593 } else if ( mName == proto::target::PackageFinished::typeName ) {
2594 const auto &p = proto::target::PackageFinished::fromStompMessage(*m);
2595 if ( !checkMsgWithStepId( p ) )
2596 continue;
2597
2598 // here we only set the step stage to done, we however need to wait for the next start in order to send
2599 // the finished report since there might be a error pending to be reported
2600 steps[ p->stepId ].stepStage( sat::Transaction::STEP_DONE );
2601
2602 } else if ( mName == proto::target::PackageProgress::typeName ) {
2603 const auto &p = proto::target::PackageProgress::fromStompMessage(*m);
2604 if ( !checkMsgWithStepId( p ) )
2605 continue;
2606
2607 if ( uninstallreport )
2608 (*uninstallreport)->progress( p->amount, makeResObject( steps.at( p->stepId ) ));
2609 else if ( installreport )
2610 (*installreport)->progress( p->amount, makeResObject( steps.at( p->stepId ) ));
2611 else
2612 ERR << "Received a " << mName << " message but there is no corresponding report running." << std::endl;
2613
2614 } else if ( mName == proto::target::PackageError::typeName ) {
2615 const auto &p = proto::target::PackageError::fromStompMessage(*m);
2616 if ( !checkMsgWithStepId( p ) )
2617 continue;
2618
2619 if ( p->stepId >= 0 && p->stepId < steps.size() )
2620 steps[ p->stepId ].stepStage( sat::Transaction::STEP_ERROR );
2621
2622 finalizeCurrentReport();
2623
2624 } else if ( mName == proto::target::ScriptBegin::typeName ) {
2625 finalizeCurrentReport();
2626
2627 const auto &p = proto::target::ScriptBegin::fromStompMessage(*m);
2628 if ( !p ) {
2629 ERR << "Failed to parse " << proto::target::ScriptBegin::typeName << " message from zypp-rpm." << std::endl;
2630 continue;
2631 }
2632
2633 aboutToStartNewReport();
2634
2635 Resolvable::constPtr resPtr;
2636 const auto stepId = p->stepId;
2637 if ( stepId >= 0 && static_cast<size_t>(stepId) < steps.size() ) {
2638 resPtr = makeResObject( steps.at(stepId).satSolvable() );
2639 }
2640
2641 currentStepId = p->stepId;
2642 scriptreport = std::make_unique< callback::SendReport <rpm::CommitScriptReportSA> > ();
2643 currentScriptType = p->scriptType;
2644 currentScriptPackage = p->scriptPackage;
2645 (*scriptreport)->start( currentScriptType, currentScriptPackage, resPtr );
2646
2647 } else if ( mName == proto::target::ScriptFinished::typeName ) {
2648
2649 // we just read the message, we do not act on it because a ScriptError is reported after ScriptFinished
2650
2651 } else if ( mName == proto::target::ScriptError::typeName ) {
2652
2653 const auto &p = proto::target::ScriptError::fromStompMessage(*m);
2654 if ( !p ) {
2655 ERR << "Failed to parse " << proto::target::ScriptError::typeName << " message from zypp-rpm." << std::endl;
2656 continue;
2657 }
2658
2659 Resolvable::constPtr resPtr;
2660 const auto stepId = p->stepId;
2661 if ( stepId >= 0 && static_cast<size_t>(stepId) < steps.size() ) {
2662 resPtr = makeResObject( steps.at(stepId).satSolvable() );
2663
2664 if ( p->fatal ) {
2665 steps.at( stepId ).stepStage( sat::Transaction::STEP_ERROR );
2666 }
2667
2668 }
2669
2670 HistoryLog().comment(
2671 str::form("Failed to execute %s script for %s ", currentScriptType.c_str(), currentScriptPackage.size() ? currentScriptPackage.c_str() : "unknown" ),
2672 true /*timestamp*/);
2673
2674 writeRpmMsgToHistory();
2675
2676 if ( !scriptreport ) {
2677 ERR << "Received a ScriptError message, but there is no running report. " << std::endl;
2678 continue;
2679 }
2680
2681 // before killing the report we need to wait for the script end tag
2682 waitForScriptEnd();
2683 (*scriptreport)->finish( resPtr, p->fatal ? rpm::CommitScriptReportSA::CRITICAL : rpm::CommitScriptReportSA::WARN );
2684
2685 // manually reset the current report since we already sent the finish(), rest will be reset by the new start
2686 scriptreport.reset();
2687 currentStepId = -1;
2688
2689 } else if ( mName == proto::target::CleanupBegin::typeName ) {
2690 finalizeCurrentReport();
2691
2692 const auto &beg = proto::target::CleanupBegin::fromStompMessage(*m);
2693 if ( !beg ) {
2694 ERR << "Failed to parse " << proto::target::CleanupBegin::typeName << " message from zypp-rpm." << std::endl;
2695 continue;
2696 }
2697
2698 aboutToStartNewReport();
2699 cleanupreport = std::make_unique< callback::SendReport <rpm::CleanupPackageReportSA> > ();
2700 (*cleanupreport)->start( beg->nvra );
2701 } else if ( mName == proto::target::CleanupFinished::typeName ) {
2702
2703 finalizeCurrentReport();
2704
2705 } else if ( mName == proto::target::CleanupProgress::typeName ) {
2706 const auto &prog = proto::target::CleanupProgress::fromStompMessage(*m);
2707 if ( !prog ) {
2708 ERR << "Failed to parse " << proto::target::CleanupProgress::typeName << " message from zypp-rpm." << std::endl;
2709 continue;
2710 }
2711
2712 if ( !cleanupreport ) {
2713 ERR << "Received a CleanupProgress message, but there is no running report. " << std::endl;
2714 continue;
2715 }
2716
2717 (*cleanupreport)->progress( prog->amount );
2718
2719 } else if ( mName == proto::target::TransBegin::typeName ) {
2720 finalizeCurrentReport();
2721
2722 const auto &beg = proto::target::TransBegin::fromStompMessage(*m);
2723 if ( !beg ) {
2724 ERR << "Failed to parse " << proto::target::TransBegin::typeName << " message from zypp-rpm." << std::endl;
2725 continue;
2726 }
2727
2728 aboutToStartNewReport();
2729 transactionreport = std::make_unique< callback::SendReport <rpm::TransactionReportSA> > ();
2730 (*transactionreport)->start( beg->name );
2731 } else if ( mName == proto::target::TransFinished::typeName ) {
2732
2733 finalizeCurrentReport();
2734
2735 } else if ( mName == proto::target::TransProgress::typeName ) {
2736 const auto &prog = proto::target::TransProgress::fromStompMessage(*m);
2737 if ( !prog ) {
2738 ERR << "Failed to parse " << proto::target::TransProgress::typeName << " message from zypp-rpm." << std::endl;
2739 continue;
2740 }
2741
2742 if ( !transactionreport ) {
2743 ERR << "Received a TransactionProgress message, but there is no running report. " << std::endl;
2744 continue;
2745 }
2746
2747 (*transactionreport)->progress( prog->amount );
2748 } else if ( mName == proto::target::TransactionError::typeName ) {
2749
2750 const auto &error = proto::target::TransactionError::fromStompMessage(*m);
2751 if ( !error ) {
2752 ERR << "Failed to parse " << proto::target::TransactionError::typeName << " message from zypp-rpm." << std::endl;
2753 continue;
2754 }
2755
2756 // this value is checked later
2757 transactionError = std::move(*error);
2758
2759 } else {
2760 ERR << "Received unexpected message from zypp-rpm: "<< m->command() << ", ignoring" << std::endl;
2761 return;
2762 }
2763
2764 }
2765 };
2766
2767 // setup the rest when zypp-rpm is running
2768 prog->sigStarted().connect( [&](){
2769
2770 // close the ends of the pipes we do not care about
2771 messagePipe->unrefWrite();
2772 scriptPipe->unrefWrite();
2773
2774 // read the stdout and stderr and forward it to our log
2775 prog->connectFunc( &zyppng::IODevice::sigChannelReadyRead, [&]( int channel ){
2776 while( prog->canReadLine( channel ) ) {
2777 L_ERR("zypp-rpm") << ( channel == zyppng::Process::StdOut ? "<stdout> " : "<stderr> " ) << prog->channelReadLine( channel ).asStringView(); // no endl! - readLine does not trim
2778 }
2779 });
2780
2781 // this is the source for control messages from zypp-rpm , we will get structured data information
2782 // in form of STOMP messages
2783 if ( !msgSource->openFds( std::vector<int>{ messagePipe->readFd }, prog->stdinFd() ) )
2784 ZYPP_THROW( target::rpm::RpmSubprocessException( "Failed to open read stream to subprocess" ) );
2785
2786 msgStream = zyppng::StompFrameStream::create(msgSource);
2787 msgStream->connectFunc( &zyppng::StompFrameStream::sigMessageReceived, processMessages );
2788
2789 const auto &msg = commit.toStompMessage();
2790 if ( !msg )
2791 std::rethrow_exception ( msg.error() );
2792
2793 if ( !msgStream->sendMessage( *msg ) ) {
2794 prog->stop( SIGKILL );
2795 ZYPP_THROW( target::rpm::RpmSubprocessException( "Failed to write commit to subprocess" ) );
2796 }
2797 });
2798
2799 // track the childs lifetime
2800 int zyppRpmExitCode = -1;
2801 prog->connectFunc( &zyppng::Process::sigFinished, [&]( int code ){
2802 zyppRpmExitCode = code;
2803 loop->quit();
2804 });
2805
2806 if ( !prog->start( argv ) ) {
2807 HistoryLog().comment( "Commit was aborted, failed to run zypp-rpm" );
2808 ZYPP_THROW( target::rpm::RpmSubprocessException( prog->execError() ) );
2809 }
2810
2811 loop->run();
2812
2813 if ( msgStream ) {
2814 // pull all messages from the IO device
2815 msgStream->readAllMessages();
2816
2817 // make sure to read ALL available messages
2818 processMessages();
2819 }
2820
2821 // we will not receive a new start message , so we need to manually finalize the last report
2822 finalizeCurrentReport();
2823
2824 // make sure to read all data from the log source
2825 bool readMsgs = false;
2826 while( prog->canReadLine( zyppng::Process::StdErr ) ) {
2827 readMsgs = true;
2828 MIL << "zypp-rpm: " << prog->channelReadLine( zyppng::Process::StdErr ).asStringView();
2829 }
2830 while( prog->canReadLine( zyppng::Process::StdOut ) ) {
2831 readMsgs = true;
2832 MIL << "zypp-rpm: " << prog->channelReadLine( zyppng::Process::StdOut ).asStringView();
2833 }
2834
2835 while ( scriptSource->canReadLine() ) {
2836 readMsgs = true;
2837 MIL << "rpm-script-fd: " << scriptSource->readLine().asStringView();
2838 }
2839 if ( scriptSource->bytesAvailable() > 0 ) {
2840 readMsgs = true;
2841 MIL << "rpm-script-fd: " << scriptSource->readAll().asStringView();
2842 }
2843 if ( readMsgs )
2844 MIL << std::endl;
2845
2846 switch ( zyppRpmExitCode ) {
2847 // we need to look at the summary, handle finishedwitherrors like no error here
2848 case zypprpm::NoError:
2849 case zypprpm::RpmFinishedWithError:
2850 break;
2851 case zypprpm::RpmFinishedWithTransactionError: {
2852 // here zypp-rpm sent us a error description
2853 if ( transactionError ) {
2854
2855 std::ostringstream sstr;
2856 sstr << _("Executing the transaction failed because of the following problems:") << "\n";
2857 for ( const auto & err : transactionError->problems ) {
2858 sstr << " " << err << "\n";
2859 }
2860 sstr << std::endl;
2861 ZYPP_THROW( rpm::RpmTransactionFailedException( sstr.str() ) );
2862
2863 } else {
2864 ZYPP_THROW( rpm::RpmTransactionFailedException("RPM failed with a unexpected error, check the logs for more information.") );
2865 }
2866 break;
2867 }
2868 case zypprpm::FailedToOpenDb:
2869 ZYPP_THROW( rpm::RpmDbOpenException( rpm().root(), rpm().dbPath() ) );
2870 break;
2871 case zypprpm::WrongHeaderSize:
2872 case zypprpm::WrongMessageFormat:
2873 ZYPP_THROW( rpm::RpmSubprocessException("Failed to communicate with zypp-rpm, this is most likely a bug. Consider to fall back to legacy transaction strategy.") );
2874 break;
2875 case zypprpm::RpmInitFailed:
2876 ZYPP_THROW( rpm::RpmInitException( rpm().root(), rpm().dbPath() ) );
2877 break;
2878 case zypprpm::FailedToReadPackage:
2879 ZYPP_THROW( rpm::RpmSubprocessException("zypp-rpm was unable to read a package, check the logs for more information.") );
2880 break;
2881 case zypprpm::FailedToAddStepToTransaction:
2882 ZYPP_THROW( rpm::RpmSubprocessException("zypp-rpm failed to build the transaction, check the logs for more information.") );
2883 break;
2884 case zypprpm::RpmOrderFailed:
2885 ZYPP_THROW( rpm::RpmSubprocessException("zypp-rpm failed to order the transaction, check the logs for more information.") );
2886 break;
2887 case zypprpm::FailedToCreateLock:
2888 ZYPP_THROW( rpm::RpmSubprocessException("zypp-rpm failed to create its lockfile, check the logs for more information.") );
2889 break;
2890 }
2891
2892 for ( int stepId = 0; (ZYppCommitResult::TransactionStepList::size_type)stepId < steps.size() && !abort; ++stepId ) {
2893 auto &step = steps[stepId];
2894 PoolItem citem( step );
2895
2896 if ( step.stepStage() == sat::Transaction::STEP_TODO ) {
2897 // other resolvables (non-Package) that are not handled by zypp-rpm
2898 if ( !citem->isKind<Package>() && !policy_r.dryRun() ) {
2899 // Status is changed as the buddy package buddy
2900 // gets installed/deleted. Handle non-buddies only.
2901 if ( ! citem.buddy() && citem->isKind<Product>() ) {
2902 Product::constPtr p = citem->asKind<Product>();
2903
2904 if ( citem.status().isToBeInstalled() ) {
2905 ERR << "Can't install orphan product without release-package! " << citem << endl;
2906 } else {
2907 // Deleting the corresponding product entry is all we con do.
2908 // So the product will no longer be visible as installed.
2909 std::string referenceFilename( p->referenceFilename() );
2910
2911 if ( referenceFilename.empty() ) {
2912 ERR << "Can't remove orphan product without 'referenceFilename'! " << citem << endl;
2913 } else {
2914 Pathname referencePath { Pathname("/etc/products.d") / referenceFilename }; // no root prefix for rpmdb lookup!
2915
2916 if ( ! rpm().hasFile( referencePath.asString() ) ) {
2917 // If it's not owned by a package, we can delete it.
2918 referencePath = Pathname::assertprefix( _root, referencePath ); // now add a root prefix
2919 if ( filesystem::unlink( referencePath ) != 0 )
2920 ERR << "Delete orphan product failed: " << referencePath << endl;
2921 } else {
2922 WAR << "Won't remove orphan product: '/etc/products.d/" << referenceFilename << "' is owned by a package." << endl;
2923 }
2924 }
2925 }
2926 citem.status().resetTransact( ResStatus::USER );
2927 step.stepStage( sat::Transaction::STEP_DONE );
2928 }
2929 }
2930 }
2931 }
2932 }
2933
2934 // Check presence of update scripts/messages. If aborting,
2935 // at least log omitted scripts.
2936 if ( ! successfullyInstalledPackages.empty() )
2937 {
2938 if ( ! RunUpdateScripts( _root, ZConfig::instance().update_scriptsPath(),
2939 successfullyInstalledPackages, abort ) )
2940 {
2941 WAR << "Commit aborted by the user" << endl;
2942 abort = true;
2943 }
2944 // send messages after scripts in case some script generates output,
2945 // that should be kept in t %ghost message file.
2946 RunUpdateMessages( _root, ZConfig::instance().update_messagesPath(),
2947 successfullyInstalledPackages,
2948 result_r );
2949 }
2950
2951 // jsc#SLE-5116: Log patch status changes to history
2952 // NOTE: Should be the last action as it may need to reload
2953 // the Target in case of an incomplete transaction.
2954 logPatchStatusChanges( result_r.transaction(), *this );
2955
2956 if ( abort ) {
2957 HistoryLog().comment( "Commit was aborted." );
2958 ZYPP_THROW( TargetAbortedException( ) );
2959 }
2960 }
2961
2963
2964 rpm::RpmDb & TargetImpl::rpm()
2965 {
2966 return _rpm;
2967 }
2968
2969 bool TargetImpl::providesFile (const std::string & path_str, const std::string & name_str) const
2970 {
2971 return _rpm.hasFile(path_str, name_str);
2972 }
2973
2975 namespace
2976 {
2977 parser::ProductFileData baseproductdata( const Pathname & root_r )
2978 {
2979 parser::ProductFileData ret;
2980 PathInfo baseproduct( Pathname::assertprefix( root_r, "/etc/products.d/baseproduct" ) );
2981
2982 if ( baseproduct.isFile() )
2983 {
2984 try
2985 {
2986 ret = parser::ProductFileReader::scanFile( baseproduct.path() );
2987 }
2988 catch ( const Exception & excpt )
2989 {
2990 ZYPP_CAUGHT( excpt );
2991 }
2992 }
2993 else if ( PathInfo( Pathname::assertprefix( root_r, "/etc/products.d" ) ).isDir() )
2994 {
2995 ERR << "baseproduct symlink is dangling or missing: " << baseproduct << endl;
2996 }
2997 return ret;
2998 }
2999
3001 const parser::ProductFileData & cachedBaseproductdata( const Pathname & root_r )
3002 {
3003 struct CachedEntry {
3004 WatchFile watcher;
3005 parser::ProductFileData data;
3006 };
3007 static std::map<Pathname, CachedEntry> cache;
3008 auto & entry = cache[root_r];
3009 if ( entry.watcher.path().empty() )
3010 entry.watcher = WatchFile( Pathname::assertprefix( root_r, "/etc/products.d/baseproduct" ), WatchFile::NO_INIT );
3011 if ( entry.watcher.hasChanged() )
3012 entry.data = baseproductdata( root_r );
3013 return entry.data;
3014 }
3015
3016 inline Pathname staticGuessRoot( const Pathname & root_r )
3017 {
3018 if ( root_r.empty() )
3019 {
3020 // empty root: use existing Target or assume "/"
3021 Pathname ret ( ZConfig::instance().systemRoot() );
3022 if ( ret.empty() )
3023 return Pathname("/");
3024 return ret;
3025 }
3026 return root_r;
3027 }
3028
3029 inline std::string firstNonEmptyLineIn( const Pathname & file_r )
3030 {
3031 std::ifstream idfile( file_r.c_str() );
3032 for( iostr::EachLine in( idfile ); in; in.next() )
3033 {
3034 std::string line( str::trim( *in ) );
3035 if ( ! line.empty() )
3036 return line;
3037 }
3038 return std::string();
3039 }
3040 } // namespace
3042
3043 Product::constPtr TargetImpl::baseProduct() const
3044 {
3045 ResPool pool(ResPool::instance());
3046 for_( it, pool.byKindBegin<Product>(), pool.byKindEnd<Product>() )
3047 {
3048 Product::constPtr p = (*it)->asKind<Product>();
3049 if ( p->isTargetDistribution() )
3050 return p;
3051 }
3052 return nullptr;
3053 }
3054
3055 LocaleSet TargetImpl::requestedLocales( const Pathname & root_r )
3056 {
3057 const Pathname needroot( staticGuessRoot(root_r) );
3058 const Target_constPtr target( getZYpp()->getTarget() );
3059 if ( target && target->root() == needroot )
3060 return target->requestedLocales();
3061 return RequestedLocalesFile( home(needroot) / "RequestedLocales" ).locales();
3062 }
3063
3064 void TargetImpl::updateAutoInstalled()
3065 {
3066 MIL << "updateAutoInstalled if changed..." << endl;
3067 SolvIdentFile::Data newdata;
3068 for ( auto id : sat::Pool::instance().autoInstalled() )
3069 newdata.insert( IdString(id) ); // explicit ctor!
3070 _autoInstalledFile.setData( std::move(newdata) );
3071 }
3072
3073 std::string TargetImpl::targetDistribution() const
3074 { return baseproductdata( _root ).registerTarget(); }
3075 // static version:
3076 std::string TargetImpl::targetDistribution( const Pathname & root_r )
3077 { return baseproductdata( staticGuessRoot(root_r) ).registerTarget(); }
3078
3079 std::string TargetImpl::targetDistributionRelease() const
3080 { return baseproductdata( _root ).registerRelease(); }
3081 // static version:
3082 std::string TargetImpl::targetDistributionRelease( const Pathname & root_r )
3083 { return baseproductdata( staticGuessRoot(root_r) ).registerRelease();}
3084
3085 std::string TargetImpl::targetDistributionFlavor() const
3086 { return baseproductdata( _root ).registerFlavor(); }
3087 // static version:
3088 std::string TargetImpl::targetDistributionFlavor( const Pathname & root_r )
3089 { return baseproductdata( staticGuessRoot(root_r) ).registerFlavor();}
3090
3091 Target::DistributionLabel TargetImpl::distributionLabel() const
3092 {
3093 Target::DistributionLabel ret;
3094 parser::ProductFileData pdata( baseproductdata( _root ) );
3095 ret.shortName = pdata.shortName();
3096 ret.summary = pdata.summary();
3097 return ret;
3098 }
3099 // static version:
3100 Target::DistributionLabel TargetImpl::distributionLabel( const Pathname & root_r )
3101 {
3102 Target::DistributionLabel ret;
3103 parser::ProductFileData pdata( baseproductdata( staticGuessRoot(root_r) ) );
3104 ret.shortName = pdata.shortName();
3105 ret.summary = pdata.summary();
3106 return ret;
3107 }
3108
3109 std::string TargetImpl::distributionVersion() const
3110 {
3111 if ( _baseproductWatcher.hasChanged() )
3112 {
3113 _distributionVersion = TargetImpl::distributionVersion(root());
3114 MIL << "Remember distributionVersion = '" << _distributionVersion << "'" << endl;
3115 }
3116 return _distributionVersion;
3117 }
3118 // static version
3119 std::string TargetImpl::distributionVersion( const Pathname & root_r )
3120 {
3121 const Pathname & needroot = staticGuessRoot(root_r);
3122 std::string distributionVersion = cachedBaseproductdata( needroot ).edition().version();
3123 if ( distributionVersion.empty() )
3124 {
3125 // ...But the baseproduct method is not expected to work on RedHat derivatives.
3126 // On RHEL, Fedora and others the "product version" is determined by the first package
3127 // providing 'system-release'. This value is not hardcoded in YUM and can be configured
3128 // with the $distroverpkg variable.
3129 rpm::librpmDb::db_const_iterator it( needroot );
3130 if ( it.findByProvides( ZConfig::instance().distroverpkg() ) )
3131 distributionVersion = it->tag_version();
3132 }
3133 return distributionVersion;
3134 }
3135
3136
3137 std::string TargetImpl::distributionFlavor() const
3138 {
3139 return firstNonEmptyLineIn( home() / "LastDistributionFlavor" );
3140 }
3141 // static version:
3142 std::string TargetImpl::distributionFlavor( const Pathname & root_r )
3143 {
3144 return firstNonEmptyLineIn( staticGuessRoot(root_r) / "/var/lib/zypp/LastDistributionFlavor" );
3145 }
3146
3148 namespace
3149 {
3150 std::string guessAnonymousUniqueId( const Pathname & root_r )
3151 {
3152 // bsc#1024741: Omit creating a new uid for chrooted systems (if it already has one, fine)
3153 std::string ret( firstNonEmptyLineIn( root_r / "/var/lib/zypp/AnonymousUniqueId" ) );
3154 if ( ret.empty() && root_r != "/" )
3155 {
3156 // if it has nonoe, use the outer systems one
3157 ret = firstNonEmptyLineIn( "/var/lib/zypp/AnonymousUniqueId" );
3158 }
3159 return ret;
3160 }
3161 }
3162
3163 std::string TargetImpl::anonymousUniqueId() const
3164 {
3165 return guessAnonymousUniqueId( root() );
3166 }
3167 // static version:
3168 std::string TargetImpl::anonymousUniqueId( const Pathname & root_r )
3169 {
3170 return guessAnonymousUniqueId( staticGuessRoot(root_r) );
3171 }
3172
3174
3175 void TargetImpl::vendorAttr( VendorAttr vendorAttr_r )
3176 {
3177 MIL << "New VendorAttr: " << vendorAttr_r << endl;
3178 _vendorAttr = std::move(vendorAttr_r);
3179 }
3180
3181
3182 void TargetImpl::installSrcPackage( const SrcPackage_constPtr & srcPackage_r )
3183 {
3184 // provide on local disk
3185 ManagedFile localfile = provideSrcPackage(srcPackage_r);
3186 // create a installation progress report proxy
3187 RpmInstallPackageReceiver progress( srcPackage_r );
3188 progress.connect(); // disconnected on destruction.
3189 // install it
3190 rpm().installPackage ( localfile );
3191 }
3192
3193 ManagedFile TargetImpl::provideSrcPackage( const SrcPackage_constPtr & srcPackage_r )
3194 {
3195 // provide on local disk
3196 repo::RepoMediaAccess access_r;
3197 repo::SrcPackageProvider prov( access_r );
3198 return prov.provideSrcPackage( srcPackage_r );
3199 }
3200
3201 } // namespace target
3204} // namespace zypp
CommitPackageCache.h
NON_COPYABLE
#define NON_COPYABLE(CLASS)
Delete copy ctor and copy assign.
Definition Easy.h:49
for_
#define for_(IT, BEG, END)
Convenient for-loops using iterator.
Definition Easy.h:27
NON_MOVABLE
#define NON_MOVABLE(CLASS)
Delete move ctor and move assign.
Definition Easy.h:59
Env.h
Exception.h
ZYPP_CAUGHT
#define ZYPP_CAUGHT(EXCPT)
Drops a logline telling the Exception was caught (in order to handle it).
Definition Exception.h:475
ZYPP_THROW
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition Exception.h:459
ExternalProgram.h
Functional.h
Gettext.h
_
#define _(MSG)
Definition Gettext.h:39
HistoryLog.h
IOStream.h
IOTools.h
Iterator.h
Json.h
LogTools.h
L_ERR
#define L_ERR(GROUP)
Definition Logger.h:141
DBG
#define DBG
Definition Logger.h:129
MIL
#define MIL
Definition Logger.h:130
ERR
#define ERR
Definition Logger.h:132
L_WAR
#define L_WAR(GROUP)
Definition Logger.h:140
WAR
#define WAR
Definition Logger.h:131
L_DBG
#define L_DBG(GROUP)
Definition Logger.h:138
INT
#define INT
Definition Logger.h:134
PluginExecutor.h
PoolItem.h
idstr
#define idstr(V)
Pool.h
ProductFileReader.h
RepoStatus.h
Repository.h
ResFilters.h
ResObjects.h
MAXRPMMESSAGELINES
#define MAXRPMMESSAGELINES
Definition RpmDb.cc:65
RpmException.h
RpmPostTransCollector.h
ShutdownLock_p.h
SolvableSpec.h
SrcPackageProvider.h
StringV.h
String.h
TargetCallbackReceiver.h
SUBST_IF
#define SUBST_IF(PAT, VAL)
TargetImpl.h
Transaction.h
Url.h
ZConfig.h
ZYppFactory.h
Target_Ptr
zypp::Arch
Architecture.
Definition Arch.h:37
zypp::Arch::asString
const std::string & asString() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition Arch.cc:724
zypp::Arch::compatibleWith
bool compatibleWith(const Arch &targetArch_r) const
Compatibility relation.
Definition Arch.cc:740
zypp::AutoDispose
Reference counted access to a Tp object calling a custom Dispose function when the last AutoDispose h...
Definition AutoDispose.h:95
zypp::AutoDispose::value
reference value() const
Reference to the Tp object.
Definition AutoDispose.h:138
zypp::AutoDispose::resetDispose
void resetDispose()
Set no dispose function.
Definition AutoDispose.h:171
zypp::Capability::Capability
Capability()
Default ctor, Empty capability.
Definition Capability.h:69
zypp::Date::Date
Date()
Default ctor: 0.
Definition Date.h:57
zypp::Date::now
static Date now()
Return the current time.
Definition Date.h:78
zypp::Edition
Edition represents [epoch:]version[-release].
Definition Edition.h:60
zypp::Edition::version
std::string version() const
Version.
Definition Edition.cc:96
zypp::Edition::epoch_t
unsigned int epoch_t
Type of an epoch.
Definition Edition.h:63
zypp::Edition::release
std::string release() const
Release.
Definition Edition.cc:112
zypp::Edition::epoch
epoch_t epoch() const
Epoch.
Definition Edition.cc:84
zypp::Exception
Base class for Exception.
Definition Exception.h:153
zypp::Exception::Exception
Exception()
Default ctor.
Definition Exception.cc:94
zypp::Exception::remember
void remember(const Exception &old_r)
Store an other Exception as history.
Definition Exception.cc:154
zypp::ExternalProgram
Execute a program and give access to its io An object of this class encapsulates the execution of an ...
Definition ExternalProgram.h:64
zypp::ExternalProgram::close
int close() override
Wait for the progamm to complete.
Definition ExternalProgram.cc:357
zypp::ExternalProgram::command
const std::string & command() const
The command we're executing.
Definition ExternalProgram.cc:471
zypp::ExternalProgram::Arguments
std::vector< std::string > Arguments
Definition ExternalProgram.h:68
zypp::ExternalProgram::Stderr_To_Stdout
@ Stderr_To_Stdout
Definition ExternalProgram.h:77
zypp::HistoryLog
Writing the zypp history file.
Definition HistoryLog.h:57
zypp::HistoryLog::HistoryLog
HistoryLog(const HistoryLog &)
zypp::HistoryLog::setRoot
static void setRoot(const Pathname &root)
Set new root directory to the default history log file path.
Definition HistoryLog.cc:163
zypp::HistoryLog::fname
static const Pathname & fname()
Get the current log file path.
Definition HistoryLog.cc:181
zypp::HistoryLog::comment
void comment(const std::string &comment, bool timestamp=false)
Log a comment (even multiline).
Definition HistoryLog.cc:190
zypp::IdString
Access to the sat-pools string space.
Definition IdString.h:55
zypp::IdString::c_str
const char * c_str() const
Conversion to const char *.
Definition IdString.cc:51
zypp::IdString::asString
std::string asString() const
Conversion to std::string.
Definition IdString.h:110
zypp::IdString::IdString
constexpr IdString()
Default ctor, empty string.
Definition IdString.h:61
zypp::Match::REGEX
@ REGEX
Regular Expression.
Definition StrMatcher.h:48
zypp::Package
Package interface.
Definition Package.h:34
zypp::Package::constPtr
TraitsType::constPtrType constPtr
Definition Package.h:39
zypp::Patch
Class representing a patch.
Definition Patch.h:38
zypp::Patch::constPtr
TraitsType::constPtrType constPtr
Definition Patch.h:43
zypp::PathInfo::PathInfo
PathInfo()
Definition PathInfo.cc:131
zypp::PathInfo::LSTAT
@ LSTAT
Definition PathInfo.h:231
zypp::Pathname::Pathname
Pathname()
Default ctor: an empty path.
Definition Pathname.h:51
zypp::Pathname::assertprefix
static Pathname assertprefix(const Pathname &root_r, const Pathname &path_r)
Unless path_r does not already denote a path below root_r, combine them.
Definition Pathname.cc:272
zypp::PluginExecutor
Parallel execution of stateful PluginScripts.
Definition PluginExecutor.h:42
zypp::PluginExecutor::load
void load(const Pathname &path_r)
Find and launch plugins sending PLUGINBEGIN.
Definition PluginExecutor.cc:174
zypp::PluginExecutor::send
void send(const PluginFrame &frame_r)
Send PluginFrame to all open plugins.
Definition PluginExecutor.cc:177
zypp::PluginFrame::PluginFrame
PluginFrame()
Default ctor (empty frame).
Definition PluginFrame.cc:408
zypp::PoolItem
Combining sat::Solvable and ResStatus.
Definition PoolItem.h:51
zypp::PoolItem::resolvable
ResObject::constPtr resolvable() const
Returns the ResObject::constPtr.
Definition PoolItem.cc:227
zypp::PoolItem::status
ResStatus & status() const
Returns the current status.
Definition PoolItem.cc:212
zypp::PoolItem::buddy
sat::Solvable buddy() const
Return the buddy we share our status object with.
Definition PoolItem.cc:215
zypp::Product
Product interface.
Definition Product.h:34
zypp::Product::constPtr
TraitsType::constPtrType constPtr
Definition Product.h:39
zypp::RepoStatus
Track changing files or directories.
Definition RepoStatus.h:41
zypp::RepoStatus::fromCookieFile
static RepoStatus fromCookieFile(const Pathname &path)
Reads the status from a cookie file.
Definition RepoStatus.cc:210
zypp::RepoStatus::RepoStatus
RepoStatus()
Default ctor.
Definition RepoStatus.cc:172
zypp::RepoStatus::saveToCookieFile
void saveToCookieFile(const Pathname &path_r) const
Save the status information to a cookie file.
Definition RepoStatus.cc:224
zypp::Repository
Definition Repository.h:40
zypp::Repository::solvablesEmpty
bool solvablesEmpty() const
Whether Repository contains solvables.
Definition Repository.cc:225
zypp::Repository::solvablesEnd
SolvableIterator solvablesEnd() const
Iterator behind the last Solvable.
Definition Repository.cc:247
zypp::Repository::solvablesBegin
SolvableIterator solvablesBegin() const
Iterator to the first Solvable.
Definition Repository.cc:237
zypp::Repository::solvablesSize
size_type solvablesSize() const
Number of solvables in Repository.
Definition Repository.cc:231
zypp::Repository::addSolv
void addSolv(const Pathname &file_r)
Load Solvables from a solv-file.
Definition Repository.cc:326
zypp::Repository::eraseFromPool
void eraseFromPool()
Remove this Repository from its Pool.
Definition Repository.cc:303
zypp::ResPool
Global ResObject pool.
Definition ResPool.h:62
zypp::ResPool::instance
static ResPool instance()
Singleton ctor.
Definition ResPool.cc:38
zypp::ResPool::setHardLockQueries
void setHardLockQueries(const HardLockQueries &newLocks_r)
Set a new set of queries.
Definition ResPool.cc:104
zypp::ResPool::resolver
Resolver & resolver() const
The Resolver.
Definition ResPool.cc:62
zypp::ResPool::getRequestedLocales
const LocaleSet & getRequestedLocales() const
Return the requested locales.
Definition ResPool.cc:131
zypp::ResPool::changedPseudoInstalled
ChangedPseudoInstalled changedPseudoInstalled() const
Return all pseudo installed items whose current state differs from their initial one.
Definition ResPool.h:350
zypp::ResPool::establishedStates
EstablishedStates establishedStates() const
Factory for EstablishedStates.
Definition ResPool.cc:77
zypp::ResPool::getHardLockQueries
void getHardLockQueries(HardLockQueries &activeLocks_r)
Suggest a new set of queries based on the current selection.
Definition ResPool.cc:107
zypp::ResPool::ChangedPseudoInstalled
EstablishedStates::ChangedPseudoInstalled ChangedPseudoInstalled
Map holding pseudo installed items where current and established status differ.
Definition ResPool.h:342
zypp::ResStatus::isToBeInstalled
bool isToBeInstalled() const
Definition ResStatus.h:259
zypp::ResStatus::USER
@ USER
Definition ResStatus.h:112
zypp::ResStatus::resetTransact
bool resetTransact(TransactByValue causer_r)
Not the same as setTransact( false ).
Definition ResStatus.h:490
zypp::Resolvable::constPtr
TraitsType::constPtrType constPtr
Definition Resolvable.h:59
zypp::Resolver::getTransaction
sat::Transaction getTransaction()
Return the Transaction computed by the last solver run.
Definition Resolver.cc:77
zypp::Resolver::upgradeMode
bool upgradeMode() const
Definition Resolver.cc:100
zypp::Resolver::upgradingRepos
bool upgradingRepos() const
Whether there is at least one UpgradeRepo request pending.
Definition Resolver.cc:149
zypp::ShutdownLockCommit
Definition ShutdownLock_p.h:46
zypp::SrcPackage
SrcPackage interface.
Definition SrcPackage.h:30
zypp::SrcPackage::constPtr
TraitsType::constPtrType constPtr
Definition SrcPackage.h:36
zypp::StrMatcher
String matching (STRING|SUBSTRING|GLOB|REGEX).
Definition StrMatcher.h:298
zypp::UpdateNotificationFile::UpdateNotificationFile
UpdateNotificationFile(sat::Solvable solvable_r, Pathname file_r)
Definition ZYppCommitResult.h:37
zypp::VendorAttr
Definition of vendor equivalence.
Definition VendorAttr.h:61
zypp::WatchFile
Remember a files attributes to detect content changes.
Definition watchfile.h:50
zypp::WatchFile::WatchFile
WatchFile(const Pathname &path_r=Pathname(), Initial mode=INIT)
Definition watchfile.h:56
zypp::WatchFile::hasChanged
bool hasChanged()
Definition watchfile.h:80
zypp::WatchFile::NO_INIT
@ NO_INIT
Definition watchfile.h:52
zypp::ZConfig
Interim helper class to collect global options and settings.
Definition ZConfig.h:82
zypp::ZConfig::systemArchitecture
Arch systemArchitecture() const
The system architecture zypp uses.
Definition ZConfig.cc:857
zypp::ZConfig::instance
static ZConfig & instance()
Singleton ctor.
Definition ZConfig.cc:794
zypp::ZYppCommitPolicy
Options and policies for ZYpp::commit.
Definition ZYppCommitPolicy.h:34
zypp::ZYppCommitPolicy::rpmInstFlags
ZYppCommitPolicy & rpmInstFlags(target::rpm::RpmInstFlags newFlags_r)
The default target::rpm::RpmInstFlags.
Definition ZYppCommitPolicy.cc:166
zypp::ZYppCommitPolicy::singleTransModeEnabled
bool singleTransModeEnabled() const
Whether the single_rpmtrans backend is enabled (or the classic_rpmtrans).
Definition ZYppCommitPolicy.cc:202
zypp::ZYppCommitPolicy::rpmExcludeDocs
ZYppCommitPolicy & rpmExcludeDocs(bool yesNo_r)
Use rpm option –excludedocs (default: false).
Definition ZYppCommitPolicy.cc:172
zypp::ZYppCommitPolicy::dryRun
ZYppCommitPolicy & dryRun(bool yesNo_r)
Set dry run (default: false).
Definition ZYppCommitPolicy.cc:154
zypp::ZYppCommitPolicy::restrictToMedia
ZYppCommitPolicy & restrictToMedia(unsigned mediaNr_r)
Restrict commit to media 1.
Definition ZYppCommitPolicy.cc:147
zypp::ZYppCommitPolicy::downloadMode
ZYppCommitPolicy & downloadMode(DownloadMode val_r)
Commit download policy to use.
Definition ZYppCommitPolicy.cc:160
zypp::ZYppCommitPolicy::allMedia
ZYppCommitPolicy & allMedia()
Process all media (default).
Definition ZYppCommitPolicy.h:48
zypp::ZYppCommitPolicy::rpmNoSignature
ZYppCommitPolicy & rpmNoSignature(bool yesNo_r)
Use rpm option –nosignature (default: false).
Definition ZYppCommitPolicy.cc:169
zypp::ZYppCommitResult
Result returned from ZYpp::commit.
Definition ZYppCommitResult.h:64
zypp::ZYppCommitResult::rTransactionStepList
TransactionStepList & rTransactionStepList()
Manipulate transactionStepList.
Definition ZYppCommitResult.cc:93
zypp::ZYppCommitResult::setSingleTransactionMode
void setSingleTransactionMode(bool yesno_r)
Definition ZYppCommitResult.cc:81
zypp::ZYppCommitResult::TransactionStepList
std::vector< sat::Transaction::Step > TransactionStepList
Definition ZYppCommitResult.h:66
zypp::ZYppCommitResult::transaction
const sat::Transaction & transaction() const
The full transaction list.
Definition ZYppCommitResult.cc:84
zypp::ZYppCommitResult::rTransaction
sat::Transaction & rTransaction()
Manipulate transaction.
Definition ZYppCommitResult.cc:87
zypp::ZYppFactory::lockfileDir
static zypp::Pathname lockfileDir()
Definition ZYppFactory.cc:467
zypp::callback::UserData
Typesafe passing of user data via callbacks.
Definition UserData.h:40
zypp::callback::UserData::set
bool set(const std::string &key_r, AnyType val_r)
Set the value for key (nonconst version always returns true).
Definition UserData.h:119
zypp::externalprogram::ExternalDataSource::receiveLine
std::string receiveLine()
Read one line from the input stream.
Definition ExternalDataSource.cc:115
zypp::filesystem::PathInfo
Wrapper class for stat/lstat.
Definition PathInfo.h:226
zypp::filesystem::PathInfo::isExist
bool isExist() const
Return whether valid stat info exists.
Definition PathInfo.h:286
zypp::filesystem::Pathname
Pathname.
Definition Pathname.h:48
zypp::filesystem::Pathname::dirname
Pathname dirname() const
Return all but the last component od this path.
Definition Pathname.h:133
zypp::filesystem::Pathname::c_str
const char * c_str() const
String representation.
Definition Pathname.h:113
zypp::filesystem::Pathname::asString
const std::string & asString() const
String representation.
Definition Pathname.h:94
zypp::filesystem::Pathname::empty
bool empty() const
Test for an empty path.
Definition Pathname.h:117
zypp::filesystem::TmpFile
Provide a new empty temporary file and delete it when no longer needed.
Definition TmpPath.h:118
zypp::filesystem::TmpFile::makeSibling
static TmpFile makeSibling(const Pathname &sibling_r)
Provide a new empty temporary directory as sibling.
Definition TmpPath.cc:182
zypp::filesystem::TmpPath::path
Pathname path() const
Definition TmpPath.cc:124
zypp::json::Array
Definition JsonValue.h:34
zypp::json::Array::add
void add(Value val_r)
Push JSON Value to Array.
Definition JsonValue.cc:20
zypp::json::Object
Definition JsonValue.h:101
zypp::json::Object::add
void add(String key_r, Value val_r)
Add key/value pair.
Definition JsonValue.cc:62
zypp::json::Value
Definition JsonValue.h:175
zypp::parser::ProductFileData
Data returned by ProductFileReader.
Definition ProductFileReader.h:42
zypp::parser::ProductFileData::empty
bool empty() const
Whether this is an empty object without valid data.
Definition ProductFileReader.h:49
zypp::parser::ProductFileData::summary
std::string summary() const
Definition ProductFileReader.cc:96
zypp::parser::ProductFileData::shortName
std::string shortName() const
Definition ProductFileReader.cc:95
zypp::parser::ProductFileReader::scanFile
static ProductFileData scanFile(const Pathname &file_r)
Parse one file (or symlink) and return the ProductFileData parsed.
Definition ProductFileReader.cc:272
zypp::repo::RepoMediaAccess
Provides files from different repos.
Definition RepoProvideFile.h:73
zypp::repo::SrcPackageProvider
Definition SrcPackageProvider.h:39
zypp::repo::SrcPackageProvider::provideSrcPackage
ManagedFile provideSrcPackage(const SrcPackage_constPtr &srcPackage_r) const
Provide SrcPackage in a local file.
Definition SrcPackageProvider.cc:36
zypp::sat::Pool
Global sat-pool.
Definition Pool.h:47
zypp::sat::Pool::setAutoInstalled
void setAutoInstalled(const Queue &autoInstalled_r)
Set ident list of all autoinstalled solvables.
Definition Pool.cc:265
zypp::sat::Pool::rootDir
Pathname rootDir() const
Get rootdir (for file conflicts check).
Definition Pool.cc:64
zypp::sat::Pool::instance
static Pool instance()
Singleton ctor.
Definition Pool.h:55
zypp::sat::Pool::systemRepoAlias
static const std::string & systemRepoAlias()
Reserved system repository alias @System .
Definition Pool.cc:46
zypp::sat::Pool::setNeedrebootSpec
void setNeedrebootSpec(sat::SolvableSpec needrebootSpec_r)
Solvables which should trigger the reboot-needed hint if installed/updated.
Definition Pool.cc:267
zypp::sat::Pool::systemRepo
Repository systemRepo()
Return the system repository, create it if missing.
Definition Pool.cc:178
zypp::sat::Pool::initRequestedLocales
void initRequestedLocales(const LocaleSet &locales_r)
Start tracking changes based on this locales_r.
Definition Pool.cc:251
zypp::sat::Queue::value_type
detail::IdType value_type
Definition Queue.h:39
zypp::sat::Queue::push
void push(value_type val_r)
Push a value to the end off the Queue.
Definition Queue.cc:103
zypp::sat::Solvable
A Solvable object within the sat Pool.
Definition Solvable.h:54
zypp::sat::Transaction::Step
A single step within a Transaction.
Definition Transaction.h:219
zypp::sat::Transaction::Step::arch
Arch arch() const
Definition Transaction.cc:405
zypp::sat::Transaction::Step::ident
IdString ident() const
Definition Transaction.cc:399
zypp::sat::Transaction::Step::stepType
StepType stepType() const
Type of action to perform in this step.
Definition Transaction.cc:390
zypp::sat::Transaction::Step::stepStage
StepStage stepStage() const
Step action result.
Definition Transaction.cc:393
zypp::sat::Transaction::Step::satSolvable
Solvable satSolvable() const
Return the corresponding Solvable.
Definition Transaction.h:243
zypp::sat::Transaction::Step::edition
Edition edition() const
Definition Transaction.cc:402
zypp::sat::Transaction
Libsolv transaction wrapper.
Definition Transaction.h:52
zypp::sat::Transaction::end
const_iterator end() const
Iterator behind the last TransactionStep.
Definition Transaction.cc:345
zypp::sat::Transaction::autoInstalled
StringQueue autoInstalled() const
Return the ident strings of all packages that would be auto-installed after the transaction is run.
Definition Transaction.cc:360
zypp::sat::Transaction::begin
const_iterator begin() const
Iterator to the first TransactionStep.
Definition Transaction.cc:339
zypp::sat::Transaction::order
bool order()
Order transaction steps for commit.
Definition Transaction.cc:330
zypp::sat::Transaction::TRANSACTION_MULTIINSTALL
@ TRANSACTION_MULTIINSTALL
[M] Install(multiversion) item (
Definition Transaction.h:67
zypp::sat::Transaction::TRANSACTION_INSTALL
@ TRANSACTION_INSTALL
[+] Install(update) item
Definition Transaction.h:66
zypp::sat::Transaction::TRANSACTION_IGNORE
@ TRANSACTION_IGNORE
[ ] Nothing (includes implicit deletes due to obsoletes and non-package actions)
Definition Transaction.h:64
zypp::sat::Transaction::TRANSACTION_ERASE
@ TRANSACTION_ERASE
[-] Delete item
Definition Transaction.h:65
zypp::sat::Transaction::STEP_DONE
@ STEP_DONE
[OK] success
Definition Transaction.h:74
zypp::sat::Transaction::STEP_TODO
@ STEP_TODO
[__] unprocessed
Definition Transaction.h:73
zypp::sat::Transaction::STEP_ERROR
@ STEP_ERROR
[**] error
Definition Transaction.h:75
zypp::sat::detail::PoolImpl::multiversionSpecChanged
void multiversionSpecChanged()
Definition PoolImpl.cc:626
zypp::target::CommitPackageCache
Target::commit helper optimizing package provision.
Definition CommitPackageCache.h:59
zypp::target::CommitPackageCache::setCommitList
void setCommitList(std::vector< sat::Solvable > commitList_r)
Download(commit) sequence of solvables to compute read ahead.
Definition CommitPackageCache.cc:138
zypp::target::CommitPackageCache::preloaded
bool preloaded() const
Whether preloaded hint is set.
Definition CommitPackageCache.cc:144
zypp::target::CommitPackageCache::get
ManagedFile get(const PoolItem &citem_r)
Provide a package.
Definition CommitPackageCache.cc:141
zypp::target::HardLocksFile::setData
void setData(const Data &data_r)
Store new Data.
Definition HardLocksFile.h:74
zypp::target::HardLocksFile::data
const Data & data() const
Return the data.
Definition HardLocksFile.h:58
zypp::target::HardLocksFile::Data
pool::PoolTraits::HardLockQueries Data
Definition HardLocksFile.h:42
zypp::target::RequestedLocalesFile::locales
const LocaleSet & locales() const
Return the loacale set.
Definition RequestedLocalesFile.h:54
zypp::target::RequestedLocalesFile::RequestedLocalesFile
RequestedLocalesFile(Pathname file_r)
Ctor taking the file to read/write.
Definition RequestedLocalesFile.h:42
zypp::target::RequestedLocalesFile::setLocales
void setLocales(const LocaleSet &locales_r)
Store a new locale set.
Definition RequestedLocalesFile.h:69
zypp::target::RpmInstallPackageReceiver
Definition TargetCallbackReceiver.h:27
zypp::target::RpmInstallPackageReceiver::tryLevel
void tryLevel(target::rpm::InstallResolvableReport::RpmLevel level_r)
Definition TargetCallbackReceiver.cc:110
zypp::target::RpmInstallPackageReceiver::aborted
bool aborted() const
Definition TargetCallbackReceiver.h:51
zypp::target::RpmPostTransCollector
Extract and remember posttrans scripts for later execution.
Definition RpmPostTransCollector.h:41
zypp::target::RpmPostTransCollector::executeScripts
void executeScripts(rpm::RpmDb &rpm_r, const IdStringSet &obsoletedPackages_r)
Execute the remembered scripts and/or or dump_posttrans lines.
Definition RpmPostTransCollector.cc:426
zypp::target::RpmPostTransCollector::discardScripts
void discardScripts()
Discard all remembered scripts and/or or dump_posttrans lines.
Definition RpmPostTransCollector.cc:429
zypp::target::RpmRemovePackageReceiver
Definition TargetCallbackReceiver.h:74
zypp::target::RpmRemovePackageReceiver::aborted
bool aborted() const
Returns true if removing is aborted during progress.
Definition TargetCallbackReceiver.h:104
zypp::target::SolvIdentFile::data
const Data & data() const
Return the data.
Definition SolvIdentFile.h:54
zypp::target::SolvIdentFile::Data
std::unordered_set< IdString > Data
Definition SolvIdentFile.h:38
zypp::target::SolvIdentFile::setData
void setData(const Data &data_r)
Store new Data.
Definition SolvIdentFile.h:70
zypp::target::SolvIdentFile::file
const Pathname & file() const
Return the file path.
Definition SolvIdentFile.h:47
zypp::target::TargetAbortedException::TargetAbortedException
TargetAbortedException()
Definition TargetException.cc:26
zypp::target::TargetImpl
Base class for concrete Target implementations.
Definition TargetImpl.h:55
zypp::target::TargetImpl::targetDistributionRelease
std::string targetDistributionRelease() const
This is register.release attribute of the installed base product.
Definition TargetImpl.cc:3079
zypp::target::TargetImpl::clearCache
void clearCache()
Definition TargetImpl.cc:1109
zypp::target::TargetImpl::vendorAttr
const VendorAttr & vendorAttr() const
The targets current vendor equivalence settings.
Definition TargetImpl.h:200
zypp::target::TargetImpl::targetDistribution
std::string targetDistribution() const
This is register.target attribute of the installed base product.
Definition TargetImpl.cc:3073
zypp::target::TargetImpl::PoolItemList
std::list< PoolItem > PoolItemList
list of pool items
Definition TargetImpl.h:60
zypp::target::TargetImpl::requestedLocales
LocaleSet requestedLocales() const
Languages to be supported by the system.
Definition TargetImpl.h:156
zypp::target::TargetImpl::updateAutoInstalled
void updateAutoInstalled()
Update the database of autoinstalled packages.
Definition TargetImpl.cc:3064
zypp::target::TargetImpl::provideSrcPackage
ManagedFile provideSrcPackage(const SrcPackage_constPtr &srcPackage_r)
Provides a source package on the Target.
Definition TargetImpl.cc:3193
zypp::target::TargetImpl::_root
Pathname _root
Path to the target.
Definition TargetImpl.h:223
zypp::target::TargetImpl::_requestedLocalesFile
RequestedLocalesFile _requestedLocalesFile
Requested Locales database.
Definition TargetImpl.h:227
zypp::target::TargetImpl::createLastDistributionFlavorCache
void createLastDistributionFlavorCache() const
generates a cache of the last product flavor
Definition TargetImpl.cc:1055
zypp::target::TargetImpl::_baseproductWatcher
WatchFile _baseproductWatcher
Cache distributionVersion.
Definition TargetImpl.h:233
zypp::target::TargetImpl::_tmpSolvfilesPath
Pathname _tmpSolvfilesPath
Definition TargetImpl.h:100
zypp::target::TargetImpl::_distributionVersion
std::string _distributionVersion
Definition TargetImpl.h:234
zypp::target::TargetImpl::_rpm
rpm::RpmDb _rpm
RPM database.
Definition TargetImpl.h:225
zypp::target::TargetImpl::~TargetImpl
~TargetImpl() override
Dtor.
Definition TargetImpl.cc:1091
zypp::target::TargetImpl::buildCache
bool buildCache()
Definition TargetImpl.cc:1115
zypp::target::TargetImpl::rpm
rpm::RpmDb & rpm()
The RPM database.
Definition TargetImpl.cc:2964
zypp::target::TargetImpl::solvfilesPath
Pathname solvfilesPath() const
The solv file location actually in use (default or temp).
Definition TargetImpl.h:93
zypp::target::TargetImpl::distributionVersion
std::string distributionVersion() const
This is version attribute of the installed base product.
Definition TargetImpl.cc:3109
zypp::target::TargetImpl::createAnonymousId
void createAnonymousId() const
generates the unique anonymous id which is called when creating the target
Definition TargetImpl.cc:1033
zypp::target::TargetImpl::unload
void unload()
Definition TargetImpl.cc:1269
zypp::target::TargetImpl::_autoInstalledFile
SolvIdentFile _autoInstalledFile
user/auto installed database
Definition TargetImpl.h:229
zypp::target::TargetImpl::baseProduct
Product::constPtr baseProduct() const
returns the target base installed product, also known as the distribution or platform.
Definition TargetImpl.cc:3043
zypp::target::TargetImpl::distributionLabel
Target::DistributionLabel distributionLabel() const
This is shortName and summary attribute of the installed base product.
Definition TargetImpl.cc:3091
zypp::target::TargetImpl::providesFile
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:2969
zypp::target::TargetImpl::_hardLocksFile
HardLocksFile _hardLocksFile
Hard-Locks database.
Definition TargetImpl.h:231
zypp::target::TargetImpl::root
Pathname root() const
The root set for this target.
Definition TargetImpl.h:117
zypp::target::TargetImpl::load
void load(bool force=true)
Definition TargetImpl.cc:1276
zypp::target::TargetImpl::distributionFlavor
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:3137
zypp::target::TargetImpl::commitInSingleTransaction
void commitInSingleTransaction(const ZYppCommitPolicy &policy_r, CommitPackageCache &packageCache_r, ZYppCommitResult &result_r)
Commit ordered changes (internal helper).
Definition TargetImpl.cc:2089
zypp::target::TargetImpl::reload
void reload()
Definition TargetImpl.cc:1264
zypp::target::TargetImpl::installSrcPackage
void installSrcPackage(const SrcPackage_constPtr &srcPackage_r)
Install a source package on the Target.
Definition TargetImpl.cc:3182
zypp::target::TargetImpl::commit
ZYppCommitResult commit(ResPool pool_r, const ZYppCommitPolicy &policy_r)
Commit changes in the pool.
Definition TargetImpl.cc:1412
zypp::target::TargetImpl::_vendorAttr
VendorAttr _vendorAttr
vendor equivalence settings.
Definition TargetImpl.h:236
zypp::target::TargetImpl::home
Pathname home() const
The directory to store things.
Definition TargetImpl.h:121
zypp::target::TargetImpl::commitFindFileConflicts
void commitFindFileConflicts(const ZYppCommitPolicy &policy_r, ZYppCommitResult &result_r)
Commit helper checking for file conflicts after download.
Definition TargetImpl.commitFindFileConflicts.cc:122
zypp::target::TargetImpl::defaultSolvfilesPath
Pathname defaultSolvfilesPath() const
The systems default solv file location.
Definition TargetImpl.cc:1104
zypp::target::TargetImpl::anonymousUniqueId
std::string anonymousUniqueId() const
anonymous unique id
Definition TargetImpl.cc:3163
zypp::target::TargetImpl::TargetImpl
TargetImpl(const Pathname &root_r="/", bool doRebuild_r=false)
Ctor.
Definition TargetImpl.cc:962
zypp::target::TargetImpl::solvfilesPathIsTemp
bool solvfilesPathIsTemp() const
Whether we're using a temp.
Definition TargetImpl.h:97
zypp::target::TargetImpl::targetDistributionFlavor
std::string targetDistributionFlavor() const
This is register.flavor attribute of the installed base product.
Definition TargetImpl.cc:3085
zypp::target::rpm::RpmDbOpenException
Definition RpmException.h:163
zypp::target::rpm::RpmDb
Interface to the rpm program.
Definition RpmDb.h:51
zypp::target::rpm::RpmDb::installPackage
void installPackage(const Pathname &filename, RpmInstFlags flags=RPMINST_NONE)
install rpm package
Definition RpmDb.cc:1652
zypp::target::rpm::RpmDb::initDatabase
void initDatabase(Pathname root_r=Pathname(), bool doRebuild_r=false)
Prepare access to the rpm database below root_r.
Definition RpmDb.cc:281
zypp::target::rpm::RpmDb::root
const Pathname & root() const
Definition RpmDb.h:109
zypp::target::rpm::RpmDb::removePackage
void removePackage(const std::string &name_r, RpmInstFlags flags=RPMINST_NONE)
remove rpm package
Definition RpmDb.cc:1854
zypp::target::rpm::RpmDb::dbPath
const Pathname & dbPath() const
Definition RpmDb.h:117
zypp::target::rpm::RpmDb::closeDatabase
void closeDatabase()
Block further access to the rpm database and go back to uninitialized state.
Definition RpmDb.cc:353
zypp::target::rpm::RpmDb::hasFile
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:956
zypp::target::rpm::RpmInitException
Definition RpmException.h:145
zypp::target::rpm::RpmSubprocessException
Definition RpmException.h:130
zypp::target::rpm::RpmTransactionFailedException
Definition RpmException.h:244
zypp::target::rpm::librpmDb::db_const_iterator
Subclass to retrieve rpm database content.
Definition librpmDb.h:198
zypp::target::rpm::librpmDb::db_const_iterator::findByProvides
bool findByProvides(const std::string &tag_r)
Reset to iterate all packages that provide a certain tag.
Definition librpmDb.cc:421
zyppng::AsyncDataSource::create
static Ptr create()
Definition asyncdatasource.cpp:146
zyppng::EventLoop::create
static Ptr create(GMainContext *ctx=nullptr)
Definition eventloop_glib.cc:29
zyppng::IODevice::sigChannelReadyRead
SignalProxy< void(uint)> sigChannelReadyRead()
Definition iodevice.cc:373
zyppng::Process::create
static Ptr create()
Definition process.cpp:49
zyppng::Process::StdErr
@ StdErr
Definition process.h:49
zyppng::Process::StdOut
@ StdOut
Definition process.h:48
zyppng::Process::sigFinished
SignalProxy< void(int)> sigFinished()
Definition process.cpp:294
zyppng::StompFrameStream::sigMessageReceived
SignalProxy< void()> sigMessageReceived()
Definition stompframestream.cc:310
zyppng::StompFrameStream::create
static Ptr create(IODevice::Ptr iostr)
Definition stompframestream.h:119
commitpackagepreloader_p.h
librpmDb.h
linuxhelpers_p.h
form
std::string form(const char *format,...) __attribute__((format(printf
Printf style construction of std::string.
Definition String.cc:39
std
Definition ansi.h:855
ztui::UNKNOWN
@ UNKNOWN
Definition richtext.cc:49
zypp::base
Definition Random.cc:7
zypp::env
Namespace intended to collect all environment variables we use.
Definition RepoVariables.cc:34
zypp::env::TRANSACTIONAL_UPDATE
bool TRANSACTIONAL_UPDATE()
Definition TargetImpl.cc:87
zypp::filesystem::chmod
int chmod(const Pathname &path, mode_t mode)
Like 'chmod'.
Definition PathInfo.cc:1111
zypp::filesystem::symlink
int symlink(const Pathname &oldpath, const Pathname &newpath)
Like 'symlink'.
Definition PathInfo.cc:874
zypp::filesystem::matchNoDots
const StrMatcher & matchNoDots()
Convenience returning StrMatcher( "[^.]*", Match::GLOB ).
Definition PathInfo.cc:26
zypp::filesystem::assert_file
int assert_file(const Pathname &path, unsigned mode)
Create an empty file if it does not yet exist.
Definition PathInfo.cc:1205
zypp::filesystem::recursive_rmdir
int recursive_rmdir(const Pathname &path)
Like 'rm -r DIR'.
Definition PathInfo.cc:431
zypp::filesystem::unlink
int unlink(const Pathname &path)
Like 'unlink'.
Definition PathInfo.cc:719
zypp::filesystem::readdir
int readdir(std::list< std::string > &retlist_r, const Pathname &path_r, bool dots_r)
Return content of directory via retlist.
Definition PathInfo.cc:624
zypp::filesystem::dirForEach
int dirForEach(const Pathname &dir_r, const StrMatcher &matcher_r, function< bool(const Pathname &, const char *const)> fnc_r)
Definition PathInfo.cc:32
zypp::filesystem::addmod
int addmod(const Pathname &path, mode_t mode)
Add the mode bits to the file given by path.
Definition PathInfo.cc:1123
zypp::filesystem::assert_dir
int assert_dir(const Pathname &path, unsigned mode)
Like 'mkdir -p'.
Definition PathInfo.cc:338
zypp::filesystem::readlink
int readlink(const Pathname &symlink_r, Pathname &target_r)
Like 'readlink'.
Definition PathInfo.cc:943
zypp::filesystem::md5sum
std::string md5sum(const Pathname &file)
Compute a files md5sum.
Definition PathInfo.cc:1043
zypp::filesystem::rename
int rename(const Pathname &oldpath, const Pathname &newpath)
Like 'rename'.
Definition PathInfo.cc:761
zypp::filesystem::touch
int touch(const Pathname &path)
Change file's modification and access times.
Definition PathInfo.cc:1256
zypp::iostr::getline
std::string getline(std::istream &str)
Read one line from stream.
Definition IOStream.cc:33
zypp::json
Definition TargetImpl.cc:153
zypp::json::toJSON
json::Value toJSON(const sat::Transaction::Step &step_r)
See COMMITBEGIN (added in v1) on page Commit plugin for the specs.
Definition TargetImpl.cc:158
zypp::pool
Definition ByIdent.h:24
zypp::sat::empty
bool empty() const
Whether neither idents nor provides are set.
zypp::sat::StringQueue
Queue StringQueue
Queue with String ids.
Definition Queue.h:28
zypp::sat::updateSolvFileIndex
void updateSolvFileIndex(const Pathname &solvfile_r)
Create solv file content digest for zypper bash completion.
Definition Pool.cc:286
zypp::str::hasPrefix
bool hasPrefix(const C_Str &str_r, const C_Str &prefix_r)
Return whether str_r has prefix prefix_r.
Definition String.h:1097
zypp::str::toLower
std::string toLower(const std::string &s)
Return lowercase version of s.
Definition String.cc:180
zypp::str::startsWith
bool startsWith(const C_Str &str_r, const C_Str &prefix_r)
alias for hasPrefix
Definition String.h:1155
zypp::str::endsWith
bool endsWith(const C_Str &str_r, const C_Str &prefix_r)
alias for hasSuffix
Definition String.h:1162
zypp::str::form
std::string form(const char *format,...) __attribute__((format(printf
Printf style construction of std::string.
Definition String.cc:39
zypp::str::strToBool
bool strToBool(const C_Str &str, bool default_r)
Parse str into a bool depending on the default value.
Definition String.h:500
zypp::str::splitEscaped
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:665
zypp::str::trim
std::string trim(const std::string &s, const Trim trim_r)
Definition String.cc:226
zypp::target::rpm::RPMINST_NOSIGNATURE
@ RPMINST_NOSIGNATURE
Definition RpmFlags.h:47
zypp::target::rpm::RPMINST_ALLOWUNTRUSTED
@ RPMINST_ALLOWUNTRUSTED
Definition RpmFlags.h:53
zypp::target::rpm::RPMINST_NODEPS
@ RPMINST_NODEPS
Definition RpmFlags.h:43
zypp::target::rpm::RPMINST_JUSTDB
@ RPMINST_JUSTDB
Definition RpmFlags.h:45
zypp::target::rpm::RPMINST_FORCE
@ RPMINST_FORCE
Definition RpmFlags.h:42
zypp::target::rpm::RPMINST_TEST
@ RPMINST_TEST
Definition RpmFlags.h:49
zypp::target::rpm::RPMINST_NODIGEST
@ RPMINST_NODIGEST
Definition RpmFlags.h:46
zypp::target::rpm::RPMINST_NOUPGRADE
@ RPMINST_NOUPGRADE
Definition RpmFlags.h:48
zypp::target::rpm::RPMINST_EXCLUDEDOCS
@ RPMINST_EXCLUDEDOCS
Definition RpmFlags.h:40
zypp::target
Definition KeyRing.h:325
zypp::target::IMPL_PTR_TYPE
IMPL_PTR_TYPE(TargetImpl)
zypp::target::XRunUpdateMessages
void XRunUpdateMessages(const Pathname &root_r, const Pathname &messagesPath_r, const std::vector< sat::Solvable > &checkPackages_r, ZYppCommitResult &result_r)
Definition TargetImpl.cc:947
zypp::target::rpmDbStateHash
std::string rpmDbStateHash(const Pathname &root_r)
Definition TargetImpl.cc:109
zypp::target::writeUpgradeTestcase
void writeUpgradeTestcase()
Definition TargetImpl.cc:501
zypp::target::fileMissing
static bool fileMissing(const Pathname &pathname)
helper functor
Definition TargetImpl.cc:1028
zypp::target::updateFileContent
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:993
zypp::target::rpmDbRepoStatus
RepoStatus rpmDbRepoStatus(const Pathname &root_r)
Definition TargetImpl.cc:127
zypp::target::generateRandomId
static std::string generateRandomId()
generates a random id using uuidgen
Definition TargetImpl.cc:982
zypp
Easy-to use interface to the ZYPP dependency resolver.
Definition CodePitfalls.doc:2
zypp::LocaleSet
std::unordered_set< Locale > LocaleSet
Definition Locale.h:29
zypp::getZYpp
ZYpp::Ptr getZYpp()
relates: ZYppFactory Convenience to get the Pointer to the ZYpp instance.
Definition ZYppFactory.h:77
zypp::ManagedFile
AutoDispose< const Pathname > ManagedFile
A Pathname plus associated cleanup code to be executed when path is no longer needed.
Definition ManagedFile.h:27
zypp::UpdateNotifications
std::list< UpdateNotificationFile > UpdateNotifications
Definition ZYppCommitResult.h:48
zypp::IdStringSet
std::unordered_set< IdString > IdStringSet
Definition IdString.h:37
zypp::make
ResTraits< TRes >::PtrType make(const sat::Solvable &solvable_r)
Directly create a certain kind of ResObject from sat::Solvable.
Definition ResObject.h:118
zypp::makeResObject
ResObject::Ptr makeResObject(const sat::Solvable &solvable_r)
Create ResObject from sat::Solvable.
Definition ResObject.cc:43
zypp::asString
std::string asString(const Patch::Category &obj)
relates: Patch::Category string representation.
Definition Patch.cc:122
zypp::asKind
ResTraits< TRes >::PtrType asKind(const sat::Solvable &solvable_r)
Directly create a certain kind of ResObject from sat::Solvable.
Definition ResObject.h:127
zypp::TrueBool
DefaultIntegral< bool, true > TrueBool
relates: DefaultIntegral true initialized bool
Definition defaultintegral.h:88
zypp::DownloadInHeaps
@ DownloadInHeaps
Definition DownloadMode.h:31
zypp::DownloadOnly
@ DownloadOnly
Definition DownloadMode.h:27
zypp::DownloadAsNeeded
@ DownloadAsNeeded
Definition DownloadMode.h:34
zypp::DownloadInAdvance
@ DownloadInAdvance
Definition DownloadMode.h:29
zypp::DownloadDefault
@ DownloadDefault
libzypp will decide what to do.
Definition DownloadMode.h:26
zyppng::IdString
zypp::IdString IdString
Definition idstring.h:16
zyppng::UserData
zypp::callback::UserData UserData
Definition userrequest.h:18
PoolImpl.h
stompframestream.h
zypp::Deferred
Definition AutoDispose.h:279
zypp::JobReport::error
static bool error(const std::string &msg_r, const UserData &userData_r=UserData())
send error text
Definition ZYppCallbacks.h:1140
zypp::Target::DistributionLabel
Definition Target.h:168
zypp::Target::DistributionLabel::shortName
std::string shortName
Definition Target.h:168
zypp::Target::DistributionLabel::summary
std::string summary
Definition Target.h:168
zypp::callback::ReceiveReport::connect
void connect()
Definition Callback.h:183
zypp::callback::SendReport
Definition Callback.h:237
zypp::callback::SendReport::connected
static bool connected()
Definition Callback.h:251
zypp::env::ScopedSet
Temporarily set/unset an environment variable.
Definition Env.h:45
zypp::functor::Constant
Definition Functional.h:59
zypp::sat::SolvableType::satSolvable
Solvable satSolvable() const
Return the corresponding sat::Solvable.
Definition SolvableType.h:57
zypp::sat::SolvableType::isNeedreboot
bool isNeedreboot() const
Definition SolvableType.h:83
zypp::sat::detail::PoolMember::myPool
static PoolImpl & myPool()
Definition PoolMember.cc:41
zypp::sat::detail::PoolMember::poolValid
static bool poolValid()
Definition PoolMember.cc:48
zypp::str::Format
Convenient building of std::string with boost::format.
Definition String.h:254
zypp::target::PatchScriptReport::ABORT
@ ABORT
Definition ZYppCallbacks.h:523
zypp::target::PatchScriptReport::RETRY
@ RETRY
Definition ZYppCallbacks.h:524
zypp::target::PatchScriptReport::IGNORE
@ IGNORE
Definition ZYppCallbacks.h:525
zypp::target::PatchScriptReport::OUTPUT
@ OUTPUT
Definition ZYppCallbacks.h:521
zypp::target::SendSingleTransReport
Convenience SendReport<rpm::SingleTransReport> wrapper.
Definition TargetImpl.cc:2051
zypp::target::SendSingleTransReport::report
void report(const callback::UserData &userData_r)
Definition TargetImpl.cc:2085
zypp::target::SendSingleTransReport::sendLoglineRpm
void sendLoglineRpm(const std::string &line_r, unsigned rpmlevel_r)
Convenience to send a contentLogline translating a rpm loglevel.
Definition TargetImpl.cc:2061
zypp::target::SendSingleTransReport::sendLogline
void sendLogline(const std::string &line_r, ReportType::loglevel level_r=ReportType::loglevel::msg)
Convenience to send a contentLogline.
Definition TargetImpl.cc:2053
zypp::target::rpm::CleanupPackageReportSA::NO_ERROR
@ NO_ERROR
Definition ZYppCallbacks.h:917
zypp::target::rpm::CommitScriptReportSA::CRITICAL
@ CRITICAL
Definition ZYppCallbacks.h:949
zypp::target::rpm::CommitScriptReportSA::WARN
@ WARN
Definition ZYppCallbacks.h:948
zypp::target::rpm::CommitScriptReportSA::NO_ERROR
@ NO_ERROR
Definition ZYppCallbacks.h:947
zypp::target::rpm::InstallResolvableReportSA::INVALID
@ INVALID
Definition ZYppCallbacks.h:852
zypp::target::rpm::InstallResolvableReportSA::NO_ERROR
@ NO_ERROR
Definition ZYppCallbacks.h:849
zypp::target::rpm::InstallResolvableReport::Error
Error
Definition ZYppCallbacks.h:632
zypp::target::rpm::InstallResolvableReport::RPM_NODEPS_FORCE
@ RPM_NODEPS_FORCE
only this one used
Definition ZYppCallbacks.h:644
zypp::target::rpm::InstallResolvableReport::RPM
@ RPM
Definition ZYppCallbacks.h:642
zypp::target::rpm::RemoveResolvableReportSA::INVALID
@ INVALID
Definition ZYppCallbacks.h:887
zypp::target::rpm::RemoveResolvableReportSA::NO_ERROR
@ NO_ERROR
Definition ZYppCallbacks.h:884
zypp::target::rpm::RemoveResolvableReport::Error
Error
Definition ZYppCallbacks.h:686
zypp::target::rpm::TransactionReportSA::NO_ERROR
@ NO_ERROR
Definition ZYppCallbacks.h:817
zyppng::Pipe::create
static std::optional< Pipe > create(int flags=0)
Definition linuxhelpers.cc:71
PathInfo.h
TmpPath.h