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;
|
||||
|
||||
BApplication(const char* signature,
|
||||
const char* looperName,
|
||||
const char* looperName, port_id port,
|
||||
bool initGUI, status_t* error);
|
||||
BApplication(uint32 signature);
|
||||
BApplication(const BApplication&);
|
||||
@@ -121,6 +121,7 @@ private:
|
||||
const char* property);
|
||||
void _InitData(const char* signature, bool initGUI,
|
||||
status_t* error);
|
||||
port_id _GetPort(const char* signature);
|
||||
void BeginRectTracking(BRect r, bool trackWhole);
|
||||
void EndRectTracking();
|
||||
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.
|
||||
*
|
||||
* Authors:
|
||||
@@ -135,14 +135,16 @@ private:
|
||||
static status_t _LockComplete(BLooper* loop, int32 old,
|
||||
thread_id this_tid, sem_id sem,
|
||||
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 _AddMessagePriv(BMessage* msg);
|
||||
static status_t _task0_(void* arg);
|
||||
|
||||
void* ReadRawFromPort(int32* code,
|
||||
bigtime_t tout = B_INFINITE_TIMEOUT);
|
||||
BMessage* ReadMessageFromPort(bigtime_t tout = B_INFINITE_TIMEOUT);
|
||||
bigtime_t timeout = B_INFINITE_TIMEOUT);
|
||||
BMessage* ReadMessageFromPort(
|
||||
bigtime_t timeout = B_INFINITE_TIMEOUT);
|
||||
virtual BMessage* ConvertToMessage(void* raw, int32 code);
|
||||
virtual void task_looper();
|
||||
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,
|
||||
status_t *error);
|
||||
BServer(const char* signature, const char*
|
||||
looperName, bool initGUI, status_t *error);
|
||||
looperName, port_id port, bool initGUI,
|
||||
status_t *error);
|
||||
|
||||
status_t InitGUIContext();
|
||||
|
||||
|
||||
@@ -40,6 +40,8 @@
|
||||
#include <AutoLocker.h>
|
||||
#include <BitmapPrivate.h>
|
||||
#include <DraggerPrivate.h>
|
||||
#include <LaunchDaemonDefs.h>
|
||||
#include <LaunchRoster.h>
|
||||
#include <LooperList.h>
|
||||
#include <MenuWindow.h>
|
||||
#include <PicturePrivate.h>
|
||||
@@ -259,9 +261,10 @@ BApplication::BApplication(const char* signature, status_t* _error)
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -356,8 +359,9 @@ BApplication::_InitData(const char* signature, bool initGUI, status_t* _error)
|
||||
fAppName = signature;
|
||||
|
||||
#ifndef RUN_WITHOUT_REGISTRAR
|
||||
bool isRegistrar = signature
|
||||
&& strcasecmp(signature, kRegistrarSignature) == 0;
|
||||
bool registerApp = signature == NULL
|
||||
|| (strcasecmp(signature, kRegistrarSignature) != 0
|
||||
&& strcasecmp(signature, kLaunchDaemonSignature) != 0);
|
||||
// get team and thread
|
||||
team_id team = 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
|
||||
// check whether be_roster is valid
|
||||
if (fInitError == B_OK && !isRegistrar
|
||||
if (fInitError == B_OK && registerApp
|
||||
&& !BRoster::Private().IsMessengerValid(false)) {
|
||||
printf("FATAL: be_roster is not valid. Is the registrar running?\n");
|
||||
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
|
||||
bool preRegistered = false;
|
||||
app_info appInfo;
|
||||
if (fInitError == B_OK && !isRegistrar) {
|
||||
if (fInitError == B_OK && registerApp) {
|
||||
if (BRoster::Private().IsAppRegistered(&ref, team, 0, &preRegistered,
|
||||
&appInfo) != B_OK) {
|
||||
preRegistered = false;
|
||||
@@ -429,8 +433,7 @@ BApplication::_InitData(const char* signature, bool initGUI, status_t* _error)
|
||||
} else if (fInitError == B_OK) {
|
||||
// not pre-registered -- try to register the application
|
||||
team_id otherTeam = -1;
|
||||
// the registrar must not register
|
||||
if (!isRegistrar) {
|
||||
if (registerApp) {
|
||||
fInitError = BRoster::Private().AddApplication(signature, &ref,
|
||||
appFlags, team, thread, fMsgPort, true, NULL, &otherTeam);
|
||||
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*
|
||||
BApplication::Instantiate(BMessage* data)
|
||||
{
|
||||
|
||||
@@ -41,6 +41,7 @@ for architectureObject in [ MultiArchSubDirSetup ] {
|
||||
Handler.cpp
|
||||
InitTerminateLibBe.cpp
|
||||
Invoker.cpp
|
||||
LaunchRoster.cpp
|
||||
LinkReceiver.cpp
|
||||
LinkSender.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, axeld@pinc-software.de
|
||||
*/
|
||||
|
||||
|
||||
#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)
|
||||
{
|
||||
_InitData(name, priority, portCapacity);
|
||||
_InitData(name, priority, -1, portCapacity);
|
||||
}
|
||||
|
||||
|
||||
@@ -183,7 +183,7 @@ BLooper::BLooper(BMessage* data)
|
||||
if (data->FindInt32("_prio", &priority) != B_OK)
|
||||
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)
|
||||
{
|
||||
// This must be a legacy constructor
|
||||
fMsgPort = port;
|
||||
_InitData(name, priority, B_LOOPER_PORT_DEFAULT_CAPACITY);
|
||||
_InitData(name, priority, port, B_LOOPER_PORT_DEFAULT_CAPACITY);
|
||||
}
|
||||
|
||||
|
||||
@@ -935,7 +933,8 @@ BLooper::_LockComplete(BLooper* looper, int32 oldCount, thread_id thread,
|
||||
|
||||
|
||||
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;
|
||||
fCachedStack = 0;
|
||||
@@ -961,7 +960,10 @@ BLooper::_InitData(const char* name, int32 priority, int32 portCapacity)
|
||||
if (portCapacity <= 0)
|
||||
portCapacity = B_LOOPER_PORT_DEFAULT_CAPACITY;
|
||||
|
||||
fMsgPort = create_port(portCapacity, name);
|
||||
if (port >= 0)
|
||||
fMsgPort = port;
|
||||
else
|
||||
fMsgPort = create_port(portCapacity, name);
|
||||
|
||||
fInitPriority = priority;
|
||||
|
||||
|
||||
@@ -13,17 +13,17 @@
|
||||
|
||||
BServer::BServer(const char* signature, bool initGUI, status_t *error)
|
||||
:
|
||||
BApplication(signature, NULL, initGUI, error),
|
||||
BApplication(signature, NULL, -1, initGUI, error),
|
||||
fGUIContextInitialized(false)
|
||||
{
|
||||
fGUIContextInitialized = initGUI && (error == NULL || *error == B_OK);
|
||||
}
|
||||
|
||||
|
||||
BServer::BServer(const char* signature, const char* looperName, bool initGUI,
|
||||
status_t *error)
|
||||
BServer::BServer(const char* signature, const char* looperName, port_id port,
|
||||
bool initGUI, status_t *error)
|
||||
:
|
||||
BApplication(signature, looperName, initGUI, error),
|
||||
BApplication(signature, looperName, port, initGUI, error),
|
||||
fGUIContextInitialized(false)
|
||||
{
|
||||
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 input ;
|
||||
SubInclude HAIKU_TOP src servers keystore ;
|
||||
SubInclude HAIKU_TOP src servers launch ;
|
||||
SubInclude HAIKU_TOP src servers mail ;
|
||||
SubInclude HAIKU_TOP src servers media ;
|
||||
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)
|
||||
:
|
||||
BServer(kRegistrarSignature, BPrivate::get_roster_port_name(), false,
|
||||
_error),
|
||||
BServer(kRegistrarSignature, BPrivate::get_roster_port_name(), -1,
|
||||
false, _error),
|
||||
fRoster(NULL),
|
||||
fClipboardHandler(NULL),
|
||||
fMIMEManager(NULL),
|
||||
|
||||
Reference in New Issue
Block a user