launch_daemon: Moved Job+Target into separate files.

This commit is contained in:
Axel Dörfler 2015-06-15 19:21:29 +02:00
parent c086a1834b
commit 8b8780bfe3
6 changed files with 582 additions and 526 deletions

View File

@ -8,6 +8,8 @@ UseHeaders [ FDirName $(HAIKU_TOP) src bin multiuser ] ;
Server launch_daemon
:
LaunchDaemon.cpp
Job.cpp
Target.cpp
Worker.cpp
# init jobs

407
src/servers/launch/Job.cpp Normal file
View File

@ -0,0 +1,407 @@
/*
* Copyright 2015, Axel Dörfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
*/
#include "Job.h"
#include <Entry.h>
#include <Looper.h>
#include <Message.h>
#include "Target.h"
Job::Job(const char* name)
:
BJob(name),
fEnabled(true),
fService(false),
fCreateDefaultPort(false),
fLaunchInSafeMode(true),
fInitStatus(B_NO_INIT),
fTeam(-1),
fTarget(NULL)
{
}
Job::Job(const Job& other)
:
BJob(other.Name()),
fEnabled(other.IsEnabled()),
fService(other.IsService()),
fCreateDefaultPort(other.CreateDefaultPort()),
fLaunchInSafeMode(other.LaunchInSafeMode()),
fInitStatus(B_NO_INIT),
fTeam(-1),
fTarget(other.Target())
{
for (int32 i = 0; i < other.Arguments().CountStrings(); i++)
AddArgument(other.Arguments().StringAt(i));
for (int32 i = 0; i < other.Requirements().CountStrings(); i++)
AddRequirement(other.Requirements().StringAt(i));
PortMap::const_iterator constIterator = other.Ports().begin();
for (; constIterator != other.Ports().end(); constIterator++) {
fPortMap.insert(
std::make_pair(constIterator->first, constIterator->second));
}
PortMap::iterator iterator = fPortMap.begin();
for (; iterator != fPortMap.end(); iterator++)
iterator->second.RemoveData("port");
}
Job::~Job()
{
_DeletePorts();
}
const char*
Job::Name() const
{
return Title().String();
}
bool
Job::IsEnabled() const
{
return fEnabled;
}
void
Job::SetEnabled(bool enable)
{
fEnabled = enable;
}
bool
Job::IsService() const
{
return fService;
}
void
Job::SetService(bool service)
{
fService = service;
}
bool
Job::CreateDefaultPort() const
{
return fCreateDefaultPort;
}
void
Job::SetCreateDefaultPort(bool createPort)
{
fCreateDefaultPort = createPort;
}
void
Job::AddPort(BMessage& data)
{
const char* name = data.GetString("name");
fPortMap.insert(std::pair<BString, BMessage>(BString(name), data));
}
bool
Job::LaunchInSafeMode() const
{
return fLaunchInSafeMode;
}
void
Job::SetLaunchInSafeMode(bool launch)
{
fLaunchInSafeMode = launch;
}
const BStringList&
Job::Arguments() const
{
return fArguments;
}
BStringList&
Job::Arguments()
{
return fArguments;
}
void
Job::AddArgument(const char* argument)
{
fArguments.Add(argument);
}
::Target*
Job::Target() const
{
return fTarget;
}
void
Job::SetTarget(::Target* target)
{
fTarget = target;
}
const BStringList&
Job::Requirements() const
{
return fRequirements;
}
BStringList&
Job::Requirements()
{
return fRequirements;
}
void
Job::AddRequirement(const char* requirement)
{
fRequirements.Add(requirement);
}
status_t
Job::Init(const Finder& finder, std::set<BString>& dependencies)
{
// Only initialize the jobs once
if (fInitStatus != B_NO_INIT)
return fInitStatus;
fInitStatus = B_OK;
if (fTarget != NULL)
fTarget->AddDependency(this);
// Check dependencies
for (int32 index = 0; index < Requirements().CountStrings(); index++) {
const BString& requires = Requirements().StringAt(index);
if (dependencies.find(requires) != dependencies.end()) {
// Found a cyclic dependency
// TODO: log error
return fInitStatus = B_ERROR;
}
dependencies.insert(requires);
Job* dependency = finder.FindJob(requires);
if (dependency != NULL) {
std::set<BString> subDependencies = dependencies;
fInitStatus = dependency->Init(finder, subDependencies);
if (fInitStatus != B_OK) {
// TODO: log error
return fInitStatus;
}
fInitStatus = _AddRequirement(dependency);
} else {
::Target* target = finder.FindTarget(requires);
if (target != NULL)
fInitStatus = _AddRequirement(dependency);
else {
// Could not find dependency
fInitStatus = B_NAME_NOT_FOUND;
}
}
if (fInitStatus != B_OK) {
// TODO: log error
return fInitStatus;
}
}
// Create ports
// TODO: prefix system ports with "system:"
bool defaultPort = false;
for (PortMap::iterator iterator = fPortMap.begin();
iterator != fPortMap.end(); iterator++) {
BString name(Name());
const char* suffix = iterator->second.GetString("name");
if (suffix != NULL)
name << ':' << suffix;
else
defaultPort = true;
const int32 capacity = iterator->second.GetInt32("capacity",
B_LOOPER_PORT_DEFAULT_CAPACITY);
port_id port = create_port(capacity, name.String());
if (port < 0) {
fInitStatus = port;
break;
}
iterator->second.SetInt32("port", port);
}
if (fInitStatus == B_OK && fCreateDefaultPort && !defaultPort) {
BMessage data;
data.AddInt32("capacity", B_LOOPER_PORT_DEFAULT_CAPACITY);
port_id port = create_port(B_LOOPER_PORT_DEFAULT_CAPACITY, Name());
if (port < 0) {
// TODO: log error
fInitStatus = port;
} else {
data.SetInt32("port", port);
AddPort(data);
}
}
return fInitStatus;
}
status_t
Job::InitCheck() const
{
return fInitStatus;
}
team_id
Job::Team() const
{
return fTeam;
}
const PortMap&
Job::Ports() const
{
return fPortMap;
}
port_id
Job::Port(const char* name) const
{
PortMap::const_iterator found = fPortMap.find(name);
if (found != fPortMap.end())
return found->second.GetInt32("port", -1);
return B_NAME_NOT_FOUND;
}
status_t
Job::Launch()
{
if (fArguments.IsEmpty()) {
// TODO: Launch via signature
// We cannot use the BRoster here as it tries to pre-register
// the application.
BString signature("application/");
signature << Name();
return B_NOT_SUPPORTED;
//return be_roster->Launch(signature.String(), (BMessage*)NULL, &fTeam);
}
entry_ref ref;
status_t status = get_ref_for_path(fArguments.StringAt(0).String(), &ref);
if (status != B_OK)
return status;
size_t count = fArguments.CountStrings();
const char* args[count + 1];
for (int32 i = 0; i < fArguments.CountStrings(); i++) {
args[i] = fArguments.StringAt(i);
}
args[count] = NULL;
thread_id thread = load_image(count, args,
const_cast<const char**>(environ));
if (thread >= 0)
resume_thread(thread);
thread_info info;
if (get_thread_info(thread, &info) == B_OK)
fTeam = info.team;
return B_OK;
// return be_roster->Launch(&ref, count, args, &fTeam);
}
bool
Job::IsLaunched() const
{
return fTeam >= 0;
}
status_t
Job::Execute()
{
if (!IsLaunched())
return Launch();
return B_OK;
}
void
Job::_DeletePorts()
{
PortMap::const_iterator iterator = Ports().begin();
for (; iterator != Ports().end(); iterator++) {
port_id port = iterator->second.GetInt32("port", -1);
if (port >= 0)
delete_port(port);
}
}
status_t
Job::_AddRequirement(BJob* dependency)
{
if (dependency == NULL)
return B_OK;
switch (dependency->State()) {
case B_JOB_STATE_WAITING_TO_RUN:
case B_JOB_STATE_STARTED:
case B_JOB_STATE_IN_PROGRESS:
AddDependency(dependency);
break;
case B_JOB_STATE_SUCCEEDED:
// Just queue it without any dependencies
break;
case B_JOB_STATE_FAILED:
case B_JOB_STATE_ABORTED:
// TODO: return appropriate error
return B_BAD_VALUE;
}
return B_OK;
}

102
src/servers/launch/Job.h Normal file
View File

@ -0,0 +1,102 @@
/*
* Copyright 2015, Axel Dörfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
*/
#ifndef JOB_H
#define JOB_H
#include <Job.h>
#include <map>
#include <set>
#include <OS.h>
#include <StringList.h>
using namespace BSupportKit;
class BMessage;
class Finder;
class Target;
typedef std::map<BString, BMessage> PortMap;
class Job : public BJob {
public:
Job(const char* name);
Job(const Job& other);
virtual ~Job();
const char* Name() const;
bool IsEnabled() const;
void SetEnabled(bool enable);
bool IsService() const;
void SetService(bool service);
bool CreateDefaultPort() const;
void SetCreateDefaultPort(bool createPort);
void AddPort(BMessage& data);
bool LaunchInSafeMode() const;
void SetLaunchInSafeMode(bool launch);
const BStringList& Arguments() const;
BStringList& Arguments();
void AddArgument(const char* argument);
::Target* Target() const;
void SetTarget(::Target* target);
const BStringList& Requirements() const;
BStringList& Requirements();
void AddRequirement(const char* requirement);
status_t Init(const Finder& jobs,
std::set<BString>& dependencies);
status_t InitCheck() const;
team_id Team() const;
const PortMap& Ports() const;
port_id Port(const char* name = NULL) const;
status_t Launch();
bool IsLaunched() const;
protected:
virtual status_t Execute();
private:
Job& operator=(const Job& other);
void _DeletePorts();
status_t _AddRequirement(BJob* dependency);
private:
BStringList fArguments;
BStringList fRequirements;
bool fEnabled;
bool fService;
bool fCreateDefaultPort;
bool fLaunchInSafeMode;
PortMap fPortMap;
status_t fInitStatus;
team_id fTeam;
::Target* fTarget;
};
class Finder {
public:
virtual Job* FindJob(const char* name) const = 0;
virtual Target* FindTarget(const char* name) const = 0;
};
#endif // JOB_H

View File

@ -33,6 +33,8 @@
#include "InitRealTimeClockJob.h"
#include "InitSharedMemoryDirectoryJob.h"
#include "InitTemporaryDirectoryJob.h"
#include "Job.h"
#include "Target.h"
#include "Worker.h"
@ -76,9 +78,6 @@ const static settings_template kSettingsTemplate[] = {
};
typedef std::map<BString, BMessage> PortMap;
class Session {
public:
Session(uid_t user, const BMessenger& target);
@ -94,101 +93,6 @@ private:
};
class Target : public BJob {
public:
Target(const char* name);
const char* Name() const;
status_t AddData(const char* name, BMessage& data);
const BMessage& Data() const
{ return fData; }
protected:
virtual status_t Execute();
private:
BMessage fData;
};
class Finder;
class Job : public BJob {
public:
Job(const char* name);
Job(const Job& other);
virtual ~Job();
const char* Name() const;
bool IsEnabled() const;
void SetEnabled(bool enable);
bool IsService() const;
void SetService(bool service);
bool CreateDefaultPort() const;
void SetCreateDefaultPort(bool createPort);
void AddPort(BMessage& data);
bool LaunchInSafeMode() const;
void SetLaunchInSafeMode(bool launch);
const BStringList& Arguments() const;
BStringList& Arguments();
void AddArgument(const char* argument);
::Target* Target() const;
void SetTarget(::Target* target);
const BStringList& Requirements() const;
BStringList& Requirements();
void AddRequirement(const char* requirement);
status_t Init(const Finder& jobs,
std::set<BString>& dependencies);
status_t InitCheck() const;
team_id Team() const;
const PortMap& Ports() const;
port_id Port(const char* name = NULL) const;
status_t Launch();
bool IsLaunched() const;
protected:
virtual status_t Execute();
private:
Job& operator=(const Job& other);
void _DeletePorts();
status_t _AddRequirement(BJob* dependency);
private:
BStringList fArguments;
BStringList fRequirements;
bool fEnabled;
bool fService;
bool fCreateDefaultPort;
bool fLaunchInSafeMode;
PortMap fPortMap;
status_t fInitStatus;
team_id fTeam;
::Target* fTarget;
};
class Finder {
public:
virtual Job* FindJob(const char* name) const = 0;
virtual Target* FindTarget(const char* name) const = 0;
};
typedef std::map<BString, Job*> JobMap;
typedef std::map<uid_t, Session*> SessionMap;
typedef std::map<BString, Target*> TargetMap;
@ -259,403 +163,6 @@ get_leaf(const char* signature)
// #pragma mark -
Job::Job(const char* name)
:
BJob(name),
fEnabled(true),
fService(false),
fCreateDefaultPort(false),
fLaunchInSafeMode(true),
fInitStatus(B_NO_INIT),
fTeam(-1),
fTarget(NULL)
{
}
Job::Job(const Job& other)
:
BJob(other.Name()),
fEnabled(other.IsEnabled()),
fService(other.IsService()),
fCreateDefaultPort(other.CreateDefaultPort()),
fLaunchInSafeMode(other.LaunchInSafeMode()),
fInitStatus(B_NO_INIT),
fTeam(-1),
fTarget(other.Target())
{
for (int32 i = 0; i < other.Arguments().CountStrings(); i++)
AddArgument(other.Arguments().StringAt(i));
for (int32 i = 0; i < other.Requirements().CountStrings(); i++)
AddRequirement(other.Requirements().StringAt(i));
PortMap::const_iterator constIterator = other.Ports().begin();
for (; constIterator != other.Ports().end(); constIterator++) {
fPortMap.insert(
std::make_pair(constIterator->first, constIterator->second));
}
PortMap::iterator iterator = fPortMap.begin();
for (; iterator != fPortMap.end(); iterator++)
iterator->second.RemoveData("port");
}
Job::~Job()
{
_DeletePorts();
}
const char*
Job::Name() const
{
return Title().String();
}
bool
Job::IsEnabled() const
{
return fEnabled;
}
void
Job::SetEnabled(bool enable)
{
fEnabled = enable;
}
bool
Job::IsService() const
{
return fService;
}
void
Job::SetService(bool service)
{
fService = service;
}
bool
Job::CreateDefaultPort() const
{
return fCreateDefaultPort;
}
void
Job::SetCreateDefaultPort(bool createPort)
{
fCreateDefaultPort = createPort;
}
void
Job::AddPort(BMessage& data)
{
const char* name = data.GetString("name");
fPortMap.insert(std::pair<BString, BMessage>(BString(name), data));
}
bool
Job::LaunchInSafeMode() const
{
return fLaunchInSafeMode;
}
void
Job::SetLaunchInSafeMode(bool launch)
{
fLaunchInSafeMode = launch;
}
const BStringList&
Job::Arguments() const
{
return fArguments;
}
BStringList&
Job::Arguments()
{
return fArguments;
}
void
Job::AddArgument(const char* argument)
{
fArguments.Add(argument);
}
::Target*
Job::Target() const
{
return fTarget;
}
void
Job::SetTarget(::Target* target)
{
fTarget = target;
}
const BStringList&
Job::Requirements() const
{
return fRequirements;
}
BStringList&
Job::Requirements()
{
return fRequirements;
}
void
Job::AddRequirement(const char* requirement)
{
fRequirements.Add(requirement);
}
status_t
Job::Init(const Finder& finder, std::set<BString>& dependencies)
{
// Only initialize the jobs once
if (fInitStatus != B_NO_INIT)
return fInitStatus;
fInitStatus = B_OK;
if (fTarget != NULL)
fTarget->AddDependency(this);
// Check dependencies
for (int32 index = 0; index < Requirements().CountStrings(); index++) {
const BString& requires = Requirements().StringAt(index);
if (dependencies.find(requires) != dependencies.end()) {
// Found a cyclic dependency
// TODO: log error
return fInitStatus = B_ERROR;
}
dependencies.insert(requires);
Job* dependency = finder.FindJob(requires);
if (dependency != NULL) {
std::set<BString> subDependencies = dependencies;
fInitStatus = dependency->Init(finder, subDependencies);
if (fInitStatus != B_OK) {
// TODO: log error
return fInitStatus;
}
fInitStatus = _AddRequirement(dependency);
} else {
::Target* target = finder.FindTarget(requires);
if (target != NULL)
fInitStatus = _AddRequirement(dependency);
else {
// Could not find dependency
fInitStatus = B_NAME_NOT_FOUND;
}
}
if (fInitStatus != B_OK) {
// TODO: log error
return fInitStatus;
}
}
// Create ports
// TODO: prefix system ports with "system:"
bool defaultPort = false;
for (PortMap::iterator iterator = fPortMap.begin();
iterator != fPortMap.end(); iterator++) {
BString name(Name());
const char* suffix = iterator->second.GetString("name");
if (suffix != NULL)
name << ':' << suffix;
else
defaultPort = true;
const int32 capacity = iterator->second.GetInt32("capacity",
B_LOOPER_PORT_DEFAULT_CAPACITY);
port_id port = create_port(capacity, name.String());
if (port < 0) {
fInitStatus = port;
break;
}
iterator->second.SetInt32("port", port);
}
if (fInitStatus == B_OK && fCreateDefaultPort && !defaultPort) {
BMessage data;
data.AddInt32("capacity", B_LOOPER_PORT_DEFAULT_CAPACITY);
port_id port = create_port(B_LOOPER_PORT_DEFAULT_CAPACITY, Name());
if (port < 0) {
// TODO: log error
fInitStatus = port;
} else {
data.SetInt32("port", port);
AddPort(data);
}
}
return fInitStatus;
}
status_t
Job::InitCheck() const
{
return fInitStatus;
}
team_id
Job::Team() const
{
return fTeam;
}
const PortMap&
Job::Ports() const
{
return fPortMap;
}
port_id
Job::Port(const char* name) const
{
PortMap::const_iterator found = fPortMap.find(name);
if (found != fPortMap.end())
return found->second.GetInt32("port", -1);
return B_NAME_NOT_FOUND;
}
status_t
Job::Launch()
{
if (fArguments.IsEmpty()) {
// TODO: Launch via signature
// We cannot use the BRoster here as it tries to pre-register
// the application.
BString signature("application/");
signature << Name();
return B_NOT_SUPPORTED;
//return be_roster->Launch(signature.String(), (BMessage*)NULL, &fTeam);
}
entry_ref ref;
status_t status = get_ref_for_path(fArguments.StringAt(0).String(), &ref);
if (status != B_OK)
return status;
size_t count = fArguments.CountStrings();
const char* args[count + 1];
for (int32 i = 0; i < fArguments.CountStrings(); i++) {
args[i] = fArguments.StringAt(i);
}
args[count] = NULL;
thread_id thread = load_image(count, args,
const_cast<const char**>(environ));
if (thread >= 0)
resume_thread(thread);
thread_info info;
if (get_thread_info(thread, &info) == B_OK)
fTeam = info.team;
return B_OK;
// return be_roster->Launch(&ref, count, args, &fTeam);
}
bool
Job::IsLaunched() const
{
return fTeam >= 0;
}
status_t
Job::Execute()
{
if (!IsLaunched())
return Launch();
return B_OK;
}
void
Job::_DeletePorts()
{
PortMap::const_iterator iterator = Ports().begin();
for (; iterator != Ports().end(); iterator++) {
port_id port = iterator->second.GetInt32("port", -1);
if (port >= 0)
delete_port(port);
}
}
status_t
Job::_AddRequirement(BJob* dependency)
{
if (dependency == NULL)
return B_OK;
switch (dependency->State()) {
case B_JOB_STATE_WAITING_TO_RUN:
case B_JOB_STATE_STARTED:
case B_JOB_STATE_IN_PROGRESS:
AddDependency(dependency);
break;
case B_JOB_STATE_SUCCEEDED:
// Just queue it without any dependencies
break;
case B_JOB_STATE_FAILED:
case B_JOB_STATE_ABORTED:
// TODO: return appropriate error
return B_BAD_VALUE;
}
return B_OK;
}
// #pragma mark -
Session::Session(uid_t user, const BMessenger& daemon)
:
fUser(user),
@ -667,37 +174,6 @@ Session::Session(uid_t user, const BMessenger& daemon)
// #pragma mark -
Target::Target(const char* name)
:
BJob(name)
{
}
const char*
Target::Name() const
{
return Title().String();
}
status_t
Target::AddData(const char* name, BMessage& data)
{
return fData.AddMessage(name, &data);
}
status_t
Target::Execute()
{
return B_OK;
}
// #pragma mark -
LaunchDaemon::LaunchDaemon(bool userMode, status_t& error)
:
BServer(kLaunchDaemonSignature, NULL,

View File

@ -0,0 +1,35 @@
/*
* Copyright 2015, Axel Dörfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
*/
#include "Target.h"
Target::Target(const char* name)
:
BJob(name)
{
}
const char*
Target::Name() const
{
return Title().String();
}
status_t
Target::AddData(const char* name, BMessage& data)
{
return fData.AddMessage(name, &data);
}
status_t
Target::Execute()
{
return B_OK;
}

View File

@ -0,0 +1,34 @@
/*
* Copyright 2015, Axel Dörfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
*/
#ifndef TARGET_H
#define TARGET_H
#include <Job.h>
#include <Message.h>
using namespace BSupportKit;
class Target : public BJob {
public:
Target(const char* name);
const char* Name() const;
status_t AddData(const char* name, BMessage& data);
const BMessage& Data() const
{ return fData; }
protected:
virtual status_t Execute();
private:
BMessage fData;
};
#endif // TARGET_H