diff --git a/headers/private/app/LaunchDaemonDefs.h b/headers/private/app/LaunchDaemonDefs.h index ba791aa7ab0..e3e1a5e515c 100644 --- a/headers/private/app/LaunchDaemonDefs.h +++ b/headers/private/app/LaunchDaemonDefs.h @@ -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', diff --git a/headers/private/app/LaunchRoster.h b/headers/private/app/LaunchRoster.h index 785fe0a846c..46332de2466 100644 --- a/headers/private/app/LaunchRoster.h +++ b/headers/private/app/LaunchRoster.h @@ -34,6 +34,9 @@ class BLaunchRoster { 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 @@ class BLaunchRoster { 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); diff --git a/src/kits/app/LaunchRoster.cpp b/src/kits/app/LaunchRoster.cpp index 1290b281900..b990d0ed088 100644 --- a/src/kits/app/LaunchRoster.cpp +++ b/src/kits/app/LaunchRoster.cpp @@ -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); } diff --git a/src/servers/launch/Job.cpp b/src/servers/launch/Job.cpp index 5cdeeab4282..2c5ad6f3faa 100644 --- a/src/servers/launch/Job.cpp +++ b/src/servers/launch/Job.cpp @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -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() { diff --git a/src/servers/launch/Job.h b/src/servers/launch/Job.h index b18dbd10998..3995cf2848c 100644 --- a/src/servers/launch/Job.h +++ b/src/servers/launch/Job.h @@ -20,6 +20,7 @@ using namespace BSupportKit; class BMessage; +class BMessenger; class Finder; class Job; @@ -90,6 +91,7 @@ class Job : public BaseJob { void SetLaunching(bool launching); status_t HandleGetLaunchData(BMessage* message); + status_t GetMessenger(BMessenger& messenger); virtual status_t Run(); diff --git a/src/servers/launch/LaunchDaemon.cpp b/src/servers/launch/LaunchDaemon.cpp index 3ac3c627138..d7e5cc10f84 100644 --- a/src/servers/launch/LaunchDaemon.cpp +++ b/src/servers/launch/LaunchDaemon.cpp @@ -153,6 +153,8 @@ class LaunchDaemon : public BServer, public Finder, public ConditionContext, 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 @@ class LaunchDaemon : public BServer, public Finder, public ConditionContext, 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) {