* Copyright 2013-2014, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Ingo Weinhold <ingo_weinhold@gmx.de>
*/
#include <package/DaemonClient.h>
#include <time.h>
#include <Directory.h>
#include <Entry.h>
#include <package/CommitTransactionResult.h>
#include <package/InstallationLocationInfo.h>
#include <package/PackageInfo.h>
#include <package/ActivationTransaction.h>
#include <package/PackagesDirectoryDefs.h>
namespace BPackageKit {
namespace BPrivate {
BDaemonClient::BDaemonClient()
:
fDaemonMessenger()
{
}
BDaemonClient::~BDaemonClient()
{
}
status_t
BDaemonClient::GetInstallationLocationInfo(
BPackageInstallationLocation location, BInstallationLocationInfo& _info)
{
status_t error = _InitMessenger();
if (error != B_OK)
return error;
BMessage request(B_MESSAGE_GET_INSTALLATION_LOCATION_INFO);
error = request.AddInt32("location", location);
if (error != B_OK)
return error;
struct stat st;
if (stat("/boot", &st) == 0) {
error = request.AddInt32("volume", st.st_dev);
if (error != B_OK)
return error;
error = request.AddInt64("root", st.st_ino);
if (error != B_OK)
return error;
}
BMessage reply;
error = fDaemonMessenger.SendMessage(&request, &reply);
if (error != B_OK)
return error;
if (reply.what != B_MESSAGE_GET_INSTALLATION_LOCATION_INFO_REPLY)
return B_BAD_REPLY;
int32 baseDirectoryDevice;
int64 baseDirectoryNode;
int32 packagesDirectoryDevice;
int64 packagesDirectoryNode;
int64 changeCount;
BPackageInfoSet latestActivePackages;
BPackageInfoSet latestInactivePackages;
if ((error = reply.FindInt32("base directory device", &baseDirectoryDevice))
!= B_OK
|| (error = reply.FindInt64("base directory node", &baseDirectoryNode))
!= B_OK
|| (error = reply.FindInt32("packages directory device",
&packagesDirectoryDevice)) != B_OK
|| (error = reply.FindInt64("packages directory node",
&packagesDirectoryNode)) != B_OK
|| (error = _ExtractPackageInfoSet(reply, "latest active packages",
latestActivePackages)) != B_OK
|| (error = _ExtractPackageInfoSet(reply, "latest inactive packages",
latestInactivePackages)) != B_OK
|| (error = reply.FindInt64("change count", &changeCount)) != B_OK) {
return error;
}
BPackageInfoSet currentlyActivePackages;
error = _ExtractPackageInfoSet(reply, "currently active packages",
currentlyActivePackages);
if (error != B_OK && error != B_NAME_NOT_FOUND)
return error;
BString oldStateName;
error = reply.FindString("old state", &oldStateName);
if (error != B_OK && error != B_NAME_NOT_FOUND)
return error;
_info.Unset();
_info.SetLocation(location);
_info.SetBaseDirectoryRef(node_ref(baseDirectoryDevice, baseDirectoryNode));
_info.SetPackagesDirectoryRef(
node_ref(packagesDirectoryDevice, packagesDirectoryNode));
_info.SetLatestActivePackageInfos(latestActivePackages);
_info.SetLatestInactivePackageInfos(latestInactivePackages);
_info.SetCurrentlyActivePackageInfos(currentlyActivePackages);
_info.SetOldStateName(oldStateName);
_info.SetChangeCount(changeCount);
return B_OK;
}
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;
BMessage request(B_MESSAGE_COMMIT_TRANSACTION);
error = transaction.Archive(&request);
if (error != B_OK)
return error;
BMessage reply;
fDaemonMessenger.SendMessage(&request, &reply);
if (reply.what != B_MESSAGE_COMMIT_TRANSACTION_REPLY)
return B_ERROR;
return _result.ExtractFromMessage(reply);
}
status_t
BDaemonClient::CreateTransaction(BPackageInstallationLocation location,
BActivationTransaction& _transaction, BDirectory& _transactionDirectory)
{
BInstallationLocationInfo info;
status_t error = GetInstallationLocationInfo(location, info);
if (error != B_OK)
return error;
entry_ref entryRef;
entryRef.device = info.PackagesDirectoryRef().device;
entryRef.directory = info.PackagesDirectoryRef().node;
error = entryRef.set_name(PACKAGES_DIRECTORY_ADMIN_DIRECTORY);
if (error != B_OK)
return error;
BDirectory adminDirectory;
error = adminDirectory.SetTo(&entryRef);
if (error != B_OK)
return error;
int uniqueId = 1;
BString directoryName;
for (;; uniqueId++) {
directoryName.SetToFormat("transaction-%d", uniqueId);
if (directoryName.IsEmpty())
return B_NO_MEMORY;
error = adminDirectory.CreateDirectory(directoryName,
&_transactionDirectory);
if (error == B_OK)
break;
if (error != B_FILE_EXISTS)
return error;
}
error = _transaction.SetTo(location, info.ChangeCount(), directoryName);
if (error != B_OK) {
BEntry entry;
_transactionDirectory.GetEntry(&entry);
_transactionDirectory.Unset();
if (entry.InitCheck() == B_OK)
entry.Remove();
return error;
}
return B_OK;
}
status_t
BDaemonClient::_InitMessenger()
{
if (fDaemonMessenger.IsValid())
return B_OK;
status_t error;
fDaemonMessenger = BMessenger(B_PACKAGE_DAEMON_APP_SIGNATURE, -1, &error);
return error;
}
status_t
BDaemonClient::_ExtractPackageInfoSet(const BMessage& message,
const char* field, BPackageInfoSet& _infos)
{
type_code type;
int32 count;
if (message.GetInfo(field, &type, &count) != B_OK) {
return B_OK;
}
if (type != B_MESSAGE_TYPE)
return B_BAD_DATA;
for (int32 i = 0; i < count; i++) {
BMessage archive;
status_t error = message.FindMessage(field, i, &archive);
if (error != B_OK)
return error;
BPackageInfo info(&archive, &error);
if (error != B_OK)
return error;
error = _infos.AddInfo(info);
if (error != B_OK)
return error;
}
return B_OK;
}
}
}