From 3376ed1a72dc862faea22f98e4610bcf83760749 Mon Sep 17 00:00:00 2001 From: "Alexander G. M. Smith" Date: Tue, 2 Feb 2021 17:27:06 -0500 Subject: [PATCH] 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 Reviewed-by: Niels Sascha Reedijk Reviewed-by: Adrien Destugues --- data/system/boot/PostInstallScript | 32 +++- docs/develop/packages/BuildingPackages.rst | 5 +- .../private/package/ActivationTransaction.h | 8 +- headers/private/package/DaemonDefs.h | 5 + src/apps/installer/WorkerThread.cpp | 9 ++ src/kits/package/ActivationTransaction.cpp | 30 +++- .../package/CommitTransactionHandler.cpp | 143 +++++++++++++----- .../package/CommitTransactionHandler.h | 2 + src/servers/package/Constants.cpp | 2 + src/servers/package/Constants.h | 1 + src/servers/package/Volume.cpp | 78 +++++++++- src/servers/package/package_daemon.rdef | 2 +- 12 files changed, 261 insertions(+), 56 deletions(-) mode change 100644 => 100755 data/system/boot/PostInstallScript diff --git a/data/system/boot/PostInstallScript b/data/system/boot/PostInstallScript old mode 100644 new mode 100755 index 6fa36e591a..e3f665c374 --- a/data/system/boot/PostInstallScript +++ b/data/system/boot/PostInstallScript @@ -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 diff --git a/docs/develop/packages/BuildingPackages.rst b/docs/develop/packages/BuildingPackages.rst index 86928fce99..00bf070fc5 100644 --- a/docs/develop/packages/BuildingPackages.rst +++ b/docs/develop/packages/BuildingPackages.rst @@ -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/". diff --git a/headers/private/package/ActivationTransaction.h b/headers/private/package/ActivationTransaction.h index 02ceeb4e9e..e388cd7a71 100644 --- a/headers/private/package/ActivationTransaction.h +++ b/headers/private/package/ActivationTransaction.h @@ -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; }; diff --git a/headers/private/package/DaemonDefs.h b/headers/private/package/DaemonDefs.h index 0fd7d5767e..bf4f1e0844 100644 --- a/headers/private/package/DaemonDefs.h +++ b/headers/private/package/DaemonDefs.h @@ -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 diff --git a/src/apps/installer/WorkerThread.cpp b/src/apps/installer/WorkerThread.cpp index 7ef6f6cab7..adaef590ca 100644 --- a/src/apps/installer/WorkerThread.cpp +++ b/src/apps/installer/WorkerThread.cpp @@ -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()); } diff --git a/src/kits/package/ActivationTransaction.cpp b/src/kits/package/ActivationTransaction.cpp index 2a73b02fe8..83a598c04e 100644 --- a/src/kits/package/ActivationTransaction.cpp +++ b/src/kits/package/ActivationTransaction.cpp @@ -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; } diff --git a/src/servers/package/CommitTransactionHandler.cpp b/src/servers/package/CommitTransactionHandler.cpp index 2f86307d8d..aa3dbfb66b 100644 --- a/src/servers/package/CommitTransactionHandler.cpp +++ b/src/servers/package/CommitTransactionHandler.cpp @@ -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; -} \ No newline at end of file +} diff --git a/src/servers/package/CommitTransactionHandler.h b/src/servers/package/CommitTransactionHandler.h index a9f65f5b20..0178d84cc1 100644 --- a/src/servers/package/CommitTransactionHandler.h +++ b/src/servers/package/CommitTransactionHandler.h @@ -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; diff --git a/src/servers/package/Constants.cpp b/src/servers/package/Constants.cpp index 2ae3e48f87..d552fc8330 100644 --- a/src/servers/package/Constants.cpp +++ b/src/servers/package/Constants.cpp @@ -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"; diff --git a/src/servers/package/Constants.h b/src/servers/package/Constants.h index e3057e0711..26410a274c 100644 --- a/src/servers/package/Constants.h +++ b/src/servers/package/Constants.h @@ -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; diff --git a/src/servers/package/Volume.cpp b/src/servers/package/Volume.cpp index 79f952a0ac..d2cb6704b8 100644 --- a/src/servers/package/Volume.cpp +++ b/src/servers/package/Volume.cpp @@ -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); } diff --git a/src/servers/package/package_daemon.rdef b/src/servers/package/package_daemon.rdef index fed10e5f94..fd33293397 100644 --- a/src/servers/package/package_daemon.rdef +++ b/src/servers/package/package_daemon.rdef @@ -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,