From 6f19d31cd4d8fda1e85d5a2ab8717263c9b84f34 Mon Sep 17 00:00:00 2001 From: Jessica Hamilton Date: Sun, 14 Jun 2015 17:13:53 +1200 Subject: [PATCH] package_daemon: queue post-install scripts to run after reboot * Creates symlinks to the post-install scripts into the administrative/queued-scripts directory. * Upon reboot, post-install scripts in the queued-scripts are run, and then the symlinks to the scripts removed. * This solves the issue of post-install scripts not being run when the package is installed/upgraded along with the system packages, as experienced with the latest upgrade to the bash package. --- .../package/CommitTransactionHandler.cpp | 49 ++++++++++++++++++- .../package/CommitTransactionHandler.h | 2 + src/servers/package/Constants.cpp | 1 + src/servers/package/Constants.h | 1 + src/servers/package/Volume.cpp | 44 +++++++++++++++++ src/servers/package/Volume.h | 1 + 6 files changed, 97 insertions(+), 1 deletion(-) diff --git a/src/servers/package/CommitTransactionHandler.cpp b/src/servers/package/CommitTransactionHandler.cpp index 7336c05144..ea37e1aeee 100644 --- a/src/servers/package/CommitTransactionHandler.cpp +++ b/src/servers/package/CommitTransactionHandler.cpp @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -397,7 +398,7 @@ CommitTransactionHandler::_ApplyChanges() // run post-installation scripts _RunPostInstallScripts(); } else { - // TODO: Make sure the post-install scripts are run on next boot! + _QueuePostInstallScripts(); } // removed packages have been deleted, new packages shall not be deleted @@ -1351,6 +1352,52 @@ CommitTransactionHandler::_RunPostInstallScript(Package* package, } +void +CommitTransactionHandler::_QueuePostInstallScripts() +{ + BDirectory adminDirectory; + status_t error = _OpenPackagesSubDirectory( + RelativePath(kAdminDirectoryName), true, adminDirectory); + if (error != B_OK) { + ERROR("Failed to open administrative directory: %s\n", strerror(error)); + return; + } + + BDirectory scriptsDirectory; + error = scriptsDirectory.SetTo(&adminDirectory, kQueuedScriptsDirectoryName); + if (error == B_ENTRY_NOT_FOUND) + error = adminDirectory.CreateDirectory(kQueuedScriptsDirectoryName, &scriptsDirectory); + if (error != B_OK) { + ERROR("Failed to open queued scripts directory: %s\n", strerror(error)); + return; + } + + BDirectory rootDir(&fVolume->RootDirectoryRef()); + for (PackageSet::iterator it = fAddedPackages.begin(); + it != fAddedPackages.end(); ++it) { + Package* package = *it; + const BStringList& scripts = package->Info().PostInstallScripts(); + for (int32 i = 0; i < scripts.CountStrings(); ++i) { + BPath scriptPath(&rootDir, scripts.StringAt(i)); + status_t error = scriptPath.InitCheck(); + if (error != B_OK) { + ERROR("Can't find script: %s\n", scripts.StringAt(i).String()); + continue; + } + + // symlink to the script + BSymLink scriptLink; + scriptsDirectory.CreateSymLink(scriptPath.Leaf(), + scriptPath.Path(), &scriptLink); + if (scriptLink.InitCheck() != B_OK) { + ERROR("Creating symlink failed: %s\n", strerror(scriptLink.InitCheck())); + continue; + } + } + } +} + + void CommitTransactionHandler::_ExtractPackageContent(Package* package, const BStringList& contentPaths, BDirectory& targetDirectory, diff --git a/src/servers/package/CommitTransactionHandler.h b/src/servers/package/CommitTransactionHandler.h index bf6a4b897d..64c573b43e 100644 --- a/src/servers/package/CommitTransactionHandler.h +++ b/src/servers/package/CommitTransactionHandler.h @@ -100,6 +100,8 @@ private: void _RunPostInstallScript(Package* package, const BString& script); + void _QueuePostInstallScripts(); + void _ExtractPackageContent(Package* package, const BStringList& contentPaths, BDirectory& targetDirectory, diff --git a/src/servers/package/Constants.cpp b/src/servers/package/Constants.cpp index ed0f7c5b11..2ae3e48f87 100644 --- a/src/servers/package/Constants.cpp +++ b/src/servers/package/Constants.cpp @@ -16,3 +16,4 @@ const char* const kTemporaryActivationFileName = PACKAGES_DIRECTORY_ACTIVATION_FILE ".tmp"; const char* const kWritableFilesDirectoryName = "writable-files"; const char* const kPackageFileAttribute = "SYS:PACKAGE"; +const char* const kQueuedScriptsDirectoryName = "queued-scripts"; diff --git a/src/servers/package/Constants.h b/src/servers/package/Constants.h index d3c8686422..e3057e0711 100644 --- a/src/servers/package/Constants.h +++ b/src/servers/package/Constants.h @@ -15,6 +15,7 @@ extern const char* const kActivationFileName; extern const char* const kTemporaryActivationFileName; extern const char* const kWritableFilesDirectoryName; extern const char* const kPackageFileAttribute; +extern const char* const kQueuedScriptsDirectoryName; static const bigtime_t kHandleNodeMonitorEvents = 'nmon'; diff --git a/src/servers/package/Volume.cpp b/src/servers/package/Volume.cpp index 38453dd0be..f6ae125acf 100644 --- a/src/servers/package/Volume.cpp +++ b/src/servers/package/Volume.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -1130,6 +1131,49 @@ Volume::_GetActivePackages(int fd) } +void +Volume::_RunQueuedScripts() +{ + BDirectory adminDirectory; + status_t error = _OpenPackagesSubDirectory( + RelativePath(kAdminDirectoryName), false, adminDirectory); + if (error != B_OK) + return; + + BDirectory scriptsDirectory; + error = scriptsDirectory.SetTo(&adminDirectory, kQueuedScriptsDirectoryName); + if (error != B_OK) + return; + + // enumerate all the symlinks in the queued scripts directory + BEntry scriptEntry; + while (scriptsDirectory.GetNextEntry(&scriptEntry, false) == B_OK) { + BPath scriptPath; + scriptEntry.GetPath(&scriptPath); + error = scriptPath.InitCheck(); + if (error != B_OK) { + INFORM("failed to get path of post-installation script \"%s\"\n", + strerror(error)); + continue; + } + + errno = 0; + int result = system(scriptPath.Path()); + if (result != 0) { + INFORM("running post-installation script \"%s\" " + "failed: %d (errno: %s)\n", scriptPath.Leaf(), errno, strerror(errno)); + } + + // remove the symlink, now that we've run the post-installation script + error = scriptEntry.Remove(); + if (error != B_OK) { + INFORM("removing queued post-install script failed \"%s\"\n", + strerror(error)); + } + } +} + + bool Volume::_CheckActivePackagesMatchLatestState( PackageFSGetPackageInfosRequest* request) diff --git a/src/servers/package/Volume.h b/src/servers/package/Volume.h index f083860f9b..164a3a6a96 100644 --- a/src/servers/package/Volume.h +++ b/src/servers/package/Volume.h @@ -160,6 +160,7 @@ private: status_t _InitLatestState(); status_t _InitLatestStateFromActivatedPackages(); status_t _GetActivePackages(int fd); + void _RunQueuedScripts(); bool _CheckActivePackagesMatchLatestState( PackageFSGetPackageInfosRequest* request); void _SetLatestState(VolumeState* state,