launch_daemon: Improved target support.

* You can now put jobs/services into a target.
* Instead of having Login started as part of the normal boot process,
  it's now in the "login" target.
* The app_server now launches the login target when a login becomes
  available (ie. during startup, but that could be improved later on).
This commit is contained in:
Axel Dörfler
2015-07-22 20:41:51 +02:00
parent a44d3faf2e
commit c086a1834b
7 changed files with 353 additions and 62 deletions
+5 -3
View File
@@ -71,7 +71,9 @@ service x-vnd.Haiku-power_daemon {
legacy legacy
} }
job x-vnd.Haiku-Login { target login {
launch /system/apps/Login job x-vnd.Haiku-Login {
legacy launch /system/apps/Login
legacy
}
} }
+3 -2
View File
@@ -19,14 +19,15 @@
namespace BPrivate { namespace BPrivate {
#define kLaunchDaemonSignature "application/x-vnd.Haiku-launch_daemon" #define kLaunchDaemonSignature "application/x-vnd.Haiku-launch_daemon"
#define B_LAUNCH_DAEMON_PORT_NAME "system:launch_daemon" #define B_LAUNCH_DAEMON_PORT_NAME "system:launch_daemon"
// message constants // message constants
enum { enum {
B_GET_LAUNCH_DATA = 'lnda', B_GET_LAUNCH_DATA = 'lnda',
B_LAUNCH_TARGET = 'lntg',
B_LAUNCH_SESSION = 'lnse', B_LAUNCH_SESSION = 'lnse',
B_REGISTER_LAUNCH_SESSION = 'lnrs', B_REGISTER_SESSION_DAEMON = 'lnrs',
}; };
+3
View File
@@ -22,6 +22,9 @@ public:
port_id GetPort(const char* signature, port_id GetPort(const char* signature,
const char* name); const char* name);
status_t Target(const char* name, BMessage& data,
const char* baseName = NULL);
status_t StartSession(const char* login, status_t StartSession(const char* login,
const char* password); const char* password);
+1 -1
View File
@@ -14,7 +14,7 @@ public:
Private(BLaunchRoster* roster); Private(BLaunchRoster* roster);
Private(BLaunchRoster& roster); Private(BLaunchRoster& roster);
status_t RegisterSession(const BMessenger& target); status_t RegisterSessionDaemon(const BMessenger& daemon);
private: private:
BLaunchRoster* fRoster; BLaunchRoster* fRoster;
+32 -3
View File
@@ -39,12 +39,12 @@ BLaunchRoster::Private::Private(BLaunchRoster& roster)
status_t status_t
BLaunchRoster::Private::RegisterSession(const BMessenger& target) BLaunchRoster::Private::RegisterSessionDaemon(const BMessenger& daemon)
{ {
BMessage request(B_REGISTER_LAUNCH_SESSION); BMessage request(B_REGISTER_SESSION_DAEMON);
status_t status = request.AddInt32("user", getuid()); status_t status = request.AddInt32("user", getuid());
if (status == B_OK) if (status == B_OK)
status = request.AddMessenger("target", target); status = request.AddMessenger("daemon", daemon);
if (status != B_OK) if (status != B_OK)
return status; return status;
@@ -145,6 +145,35 @@ BLaunchRoster::GetPort(const char* signature, const char* name)
} }
status_t
BLaunchRoster::Target(const char* name, BMessage& data, const char* baseName)
{
if (name == NULL)
return B_BAD_VALUE;
BMessage request(B_LAUNCH_TARGET);
status_t status = request.AddInt32("user", getuid());
if (status == B_OK)
status = request.AddString("target", name);
if (status == B_OK && !data.IsEmpty())
status = request.AddMessage("data", &data);
if (status == B_OK && baseName != NULL)
status = request.AddString("base target", baseName);
if (status != B_OK)
return status;
// send the request
BMessage result;
status = fMessenger.SendMessage(&request, &result);
// evaluate the reply
if (status == B_OK)
status = result.what;
return status;
}
status_t status_t
BLaunchRoster::StartSession(const char* login, const char* password) BLaunchRoster::StartSession(const char* login, const char* password)
{ {
+11 -4
View File
@@ -12,6 +12,11 @@
#include "AppServer.h" #include "AppServer.h"
#include <syslog.h>
#include <LaunchRoster.h>
#include <PortLink.h>
#include "BitmapManager.h" #include "BitmapManager.h"
#include "Desktop.h" #include "Desktop.h"
#include "FontManager.h" #include "FontManager.h"
@@ -19,10 +24,6 @@
#include "ScreenManager.h" #include "ScreenManager.h"
#include "ServerProtocol.h" #include "ServerProtocol.h"
#include <PortLink.h>
#include <syslog.h>
//#define DEBUG_SERVER //#define DEBUG_SERVER
#ifdef DEBUG_SERVER #ifdef DEBUG_SERVER
@@ -66,6 +67,12 @@ AppServer::AppServer(status_t* status)
// Create the bitmap allocator. Object declared in BitmapManager.cpp // Create the bitmap allocator. Object declared in BitmapManager.cpp
gBitmapManager = new BitmapManager(); gBitmapManager = new BitmapManager();
// TODO: check the attached displays, and launch login session for them
BMessage data;
data.AddString("name", "app_server");
data.AddInt32("session", 0);
BLaunchRoster().Target("login", data);
} }
+298 -49
View File
@@ -60,7 +60,16 @@ const static settings_template kJobTemplate[] = {
{0, NULL, NULL} {0, NULL, NULL}
}; };
const static settings_template kTargetTemplate[] = {
{B_STRING_TYPE, "name", NULL, true},
{B_BOOL_TYPE, "reset", NULL},
{B_MESSAGE_TYPE, "job", kJobTemplate},
{B_MESSAGE_TYPE, "service", kJobTemplate},
{0, NULL, NULL}
};
const static settings_template kSettingsTemplate[] = { const static settings_template kSettingsTemplate[] = {
{B_MESSAGE_TYPE, "target", kTargetTemplate},
{B_MESSAGE_TYPE, "job", kJobTemplate}, {B_MESSAGE_TYPE, "job", kJobTemplate},
{B_MESSAGE_TYPE, "service", kJobTemplate}, {B_MESSAGE_TYPE, "service", kJobTemplate},
{0, NULL, NULL} {0, NULL, NULL}
@@ -76,12 +85,12 @@ public:
uid_t User() const uid_t User() const
{ return fUser; } { return fUser; }
const BMessenger& Target() const const BMessenger& Daemon() const
{ return fTarget; } { return fDaemon; }
private: private:
uid_t fUser; uid_t fUser;
BMessenger fTarget; BMessenger fDaemon;
}; };
@@ -89,17 +98,27 @@ class Target : public BJob {
public: public:
Target(const char* name); Target(const char* name);
const char* Name() const;
status_t AddData(const char* name, BMessage& data);
const BMessage& Data() const
{ return fData; }
protected: protected:
virtual status_t Execute(); virtual status_t Execute();
private:
BMessage fData;
}; };
class JobFinder; class Finder;
class Job : public BJob { class Job : public BJob {
public: public:
Job(const char* name); Job(const char* name);
Job(const Job& other);
virtual ~Job(); virtual ~Job();
const char* Name() const; const char* Name() const;
@@ -122,11 +141,14 @@ public:
BStringList& Arguments(); BStringList& Arguments();
void AddArgument(const char* argument); void AddArgument(const char* argument);
::Target* Target() const;
void SetTarget(::Target* target);
const BStringList& Requirements() const; const BStringList& Requirements() const;
BStringList& Requirements(); BStringList& Requirements();
void AddRequirement(const char* requirement); void AddRequirement(const char* requirement);
status_t Init(Target* target, const JobFinder& jobs, status_t Init(const Finder& jobs,
std::set<BString>& dependencies); std::set<BString>& dependencies);
status_t InitCheck() const; status_t InitCheck() const;
@@ -142,7 +164,11 @@ protected:
virtual status_t Execute(); virtual status_t Execute();
private: private:
BString fName; Job& operator=(const Job& other);
void _DeletePorts();
status_t _AddRequirement(BJob* dependency);
private:
BStringList fArguments; BStringList fArguments;
BStringList fRequirements; BStringList fRequirements;
bool fEnabled; bool fEnabled;
@@ -152,25 +178,29 @@ private:
PortMap fPortMap; PortMap fPortMap;
status_t fInitStatus; status_t fInitStatus;
team_id fTeam; team_id fTeam;
::Target* fTarget;
}; };
class JobFinder { class Finder {
public: public:
virtual Job* FindJob(const char* name) const = 0; 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<BString, Job*> JobMap;
typedef std::map<uid_t, Session*> SessionMap; typedef std::map<uid_t, Session*> SessionMap;
typedef std::map<BString, Target*> TargetMap;
class LaunchDaemon : public BServer, public JobFinder { class LaunchDaemon : public BServer, public Finder {
public: public:
LaunchDaemon(bool userMode, status_t& error); LaunchDaemon(bool userMode, status_t& error);
virtual ~LaunchDaemon(); virtual ~LaunchDaemon();
virtual Job* FindJob(const char* name) const; virtual Job* FindJob(const char* name) const;
virtual Target* FindTarget(const char* name) const;
Session* FindSession(uid_t user) const; Session* FindSession(uid_t user) const;
virtual void ReadyToRun(); virtual void ReadyToRun();
@@ -185,10 +215,13 @@ private:
BEntry& directory); BEntry& directory);
status_t _ReadFile(const char* context, BEntry& entry); status_t _ReadFile(const char* context, BEntry& entry);
void _AddJob(bool service, BMessage& message); void _AddJobs(Target* target, BMessage& message);
void _InitJobs(Target* target); void _AddJob(Target* target, bool service,
void _LaunchJobs(); BMessage& message);
void _InitJobs();
void _LaunchJobs(Target* target);
void _AddLaunchJob(Job* job); void _AddLaunchJob(Job* job);
void _AddTarget(Target* target);
status_t _StartSession(const char* login, status_t _StartSession(const char* login,
const char* password); const char* password);
@@ -202,6 +235,7 @@ private:
private: private:
JobMap fJobs; JobMap fJobs;
TargetMap fTargets;
JobQueue fJobQueue; JobQueue fJobQueue;
SessionMap fSessions; SessionMap fSessions;
MainWorker* fMainWorker; MainWorker* fMainWorker;
@@ -233,19 +267,44 @@ Job::Job(const char* name)
fCreateDefaultPort(false), fCreateDefaultPort(false),
fLaunchInSafeMode(true), fLaunchInSafeMode(true),
fInitStatus(B_NO_INIT), fInitStatus(B_NO_INIT),
fTeam(-1) 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() Job::~Job()
{ {
PortMap::const_iterator iterator = Ports().begin(); _DeletePorts();
for (; iterator != Ports().end(); iterator++) {
port_id port = iterator->second.GetInt32("port", -1);
if (port >= 0)
delete_port(port);
}
} }
@@ -341,6 +400,20 @@ Job::AddArgument(const char* argument)
} }
::Target*
Job::Target() const
{
return fTarget;
}
void
Job::SetTarget(::Target* target)
{
fTarget = target;
}
const BStringList& const BStringList&
Job::Requirements() const Job::Requirements() const
{ {
@@ -363,8 +436,7 @@ Job::AddRequirement(const char* requirement)
status_t status_t
Job::Init(Target* target, const JobFinder& jobs, Job::Init(const Finder& finder, std::set<BString>& dependencies)
std::set<BString>& dependencies)
{ {
// Only initialize the jobs once // Only initialize the jobs once
if (fInitStatus != B_NO_INIT) if (fInitStatus != B_NO_INIT)
@@ -372,8 +444,8 @@ Job::Init(Target* target, const JobFinder& jobs,
fInitStatus = B_OK; fInitStatus = B_OK;
if (target != NULL && target->State() < B_JOB_STATE_SUCCEEDED) if (fTarget != NULL)
AddDependency(target); fTarget->AddDependency(this);
// Check dependencies // Check dependencies
@@ -386,21 +458,29 @@ Job::Init(Target* target, const JobFinder& jobs,
} }
dependencies.insert(requires); dependencies.insert(requires);
Job* dependency = jobs.FindJob(requires); Job* dependency = finder.FindJob(requires);
if (dependency != NULL) { if (dependency != NULL) {
std::set<BString> subDependencies = dependencies; std::set<BString> subDependencies = dependencies;
fInitStatus = dependency->Init(target, jobs, subDependencies); fInitStatus = dependency->Init(finder, subDependencies);
if (fInitStatus != B_OK) { if (fInitStatus != B_OK) {
// TODO: log error // TODO: log error
return fInitStatus; return fInitStatus;
} }
AddDependency(dependency); fInitStatus = _AddRequirement(dependency);
} else { } else {
// Could not find dependency ::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 // TODO: log error
return fInitStatus = B_NAME_NOT_FOUND; return fInitStatus;
} }
} }
@@ -487,7 +567,7 @@ Job::Launch()
// We cannot use the BRoster here as it tries to pre-register // We cannot use the BRoster here as it tries to pre-register
// the application. // the application.
BString signature("application/"); BString signature("application/");
signature << fName; signature << Name();
return B_NOT_SUPPORTED; return B_NOT_SUPPORTED;
//return be_roster->Launch(signature.String(), (BMessage*)NULL, &fTeam); //return be_roster->Launch(signature.String(), (BMessage*)NULL, &fTeam);
} }
@@ -534,13 +614,52 @@ Job::Execute()
} }
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 - // #pragma mark -
Session::Session(uid_t user, const BMessenger& target) Session::Session(uid_t user, const BMessenger& daemon)
: :
fUser(user), fUser(user),
fTarget(target) fDaemon(daemon)
{ {
} }
@@ -555,6 +674,20 @@ Target::Target(const char* 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 status_t
Target::Execute() Target::Execute()
{ {
@@ -574,6 +707,8 @@ LaunchDaemon::LaunchDaemon(bool userMode, status_t& error)
fUserMode(userMode) fUserMode(userMode)
{ {
fMainWorker = new MainWorker(fJobQueue); fMainWorker = new MainWorker(fJobQueue);
if (fInitTarget != NULL)
_AddTarget(fInitTarget);
} }
@@ -596,6 +731,20 @@ LaunchDaemon::FindJob(const char* name) const
} }
Target*
LaunchDaemon::FindTarget(const char* name) const
{
if (name == NULL)
return NULL;
TargetMap::const_iterator found = fTargets.find(BString(name).ToLower());
if (found != fTargets.end())
return found->second;
return NULL;
}
Session* Session*
LaunchDaemon::FindSession(uid_t user) const LaunchDaemon::FindSession(uid_t user) const
{ {
@@ -614,7 +763,7 @@ LaunchDaemon::ReadyToRun()
_SetupEnvironment(); _SetupEnvironment();
if (fUserMode) { if (fUserMode) {
BLaunchRoster roster; BLaunchRoster roster;
BLaunchRoster::Private(roster).RegisterSession(this); BLaunchRoster::Private(roster).RegisterSessionDaemon(this);
} else } else
_InitSystem(); _InitSystem();
@@ -627,8 +776,8 @@ LaunchDaemon::ReadyToRun()
fUserMode ? B_FIND_PATHS_USER_ONLY : B_FIND_PATHS_SYSTEM_ONLY, paths); fUserMode ? B_FIND_PATHS_USER_ONLY : B_FIND_PATHS_SYSTEM_ONLY, paths);
_ReadPaths(paths); _ReadPaths(paths);
_InitJobs(fUserMode ? NULL : fInitTarget); _InitJobs();
_LaunchJobs(); _LaunchJobs(NULL);
} }
@@ -648,7 +797,7 @@ LaunchDaemon::MessageReceived(BMessage* message)
Session* session = FindSession(user); Session* session = FindSession(user);
if (session != NULL) { if (session != NULL) {
// Forward request to user launch_daemon // Forward request to user launch_daemon
if (session->Target().SendMessage(message) == B_OK) if (session->Daemon().SendMessage(message) == B_OK)
break; break;
} }
reply.what = B_NAME_NOT_FOUND; reply.what = B_NAME_NOT_FOUND;
@@ -676,6 +825,57 @@ LaunchDaemon::MessageReceived(BMessage* message)
break; break;
} }
case B_LAUNCH_TARGET:
{
uid_t user = _GetUserID(message);
if (user < 0)
break;
const char* name = message->GetString("target");
const char* baseName = message->GetString("base target");
Target* target = FindTarget(name);
if (target == NULL) {
Target* baseTarget = FindTarget(baseName);
if (baseTarget != NULL) {
target = new Target(name);
// Copy all jobs with the base target into the new target
for (JobMap::iterator iterator = fJobs.begin();
iterator != fJobs.end();) {
Job* job = iterator->second;
iterator++;
if (job->Target() == baseTarget) {
Job* copy = new Job(*job);
copy->SetTarget(target);
fJobs.insert(std::make_pair(copy->Name(), copy));
}
}
}
}
if (target == NULL) {
Session* session = FindSession(user);
if (session != NULL) {
// Forward request to user launch_daemon
if (session->Daemon().SendMessage(message) == B_OK)
break;
}
BMessage reply(B_NAME_NOT_FOUND);
message->SendReply(&reply);
break;
}
BMessage data;
if (message->FindMessage("data", &data) == B_OK)
target->AddData(data.GetString("name"), data);
_LaunchJobs(target);
break;
}
case B_LAUNCH_SESSION: case B_LAUNCH_SESSION:
{ {
uid_t user = _GetUserID(message); uid_t user = _GetUserID(message);
@@ -699,7 +899,7 @@ LaunchDaemon::MessageReceived(BMessage* message)
break; break;
} }
case B_REGISTER_LAUNCH_SESSION: case B_REGISTER_SESSION_DAEMON:
{ {
uid_t user = _GetUserID(message); uid_t user = _GetUserID(message);
if (user < 0) if (user < 0)
@@ -792,16 +992,37 @@ LaunchDaemon::_ReadFile(const char* context, BEntry& entry)
status = adapter.ConvertFromDriverSettings(path.Path(), kSettingsTemplate, status = adapter.ConvertFromDriverSettings(path.Path(), kSettingsTemplate,
message); message);
if (status == B_OK) { if (status == B_OK) {
message.PrintToStream(); _AddJobs(NULL, message);
BMessage job;
for (int32 index = 0; message.FindMessage("service", index,
&job) == B_OK; index++) {
_AddJob(true, job);
}
for (int32 index = 0; message.FindMessage("job", index, &job) == B_OK; BMessage targetMessage;
index++) { for (int32 index = 0; message.FindMessage("target", index,
_AddJob(false, job); &targetMessage) == B_OK; index++) {
const char* name = targetMessage.GetString("name");
if (name == NULL) {
// TODO: log error
debug_printf("Target has no name, ignoring it!\n");
continue;
}
Target* target = FindTarget(name);
if (target == NULL) {
target = new Target(name);
_AddTarget(target);
} else if (targetMessage.GetBool("reset")) {
// Remove all jobs from this target
for (JobMap::iterator iterator = fJobs.begin();
iterator != fJobs.end();) {
Job* job = iterator->second;
JobMap::iterator remove = iterator++;
if (job->Target() == target) {
fJobs.erase(remove);
delete job;
}
}
}
_AddJobs(target, targetMessage);
} }
} }
@@ -810,7 +1031,23 @@ LaunchDaemon::_ReadFile(const char* context, BEntry& entry)
void void
LaunchDaemon::_AddJob(bool service, BMessage& message) LaunchDaemon::_AddJobs(Target* target, BMessage& message)
{
BMessage job;
for (int32 index = 0; message.FindMessage("service", index,
&job) == B_OK; index++) {
_AddJob(target, true, job);
}
for (int32 index = 0; message.FindMessage("job", index, &job) == B_OK;
index++) {
_AddJob(target, false, job);
}
}
void
LaunchDaemon::_AddJob(Target* target, bool service, BMessage& message)
{ {
BString name = message.GetString("name"); BString name = message.GetString("name");
if (name.IsEmpty()) { if (name.IsEmpty()) {
@@ -828,6 +1065,7 @@ LaunchDaemon::_AddJob(bool service, BMessage& message)
job->SetCreateDefaultPort(!message.GetBool("legacy", !service)); job->SetCreateDefaultPort(!message.GetBool("legacy", !service));
job->SetLaunchInSafeMode( job->SetLaunchInSafeMode(
!message.GetBool("no_safemode", !job->LaunchInSafeMode())); !message.GetBool("no_safemode", !job->LaunchInSafeMode()));
job->SetTarget(target);
BMessage portMessage; BMessage portMessage;
for (int32 index = 0; for (int32 index = 0;
@@ -847,13 +1085,15 @@ LaunchDaemon::_AddJob(bool service, BMessage& message)
index++) { index++) {
job->AddRequirement(requirement); job->AddRequirement(requirement);
} }
if (fInitTarget != NULL)
job->AddRequirement(fInitTarget->Name());
fJobs.insert(std::pair<BString, Job*>(job->Name(), job)); fJobs.insert(std::pair<BString, Job*>(job->Name(), job));
} }
void void
LaunchDaemon::_InitJobs(Target* target) LaunchDaemon::_InitJobs()
{ {
for (JobMap::iterator iterator = fJobs.begin(); iterator != fJobs.end();) { for (JobMap::iterator iterator = fJobs.begin(); iterator != fJobs.end();) {
Job* job = iterator->second; Job* job = iterator->second;
@@ -862,7 +1102,7 @@ LaunchDaemon::_InitJobs(Target* target)
status_t status = B_NO_INIT; status_t status = B_NO_INIT;
if (job->IsEnabled() && (!_IsSafeMode() || job->LaunchInSafeMode())) { if (job->IsEnabled() && (!_IsSafeMode() || job->LaunchInSafeMode())) {
std::set<BString> dependencies; std::set<BString> dependencies;
status = job->Init(target, *this, dependencies); status = job->Init(*this, dependencies);
} }
if (status != B_OK) { if (status != B_OK) {
@@ -874,18 +1114,20 @@ LaunchDaemon::_InitJobs(Target* target)
// Remove jobs that won't be used later on // Remove jobs that won't be used later on
fJobs.erase(remove); fJobs.erase(remove);
delete job;
} }
} }
} }
void void
LaunchDaemon::_LaunchJobs() LaunchDaemon::_LaunchJobs(Target* target)
{ {
for (JobMap::iterator iterator = fJobs.begin(); iterator != fJobs.end(); for (JobMap::iterator iterator = fJobs.begin(); iterator != fJobs.end();
iterator++) { iterator++) {
Job* job = iterator->second; Job* job = iterator->second;
_AddLaunchJob(job); if (job->Target() == target)
_AddLaunchJob(job);
} }
} }
@@ -898,6 +1140,13 @@ LaunchDaemon::_AddLaunchJob(Job* job)
} }
void
LaunchDaemon::_AddTarget(Target* target)
{
fTargets.insert(std::make_pair(target->Title(), target));
}
status_t status_t
LaunchDaemon::_StartSession(const char* login, const char* password) LaunchDaemon::_StartSession(const char* login, const char* password)
{ {