package daemon: Add support for activation change request

* daemon: Handle new request B_MESSAGE_COMMIT_TRANSACTION. It activates
  and deactivates given sets of packages. The new packages must be
  placed in a directory in the administrative directory. The daemon
  moves them to the packages directory and the deactivated packages to
  a subdirectory it creates. It also save the old activation state
  there.
* Add private BActivationTransaction, describing an activation change
  transaction.
* BDaemonClient: Add CommitTransaction(), which sends a given
  BActivationTransaction as a B_MESSAGE_COMMIT_TRANSACTION request to
  the daemon.

Completely untested yet.
This commit is contained in:
Ingo Weinhold 2013-04-20 01:28:18 +02:00
parent 7a27bcd113
commit 85d2badf00
15 changed files with 1434 additions and 170 deletions

View File

@ -0,0 +1 @@
#include <../private/package/ActivationTransaction.h>

View File

@ -0,0 +1,70 @@
/*
* Copyright 2013, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Ingo Weinhold <ingo_weinhold@gmx.de>
*/
#ifndef _PACKAGE__PRIVATE__ACTIVATION_TRANSACTION_H_
#define _PACKAGE__PRIVATE__ACTIVATION_TRANSACTION_H_
#include <package/PackageDefs.h>
#include <StringList.h>
namespace BPackageKit {
namespace BPrivate {
class BActivationTransaction {
public:
BActivationTransaction();
BActivationTransaction(
BPackageInstallationLocation location,
int64 changeCount,
const BString& directoryName,
const BStringList& packagesToActivate,
const BStringList& packagesToDeactivate);
~BActivationTransaction();
status_t InitCheck() const;
status_t SetTo(BPackageInstallationLocation location,
int64 changeCount,
const BString& directoryName,
const BStringList& packagesToActivate,
const BStringList& packagesToDeactivate);
BPackageInstallationLocation Location() const;
void SetLocation(
BPackageInstallationLocation location);
int64 ChangeCount() const;
void SetChangeCount(int64 changeCount);
const BString& TransactionDirectoryName() const;
void SetTransactionDirectoryName(
const BString& directoryName);
const BStringList& PackagesToActivate() const;
void SetPackagesToActivate(
const BStringList& packages);
const BStringList& PackagesToDeactivate() const;
void SetPackagesToDeactivate(
const BStringList& packages);
private:
BPackageInstallationLocation fLocation;
int64 fChangeCount;
BString fTransactionDirectoryName;
BStringList fPackagesToActivate;
BStringList fPackagesToDeactivate;
};
} // namespace BPrivate
} // namespace BPackageKit
#endif // _PACKAGE__PRIVATE__ACTIVATION_TRANSACTION_H_

View File

@ -11,6 +11,9 @@
#include <Messenger.h>
#include <package/PackageDefs.h>
#include <String.h>
#include <package/DaemonDefs.h>
namespace BPackageKit {
@ -23,7 +26,13 @@ class BPackageInfoSet;
namespace BPrivate {
class BActivationTransaction;
class BDaemonClient {
public:
class BCommitTransactionResult;
public:
BDaemonClient();
~BDaemonClient();
@ -31,17 +40,57 @@ public:
status_t GetInstallationLocationInfo(
BPackageInstallationLocation location,
BInstallationLocationInfo& _info);
status_t CommitTransaction(
const BActivationTransaction& transaction,
BCommitTransactionResult& _result);
private:
status_t _InitMessenger();
status_t _ExtractPackageInfoSet(const BMessage& message,
const char* field, BPackageInfoSet& _infos);
status_t _CommitTransaction(
const BActivationTransaction& transaction,
BCommitTransactionResult& _result);
private:
BMessenger fDaemonMessenger;
};
class BDaemonClient::BCommitTransactionResult {
public:
BCommitTransactionResult();
BCommitTransactionResult(int32 error,
const BString& errorMessage,
const BString& errorPackage,
const BString& oldStateDirectory);
~BCommitTransactionResult();
void SetTo(int32 error, const BString& errorMessage,
const BString& errorPackage,
const BString& oldStateDirectory);
status_t Error() const;
BDaemonError DaemonError() const;
// may be B_DAEMON_OK, even if Error() is
// != B_OK, then Error() is as specific as
// is known
const BString& ErrorMessage() const;
// may be empty, even on error
const BString& ErrorPackage() const;
// may be empty, even on error
const BString& OldStateDirectory() const;
private:
int32 fError;
BString fErrorMessage;
BString fErrorPackage;
BString fOldStateDirectory;
};
} // namespace BPrivate
} // namespace BPackageKit

View File

@ -17,7 +17,11 @@ namespace BPrivate {
enum BDaemonError {
B_DAEMON_OK
B_DAEMON_OK = 0,
B_DAEMON_CHANGE_COUNT_MISMATCH,
B_DAEMON_BAD_REQUEST,
B_DAEMON_NO_SUCH_PACKAGE,
B_DAEMON_PACKAGE_ALREADY_EXISTS
};
@ -36,11 +40,40 @@ enum {
// archived BPackageInfos of the active packages
// "inactive packages": message[]
// archived BPackageInfos of the inactive packages
B_MESSAGE_COMMIT_TRANSACTION = 'PKTC',
// "location": int32
// the respective installation location constant
// "change count": int64
// the expected change count of the installation location; fail,
// if something has changed in the meantime
// "transaction": string
// name of the transaction directory (subdirectory of the
// administrative directory) where to-be-activated packages live
// "activate": string[]
// file names of the packages to activate; must be in the
// transaction directory
// "deactivate": string[]
// file names of the packages to activate; must be in the
// transaction directory
B_MESSAGE_COMMIT_TRANSACTION_REPLY = 'PKTR'
// "error": int32
// regular error code or BDaemonError describing how committing
// the transaction went
// "error message": string
// [error case only] gives some additional information what went
// wrong; optional
// "error package": string
// [error case only] file name of the package causing the error,
// if any in particarly; optional
// "old state": string
// name of the directory (subdirectory of the administrative
// directory) containing the deactivated packages
};
#endif // _PACKAGE__PRIVATE__DAEMON_DEFS_H_
} // namespace BPrivate
} // namespace BPackageKit
#endif // _PACKAGE__PRIVATE__DAEMON_DEFS_H_

View File

@ -67,6 +67,7 @@ BuildPlatformSharedLibrary libpackage_build.so
:
ActivateRepositoryCacheJob.cpp
ActivateRepositoryConfigJob.cpp
ActivationTransaction.cpp
AddRepositoryRequest.cpp
Attributes.cpp
BlockBufferCacheNoLock.cpp

View File

@ -0,0 +1,158 @@
/*
* Copyright 2013, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Ingo Weinhold <ingo_weinhold@gmx.de>
*/
#include <package/ActivationTransaction.h>
namespace BPackageKit {
namespace BPrivate {
BActivationTransaction::BActivationTransaction()
:
fLocation(B_PACKAGE_INSTALLATION_LOCATION_ENUM_COUNT),
fChangeCount(0),
fTransactionDirectoryName(),
fPackagesToActivate(),
fPackagesToDeactivate()
{
}
BActivationTransaction::BActivationTransaction(
BPackageInstallationLocation location, int64 changeCount,
const BString& directoryName, const BStringList& packagesToActivate,
const BStringList& packagesToDeactivate)
:
fLocation(location),
fChangeCount(changeCount),
fTransactionDirectoryName(directoryName),
fPackagesToActivate(packagesToActivate),
fPackagesToDeactivate(packagesToDeactivate)
{
}
BActivationTransaction::~BActivationTransaction()
{
}
status_t
BActivationTransaction::InitCheck() const
{
if (fLocation < 0 || fLocation >= B_PACKAGE_INSTALLATION_LOCATION_ENUM_COUNT
|| fTransactionDirectoryName.IsEmpty()
|| (fPackagesToActivate.IsEmpty() && fPackagesToDeactivate.IsEmpty())) {
return B_BAD_VALUE;
}
return B_OK;
}
status_t
BActivationTransaction::SetTo(BPackageInstallationLocation location,
int64 changeCount, const BString& directoryName,
const BStringList& packagesToActivate,
const BStringList& packagesToDeactivate)
{
if (location < 0 || location >= B_PACKAGE_INSTALLATION_LOCATION_ENUM_COUNT
|| directoryName.IsEmpty()
|| (packagesToActivate.IsEmpty() && packagesToDeactivate.IsEmpty())) {
return B_BAD_VALUE;
}
fLocation = location;
fChangeCount = changeCount;
fTransactionDirectoryName = directoryName;
fPackagesToActivate = packagesToActivate;
fPackagesToDeactivate = packagesToDeactivate;
if (fPackagesToActivate.CountStrings() != packagesToActivate.CountStrings()
|| fPackagesToDeactivate.CountStrings()
!= packagesToDeactivate.CountStrings()) {
return B_NO_MEMORY;
}
return B_OK;
}
BPackageInstallationLocation
BActivationTransaction::Location() const
{
return fLocation;
}
void
BActivationTransaction::SetLocation(BPackageInstallationLocation location)
{
fLocation = location;
}
int64
BActivationTransaction::ChangeCount() const
{
return fChangeCount;
}
void
BActivationTransaction::SetChangeCount(int64 changeCount)
{
fChangeCount = changeCount;
}
const BString&
BActivationTransaction::TransactionDirectoryName() const
{
return fTransactionDirectoryName;
}
void
BActivationTransaction::SetTransactionDirectoryName(
const BString& directoryName)
{
fTransactionDirectoryName = directoryName;
}
const BStringList&
BActivationTransaction::PackagesToActivate() const
{
return fPackagesToActivate;
}
void
BActivationTransaction::SetPackagesToActivate(const BStringList& packages)
{
fPackagesToActivate = packages;
}
const BStringList&
BActivationTransaction::PackagesToDeactivate() const
{
return fPackagesToDeactivate;
}
void
BActivationTransaction::SetPackagesToDeactivate(const BStringList& packages)
{
fPackagesToDeactivate = packages;
}
} // namespace BPrivate
} // namespace BPackageKit

View File

@ -12,13 +12,16 @@
#include <package/InstallationLocationInfo.h>
#include <package/PackageInfo.h>
#include <package/DaemonDefs.h>
#include <package/ActivationTransaction.h>
namespace BPackageKit {
namespace BPrivate {
// #pragma mark - BCommitTransactionResult
BDaemonClient::BDaemonClient()
:
fDaemonMessenger()
@ -87,6 +90,19 @@ BDaemonClient::GetInstallationLocationInfo(
}
status_t
BDaemonClient::CommitTransaction(const BActivationTransaction& transaction,
BCommitTransactionResult& _result)
{
status_t error = _CommitTransaction(transaction, _result);
// B_OK just indicates that _result has been initialized.
if (error != B_OK)
_result.SetTo(error, BString(), BString(), BString());
return _result.Error();
}
status_t
BDaemonClient::_InitMessenger()
{
@ -133,5 +149,136 @@ BDaemonClient::_ExtractPackageInfoSet(const BMessage& message,
}
status_t
BDaemonClient::_CommitTransaction(const BActivationTransaction& transaction,
BCommitTransactionResult& _result)
{
if (transaction.InitCheck() != B_OK)
return B_BAD_VALUE;
status_t error = _InitMessenger();
if (error != B_OK)
return error;
// send the request
BMessage request(B_MESSAGE_COMMIT_TRANSACTION);
if ((error = request.AddInt32("location", transaction.Location())) != B_OK
|| (error = request.AddInt64("change count",
transaction.ChangeCount())) != B_OK
|| (error = request.AddString("transaction",
transaction.TransactionDirectoryName())) != B_OK
|| (error = request.AddStrings("activate",
transaction.PackagesToActivate())) != B_OK
|| (error = request.AddStrings("deactivate",
transaction.PackagesToDeactivate())) != B_OK) {
return error;
}
BMessage reply;
fDaemonMessenger.SendMessage(&request, &reply);
if (reply.what != B_MESSAGE_COMMIT_TRANSACTION_REPLY)
return B_ERROR;
// extract the result
int32 requestError;
error = reply.FindInt32("error", &requestError);
if (error != B_OK)
return error;
BString errorMessage;
BString errorPackage;
BString oldStateDirectory;
if (requestError == 0) {
error = reply.FindString("old state", &oldStateDirectory);
if (error != B_OK)
return error;
} else {
reply.FindString("error message", &errorMessage);
reply.FindString("error package", &errorPackage);
}
_result.SetTo(requestError, errorMessage, errorPackage, oldStateDirectory);
return B_OK;
// Even on error. B_OK just indicates that we have initialized _result.
}
// #pragma mark - BCommitTransactionResult
BDaemonClient::BCommitTransactionResult::BCommitTransactionResult()
:
fError(B_NO_INIT),
fErrorMessage(),
fErrorPackage(),
fOldStateDirectory()
{
}
BDaemonClient::BCommitTransactionResult::BCommitTransactionResult(int32 error,
const BString& errorMessage, const BString& errorPackage,
const BString& oldStateDirectory)
:
fError(error),
fErrorMessage(errorMessage),
fErrorPackage(errorPackage),
fOldStateDirectory(oldStateDirectory)
{
}
BDaemonClient::BCommitTransactionResult::~BCommitTransactionResult()
{
}
void
BDaemonClient::BCommitTransactionResult::SetTo(int32 error,
const BString& errorMessage, const BString& errorPackage,
const BString& oldStateDirectory)
{
fError = error;
fErrorMessage = errorMessage;
fErrorPackage = errorPackage;
fOldStateDirectory = oldStateDirectory;
}
status_t
BDaemonClient::BCommitTransactionResult::Error() const
{
return fError <= 0 ? fError : B_ERROR;
}
BDaemonError
BDaemonClient::BCommitTransactionResult::DaemonError() const
{
return fError > 0 ? (BDaemonError)fError : B_DAEMON_OK;
}
const BString&
BDaemonClient::BCommitTransactionResult::ErrorMessage() const
{
return fErrorMessage;
}
const BString&
BDaemonClient::BCommitTransactionResult::ErrorPackage() const
{
return fErrorPackage;
}
const BString&
BDaemonClient::BCommitTransactionResult::OldStateDirectory() const
{
return fOldStateDirectory;
}
} // namespace BPrivate
} // namespace BPackageKit

View File

@ -46,6 +46,7 @@ SharedLibrary libpackage.so
:
ActivateRepositoryCacheJob.cpp
ActivateRepositoryConfigJob.cpp
ActivationTransaction.cpp
AddRepositoryRequest.cpp
Attributes.cpp
BlockBufferCacheNoLock.cpp

View File

@ -25,7 +25,9 @@ Package::Package()
fInfo(),
fActive(false),
fFileNameHashTableNext(NULL),
fNodeRefHashTableNext(NULL)
fNodeRefHashTableNext(NULL),
fIgnoreEntryCreated(0),
fIgnoreEntryRemoved(0)
{
}

View File

@ -39,6 +39,20 @@ public:
void SetActive(bool active)
{ fActive = active; }
int32 EntryCreatedIgnoreLevel() const
{ return fIgnoreEntryCreated; }
void IncrementEntryCreatedIgnoreLevel()
{ fIgnoreEntryCreated++; }
void DecrementEntryCreatedIgnoreLevel()
{ fIgnoreEntryCreated--; }
int32 EntryRemovedIgnoreLevel() const
{ return fIgnoreEntryRemoved; }
void IncrementEntryRemovedIgnoreLevel()
{ fIgnoreEntryRemoved++; }
void DecrementEntryRemovedIgnoreLevel()
{ fIgnoreEntryRemoved--; }
Package*& FileNameHashTableNext()
{ return fFileNameHashTableNext; }
Package*& NodeRefHashTableNext()
@ -51,6 +65,8 @@ private:
bool fActive;
Package* fFileNameHashTableNext;
Package* fNodeRefHashTableNext;
int32 fIgnoreEntryCreated;
int32 fIgnoreEntryRemoved;
};

View File

@ -86,11 +86,10 @@ PackageDaemon::MessageReceived(BMessage* message)
}
case B_MESSAGE_GET_INSTALLATION_LOCATION_INFO:
case B_MESSAGE_COMMIT_TRANSACTION:
{
if (fSystemRoot == NULL)
break;
fSystemRoot->HandleGetLocationInfoRequest(DetachCurrentMessage());
if (fSystemRoot != NULL)
fSystemRoot->HandleRequest(DetachCurrentMessage());
break;
}

View File

@ -17,9 +17,14 @@
#include <AutoDeleter.h>
#include <AutoLocker.h>
#include <package/DaemonDefs.h>
#include "DebugSupport.h"
using namespace BPackageKit::BPrivate;
// #pragma mark - VolumeJob
@ -42,11 +47,11 @@ private:
};
// #pragma mark - HandleGetLocationInfoRequestJob
// #pragma mark - RequestJob
struct Root::HandleGetLocationInfoRequestJob : public Job {
HandleGetLocationInfoRequestJob(Root* root, BMessage* message)
struct Root::RequestJob : public Job {
RequestJob(Root* root, BMessage* message)
:
fRoot(root),
fMessage(message)
@ -55,7 +60,7 @@ struct Root::HandleGetLocationInfoRequestJob : public Job {
virtual void Do()
{
fRoot->_HandleGetLocationInfoRequest(fMessage.Get());
fRoot->_HandleRequest(fMessage.Get());
}
private:
@ -209,10 +214,9 @@ Root::FindVolume(dev_t deviceID) const
void
Root::HandleGetLocationInfoRequest(BMessage* message)
Root::HandleRequest(BMessage* message)
{
HandleGetLocationInfoRequestJob* job
= new(std::nothrow) HandleGetLocationInfoRequestJob(this, message);
RequestJob* job = new(std::nothrow) RequestJob(this, message);
if (job == NULL) {
delete message;
return;
@ -253,6 +257,22 @@ Root::_GetVolume(PackageFSMountType mountType)
}
Volume*
Root::_GetVolume(BPackageInstallationLocation location)
{
switch ((BPackageInstallationLocation)location) {
case B_PACKAGE_INSTALLATION_LOCATION_SYSTEM:
return fSystemVolume;
case B_PACKAGE_INSTALLATION_LOCATION_COMMON:
return fCommonVolume;
case B_PACKAGE_INSTALLATION_LOCATION_HOME:
return fHomeVolume;
default:
return NULL;
}
}
Volume*
Root::_NextVolumeFor(Volume* volume)
{
@ -314,7 +334,7 @@ Root::_ProcessNodeMonitorEvents(Volume* volume)
void
Root::_HandleGetLocationInfoRequest(BMessage* message)
Root::_HandleRequest(BMessage* message)
{
int32 location;
if (message->FindInt32("location", &location) != B_OK
@ -325,23 +345,19 @@ Root::_HandleGetLocationInfoRequest(BMessage* message)
// get the volume and let it handle the message
AutoLocker<BLocker> locker(fLock);
Volume* volume;
switch ((BPackageInstallationLocation)location) {
case B_PACKAGE_INSTALLATION_LOCATION_SYSTEM:
volume = fSystemVolume;
break;
case B_PACKAGE_INSTALLATION_LOCATION_COMMON:
volume = fCommonVolume;
break;
case B_PACKAGE_INSTALLATION_LOCATION_HOME:
volume = fHomeVolume;
break;
default:
return;
}
Volume* volume = _GetVolume((BPackageInstallationLocation)location);
locker.Unlock();
if (volume != NULL)
volume->HandleGetLocationInfoRequest(message);
if (volume != NULL) {
switch (message->what) {
case B_MESSAGE_GET_INSTALLATION_LOCATION_INFO:
volume->HandleGetLocationInfoRequest(message);
break;
case B_MESSAGE_COMMIT_TRANSACTION:
volume->HandleCommitTransactionRequest(message);
break;
}
}
}

View File

@ -13,6 +13,7 @@
#include <Node.h>
#include <ObjectList.h>
#include <OS.h>
#include <package/PackageDefs.h>
#include <String.h>
#include <Referenceable.h>
@ -41,7 +42,7 @@ public:
Volume* FindVolume(dev_t deviceID) const;
void HandleGetLocationInfoRequest(BMessage* message);
void HandleRequest(BMessage* message);
private:
// Volume::Listener
@ -52,19 +53,20 @@ protected:
private:
struct VolumeJob;
struct HandleGetLocationInfoRequestJob;
struct RequestJob;
friend struct HandleGetLocationInfoRequestJob;
friend struct RequestJob;
private:
Volume** _GetVolume(PackageFSMountType mountType);
Volume* _GetVolume(
BPackageInstallationLocation location);
Volume* _NextVolumeFor(Volume* volume);
void _InitPackages(Volume* volume);
void _DeleteVolume(Volume* volume);
void _ProcessNodeMonitorEvents(Volume* volume);
void _HandleGetLocationInfoRequest(
BMessage* message);
void _HandleRequest(BMessage* message);
status_t _QueueJob(Job* job);

File diff suppressed because it is too large Load Diff

View File

@ -50,6 +50,8 @@ public:
void InitialVerify(Volume* nextVolume,
Volume* nextNextVolume);
void HandleGetLocationInfoRequest(BMessage* message);
void HandleCommitTransactionRequest(
BMessage* message);
void Unmounted();
@ -88,8 +90,13 @@ public:
private:
struct NodeMonitorEvent;
typedef DoublyLinkedList<NodeMonitorEvent> NodeMonitorEventList;
struct RelativePath;
struct Exception;
struct CommitTransactionHandler;
friend struct CommitTransactionHandler;
typedef DoublyLinkedList<NodeMonitorEvent> NodeMonitorEventList;
typedef std::set<Package*> PackageSet;
private:
@ -117,11 +124,34 @@ private:
BSolverRepository& repository,
bool activeOnly, bool installed);
status_t _OpenPackagesFile(const char* subDirectoryPath,
status_t _OpenPackagesFile(
const RelativePath& subDirectoryPath,
const char* fileName, uint32 openMode,
BFile& _file, BEntry* _entry = NULL);
status_t _OpenPackagesSubDirectory(const char* path,
bool create, BDirectory& _directory);
status_t _OpenPackagesSubDirectory(
const RelativePath& path, bool create,
BDirectory& _directory);
status_t _CreateActivationFileContent(
const PackageSet& toActivate,
const PackageSet& toDeactivate,
BString& _content);
status_t _WriteActivationFile(
const RelativePath& directoryPath,
const char* fileName,
const PackageSet& toActivate,
const PackageSet& toDeactivate,
BEntry& _entry);
status_t _WriteTextFile(
const RelativePath& directoryPath,
const char* fileName,
const BString& content, BEntry& _entry);
void _ChangePackageActivation(
const PackageSet& packagesToActivate,
const PackageSet& packagesToDeactivate);
// throws Exception
private:
BString fPath;