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 <[email protected]>
Reviewed-by: Niels Sascha Reedijk <[email protected]>
Reviewed-by: Adrien Destugues <[email protected]>
This commit is contained in:
Alexander G. M. Smith
2021-03-14 09:10:18 +00:00
committed by Adrien Destugues
parent e459857d1c
commit 3376ed1a72
12 changed files with 261 additions and 56 deletions
+25 -7
View File
@@ -1,6 +1,8 @@
#!/bin/sh #!/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 title=$1
freshInstallIndicator=$2 freshInstallIndicator=$2
@@ -8,13 +10,29 @@ postInstallDir=$3
if [ -e $freshInstallIndicator ]; then if [ -e $freshInstallIndicator ]; then
# execute scripts # execute scripts
for f in $postInstallDir/*.sh
do if [ "$postInstallDir" == "/boot/system/boot/post-install" ]; then
if [ -f $f ]; then # Special case for one script file that isn't in a package. Rest
echo "Running $title script $f ..." > /dev/dprintf # of the files in there will be run by package_daemon when
$f # 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 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 sync
rm $freshInstallIndicator rm $freshInstallIndicator
+4 -1
View File
@@ -179,7 +179,10 @@ The supported attributes are:
- ``post-install-scripts``: A list of paths of files included in the package, - ``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 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/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, - ``pre-uninstall-scripts``: A list of paths of files included in the package,
which shall be executed on package deactivation. For consistency, each path which shall be executed on package deactivation. For consistency, each path
should start with "boot/pre-uninstall/". should start with "boot/pre-uninstall/".
@@ -21,8 +21,8 @@ namespace BPrivate {
class BActivationTransaction : public BArchivable { class BActivationTransaction : public BArchivable {
public: public:
BActivationTransaction(); BActivationTransaction();
BActivationTransaction(BMessage* archive, BActivationTransaction(BMessage* archive,
status_t* _error = NULL); status_t* _error = NULL);
virtual ~BActivationTransaction(); virtual ~BActivationTransaction();
status_t SetTo(BPackageInstallationLocation location, status_t SetTo(BPackageInstallationLocation location,
@@ -52,6 +52,9 @@ public:
const BStringList& packages); const BStringList& packages);
bool AddPackageToDeactivate(const BString& package); bool AddPackageToDeactivate(const BString& package);
bool FirstBootProcessing() const;
void SetFirstBootProcessing(bool processingIsOn);
virtual status_t Archive(BMessage* archive, virtual status_t Archive(BMessage* archive,
bool deep = true) const; bool deep = true) const;
static BArchivable* Instantiate(BMessage* archive); static BArchivable* Instantiate(BMessage* archive);
@@ -66,6 +69,7 @@ private:
BString fTransactionDirectoryName; BString fTransactionDirectoryName;
BStringList fPackagesToActivate; BStringList fPackagesToActivate;
BStringList fPackagesToDeactivate; BStringList fPackagesToDeactivate;
bool fFirstBootProcessing;
}; };
+5
View File
@@ -47,6 +47,11 @@ enum {
// "deactivate": string[] // "deactivate": string[]
// file names of the packages to activate; must be in the // file names of the packages to activate; must be in the
// transaction directory // 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' B_MESSAGE_COMMIT_TRANSACTION_REPLY = 'PKTR'
// "error": int32 // "error": int32
// a BTransactionError describing how committing the transaction // a BTransactionError describing how committing the transaction
+9
View File
@@ -312,6 +312,15 @@ WorkerThread::_LaunchFinishScript(BPath &path)
if (system(command.String()) != 0) if (system(command.String()) != 0)
return B_ERROR; 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()); command.SetToFormat("rm -f \"%s/home/Desktop/Installer\"", path.Path());
return system(command.String()); return system(command.String());
} }
+27 -3
View File
@@ -24,7 +24,8 @@ BActivationTransaction::BActivationTransaction()
fChangeCount(0), fChangeCount(0),
fTransactionDirectoryName(), fTransactionDirectoryName(),
fPackagesToActivate(), fPackagesToActivate(),
fPackagesToDeactivate() fPackagesToDeactivate(),
fFirstBootProcessing(false)
{ {
} }
@@ -36,10 +37,16 @@ BActivationTransaction::BActivationTransaction(BMessage* archive,
fChangeCount(0), fChangeCount(0),
fTransactionDirectoryName(), fTransactionDirectoryName(),
fPackagesToActivate(), fPackagesToActivate(),
fPackagesToDeactivate() fPackagesToDeactivate(),
fFirstBootProcessing(false)
{ {
status_t error; status_t error;
int32 location; 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 if ((error = archive->FindInt32("location", &location)) == B_OK
&& (error = archive->FindInt64("change count", &fChangeCount)) == B_OK && (error = archive->FindInt64("change count", &fChangeCount)) == B_OK
&& (error = archive->FindString("transaction", && (error = archive->FindString("transaction",
@@ -91,6 +98,7 @@ BActivationTransaction::SetTo(BPackageInstallationLocation location,
fTransactionDirectoryName = directoryName; fTransactionDirectoryName = directoryName;
fPackagesToActivate.MakeEmpty(); fPackagesToActivate.MakeEmpty();
fPackagesToDeactivate.MakeEmpty(); fPackagesToDeactivate.MakeEmpty();
fFirstBootProcessing = false;
return B_OK; 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 status_t
BActivationTransaction::Archive(BMessage* archive, bool deep) const BActivationTransaction::Archive(BMessage* archive, bool deep) const
{ {
@@ -197,7 +219,9 @@ BActivationTransaction::Archive(BMessage* archive, bool deep) const
|| (error = archive->AddStrings("activate", fPackagesToActivate)) || (error = archive->AddStrings("activate", fPackagesToActivate))
!= B_OK != B_OK
|| (error = archive->AddStrings("deactivate", fPackagesToDeactivate)) || (error = archive->AddStrings("deactivate", fPackagesToDeactivate))
!= B_OK) { != B_OK
|| (error = archive->AddBool("first boot processing",
fFirstBootProcessing)) != B_OK) {
return error; return error;
} }
+103 -38
View File
@@ -126,6 +126,7 @@ CommitTransactionHandler::CommitTransactionHandler(Volume* volume,
fOldStateDirectoryRef(), fOldStateDirectoryRef(),
fOldStateDirectoryName(), fOldStateDirectoryName(),
fTransactionDirectoryRef(), fTransactionDirectoryRef(),
fFirstBootProcessing(false),
fWritableFilesDirectory(), fWritableFilesDirectory(),
fAddedGroups(), fAddedGroups(),
fAddedUsers(), fAddedUsers(),
@@ -182,6 +183,7 @@ void
CommitTransactionHandler::HandleRequest(BMessage* request) CommitTransactionHandler::HandleRequest(BMessage* request)
{ {
status_t error; status_t error;
BActivationTransaction transaction(request, &error); BActivationTransaction transaction(request, &error);
if (error == B_OK) if (error == B_OK)
error = transaction.InitCheck(); error = transaction.InitCheck();
@@ -203,6 +205,8 @@ CommitTransactionHandler::HandleRequest(
if (transaction.ChangeCount() != fVolume->ChangeCount()) if (transaction.ChangeCount() != fVolume->ChangeCount())
throw Exception(B_TRANSACTION_CHANGE_COUNT_MISMATCH); throw Exception(B_TRANSACTION_CHANGE_COUNT_MISMATCH);
fFirstBootProcessing = transaction.FirstBootProcessing();
// collect the packages to deactivate // collect the packages to deactivate
_GetPackagesToDeactivate(transaction); _GetPackagesToDeactivate(transaction);
@@ -210,13 +214,30 @@ CommitTransactionHandler::HandleRequest(
_ReadPackagesToActivate(transaction); _ReadPackagesToActivate(transaction);
// anything to do at all? // 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" WARN("Bad package activation request: no packages to activate or"
" deactivate\n"); " deactivate\n");
throw Exception(B_TRANSACTION_BAD_REQUEST); throw Exception(B_TRANSACTION_BAD_REQUEST);
} }
_ApplyChanges(); _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 // read the packages
for (int32 i = 0; i < packagesToActivateCount; i++) { for (int32 i = 0; i < packagesToActivateCount; i++) {
BString packageName = packagesToActivate.StringAt(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); Package* package = fVolumeState->FindPackage(packageName);
if (package != NULL) { if (fFirstBootProcessing) {
if (fPackagesAlreadyAdded.find(package) if (package == NULL) {
!= fPackagesAlreadyAdded.end()) { throw Exception(B_TRANSACTION_NO_SUCH_PACKAGE)
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); .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 // read the package
@@ -382,27 +413,31 @@ CommitTransactionHandler::_ReadPackagesToActivate(
void void
CommitTransactionHandler::_ApplyChanges() CommitTransactionHandler::_ApplyChanges()
{ {
// create an old state directory if (!fFirstBootProcessing)
_CreateOldStateDirectory(); {
// create an old state directory
_CreateOldStateDirectory();
// move packages to deactivate to old state directory // move packages to deactivate to old state directory
_RemovePackagesToDeactivate(); _RemovePackagesToDeactivate();
// move packages to activate to packages directory // move packages to activate to packages directory
_AddPackagesToActivate(); _AddPackagesToActivate();
// run pre-uninstall scripts, before their packages vanish. // run pre-uninstall scripts, before their packages vanish.
_RunPreUninstallScripts(); _RunPreUninstallScripts();
// activate/deactivate packages // activate/deactivate packages and create users, groups, settings files.
_ChangePackageActivation(fAddedPackages, fRemovedPackages); _ChangePackageActivation(fAddedPackages, fRemovedPackages);
} else // FirstBootProcessing, skip several steps and just do package setup.
_PrepareFirstBootPackages();
// run post-installation scripts // run post-install scripts now that the new packages are visible in the
if (fVolumeStateIsActive) { // package file system.
if (fVolumeStateIsActive || fFirstBootProcessing) {
_RunPostInstallScripts(); _RunPostInstallScripts();
} else { } else {
// need to reboot to finish installation so queue up scripts as // Do post-install scripts later after a reboot, for Haiku OS packages.
// symbolic links in a work directory, which will run later.
_QueuePostInstallScripts(); _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 void
CommitTransactionHandler::_PreparePackageToActivate(Package* package) CommitTransactionHandler::_PreparePackageToActivate(Package* package)
{ {
@@ -904,7 +964,8 @@ CommitTransactionHandler::_AddGlobalWritableFileRecurse(Package* package,
if (targetDirectory.GetStatFor(targetName, &targetStat) != B_OK) { if (targetDirectory.GetStatFor(targetName, &targetStat) != B_OK) {
// target doesn't exist -- just copy // target doesn't exist -- just copy
PRINT("Volume::CommitTransactionHandler::_AddGlobalWritableFile(): " 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, FSTransaction::CreateOperation copyOperation(&fFSTransaction,
FSUtils::Entry(targetDirectory, targetName)); FSUtils::Entry(targetDirectory, targetName));
status_t error = BCopyEngine(BCopyEngine::COPY_RECURSIVELY) 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 // Source and target entry types don't match or this is an entry
// we cannot handle. The user must handle this manually. // we cannot handle. The user must handle this manually.
PRINT("Volume::CommitTransactionHandler::_AddGlobalWritableFile(): " 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( _AddIssue(TransactionIssueBuilder(
BTransactionIssue::B_WRITABLE_FILE_TYPE_MISMATCH) BTransactionIssue::B_WRITABLE_FILE_TYPE_MISMATCH)
.SetPath1(FSUtils::Entry(targetDirectory, targetName)) .SetPath1(FSUtils::Entry(targetDirectory, targetName))
@@ -1003,7 +1065,9 @@ CommitTransactionHandler::_AddGlobalWritableFileRecurse(Package* package,
// Can't determine the original package. The user must handle this // Can't determine the original package. The user must handle this
// manually. // manually.
PRINT("Volume::CommitTransactionHandler::_AddGlobalWritableFile(): " 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) { if (updateType != B_WRITABLE_FILE_UPDATE_TYPE_KEEP_OLD) {
_AddIssue(TransactionIssueBuilder( _AddIssue(TransactionIssueBuilder(
BTransactionIssue::B_WRITABLE_FILE_NO_PACKAGE_ATTRIBUTE) BTransactionIssue::B_WRITABLE_FILE_NO_PACKAGE_ATTRIBUTE)
@@ -1015,7 +1079,8 @@ CommitTransactionHandler::_AddGlobalWritableFileRecurse(Package* package,
// If that's our package, we're happy. // If that's our package, we're happy.
if (originalPackage == package->RevisionedNameThrows()) { if (originalPackage == package->RevisionedNameThrows()) {
PRINT("Volume::CommitTransactionHandler::_AddGlobalWritableFile(): " 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; return;
} }
@@ -1073,8 +1138,8 @@ CommitTransactionHandler::_AddGlobalWritableFileRecurse(Package* package,
// handle this manually. // handle this manually.
PRINT("Volume::CommitTransactionHandler::" PRINT("Volume::CommitTransactionHandler::"
"_AddGlobalWritableFile(): " "_AddGlobalWritableFile(): "
"file comparison failed (%s) or files aren't equal\n", "file comparison \"%s\" failed (%s) or files aren't equal\n",
strerror(error)); targetName, strerror(error));
if (updateType != B_WRITABLE_FILE_UPDATE_TYPE_KEEP_OLD) { if (updateType != B_WRITABLE_FILE_UPDATE_TYPE_KEEP_OLD) {
if (error != B_OK) { if (error != B_OK) {
_AddIssue(TransactionIssueBuilder( _AddIssue(TransactionIssueBuilder(
@@ -1108,8 +1173,8 @@ CommitTransactionHandler::_AddGlobalWritableFileRecurse(Package* package,
// handle this manually. // handle this manually.
PRINT("Volume::CommitTransactionHandler::" PRINT("Volume::CommitTransactionHandler::"
"_AddGlobalWritableFile(): " "_AddGlobalWritableFile(): "
"symlink comparison failed (%s) or symlinks aren't equal\n", "symlink comparison \"%s\" failed (%s) or symlinks aren't "
strerror(error)); "equal\n", targetName, strerror(error));
if (updateType != B_WRITABLE_FILE_UPDATE_TYPE_KEEP_OLD) { if (updateType != B_WRITABLE_FILE_UPDATE_TYPE_KEEP_OLD) {
if (error != B_OK) { if (error != B_OK) {
_AddIssue(TransactionIssueBuilder( _AddIssue(TransactionIssueBuilder(
@@ -1189,7 +1254,7 @@ CommitTransactionHandler::_AddGlobalWritableFileRecurse(Package* package,
void void
CommitTransactionHandler::_RevertAddPackagesToActivate() CommitTransactionHandler::_RevertAddPackagesToActivate()
{ {
if (fAddedPackages.empty()) if (fAddedPackages.empty() || fFirstBootProcessing)
return; return;
// open transaction directory // open transaction directory
@@ -1244,7 +1309,7 @@ CommitTransactionHandler::_RevertAddPackagesToActivate()
void void
CommitTransactionHandler::_RevertRemovePackagesToDeactivate() CommitTransactionHandler::_RevertRemovePackagesToDeactivate()
{ {
if (fRemovedPackages.empty()) if (fRemovedPackages.empty() || fFirstBootProcessing)
return; return;
// open packages directory // open packages directory
@@ -139,6 +139,7 @@ private:
const PackageSet& packagesToActivate, const PackageSet& packagesToActivate,
const PackageSet& packagesToDeactivate); const PackageSet& packagesToDeactivate);
// throws Exception // throws Exception
void _PrepareFirstBootPackages();
void _FillInActivationChangeItem( void _FillInActivationChangeItem(
PackageFSActivationChangeItem* item, PackageFSActivationChangeItem* item,
PackageFSActivationChangeType type, PackageFSActivationChangeType type,
@@ -174,6 +175,7 @@ private:
node_ref fOldStateDirectoryRef; node_ref fOldStateDirectoryRef;
BString fOldStateDirectoryName; BString fOldStateDirectoryName;
node_ref fTransactionDirectoryRef; node_ref fTransactionDirectoryRef;
bool fFirstBootProcessing;
BDirectory fWritableFilesDirectory; BDirectory fWritableFilesDirectory;
StringSet fAddedGroups; StringSet fAddedGroups;
StringSet fAddedUsers; StringSet fAddedUsers;
+2
View File
@@ -14,6 +14,8 @@ const char* const kAdminDirectoryName = PACKAGES_DIRECTORY_ADMIN_DIRECTORY;
const char* const kActivationFileName = PACKAGES_DIRECTORY_ACTIVATION_FILE; const char* const kActivationFileName = PACKAGES_DIRECTORY_ACTIVATION_FILE;
const char* const kTemporaryActivationFileName const char* const kTemporaryActivationFileName
= PACKAGES_DIRECTORY_ACTIVATION_FILE ".tmp"; = PACKAGES_DIRECTORY_ACTIVATION_FILE ".tmp";
const char* const kFirstBootProcessingNeededFileName
= "FirstBootProcessingNeeded";
const char* const kWritableFilesDirectoryName = "writable-files"; const char* const kWritableFilesDirectoryName = "writable-files";
const char* const kPackageFileAttribute = "SYS:PACKAGE"; const char* const kPackageFileAttribute = "SYS:PACKAGE";
const char* const kQueuedScriptsDirectoryName = "queued-scripts"; const char* const kQueuedScriptsDirectoryName = "queued-scripts";
+1
View File
@@ -13,6 +13,7 @@ extern const char* const kPackageFileNameExtension;
extern const char* const kAdminDirectoryName; extern const char* const kAdminDirectoryName;
extern const char* const kActivationFileName; extern const char* const kActivationFileName;
extern const char* const kTemporaryActivationFileName; extern const char* const kTemporaryActivationFileName;
extern const char* const kFirstBootProcessingNeededFileName;
extern const char* const kWritableFilesDirectoryName; extern const char* const kWritableFilesDirectoryName;
extern const char* const kPackageFileAttribute; extern const char* const kPackageFileAttribute;
extern const char* const kQueuedScriptsDirectoryName; extern const char* const kQueuedScriptsDirectoryName;
+75 -3
View File
@@ -332,9 +332,75 @@ Volume::InitPackages(Listener* listener)
// create the admin directory, if it doesn't exist yet // create the admin directory, if it doesn't exist yet
BDirectory packagesDirectory; BDirectory packagesDirectory;
bool createdAdminDirectory = false;
if (packagesDirectory.SetTo(&PackagesDirectoryRef()) == B_OK) { if (packagesDirectory.SetTo(&PackagesDirectoryRef()) == B_OK) {
if (!BEntry(&packagesDirectory, kAdminDirectoryName).Exists()) if (!BEntry(&packagesDirectory, kAdminDirectoryName).Exists()) {
packagesDirectory.CreateDirectory(kAdminDirectoryName, NULL); 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; return B_OK;
@@ -1003,8 +1069,14 @@ Volume::_InitLatestStateFromActivatedPackages()
BFile file; BFile file;
error = file.SetTo(&entryRef, B_READ_ONLY); error = file.SetTo(&entryRef, B_READ_ONLY);
if (error != B_OK) { if (error != B_OK) {
INFORM("Failed to open packages activation file: %s\n", BEntry activationEntry(&entryRef);
strerror(error)); 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); RETURN_ERROR(error);
} }
+1 -1
View File
@@ -5,7 +5,7 @@ resource app_flags B_EXCLUSIVE_LAUNCH | B_BACKGROUND_APP;
resource app_version { resource app_version {
major = 1, major = 1,
middle = 0, middle = 0,
minor = 0, minor = 1,
variety = B_APPV_ALPHA, variety = B_APPV_ALPHA,
internal = 0, internal = 0,