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.
This commit is contained in:
Jessica Hamilton 2015-06-14 17:13:53 +12:00
parent 5b57e337e9
commit 6f19d31cd4
6 changed files with 97 additions and 1 deletions

View File

@ -15,6 +15,7 @@
#include <File.h>
#include <Path.h>
#include <SymLink.h>
#include <AutoDeleter.h>
#include <CopyEngine.h>
@ -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,

View File

@ -100,6 +100,8 @@ private:
void _RunPostInstallScript(Package* package,
const BString& script);
void _QueuePostInstallScripts();
void _ExtractPackageContent(Package* package,
const BStringList& contentPaths,
BDirectory& targetDirectory,

View File

@ -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";

View File

@ -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';

View File

@ -23,6 +23,7 @@
#include <NodeMonitor.h>
#include <Path.h>
#include <Roster.h>
#include <SymLink.h>
#include <package/CommitTransactionResult.h>
#include <package/PackageRoster.h>
@ -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)

View File

@ -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,