19 #include <sys/types.h>
86 for_( it, _scripts.begin(), _scripts.end() )
88 MIL <<
"Unload plugin: " << *it << endl;
92 if ( ! ret.isAckCommand() )
94 WAR <<
"Failed to unload plugin: Bad plugin response." << endl;
100 WAR <<
"Failed to unload plugin." << endl;
112 void load(
const Pathname & path_r )
114 PathInfo pi( path_r );
117 std::list<Pathname> entries;
120 WAR <<
"Plugin dir is not readable: " << pi << endl;
123 for_( it, entries.begin(), entries.end() )
126 if ( pii.isFile() && pii.userMayRX() )
130 else if ( pi.isFile() )
132 if ( pi.userMayRX() )
135 WAR <<
"Plugin file is not executable: " << pi << endl;
139 WAR <<
"Plugin path is neither dir nor file: " << pi << endl;
144 void doLoad(
const PathInfo & pi_r )
146 MIL <<
"Load plugin: " << pi_r << endl;
152 if ( ret.isAckCommand() )
154 _scripts.push_back( plugin );
158 WAR <<
"Failed to load plugin: Bad plugin response." << endl;
163 WAR <<
"Failed to load plugin." << endl;
173 USR <<
"+++++" << endl;
177 USR <<
"=====" << endl;
179 USR <<
"-----" << endl;
187 unsigned toKeep( ZConfig::instance().solver_upgradeTestcasesToKeep() );
188 MIL <<
"Testcases to keep: " << toKeep << endl;
191 Target_Ptr target( getZYpp()->getTarget() );
194 WAR <<
"No Target no Testcase!" << endl;
198 std::string stem(
"updateTestcase" );
199 Pathname dir( target->assertRootPrefix(
"/var/log/") );
200 Pathname next( dir / Date::now().
form( stem+
"-%Y-%m-%d-%H-%M-%S" ) );
203 std::list<std::string> content;
205 std::set<std::string> cases;
206 for_( c, content.begin(), content.end() )
211 if ( cases.size() >= toKeep )
213 unsigned toDel = cases.size() - toKeep + 1;
214 for_( c, cases.begin(), cases.end() )
223 MIL <<
"Write new testcase " << next << endl;
224 getZYpp()->resolver()->createSolverTestcase( next.asString(),
false );
241 std::pair<bool,PatchScriptReport::Action> doExecuteScript(
const Pathname & root_r,
242 const Pathname & script_r,
245 MIL <<
"Execute script " << PathInfo(Pathname::assertprefix( root_r,script_r)) << endl;
248 historylog.
comment(script_r.asString() +
_(
" executed"),
true);
249 ExternalProgram prog( script_r.asString(), ExternalProgram::Stderr_To_Stdout,
false, -1,
true, root_r );
251 for ( std::string output = prog.receiveLine(); output.length(); output = prog.receiveLine() )
254 if ( ! report_r->progress( PatchScriptReport::OUTPUT, output ) )
256 WAR <<
"User request to abort script " << script_r << endl;
263 std::pair<bool,PatchScriptReport::Action> ret( std::make_pair(
false, PatchScriptReport::ABORT ) );
265 if ( prog.close() != 0 )
267 ret.second = report_r->problem( prog.execError() );
268 WAR <<
"ACTION" << ret.second <<
"(" << prog.execError() <<
")" << endl;
269 std::ostringstream sstr;
270 sstr << script_r <<
_(
" execution failed") <<
" (" << prog.execError() <<
")" << endl;
271 historylog.
comment(sstr.str(),
true);
283 bool executeScript(
const Pathname & root_r,
284 const Pathname & script_r,
285 callback::SendReport<PatchScriptReport> & report_r )
287 std::pair<bool,PatchScriptReport::Action> action( std::make_pair(
false, PatchScriptReport::ABORT ) );
290 action = doExecuteScript( root_r, script_r, report_r );
294 switch ( action.second )
296 case PatchScriptReport::ABORT:
297 WAR <<
"User request to abort at script " << script_r << endl;
301 case PatchScriptReport::IGNORE:
302 WAR <<
"User request to skip script " << script_r << endl;
306 case PatchScriptReport::RETRY:
309 }
while ( action.second == PatchScriptReport::RETRY );
312 INT <<
"Abort on unknown ACTION request " << action.second <<
" returned" << endl;
321 bool RunUpdateScripts(
const Pathname & root_r,
322 const Pathname & scriptsPath_r,
323 const std::vector<sat::Solvable> & checkPackages_r,
326 if ( checkPackages_r.empty() )
329 MIL <<
"Looking for new update scripts in (" << root_r <<
")" << scriptsPath_r << endl;
330 Pathname scriptsDir( Pathname::assertprefix( root_r, scriptsPath_r ) );
331 if ( ! PathInfo( scriptsDir ).isDir() )
334 std::list<std::string> scripts;
336 if ( scripts.empty() )
344 for_( it, checkPackages_r.begin(), checkPackages_r.end() )
346 std::string prefix(
str::form(
"%s-%s", it->name().c_str(), it->edition().c_str() ) );
347 for_( sit, scripts.begin(), scripts.end() )
352 if ( (*sit)[prefix.size()] !=
'\0' && (*sit)[prefix.size()] !=
'-' )
355 PathInfo script( scriptsDir / *sit );
356 if ( ! script.isFile() )
362 Pathname localPath( scriptsPath_r/(*sit) );
363 if ( abort || aborting_r )
365 WAR <<
"Aborting: Skip update script " << *sit << endl;
366 HistoryLog().comment(
367 localPath.asString() +
_(
" execution skipped while aborting"),
372 MIL <<
"Found update script " << *sit << endl;
373 callback::SendReport<PatchScriptReport>
report;
374 report->start( make<Package>( *it ), script.path() );
376 if ( ! executeScript( root_r, localPath, report ) )
388 inline void copyTo( std::ostream & out_r,
const Pathname & file_r )
390 std::ifstream infile( file_r.c_str() );
391 for( iostr::EachLine in( infile ); in; in.next() )
393 out_r << *in << endl;
397 inline std::string notificationCmdSubst(
const std::string & cmd_r,
const UpdateNotificationFile & notification_r )
399 std::string ret( cmd_r );
400 #define SUBST_IF(PAT,VAL) if ( ret.find( PAT ) != std::string::npos ) ret = str::gsub( ret, PAT, VAL )
401 SUBST_IF(
"%p", notification_r.solvable().asString() );
402 SUBST_IF(
"%P", notification_r.file().asString() );
407 void sendNotification(
const Pathname & root_r,
410 if ( notifications_r.empty() )
413 std::string cmdspec( ZConfig::instance().updateMessagesNotify() );
414 MIL <<
"Notification command is '" << cmdspec <<
"'" << endl;
415 if ( cmdspec.empty() )
419 if ( pos == std::string::npos )
421 ERR <<
"Can't send Notification: Missing 'format |' in command spec." << endl;
422 HistoryLog().comment( str::Str() <<
_(
"Error sending update message notification."),
true );
427 std::string commandStr(
str::trim( cmdspec.substr( pos + 1 ) ) );
429 enum Format { UNKNOWN, NONE, SINGLE, DIGEST, BULK };
430 Format format = UNKNOWN;
431 if ( formatStr ==
"none" )
433 else if ( formatStr ==
"single" )
435 else if ( formatStr ==
"digest" )
437 else if ( formatStr ==
"bulk" )
441 ERR <<
"Can't send Notification: Unknown format '" << formatStr <<
" |' in command spec." << endl;
442 HistoryLog().comment( str::Str() <<
_(
"Error sending update message notification."),
true );
450 if ( format == NONE || format == SINGLE )
452 for_( it, notifications_r.begin(), notifications_r.end() )
454 std::vector<std::string> command;
455 if ( format == SINGLE )
456 command.push_back(
"<"+Pathname::assertprefix( root_r, it->file() ).
asString() );
457 str::splitEscaped( notificationCmdSubst( commandStr, *it ), std::back_inserter( command ) );
459 ExternalProgram prog( command, ExternalProgram::Stderr_To_Stdout,
false, -1,
true, root_r );
462 for( std::string line = prog.receiveLine(); ! line.empty(); line = prog.receiveLine() )
466 int ret = prog.close();
469 ERR <<
"Notification command returned with error (" << ret <<
")." << endl;
470 HistoryLog().comment( str::Str() <<
_(
"Error sending update message notification."),
true );
476 else if ( format == DIGEST || format == BULK )
478 filesystem::TmpFile tmpfile;
479 ofstream out( tmpfile.path().c_str() );
480 for_( it, notifications_r.begin(), notifications_r.end() )
482 if ( format == DIGEST )
484 out << it->file() << endl;
486 else if ( format == BULK )
488 copyTo( out <<
'\f', Pathname::assertprefix( root_r, it->file() ) );
492 std::vector<std::string> command;
493 command.push_back(
"<"+tmpfile.path().asString() );
494 str::splitEscaped( notificationCmdSubst( commandStr, *notifications_r.begin() ), std::back_inserter( command ) );
496 ExternalProgram prog( command, ExternalProgram::Stderr_To_Stdout,
false, -1,
true, root_r );
499 for( std::string line = prog.receiveLine(); ! line.empty(); line = prog.receiveLine() )
503 int ret = prog.close();
506 ERR <<
"Notification command returned with error (" << ret <<
")." << endl;
507 HistoryLog().comment( str::Str() <<
_(
"Error sending update message notification."),
true );
514 INT <<
"Can't send Notification: Missing handler for 'format |' in command spec." << endl;
515 HistoryLog().comment( str::Str() <<
_(
"Error sending update message notification."),
true );
526 void RunUpdateMessages(
const Pathname & root_r,
527 const Pathname & messagesPath_r,
528 const std::vector<sat::Solvable> & checkPackages_r,
529 ZYppCommitResult & result_r )
531 if ( checkPackages_r.empty() )
534 MIL <<
"Looking for new update messages in (" << root_r <<
")" << messagesPath_r << endl;
535 Pathname messagesDir( Pathname::assertprefix( root_r, messagesPath_r ) );
536 if ( ! PathInfo( messagesDir ).isDir() )
539 std::list<std::string> messages;
541 if ( messages.empty() )
547 HistoryLog historylog;
548 for_( it, checkPackages_r.begin(), checkPackages_r.end() )
550 std::string prefix(
str::form(
"%s-%s", it->name().c_str(), it->edition().c_str() ) );
551 for_( sit, messages.begin(), messages.end() )
556 if ( (*sit)[prefix.size()] !=
'\0' && (*sit)[prefix.size()] !=
'-' )
559 PathInfo message( messagesDir / *sit );
560 if ( ! message.isFile() || message.size() == 0 )
563 MIL <<
"Found update message " << *sit << endl;
564 Pathname localPath( messagesPath_r/(*sit) );
565 result_r.rUpdateMessages().push_back( UpdateNotificationFile( *it, localPath ) );
566 historylog.comment( str::Str() <<
_(
"New update message") <<
" " << localPath,
true );
569 sendNotification( root_r, result_r.updateMessages() );
577 const Pathname & messagesPath_r,
578 const std::vector<sat::Solvable> & checkPackages_r,
580 { RunUpdateMessages( root_r, messagesPath_r, checkPackages_r, result_r ); }
585 bool operator()(
const std::string & name_r,
587 const Arch & arch_r )
const
592 if ( arch_r == it->tag_arch()
593 && ( ed_r == Edition::noedition || ed_r == it->tag_edition() ) )
613 : _pool(pool_r), _access(access)
627 std::list<Repository> repos( _pool.knownRepositoriesBegin(), _pool.knownRepositoriesEnd() );
639 TargetImpl_Ptr TargetImpl::_nullimpl;
642 TargetImpl_Ptr TargetImpl::nullimpl()
654 TargetImpl::TargetImpl(
const Pathname & root_r,
bool doRebuild_r )
656 , _requestedLocalesFile( home() /
"RequestedLocales" )
657 , _softLocksFile( home() /
"SoftLocks" )
658 , _hardLocksFile( Pathname::assertprefix( _root,
ZConfig::instance().locksFile() ) )
666 MIL <<
"Initialized target on " <<
_root << endl;
674 std::ifstream uuidprovider(
"/proc/sys/kernel/random/uuid" );
684 boost::function<
bool ()> condition,
685 boost::function<
string ()> value )
687 string val = value();
695 MIL <<
"updating '" << filename <<
"' content." << endl;
699 std::ofstream filestr;
702 filestr.open( filename.c_str() );
704 if ( filestr.good() )
720 return ! PathInfo(pathname).isExist();
728 Pathname idpath(
home() /
"AnonymousUniqueId");
738 WAR <<
"Can't create anonymous id file" << endl;
747 Pathname flavorpath(
home() /
"LastDistributionFlavor");
753 WAR <<
"No base product, I won't create flavor cache" << endl;
757 string flavor = p->flavor();
769 WAR <<
"Can't create flavor cache" << endl;
782 MIL <<
"Targets closed" << endl;
805 Pathname rpmsolv = base/
"solv";
806 Pathname rpmsolvcookie = base/
"cookie";
808 bool build_rpm_solv =
true;
812 && (
_root/
"/etc/products.d") );
814 bool solvexisted = PathInfo(rpmsolv).isExist();
818 PathInfo cookie( rpmsolvcookie );
819 MIL <<
"Read cookie: " << cookie << endl;
820 if ( cookie.isExist() )
825 build_rpm_solv =
false;
826 MIL <<
"Read cookie: " << rpmsolvcookie <<
" says: "
827 << (build_rpm_solv ?
"outdated" :
"uptodate") << endl;
831 if ( build_rpm_solv )
836 Pathname oldSolvFile( solvexisted ? rpmsolv : Pathname() );
845 bool switchingToTmpSolvfile =
false;
846 Exception ex(
"Failed to cache rpm database.");
852 rpmsolv = base/
"solv";
853 rpmsolvcookie = base/
"cookie";
860 WAR <<
"Using a temporary solv file at " << base << endl;
861 switchingToTmpSolvfile =
true;
870 if ( ! switchingToTmpSolvfile )
879 std::ostringstream cmd;
881 if ( !
_root.empty() )
882 cmd <<
" -r '" <<
_root <<
"'";
884 cmd <<
" -p '" << Pathname::assertprefix(
_root,
"/etc/products.d" ) <<
"'";
886 if ( ! oldSolvFile.empty() )
887 cmd <<
" '" << oldSolvFile <<
"'";
889 cmd <<
" > '" << tmpsolv.
path() <<
"'";
891 MIL <<
"Executing: " << cmd << endl;
895 for ( std::string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
896 WAR <<
" " << output;
897 cmd <<
" " << output;
900 int ret = prog.close();
923 if ( PathInfo( script ).isX() )
929 spacewalk.
send( notify );
933 if ( ret.command() ==
"ERROR" )
934 ret.writeTo(
WAR ) << endl;
959 MIL <<
"adding " << rpmsolv <<
" to pool(" << satpool.
systemRepoAlias() <<
")" << endl;
979 MIL <<
"Try to handle exception by rebuilding the solv-file" << endl;
1000 if ( ! softLocks.empty() )
1005 softLocks.erase( it->ident() );
1013 if ( ! hardLocks.empty() )
1022 MIL <<
"Target loaded: " << system.
solvablesSize() <<
" resolvables" << endl;
1041 if (
root() ==
"/" )
1051 MIL <<
"TargetImpl::commit(<pool>, " << policy_r <<
")" << endl;
1060 commitPlugins.
load( plugindir );
1066 if ( getZYpp()->resolver()->upgradeMode() )
1068 if ( ! policy_r.
dryRun() )
1074 DBG <<
"dryRun: Not writing upgrade testcase." << endl;
1081 if ( ! policy_r.
dryRun() )
1102 DBG <<
"dryRun: Not stroring non-package data." << endl;
1122 steps.push_back( *it );
1129 MIL <<
"Todo: " << result << endl;
1135 if ( ! policy_r.
dryRun() )
1137 for_( it, steps.begin(), steps.end() )
1139 if ( ! it->satSolvable().isKind<
Patch>() )
1147 if ( ! patch ||patch->message().empty() )
1150 MIL <<
"Show message for " << patch << endl;
1152 if ( ! report->show( patch ) )
1154 WAR <<
"commit aborted by the user" << endl;
1161 DBG <<
"dryRun: Not checking patch messages." << endl;
1182 for_( it, steps.begin(), steps.end() )
1184 switch ( it->stepType() )
1206 localfile = packageCache.
get( pi );
1216 INT <<
"Don't know howto cache: Neither Package nor SrcPackage: " << pi << endl;
1221 catch (
const AbortRequestException & exp )
1225 WAR <<
"commit cache preload aborted by the user" << endl;
1229 catch (
const SkipRequestException & exp )
1234 WAR <<
"Skipping cache preload package " << pi->asKind<
Package>() <<
" in commit" << endl;
1244 INT <<
"Unexpected Error: Skipping cache preload package " << pi->asKind<
Package>() <<
" in commit" << endl;
1253 ERR <<
"Some packages could not be provided. Aborting commit."<< endl;
1255 else if ( ! policy_r.
dryRun() )
1257 commit( policy_r, packageCache, result );
1261 DBG <<
"dryRun: Not installing/deleting anything." << endl;
1266 DBG <<
"dryRun: Not downloading/installing/deleting anything." << endl;
1272 if ( ! policy_r.
dryRun() )
1281 result._errors.clear();
1282 result._remaining.clear();
1283 result._srcremaining.clear();
1284 unsigned toInstall = 0;
1285 for_( step, steps.begin(), steps.end() )
1291 if ( step->satSolvable().isSystem() || ! step->satSolvable().isKind<
Product>() )
1300 switch ( step->stepStage() )
1303 if ( step->satSolvable().isKind<
Package>() )
1304 result._remaining.push_back(
PoolItem( *step ) );
1305 else if ( step->satSolvable().isKind<
SrcPackage>() )
1306 result._srcremaining.push_back(
PoolItem( *step ) );
1312 result._errors.push_back(
PoolItem( *step ) );
1316 result._result = (toInstall - result._remaining.size());
1319 MIL <<
"TargetImpl::commit(<pool>, " << policy_r <<
") returns: " << result << endl;
1334 MIL <<
"TargetImpl::commit(<list>" << policy_r <<
")" << steps.size() << endl;
1337 std::vector<sat::Solvable> successfullyInstalledPackages;
1340 for_( step, steps.begin(), steps.end() )
1345 if ( citem->isKind<
Package>() )
1354 if ( citem->isKind<
Package>() )
1362 localfile = packageCache_r.
get( citem );
1364 catch (
const AbortRequestException &e )
1366 WAR <<
"commit aborted by the user" << endl;
1371 catch (
const SkipRequestException &e )
1374 WAR <<
"Skipping package " << p <<
" in commit" << endl;
1383 INT <<
"Unexpected Error: Skipping package " << p <<
" in commit" << endl;
1388 #warning Exception handling
1393 bool success =
false;
1416 if ( progress.aborted() )
1418 WAR <<
"commit aborted by the user" << endl;
1437 WAR <<
"dry run failed" << endl;
1442 if ( progress.aborted() )
1444 WAR <<
"commit aborted by the user" << endl;
1449 WAR <<
"Install failed" << endl;
1455 if ( success && !policy_r.
dryRun() )
1458 successfullyInstalledPackages.push_back( citem.
satSolvable() );
1467 bool success =
false;
1476 if ( progress.aborted() )
1478 WAR <<
"commit aborted by the user" << endl;
1492 if ( progress.aborted() )
1494 WAR <<
"commit aborted by the user" << endl;
1500 WAR <<
"removal of " << p <<
" failed";
1503 if ( success && !policy_r.
dryRun() )
1510 else if ( ! policy_r.
dryRun() )
1514 if ( ! citem.
buddy() )
1516 if ( citem->isKind<
Product>() )
1521 ERR <<
"Can't install orphan product without release-package! " << citem << endl;
1527 std::string referenceFilename( p->referenceFilename() );
1528 if ( referenceFilename.empty() )
1530 ERR <<
"Can't remove orphan product without 'referenceFilename'! " << citem << endl;
1534 PathInfo referenceFile( Pathname::assertprefix(
_root, Pathname(
"/etc/products.d" ) ) / referenceFilename );
1537 ERR <<
"Delete orphan product failed: " << referenceFile << endl;
1559 if ( ! successfullyInstalledPackages.empty() )
1562 successfullyInstalledPackages, abort ) )
1564 WAR <<
"Commit aborted by the user" << endl;
1570 successfullyInstalledPackages,
1603 PathInfo baseproduct( Pathname::assertprefix( root_r,
"/etc/products.d/baseproduct" ) );
1604 if ( baseproduct.isFile() )
1615 return parser::ProductFileData();
1618 inline Pathname staticGuessRoot(
const Pathname & root_r )
1620 if ( root_r.empty() )
1625 return Pathname(
"/");
1631 inline std::string firstNonEmptyLineIn(
const Pathname & file_r )
1633 std::ifstream idfile( file_r.c_str() );
1634 for( iostr::EachLine in( idfile ); in; in.next() )
1637 if ( ! line.empty() )
1640 return std::string();
1651 if ( p->isTargetDistribution() )
1659 const Pathname needroot( staticGuessRoot(root_r) );
1660 const Target_constPtr target( getZYpp()->getTarget() );
1661 if ( target && target->root() == needroot )
1662 return target->requestedLocales();
1667 {
return baseproductdata(
_root ).registerTarget(); }
1670 {
return baseproductdata( staticGuessRoot(root_r) ).registerTarget(); }
1673 {
return baseproductdata(
_root ).registerRelease(); }
1676 {
return baseproductdata( staticGuessRoot(root_r) ).registerRelease();}
1709 std::string
distributionVersion = baseproductdata( staticGuessRoot(root_r) ).edition().version();
1710 if ( distributionVersion.empty() )
1716 scoped_ptr<rpm::RpmDb> tmprpmdb;
1722 tmprpmdb->initDatabase( );
1731 distributionVersion = it->tag_version();
1739 return firstNonEmptyLineIn(
home() /
"LastDistributionFlavor" );
1744 return firstNonEmptyLineIn( staticGuessRoot(root_r) /
"/var/lib/zypp/LastDistributionFlavor" );
1751 return firstNonEmptyLineIn(
home() /
"AnonymousUniqueId" );
1756 return firstNonEmptyLineIn( staticGuessRoot(root_r) /
"/var/lib/zypp/AnonymousUniqueId" );