The beginnings of a launch_daemon for Haiku.
* This will be heavily inspired by Apple's launchd, as well as systemd -- for now it really doesn't do a whole lot, though. * What works so far: the configuration files are read, parsed, and the jobs created. * The jobs are even initialized, and their message ports created. * BApplication now retrieves a previously created port from the launch_daemon for use with BServer. * Only the registrar actually uses this for now.
This commit is contained in:
@@ -0,0 +1,60 @@
|
|||||||
|
service x-vnd.Haiku-registrar {
|
||||||
|
launch /system/servers/registrar
|
||||||
|
create_port
|
||||||
|
}
|
||||||
|
|
||||||
|
service x-vnd.Haiku-app_server {
|
||||||
|
launch /system/servers/app_server
|
||||||
|
create_port
|
||||||
|
}
|
||||||
|
|
||||||
|
service x-vnd.Haiku-debug_server {
|
||||||
|
launch /system/servers/debug_server
|
||||||
|
}
|
||||||
|
|
||||||
|
service x-vnd.Haiku-package_daemon {
|
||||||
|
launch /system/servers/package_daemon
|
||||||
|
}
|
||||||
|
|
||||||
|
service x-vnd.Haiku-syslog_daemon {
|
||||||
|
launch /system/servers/syslog_daemon
|
||||||
|
}
|
||||||
|
|
||||||
|
service x-vnd.Haiku-mount_server {
|
||||||
|
launch /system/servers/mount_server
|
||||||
|
}
|
||||||
|
|
||||||
|
service x-vnd.Haiku-media_server {
|
||||||
|
launch /system/servers/media_server
|
||||||
|
no_safemode
|
||||||
|
}
|
||||||
|
|
||||||
|
service x-vnd.Haiku-midi_server {
|
||||||
|
launch /system/servers/midi_server
|
||||||
|
no_safemode
|
||||||
|
}
|
||||||
|
|
||||||
|
service x-vnd.Haiku-mail_daemon {
|
||||||
|
launch /system/servers/mail_daemon -E
|
||||||
|
no_safemode
|
||||||
|
}
|
||||||
|
|
||||||
|
service x-vnd.Haiku-cddb_daemon {
|
||||||
|
launch /system/servers/cddb_daemon
|
||||||
|
no_safemode
|
||||||
|
}
|
||||||
|
|
||||||
|
service x-vnd.Haiku-print_server {
|
||||||
|
launch /system/servers/print_server
|
||||||
|
no_safemode
|
||||||
|
}
|
||||||
|
|
||||||
|
service x-vnd.Haiku-notification_server {
|
||||||
|
launch /system/servers/notification_server
|
||||||
|
no_safemode
|
||||||
|
}
|
||||||
|
|
||||||
|
service x-vnd.Haiku-power_daemon {
|
||||||
|
launch /system/servers/power_daemon
|
||||||
|
no_safemode
|
||||||
|
}
|
||||||
@@ -101,7 +101,7 @@ private:
|
|||||||
friend class BServer;
|
friend class BServer;
|
||||||
|
|
||||||
BApplication(const char* signature,
|
BApplication(const char* signature,
|
||||||
const char* looperName,
|
const char* looperName, port_id port,
|
||||||
bool initGUI, status_t* error);
|
bool initGUI, status_t* error);
|
||||||
BApplication(uint32 signature);
|
BApplication(uint32 signature);
|
||||||
BApplication(const BApplication&);
|
BApplication(const BApplication&);
|
||||||
@@ -121,6 +121,7 @@ private:
|
|||||||
const char* property);
|
const char* property);
|
||||||
void _InitData(const char* signature, bool initGUI,
|
void _InitData(const char* signature, bool initGUI,
|
||||||
status_t* error);
|
status_t* error);
|
||||||
|
port_id _GetPort(const char* signature);
|
||||||
void BeginRectTracking(BRect r, bool trackWhole);
|
void BeginRectTracking(BRect r, bool trackWhole);
|
||||||
void EndRectTracking();
|
void EndRectTracking();
|
||||||
status_t _SetupServerAllocator();
|
status_t _SetupServerAllocator();
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2001-2014 Haiku, Inc. All rights reserved.
|
* Copyright 2001-2015 Haiku, Inc. All rights reserved.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
*
|
||||||
* Authors:
|
* Authors:
|
||||||
@@ -135,14 +135,16 @@ private:
|
|||||||
static status_t _LockComplete(BLooper* loop, int32 old,
|
static status_t _LockComplete(BLooper* loop, int32 old,
|
||||||
thread_id this_tid, sem_id sem,
|
thread_id this_tid, sem_id sem,
|
||||||
bigtime_t timeout);
|
bigtime_t timeout);
|
||||||
void _InitData(const char* name, int32 priority, int32 capacity);
|
void _InitData(const char* name, int32 priority,
|
||||||
|
port_id port, int32 capacity);
|
||||||
void AddMessage(BMessage* msg);
|
void AddMessage(BMessage* msg);
|
||||||
void _AddMessagePriv(BMessage* msg);
|
void _AddMessagePriv(BMessage* msg);
|
||||||
static status_t _task0_(void* arg);
|
static status_t _task0_(void* arg);
|
||||||
|
|
||||||
void* ReadRawFromPort(int32* code,
|
void* ReadRawFromPort(int32* code,
|
||||||
bigtime_t tout = B_INFINITE_TIMEOUT);
|
bigtime_t timeout = B_INFINITE_TIMEOUT);
|
||||||
BMessage* ReadMessageFromPort(bigtime_t tout = B_INFINITE_TIMEOUT);
|
BMessage* ReadMessageFromPort(
|
||||||
|
bigtime_t timeout = B_INFINITE_TIMEOUT);
|
||||||
virtual BMessage* ConvertToMessage(void* raw, int32 code);
|
virtual BMessage* ConvertToMessage(void* raw, int32 code);
|
||||||
virtual void task_looper();
|
virtual void task_looper();
|
||||||
void _QuitRequested(BMessage* msg);
|
void _QuitRequested(BMessage* msg);
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015, Haiku, Inc. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Axel Dörfler, [email protected]
|
||||||
|
*/
|
||||||
|
#ifndef LAUNCH_DAEMON_DEFS_H
|
||||||
|
#define LAUNCH_DAEMON_DEFS_H
|
||||||
|
|
||||||
|
|
||||||
|
//! launch_daemon interface
|
||||||
|
|
||||||
|
|
||||||
|
#include <Errors.h>
|
||||||
|
#include <Roster.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace BPrivate {
|
||||||
|
|
||||||
|
#define kLaunchDaemonSignature "application/x-vnd.Haiku-launch_daemon"
|
||||||
|
#define B_LAUNCH_DAEMON_PORT_NAME "system:launch_daemon"
|
||||||
|
|
||||||
|
|
||||||
|
// message constants
|
||||||
|
enum {
|
||||||
|
B_GET_LAUNCH_CONNECTIONS = 'lncc',
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace BPrivate
|
||||||
|
|
||||||
|
|
||||||
|
#endif // LAUNCH_DAEMON_DEFS_H
|
||||||
|
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 Haiku, Inc. All rights reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef _LAUNCH_ROSTER_H
|
||||||
|
#define _LAUNCH_ROSTER_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <Messenger.h>
|
||||||
|
|
||||||
|
|
||||||
|
class BLaunchRoster {
|
||||||
|
public:
|
||||||
|
BLaunchRoster();
|
||||||
|
~BLaunchRoster();
|
||||||
|
|
||||||
|
status_t InitCheck() const;
|
||||||
|
|
||||||
|
status_t GetData(const char* signature, BMessage& data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _InitMessenger();
|
||||||
|
|
||||||
|
private:
|
||||||
|
BMessenger fMessenger;
|
||||||
|
uint32 _reserved[5];
|
||||||
|
};
|
||||||
|
|
||||||
|
// global BLaunchRoster instance
|
||||||
|
extern const BLaunchRoster* be_launch_roster;
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _LAUNCH_ROSTER_H
|
||||||
@@ -17,7 +17,8 @@ public:
|
|||||||
BServer(const char* signature, bool initGUI,
|
BServer(const char* signature, bool initGUI,
|
||||||
status_t *error);
|
status_t *error);
|
||||||
BServer(const char* signature, const char*
|
BServer(const char* signature, const char*
|
||||||
looperName, bool initGUI, status_t *error);
|
looperName, port_id port, bool initGUI,
|
||||||
|
status_t *error);
|
||||||
|
|
||||||
status_t InitGUIContext();
|
status_t InitGUIContext();
|
||||||
|
|
||||||
|
|||||||
@@ -40,6 +40,8 @@
|
|||||||
#include <AutoLocker.h>
|
#include <AutoLocker.h>
|
||||||
#include <BitmapPrivate.h>
|
#include <BitmapPrivate.h>
|
||||||
#include <DraggerPrivate.h>
|
#include <DraggerPrivate.h>
|
||||||
|
#include <LaunchDaemonDefs.h>
|
||||||
|
#include <LaunchRoster.h>
|
||||||
#include <LooperList.h>
|
#include <LooperList.h>
|
||||||
#include <MenuWindow.h>
|
#include <MenuWindow.h>
|
||||||
#include <PicturePrivate.h>
|
#include <PicturePrivate.h>
|
||||||
@@ -259,9 +261,10 @@ BApplication::BApplication(const char* signature, status_t* _error)
|
|||||||
|
|
||||||
|
|
||||||
BApplication::BApplication(const char* signature, const char* looperName,
|
BApplication::BApplication(const char* signature, const char* looperName,
|
||||||
bool initGUI, status_t* _error)
|
port_id port, bool initGUI, status_t* _error)
|
||||||
:
|
:
|
||||||
BLooper(looperName != NULL ? looperName : kDefaultLooperName)
|
BLooper(B_NORMAL_PRIORITY + 1, port < 0 ? _GetPort(signature) : port,
|
||||||
|
looperName != NULL ? looperName : kDefaultLooperName)
|
||||||
{
|
{
|
||||||
_InitData(signature, initGUI, _error);
|
_InitData(signature, initGUI, _error);
|
||||||
}
|
}
|
||||||
@@ -356,8 +359,9 @@ BApplication::_InitData(const char* signature, bool initGUI, status_t* _error)
|
|||||||
fAppName = signature;
|
fAppName = signature;
|
||||||
|
|
||||||
#ifndef RUN_WITHOUT_REGISTRAR
|
#ifndef RUN_WITHOUT_REGISTRAR
|
||||||
bool isRegistrar = signature
|
bool registerApp = signature == NULL
|
||||||
&& strcasecmp(signature, kRegistrarSignature) == 0;
|
|| (strcasecmp(signature, kRegistrarSignature) != 0
|
||||||
|
&& strcasecmp(signature, kLaunchDaemonSignature) != 0);
|
||||||
// get team and thread
|
// get team and thread
|
||||||
team_id team = Team();
|
team_id team = Team();
|
||||||
thread_id thread = BPrivate::main_thread_for(team);
|
thread_id thread = BPrivate::main_thread_for(team);
|
||||||
@@ -396,7 +400,7 @@ BApplication::_InitData(const char* signature, bool initGUI, status_t* _error)
|
|||||||
|
|
||||||
#ifndef RUN_WITHOUT_REGISTRAR
|
#ifndef RUN_WITHOUT_REGISTRAR
|
||||||
// check whether be_roster is valid
|
// check whether be_roster is valid
|
||||||
if (fInitError == B_OK && !isRegistrar
|
if (fInitError == B_OK && registerApp
|
||||||
&& !BRoster::Private().IsMessengerValid(false)) {
|
&& !BRoster::Private().IsMessengerValid(false)) {
|
||||||
printf("FATAL: be_roster is not valid. Is the registrar running?\n");
|
printf("FATAL: be_roster is not valid. Is the registrar running?\n");
|
||||||
fInitError = B_NO_INIT;
|
fInitError = B_NO_INIT;
|
||||||
@@ -405,7 +409,7 @@ BApplication::_InitData(const char* signature, bool initGUI, status_t* _error)
|
|||||||
// check whether or not we are pre-registered
|
// check whether or not we are pre-registered
|
||||||
bool preRegistered = false;
|
bool preRegistered = false;
|
||||||
app_info appInfo;
|
app_info appInfo;
|
||||||
if (fInitError == B_OK && !isRegistrar) {
|
if (fInitError == B_OK && registerApp) {
|
||||||
if (BRoster::Private().IsAppRegistered(&ref, team, 0, &preRegistered,
|
if (BRoster::Private().IsAppRegistered(&ref, team, 0, &preRegistered,
|
||||||
&appInfo) != B_OK) {
|
&appInfo) != B_OK) {
|
||||||
preRegistered = false;
|
preRegistered = false;
|
||||||
@@ -429,8 +433,7 @@ BApplication::_InitData(const char* signature, bool initGUI, status_t* _error)
|
|||||||
} else if (fInitError == B_OK) {
|
} else if (fInitError == B_OK) {
|
||||||
// not pre-registered -- try to register the application
|
// not pre-registered -- try to register the application
|
||||||
team_id otherTeam = -1;
|
team_id otherTeam = -1;
|
||||||
// the registrar must not register
|
if (registerApp) {
|
||||||
if (!isRegistrar) {
|
|
||||||
fInitError = BRoster::Private().AddApplication(signature, &ref,
|
fInitError = BRoster::Private().AddApplication(signature, &ref,
|
||||||
appFlags, team, thread, fMsgPort, true, NULL, &otherTeam);
|
appFlags, team, thread, fMsgPort, true, NULL, &otherTeam);
|
||||||
if (fInitError != B_OK) {
|
if (fInitError != B_OK) {
|
||||||
@@ -525,6 +528,22 @@ DBG(OUT("BApplication::InitData() done\n"));
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
port_id
|
||||||
|
BApplication::_GetPort(const char* signature)
|
||||||
|
{
|
||||||
|
BLaunchRoster launchRoster;
|
||||||
|
BMessage data;
|
||||||
|
status_t status = launchRoster.GetData(signature, data);
|
||||||
|
if (status == B_OK) {
|
||||||
|
port_id port = data.GetInt32("port", B_NAME_NOT_FOUND);
|
||||||
|
if (port >= 0)
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
BArchivable*
|
BArchivable*
|
||||||
BApplication::Instantiate(BMessage* data)
|
BApplication::Instantiate(BMessage* data)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ for architectureObject in [ MultiArchSubDirSetup ] {
|
|||||||
Handler.cpp
|
Handler.cpp
|
||||||
InitTerminateLibBe.cpp
|
InitTerminateLibBe.cpp
|
||||||
Invoker.cpp
|
Invoker.cpp
|
||||||
|
LaunchRoster.cpp
|
||||||
LinkReceiver.cpp
|
LinkReceiver.cpp
|
||||||
LinkSender.cpp
|
LinkSender.cpp
|
||||||
Looper.cpp
|
Looper.cpp
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 Haiku, Inc. All rights reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Axel Dörfler, [email protected]
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <LaunchRoster.h>
|
||||||
|
|
||||||
|
#include <LaunchDaemonDefs.h>
|
||||||
|
#include <MessengerPrivate.h>
|
||||||
|
|
||||||
|
|
||||||
|
using namespace BPrivate;
|
||||||
|
|
||||||
|
|
||||||
|
const BLaunchRoster* be_launch_roster;
|
||||||
|
|
||||||
|
|
||||||
|
BLaunchRoster::BLaunchRoster()
|
||||||
|
{
|
||||||
|
_InitMessenger();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BLaunchRoster::~BLaunchRoster()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
BLaunchRoster::InitCheck() const
|
||||||
|
{
|
||||||
|
return fMessenger.Team() >= 0 ? B_OK : B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
BLaunchRoster::GetData(const char* signature, BMessage& data)
|
||||||
|
{
|
||||||
|
if (signature == NULL || signature[0] == '\0')
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
BMessage request(B_GET_LAUNCH_CONNECTIONS);
|
||||||
|
status_t status = request.AddString("name", signature);
|
||||||
|
if (status != B_OK)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
// send the request
|
||||||
|
status = fMessenger.SendMessage(&request, &data);
|
||||||
|
|
||||||
|
// evaluate the reply
|
||||||
|
if (status == B_OK)
|
||||||
|
status = data.GetInt32("error", B_OK);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BLaunchRoster::_InitMessenger()
|
||||||
|
{
|
||||||
|
// find the launch_daemon port
|
||||||
|
port_id daemonPort = find_port(B_LAUNCH_DAEMON_PORT_NAME);
|
||||||
|
port_info info;
|
||||||
|
if (daemonPort >= 0 && get_port_info(daemonPort, &info) == B_OK) {
|
||||||
|
BMessenger::Private(fMessenger).SetTo(info.team, daemonPort,
|
||||||
|
B_PREFERRED_TOKEN);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -110,7 +110,7 @@ BLooper::BLooper(const char* name, int32 priority, int32 portCapacity)
|
|||||||
:
|
:
|
||||||
BHandler(name)
|
BHandler(name)
|
||||||
{
|
{
|
||||||
_InitData(name, priority, portCapacity);
|
_InitData(name, priority, -1, portCapacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -183,7 +183,7 @@ BLooper::BLooper(BMessage* data)
|
|||||||
if (data->FindInt32("_prio", &priority) != B_OK)
|
if (data->FindInt32("_prio", &priority) != B_OK)
|
||||||
priority = B_NORMAL_PRIORITY;
|
priority = B_NORMAL_PRIORITY;
|
||||||
|
|
||||||
_InitData(Name(), priority, portCapacity);
|
_InitData(Name(), priority, -1, portCapacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -827,9 +827,7 @@ BLooper::operator=(const BLooper& other)
|
|||||||
|
|
||||||
BLooper::BLooper(int32 priority, port_id port, const char* name)
|
BLooper::BLooper(int32 priority, port_id port, const char* name)
|
||||||
{
|
{
|
||||||
// This must be a legacy constructor
|
_InitData(name, priority, port, B_LOOPER_PORT_DEFAULT_CAPACITY);
|
||||||
fMsgPort = port;
|
|
||||||
_InitData(name, priority, B_LOOPER_PORT_DEFAULT_CAPACITY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -935,7 +933,8 @@ BLooper::_LockComplete(BLooper* looper, int32 oldCount, thread_id thread,
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
BLooper::_InitData(const char* name, int32 priority, int32 portCapacity)
|
BLooper::_InitData(const char* name, int32 priority, port_id port,
|
||||||
|
int32 portCapacity)
|
||||||
{
|
{
|
||||||
fOwner = B_ERROR;
|
fOwner = B_ERROR;
|
||||||
fCachedStack = 0;
|
fCachedStack = 0;
|
||||||
@@ -961,7 +960,10 @@ BLooper::_InitData(const char* name, int32 priority, int32 portCapacity)
|
|||||||
if (portCapacity <= 0)
|
if (portCapacity <= 0)
|
||||||
portCapacity = B_LOOPER_PORT_DEFAULT_CAPACITY;
|
portCapacity = B_LOOPER_PORT_DEFAULT_CAPACITY;
|
||||||
|
|
||||||
fMsgPort = create_port(portCapacity, name);
|
if (port >= 0)
|
||||||
|
fMsgPort = port;
|
||||||
|
else
|
||||||
|
fMsgPort = create_port(portCapacity, name);
|
||||||
|
|
||||||
fInitPriority = priority;
|
fInitPriority = priority;
|
||||||
|
|
||||||
|
|||||||
@@ -13,17 +13,17 @@
|
|||||||
|
|
||||||
BServer::BServer(const char* signature, bool initGUI, status_t *error)
|
BServer::BServer(const char* signature, bool initGUI, status_t *error)
|
||||||
:
|
:
|
||||||
BApplication(signature, NULL, initGUI, error),
|
BApplication(signature, NULL, -1, initGUI, error),
|
||||||
fGUIContextInitialized(false)
|
fGUIContextInitialized(false)
|
||||||
{
|
{
|
||||||
fGUIContextInitialized = initGUI && (error == NULL || *error == B_OK);
|
fGUIContextInitialized = initGUI && (error == NULL || *error == B_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
BServer::BServer(const char* signature, const char* looperName, bool initGUI,
|
BServer::BServer(const char* signature, const char* looperName, port_id port,
|
||||||
status_t *error)
|
bool initGUI, status_t *error)
|
||||||
:
|
:
|
||||||
BApplication(signature, looperName, initGUI, error),
|
BApplication(signature, looperName, port, initGUI, error),
|
||||||
fGUIContextInitialized(false)
|
fGUIContextInitialized(false)
|
||||||
{
|
{
|
||||||
fGUIContextInitialized = initGUI && (error == NULL || *error == B_OK);
|
fGUIContextInitialized = initGUI && (error == NULL || *error == B_OK);
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ SubInclude HAIKU_TOP src servers debug ;
|
|||||||
SubInclude HAIKU_TOP src servers index ;
|
SubInclude HAIKU_TOP src servers index ;
|
||||||
SubInclude HAIKU_TOP src servers input ;
|
SubInclude HAIKU_TOP src servers input ;
|
||||||
SubInclude HAIKU_TOP src servers keystore ;
|
SubInclude HAIKU_TOP src servers keystore ;
|
||||||
|
SubInclude HAIKU_TOP src servers launch ;
|
||||||
SubInclude HAIKU_TOP src servers mail ;
|
SubInclude HAIKU_TOP src servers mail ;
|
||||||
SubInclude HAIKU_TOP src servers media ;
|
SubInclude HAIKU_TOP src servers media ;
|
||||||
SubInclude HAIKU_TOP src servers media_addon ;
|
SubInclude HAIKU_TOP src servers media_addon ;
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
SubDir HAIKU_TOP src servers launch ;
|
||||||
|
|
||||||
|
UsePrivateHeaders app shared ;
|
||||||
|
UsePrivateSystemHeaders ;
|
||||||
|
|
||||||
|
Server launch_daemon
|
||||||
|
:
|
||||||
|
LaunchDaemon.cpp
|
||||||
|
:
|
||||||
|
be libshared.a [ TargetLibstdc++ ]
|
||||||
|
:
|
||||||
|
LaunchDaemon.rdef
|
||||||
|
;
|
||||||
@@ -0,0 +1,534 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015, Axel Dörfler, axeld@pinc-software.de.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <Directory.h>
|
||||||
|
#include <driver_settings.h>
|
||||||
|
#include <Entry.h>
|
||||||
|
#include <ObjectList.h>
|
||||||
|
#include <Path.h>
|
||||||
|
#include <PathFinder.h>
|
||||||
|
#include <Server.h>
|
||||||
|
|
||||||
|
#include <DriverSettingsMessageAdapter.h>
|
||||||
|
#include <LaunchDaemonDefs.h>
|
||||||
|
#include <syscalls.h>
|
||||||
|
|
||||||
|
|
||||||
|
using namespace BPrivate;
|
||||||
|
|
||||||
|
|
||||||
|
static const char* kLaunchDirectory = "launch";
|
||||||
|
|
||||||
|
|
||||||
|
const static settings_template kJobTemplate[] = {
|
||||||
|
{B_STRING_TYPE, "name", NULL, true},
|
||||||
|
{B_BOOL_TYPE, "disabled", NULL},
|
||||||
|
{B_STRING_TYPE, "launch", NULL},
|
||||||
|
{B_BOOL_TYPE, "create_port", NULL},
|
||||||
|
{B_BOOL_TYPE, "no_safemode", NULL},
|
||||||
|
{0, NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
const static settings_template kSettingsTemplate[] = {
|
||||||
|
{B_MESSAGE_TYPE, "job", kJobTemplate},
|
||||||
|
{B_MESSAGE_TYPE, "service", kJobTemplate},
|
||||||
|
{0, NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Job {
|
||||||
|
public:
|
||||||
|
Job(const char* name);
|
||||||
|
virtual ~Job();
|
||||||
|
|
||||||
|
const char* Name() const;
|
||||||
|
|
||||||
|
bool IsEnabled() const;
|
||||||
|
void SetEnabled(bool enable);
|
||||||
|
|
||||||
|
bool IsService() const;
|
||||||
|
void SetService(bool service);
|
||||||
|
|
||||||
|
bool CreatePort() const;
|
||||||
|
void SetCreatePort(bool createPort);
|
||||||
|
|
||||||
|
bool LaunchInSafeMode() const;
|
||||||
|
void SetLaunchInSafeMode(bool launch);
|
||||||
|
|
||||||
|
const BStringList& Arguments() const;
|
||||||
|
BStringList& Arguments();
|
||||||
|
void AddArgument(const char* argument);
|
||||||
|
|
||||||
|
status_t Init();
|
||||||
|
status_t InitCheck() const;
|
||||||
|
|
||||||
|
port_id Port() const;
|
||||||
|
|
||||||
|
status_t Launch();
|
||||||
|
bool IsLaunched() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
BString fName;
|
||||||
|
BStringList fArguments;
|
||||||
|
bool fEnabled;
|
||||||
|
bool fService;
|
||||||
|
bool fCreatePort;
|
||||||
|
bool fLaunchInSafeMode;
|
||||||
|
port_id fPort;
|
||||||
|
status_t fInitStatus;
|
||||||
|
team_id fTeam;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
typedef std::map<BString, Job*> JobMap;
|
||||||
|
|
||||||
|
|
||||||
|
class LaunchDaemon : public BServer {
|
||||||
|
public:
|
||||||
|
LaunchDaemon(status_t& error);
|
||||||
|
virtual ~LaunchDaemon();
|
||||||
|
|
||||||
|
virtual void ReadyToRun();
|
||||||
|
virtual void MessageReceived(BMessage* message);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _ReadPaths(const BStringList& paths);
|
||||||
|
void _ReadEntry(const char* context, BEntry& entry);
|
||||||
|
void _ReadDirectory(const char* context,
|
||||||
|
BEntry& directory);
|
||||||
|
status_t _ReadFile(const char* context, BEntry& entry);
|
||||||
|
|
||||||
|
void _AddJob(bool service, BMessage& message);
|
||||||
|
Job* _Job(const char* name);
|
||||||
|
void _InitJobs();
|
||||||
|
void _LaunchJobs();
|
||||||
|
|
||||||
|
void _SetupEnvironment();
|
||||||
|
bool _IsSafeMode() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
JobMap fJobs;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static const char*
|
||||||
|
get_leaf(const char* signature)
|
||||||
|
{
|
||||||
|
const char* separator = strrchr(signature, '/');
|
||||||
|
if (separator != NULL)
|
||||||
|
return separator + 1;
|
||||||
|
|
||||||
|
return signature;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
|
Job::Job(const char* name)
|
||||||
|
:
|
||||||
|
fName(name),
|
||||||
|
fEnabled(true),
|
||||||
|
fService(false),
|
||||||
|
fCreatePort(false),
|
||||||
|
fLaunchInSafeMode(true),
|
||||||
|
fPort(-1),
|
||||||
|
fInitStatus(B_NO_INIT),
|
||||||
|
fTeam(-1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Job::~Job()
|
||||||
|
{
|
||||||
|
if (fPort >= 0)
|
||||||
|
delete_port(fPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char*
|
||||||
|
Job::Name() const
|
||||||
|
{
|
||||||
|
return fName.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::CreatePort() const
|
||||||
|
{
|
||||||
|
return fCreatePort;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Job::SetCreatePort(bool createPort)
|
||||||
|
{
|
||||||
|
fCreatePort = createPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
Job::Init()
|
||||||
|
{
|
||||||
|
fInitStatus = B_OK;
|
||||||
|
|
||||||
|
if (fCreatePort) {
|
||||||
|
// TODO: prefix system ports with "system:"
|
||||||
|
fPort = create_port(B_LOOPER_PORT_DEFAULT_CAPACITY, Name());
|
||||||
|
if (fPort < 0)
|
||||||
|
fInitStatus = fPort;
|
||||||
|
|
||||||
|
printf("PORT %s: %s\n", Name(), strerror(fPort));
|
||||||
|
}
|
||||||
|
|
||||||
|
return fInitStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
Job::InitCheck() const
|
||||||
|
{
|
||||||
|
return fInitStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
port_id
|
||||||
|
Job::Port() const
|
||||||
|
{
|
||||||
|
return fPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
Job::Launch()
|
||||||
|
{
|
||||||
|
if (fArguments.IsEmpty()) {
|
||||||
|
// TODO: launch via signature
|
||||||
|
} else {
|
||||||
|
printf("LAUNCH %s\n", fArguments.StringAt(0).String());
|
||||||
|
}
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Job::IsLaunched() const
|
||||||
|
{
|
||||||
|
return fTeam >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
|
LaunchDaemon::LaunchDaemon(status_t& error)
|
||||||
|
:
|
||||||
|
BServer(kLaunchDaemonSignature, NULL,
|
||||||
|
create_port(B_LOOPER_PORT_DEFAULT_CAPACITY,
|
||||||
|
B_LAUNCH_DAEMON_PORT_NAME), false, &error)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LaunchDaemon::~LaunchDaemon()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
LaunchDaemon::ReadyToRun()
|
||||||
|
{
|
||||||
|
_SetupEnvironment();
|
||||||
|
|
||||||
|
BStringList paths;
|
||||||
|
BPathFinder::FindPaths(B_FIND_PATH_DATA_DIRECTORY, kLaunchDirectory,
|
||||||
|
B_FIND_PATHS_SYSTEM_ONLY, paths);
|
||||||
|
_ReadPaths(paths);
|
||||||
|
|
||||||
|
BPathFinder::FindPaths(B_FIND_PATH_SETTINGS_DIRECTORY, kLaunchDirectory,
|
||||||
|
B_FIND_PATHS_SYSTEM_ONLY, paths);
|
||||||
|
_ReadPaths(paths);
|
||||||
|
|
||||||
|
_InitJobs();
|
||||||
|
_LaunchJobs();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
LaunchDaemon::MessageReceived(BMessage* message)
|
||||||
|
{
|
||||||
|
switch (message->what) {
|
||||||
|
case B_GET_LAUNCH_CONNECTIONS:
|
||||||
|
{
|
||||||
|
BMessage reply;
|
||||||
|
Job* job = _Job(get_leaf(message->GetString("name")));
|
||||||
|
if (job == NULL) {
|
||||||
|
reply.AddInt32("error", B_NAME_NOT_FOUND);
|
||||||
|
} else {
|
||||||
|
if (job->CreatePort())
|
||||||
|
reply.AddInt32("port", job->Port());
|
||||||
|
|
||||||
|
// Launch job now if it isn't running yet
|
||||||
|
if (!job->IsLaunched())
|
||||||
|
job->Launch();
|
||||||
|
}
|
||||||
|
message->SendReply(&reply);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
BServer::MessageReceived(message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
LaunchDaemon::_ReadPaths(const BStringList& paths)
|
||||||
|
{
|
||||||
|
for (int32 i = 0; i < paths.CountStrings(); i++) {
|
||||||
|
printf("----- %s -------\n", paths.StringAt(i).String());
|
||||||
|
BEntry entry(paths.StringAt(i));
|
||||||
|
if (entry.InitCheck() != B_OK || !entry.Exists())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
_ReadDirectory(NULL, entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
LaunchDaemon::_ReadEntry(const char* context, BEntry& entry)
|
||||||
|
{
|
||||||
|
if (entry.IsDirectory())
|
||||||
|
_ReadDirectory(context, entry);
|
||||||
|
else
|
||||||
|
_ReadFile(context, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LaunchDaemon::_ReadDirectory(const char* context, BEntry& directoryEntry)
|
||||||
|
{
|
||||||
|
BDirectory directory(&directoryEntry);
|
||||||
|
printf("DIR %s\n", directoryEntry.Name());
|
||||||
|
|
||||||
|
BEntry entry;
|
||||||
|
while (directory.GetNextEntry(&entry) == B_OK) {
|
||||||
|
_ReadEntry(context, entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
LaunchDaemon::_ReadFile(const char* context, BEntry& entry)
|
||||||
|
{
|
||||||
|
printf("FILE %s\n", entry.Name());
|
||||||
|
DriverSettingsMessageAdapter adapter;
|
||||||
|
|
||||||
|
BPath path;
|
||||||
|
status_t status = path.SetTo(&entry);
|
||||||
|
if (status != B_OK)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
BMessage message;
|
||||||
|
status = adapter.ConvertFromDriverSettings(path.Path(), kSettingsTemplate,
|
||||||
|
message);
|
||||||
|
if (status == B_OK) {
|
||||||
|
message.PrintToStream();
|
||||||
|
BMessage job;
|
||||||
|
for (int32 index = 0; message.FindMessage("service", index,
|
||||||
|
&job) == B_OK; index++) {
|
||||||
|
_AddJob(false, job);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int32 index = 0; message.FindMessage("job", index, &job) == B_OK;
|
||||||
|
index++) {
|
||||||
|
_AddJob(false, job);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
LaunchDaemon::_AddJob(bool service, BMessage& message)
|
||||||
|
{
|
||||||
|
const char* name = message.GetString("name");
|
||||||
|
printf("JOB %s\n", name);
|
||||||
|
if (name == NULL || name[0] == '\0') {
|
||||||
|
// Invalid job description
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Job* job = _Job(name);
|
||||||
|
if (job == NULL)
|
||||||
|
job = new Job(name);
|
||||||
|
|
||||||
|
job->SetEnabled(!message.GetBool("disabled", !job->IsEnabled()));
|
||||||
|
job->SetService(service);
|
||||||
|
job->SetCreatePort(message.GetBool("create_port", job->CreatePort()));
|
||||||
|
job->SetLaunchInSafeMode(
|
||||||
|
!message.GetBool("no_safemode", !job->LaunchInSafeMode()));
|
||||||
|
|
||||||
|
const char* argument;
|
||||||
|
for (int32 index = 0;
|
||||||
|
message.FindString("launch", index, &argument) == B_OK; index++) {
|
||||||
|
job->AddArgument(argument);
|
||||||
|
}
|
||||||
|
|
||||||
|
fJobs.insert(std::pair<BString, Job*>(job->Name(), job));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Job*
|
||||||
|
LaunchDaemon::_Job(const char* name)
|
||||||
|
{
|
||||||
|
if (name == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
JobMap::const_iterator found = fJobs.find(name);
|
||||||
|
if (found != fJobs.end())
|
||||||
|
return found->second;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
LaunchDaemon::_InitJobs()
|
||||||
|
{
|
||||||
|
for (JobMap::iterator iterator = fJobs.begin(); iterator != fJobs.end();
|
||||||
|
iterator++) {
|
||||||
|
Job* job = iterator->second;
|
||||||
|
printf(" enabled? %s - %d\n", job->Name(), job->IsEnabled());
|
||||||
|
if (job->IsEnabled() && (!_IsSafeMode() || job->LaunchInSafeMode()))
|
||||||
|
job->Init();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
LaunchDaemon::_LaunchJobs()
|
||||||
|
{
|
||||||
|
for (JobMap::iterator iterator = fJobs.begin(); iterator != fJobs.end();
|
||||||
|
iterator++) {
|
||||||
|
Job* job = iterator->second;
|
||||||
|
if (job->IsEnabled() && job->InitCheck() == B_OK)
|
||||||
|
job->Launch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
LaunchDaemon::_SetupEnvironment()
|
||||||
|
{
|
||||||
|
// Determine safemode kernel option
|
||||||
|
BString safemode = "SAFEMODE=";
|
||||||
|
safemode << _IsSafeMode() ? "yes" : "no";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
LaunchDaemon::_IsSafeMode() const
|
||||||
|
{
|
||||||
|
char buffer[32];
|
||||||
|
size_t size = sizeof(buffer);
|
||||||
|
status_t status = _kern_get_safemode_option(B_SAFEMODE_SAFE_MODE, buffer,
|
||||||
|
&size);
|
||||||
|
if (status == B_OK) {
|
||||||
|
return !strncasecmp(buffer, "true", size)
|
||||||
|
|| !strncasecmp(buffer, "yes", size)
|
||||||
|
|| !strncasecmp(buffer, "on", size)
|
||||||
|
|| !strncasecmp(buffer, "enabled", size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
main()
|
||||||
|
{
|
||||||
|
status_t status;
|
||||||
|
LaunchDaemon* daemon = new LaunchDaemon(status);
|
||||||
|
if (status == B_OK)
|
||||||
|
daemon->Run();
|
||||||
|
|
||||||
|
delete daemon;
|
||||||
|
return status == B_OK ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
resource app_signature "application/x-vnd.haiku-launch_daemon";
|
||||||
|
|
||||||
|
resource app_flags B_EXCLUSIVE_LAUNCH | B_BACKGROUND_APP;
|
||||||
|
|
||||||
|
resource app_version {
|
||||||
|
major = 1,
|
||||||
|
middle = 0,
|
||||||
|
minor = 0,
|
||||||
|
|
||||||
|
variety = B_APPV_ALPHA,
|
||||||
|
internal = 0,
|
||||||
|
|
||||||
|
short_info = "launch_daemon",
|
||||||
|
long_info = "launch_daemon ©2015 Haiku Inc."
|
||||||
|
};
|
||||||
@@ -57,8 +57,8 @@ static const bigtime_t kRosterSanityEventInterval = 1000000LL;
|
|||||||
*/
|
*/
|
||||||
Registrar::Registrar(status_t* _error)
|
Registrar::Registrar(status_t* _error)
|
||||||
:
|
:
|
||||||
BServer(kRegistrarSignature, BPrivate::get_roster_port_name(), false,
|
BServer(kRegistrarSignature, BPrivate::get_roster_port_name(), -1,
|
||||||
_error),
|
false, _error),
|
||||||
fRoster(NULL),
|
fRoster(NULL),
|
||||||
fClipboardHandler(NULL),
|
fClipboardHandler(NULL),
|
||||||
fMIMEManager(NULL),
|
fMIMEManager(NULL),
|
||||||
|
|||||||
Reference in New Issue
Block a user