Package Kit: Proper Installation for First Boot Packages
Do the final installation operations for all the packages in the /system/packages directory when the OS is booted for the first time. This will run their post-install scripts, create users, groups and generate settings files (marked with a package version attribute). Previously we just ran all the shell scripts found in the /system/boot/post-install directory (don't do that as much now). Fixes bug #14382 This patch has simpler code flow in CommitTransactionHandler::_ApplyChanges Tested on 32 and 64 bit systems. Once it's official, need to remove the open_ssh redundant post-install script that creates users etc. from HaikuPorts. Now we can notice bugs like package version attributes on settings files aren't fully working. :-) Didn't remove special case for add_catalog_entry_attributes.sh since it still does stuff that the build system doesn't do. Might be able to add that script as part of the Haiku.hpkg. See change 3751 for removing it, https://review.haiku-os.org/c/haiku/+/3751 Change-Id: I3807b78042fdb70e5a79eca2e2a45816ece0236f Reviewed-on: https://review.haiku-os.org/c/haiku/+/2342 Reviewed-by: Alexander G. M. Smith <agmsmith@ncf.ca> Reviewed-by: Niels Sascha Reedijk <niels.reedijk@gmail.com> Reviewed-by: Adrien Destugues <pulkomandy@gmail.com>
This commit is contained in:
parent
e459857d1c
commit
3376ed1a72
32
data/system/boot/PostInstallScript
Normal file → Executable file
32
data/system/boot/PostInstallScript
Normal file → Executable file
@ -1,6 +1,8 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Check for fresh install and run post install scripts.
|
||||
# Check for fresh install and run oddball system post install stuff that the
|
||||
# package_daemon doesn't handle. All Home and other post install scripts
|
||||
# get run the old way here (probably won't be any, unless you reinstalled?).
|
||||
|
||||
title=$1
|
||||
freshInstallIndicator=$2
|
||||
@ -8,13 +10,29 @@ postInstallDir=$3
|
||||
|
||||
if [ -e $freshInstallIndicator ]; then
|
||||
# execute scripts
|
||||
for f in $postInstallDir/*.sh
|
||||
do
|
||||
if [ -f $f ]; then
|
||||
echo "Running $title script $f ..." > /dev/dprintf
|
||||
$f
|
||||
|
||||
if [ "$postInstallDir" == "/boot/system/boot/post-install" ]; then
|
||||
# Special case for one script file that isn't in a package. Rest
|
||||
# of the files in there will be run by package_daemon when
|
||||
# doing first boot processing. Can be removed when Gerrit
|
||||
# Change #3751 is done.
|
||||
specialCaseFile="$postInstallDir/add_catalog_entry_attributes.sh"
|
||||
if [ -e "$specialCaseFile" ]; then
|
||||
echo "Running $title special case $specialCaseFile first boot processing." > /dev/dprintf
|
||||
"$specialCaseFile"
|
||||
else
|
||||
echo "Skipping $title obsolete first boot processing, files:" > /dev/dprintf
|
||||
ls "$postInstallDir" > /dev/dprintf
|
||||
fi
|
||||
done
|
||||
else
|
||||
for f in $postInstallDir/*.sh
|
||||
do
|
||||
if [ -f $f ]; then
|
||||
echo "Running $title script $f ..." > /dev/dprintf
|
||||
$f
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
sync
|
||||
rm $freshInstallIndicator
|
||||
|
@ -179,7 +179,10 @@ The supported attributes are:
|
||||
- ``post-install-scripts``: A list of paths of files included in the package,
|
||||
which shall be executed on package activation. Each path must start with
|
||||
"boot/post-install/". All the files in that directory are also run on first
|
||||
boot after installing or copying the OS to a new disk.
|
||||
boot after installing or copying the OS to a new disk. As an odd bonus,
|
||||
they're also run when you boot the installer disc, and the installer copies
|
||||
some of the resulting settings data to the new install too. So try to
|
||||
handle being run twice.
|
||||
- ``pre-uninstall-scripts``: A list of paths of files included in the package,
|
||||
which shall be executed on package deactivation. For consistency, each path
|
||||
should start with "boot/pre-uninstall/".
|
||||
|
@ -21,8 +21,8 @@ namespace BPrivate {
|
||||
class BActivationTransaction : public BArchivable {
|
||||
public:
|
||||
BActivationTransaction();
|
||||
BActivationTransaction(BMessage* archive,
|
||||
status_t* _error = NULL);
|
||||
BActivationTransaction(BMessage* archive,
|
||||
status_t* _error = NULL);
|
||||
virtual ~BActivationTransaction();
|
||||
|
||||
status_t SetTo(BPackageInstallationLocation location,
|
||||
@ -52,6 +52,9 @@ public:
|
||||
const BStringList& packages);
|
||||
bool AddPackageToDeactivate(const BString& package);
|
||||
|
||||
bool FirstBootProcessing() const;
|
||||
void SetFirstBootProcessing(bool processingIsOn);
|
||||
|
||||
virtual status_t Archive(BMessage* archive,
|
||||
bool deep = true) const;
|
||||
static BArchivable* Instantiate(BMessage* archive);
|
||||
@ -66,6 +69,7 @@ private:
|
||||
BString fTransactionDirectoryName;
|
||||
BStringList fPackagesToActivate;
|
||||
BStringList fPackagesToDeactivate;
|
||||
bool fFirstBootProcessing;
|
||||
};
|
||||
|
||||
|
||||
|
@ -47,6 +47,11 @@ enum {
|
||||
// "deactivate": string[]
|
||||
// file names of the packages to activate; must be in the
|
||||
// transaction directory
|
||||
// "first boot processing": bool
|
||||
// if true then runs the package installation processing for
|
||||
// specified (in the activate list) packages on the volume.
|
||||
// Doesn't actually add the packages. Package_daemon preemptively
|
||||
// deletes an empty transaction directory when done.
|
||||
B_MESSAGE_COMMIT_TRANSACTION_REPLY = 'PKTR'
|
||||
// "error": int32
|
||||
// a BTransactionError describing how committing the transaction
|
||||
|
@ -312,6 +312,15 @@ WorkerThread::_LaunchFinishScript(BPath &path)
|
||||
if (system(command.String()) != 0)
|
||||
return B_ERROR;
|
||||
|
||||
// Ask for first boot processing of all the packages copied into the new
|
||||
// installation, since by just copying them the normal package processing
|
||||
// isn't done. package_daemon will detect the magic file and do it.
|
||||
command.SetToFormat("echo 'First Boot written by Installer.' > "
|
||||
"\"%s/system/packages/administrative/FirstBootProcessingNeeded\"",
|
||||
path.Path());
|
||||
if (system(command.String()) != 0)
|
||||
return B_ERROR;
|
||||
|
||||
command.SetToFormat("rm -f \"%s/home/Desktop/Installer\"", path.Path());
|
||||
return system(command.String());
|
||||
}
|
||||
|
@ -24,7 +24,8 @@ BActivationTransaction::BActivationTransaction()
|
||||
fChangeCount(0),
|
||||
fTransactionDirectoryName(),
|
||||
fPackagesToActivate(),
|
||||
fPackagesToDeactivate()
|
||||
fPackagesToDeactivate(),
|
||||
fFirstBootProcessing(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -36,10 +37,16 @@ BActivationTransaction::BActivationTransaction(BMessage* archive,
|
||||
fChangeCount(0),
|
||||
fTransactionDirectoryName(),
|
||||
fPackagesToActivate(),
|
||||
fPackagesToDeactivate()
|
||||
fPackagesToDeactivate(),
|
||||
fFirstBootProcessing(false)
|
||||
{
|
||||
status_t error;
|
||||
int32 location;
|
||||
|
||||
if (archive->FindBool("first boot processing", &fFirstBootProcessing)
|
||||
!= B_OK)
|
||||
fFirstBootProcessing = false; // Field is optional for compatibility.
|
||||
|
||||
if ((error = archive->FindInt32("location", &location)) == B_OK
|
||||
&& (error = archive->FindInt64("change count", &fChangeCount)) == B_OK
|
||||
&& (error = archive->FindString("transaction",
|
||||
@ -91,6 +98,7 @@ BActivationTransaction::SetTo(BPackageInstallationLocation location,
|
||||
fTransactionDirectoryName = directoryName;
|
||||
fPackagesToActivate.MakeEmpty();
|
||||
fPackagesToDeactivate.MakeEmpty();
|
||||
fFirstBootProcessing = false;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
@ -183,6 +191,20 @@ BActivationTransaction::AddPackageToDeactivate(const BString& package)
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
BActivationTransaction::FirstBootProcessing() const
|
||||
{
|
||||
return fFirstBootProcessing;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BActivationTransaction::SetFirstBootProcessing(bool processingIsOn)
|
||||
{
|
||||
fFirstBootProcessing = processingIsOn;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BActivationTransaction::Archive(BMessage* archive, bool deep) const
|
||||
{
|
||||
@ -197,7 +219,9 @@ BActivationTransaction::Archive(BMessage* archive, bool deep) const
|
||||
|| (error = archive->AddStrings("activate", fPackagesToActivate))
|
||||
!= B_OK
|
||||
|| (error = archive->AddStrings("deactivate", fPackagesToDeactivate))
|
||||
!= B_OK) {
|
||||
!= B_OK
|
||||
|| (error = archive->AddBool("first boot processing",
|
||||
fFirstBootProcessing)) != B_OK) {
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -126,6 +126,7 @@ CommitTransactionHandler::CommitTransactionHandler(Volume* volume,
|
||||
fOldStateDirectoryRef(),
|
||||
fOldStateDirectoryName(),
|
||||
fTransactionDirectoryRef(),
|
||||
fFirstBootProcessing(false),
|
||||
fWritableFilesDirectory(),
|
||||
fAddedGroups(),
|
||||
fAddedUsers(),
|
||||
@ -182,6 +183,7 @@ void
|
||||
CommitTransactionHandler::HandleRequest(BMessage* request)
|
||||
{
|
||||
status_t error;
|
||||
|
||||
BActivationTransaction transaction(request, &error);
|
||||
if (error == B_OK)
|
||||
error = transaction.InitCheck();
|
||||
@ -203,6 +205,8 @@ CommitTransactionHandler::HandleRequest(
|
||||
if (transaction.ChangeCount() != fVolume->ChangeCount())
|
||||
throw Exception(B_TRANSACTION_CHANGE_COUNT_MISMATCH);
|
||||
|
||||
fFirstBootProcessing = transaction.FirstBootProcessing();
|
||||
|
||||
// collect the packages to deactivate
|
||||
_GetPackagesToDeactivate(transaction);
|
||||
|
||||
@ -210,13 +214,30 @@ CommitTransactionHandler::HandleRequest(
|
||||
_ReadPackagesToActivate(transaction);
|
||||
|
||||
// anything to do at all?
|
||||
if (fPackagesToActivate.IsEmpty() && fPackagesToDeactivate.empty()) {
|
||||
if (fPackagesToActivate.IsEmpty() && fPackagesToDeactivate.empty()) {
|
||||
WARN("Bad package activation request: no packages to activate or"
|
||||
" deactivate\n");
|
||||
throw Exception(B_TRANSACTION_BAD_REQUEST);
|
||||
}
|
||||
|
||||
_ApplyChanges();
|
||||
|
||||
// Clean up the unused empty transaction directory for first boot
|
||||
// processing, since it's usually an internal to package_daemon
|
||||
// operation and there is no external client to clean it up.
|
||||
if (fFirstBootProcessing) {
|
||||
RelativePath directoryPath(kAdminDirectoryName,
|
||||
transaction.TransactionDirectoryName().String());
|
||||
BDirectory transactionDir;
|
||||
status_t error = _OpenPackagesSubDirectory(directoryPath, false,
|
||||
transactionDir);
|
||||
if (error == B_OK) {
|
||||
BEntry transactionDirEntry;
|
||||
error = transactionDir.GetEntry(&transactionDirEntry);
|
||||
if (error == B_OK)
|
||||
transactionDirEntry.Remove(); // Okay to fail when non-empty.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -336,22 +357,32 @@ CommitTransactionHandler::_ReadPackagesToActivate(
|
||||
// read the packages
|
||||
for (int32 i = 0; i < packagesToActivateCount; i++) {
|
||||
BString packageName = packagesToActivate.StringAt(i);
|
||||
|
||||
// make sure it doesn't clash with an already existing package
|
||||
// make sure it doesn't clash with an already existing package,
|
||||
// except in first boot mode where it should always clash.
|
||||
Package* package = fVolumeState->FindPackage(packageName);
|
||||
if (package != NULL) {
|
||||
if (fPackagesAlreadyAdded.find(package)
|
||||
!= fPackagesAlreadyAdded.end()) {
|
||||
if (!fPackagesToActivate.AddItem(package))
|
||||
throw Exception(B_TRANSACTION_NO_MEMORY);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fPackagesToDeactivate.find(package)
|
||||
== fPackagesToDeactivate.end()) {
|
||||
throw Exception(B_TRANSACTION_PACKAGE_ALREADY_EXISTS)
|
||||
if (fFirstBootProcessing) {
|
||||
if (package == NULL) {
|
||||
throw Exception(B_TRANSACTION_NO_SUCH_PACKAGE)
|
||||
.SetPackageName(packageName);
|
||||
}
|
||||
if (!fPackagesToActivate.AddItem(package))
|
||||
throw Exception(B_TRANSACTION_NO_MEMORY);
|
||||
continue;
|
||||
} else {
|
||||
if (package != NULL) {
|
||||
if (fPackagesAlreadyAdded.find(package)
|
||||
!= fPackagesAlreadyAdded.end()) {
|
||||
if (!fPackagesToActivate.AddItem(package))
|
||||
throw Exception(B_TRANSACTION_NO_MEMORY);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fPackagesToDeactivate.find(package)
|
||||
== fPackagesToDeactivate.end()) {
|
||||
throw Exception(B_TRANSACTION_PACKAGE_ALREADY_EXISTS)
|
||||
.SetPackageName(packageName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// read the package
|
||||
@ -382,27 +413,31 @@ CommitTransactionHandler::_ReadPackagesToActivate(
|
||||
void
|
||||
CommitTransactionHandler::_ApplyChanges()
|
||||
{
|
||||
// create an old state directory
|
||||
_CreateOldStateDirectory();
|
||||
if (!fFirstBootProcessing)
|
||||
{
|
||||
// create an old state directory
|
||||
_CreateOldStateDirectory();
|
||||
|
||||
// move packages to deactivate to old state directory
|
||||
_RemovePackagesToDeactivate();
|
||||
// move packages to deactivate to old state directory
|
||||
_RemovePackagesToDeactivate();
|
||||
|
||||
// move packages to activate to packages directory
|
||||
_AddPackagesToActivate();
|
||||
// move packages to activate to packages directory
|
||||
_AddPackagesToActivate();
|
||||
|
||||
// run pre-uninstall scripts, before their packages vanish.
|
||||
_RunPreUninstallScripts();
|
||||
// run pre-uninstall scripts, before their packages vanish.
|
||||
_RunPreUninstallScripts();
|
||||
|
||||
// activate/deactivate packages
|
||||
_ChangePackageActivation(fAddedPackages, fRemovedPackages);
|
||||
// activate/deactivate packages and create users, groups, settings files.
|
||||
_ChangePackageActivation(fAddedPackages, fRemovedPackages);
|
||||
} else // FirstBootProcessing, skip several steps and just do package setup.
|
||||
_PrepareFirstBootPackages();
|
||||
|
||||
// run post-installation scripts
|
||||
if (fVolumeStateIsActive) {
|
||||
// run post-install scripts now that the new packages are visible in the
|
||||
// package file system.
|
||||
if (fVolumeStateIsActive || fFirstBootProcessing) {
|
||||
_RunPostInstallScripts();
|
||||
} else {
|
||||
// need to reboot to finish installation so queue up scripts as
|
||||
// symbolic links in a work directory, which will run later.
|
||||
// Do post-install scripts later after a reboot, for Haiku OS packages.
|
||||
_QueuePostInstallScripts();
|
||||
}
|
||||
|
||||
@ -631,6 +666,31 @@ CommitTransactionHandler::_AddPackagesToActivate()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CommitTransactionHandler::_PrepareFirstBootPackages()
|
||||
{
|
||||
int32 count = fPackagesToActivate.CountItems();
|
||||
|
||||
BDirectory transactionDir(&fTransactionDirectoryRef);
|
||||
BEntry transactionEntry;
|
||||
BPath transactionPath;
|
||||
if (transactionDir.InitCheck() == B_OK &&
|
||||
transactionDir.GetEntry(&transactionEntry) == B_OK &&
|
||||
transactionEntry.GetPath(&transactionPath) == B_OK) {
|
||||
INFORM("Starting First Boot Processing for %d packages in %s.\n",
|
||||
(int) count, transactionPath.Path());
|
||||
}
|
||||
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
Package* package = fPackagesToActivate.ItemAt(i);
|
||||
fAddedPackages.insert(package);
|
||||
INFORM("Doing first boot processing #%d for package %s.\n",
|
||||
(int) i, package->FileName().String());
|
||||
_PreparePackageToActivate(package);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CommitTransactionHandler::_PreparePackageToActivate(Package* package)
|
||||
{
|
||||
@ -904,7 +964,8 @@ CommitTransactionHandler::_AddGlobalWritableFileRecurse(Package* package,
|
||||
if (targetDirectory.GetStatFor(targetName, &targetStat) != B_OK) {
|
||||
// target doesn't exist -- just copy
|
||||
PRINT("Volume::CommitTransactionHandler::_AddGlobalWritableFile(): "
|
||||
"couldn't get stat for writable file, copying...\n");
|
||||
"couldn't get stat for writable file \"%s\", copying...\n",
|
||||
targetName);
|
||||
FSTransaction::CreateOperation copyOperation(&fFSTransaction,
|
||||
FSUtils::Entry(targetDirectory, targetName));
|
||||
status_t error = BCopyEngine(BCopyEngine::COPY_RECURSIVELY)
|
||||
@ -947,7 +1008,8 @@ CommitTransactionHandler::_AddGlobalWritableFileRecurse(Package* package,
|
||||
// Source and target entry types don't match or this is an entry
|
||||
// we cannot handle. The user must handle this manually.
|
||||
PRINT("Volume::CommitTransactionHandler::_AddGlobalWritableFile(): "
|
||||
"writable file exists, but type doesn't match previous type\n");
|
||||
"writable file \"%s\" exists, but type doesn't match previous "
|
||||
"type\n", targetName);
|
||||
_AddIssue(TransactionIssueBuilder(
|
||||
BTransactionIssue::B_WRITABLE_FILE_TYPE_MISMATCH)
|
||||
.SetPath1(FSUtils::Entry(targetDirectory, targetName))
|
||||
@ -1003,7 +1065,9 @@ CommitTransactionHandler::_AddGlobalWritableFileRecurse(Package* package,
|
||||
// Can't determine the original package. The user must handle this
|
||||
// manually.
|
||||
PRINT("Volume::CommitTransactionHandler::_AddGlobalWritableFile(): "
|
||||
"failed to get SYS:PACKAGE attribute\n");
|
||||
"failed to get SYS:PACKAGE attribute for \"%s\", can't tell if "
|
||||
"file needs to be updated\n",
|
||||
targetName);
|
||||
if (updateType != B_WRITABLE_FILE_UPDATE_TYPE_KEEP_OLD) {
|
||||
_AddIssue(TransactionIssueBuilder(
|
||||
BTransactionIssue::B_WRITABLE_FILE_NO_PACKAGE_ATTRIBUTE)
|
||||
@ -1015,7 +1079,8 @@ CommitTransactionHandler::_AddGlobalWritableFileRecurse(Package* package,
|
||||
// If that's our package, we're happy.
|
||||
if (originalPackage == package->RevisionedNameThrows()) {
|
||||
PRINT("Volume::CommitTransactionHandler::_AddGlobalWritableFile(): "
|
||||
"file tagged with same package version we're activating\n");
|
||||
"file \"%s\" tagged with same package version we're activating\n",
|
||||
targetName);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1073,8 +1138,8 @@ CommitTransactionHandler::_AddGlobalWritableFileRecurse(Package* package,
|
||||
// handle this manually.
|
||||
PRINT("Volume::CommitTransactionHandler::"
|
||||
"_AddGlobalWritableFile(): "
|
||||
"file comparison failed (%s) or files aren't equal\n",
|
||||
strerror(error));
|
||||
"file comparison \"%s\" failed (%s) or files aren't equal\n",
|
||||
targetName, strerror(error));
|
||||
if (updateType != B_WRITABLE_FILE_UPDATE_TYPE_KEEP_OLD) {
|
||||
if (error != B_OK) {
|
||||
_AddIssue(TransactionIssueBuilder(
|
||||
@ -1108,8 +1173,8 @@ CommitTransactionHandler::_AddGlobalWritableFileRecurse(Package* package,
|
||||
// handle this manually.
|
||||
PRINT("Volume::CommitTransactionHandler::"
|
||||
"_AddGlobalWritableFile(): "
|
||||
"symlink comparison failed (%s) or symlinks aren't equal\n",
|
||||
strerror(error));
|
||||
"symlink comparison \"%s\" failed (%s) or symlinks aren't "
|
||||
"equal\n", targetName, strerror(error));
|
||||
if (updateType != B_WRITABLE_FILE_UPDATE_TYPE_KEEP_OLD) {
|
||||
if (error != B_OK) {
|
||||
_AddIssue(TransactionIssueBuilder(
|
||||
@ -1189,7 +1254,7 @@ CommitTransactionHandler::_AddGlobalWritableFileRecurse(Package* package,
|
||||
void
|
||||
CommitTransactionHandler::_RevertAddPackagesToActivate()
|
||||
{
|
||||
if (fAddedPackages.empty())
|
||||
if (fAddedPackages.empty() || fFirstBootProcessing)
|
||||
return;
|
||||
|
||||
// open transaction directory
|
||||
@ -1244,7 +1309,7 @@ CommitTransactionHandler::_RevertAddPackagesToActivate()
|
||||
void
|
||||
CommitTransactionHandler::_RevertRemovePackagesToDeactivate()
|
||||
{
|
||||
if (fRemovedPackages.empty())
|
||||
if (fRemovedPackages.empty() || fFirstBootProcessing)
|
||||
return;
|
||||
|
||||
// open packages directory
|
||||
@ -1979,4 +2044,4 @@ CommitTransactionHandler::_AssertEntriesAreEqual(const BEntry& entry,
|
||||
"Package file '%s' already exists in target folder "
|
||||
"with equal contents\n", entry.Name());
|
||||
return B_OK;
|
||||
}
|
||||
}
|
||||
|
@ -139,6 +139,7 @@ private:
|
||||
const PackageSet& packagesToActivate,
|
||||
const PackageSet& packagesToDeactivate);
|
||||
// throws Exception
|
||||
void _PrepareFirstBootPackages();
|
||||
void _FillInActivationChangeItem(
|
||||
PackageFSActivationChangeItem* item,
|
||||
PackageFSActivationChangeType type,
|
||||
@ -174,6 +175,7 @@ private:
|
||||
node_ref fOldStateDirectoryRef;
|
||||
BString fOldStateDirectoryName;
|
||||
node_ref fTransactionDirectoryRef;
|
||||
bool fFirstBootProcessing;
|
||||
BDirectory fWritableFilesDirectory;
|
||||
StringSet fAddedGroups;
|
||||
StringSet fAddedUsers;
|
||||
|
@ -14,6 +14,8 @@ const char* const kAdminDirectoryName = PACKAGES_DIRECTORY_ADMIN_DIRECTORY;
|
||||
const char* const kActivationFileName = PACKAGES_DIRECTORY_ACTIVATION_FILE;
|
||||
const char* const kTemporaryActivationFileName
|
||||
= PACKAGES_DIRECTORY_ACTIVATION_FILE ".tmp";
|
||||
const char* const kFirstBootProcessingNeededFileName
|
||||
= "FirstBootProcessingNeeded";
|
||||
const char* const kWritableFilesDirectoryName = "writable-files";
|
||||
const char* const kPackageFileAttribute = "SYS:PACKAGE";
|
||||
const char* const kQueuedScriptsDirectoryName = "queued-scripts";
|
||||
|
@ -13,6 +13,7 @@ extern const char* const kPackageFileNameExtension;
|
||||
extern const char* const kAdminDirectoryName;
|
||||
extern const char* const kActivationFileName;
|
||||
extern const char* const kTemporaryActivationFileName;
|
||||
extern const char* const kFirstBootProcessingNeededFileName;
|
||||
extern const char* const kWritableFilesDirectoryName;
|
||||
extern const char* const kPackageFileAttribute;
|
||||
extern const char* const kQueuedScriptsDirectoryName;
|
||||
|
@ -332,9 +332,75 @@ Volume::InitPackages(Listener* listener)
|
||||
|
||||
// create the admin directory, if it doesn't exist yet
|
||||
BDirectory packagesDirectory;
|
||||
bool createdAdminDirectory = false;
|
||||
if (packagesDirectory.SetTo(&PackagesDirectoryRef()) == B_OK) {
|
||||
if (!BEntry(&packagesDirectory, kAdminDirectoryName).Exists())
|
||||
if (!BEntry(&packagesDirectory, kAdminDirectoryName).Exists()) {
|
||||
packagesDirectory.CreateDirectory(kAdminDirectoryName, NULL);
|
||||
createdAdminDirectory = true;
|
||||
}
|
||||
}
|
||||
BDirectory adminDirectory(&packagesDirectory, kAdminDirectoryName);
|
||||
error = adminDirectory.InitCheck();
|
||||
if (error != B_OK)
|
||||
RETURN_ERROR(error);
|
||||
|
||||
// First boot processing requested by a magic file left by the OS installer?
|
||||
BEntry flagFileEntry(&adminDirectory, kFirstBootProcessingNeededFileName);
|
||||
if (createdAdminDirectory || flagFileEntry.Exists()) {
|
||||
INFORM("Volume::InitPackages Requesting delayed first boot processing "
|
||||
"for packages dir %s.\n", BPath(&packagesDirectory).Path());
|
||||
if (flagFileEntry.Exists())
|
||||
flagFileEntry.Remove(); // Remove early on to avoid an error loop.
|
||||
|
||||
// Are there any packages needing processing? Don't want to create an
|
||||
// empty transaction directory and then never have it cleaned up when
|
||||
// the empty transaction gets rejected.
|
||||
bool anyPackages = false;
|
||||
for (PackageNodeRefHashTable::Iterator it =
|
||||
fActiveState->ByNodeRefIterator(); it.HasNext();) {
|
||||
Package* package = it.Next();
|
||||
if (package->IsActive()) {
|
||||
anyPackages = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (anyPackages) {
|
||||
// Create first boot processing special transaction for current
|
||||
// volume, which also creates an empty transaction directory.
|
||||
BPackageInstallationLocation location = Location();
|
||||
BDirectory transactionDirectory;
|
||||
BActivationTransaction transaction;
|
||||
error = CreateTransaction(location, transaction,
|
||||
transactionDirectory);
|
||||
if (error != B_OK)
|
||||
RETURN_ERROR(error);
|
||||
|
||||
// Add all package files in currently active state to transaction.
|
||||
for (PackageNodeRefHashTable::Iterator it =
|
||||
fActiveState->ByNodeRefIterator(); it.HasNext();) {
|
||||
Package* package = it.Next();
|
||||
if (package->IsActive()) {
|
||||
if (!transaction.AddPackageToActivate(
|
||||
package->FileName().String()))
|
||||
RETURN_ERROR(B_NO_MEMORY);
|
||||
}
|
||||
}
|
||||
transaction.SetFirstBootProcessing(true);
|
||||
|
||||
// Queue up the transaction as a BMessage for processing a bit
|
||||
// later, once the package daemon has finished initialising.
|
||||
BMessage commitMessage(B_MESSAGE_COMMIT_TRANSACTION);
|
||||
error = transaction.Archive(&commitMessage);
|
||||
if (error != B_OK)
|
||||
RETURN_ERROR(error);
|
||||
BLooper *myLooper = Looper() ;
|
||||
if (myLooper == NULL)
|
||||
RETURN_ERROR(B_NOT_INITIALIZED);
|
||||
error = myLooper->PostMessage(&commitMessage);
|
||||
if (error != B_OK)
|
||||
RETURN_ERROR(error);
|
||||
}
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
@ -1003,8 +1069,14 @@ Volume::_InitLatestStateFromActivatedPackages()
|
||||
BFile file;
|
||||
error = file.SetTo(&entryRef, B_READ_ONLY);
|
||||
if (error != B_OK) {
|
||||
INFORM("Failed to open packages activation file: %s\n",
|
||||
strerror(error));
|
||||
BEntry activationEntry(&entryRef);
|
||||
BPath activationPath;
|
||||
const char *activationFilePathName = "Unknown due to errors";
|
||||
if (activationEntry.InitCheck() == B_OK &&
|
||||
activationEntry.GetPath(&activationPath) == B_OK)
|
||||
activationFilePathName = activationPath.Path();
|
||||
INFORM("Failed to open packages activation file %s: %s\n",
|
||||
activationFilePathName, strerror(error));
|
||||
RETURN_ERROR(error);
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@ resource app_flags B_EXCLUSIVE_LAUNCH | B_BACKGROUND_APP;
|
||||
resource app_version {
|
||||
major = 1,
|
||||
middle = 0,
|
||||
minor = 0,
|
||||
minor = 1,
|
||||
|
||||
variety = B_APPV_ALPHA,
|
||||
internal = 0,
|
||||
|
Loading…
Reference in New Issue
Block a user