mirror of
https://github.com/systemd/systemd.git
synced 2024-11-23 18:23:32 +08:00
service: optionally, trie dbus name cycle to service cycle
This commit is contained in:
parent
4f2d528d3b
commit
05e343b704
158
dbus.c
158
dbus.c
@ -316,17 +316,25 @@ static DBusHandlerResult api_bus_message_filter(DBusConnection *connection, DBu
|
||||
bus_done_api(m);
|
||||
|
||||
} else if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) {
|
||||
const char *name, *old, *new;
|
||||
const char *name, *old_owner, *new_owner;
|
||||
|
||||
if (!dbus_message_get_args(message, &error,
|
||||
DBUS_TYPE_STRING, &name,
|
||||
DBUS_TYPE_STRING, &old,
|
||||
DBUS_TYPE_STRING, &new,
|
||||
DBUS_TYPE_STRING, &old_owner,
|
||||
DBUS_TYPE_STRING, &new_owner,
|
||||
DBUS_TYPE_INVALID))
|
||||
log_error("Failed to parse NameOwnerChanged message: %s", error.message);
|
||||
else {
|
||||
if (set_remove(m->subscribed, (char*) name))
|
||||
log_debug("Subscription client vanished: %s (left: %u)", name, set_size(m->subscribed));
|
||||
|
||||
if (old_owner[0] == 0)
|
||||
old_owner = NULL;
|
||||
|
||||
if (new_owner[0] == 0)
|
||||
new_owner = NULL;
|
||||
|
||||
manager_dispatch_bus_name_owner_changed(m, name, old_owner, new_owner);
|
||||
}
|
||||
}
|
||||
|
||||
@ -388,7 +396,7 @@ unsigned bus_dispatch(Manager *m) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pending_cb(DBusPendingCall *pending, void *userdata) {
|
||||
static void request_name_pending_cb(DBusPendingCall *pending, void *userdata) {
|
||||
DBusMessage *reply;
|
||||
DBusError error;
|
||||
|
||||
@ -432,48 +440,49 @@ static void pending_cb(DBusPendingCall *pending, void *userdata) {
|
||||
}
|
||||
|
||||
static int request_name(Manager *m) {
|
||||
DBusMessage *message;
|
||||
const char *name = "org.freedesktop.systemd1";
|
||||
uint32_t flags = 0;
|
||||
DBusPendingCall *pending;
|
||||
DBusMessage *message = NULL;
|
||||
DBusPendingCall *pending = NULL;
|
||||
|
||||
if (!(message = dbus_message_new_method_call(
|
||||
DBUS_SERVICE_DBUS,
|
||||
DBUS_PATH_DBUS,
|
||||
DBUS_INTERFACE_DBUS,
|
||||
"RequestName")))
|
||||
return -ENOMEM;
|
||||
goto oom;
|
||||
|
||||
if (!dbus_message_append_args(
|
||||
message,
|
||||
DBUS_TYPE_STRING, &name,
|
||||
DBUS_TYPE_UINT32, &flags,
|
||||
DBUS_TYPE_INVALID)) {
|
||||
dbus_message_unref(message);
|
||||
return -ENOMEM;
|
||||
}
|
||||
DBUS_TYPE_INVALID))
|
||||
goto oom;
|
||||
|
||||
if (!dbus_connection_send_with_reply(m->api_bus, message, &pending, -1)) {
|
||||
dbus_message_unref(message);
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (!dbus_connection_send_with_reply(m->api_bus, message, &pending, -1))
|
||||
goto oom;
|
||||
|
||||
if (!dbus_pending_call_set_notify(pending, request_name_pending_cb, m, NULL))
|
||||
goto oom;
|
||||
|
||||
dbus_message_unref(message);
|
||||
|
||||
if (!dbus_pending_call_set_notify(pending, pending_cb, NULL, NULL)) {
|
||||
dbus_pending_call_cancel(pending);
|
||||
dbus_pending_call_unref(pending);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
||||
dbus_pending_call_unref(pending);
|
||||
|
||||
/* We simple ask for the name and don't wait for it. Sooner or
|
||||
* later we'll have it. */
|
||||
|
||||
return 0;
|
||||
|
||||
oom:
|
||||
if (pending) {
|
||||
dbus_pending_call_cancel(pending);
|
||||
dbus_pending_call_unref(pending);
|
||||
}
|
||||
|
||||
if (message)
|
||||
dbus_message_unref(message);
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static int bus_setup_loop(Manager *m, DBusConnection *bus) {
|
||||
@ -557,6 +566,10 @@ int bus_init_api(Manager *m) {
|
||||
if (m->api_bus)
|
||||
return 0;
|
||||
|
||||
if (m->name_data_slot < 0)
|
||||
if (!dbus_pending_call_allocate_data_slot(&m->name_data_slot))
|
||||
return -ENOMEM;
|
||||
|
||||
if (m->running_as != MANAGER_SESSION && m->system_bus)
|
||||
m->api_bus = m->system_bus;
|
||||
else {
|
||||
@ -636,6 +649,9 @@ void bus_done_api(Manager *m) {
|
||||
set_free(m->subscribed);
|
||||
m->subscribed = NULL;
|
||||
}
|
||||
|
||||
if (m->name_data_slot >= 0)
|
||||
dbus_pending_call_free_data_slot(&m->name_data_slot);
|
||||
}
|
||||
|
||||
void bus_done_system(Manager *m) {
|
||||
@ -652,6 +668,102 @@ void bus_done_system(Manager *m) {
|
||||
}
|
||||
}
|
||||
|
||||
static void query_pid_pending_cb(DBusPendingCall *pending, void *userdata) {
|
||||
Manager *m = userdata;
|
||||
DBusMessage *reply;
|
||||
DBusError error;
|
||||
const char *name;
|
||||
|
||||
dbus_error_init(&error);
|
||||
|
||||
assert_se(name = dbus_pending_call_get_data(pending, m->name_data_slot));
|
||||
assert_se(reply = dbus_pending_call_steal_reply(pending));
|
||||
|
||||
switch (dbus_message_get_type(reply)) {
|
||||
|
||||
case DBUS_MESSAGE_TYPE_ERROR:
|
||||
|
||||
assert_se(dbus_set_error_from_message(&error, reply));
|
||||
log_warning("GetConnectionUnixProcessID() failed: %s", error.message);
|
||||
break;
|
||||
|
||||
case DBUS_MESSAGE_TYPE_METHOD_RETURN: {
|
||||
uint32_t r;
|
||||
|
||||
if (!dbus_message_get_args(reply,
|
||||
&error,
|
||||
DBUS_TYPE_UINT32, &r,
|
||||
DBUS_TYPE_INVALID)) {
|
||||
log_error("Failed to parse GetConnectionUnixProcessID() reply: %s", error.message);
|
||||
break;
|
||||
}
|
||||
|
||||
manager_dispatch_bus_query_pid_done(m, name, (pid_t) r);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
assert_not_reached("Invalid reply message");
|
||||
}
|
||||
|
||||
dbus_message_unref(reply);
|
||||
dbus_error_free(&error);
|
||||
}
|
||||
|
||||
int bus_query_pid(Manager *m, const char *name) {
|
||||
DBusMessage *message = NULL;
|
||||
DBusPendingCall *pending = NULL;
|
||||
char *n = NULL;
|
||||
|
||||
assert(m);
|
||||
assert(name);
|
||||
|
||||
if (!(message = dbus_message_new_method_call(
|
||||
DBUS_SERVICE_DBUS,
|
||||
DBUS_PATH_DBUS,
|
||||
DBUS_INTERFACE_DBUS,
|
||||
"GetConnectionUnixProcessID")))
|
||||
goto oom;
|
||||
|
||||
if (!(dbus_message_append_args(
|
||||
message,
|
||||
DBUS_TYPE_STRING, &name,
|
||||
DBUS_TYPE_INVALID)))
|
||||
goto oom;
|
||||
|
||||
if (!dbus_connection_send_with_reply(m->api_bus, message, &pending, -1))
|
||||
goto oom;
|
||||
|
||||
if (!(n = strdup(name)))
|
||||
goto oom;
|
||||
|
||||
if (!dbus_pending_call_set_data(pending, m->name_data_slot, n, free))
|
||||
goto oom;
|
||||
|
||||
n = NULL;
|
||||
|
||||
if (!dbus_pending_call_set_notify(pending, query_pid_pending_cb, m, NULL))
|
||||
goto oom;
|
||||
|
||||
dbus_message_unref(message);
|
||||
dbus_pending_call_unref(pending);
|
||||
|
||||
return 0;
|
||||
|
||||
oom:
|
||||
free(n);
|
||||
|
||||
if (pending) {
|
||||
dbus_pending_call_cancel(pending);
|
||||
dbus_pending_call_unref(pending);
|
||||
}
|
||||
|
||||
if (message)
|
||||
dbus_message_unref(message);
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
DBusHandlerResult bus_default_message_handler(Manager *m, DBusMessage *message, const char*introspection, const BusProperty *properties) {
|
||||
DBusError error;
|
||||
DBusMessage *reply = NULL;
|
||||
|
2
dbus.h
2
dbus.h
@ -70,6 +70,8 @@ DBusHandlerResult bus_default_message_handler(Manager *m, DBusMessage *message,
|
||||
|
||||
DBusHandlerResult bus_send_error_reply(Manager *m, DBusMessage *message, DBusError *bus_error, int error);
|
||||
|
||||
int bus_query_pid(Manager *m, const char *name);
|
||||
|
||||
int bus_property_append_string(Manager *m, DBusMessageIter *i, const char *property, void *data);
|
||||
int bus_property_append_strv(Manager *m, DBusMessageIter *i, const char *property, void *data);
|
||||
int bus_property_append_bool(Manager *m, DBusMessageIter *i, const char *property, void *data);
|
||||
|
@ -1182,6 +1182,7 @@ static int load_from_path(Unit *u, const char *path) {
|
||||
{ "SysVStartPriority", config_parse_sysv_priority, &u->service.sysv_start_priority, "Service" },
|
||||
{ "KillMode", config_parse_kill_mode, &u->service.kill_mode, "Service" },
|
||||
{ "NonBlocking", config_parse_bool, &u->service.exec_context.non_blocking, "Service" },
|
||||
{ "BusName", config_parse_string, &u->service.bus_name, "Service" },
|
||||
EXEC_CONTEXT_CONFIG_ITEMS(u->service.exec_context, "Service"),
|
||||
|
||||
{ "ListenStream", config_parse_listen, &u->socket, "Socket" },
|
||||
|
39
manager.c
39
manager.c
@ -320,6 +320,7 @@ int manager_new(ManagerRunningAs running_as, bool confirm_spawn, Manager **_m) {
|
||||
|
||||
m->running_as = running_as;
|
||||
m->confirm_spawn = confirm_spawn;
|
||||
m->name_data_slot = -1;
|
||||
|
||||
m->signal_watch.fd = m->mount_watch.fd = m->udev_watch.fd = m->epoll_fd = -1;
|
||||
m->current_job_id = 1; /* start as id #1, so that we can leave #0 around as "null-like" value */
|
||||
@ -339,6 +340,9 @@ int manager_new(ManagerRunningAs running_as, bool confirm_spawn, Manager **_m) {
|
||||
if (!(m->cgroup_bondings = hashmap_new(string_hash_func, string_compare_func)))
|
||||
goto fail;
|
||||
|
||||
if (!(m->watch_bus = hashmap_new(string_hash_func, string_compare_func)))
|
||||
goto fail;
|
||||
|
||||
if ((m->epoll_fd = epoll_create1(EPOLL_CLOEXEC)) < 0)
|
||||
goto fail;
|
||||
|
||||
@ -408,6 +412,7 @@ void manager_free(Manager *m) {
|
||||
hashmap_free(m->jobs);
|
||||
hashmap_free(m->transaction_jobs);
|
||||
hashmap_free(m->watch_pids);
|
||||
hashmap_free(m->watch_bus);
|
||||
|
||||
if (m->epoll_fd >= 0)
|
||||
close_nointr(m->epoll_fd);
|
||||
@ -1866,6 +1871,40 @@ void manager_write_utmp_runlevel(Manager *m, Unit *u) {
|
||||
}
|
||||
}
|
||||
|
||||
void manager_dispatch_bus_name_owner_changed(
|
||||
Manager *m,
|
||||
const char *name,
|
||||
const char* old_owner,
|
||||
const char *new_owner) {
|
||||
|
||||
Unit *u;
|
||||
|
||||
assert(m);
|
||||
assert(name);
|
||||
|
||||
if (!(u = hashmap_get(m->watch_bus, name)))
|
||||
return;
|
||||
|
||||
UNIT_VTABLE(u)->bus_name_owner_change(u, name, old_owner, new_owner);
|
||||
}
|
||||
|
||||
void manager_dispatch_bus_query_pid_done(
|
||||
Manager *m,
|
||||
const char *name,
|
||||
pid_t pid) {
|
||||
|
||||
Unit *u;
|
||||
|
||||
assert(m);
|
||||
assert(name);
|
||||
assert(pid >= 1);
|
||||
|
||||
if (!(u = hashmap_get(m->watch_bus, name)))
|
||||
return;
|
||||
|
||||
UNIT_VTABLE(u)->bus_query_pid_done(u, name, pid);
|
||||
}
|
||||
|
||||
static const char* const manager_running_as_table[_MANAGER_RUNNING_AS_MAX] = {
|
||||
[MANAGER_INIT] = "init",
|
||||
[MANAGER_SYSTEM] = "system",
|
||||
|
13
manager.h
13
manager.h
@ -178,6 +178,9 @@ struct Manager {
|
||||
DBusConnection *api_bus, *system_bus;
|
||||
Set *subscribed;
|
||||
|
||||
Hashmap *watch_bus; /* D-Bus names => Unit object n:1 */
|
||||
int32_t name_data_slot;
|
||||
|
||||
/* Data specific to the cgroup subsystem */
|
||||
Hashmap *cgroup_bondings; /* path string => CGroupBonding object 1:n */
|
||||
char *cgroup_controller;
|
||||
@ -215,11 +218,13 @@ unsigned manager_dispatch_dbus_queue(Manager *m);
|
||||
|
||||
int manager_loop(Manager *m);
|
||||
|
||||
void manager_write_utmp_reboot(Manager *m);
|
||||
void manager_write_utmp_runlevel(Manager *m, Unit *t);
|
||||
|
||||
void manager_dispatch_bus_name_owner_changed(Manager *m, const char *name, const char* old_owner, const char *new_owner);
|
||||
void manager_dispatch_bus_query_pid_done(Manager *m, const char *name, pid_t pid);
|
||||
|
||||
const char *manager_running_as_to_string(ManagerRunningAs i);
|
||||
ManagerRunningAs manager_running_as_from_string(const char *s);
|
||||
|
||||
void manager_write_utmp_reboot(Manager *m);
|
||||
|
||||
void manager_write_utmp_runlevel(Manager *m, Unit *t);
|
||||
|
||||
#endif
|
||||
|
128
service.c
128
service.c
@ -118,6 +118,12 @@ static void service_done(Unit *u) {
|
||||
service_unwatch_main_pid(s);
|
||||
service_unwatch_control_pid(s);
|
||||
|
||||
if (s->bus_name) {
|
||||
unit_unwatch_bus_name(UNIT(u), s->bus_name);
|
||||
free(s->bus_name);
|
||||
s->bus_name = NULL;
|
||||
}
|
||||
|
||||
service_close_socket_fd(s);
|
||||
|
||||
unit_unwatch_timer(u, &s->timer_watch);
|
||||
@ -712,6 +718,22 @@ static int service_load_sysv(Service *s) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int service_add_bus_name(Service *s) {
|
||||
char *n;
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
assert(s->bus_name);
|
||||
|
||||
if (asprintf(&n, "dbus-%s.service", s->bus_name) < 0)
|
||||
return 0;
|
||||
|
||||
r = unit_merge_by_name(UNIT(s), n);
|
||||
free(n);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void service_init(Unit *u) {
|
||||
Service *s = SERVICE(u);
|
||||
|
||||
@ -741,6 +763,7 @@ static void service_init(Unit *u) {
|
||||
s->failure = false;
|
||||
|
||||
s->socket_fd = -1;
|
||||
s->bus_name_good = false;
|
||||
|
||||
RATELIMIT_INIT(s->ratelimit, 10*USEC_PER_SEC, 5);
|
||||
}
|
||||
@ -756,6 +779,11 @@ static int service_verify(Service *s) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (s->type == SERVICE_DBUS && !s->bus_name) {
|
||||
log_error("%s is of type D-Bus but no D-Bus service name has been specified. Refusing.", UNIT(s)->meta.id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -793,6 +821,14 @@ static int service_load(Unit *u) {
|
||||
|
||||
if ((r = sysv_chkconfig_order(s)) < 0)
|
||||
return r;
|
||||
|
||||
if (s->bus_name) {
|
||||
if ((r = service_add_bus_name(s)) < 0)
|
||||
return r;
|
||||
|
||||
if ((r = unit_watch_bus_name(u, s->bus_name)) < 0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
return service_verify(s);
|
||||
@ -839,6 +875,13 @@ static void service_dump(Unit *u, FILE *f, const char *prefix) {
|
||||
"%sPIDFile: %s\n",
|
||||
prefix, s->pid_file);
|
||||
|
||||
if (s->bus_name)
|
||||
fprintf(f,
|
||||
"%sBusName: %s\n"
|
||||
"%sBus Name Good: %s\n",
|
||||
prefix, s->bus_name,
|
||||
prefix, yes_no(s->bus_name_good));
|
||||
|
||||
exec_context_dump(&s->exec_context, f, prefix);
|
||||
|
||||
for (c = 0; c < _SERVICE_EXEC_COMMAND_MAX; c++) {
|
||||
@ -1373,7 +1416,9 @@ static void service_enter_running(Service *s, bool success) {
|
||||
if (!success)
|
||||
s->failure = true;
|
||||
|
||||
if (main_pid_good(s) != 0 && cgroup_good(s) != 0)
|
||||
if (main_pid_good(s) != 0 &&
|
||||
cgroup_good(s) != 0 &&
|
||||
(s->bus_name_good || s->type != SERVICE_DBUS))
|
||||
service_set_state(s, SERVICE_RUNNING);
|
||||
else if (s->valid_no_process)
|
||||
service_set_state(s, SERVICE_EXITED);
|
||||
@ -1425,7 +1470,7 @@ static void service_enter_start(Service *s) {
|
||||
|
||||
if ((r = service_spawn(s,
|
||||
s->exec_command[SERVICE_EXEC_START],
|
||||
s->type == SERVICE_FORKING,
|
||||
s->type == SERVICE_FORKING || s->type == SERVICE_DBUS,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
@ -1451,15 +1496,18 @@ static void service_enter_start(Service *s) {
|
||||
s->control_command = s->exec_command[SERVICE_EXEC_START];
|
||||
service_set_state(s, SERVICE_START);
|
||||
|
||||
} else if (s->type == SERVICE_FINISH) {
|
||||
} else if (s->type == SERVICE_FINISH ||
|
||||
s->type == SERVICE_DBUS) {
|
||||
|
||||
/* For finishing services we wait until the start
|
||||
* process exited, too, but it is our main process. */
|
||||
|
||||
/* For D-Bus services we know the main pid right away,
|
||||
* but wait for the bus name to appear on the bus. */
|
||||
|
||||
s->main_pid = pid;
|
||||
s->main_pid_known = true;
|
||||
|
||||
s->control_command = s->exec_command[SERVICE_EXEC_START];
|
||||
service_set_state(s, SERVICE_START);
|
||||
} else
|
||||
assert_not_reached("Unknown service type");
|
||||
@ -2046,6 +2094,72 @@ finish:
|
||||
return r;
|
||||
}
|
||||
|
||||
static void service_bus_name_owner_change(
|
||||
Unit *u,
|
||||
const char *name,
|
||||
const char *old_owner,
|
||||
const char *new_owner) {
|
||||
|
||||
Service *s = SERVICE(u);
|
||||
|
||||
assert(s);
|
||||
assert(name);
|
||||
|
||||
assert(streq(s->bus_name, name));
|
||||
assert(old_owner || new_owner);
|
||||
|
||||
if (old_owner && new_owner)
|
||||
log_debug("%s's D-Bus name %s changed owner from %s to %s", u->meta.id, name, old_owner, new_owner);
|
||||
else if (old_owner)
|
||||
log_debug("%s's D-Bus name %s no longer registered by %s", u->meta.id, name, old_owner);
|
||||
else
|
||||
log_debug("%s's D-Bus name %s now registered by %s", u->meta.id, name, new_owner);
|
||||
|
||||
s->bus_name_good = !!new_owner;
|
||||
|
||||
if (s->type == SERVICE_DBUS) {
|
||||
|
||||
/* service_enter_running() will figure out what to
|
||||
* do */
|
||||
if (s->state == SERVICE_RUNNING)
|
||||
service_enter_running(s, true);
|
||||
else if (s->state == SERVICE_START && new_owner)
|
||||
service_enter_start_post(s);
|
||||
|
||||
} else if (new_owner &&
|
||||
s->main_pid <= 0 &&
|
||||
(s->state == SERVICE_START ||
|
||||
s->state == SERVICE_START_POST ||
|
||||
s->state == SERVICE_RUNNING ||
|
||||
s->state == SERVICE_RELOAD)) {
|
||||
|
||||
/* Try to acquire PID from bus service */
|
||||
log_debug("Trying to acquire PID from D-Bus name...");
|
||||
|
||||
bus_query_pid(u->meta.manager, name);
|
||||
}
|
||||
}
|
||||
|
||||
static void service_bus_query_pid_done(
|
||||
Unit *u,
|
||||
const char *name,
|
||||
pid_t pid) {
|
||||
|
||||
Service *s = SERVICE(u);
|
||||
|
||||
assert(s);
|
||||
assert(name);
|
||||
|
||||
log_debug("%s's D-Bus name %s is now owned by process %u", u->meta.id, name, (unsigned) pid);
|
||||
|
||||
if (s->main_pid <= 0 &&
|
||||
(s->state == SERVICE_START ||
|
||||
s->state == SERVICE_START_POST ||
|
||||
s->state == SERVICE_RUNNING ||
|
||||
s->state == SERVICE_RELOAD))
|
||||
s->main_pid = pid;
|
||||
}
|
||||
|
||||
int service_set_socket_fd(Service *s, int fd) {
|
||||
assert(s);
|
||||
assert(fd >= 0);
|
||||
@ -2098,7 +2212,8 @@ DEFINE_STRING_TABLE_LOOKUP(service_restart, ServiceRestart);
|
||||
static const char* const service_type_table[_SERVICE_TYPE_MAX] = {
|
||||
[SERVICE_FORKING] = "forking",
|
||||
[SERVICE_SIMPLE] = "simple",
|
||||
[SERVICE_FINISH] = "finish"
|
||||
[SERVICE_FINISH] = "finish",
|
||||
[SERVICE_DBUS] = "dbus"
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(service_type, ServiceType);
|
||||
@ -2137,5 +2252,8 @@ const UnitVTable service_vtable = {
|
||||
|
||||
.cgroup_notify_empty = service_cgroup_notify_event,
|
||||
|
||||
.bus_name_owner_change = service_bus_name_owner_change,
|
||||
.bus_query_pid_done = service_bus_query_pid_done,
|
||||
|
||||
.enumerate = service_enumerate
|
||||
};
|
||||
|
10
service.h
10
service.h
@ -57,8 +57,9 @@ typedef enum ServiceRestart {
|
||||
|
||||
typedef enum ServiceType {
|
||||
SERVICE_FORKING, /* forks by itself (i.e. traditional daemons) */
|
||||
SERVICE_SIMPLE, /* we fork and go on right-away (i.e. modern socket activated daemons)*/
|
||||
SERVICE_SIMPLE, /* we fork and go on right-away (i.e. modern socket activated daemons) */
|
||||
SERVICE_FINISH, /* we fork and wait until the program finishes (i.e. programs like fsck which run and need to finish before we continue) */
|
||||
SERVICE_DBUS, /* we fork and wait until a specific D-Bus name appears on the bus */
|
||||
_SERVICE_TYPE_MAX,
|
||||
_SERVICE_TYPE_INVALID = -1
|
||||
} ServiceType;
|
||||
@ -103,13 +104,18 @@ struct Service {
|
||||
pid_t main_pid, control_pid;
|
||||
bool main_pid_known:1;
|
||||
|
||||
bool failure:1; /* if we shut down, remember why */
|
||||
/* If we shut down, remember why */
|
||||
bool failure:1;
|
||||
|
||||
bool bus_name_good:1;
|
||||
|
||||
bool sysv_has_lsb:1;
|
||||
char *sysv_path;
|
||||
int sysv_start_priority;
|
||||
char *sysv_runlevels;
|
||||
|
||||
char *bus_name;
|
||||
|
||||
RateLimit ratelimit;
|
||||
|
||||
int socket_fd;
|
||||
|
22
unit.c
22
unit.c
@ -1023,6 +1023,9 @@ int unit_watch_pid(Unit *u, pid_t pid) {
|
||||
assert(u);
|
||||
assert(pid >= 1);
|
||||
|
||||
/* Watch a specific PID. We only support one unit watching
|
||||
* each PID for now. */
|
||||
|
||||
return hashmap_put(u->meta.manager->watch_pids, UINT32_TO_PTR(pid), u);
|
||||
}
|
||||
|
||||
@ -1030,7 +1033,7 @@ void unit_unwatch_pid(Unit *u, pid_t pid) {
|
||||
assert(u);
|
||||
assert(pid >= 1);
|
||||
|
||||
hashmap_remove(u->meta.manager->watch_pids, UINT32_TO_PTR(pid));
|
||||
hashmap_remove_value(u->meta.manager->watch_pids, UINT32_TO_PTR(pid), u);
|
||||
}
|
||||
|
||||
int unit_watch_timer(Unit *u, usec_t delay, Watch *w) {
|
||||
@ -1606,6 +1609,23 @@ fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int unit_watch_bus_name(Unit *u, const char *name) {
|
||||
assert(u);
|
||||
assert(name);
|
||||
|
||||
/* Watch a specific name on the bus. We only support one unit
|
||||
* watching each name for now. */
|
||||
|
||||
return hashmap_put(u->meta.manager->watch_bus, name, u);
|
||||
}
|
||||
|
||||
void unit_unwatch_bus_name(Unit *u, const char *name) {
|
||||
assert(u);
|
||||
assert(name);
|
||||
|
||||
hashmap_remove_value(u->meta.manager->watch_bus, name, u);
|
||||
}
|
||||
|
||||
static const char* const unit_type_table[_UNIT_TYPE_MAX] = {
|
||||
[UNIT_SERVICE] = "service",
|
||||
[UNIT_TIMER] = "timer",
|
||||
|
12
unit.h
12
unit.h
@ -250,8 +250,17 @@ struct UnitVTable {
|
||||
void (*sigchld_event)(Unit *u, pid_t pid, int code, int status);
|
||||
void (*timer_event)(Unit *u, uint64_t n_elapsed, Watch *w);
|
||||
|
||||
/* Called whenever any of the cgroups this unit watches for
|
||||
* ran empty */
|
||||
void (*cgroup_notify_empty)(Unit *u);
|
||||
|
||||
/* Called whenever a name thus Unit registered for comes or
|
||||
* goes away. */
|
||||
void (*bus_name_owner_change)(Unit *u, const char *name, const char *old_owner, const char *new_owner);
|
||||
|
||||
/* Called whenever a bus PID lookup finishes */
|
||||
void (*bus_query_pid_done)(Unit *u, const char *name, pid_t pid);
|
||||
|
||||
/* This is called for each unit type and should be used to
|
||||
* enumerate existing devices and load them. However,
|
||||
* everything that is loaded here should still stay in
|
||||
@ -348,6 +357,9 @@ void unit_unwatch_pid(Unit *u, pid_t pid);
|
||||
int unit_watch_timer(Unit *u, usec_t delay, Watch *w);
|
||||
void unit_unwatch_timer(Unit *u, Watch *w);
|
||||
|
||||
int unit_watch_bus_name(Unit *u, const char *name);
|
||||
void unit_unwatch_bus_name(Unit *u, const char *name);
|
||||
|
||||
bool unit_job_is_applicable(Unit *u, JobType j);
|
||||
|
||||
int set_unit_path(const char *p);
|
||||
|
Loading…
Reference in New Issue
Block a user