assert(a);
unmount_autofs(a);
- a->mount = NULL;
+ unit_ref_unset(&a->mount);
free(a->where);
a->where = NULL;
return r;
if (u->meta.load_state == UNIT_LOADED) {
+ Unit *x;
if (!a->where)
if (!(a->where = unit_name_to_path(u->meta.id)))
if ((r = automount_add_mount_links(a)) < 0)
return r;
- if ((r = unit_load_related_unit(u, ".mount", (Unit**) &a->mount)) < 0)
+ r = unit_load_related_unit(u, ".mount", &x);
+ if (r < 0)
return r;
- if ((r = unit_add_dependency(u, UNIT_BEFORE, UNIT(a->mount), true)) < 0)
+ unit_ref_set(&a->mount, x);
+
+ r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, UNIT_DEREF(a->mount), true);
+ if (r < 0)
return r;
if (a->meta.default_dependencies)
DBusError error;
assert(a);
- assert(a->mount);
+ assert(UNIT_DEREF(a->mount));
dbus_error_init(&error);
if (!S_ISDIR(st.st_mode) || st.st_dev != a->dev_id)
log_info("%s's automount point already active?", a->meta.id);
- else if ((r = manager_add_job(a->meta.manager, JOB_START, UNIT(a->mount), JOB_REPLACE, true, &error, NULL)) < 0) {
+ else if ((r = manager_add_job(a->meta.manager, JOB_START, UNIT_DEREF(a->mount), JOB_REPLACE, true, &error, NULL)) < 0) {
log_warning("%s failed to queue mount startup job: %s", a->meta.id, bus_error(&error, r));
goto fail;
}
return -EEXIST;
}
- if (a->mount->meta.load_state != UNIT_LOADED)
+ if (UNIT_DEREF(a->mount)->meta.load_state != UNIT_LOADED)
return -ENOENT;
a->failure = false;
assert(a);
- if (!a->mount)
+ if (!UNIT_DEREF(a->mount))
return false;
- return UNIT_VTABLE(UNIT(a->mount))->check_gc(UNIT(a->mount));
+ return UNIT_VTABLE(UNIT_DEREF(a->mount))->check_gc(UNIT_DEREF(a->mount));
}
static void automount_fd_event(Unit *u, int fd, uint32_t events, Watch *w) {
char *where;
- Mount *mount;
+ UnitRef mount;
int pipe_fd;
mode_t directory_mode;
Watch pipe_watch;
dev_t dev_id;
-
Set *tokens;
bool failure:1;
assert(property);
assert(u);
- t = u->path.unit ? u->path.unit->meta.id : "";
+ t = UNIT_DEREF(u->path.unit) ? UNIT_DEREF(u->path.unit)->meta.id : "";
return dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t) ? 0 : -ENOMEM;
}
" <property name=\"BusName\" type=\"s\" access=\"read\"/>\n" \
" <property name=\"StatusText\" type=\"s\" access=\"read\"/>\n" \
" <property name=\"FsckPassNo\" type=\"i\" access=\"read\"/>\n" \
- " <property name=\"Sockets\" type=\"as\" access=\"read\"/>\n" \
BUS_SERVICE_SYSV_INTERFACE_FRAGMENT \
" </interface>\n"
{ "org.freedesktop.systemd1.Service", "ControlPID", bus_property_append_pid, "u", &u->service.control_pid },
{ "org.freedesktop.systemd1.Service", "BusName", bus_property_append_string, "s", u->service.bus_name },
{ "org.freedesktop.systemd1.Service", "StatusText", bus_property_append_string, "s", u->service.status_text },
- { "org.freedesktop.systemd1.Service", "Sockets", bus_unit_append_dependencies, "as", u->service.configured_sockets },
#ifdef HAVE_SYSV_COMPAT
{ "org.freedesktop.systemd1.Service", "SysVRunLevels", bus_property_append_string, "s", u->service.sysv_runlevels },
{ "org.freedesktop.systemd1.Service", "SysVStartPriority", bus_property_append_int, "i", &u->service.sysv_start_priority },
assert(property);
assert(u);
- t = u->timer.unit ? u->timer.unit->meta.id : "";
+ t = UNIT_DEREF(u->timer.unit) ? UNIT_DEREF(u->timer.unit)->meta.id : "";
return dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t) ? 0 : -ENOMEM;
}
{ "org.freedesktop.systemd1.Unit", "Before", bus_unit_append_dependencies, "as", u->meta.dependencies[UNIT_BEFORE] }, \
{ "org.freedesktop.systemd1.Unit", "After", bus_unit_append_dependencies, "as", u->meta.dependencies[UNIT_AFTER] }, \
{ "org.freedesktop.systemd1.Unit", "OnFailure", bus_unit_append_dependencies, "as", u->meta.dependencies[UNIT_ON_FAILURE] }, \
+ { "org.freedesktop.systemd1.Unit", "Triggers", bus_unit_append_dependencies, "as", u->meta.dependencies[UNIT_TRIGGERS] }, \
+ { "org.freedesktop.systemd1.Unit", "TriggeredBy", bus_unit_append_dependencies, "as", u->meta.dependencies[UNIT_TRIGGERED_BY] }, \
{ "org.freedesktop.systemd1.Unit", "Description", bus_unit_append_description, "s", u }, \
{ "org.freedesktop.systemd1.Unit", "LoadState", bus_unit_append_load_state, "s", &u->meta.load_state }, \
{ "org.freedesktop.systemd1.Unit", "ActiveState", bus_unit_append_active_state, "s", u }, \
char *t, *k;
int r;
- if (!(t = strndup(w, l)))
+ t = strndup(w, l);
+ if (!t)
return -ENOMEM;
k = unit_name_printf(u, t);
return -ENOMEM;
r = unit_add_dependency_by_name(u, d, k, NULL, true);
-
- if (r < 0) {
- log_error("Failed to add dependency on %s, ignoring: %s", k, strerror(-r));
- free(k);
- return 0;
- }
+ if (r < 0)
+ log_error("[%s:%u] Failed to add dependency on %s, ignoring: %s", filename, line, k, strerror(-r));
free(k);
}
Timer *t = data;
int r;
DBusError error;
+ Unit *u;
assert(filename);
assert(lvalue);
return 0;
}
- if ((r = manager_load_unit(t->meta.manager, rvalue, NULL, NULL, &t->unit)) < 0) {
+ r = manager_load_unit(t->meta.manager, rvalue, NULL, NULL, &u);
+ if (r < 0) {
log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
dbus_error_free(&error);
return 0;
}
+ unit_ref_set(&t->unit, u);
+
return 0;
}
Path *t = data;
int r;
DBusError error;
+ Unit *u;
assert(filename);
assert(lvalue);
return 0;
}
- if ((r = manager_load_unit(t->meta.manager, rvalue, NULL, &error, &t->unit)) < 0) {
+ if ((r = manager_load_unit(t->meta.manager, rvalue, NULL, &error, &u)) < 0) {
log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
dbus_error_free(&error);
return 0;
}
+ unit_ref_set(&t->unit, u);
+
return 0;
}
Service *s = data;
int r;
- DBusError error;
char *state, *w;
size_t l;
assert(rvalue);
assert(data);
- dbus_error_init(&error);
-
FOREACH_WORD_QUOTED(w, l, rvalue, state) {
- char *t;
- Unit *sock;
+ char *t, *k;
- if (!(t = strndup(w, l)))
+ t = strndup(w, l);
+ if (!t)
return -ENOMEM;
- if (!endswith(t, ".socket")) {
- log_error("[%s:%u] Unit must be of type socket, ignoring: %s", filename, line, rvalue);
- free(t);
- continue;
- }
-
- r = manager_load_unit(s->meta.manager, t, NULL, &error, &sock);
+ k = unit_name_printf(UNIT(s), t);
free(t);
- if (r < 0) {
- log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
- dbus_error_free(&error);
+ if (!k)
+ return -ENOMEM;
+
+ if (!endswith(k, ".socket")) {
+ log_error("[%s:%u] Unit must be of type socket, ignoring: %s", filename, line, rvalue);
+ free(k);
continue;
}
- if ((r = set_ensure_allocated(&s->configured_sockets, trivial_hash_func, trivial_compare_func)) < 0)
- return r;
+ r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true);
+ if (r < 0)
+ log_error("[%s:%u] Failed to add dependency on %s, ignoring: %s", filename, line, k, strerror(-r));
- if ((r = set_put(s->configured_sockets, sock)) < 0)
+ r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true);
+ if (r < 0)
return r;
+
+ free(k);
}
return 0;
static void mount_done(Unit *u) {
Mount *m = MOUNT(u);
- Meta *other;
assert(m);
free(m->where);
m->where = NULL;
- /* Try to detach us from the automount unit if there is any */
- LIST_FOREACH(units_by_type, other, m->meta.manager->units_by_type[UNIT_AUTOMOUNT]) {
- Automount *a = (Automount*) other;
-
- if (a->mount == m)
- a->mount = NULL;
- }
-
mount_parameters_done(&m->parameters_etc_fstab);
mount_parameters_done(&m->parameters_proc_self_mountinfo);
mount_parameters_done(&m->parameters_fragment);
static int mount_notify_automount(Mount *m, int status) {
Unit *p;
int r;
+ Iterator i;
assert(m);
- if ((r = unit_get_related_unit(UNIT(m), ".automount", &p)) < 0)
- return r == -ENOENT ? 0 : r;
+ SET_FOREACH(p, m->meta.dependencies[UNIT_TRIGGERED_BY], i)
+ if (p->meta.type == UNIT_AUTOMOUNT) {
+ r = automount_send_ready(AUTOMOUNT(p), status);
+ if (r < 0)
+ return r;
+ }
- return automount_send_ready(AUTOMOUNT(p), status);
+ return 0;
}
static void mount_set_state(Mount *m, MountState state) {
[PATH_FAILED] = UNIT_FAILED
};
-int pathspec_watch(PathSpec *s, Unit *u) {
+int path_spec_watch(PathSpec *s, Unit *u) {
+
static const int flags_table[_PATH_TYPE_MAX] = {
[PATH_EXISTS] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB,
[PATH_EXISTS_GLOB] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB,
assert(u);
assert(s);
- pathspec_unwatch(s, u);
+ path_spec_unwatch(s, u);
if (!(k = strdup(s->path)))
return -ENOMEM;
fail:
free(k);
- pathspec_unwatch(s, u);
+ path_spec_unwatch(s, u);
return r;
}
-void pathspec_unwatch(PathSpec *s, Unit *u) {
+void path_spec_unwatch(PathSpec *s, Unit *u) {
if (s->inotify_fd < 0)
return;
s->inotify_fd = -1;
}
-int pathspec_fd_event(PathSpec *s, uint32_t events) {
+int path_spec_fd_event(PathSpec *s, uint32_t events) {
uint8_t *buf = NULL;
struct inotify_event *e;
ssize_t k;
return r;
}
-static bool pathspec_check_good(PathSpec *s, bool initial) {
+static bool path_spec_check_good(PathSpec *s, bool initial) {
bool good = false;
switch (s->type) {
return good;
}
-static bool pathspec_startswith(PathSpec *s, const char *what) {
+static bool path_spec_startswith(PathSpec *s, const char *what) {
return path_startswith(s->path, what);
}
-static void pathspec_mkdir(PathSpec *s, mode_t mode) {
+static void path_spec_mkdir(PathSpec *s, mode_t mode) {
int r;
if (s->type == PATH_EXISTS || s->type == PATH_EXISTS_GLOB)
log_warning("mkdir(%s) failed: %s", s->path, strerror(-r));
}
-static void pathspec_dump(PathSpec *s, FILE *f, const char *prefix) {
+static void path_spec_dump(PathSpec *s, FILE *f, const char *prefix) {
fprintf(f,
"%s%s: %s\n",
prefix,
s->path);
}
-void pathspec_done(PathSpec *s) {
+void path_spec_done(PathSpec *s) {
+ assert(s);
assert(s->inotify_fd == -1);
+
free(s->path);
}
assert(p);
+ unit_ref_unset(&p->unit);
+
while ((s = p->specs)) {
- pathspec_unwatch(s, u);
+ path_spec_unwatch(s, u);
LIST_REMOVE(PathSpec, spec, p->specs, s);
- pathspec_done(s);
+ path_spec_done(s);
free(s);
}
}
LIST_FOREACH(spec, s, p->specs) {
- if (!pathspec_startswith(s, m->where))
+ if (!path_spec_startswith(s, m->where))
continue;
if ((r = unit_add_two_dependencies(UNIT(p), UNIT_AFTER, UNIT_REQUIRES, UNIT(m), true)) < 0)
if (u->meta.load_state == UNIT_LOADED) {
- if (!p->unit)
- if ((r = unit_load_related_unit(u, ".service", &p->unit)))
+ if (!UNIT_DEREF(p->unit)) {
+ Unit *x;
+
+ r = unit_load_related_unit(u, ".service", &x);
+ if (r < 0)
return r;
- if ((r = unit_add_dependency(u, UNIT_BEFORE, p->unit, true)) < 0)
+ unit_ref_set(&p->unit, x);
+ }
+
+ r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, UNIT_DEREF(p->unit), true);
+ if (r < 0)
return r;
if ((r = path_add_mount_links(p)) < 0)
"%sMakeDirectory: %s\n"
"%sDirectoryMode: %04o\n",
prefix, path_state_to_string(p->state),
- prefix, p->unit->meta.id,
+ prefix, UNIT_DEREF(p->unit)->meta.id,
prefix, yes_no(p->make_directory),
prefix, p->directory_mode);
LIST_FOREACH(spec, s, p->specs)
- pathspec_dump(s, f, prefix);
+ path_spec_dump(s, f, prefix);
}
static void path_unwatch(Path *p) {
assert(p);
LIST_FOREACH(spec, s, p->specs)
- pathspec_unwatch(s, UNIT(p));
+ path_spec_unwatch(s, UNIT(p));
}
static int path_watch(Path *p) {
assert(p);
LIST_FOREACH(spec, s, p->specs)
- if ((r = pathspec_watch(s, UNIT(p))) < 0)
+ if ((r = path_spec_watch(s, UNIT(p))) < 0)
return r;
return 0;
if (p->meta.job && p->meta.job->type == JOB_STOP)
return;
- if ((r = manager_add_job(p->meta.manager, JOB_START, p->unit, JOB_REPLACE, true, &error, NULL)) < 0)
+ if ((r = manager_add_job(p->meta.manager, JOB_START, UNIT_DEREF(p->unit), JOB_REPLACE, true, &error, NULL)) < 0)
goto fail;
p->inotify_triggered = false;
assert(p);
LIST_FOREACH(spec, s, p->specs) {
- good = pathspec_check_good(s, initial);
+ good = path_spec_check_good(s, initial);
if (good)
break;
return;
LIST_FOREACH(spec, s, p->specs)
- pathspec_mkdir(s, p->directory_mode);
+ path_spec_mkdir(s, p->directory_mode);
}
static int path_start(Unit *u) {
assert(p);
assert(p->state == PATH_DEAD || p->state == PATH_FAILED);
- if (p->unit->meta.load_state != UNIT_LOADED)
+ if (UNIT_DEREF(p->unit)->meta.load_state != UNIT_LOADED)
return -ENOENT;
path_mkdir(p);
/* log_debug("inotify wakeup on %s.", u->meta.id); */
LIST_FOREACH(spec, s, p->specs)
- if (pathspec_owns_inotify_fd(s, fd))
+ if (path_spec_owns_inotify_fd(s, fd))
break;
if (!s) {
goto fail;
}
- changed = pathspec_fd_event(s, events);
+ changed = path_spec_fd_event(s, events);
if (changed < 0)
goto fail;
}
void path_unit_notify(Unit *u, UnitActiveState new_state) {
- char *n;
- int r;
Iterator i;
+ Unit *k;
if (u->meta.type == UNIT_PATH)
return;
- SET_FOREACH(n, u->meta.names, i) {
- char *k;
- Unit *t;
+ SET_FOREACH(k, u->meta.dependencies[UNIT_TRIGGERED_BY], i) {
Path *p;
- if (!(k = unit_name_change_suffix(n, ".path"))) {
- r = -ENOMEM;
- goto fail;
- }
-
- t = manager_get_unit(u->meta.manager, k);
- free(k);
-
- if (!t)
+ if (k->meta.type != UNIT_PATH)
continue;
- if (t->meta.load_state != UNIT_LOADED)
+ if (k->meta.load_state != UNIT_LOADED)
continue;
- p = PATH(t);
-
- if (p->unit != u)
- continue;
+ p = PATH(k);
if (p->state == PATH_RUNNING && new_state == UNIT_INACTIVE) {
log_debug("%s got notified about unit deactivation.", p->meta.id);
path_enter_waiting(p, false, p->inotify_triggered);
}
}
-
- return;
-
-fail:
- log_error("Failed find path unit: %s", strerror(-r));
}
static void path_reset_failed(Unit *u) {
int primary_wd;
bool previous_exists;
-
} PathSpec;
-int pathspec_watch(PathSpec *s, Unit *u);
-void pathspec_unwatch(PathSpec *s, Unit *u);
-int pathspec_fd_event(PathSpec *s, uint32_t events);
-void pathspec_done(PathSpec *s);
-static inline bool pathspec_owns_inotify_fd(PathSpec *s, int fd) {
+int path_spec_watch(PathSpec *s, Unit *u);
+void path_spec_unwatch(PathSpec *s, Unit *u);
+int path_spec_fd_event(PathSpec *s, uint32_t events);
+void path_spec_done(PathSpec *s);
+
+static inline bool path_spec_owns_inotify_fd(PathSpec *s, int fd) {
return s->inotify_fd == fd;
}
LIST_HEAD(PathSpec, specs);
- Unit *unit;
+ UnitRef unit;
PathState state, deserialized_state;
static void service_connection_unref(Service *s) {
assert(s);
- if (!s->accept_socket)
+ if (!UNIT_DEREF(s->accept_socket))
return;
- socket_connection_unref(s->accept_socket);
- s->accept_socket = NULL;
+ socket_connection_unref(SOCKET(UNIT_DEREF(s->accept_socket)));
+ unit_ref_unset(&s->accept_socket);
}
static void service_done(Unit *u) {
service_close_socket_fd(s);
service_connection_unref(s);
- set_free(s->configured_sockets);
+ unit_ref_unset(&s->accept_socket);
unit_unwatch_timer(u, &s->timer_watch);
}
return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
}
-static int service_add_socket_dependencies(Service *s) {
- Iterator i;
- Unit *u;
- int r;
-
- /* Make sure we pull in all explicitly configured sockets */
-
- SET_FOREACH(u, s->configured_sockets, i) {
- r = unit_add_two_dependencies(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, u, true);
- if (r < 0)
- return r;
- }
-
- return 0;
-}
-
static void service_fix_output(Service *s) {
assert(s);
if ((r = unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_REQUIRES, SPECIAL_DBUS_SOCKET, NULL, true)) < 0)
return r;
- if (!set_isempty(s->configured_sockets)) {
- r = service_add_socket_dependencies(s);
- if (r < 0)
- return r;
- }
-
if (s->meta.default_dependencies)
if ((r = service_add_default_dependencies(s)) < 0)
return r;
return 0;
}
-static int service_get_sockets(Service *s, Set **_set) {
- Set *set;
+static void service_notify_sockets_dead(Service *s) {
Iterator i;
- char *t;
- int r;
-
- assert(s);
- assert(_set);
-
- if (s->socket_fd >= 0)
- return 0;
-
- if (!set_isempty(s->configured_sockets))
- return 0;
-
- /* Collects all Socket objects that belong to this
- * service. Note that a service might have multiple sockets
- * via multiple names. */
-
- if (!(set = set_new(NULL, NULL)))
- return -ENOMEM;
-
- SET_FOREACH(t, s->meta.names, i) {
- char *k;
- Unit *p;
-
- /* Look for all socket objects that go by any of our
- * units and collect their fds */
-
- if (!(k = unit_name_change_suffix(t, ".socket"))) {
- r = -ENOMEM;
- goto fail;
- }
-
- p = manager_get_unit(s->meta.manager, k);
- free(k);
-
- if (!p)
- continue;
-
- if ((r = set_put(set, p)) < 0)
- goto fail;
- }
-
- *_set = set;
- return 0;
-
-fail:
- set_free(set);
- return r;
-}
-
-static int service_notify_sockets_dead(Service *s) {
- Iterator i;
- Set *set, *free_set = NULL;
- Socket *sock;
- int r;
+ Unit *u;
assert(s);
/* Notifies all our sockets when we die */
if (s->socket_fd >= 0)
- return 0;
-
- if (!set_isempty(s->configured_sockets))
- set = s->configured_sockets;
- else {
- if ((r = service_get_sockets(s, &free_set)) < 0)
- return r;
-
- set = free_set;
- }
-
- SET_FOREACH(sock, set, i)
- socket_notify_service_dead(sock);
+ return;
- set_free(free_set);
+ SET_FOREACH(u, s->meta.dependencies[UNIT_TRIGGERED_BY], i)
+ if (u->meta.type == UNIT_SOCKET)
+ socket_notify_service_dead(SOCKET(u));
- return 0;
+ return;
}
static void service_unwatch_pid_file(Service *s) {
return;
log_debug("Stopping watch for %s's PID file %s", s->meta.id, s->pid_file_pathspec->path);
- pathspec_unwatch(s->pid_file_pathspec, UNIT(s));
- pathspec_done(s->pid_file_pathspec);
+ path_spec_unwatch(s->pid_file_pathspec, UNIT(s));
+ path_spec_done(s->pid_file_pathspec);
free(s->pid_file_pathspec);
s->pid_file_pathspec = NULL;
}
int r;
int *rfds = NULL;
unsigned rn_fds = 0;
- Set *set, *free_set = NULL;
- Socket *sock;
+ Unit *u;
assert(s);
assert(fds);
if (s->socket_fd >= 0)
return 0;
- if (!set_isempty(s->configured_sockets))
- set = s->configured_sockets;
- else {
- if ((r = service_get_sockets(s, &free_set)) < 0)
- return r;
-
- set = free_set;
- }
-
- SET_FOREACH(sock, set, i) {
+ SET_FOREACH(u, s->meta.dependencies[UNIT_TRIGGERED_BY], i) {
int *cfds;
unsigned cn_fds;
+ Socket *sock;
+
+ if (u->meta.type != UNIT_SOCKET)
+ continue;
+
+ sock = SOCKET(u);
if ((r = socket_collect_fds(sock, &cfds, &cn_fds)) < 0)
goto fail;
*fds = rfds;
*n_fds = rn_fds;
- set_free(free_set);
-
return 0;
fail:
- set_free(set);
free(rfds);
return r;
int r;
log_debug("Setting watch for %s's PID file %s", s->meta.id, s->pid_file_pathspec->path);
- r = pathspec_watch(s->pid_file_pathspec, UNIT(s));
+ r = path_spec_watch(s->pid_file_pathspec, UNIT(s));
if (r < 0)
goto fail;
assert(fd >= 0);
assert(s->state == SERVICE_START || s->state == SERVICE_START_POST);
assert(s->pid_file_pathspec);
- assert(pathspec_owns_inotify_fd(s->pid_file_pathspec, fd));
+ assert(path_spec_owns_inotify_fd(s->pid_file_pathspec, fd));
log_debug("inotify event for %s", u->meta.id);
- if (pathspec_fd_event(s->pid_file_pathspec, events) < 0)
+ if (path_spec_fd_event(s->pid_file_pathspec, events) < 0)
goto fail;
if (service_retry_pid_file(s) == 0)
}
int service_set_socket_fd(Service *s, int fd, Socket *sock) {
+
assert(s);
assert(fd >= 0);
s->socket_fd = fd;
s->got_socket_fd = true;
- s->accept_socket = sock;
- return 0;
+ unit_ref_set(&s->accept_socket, UNIT(sock));
+
+ return unit_add_two_dependencies(UNIT(sock), UNIT_BEFORE, UNIT_TRIGGERS, UNIT(s), false);
}
static void service_reset_failed(Unit *u) {
#include "unit.h"
#include "path.h"
#include "ratelimit.h"
+#include "service.h"
typedef enum ServiceState {
SERVICE_DEAD,
RateLimit ratelimit;
- struct Socket *accept_socket;
- Set *configured_sockets;
+ UnitRef accept_socket;
Watch timer_watch;
PathSpec *pid_file_pathspec;
extern const UnitVTable service_vtable;
+struct Socket;
+
int service_set_socket_fd(Service *s, int fd, struct Socket *socket);
const char* service_state_to_string(ServiceState i);
static void socket_done(Unit *u) {
Socket *s = SOCKET(u);
SocketPort *p;
- Meta *i;
assert(s);
socket_unwatch_control_pid(s);
- s->service = NULL;
+ unit_ref_unset(&s->service);
free(s->tcp_congestion);
s->tcp_congestion = NULL;
s->bind_to_device = NULL;
unit_unwatch_timer(u, &s->timer_watch);
-
- /* Make sure no service instance refers to us anymore. */
- LIST_FOREACH(units_by_type, i, u->meta.manager->units_by_type[UNIT_SERVICE]) {
- Service *service = (Service *) i;
-
- if (service->accept_socket == s)
- service->accept_socket = NULL;
-
- set_remove(service->configured_sockets, s);
- }
}
static int socket_instantiate_service(Socket *s) {
* here. For Accept=no this is mostly a NOP since the service
* is figured out at load time anyway. */
- if (s->service)
+ if (UNIT_DEREF(s->service))
return 0;
assert(s->accept);
#endif
u->meta.no_gc = true;
- s->service = SERVICE(u);
- return 0;
+ unit_ref_set(&s->service, u);
+
+ return unit_add_two_dependencies(UNIT(s), UNIT_BEFORE, UNIT_TRIGGERS, u, false);
}
static bool have_non_accept_socket(Socket *s) {
return -EINVAL;
}
- if (s->accept && s->service) {
+ if (s->accept && UNIT_DEREF(s->service)) {
log_error("Explicit service configuration for accepting sockets not supported on %s. Refusing.", s->meta.id);
return -EINVAL;
}
if (have_non_accept_socket(s)) {
- if (!s->service)
- if ((r = unit_load_related_unit(u, ".service", (Unit**) &s->service)) < 0)
+ if (!UNIT_DEREF(s->service)) {
+ Unit *x;
+
+ r = unit_load_related_unit(u, ".service", &x);
+ if (r < 0)
return r;
- if ((r = unit_add_dependency(u, UNIT_BEFORE, UNIT(s->service), true)) < 0)
+ unit_ref_set(&s->service, x);
+ }
+
+ r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, UNIT_DEREF(s->service), true);
+ if (r < 0)
return r;
}
if ((r = socket_instantiate_service(s)) < 0)
return r;
- if (s->service && s->service->exec_command[SERVICE_EXEC_START]) {
- r = label_get_create_label_from_exe(s->service->exec_command[SERVICE_EXEC_START]->path, &label);
+ if (UNIT_DEREF(s->service) &&
+ SERVICE(UNIT_DEREF(s->service))->exec_command[SERVICE_EXEC_START]) {
+ r = label_get_create_label_from_exe(SERVICE(UNIT_DEREF(s->service))->exec_command[SERVICE_EXEC_START]->path, &label);
if (r < 0) {
if (r != -EPERM)
}
if (cfd < 0) {
+ Iterator i;
+ Unit *u;
bool pending = false;
- Meta *i;
/* If there's already a start pending don't bother to
* do anything */
- LIST_FOREACH(units_by_type, i, s->meta.manager->units_by_type[UNIT_SERVICE]) {
- Service *service = (Service *) i;
-
- if (!set_get(service->configured_sockets, s))
- continue;
-
- if (!unit_pending_active(UNIT(service)))
- continue;
-
- pending = true;
- break;
- }
+ SET_FOREACH(u, s->meta.dependencies[UNIT_TRIGGERS], i)
+ if (unit_pending_active(u)) {
+ pending = true;
+ break;
+ }
if (!pending)
- if ((r = manager_add_job(s->meta.manager, JOB_START, UNIT(s->service), JOB_REPLACE, true, &error, NULL)) < 0)
+ if ((r = manager_add_job(s->meta.manager, JOB_START, UNIT_DEREF(s->service), JOB_REPLACE, true, &error, NULL)) < 0)
goto fail;
socket_set_state(s, SOCKET_RUNNING);
goto fail;
}
- if ((r = unit_add_name(UNIT(s->service), name)) < 0) {
+ if ((r = unit_add_name(UNIT_DEREF(s->service), name)) < 0) {
free(name);
goto fail;
}
- service = s->service;
- s->service = NULL;
+ service = SERVICE(UNIT_DEREF(s->service));
+ unit_ref_unset(&s->service);
s->n_accepted ++;
service->meta.no_gc = false;
return 0;
/* Cannot run this without the service being around */
- if (s->service) {
- if (s->service->meta.load_state != UNIT_LOADED) {
- log_error("Socket service %s not loaded, refusing.", s->service->meta.id);
+ if (UNIT_DEREF(s->service)) {
+ Service *service;
+
+ service = SERVICE(UNIT_DEREF(s->service));
+
+ if (service->meta.load_state != UNIT_LOADED) {
+ log_error("Socket service %s not loaded, refusing.", service->meta.id);
return -ENOENT;
}
/* If the service is already active we cannot start the
* socket */
- if (s->service->state != SERVICE_DEAD &&
- s->service->state != SERVICE_FAILED &&
- s->service->state != SERVICE_AUTO_RESTART) {
- log_error("Socket service %s already active, refusing.", s->service->meta.id);
+ if (service->state != SERVICE_DEAD &&
+ service->state != SERVICE_FAILED &&
+ service->state != SERVICE_AUTO_RESTART) {
+ log_error("Socket service %s already active, refusing.", service->meta.id);
return -EBUSY;
}
#ifdef HAVE_SYSV_COMPAT
- if (s->service->sysv_path) {
+ if (service->sysv_path) {
log_error("Using SysV services for socket activation is not supported. Refusing.");
return -ENOENT;
}
#include "unit.h"
#include "socket-util.h"
#include "mount.h"
+#include "service.h"
typedef enum SocketState {
SOCKET_DEAD,
/* For Accept=no sockets refers to the one service we'll
activate. For Accept=yes sockets is either NULL, or filled
when the next service we spawn. */
- Service *service;
+ UnitRef service;
SocketState state, deserialized_state;
SocketExecCommand control_command_id;
pid_t control_pid;
- /* Only for INET6 sockets: issue IPV6_V6ONLY sockopt */
- SocketAddressBindIPv6Only bind_ipv6_only;
-
mode_t directory_mode;
mode_t socket_mode;
char *tcp_congestion;
long mq_maxmsg;
long mq_msgsize;
+
+ /* Only for INET6 sockets: issue IPV6_V6ONLY sockopt */
+ SocketAddressBindIPv6Only bind_ipv6_only;
};
/* Called from the service code when collecting fds */
}
unit_unwatch_timer(u, &t->timer_watch);
+
+ unit_ref_unset(&t->unit);
}
static int timer_verify(Timer *t) {
if (u->meta.load_state == UNIT_LOADED) {
- if (!t->unit)
- if ((r = unit_load_related_unit(u, ".service", &t->unit)))
+ if (!UNIT_DEREF(t->unit)) {
+ Unit *x;
+
+ r = unit_load_related_unit(u, ".service", &x);
+ if (r < 0)
return r;
- if ((r = unit_add_dependency(u, UNIT_BEFORE, t->unit, true)) < 0)
+ unit_ref_set(&t->unit, x);
+ }
+
+ r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, UNIT_DEREF(t->unit), true);
+ if (r < 0)
return r;
if (t->meta.default_dependencies)
"%sTimer State: %s\n"
"%sUnit: %s\n",
prefix, timer_state_to_string(t->state),
- prefix, t->unit->meta.id);
+ prefix, UNIT_DEREF(t->unit)->meta.id);
LIST_FOREACH(value, v, t->values)
fprintf(f,
case TIMER_UNIT_ACTIVE:
- if (t->unit->meta.inactive_exit_timestamp.monotonic <= 0)
+ if (UNIT_DEREF(t->unit)->meta.inactive_exit_timestamp.monotonic <= 0)
continue;
- base = t->unit->meta.inactive_exit_timestamp.monotonic;
+ base = UNIT_DEREF(t->unit)->meta.inactive_exit_timestamp.monotonic;
break;
case TIMER_UNIT_INACTIVE:
- if (t->unit->meta.inactive_enter_timestamp.monotonic <= 0)
+ if (UNIT_DEREF(t->unit)->meta.inactive_enter_timestamp.monotonic <= 0)
continue;
- base = t->unit->meta.inactive_enter_timestamp.monotonic;
+ base = UNIT_DEREF(t->unit)->meta.inactive_enter_timestamp.monotonic;
break;
default:
if (t->meta.job && t->meta.job->type == JOB_STOP)
return;
- if ((r = manager_add_job(t->meta.manager, JOB_START, t->unit, JOB_REPLACE, true, &error, NULL)) < 0)
+ if ((r = manager_add_job(t->meta.manager, JOB_START, UNIT_DEREF(t->unit), JOB_REPLACE, true, &error, NULL)) < 0)
goto fail;
timer_set_state(t, TIMER_RUNNING);
assert(t);
assert(t->state == TIMER_DEAD || t->state == TIMER_FAILED);
- if (t->unit->meta.load_state != UNIT_LOADED)
+ if (UNIT_DEREF(t->unit)->meta.load_state != UNIT_LOADED)
return -ENOENT;
t->failure = false;
}
void timer_unit_notify(Unit *u, UnitActiveState new_state) {
- char *n;
int r;
Iterator i;
+ Unit *k;
if (u->meta.type == UNIT_TIMER)
return;
- SET_FOREACH(n, u->meta.names, i) {
- char *k;
- Unit *p;
+ SET_FOREACH(k, u->meta.dependencies[UNIT_TRIGGERED_BY], i) {
Timer *t;
TimerValue *v;
- if (!(k = unit_name_change_suffix(n, ".timer"))) {
- r = -ENOMEM;
- goto fail;
- }
-
- p = manager_get_unit(u->meta.manager, k);
- free(k);
-
- if (!p)
+ if (k->meta.type != UNIT_TIMER)
continue;
- if (p->meta.load_state != UNIT_LOADED)
+ if (k->meta.load_state != UNIT_LOADED)
continue;
- t = TIMER(p);
-
- if (t->unit != u)
- continue;
+ t = TIMER(k);
/* Reenable all timers that depend on unit state */
LIST_FOREACH(value, v, t->values)
assert_not_reached("Unknown timer state");
}
}
-
- return;
-
-fail:
- log_error("Failed find timer unit: %s", strerror(-r));
}
static void timer_reset_failed(Unit *u) {
usec_t next_elapse;
TimerState state, deserialized_state;
- Unit *unit;
+ UnitRef unit;
Watch timer_watch;
free(u->meta.description);
free(u->meta.fragment_path);
+ free(u->meta.instance);
set_free_free(u->meta.names);
condition_free_list(u->meta.conditions);
- free(u->meta.instance);
+ while (u->meta.refs)
+ unit_ref_unset(u->meta.refs);
+
free(u);
}
/* Merge names */
merge_names(u, other);
+ /* Redirect all references */
+ while (other->meta.refs)
+ unit_ref_set(other->meta.refs, u);
+
/* Merge dependencies */
for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++)
merge_dependencies(u, other, d);
[UNIT_AFTER] = UNIT_BEFORE,
[UNIT_ON_FAILURE] = _UNIT_DEPENDENCY_INVALID,
[UNIT_REFERENCES] = UNIT_REFERENCED_BY,
- [UNIT_REFERENCED_BY] = UNIT_REFERENCES
+ [UNIT_REFERENCED_BY] = UNIT_REFERENCES,
+ [UNIT_TRIGGERS] = UNIT_TRIGGERED_BY,
+ [UNIT_TRIGGERED_BY] = UNIT_TRIGGERS
};
int r, q = 0, v = 0, w = 0;
return u->meta.unit_file_state;
}
+Unit* unit_ref_set(UnitRef *ref, Unit *u) {
+ assert(ref);
+ assert(u);
+
+ if (ref->unit)
+ unit_ref_unset(ref);
+
+ ref->unit = u;
+ LIST_PREPEND(UnitRef, refs, u->meta.refs, ref);
+ return u;
+}
+
+void unit_ref_unset(UnitRef *ref) {
+ assert(ref);
+
+ if (!ref->unit)
+ return;
+
+ LIST_REMOVE(UnitRef, refs, ref->unit->meta.refs, ref);
+ ref->unit = NULL;
+}
+
static const char* const unit_load_state_table[_UNIT_LOAD_STATE_MAX] = {
[UNIT_STUB] = "stub",
[UNIT_LOADED] = "loaded",
[UNIT_AFTER] = "After",
[UNIT_REFERENCES] = "References",
[UNIT_REFERENCED_BY] = "ReferencedBy",
- [UNIT_ON_FAILURE] = "OnFailure"
+ [UNIT_ON_FAILURE] = "OnFailure",
+ [UNIT_TRIGGERS] = "Triggers",
+ [UNIT_TRIGGERED_BY] = "TriggeredBy"
};
DEFINE_STRING_TABLE_LOOKUP(unit_dependency, UnitDependency);
typedef enum UnitLoadState UnitLoadState;
typedef enum UnitActiveState UnitActiveState;
typedef enum UnitDependency UnitDependency;
+typedef struct UnitRef UnitRef;
#include "set.h"
#include "util.h"
/* On Failure */
UNIT_ON_FAILURE,
+ /* Triggers (i.e. a socket triggers a service) */
+ UNIT_TRIGGERS,
+ UNIT_TRIGGERED_BY,
+
/* Reference information for GC logic */
UNIT_REFERENCES, /* Inverse of 'references' is 'referenced_by' */
UNIT_REFERENCED_BY,
usec_t job_timeout;
+ /* References to this */
+ LIST_HEAD(UnitRef, refs);
+
/* Conditions to check */
LIST_HEAD(Condition, conditions);
bool in_audit:1;
};
+struct UnitRef {
+ /* Keeps tracks of references to a unit. This is useful so
+ * that we can merge two units if necessary and correct all
+ * references to them */
+
+ Unit* unit;
+ LIST_FIELDS(UnitRef, refs);
+};
+
#include "service.h"
#include "timer.h"
#include "socket.h"
UnitFileState unit_get_unit_file_state(Unit *u);
+Unit* unit_ref_set(UnitRef *ref, Unit *u);
+void unit_ref_unset(UnitRef *ref);
+
+#define UNIT_DEREF(ref) ((ref).unit)
+
const char *unit_load_state_to_string(UnitLoadState i);
UnitLoadState unit_load_state_from_string(const char *s);