launch_daemon: Added basic ability to stop/start jobs via API.
* Stopping a job is very simplistic right now, and will have to be extended considerably, probably with its own job.
This commit is contained in:
@@ -26,6 +26,8 @@ namespace BPrivate {
|
||||
enum {
|
||||
B_GET_LAUNCH_DATA = 'lnda',
|
||||
B_LAUNCH_TARGET = 'lntg',
|
||||
B_LAUNCH_JOB = 'lnjo',
|
||||
B_STOP_LAUNCH_JOB = 'lnsj',
|
||||
B_LAUNCH_SESSION = 'lnse',
|
||||
B_REGISTER_SESSION_DAEMON = 'lnrs',
|
||||
B_REGISTER_LAUNCH_EVENT = 'lnre',
|
||||
|
||||
@@ -34,6 +34,9 @@ public:
|
||||
const BMessage* data = NULL,
|
||||
const char* baseName = NULL);
|
||||
|
||||
status_t Start(const char* name);
|
||||
status_t Stop(const char* name, bool force = false);
|
||||
|
||||
status_t StartSession(const char* login);
|
||||
|
||||
status_t RegisterEvent(const BMessenger& source,
|
||||
@@ -56,6 +59,9 @@ private:
|
||||
friend class Private;
|
||||
|
||||
void _InitMessenger();
|
||||
status_t _SendRequest(BMessage& request);
|
||||
status_t _SendRequest(BMessage& request,
|
||||
BMessage& reply);
|
||||
status_t _UpdateEvent(uint32 what,
|
||||
const BMessenger& source, const char* name,
|
||||
uint32 flags = 0);
|
||||
|
||||
@@ -102,14 +102,7 @@ BLaunchRoster::GetData(const char* signature, BMessage& data)
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
// send the request
|
||||
status = fMessenger.SendMessage(&request, &data);
|
||||
|
||||
// evaluate the reply
|
||||
if (status == B_OK)
|
||||
status = data.what;
|
||||
|
||||
return status;
|
||||
return _SendRequest(request, data);
|
||||
}
|
||||
|
||||
|
||||
@@ -169,15 +162,43 @@ BLaunchRoster::Target(const char* name, const BMessage* data,
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
// send the request
|
||||
BMessage result;
|
||||
status = fMessenger.SendMessage(&request, &result);
|
||||
return _SendRequest(request);
|
||||
}
|
||||
|
||||
// evaluate the reply
|
||||
|
||||
status_t
|
||||
BLaunchRoster::Start(const char* name)
|
||||
{
|
||||
if (name == NULL)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
BMessage request(B_LAUNCH_JOB);
|
||||
status_t status = request.AddInt32("user", getuid());
|
||||
if (status == B_OK)
|
||||
status = result.what;
|
||||
status = request.AddString("name", name);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
return status;
|
||||
return _SendRequest(request);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BLaunchRoster::Stop(const char* name, bool force)
|
||||
{
|
||||
if (name == NULL)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
BMessage request(B_STOP_LAUNCH_JOB);
|
||||
status_t status = request.AddInt32("user", getuid());
|
||||
if (status == B_OK)
|
||||
status = request.AddString("name", name);
|
||||
if (status == B_OK)
|
||||
status = request.AddBool("force", force);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
return _SendRequest(request);
|
||||
}
|
||||
|
||||
|
||||
@@ -194,15 +215,7 @@ BLaunchRoster::StartSession(const char* login)
|
||||
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;
|
||||
return _SendRequest(request);
|
||||
}
|
||||
|
||||
|
||||
@@ -245,12 +258,7 @@ BLaunchRoster::GetTargets(BStringList& targets)
|
||||
|
||||
// send the request
|
||||
BMessage result;
|
||||
status = fMessenger.SendMessage(&request, &result);
|
||||
|
||||
// evaluate the reply
|
||||
if (status == B_OK)
|
||||
status = result.what;
|
||||
|
||||
status = _SendRequest(request, result);
|
||||
if (status == B_OK)
|
||||
status = result.FindStrings("target", &targets);
|
||||
|
||||
@@ -277,12 +285,7 @@ BLaunchRoster::GetJobs(const char* target, BStringList& jobs)
|
||||
|
||||
// send the request
|
||||
BMessage result;
|
||||
status = fMessenger.SendMessage(&request, &result);
|
||||
|
||||
// evaluate the reply
|
||||
if (status == B_OK)
|
||||
status = result.what;
|
||||
|
||||
status = _SendRequest(request, result);
|
||||
if (status == B_OK)
|
||||
status = result.FindStrings("job", &jobs);
|
||||
|
||||
@@ -310,6 +313,26 @@ BLaunchRoster::_InitMessenger()
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BLaunchRoster::_SendRequest(BMessage& request)
|
||||
{
|
||||
BMessage result;
|
||||
return _SendRequest(request, result);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BLaunchRoster::_SendRequest(BMessage& request, BMessage& result)
|
||||
{
|
||||
// Send the request, and evaluate the reply
|
||||
status_t status = fMessenger.SendMessage(&request, &result);
|
||||
if (status == B_OK)
|
||||
status = result.what;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BLaunchRoster::_UpdateEvent(uint32 what, const BMessenger& source,
|
||||
const char* name, uint32 flags)
|
||||
@@ -330,15 +353,7 @@ BLaunchRoster::_UpdateEvent(uint32 what, const BMessenger& source,
|
||||
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;
|
||||
return _SendRequest(request);
|
||||
}
|
||||
|
||||
|
||||
@@ -355,13 +370,5 @@ BLaunchRoster::_GetInfo(uint32 what, const char* name, BMessage& info)
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
// send the request
|
||||
BMessage result;
|
||||
status = fMessenger.SendMessage(&request, &info);
|
||||
|
||||
// evaluate the reply
|
||||
if (status == B_OK)
|
||||
status = result.what;
|
||||
|
||||
return status;
|
||||
return _SendRequest(request, info);
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <Message.h>
|
||||
#include <Roster.h>
|
||||
|
||||
#include <MessagePrivate.h>
|
||||
#include <RosterPrivate.h>
|
||||
#include <user_group.h>
|
||||
|
||||
@@ -43,6 +44,7 @@ Job::Job(const Job& other)
|
||||
fEnabled(other.IsEnabled()),
|
||||
fService(other.IsService()),
|
||||
fCreateDefaultPort(other.CreateDefaultPort()),
|
||||
fLaunching(other.IsLaunching()),
|
||||
fInitStatus(B_NO_INIT),
|
||||
fTeam(-1),
|
||||
fLaunchStatus(B_NO_INIT),
|
||||
@@ -380,7 +382,7 @@ bool
|
||||
Job::CanBeLaunched() const
|
||||
{
|
||||
// Services cannot be launched while they are running
|
||||
return !IsLaunching() && (!IsService() || !IsRunning());
|
||||
return IsEnabled() && !IsLaunching() && (!IsService() || !IsRunning());
|
||||
}
|
||||
|
||||
|
||||
@@ -409,6 +411,30 @@ Job::HandleGetLaunchData(BMessage* message)
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Job::GetMessenger(BMessenger& messenger)
|
||||
{
|
||||
PortMap::const_iterator iterator = fPortMap.begin();
|
||||
for (; iterator != fPortMap.end(); iterator++) {
|
||||
if (iterator->second.HasString("name"))
|
||||
continue;
|
||||
|
||||
port_id port = (port_id)iterator->second.GetInt32("port", -1);
|
||||
if (port >= 0) {
|
||||
BMessenger::Private(messenger).SetTo(fTeam, port,
|
||||
B_PREFERRED_TOKEN);
|
||||
return B_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// There is no default port, try roster via signature
|
||||
BString signature = "application/";
|
||||
signature << Name();
|
||||
|
||||
return messenger.SetTo(signature);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Job::Run()
|
||||
{
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
using namespace BSupportKit;
|
||||
class BMessage;
|
||||
class BMessenger;
|
||||
|
||||
class Finder;
|
||||
class Job;
|
||||
@@ -90,6 +91,7 @@ public:
|
||||
void SetLaunching(bool launching);
|
||||
|
||||
status_t HandleGetLaunchData(BMessage* message);
|
||||
status_t GetMessenger(BMessenger& messenger);
|
||||
|
||||
virtual status_t Run();
|
||||
|
||||
|
||||
@@ -153,6 +153,8 @@ public:
|
||||
private:
|
||||
void _HandleGetLaunchData(BMessage* message);
|
||||
void _HandleLaunchTarget(BMessage* message);
|
||||
void _HandleLaunchJob(BMessage* message);
|
||||
void _HandleStopLaunchJob(BMessage* message);
|
||||
void _HandleLaunchSession(BMessage* message);
|
||||
void _HandleRegisterSessionDaemon(BMessage* message);
|
||||
void _HandleRegisterLaunchEvent(BMessage* message);
|
||||
@@ -179,6 +181,7 @@ private:
|
||||
void _LaunchJobs(Target* target,
|
||||
bool forceNow = false);
|
||||
void _LaunchJob(Job* job, uint32 options = 0);
|
||||
void _StopJob(Job* job, bool force);
|
||||
void _AddTarget(Target* target);
|
||||
void _SetCondition(BaseJob* job,
|
||||
const BMessage& message);
|
||||
@@ -501,11 +504,16 @@ LaunchDaemon::MessageReceived(BMessage* message)
|
||||
case B_LAUNCH_TARGET:
|
||||
_HandleLaunchTarget(message);
|
||||
break;
|
||||
case B_LAUNCH_JOB:
|
||||
_HandleLaunchJob(message);
|
||||
break;
|
||||
case B_STOP_LAUNCH_JOB:
|
||||
_HandleStopLaunchJob(message);
|
||||
break;
|
||||
|
||||
case B_LAUNCH_SESSION:
|
||||
_HandleLaunchSession(message);
|
||||
break;
|
||||
|
||||
case B_REGISTER_SESSION_DAEMON:
|
||||
_HandleRegisterSessionDaemon(message);
|
||||
break;
|
||||
@@ -513,15 +521,12 @@ LaunchDaemon::MessageReceived(BMessage* message)
|
||||
case B_REGISTER_LAUNCH_EVENT:
|
||||
_HandleRegisterLaunchEvent(message);
|
||||
break;
|
||||
|
||||
case B_UNREGISTER_LAUNCH_EVENT:
|
||||
_HandleUnregisterLaunchEvent(message);
|
||||
break;
|
||||
|
||||
case B_NOTIFY_LAUNCH_EVENT:
|
||||
_HandleNotifyLaunchEvent(message);
|
||||
break;
|
||||
|
||||
case B_RESET_STICKY_LAUNCH_EVENT:
|
||||
_HandleResetStickyLaunchEvent(message);
|
||||
break;
|
||||
@@ -787,6 +792,67 @@ LaunchDaemon::_HandleLaunchTarget(BMessage* message)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LaunchDaemon::_HandleLaunchJob(BMessage* message)
|
||||
{
|
||||
uid_t user = _GetUserID(message);
|
||||
if (user < 0)
|
||||
return;
|
||||
|
||||
const char* name = message->GetString("name");
|
||||
|
||||
Job* job = FindJob(name);
|
||||
if (job == NULL) {
|
||||
Session* session = FindSession(user);
|
||||
if (session != NULL) {
|
||||
// Forward request to user launch_daemon
|
||||
if (session->Daemon().SendMessage(message) == B_OK)
|
||||
return;
|
||||
}
|
||||
|
||||
BMessage reply(B_NAME_NOT_FOUND);
|
||||
message->SendReply(&reply);
|
||||
return;
|
||||
}
|
||||
|
||||
job->SetEnabled(true);
|
||||
_LaunchJob(job, FORCE_NOW);
|
||||
|
||||
BMessage reply((uint32)B_OK);
|
||||
message->SendReply(&reply);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LaunchDaemon::_HandleStopLaunchJob(BMessage* message)
|
||||
{
|
||||
uid_t user = _GetUserID(message);
|
||||
if (user < 0)
|
||||
return;
|
||||
|
||||
const char* name = message->GetString("name");
|
||||
|
||||
Job* job = FindJob(name);
|
||||
if (job == NULL) {
|
||||
Session* session = FindSession(user);
|
||||
if (session != NULL) {
|
||||
// Forward request to user launch_daemon
|
||||
if (session->Daemon().SendMessage(message) == B_OK)
|
||||
return;
|
||||
}
|
||||
|
||||
BMessage reply(B_NAME_NOT_FOUND);
|
||||
message->SendReply(&reply);
|
||||
return;
|
||||
}
|
||||
|
||||
_StopJob(job, message->GetBool("force"));
|
||||
|
||||
BMessage reply((uint32)B_OK);
|
||||
message->SendReply(&reply);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LaunchDaemon::_HandleLaunchSession(BMessage* message)
|
||||
{
|
||||
@@ -1315,6 +1381,33 @@ LaunchDaemon::_LaunchJob(Job* job, uint32 options)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LaunchDaemon::_StopJob(Job* job, bool force)
|
||||
{
|
||||
// TODO: find out which jobs require this job, and don't stop if any,
|
||||
// unless force, and then stop them all.
|
||||
job->SetEnabled(false);
|
||||
|
||||
if (!job->IsRunning())
|
||||
return;
|
||||
|
||||
// Be nice first, and send a simple quit message
|
||||
BMessenger messenger;
|
||||
if (job->GetMessenger(messenger) == B_OK) {
|
||||
BMessage request(B_QUIT_REQUESTED);
|
||||
messenger.SendMessage(&request);
|
||||
|
||||
// TODO: wait a bit before going further
|
||||
return;
|
||||
}
|
||||
// TODO: allow custom shutdown
|
||||
|
||||
send_signal(-job->Team(), SIGINT);
|
||||
// TODO: this would be the next step, again, after a delay
|
||||
//send_signal(job->Team(), SIGKILL);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LaunchDaemon::_AddTarget(Target* target)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user