From 8b8780bfe399a2a8058f4620e5f33f74db097ca2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Mon, 15 Jun 2015 19:21:29 +0200 Subject: [PATCH] launch_daemon: Moved Job+Target into separate files. --- src/servers/launch/Jamfile | 2 + src/servers/launch/Job.cpp | 407 +++++++++++++++++++++ src/servers/launch/Job.h | 102 ++++++ src/servers/launch/LaunchDaemon.cpp | 528 +--------------------------- src/servers/launch/Target.cpp | 35 ++ src/servers/launch/Target.h | 34 ++ 6 files changed, 582 insertions(+), 526 deletions(-) create mode 100644 src/servers/launch/Job.cpp create mode 100644 src/servers/launch/Job.h create mode 100644 src/servers/launch/Target.cpp create mode 100644 src/servers/launch/Target.h diff --git a/src/servers/launch/Jamfile b/src/servers/launch/Jamfile index df2833cdcf..637e649f05 100644 --- a/src/servers/launch/Jamfile +++ b/src/servers/launch/Jamfile @@ -8,6 +8,8 @@ UseHeaders [ FDirName $(HAIKU_TOP) src bin multiuser ] ; Server launch_daemon : LaunchDaemon.cpp + Job.cpp + Target.cpp Worker.cpp # init jobs diff --git a/src/servers/launch/Job.cpp b/src/servers/launch/Job.cpp new file mode 100644 index 0000000000..01a6fdb213 --- /dev/null +++ b/src/servers/launch/Job.cpp @@ -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 +#include +#include + +#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(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& 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 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(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; +} diff --git a/src/servers/launch/Job.h b/src/servers/launch/Job.h new file mode 100644 index 0000000000..017555608f --- /dev/null +++ b/src/servers/launch/Job.h @@ -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 + +#include +#include + +#include +#include + + +using namespace BSupportKit; +class BMessage; + +class Finder; +class Target; + + +typedef std::map 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& 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 diff --git a/src/servers/launch/LaunchDaemon.cpp b/src/servers/launch/LaunchDaemon.cpp index ef57f9ea8f..25d4064a05 100644 --- a/src/servers/launch/LaunchDaemon.cpp +++ b/src/servers/launch/LaunchDaemon.cpp @@ -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 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& 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 JobMap; typedef std::map SessionMap; typedef std::map 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(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& 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 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(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, diff --git a/src/servers/launch/Target.cpp b/src/servers/launch/Target.cpp new file mode 100644 index 0000000000..6ee87a7467 --- /dev/null +++ b/src/servers/launch/Target.cpp @@ -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; +} diff --git a/src/servers/launch/Target.h b/src/servers/launch/Target.h new file mode 100644 index 0000000000..546cb942af --- /dev/null +++ b/src/servers/launch/Target.h @@ -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 +#include + + +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