19 #include <sys/types.h>
73 inline void sigMultiversionSpecChanged()
75 sat::detail::PoolMember::myPool().multiversionSpecChanged();
91 for (
const Transaction::Step & step : steps_r )
93 if ( step.stepType() != Transaction::TRANSACTION_IGNORE )
103 static const std::string strType(
"type" );
104 static const std::string strStage(
"stage" );
105 static const std::string strSolvable(
"solvable" );
107 static const std::string strTypeDel(
"-" );
108 static const std::string strTypeIns(
"+" );
109 static const std::string strTypeMul(
"M" );
111 static const std::string strStageDone(
"ok" );
112 static const std::string strStageFailed(
"err" );
114 static const std::string strSolvableN(
"n" );
115 static const std::string strSolvableE(
"e" );
116 static const std::string strSolvableV(
"v" );
117 static const std::string strSolvableR(
"r" );
118 static const std::string strSolvableA(
"a" );
125 case Transaction::TRANSACTION_IGNORE:
break;
126 case Transaction::TRANSACTION_ERASE: ret.
add( strType, strTypeDel );
break;
127 case Transaction::TRANSACTION_INSTALL: ret.
add( strType, strTypeIns );
break;
128 case Transaction::TRANSACTION_MULTIINSTALL: ret.
add( strType, strTypeMul );
break;
133 case Transaction::STEP_TODO:
break;
134 case Transaction::STEP_DONE: ret.
add( strStage, strStageDone );
break;
135 case Transaction::STEP_ERROR: ret.
add( strStage, strStageFailed );
break;
144 ident = solv.ident();
151 ident = step_r.
ident();
153 arch = step_r.
arch();
158 { strSolvableV, ed.
version() },
159 { strSolvableR, ed.
release() },
163 s.add( strSolvableE, epoch );
165 ret.
add( strSolvable, s );
179 SolvIdentFile::Data getUserInstalledFromHistory(
const Pathname & historyFile_r )
181 SolvIdentFile::Data onSystemByUserList;
184 std::ifstream infile( historyFile_r.c_str() );
185 for( iostr::EachLine in( infile ); in; in.next() )
187 const char * ch( (*in).c_str() );
189 if ( *ch <
'1' ||
'9' < *ch )
191 const char * sep1 = ::strchr( ch,
'|' );
196 bool installs =
true;
197 if ( ::strncmp( sep1,
"install|", 8 ) )
199 if ( ::strncmp( sep1,
"remove |", 8 ) )
206 const char * sep2 = ::strchr( sep1,
'|' );
207 if ( !sep2 || sep1 == sep2 )
209 (*in)[sep2-ch] =
'\0';
210 IdString pkg( sep1 );
214 onSystemByUserList.erase( pkg );
218 if ( (sep1 = ::strchr( sep2+1,
'|' ))
219 && (sep1 = ::strchr( sep1+1,
'|' ))
220 && (sep2 = ::strchr( sep1+1,
'|' )) )
222 (*in)[sep2-ch] =
'\0';
223 if ( ::strchr( sep1+1,
'@' ) )
226 onSystemByUserList.insert( pkg );
231 MIL <<
"onSystemByUserList found: " << onSystemByUserList.size() << endl;
232 return onSystemByUserList;
240 inline PluginFrame transactionPluginFrame(
const std::string & command_r, ZYppCommitResult::TransactionStepList & steps_r )
242 return PluginFrame( command_r, json::Object {
243 {
"TransactionStepList", steps_r }
252 unsigned toKeep( ZConfig::instance().solver_upgradeTestcasesToKeep() );
253 MIL <<
"Testcases to keep: " << toKeep << endl;
259 WAR <<
"No Target no Testcase!" << endl;
263 std::string stem(
"updateTestcase" );
264 Pathname dir( target->assertRootPrefix(
"/var/log/") );
265 Pathname next( dir / Date::now().
form( stem+
"-%Y-%m-%d-%H-%M-%S" ) );
268 std::list<std::string> content;
270 std::set<std::string> cases;
271 for_( c, content.begin(), content.end() )
276 if ( cases.size() >= toKeep )
278 unsigned toDel = cases.size() - toKeep + 1;
279 for_( c, cases.begin(), cases.end() )
288 MIL <<
"Write new testcase " << next << endl;
289 getZYpp()->resolver()->createSolverTestcase( next.asString(),
false );
306 std::pair<bool,PatchScriptReport::Action> doExecuteScript(
const Pathname & root_r,
307 const Pathname & script_r,
310 MIL <<
"Execute script " << PathInfo(Pathname::assertprefix( root_r,script_r)) << endl;
313 historylog.
comment(script_r.asString() +
_(
" executed"),
true);
314 ExternalProgram prog( script_r.asString(), ExternalProgram::Stderr_To_Stdout,
false, -1,
true, root_r );
316 for ( std::string output = prog.receiveLine(); output.length(); output = prog.receiveLine() )
319 if ( ! report_r->progress( PatchScriptReport::OUTPUT, output ) )
321 WAR <<
"User request to abort script " << script_r << endl;
328 std::pair<bool,PatchScriptReport::Action> ret( std::make_pair(
false, PatchScriptReport::ABORT ) );
330 if ( prog.close() != 0 )
332 ret.second = report_r->problem( prog.execError() );
333 WAR <<
"ACTION" << ret.second <<
"(" << prog.execError() <<
")" << endl;
334 std::ostringstream sstr;
335 sstr << script_r <<
_(
" execution failed") <<
" (" << prog.execError() <<
")" << endl;
336 historylog.
comment(sstr.str(),
true);
348 bool executeScript(
const Pathname & root_r,
349 const Pathname & script_r,
350 callback::SendReport<PatchScriptReport> & report_r )
352 std::pair<bool,PatchScriptReport::Action> action( std::make_pair(
false, PatchScriptReport::ABORT ) );
355 action = doExecuteScript( root_r, script_r, report_r );
359 switch ( action.second )
361 case PatchScriptReport::ABORT:
362 WAR <<
"User request to abort at script " << script_r << endl;
366 case PatchScriptReport::IGNORE:
367 WAR <<
"User request to skip script " << script_r << endl;
371 case PatchScriptReport::RETRY:
374 }
while ( action.second == PatchScriptReport::RETRY );
377 INT <<
"Abort on unknown ACTION request " << action.second <<
" returned" << endl;
386 bool RunUpdateScripts(
const Pathname & root_r,
387 const Pathname & scriptsPath_r,
388 const std::vector<sat::Solvable> & checkPackages_r,
391 if ( checkPackages_r.empty() )
394 MIL <<
"Looking for new update scripts in (" << root_r <<
")" << scriptsPath_r << endl;
395 Pathname scriptsDir( Pathname::assertprefix( root_r, scriptsPath_r ) );
396 if ( ! PathInfo( scriptsDir ).isDir() )
399 std::list<std::string> scripts;
401 if ( scripts.empty() )
409 std::map<std::string, Pathname> unify;
410 for_( it, checkPackages_r.begin(), checkPackages_r.end() )
412 std::string prefix(
str::form(
"%s-%s", it->name().c_str(), it->edition().c_str() ) );
413 for_( sit, scripts.begin(), scripts.end() )
418 if ( (*sit)[prefix.size()] !=
'\0' && (*sit)[prefix.size()] !=
'-' )
421 PathInfo script( scriptsDir / *sit );
422 Pathname localPath( scriptsPath_r/(*sit) );
423 std::string unifytag;
425 if ( script.isFile() )
431 else if ( ! script.isExist() )
439 if ( unifytag.empty() )
443 if ( unify[unifytag].empty() )
445 unify[unifytag] = localPath;
452 std::string msg(
str::form(
_(
"%s already executed as %s)"), localPath.asString().c_str(), unify[unifytag].c_str() ) );
453 MIL <<
"Skip update script: " << msg << endl;
454 HistoryLog().comment( msg,
true );
458 if ( abort || aborting_r )
460 WAR <<
"Aborting: Skip update script " << *sit << endl;
461 HistoryLog().comment(
462 localPath.asString() +
_(
" execution skipped while aborting"),
467 MIL <<
"Found update script " << *sit << endl;
468 callback::SendReport<PatchScriptReport>
report;
469 report->start( make<Package>( *it ), script.path() );
471 if ( ! executeScript( root_r, localPath, report ) )
483 inline void copyTo( std::ostream & out_r,
const Pathname & file_r )
485 std::ifstream infile( file_r.c_str() );
486 for( iostr::EachLine in( infile ); in; in.next() )
488 out_r << *in << endl;
492 inline std::string notificationCmdSubst(
const std::string & cmd_r,
const UpdateNotificationFile & notification_r )
494 std::string ret( cmd_r );
495 #define SUBST_IF(PAT,VAL) if ( ret.find( PAT ) != std::string::npos ) ret = str::gsub( ret, PAT, VAL )
496 SUBST_IF(
"%p", notification_r.solvable().asString() );
497 SUBST_IF(
"%P", notification_r.file().asString() );
502 void sendNotification(
const Pathname & root_r,
505 if ( notifications_r.empty() )
508 std::string cmdspec( ZConfig::instance().updateMessagesNotify() );
509 MIL <<
"Notification command is '" << cmdspec <<
"'" << endl;
510 if ( cmdspec.empty() )
514 if ( pos == std::string::npos )
516 ERR <<
"Can't send Notification: Missing 'format |' in command spec." << endl;
517 HistoryLog().comment( str::Str() <<
_(
"Error sending update message notification."),
true );
522 std::string commandStr(
str::trim( cmdspec.substr( pos + 1 ) ) );
524 enum Format { UNKNOWN, NONE, SINGLE, DIGEST, BULK };
525 Format format = UNKNOWN;
526 if ( formatStr ==
"none" )
528 else if ( formatStr ==
"single" )
530 else if ( formatStr ==
"digest" )
532 else if ( formatStr ==
"bulk" )
536 ERR <<
"Can't send Notification: Unknown format '" << formatStr <<
" |' in command spec." << endl;
537 HistoryLog().comment( str::Str() <<
_(
"Error sending update message notification."),
true );
545 if ( format == NONE || format == SINGLE )
547 for_( it, notifications_r.begin(), notifications_r.end() )
549 std::vector<std::string> command;
550 if ( format == SINGLE )
551 command.push_back(
"<"+Pathname::assertprefix( root_r, it->file() ).
asString() );
552 str::splitEscaped( notificationCmdSubst( commandStr, *it ), std::back_inserter( command ) );
554 ExternalProgram prog( command, ExternalProgram::Stderr_To_Stdout,
false, -1,
true, root_r );
557 for( std::string line = prog.receiveLine(); ! line.empty(); line = prog.receiveLine() )
561 int ret = prog.close();
564 ERR <<
"Notification command returned with error (" << ret <<
")." << endl;
565 HistoryLog().comment( str::Str() <<
_(
"Error sending update message notification."),
true );
571 else if ( format == DIGEST || format == BULK )
573 filesystem::TmpFile tmpfile;
574 ofstream out( tmpfile.path().c_str() );
575 for_( it, notifications_r.begin(), notifications_r.end() )
577 if ( format == DIGEST )
579 out << it->file() << endl;
581 else if ( format == BULK )
583 copyTo( out <<
'\f', Pathname::assertprefix( root_r, it->file() ) );
587 std::vector<std::string> command;
588 command.push_back(
"<"+tmpfile.path().asString() );
589 str::splitEscaped( notificationCmdSubst( commandStr, *notifications_r.begin() ), std::back_inserter( command ) );
591 ExternalProgram prog( command, ExternalProgram::Stderr_To_Stdout,
false, -1,
true, root_r );
594 for( std::string line = prog.receiveLine(); ! line.empty(); line = prog.receiveLine() )
598 int ret = prog.close();
601 ERR <<
"Notification command returned with error (" << ret <<
")." << endl;
602 HistoryLog().comment( str::Str() <<
_(
"Error sending update message notification."),
true );
609 INT <<
"Can't send Notification: Missing handler for 'format |' in command spec." << endl;
610 HistoryLog().comment( str::Str() <<
_(
"Error sending update message notification."),
true );
621 void RunUpdateMessages(
const Pathname & root_r,
622 const Pathname & messagesPath_r,
623 const std::vector<sat::Solvable> & checkPackages_r,
624 ZYppCommitResult & result_r )
626 if ( checkPackages_r.empty() )
629 MIL <<
"Looking for new update messages in (" << root_r <<
")" << messagesPath_r << endl;
630 Pathname messagesDir( Pathname::assertprefix( root_r, messagesPath_r ) );
631 if ( ! PathInfo( messagesDir ).isDir() )
634 std::list<std::string> messages;
636 if ( messages.empty() )
642 HistoryLog historylog;
643 for_( it, checkPackages_r.begin(), checkPackages_r.end() )
645 std::string prefix(
str::form(
"%s-%s", it->name().c_str(), it->edition().c_str() ) );
646 for_( sit, messages.begin(), messages.end() )
651 if ( (*sit)[prefix.size()] !=
'\0' && (*sit)[prefix.size()] !=
'-' )
654 PathInfo message( messagesDir / *sit );
655 if ( ! message.isFile() || message.size() == 0 )
658 MIL <<
"Found update message " << *sit << endl;
659 Pathname localPath( messagesPath_r/(*sit) );
660 result_r.rUpdateMessages().push_back( UpdateNotificationFile( *it, localPath ) );
661 historylog.comment( str::Str() <<
_(
"New update message") <<
" " << localPath,
true );
664 sendNotification( root_r, result_r.updateMessages() );
672 const Pathname & messagesPath_r,
673 const std::vector<sat::Solvable> & checkPackages_r,
675 { RunUpdateMessages( root_r, messagesPath_r, checkPackages_r, result_r ); }
686 TargetImpl::TargetImpl(
const Pathname & root_r,
bool doRebuild_r )
688 , _requestedLocalesFile( home() /
"RequestedLocales" )
689 , _autoInstalledFile( home() /
"AutoInstalled" )
690 , _hardLocksFile( Pathname::assertprefix(
_root,
ZConfig::instance().locksFile() ) )
697 sigMultiversionSpecChanged();
698 MIL <<
"Initialized target on " <<
_root << endl;
706 std::ifstream uuidprovider(
"/proc/sys/kernel/random/uuid" );
716 boost::function<
bool ()> condition,
717 boost::function<
string ()> value )
719 string val = value();
727 MIL <<
"updating '" << filename <<
"' content." << endl;
731 std::ofstream filestr;
734 filestr.open( filename.c_str() );
736 if ( filestr.good() )
752 return ! PathInfo(pathname).isExist();
762 Pathname idpath(
home() /
"AnonymousUniqueId");
772 WAR <<
"Can't create anonymous id file" << endl;
781 Pathname flavorpath(
home() /
"LastDistributionFlavor");
787 WAR <<
"No base product, I won't create flavor cache" << endl;
791 string flavor = p->flavor();
803 WAR <<
"Can't create flavor cache" << endl;
816 sigMultiversionSpecChanged();
817 MIL <<
"Targets closed" << endl;
840 Pathname rpmsolv = base/
"solv";
841 Pathname rpmsolvcookie = base/
"cookie";
843 bool build_rpm_solv =
true;
848 bool solvexisted = PathInfo(rpmsolv).isExist();
852 PathInfo cookie( rpmsolvcookie );
853 MIL <<
"Read cookie: " << cookie << endl;
854 if ( cookie.isExist() )
858 if ( status == rpmstatus )
859 build_rpm_solv =
false;
860 MIL <<
"Read cookie: " << rpmsolvcookie <<
" says: "
861 << (build_rpm_solv ?
"outdated" :
"uptodate") << endl;
865 if ( build_rpm_solv )
870 Pathname oldSolvFile( solvexisted ? rpmsolv : Pathname() );
879 bool switchingToTmpSolvfile =
false;
880 Exception ex(
"Failed to cache rpm database.");
886 rpmsolv = base/
"solv";
887 rpmsolvcookie = base/
"cookie";
894 WAR <<
"Using a temporary solv file at " << base << endl;
895 switchingToTmpSolvfile =
true;
904 if ( ! switchingToTmpSolvfile )
914 cmd.push_back(
"rpmdb2solv" );
915 if ( !
_root.empty() ) {
916 cmd.push_back(
"-r" );
917 cmd.push_back(
_root.asString() );
919 cmd.push_back(
"-X" );
921 cmd.push_back(
"-p" );
922 cmd.push_back( Pathname::assertprefix(
_root,
"/etc/products.d" ).
asString() );
924 if ( ! oldSolvFile.empty() )
925 cmd.push_back( oldSolvFile.asString() );
927 cmd.push_back(
"-o" );
931 std::string errdetail;
934 WAR <<
" " << output;
935 if ( errdetail.empty() ) {
942 int ret = prog.
close();
974 if ( ! PathInfo(base/
"solv.idx").isExist() )
977 return build_rpm_solv;
995 MIL <<
"New cache built: " << (newCache?
"true":
"false") <<
996 ", force loading: " << (force?
"true":
"false") << endl;
1001 MIL <<
"adding " << rpmsolv <<
" to pool(" << satpool.
systemRepoAlias() <<
")" << endl;
1008 if ( newCache || force )
1025 MIL <<
"adding " << rpmsolv <<
" to system" << endl;
1031 MIL <<
"Try to handle exception by rebuilding the solv-file" << endl;
1056 if ( PathInfo( historyFile ).isExist() )
1063 if ( onSystemByUser.find( ident ) == onSystemByUser.end() )
1064 onSystemByAuto.insert( ident );
1083 if ( PathInfo( needrebootFile ).isFile() )
1084 needrebootSpec.
parseFrom( needrebootFile );
1087 if ( PathInfo( needrebootDir ).isDir() )
1092 [&](
const Pathname & dir_r,
const char *
const str_r )->
bool
1094 if ( ! isRpmConfigBackup( str_r ) )
1096 Pathname needrebootFile { needrebootDir / str_r };
1097 if ( PathInfo( needrebootFile ).isFile() )
1098 needrebootSpec.
parseFrom( needrebootFile );
1109 if ( ! hardLocks.empty() )
1118 MIL <<
"Target loaded: " << system.
solvablesSize() <<
" resolvables" << endl;
1130 bool explicitDryRun = policy_r.
dryRun();
1140 if (
root() ==
"/" )
1150 MIL <<
"TargetImpl::commit(<pool>, " << policy_r <<
")" << endl;
1169 steps.push_back( *it );
1176 MIL <<
"Todo: " << result << endl;
1186 if ( commitPlugins )
1187 commitPlugins.
send( transactionPluginFrame(
"COMMITBEGIN", steps ) );
1194 if ( ! policy_r.
dryRun() )
1200 DBG <<
"dryRun: Not writing upgrade testcase." << endl;
1207 if ( ! policy_r.
dryRun() )
1229 DBG <<
"dryRun: Not stroring non-package data." << endl;
1236 if ( ! policy_r.
dryRun() )
1238 for_( it, steps.begin(), steps.end() )
1240 if ( ! it->satSolvable().isKind<
Patch>() )
1248 if ( ! patch ||patch->message().empty() )
1251 MIL <<
"Show message for " << patch << endl;
1253 if ( ! report->show( patch ) )
1255 WAR <<
"commit aborted by the user" << endl;
1262 DBG <<
"dryRun: Not checking patch messages." << endl;
1281 for_( it, steps.begin(), steps.end() )
1283 switch ( it->stepType() )
1302 localfile = packageCache.
get( pi );
1305 catch (
const AbortRequestException & exp )
1309 WAR <<
"commit cache preload aborted by the user" << endl;
1313 catch (
const SkipRequestException & exp )
1318 WAR <<
"Skipping cache preload package " << pi->asKind<
Package>() <<
" in commit" << endl;
1328 INT <<
"Unexpected Error: Skipping cache preload package " << pi->asKind<
Package>() <<
" in commit" << endl;
1338 ERR <<
"Some packages could not be provided. Aborting commit."<< endl;
1342 if ( ! policy_r.
dryRun() )
1346 commit( policy_r, packageCache, result );
1350 DBG <<
"dryRun/downloadOnly: Not installing/deleting anything." << endl;
1351 if ( explicitDryRun ) {
1360 DBG <<
"dryRun: Not downloading/installing/deleting anything." << endl;
1361 if ( explicitDryRun ) {
1370 if ( commitPlugins )
1371 commitPlugins.
send( transactionPluginFrame(
"COMMITEND", steps ) );
1376 if ( ! policy_r.
dryRun() )
1381 MIL <<
"TargetImpl::commit(<pool>, " << policy_r <<
") returns: " << result << endl;
1392 struct NotifyAttemptToModify
1410 MIL <<
"TargetImpl::commit(<list>" << policy_r <<
")" << steps.size() << endl;
1415 NotifyAttemptToModify attemptToModify( result_r );
1420 std::vector<sat::Solvable> successfullyInstalledPackages;
1423 for_( step, steps.begin(), steps.end() )
1445 localfile = packageCache_r.
get( citem );
1447 catch (
const AbortRequestException &e )
1449 WAR <<
"commit aborted by the user" << endl;
1454 catch (
const SkipRequestException &e )
1457 WAR <<
"Skipping package " << p <<
" in commit" << endl;
1466 INT <<
"Unexpected Error: Skipping package " << p <<
" in commit" << endl;
1471 #warning Exception handling
1476 bool success =
false;
1502 if ( progress.aborted() )
1504 WAR <<
"commit aborted by the user" << endl;
1513 auto rebootNeededFile =
root() /
"/var/run/reboot-needed";
1529 WAR <<
"dry run failed" << endl;
1534 if ( progress.aborted() )
1536 WAR <<
"commit aborted by the user" << endl;
1541 WAR <<
"Install failed" << endl;
1547 if ( success && !policy_r.
dryRun() )
1550 successfullyInstalledPackages.push_back( citem.
satSolvable() );
1559 bool success =
false;
1570 if ( progress.aborted() )
1572 WAR <<
"commit aborted by the user" << endl;
1586 if ( progress.aborted() )
1588 WAR <<
"commit aborted by the user" << endl;
1594 WAR <<
"removal of " << p <<
" failed";
1597 if ( success && !policy_r.
dryRun() )
1604 else if ( ! policy_r.
dryRun() )
1608 if ( ! citem.
buddy() )
1615 ERR <<
"Can't install orphan product without release-package! " << citem << endl;
1621 std::string referenceFilename( p->referenceFilename() );
1622 if ( referenceFilename.empty() )
1624 ERR <<
"Can't remove orphan product without 'referenceFilename'! " << citem << endl;
1628 Pathname referencePath { Pathname(
"/etc/products.d") / referenceFilename };
1629 if ( !
rpm().hasFile( referencePath.asString() ) )
1632 referencePath = Pathname::assertprefix(
_root, referencePath );
1634 ERR <<
"Delete orphan product failed: " << referencePath << endl;
1638 WAR <<
"Won't remove orphan product: '/etc/products.d/" << referenceFilename <<
"' is owned by a package." << endl;
1665 if ( ! successfullyInstalledPackages.empty() )
1668 successfullyInstalledPackages, abort ) )
1670 WAR <<
"Commit aborted by the user" << endl;
1676 successfullyInstalledPackages,
1710 PathInfo baseproduct( Pathname::assertprefix( root_r,
"/etc/products.d/baseproduct" ) );
1712 if ( baseproduct.isFile() )
1723 else if ( PathInfo( Pathname::assertprefix( root_r,
"/etc/products.d" ) ).isDir() )
1725 ERR <<
"baseproduct symlink is dangling or missing: " << baseproduct << endl;
1730 inline Pathname staticGuessRoot(
const Pathname & root_r )
1732 if ( root_r.empty() )
1737 return Pathname(
"/");
1743 inline std::string firstNonEmptyLineIn(
const Pathname & file_r )
1745 std::ifstream idfile( file_r.c_str() );
1746 for( iostr::EachLine in( idfile ); in; in.next() )
1749 if ( ! line.empty() )
1752 return std::string();
1763 if ( p->isTargetDistribution() )
1771 const Pathname needroot( staticGuessRoot(root_r) );
1772 const Target_constPtr target( getZYpp()->getTarget() );
1773 if ( target && target->root() == needroot )
1774 return target->requestedLocales();
1780 MIL <<
"updateAutoInstalled if changed..." << endl;
1788 {
return baseproductdata(
_root ).registerTarget(); }
1791 {
return baseproductdata( staticGuessRoot(root_r) ).registerTarget(); }
1794 {
return baseproductdata(
_root ).registerRelease(); }
1797 {
return baseproductdata( staticGuessRoot(root_r) ).registerRelease();}
1800 {
return baseproductdata(
_root ).registerFlavor(); }
1803 {
return baseproductdata( staticGuessRoot(root_r) ).registerFlavor();}
1836 std::string
distributionVersion = baseproductdata( staticGuessRoot(root_r) ).edition().version();
1837 if ( distributionVersion.empty() )
1843 scoped_ptr<rpm::RpmDb> tmprpmdb;
1849 tmprpmdb->initDatabase( );
1858 distributionVersion = it->tag_version();
1866 return firstNonEmptyLineIn(
home() /
"LastDistributionFlavor" );
1871 return firstNonEmptyLineIn( staticGuessRoot(root_r) /
"/var/lib/zypp/LastDistributionFlavor" );
1877 std::string guessAnonymousUniqueId(
const Pathname & root_r )
1880 std::string ret( firstNonEmptyLineIn( root_r /
"/var/lib/zypp/AnonymousUniqueId" ) );
1881 if ( ret.
empty() && root_r !=
"/" )
1884 ret = firstNonEmptyLineIn(
"/var/lib/zypp/AnonymousUniqueId" );
1892 return guessAnonymousUniqueId(
root() );
1897 return guessAnonymousUniqueId( staticGuessRoot(root_r) );