package kit: get active packages list from daemon
* daemon: Implement private message protocol to retrieve the active packages. * BPackageRoster::GetActivePackages(): Get the active packages list from the daemon.
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2013, Haiku, Inc. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Ingo Weinhold <[email protected]>
|
||||
*/
|
||||
#ifndef _PACKAGE__PRIVATE__PACKAGE_DAEMON_DEFS_H_
|
||||
#define _PACKAGE__PRIVATE__PACKAGE_DAEMON_DEFS_H_
|
||||
|
||||
|
||||
namespace BPackageKit {
|
||||
namespace BPrivate {
|
||||
|
||||
|
||||
#define PACKAGE_DAEMON_APP_SIGNATURE "application/x-vnd.haiku-package_daemon"
|
||||
|
||||
|
||||
// message codes for requests to and replies from the daemon
|
||||
enum {
|
||||
MESSAGE_GET_PACKAGES = 'PKGG',
|
||||
// "location": int32
|
||||
// the respective installation location constant
|
||||
MESSAGE_GET_PACKAGES_REPLY = 'PKGR'
|
||||
// "active packages": string[]
|
||||
// file names of the active packages (no path)
|
||||
// "inactive packages": string[]
|
||||
// file names of the inactive packages (no path)
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // _PACKAGE__PRIVATE__PACKAGE_DAEMON_DEFS_H_
|
||||
|
||||
|
||||
} // namespace BPrivate
|
||||
} // namespace BPackageKit
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include <Directory.h>
|
||||
#include <Entry.h>
|
||||
#include <Messenger.h>
|
||||
#include <Path.h>
|
||||
#include <String.h>
|
||||
#include <StringList.h>
|
||||
@@ -26,6 +27,10 @@
|
||||
|
||||
#include <package/hpkg/PackageReader.h>
|
||||
|
||||
#if defined(__HAIKU__) && !defined(HAIKU_HOST_PLATFORM_HAIKU)
|
||||
# include <package/PackageDaemonDefs.h>
|
||||
#endif
|
||||
|
||||
|
||||
namespace BPackageKit {
|
||||
|
||||
@@ -206,63 +211,45 @@ BPackageRoster::GetActivePackages(BPackageInstallationLocation location,
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// find the package links directory
|
||||
BPath packageLinksPath;
|
||||
status_t error = find_directory(B_PACKAGE_LINKS_DIRECTORY,
|
||||
&packageLinksPath);
|
||||
// get the package daemon's address
|
||||
status_t error;
|
||||
BMessenger messenger(PACKAGE_DAEMON_APP_SIGNATURE, -1, &error);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// request a list of packages
|
||||
BMessage request(BPackageKit::BPrivate::MESSAGE_GET_PACKAGES);
|
||||
error = request.AddInt32("location", location);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
BMessage reply;
|
||||
messenger.SendMessage(&request, &reply);
|
||||
if (reply.what != BPackageKit::BPrivate::MESSAGE_GET_PACKAGES_REPLY)
|
||||
return B_ERROR;
|
||||
|
||||
// find and open the packages directory
|
||||
BPath packagesDirPath;
|
||||
error = find_directory(packagesDirectory, &packagesDirPath);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
BDirectory directory;
|
||||
error = directory.SetTo(packagesDirPath.Path());
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// TODO: Implement that correctly be reading the activation files/directory!
|
||||
|
||||
// iterate through the packages
|
||||
char buffer[sizeof(dirent) + B_FILE_NAME_LENGTH];
|
||||
dirent* entry = (dirent*)&buffer;
|
||||
while (directory.GetNextDirents(entry, sizeof(buffer), 1) == 1) {
|
||||
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
|
||||
continue;
|
||||
|
||||
const char* packageFileName;
|
||||
for (int32 i = 0;
|
||||
reply.FindString("active packages", i, &packageFileName) == B_OK; i++) {
|
||||
// get the full package file path
|
||||
BPath packagePath;
|
||||
error = packagePath.SetTo(packagesDirPath.Path(), entry->d_name);
|
||||
error = packagePath.SetTo(packagesDirPath.Path(), packageFileName);
|
||||
if (error != B_OK)
|
||||
continue;
|
||||
|
||||
// read the package info from the file
|
||||
BPackageReader packageReader(NULL);
|
||||
error = packageReader.Init(packagePath.Path());
|
||||
if (error != B_OK)
|
||||
continue;
|
||||
|
||||
BPackageInfo info;
|
||||
BPackageInfoContentHandler handler(info);
|
||||
error = packageReader.ParseContent(&handler);
|
||||
error = info.ReadFromPackageFile(packagePath.Path());
|
||||
if (error != B_OK || info.InitCheck() != B_OK)
|
||||
continue;
|
||||
|
||||
// check whether the package is really active by verifying that a
|
||||
// package link exists for it
|
||||
BString packageLinkName(info.Name());
|
||||
packageLinkName << '-' << info.Version().ToString();
|
||||
BPath packageLinkPath;
|
||||
struct stat st;
|
||||
if (packageLinkPath.SetTo(packageLinksPath.Path(), packageLinkName)
|
||||
!= B_OK
|
||||
|| lstat(packageLinkPath.Path(), &st) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// add the info
|
||||
error = packageInfos.AddInfo(info);
|
||||
if (error != B_OK)
|
||||
|
||||
@@ -16,15 +16,19 @@
|
||||
#include <NodeMonitor.h>
|
||||
|
||||
#include <AutoDeleter.h>
|
||||
#include <package/PackageDaemonDefs.h>
|
||||
|
||||
#include "DebugSupport.h"
|
||||
#include "Root.h"
|
||||
#include "Volume.h"
|
||||
|
||||
|
||||
using namespace BPackageKit::BPrivate;
|
||||
|
||||
|
||||
PackageDaemon::PackageDaemon(status_t* _error)
|
||||
:
|
||||
BServer("application/x-vnd.haiku-package_daemon", false, _error),
|
||||
BServer(PACKAGE_DAEMON_APP_SIGNATURE, false, _error),
|
||||
fSystemRoot(NULL),
|
||||
fRoots(10, true),
|
||||
fVolumeWatcher()
|
||||
@@ -34,7 +38,6 @@ PackageDaemon::PackageDaemon(status_t* _error)
|
||||
|
||||
PackageDaemon::~PackageDaemon()
|
||||
{
|
||||
// delete fSystemRoot;
|
||||
}
|
||||
|
||||
|
||||
@@ -56,6 +59,11 @@ PackageDaemon::Init()
|
||||
_RegisterVolume(device);
|
||||
}
|
||||
|
||||
// find the system root
|
||||
struct stat st;
|
||||
if (stat("/boot", &st) == 0)
|
||||
fSystemRoot = _FindRoot(node_ref(st.st_dev, st.st_ino));
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@@ -76,6 +84,16 @@ PackageDaemon::MessageReceived(BMessage* message)
|
||||
_HandleVolumeUnmounted(message);
|
||||
break;
|
||||
}
|
||||
|
||||
case MESSAGE_GET_PACKAGES:
|
||||
{
|
||||
if (fSystemRoot == NULL)
|
||||
break;
|
||||
|
||||
fSystemRoot->HandleGetPackagesRequest(DetachCurrentMessage());
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
BServer::MessageReceived(message);
|
||||
break;
|
||||
|
||||
@@ -11,8 +11,12 @@
|
||||
|
||||
#include <Directory.h>
|
||||
#include <Entry.h>
|
||||
#include <package/PackageDefs.h>
|
||||
#include <Path.h>
|
||||
|
||||
#include <AutoDeleter.h>
|
||||
#include <AutoLocker.h>
|
||||
|
||||
#include "DebugSupport.h"
|
||||
|
||||
|
||||
@@ -38,11 +42,34 @@ private:
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark - VolumeJob
|
||||
|
||||
|
||||
struct Root::HandleGetPackagesJob : public Job {
|
||||
HandleGetPackagesJob(Root* root, BMessage* message)
|
||||
:
|
||||
fRoot(root),
|
||||
fMessage(message)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void Do()
|
||||
{
|
||||
fRoot->_HandleGetPackagesRequest(fMessage.Get());
|
||||
}
|
||||
|
||||
private:
|
||||
Root* fRoot;
|
||||
ObjectDeleter<BMessage> fMessage;
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark - Root
|
||||
|
||||
|
||||
Root::Root()
|
||||
:
|
||||
fLock("packagefs root"),
|
||||
fNodeRef(),
|
||||
fPath(),
|
||||
fSystemVolume(NULL),
|
||||
@@ -68,11 +95,15 @@ Root::Init(const node_ref& nodeRef)
|
||||
{
|
||||
fNodeRef = nodeRef;
|
||||
|
||||
// init job queue and spawn job runner thread
|
||||
// init members and spawn job runner thread
|
||||
status_t error = fJobQueue.Init();
|
||||
if (error != B_OK)
|
||||
RETURN_ERROR(error);
|
||||
|
||||
error = fLock.InitCheck();
|
||||
if (error != B_OK)
|
||||
RETURN_ERROR(error);
|
||||
|
||||
fJobRunner = spawn_thread(&_JobRunnerEntry, "job runner", B_NORMAL_PRIORITY,
|
||||
this);
|
||||
if (fJobRunner < 0)
|
||||
@@ -112,6 +143,8 @@ Root::Init(const node_ref& nodeRef)
|
||||
status_t
|
||||
Root::RegisterVolume(Volume* volume)
|
||||
{
|
||||
AutoLocker<BLocker> locker(fLock);
|
||||
|
||||
Volume** volumeToSet = _GetVolume(volume->MountType());
|
||||
if (volumeToSet == NULL)
|
||||
return B_BAD_VALUE;
|
||||
@@ -142,6 +175,8 @@ Root::RegisterVolume(Volume* volume)
|
||||
void
|
||||
Root::UnregisterVolume(Volume* volume)
|
||||
{
|
||||
AutoLocker<BLocker> locker(fLock);
|
||||
|
||||
Volume** volumeToSet = _GetVolume(volume->MountType());
|
||||
if (volumeToSet == NULL || *volumeToSet != volume) {
|
||||
ERROR("Root::UnregisterVolume(): can't unregister unknown volume at "
|
||||
@@ -160,6 +195,8 @@ Root::UnregisterVolume(Volume* volume)
|
||||
Volume*
|
||||
Root::FindVolume(dev_t deviceID) const
|
||||
{
|
||||
AutoLocker<BLocker> locker(fLock);
|
||||
|
||||
Volume* volumes[] = { fSystemVolume, fCommonVolume, fHomeVolume };
|
||||
for (size_t i = 0; i < sizeof(volumes) / sizeof(volumes[0]); i++) {
|
||||
Volume* volume = volumes[i];
|
||||
@@ -171,6 +208,20 @@ Root::FindVolume(dev_t deviceID) const
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Root::HandleGetPackagesRequest(BMessage* message)
|
||||
{
|
||||
HandleGetPackagesJob* job
|
||||
= new(std::nothrow) HandleGetPackagesJob(this, message);
|
||||
if (job == NULL) {
|
||||
delete message;
|
||||
return;
|
||||
}
|
||||
|
||||
_QueueJob(job);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Root::VolumeNodeMonitorEventOccurred(Volume* volume)
|
||||
{
|
||||
@@ -235,8 +286,11 @@ void
|
||||
Root::_InitPackages(Volume* volume)
|
||||
{
|
||||
if (volume->InitPackages(this) == B_OK) {
|
||||
AutoLocker<BLocker> locker(fLock);
|
||||
Volume* nextVolume = _NextVolumeFor(volume);
|
||||
Volume* nextNextVolume = _NextVolumeFor(nextVolume);
|
||||
locker.Unlock();
|
||||
|
||||
volume->InitialVerify(nextVolume, nextNextVolume);
|
||||
}
|
||||
}
|
||||
@@ -259,6 +313,38 @@ Root::_ProcessNodeMonitorEvents(Volume* volume)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Root::_HandleGetPackagesRequest(BMessage* message)
|
||||
{
|
||||
int32 location;
|
||||
if (message->FindInt32("location", &location) != B_OK
|
||||
|| location < 0
|
||||
|| location >= B_PACKAGE_INSTALLATION_LOCATION_ENUM_COUNT) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
if (volume != NULL)
|
||||
volume->HandleGetPackagesRequest(message);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Root::_QueueJob(Job* job)
|
||||
{
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#define ROOT_H
|
||||
|
||||
|
||||
#include <Locker.h>
|
||||
#include <Node.h>
|
||||
#include <ObjectList.h>
|
||||
#include <OS.h>
|
||||
@@ -40,6 +41,8 @@ public:
|
||||
|
||||
Volume* FindVolume(dev_t deviceID) const;
|
||||
|
||||
void HandleGetPackagesRequest(BMessage* message);
|
||||
|
||||
private:
|
||||
// Volume::Listener
|
||||
virtual void VolumeNodeMonitorEventOccurred(Volume* volume);
|
||||
@@ -49,6 +52,9 @@ protected:
|
||||
|
||||
private:
|
||||
struct VolumeJob;
|
||||
struct HandleGetPackagesJob;
|
||||
|
||||
friend struct HandleGetPackagesJob;
|
||||
|
||||
private:
|
||||
Volume** _GetVolume(PackageFSMountType mountType);
|
||||
@@ -57,6 +63,7 @@ private:
|
||||
void _InitPackages(Volume* volume);
|
||||
void _DeleteVolume(Volume* volume);
|
||||
void _ProcessNodeMonitorEvents(Volume* volume);
|
||||
void _HandleGetPackagesRequest(BMessage* message);
|
||||
|
||||
status_t _QueueJob(Job* job);
|
||||
|
||||
@@ -64,6 +71,7 @@ private:
|
||||
status_t _JobRunner();
|
||||
|
||||
private:
|
||||
mutable BLocker fLock;
|
||||
node_ref fNodeRef;
|
||||
BString fPath;
|
||||
Volume* fSystemVolume;
|
||||
|
||||
@@ -30,11 +30,15 @@
|
||||
|
||||
#include <AutoDeleter.h>
|
||||
#include <AutoLocker.h>
|
||||
#include <package/PackageDaemonDefs.h>
|
||||
#include <package/PackagesDirectoryDefs.h>
|
||||
|
||||
#include "DebugSupport.h"
|
||||
|
||||
|
||||
using namespace BPackageKit::BPrivate;
|
||||
|
||||
|
||||
static const char* const kPackageFileNameExtension = ".hpkg";
|
||||
static const char* const kConfigDirectoryName
|
||||
= PACKAGES_DIRECTORY_CONFIG_DIRECTORY;
|
||||
@@ -43,6 +47,8 @@ static const char* const kActivationFileName
|
||||
static const char* const kTemporaryActivationFileName
|
||||
= PACKAGES_DIRECTORY_ACTIVATION_FILE ".tmp";
|
||||
|
||||
static bigtime_t kCommunicationTimeout = 1000000;
|
||||
|
||||
|
||||
// #pragma mark - Listener
|
||||
|
||||
@@ -328,6 +334,24 @@ INFORM("Volume::InitialVerify(%p, %p)\n", nextVolume, nextNextVolume);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Volume::HandleGetPackagesRequest(BMessage* message)
|
||||
{
|
||||
BMessage reply(MESSAGE_GET_PACKAGES_REPLY);
|
||||
|
||||
for (PackageFileNameHashTable::Iterator it
|
||||
= fPackagesByFileName.GetIterator(); it.HasNext();) {
|
||||
Package* package = it.Next();
|
||||
const char* fieldName = package->IsActive()
|
||||
? "active packages" : "inactive packages";
|
||||
if (reply.AddString(fieldName, package->FileName()) != B_OK)
|
||||
return;
|
||||
}
|
||||
|
||||
message->SendReply(&reply, (BHandler*)NULL, kCommunicationTimeout);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Volume::Unmounted()
|
||||
{
|
||||
|
||||
@@ -48,6 +48,7 @@ public:
|
||||
bool activeOnly);
|
||||
void InitialVerify(Volume* nextVolume,
|
||||
Volume* nextNextVolume);
|
||||
void HandleGetPackagesRequest(BMessage* message);
|
||||
|
||||
void Unmounted();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user