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;
149 if ( ZConfig::instance().hasUserData() )
150 frame.
setHeader(
"userdata", ZConfig::instance().userData() );
154 plugin.send( frame );
156 if ( ret.isAckCommand() )
158 _scripts.push_back( plugin );
162 WAR <<
"Failed to load plugin: Bad plugin response." << endl;
167 WAR <<
"Failed to load plugin." << endl;
177 USR <<
"+++++" << endl;
181 USR <<
"=====" << endl;
183 USR <<
"-----" << endl;
191 unsigned toKeep( ZConfig::instance().solver_upgradeTestcasesToKeep() );
192 MIL <<
"Testcases to keep: " << toKeep << endl;
195 Target_Ptr target( getZYpp()->getTarget() );
198 WAR <<
"No Target no Testcase!" << endl;
202 std::string stem(
"updateTestcase" );
203 Pathname dir( target->assertRootPrefix(
"/var/log/") );
204 Pathname next( dir / Date::now().
form( stem+
"-%Y-%m-%d-%H-%M-%S" ) );
207 std::list<std::string> content;
209 std::set<std::string> cases;
210 for_( c, content.begin(), content.end() )
215 if ( cases.size() >= toKeep )
217 unsigned toDel = cases.size() - toKeep + 1;
218 for_( c, cases.begin(), cases.end() )
227 MIL <<
"Write new testcase " << next << endl;
228 getZYpp()->resolver()->createSolverTestcase( next.asString(),
false );
245 std::pair<bool,PatchScriptReport::Action> doExecuteScript(
const Pathname & root_r,
246 const Pathname & script_r,
249 MIL <<
"Execute script " << PathInfo(Pathname::assertprefix( root_r,script_r)) << endl;
252 historylog.
comment(script_r.asString() +
_(
" executed"),
true);
253 ExternalProgram prog( script_r.asString(), ExternalProgram::Stderr_To_Stdout,
false, -1,
true, root_r );
255 for ( std::string output = prog.receiveLine(); output.length(); output = prog.receiveLine() )
258 if ( ! report_r->progress( PatchScriptReport::OUTPUT, output ) )
260 WAR <<
"User request to abort script " << script_r << endl;
267 std::pair<bool,PatchScriptReport::Action> ret( std::make_pair(
false, PatchScriptReport::ABORT ) );
269 if ( prog.close() != 0 )
271 ret.second = report_r->problem( prog.execError() );
272 WAR <<
"ACTION" << ret.second <<
"(" << prog.execError() <<
")" << endl;
273 std::ostringstream sstr;
274 sstr << script_r <<
_(
" execution failed") <<
" (" << prog.execError() <<
")" << endl;
275 historylog.
comment(sstr.str(),
true);
287 bool executeScript(
const Pathname & root_r,
288 const Pathname & script_r,
289 callback::SendReport<PatchScriptReport> & report_r )
291 std::pair<bool,PatchScriptReport::Action> action( std::make_pair(
false, PatchScriptReport::ABORT ) );
294 action = doExecuteScript( root_r, script_r, report_r );
298 switch ( action.second )
300 case PatchScriptReport::ABORT:
301 WAR <<
"User request to abort at script " << script_r << endl;
305 case PatchScriptReport::IGNORE:
306 WAR <<
"User request to skip script " << script_r << endl;
310 case PatchScriptReport::RETRY:
313 }
while ( action.second == PatchScriptReport::RETRY );
316 INT <<
"Abort on unknown ACTION request " << action.second <<
" returned" << endl;
325 bool RunUpdateScripts(
const Pathname & root_r,
326 const Pathname & scriptsPath_r,
327 const std::vector<sat::Solvable> & checkPackages_r,
330 if ( checkPackages_r.empty() )
333 MIL <<
"Looking for new update scripts in (" << root_r <<
")" << scriptsPath_r << endl;
334 Pathname scriptsDir( Pathname::assertprefix( root_r, scriptsPath_r ) );
335 if ( ! PathInfo( scriptsDir ).isDir() )
338 std::list<std::string> scripts;
340 if ( scripts.empty() )
348 std::map<std::string, Pathname> unify;
349 for_( it, checkPackages_r.begin(), checkPackages_r.end() )
351 std::string prefix(
str::form(
"%s-%s", it->name().c_str(), it->edition().c_str() ) );
352 for_( sit, scripts.begin(), scripts.end() )
357 if ( (*sit)[prefix.size()] !=
'\0' && (*sit)[prefix.size()] !=
'-' )
360 PathInfo script( scriptsDir / *sit );
361 Pathname localPath( scriptsPath_r/(*sit) );
362 std::string unifytag;
364 if ( script.isFile() )
370 else if ( ! script.isExist() )
378 if ( unifytag.empty() )
382 if ( unify[unifytag].empty() )
384 unify[unifytag] = localPath;
391 std::string msg(
str::form(
_(
"%s already executed as %s)"), localPath.asString().c_str(), unify[unifytag].c_str() ) );
392 MIL <<
"Skip update script: " << msg << endl;
393 HistoryLog().comment( msg,
true );
397 if ( abort || aborting_r )
399 WAR <<
"Aborting: Skip update script " << *sit << endl;
400 HistoryLog().comment(
401 localPath.asString() +
_(
" execution skipped while aborting"),
406 MIL <<
"Found update script " << *sit << endl;
407 callback::SendReport<PatchScriptReport>
report;
408 report->start( make<Package>( *it ), script.path() );
410 if ( ! executeScript( root_r, localPath, report ) )
422 inline void copyTo( std::ostream & out_r,
const Pathname & file_r )
424 std::ifstream infile( file_r.c_str() );
425 for( iostr::EachLine in( infile ); in; in.next() )
427 out_r << *in << endl;
431 inline std::string notificationCmdSubst(
const std::string & cmd_r,
const UpdateNotificationFile & notification_r )
433 std::string ret( cmd_r );
434 #define SUBST_IF(PAT,VAL) if ( ret.find( PAT ) != std::string::npos ) ret = str::gsub( ret, PAT, VAL )
435 SUBST_IF(
"%p", notification_r.solvable().asString() );
436 SUBST_IF(
"%P", notification_r.file().asString() );
441 void sendNotification(
const Pathname & root_r,
444 if ( notifications_r.empty() )
447 std::string cmdspec( ZConfig::instance().updateMessagesNotify() );
448 MIL <<
"Notification command is '" << cmdspec <<
"'" << endl;
449 if ( cmdspec.empty() )
453 if ( pos == std::string::npos )
455 ERR <<
"Can't send Notification: Missing 'format |' in command spec." << endl;
456 HistoryLog().comment( str::Str() <<
_(
"Error sending update message notification."),
true );
461 std::string commandStr(
str::trim( cmdspec.substr( pos + 1 ) ) );
463 enum Format { UNKNOWN, NONE, SINGLE, DIGEST, BULK };
464 Format format = UNKNOWN;
465 if ( formatStr ==
"none" )
467 else if ( formatStr ==
"single" )
469 else if ( formatStr ==
"digest" )
471 else if ( formatStr ==
"bulk" )
475 ERR <<
"Can't send Notification: Unknown format '" << formatStr <<
" |' in command spec." << endl;
476 HistoryLog().comment( str::Str() <<
_(
"Error sending update message notification."),
true );
484 if ( format == NONE || format == SINGLE )
486 for_( it, notifications_r.begin(), notifications_r.end() )
488 std::vector<std::string> command;
489 if ( format == SINGLE )
490 command.push_back(
"<"+Pathname::assertprefix( root_r, it->file() ).
asString() );
491 str::splitEscaped( notificationCmdSubst( commandStr, *it ), std::back_inserter( command ) );
493 ExternalProgram prog( command, ExternalProgram::Stderr_To_Stdout,
false, -1,
true, root_r );
496 for( std::string line = prog.receiveLine(); ! line.empty(); line = prog.receiveLine() )
500 int ret = prog.close();
503 ERR <<
"Notification command returned with error (" << ret <<
")." << endl;
504 HistoryLog().comment( str::Str() <<
_(
"Error sending update message notification."),
true );
510 else if ( format == DIGEST || format == BULK )
512 filesystem::TmpFile tmpfile;
513 ofstream out( tmpfile.path().c_str() );
514 for_( it, notifications_r.begin(), notifications_r.end() )
516 if ( format == DIGEST )
518 out << it->file() << endl;
520 else if ( format == BULK )
522 copyTo( out <<
'\f', Pathname::assertprefix( root_r, it->file() ) );
526 std::vector<std::string> command;
527 command.push_back(
"<"+tmpfile.path().asString() );
528 str::splitEscaped( notificationCmdSubst( commandStr, *notifications_r.begin() ), std::back_inserter( command ) );
530 ExternalProgram prog( command, ExternalProgram::Stderr_To_Stdout,
false, -1,
true, root_r );
533 for( std::string line = prog.receiveLine(); ! line.empty(); line = prog.receiveLine() )
537 int ret = prog.close();
540 ERR <<
"Notification command returned with error (" << ret <<
")." << endl;
541 HistoryLog().comment( str::Str() <<
_(
"Error sending update message notification."),
true );
548 INT <<
"Can't send Notification: Missing handler for 'format |' in command spec." << endl;
549 HistoryLog().comment( str::Str() <<
_(
"Error sending update message notification."),
true );
560 void RunUpdateMessages(
const Pathname & root_r,
561 const Pathname & messagesPath_r,
562 const std::vector<sat::Solvable> & checkPackages_r,
563 ZYppCommitResult & result_r )
565 if ( checkPackages_r.empty() )
568 MIL <<
"Looking for new update messages in (" << root_r <<
")" << messagesPath_r << endl;
569 Pathname messagesDir( Pathname::assertprefix( root_r, messagesPath_r ) );
570 if ( ! PathInfo( messagesDir ).isDir() )
573 std::list<std::string> messages;
575 if ( messages.empty() )
581 HistoryLog historylog;
582 for_( it, checkPackages_r.begin(), checkPackages_r.end() )
584 std::string prefix(
str::form(
"%s-%s", it->name().c_str(), it->edition().c_str() ) );
585 for_( sit, messages.begin(), messages.end() )
590 if ( (*sit)[prefix.size()] !=
'\0' && (*sit)[prefix.size()] !=
'-' )
593 PathInfo message( messagesDir / *sit );
594 if ( ! message.isFile() || message.size() == 0 )
597 MIL <<
"Found update message " << *sit << endl;
598 Pathname localPath( messagesPath_r/(*sit) );
599 result_r.rUpdateMessages().push_back( UpdateNotificationFile( *it, localPath ) );
600 historylog.comment( str::Str() <<
_(
"New update message") <<
" " << localPath,
true );
603 sendNotification( root_r, result_r.updateMessages() );
611 const Pathname & messagesPath_r,
612 const std::vector<sat::Solvable> & checkPackages_r,
614 { RunUpdateMessages( root_r, messagesPath_r, checkPackages_r, result_r ); }
619 bool operator()(
const std::string & name_r,
621 const Arch & arch_r )
const
626 if ( arch_r == it->tag_arch()
627 && ( ed_r == Edition::noedition || ed_r == it->tag_edition() ) )
647 : _pool(pool_r), _access(access)
661 std::list<Repository>
repos( _pool.knownRepositoriesBegin(), _pool.knownRepositoriesEnd() );
673 TargetImpl_Ptr TargetImpl::_nullimpl;
676 TargetImpl_Ptr TargetImpl::nullimpl()
688 TargetImpl::TargetImpl(
const Pathname & root_r,
bool doRebuild_r )
690 , _requestedLocalesFile( home() /
"RequestedLocales" )
691 , _softLocksFile( home() /
"SoftLocks" )
692 , _hardLocksFile( Pathname::assertprefix( _root,
ZConfig::instance().locksFile() ) )
700 MIL <<
"Initialized target on " <<
_root << endl;
708 std::ifstream uuidprovider(
"/proc/sys/kernel/random/uuid" );
718 boost::function<
bool ()> condition,
719 boost::function<
string ()> value )
721 string val = value();
729 MIL <<
"updating '" << filename <<
"' content." << endl;
733 std::ofstream filestr;
736 filestr.open( filename.c_str() );
738 if ( filestr.good() )
754 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 MIL <<
"Targets closed" << endl;
839 Pathname rpmsolv = base/
"solv";
840 Pathname rpmsolvcookie = base/
"cookie";
842 bool build_rpm_solv =
true;
846 && (
_root/
"/etc/products.d") );
848 bool solvexisted = PathInfo(rpmsolv).isExist();
852 PathInfo cookie( rpmsolvcookie );
853 MIL <<
"Read cookie: " << cookie << endl;
854 if ( cookie.isExist() )
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 )
913 std::ostringstream cmd;
915 if ( !
_root.empty() )
916 cmd <<
" -r '" <<
_root <<
"'";
918 cmd <<
" -p '" << Pathname::assertprefix(
_root,
"/etc/products.d" ) <<
"'";
920 if ( ! oldSolvFile.empty() )
921 cmd <<
" '" << oldSolvFile <<
"'";
923 cmd <<
" > '" << tmpsolv.
path() <<
"'";
925 MIL <<
"Executing: " << cmd << endl;
929 for ( std::string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
930 WAR <<
" " << output;
931 cmd <<
" " << output;
934 int ret = prog.close();
957 if ( PathInfo( script ).isX() )
963 spacewalk.
send( notify );
967 if ( ret.command() ==
"ERROR" )
968 ret.writeTo(
WAR ) << endl;
976 return build_rpm_solv;
994 MIL <<
"New cache built: " << (newCache?
"true":
"false") <<
995 ", force loading: " << (force?
"true":
"false") << endl;
1000 MIL <<
"adding " << rpmsolv <<
" to pool(" << satpool.
systemRepoAlias() <<
")" << endl;
1007 if ( newCache || force )
1024 MIL <<
"adding " << rpmsolv <<
" to system" << endl;
1030 MIL <<
"Try to handle exception by rebuilding the solv-file" << endl;
1051 if ( ! softLocks.empty() )
1056 softLocks.erase( it->ident() );
1064 if ( ! hardLocks.empty() )
1073 MIL <<
"Target loaded: " << system.
solvablesSize() <<
" resolvables" << endl;
1092 if (
root() ==
"/" )
1102 MIL <<
"TargetImpl::commit(<pool>, " << policy_r <<
")" << endl;
1111 commitPlugins.
load( plugindir );
1117 if ( getZYpp()->resolver()->upgradeMode() )
1119 if ( ! policy_r.
dryRun() )
1125 DBG <<
"dryRun: Not writing upgrade testcase." << endl;
1132 if ( ! policy_r.
dryRun() )
1153 DBG <<
"dryRun: Not stroring non-package data." << endl;
1173 steps.push_back( *it );
1180 MIL <<
"Todo: " << result << endl;
1186 if ( ! policy_r.
dryRun() )
1188 for_( it, steps.begin(), steps.end() )
1190 if ( ! it->satSolvable().isKind<
Patch>() )
1198 if ( ! patch ||patch->message().empty() )
1201 MIL <<
"Show message for " << patch << endl;
1203 if ( ! report->show( patch ) )
1205 WAR <<
"commit aborted by the user" << endl;
1212 DBG <<
"dryRun: Not checking patch messages." << endl;
1233 for_( it, steps.begin(), steps.end() )
1235 switch ( it->stepType() )
1257 localfile = packageCache.
get( pi );
1267 INT <<
"Don't know howto cache: Neither Package nor SrcPackage: " << pi << endl;
1272 catch (
const AbortRequestException & exp )
1276 WAR <<
"commit cache preload aborted by the user" << endl;
1280 catch (
const SkipRequestException & exp )
1285 WAR <<
"Skipping cache preload package " << pi->asKind<
Package>() <<
" in commit" << endl;
1295 INT <<
"Unexpected Error: Skipping cache preload package " << pi->asKind<
Package>() <<
" in commit" << endl;
1304 ERR <<
"Some packages could not be provided. Aborting commit."<< endl;
1306 else if ( ! policy_r.
dryRun() )
1308 commit( policy_r, packageCache, result );
1312 DBG <<
"dryRun: Not installing/deleting anything." << endl;
1317 DBG <<
"dryRun: Not downloading/installing/deleting anything." << endl;
1323 if ( ! policy_r.
dryRun() )
1332 result._errors.clear();
1333 result._remaining.clear();
1334 result._srcremaining.clear();
1335 unsigned toInstall = 0;
1336 for_( step, steps.begin(), steps.end() )
1342 if ( step->satSolvable().isSystem() || ! step->satSolvable().isKind<
Product>() )
1351 switch ( step->stepStage() )
1354 if ( step->satSolvable().isKind<
Package>() )
1355 result._remaining.push_back(
PoolItem( *step ) );
1356 else if ( step->satSolvable().isKind<
SrcPackage>() )
1357 result._srcremaining.push_back(
PoolItem( *step ) );
1363 result._errors.push_back(
PoolItem( *step ) );
1367 result._result = (toInstall - result._remaining.size());
1370 MIL <<
"TargetImpl::commit(<pool>, " << policy_r <<
") returns: " << result << endl;
1385 MIL <<
"TargetImpl::commit(<list>" << policy_r <<
")" << steps.size() << endl;
1388 std::vector<sat::Solvable> successfullyInstalledPackages;
1391 for_( step, steps.begin(), steps.end() )
1396 if ( citem->isKind<
Package>() )
1405 if ( citem->isKind<
Package>() )
1413 localfile = packageCache_r.
get( citem );
1415 catch (
const AbortRequestException &e )
1417 WAR <<
"commit aborted by the user" << endl;
1422 catch (
const SkipRequestException &e )
1425 WAR <<
"Skipping package " << p <<
" in commit" << endl;
1434 INT <<
"Unexpected Error: Skipping package " << p <<
" in commit" << endl;
1439 #warning Exception handling
1444 bool success =
false;
1467 if ( progress.aborted() )
1469 WAR <<
"commit aborted by the user" << endl;
1488 WAR <<
"dry run failed" << endl;
1493 if ( progress.aborted() )
1495 WAR <<
"commit aborted by the user" << endl;
1500 WAR <<
"Install failed" << endl;
1506 if ( success && !policy_r.
dryRun() )
1509 successfullyInstalledPackages.push_back( citem.
satSolvable() );
1518 bool success =
false;
1527 if ( progress.aborted() )
1529 WAR <<
"commit aborted by the user" << endl;
1543 if ( progress.aborted() )
1545 WAR <<
"commit aborted by the user" << endl;
1551 WAR <<
"removal of " << p <<
" failed";
1554 if ( success && !policy_r.
dryRun() )
1561 else if ( ! policy_r.
dryRun() )
1565 if ( ! citem.
buddy() )
1567 if ( citem->isKind<
Product>() )
1572 ERR <<
"Can't install orphan product without release-package! " << citem << endl;
1578 std::string referenceFilename( p->referenceFilename() );
1579 if ( referenceFilename.empty() )
1581 ERR <<
"Can't remove orphan product without 'referenceFilename'! " << citem << endl;
1585 PathInfo referenceFile( Pathname::assertprefix(
_root, Pathname(
"/etc/products.d" ) ) / referenceFilename );
1588 ERR <<
"Delete orphan product failed: " << referenceFile << endl;
1610 if ( ! successfullyInstalledPackages.empty() )
1613 successfullyInstalledPackages, abort ) )
1615 WAR <<
"Commit aborted by the user" << endl;
1621 successfullyInstalledPackages,
1654 PathInfo baseproduct( Pathname::assertprefix( root_r,
"/etc/products.d/baseproduct" ) );
1655 if ( baseproduct.isFile() )
1666 return parser::ProductFileData();
1669 inline Pathname staticGuessRoot(
const Pathname & root_r )
1671 if ( root_r.empty() )
1676 return Pathname(
"/");
1682 inline std::string firstNonEmptyLineIn(
const Pathname & file_r )
1684 std::ifstream idfile( file_r.c_str() );
1685 for( iostr::EachLine in( idfile ); in; in.next() )
1688 if ( ! line.empty() )
1691 return std::string();
1702 if ( p->isTargetDistribution() )
1710 const Pathname needroot( staticGuessRoot(root_r) );
1711 const Target_constPtr target( getZYpp()->getTarget() );
1712 if ( target && target->root() == needroot )
1713 return target->requestedLocales();
1718 {
return baseproductdata(
_root ).registerTarget(); }
1721 {
return baseproductdata( staticGuessRoot(root_r) ).registerTarget(); }
1724 {
return baseproductdata(
_root ).registerRelease(); }
1727 {
return baseproductdata( staticGuessRoot(root_r) ).registerRelease();}
1760 std::string
distributionVersion = baseproductdata( staticGuessRoot(root_r) ).edition().version();
1761 if ( distributionVersion.empty() )
1767 scoped_ptr<rpm::RpmDb> tmprpmdb;
1773 tmprpmdb->initDatabase( );
1782 distributionVersion = it->tag_version();
1790 return firstNonEmptyLineIn(
home() /
"LastDistributionFlavor" );
1795 return firstNonEmptyLineIn( staticGuessRoot(root_r) /
"/var/lib/zypp/LastDistributionFlavor" );
1802 return firstNonEmptyLineIn(
home() /
"AnonymousUniqueId" );
1807 return firstNonEmptyLineIn( staticGuessRoot(root_r) /
"/var/lib/zypp/AnonymousUniqueId" );