X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Funit.c;h=840c1d1fc450556e56ce79b87045b1980eece2d0;hp=701dbc0952f8e561a2dc30fd8041c2d70d7ed416;hb=eeaafddcb5ce492f2b3d53678820d41a04ab66b2;hpb=9e58ff9c5c3bd46a796a20fc6c304cdab489f334 diff --git a/src/unit.c b/src/unit.c index 701dbc095..840c1d1fc 100644 --- a/src/unit.c +++ b/src/unit.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "set.h" #include "unit.h" @@ -39,6 +40,7 @@ #include "specifier.h" #include "dbus-unit.h" #include "special.h" +#include "cgroup-util.h" const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX] = { [UNIT_SERVICE] = &service_vtable, @@ -83,7 +85,7 @@ bool unit_has_name(Unit *u, const char *name) { int unit_add_name(Unit *u, const char *text) { UnitType t; - char *s = NULL, *i = NULL; + char *s, *i = NULL; int r; assert(u); @@ -118,7 +120,9 @@ int unit_add_name(Unit *u, const char *text) { if (i && unit_vtable[t]->no_instances) goto fail; - if (u->meta.type != _UNIT_TYPE_INVALID && !streq_ptr(u->meta.instance, i)) { + /* Ensure that this unit is either instanced or not instanced, + * but not both. */ + if (u->meta.type != _UNIT_TYPE_INVALID && !u->meta.instance != !i) { r = -EINVAL; goto fail; } @@ -170,7 +174,8 @@ fail: } int unit_choose_id(Unit *u, const char *name) { - char *s, *t = NULL; + char *s, *t = NULL, *i; + int r; assert(u); assert(name); @@ -193,7 +198,14 @@ int unit_choose_id(Unit *u, const char *name) { if (!s) return -ENOENT; + if ((r = unit_name_to_instance(s, &i)) < 0) + return r; + u->meta.id = s; + + free(u->meta.instance); + u->meta.instance = i; + unit_add_to_dbus_queue(u); return 0; @@ -459,7 +471,7 @@ int unit_merge(Unit *u, Unit *other) { if (u->meta.type != other->meta.type) return -EINVAL; - if (!streq_ptr(u->meta.instance, other->meta.instance)) + if (!u->meta.instance != !other->meta.instance) return -EINVAL; if (other->meta.load_state != UNIT_STUB && @@ -575,7 +587,9 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX], timestamp3[FORMAT_TIMESTAMP_MAX], - timestamp4[FORMAT_TIMESTAMP_MAX]; + timestamp4[FORMAT_TIMESTAMP_MAX], + timespan[FORMAT_TIMESPAN_MAX]; + Unit *following; assert(u); assert(u->meta.type >= 0); @@ -595,7 +609,8 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { "%s\tActive Enter Timestamp: %s\n" "%s\tActive Exit Timestamp: %s\n" "%s\tInactive Enter Timestamp: %s\n" - "%s\tGC Check Good: %s\n", + "%s\tGC Check Good: %s\n" + "%s\tNeed Daemon Reload: %s\n", prefix, u->meta.id, prefix, unit_description(u), prefix, strna(u->meta.instance), @@ -605,14 +620,21 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { prefix, strna(format_timestamp(timestamp2, sizeof(timestamp2), u->meta.active_enter_timestamp.realtime)), prefix, strna(format_timestamp(timestamp3, sizeof(timestamp3), u->meta.active_exit_timestamp.realtime)), prefix, strna(format_timestamp(timestamp4, sizeof(timestamp4), u->meta.inactive_enter_timestamp.realtime)), - prefix, yes_no(unit_check_gc(u))); + prefix, yes_no(unit_check_gc(u)), + prefix, yes_no(unit_need_daemon_reload(u))); SET_FOREACH(t, u->meta.names, i) fprintf(f, "%s\tName: %s\n", prefix, t); + if ((following = unit_following(u))) + fprintf(f, "%s\tFollowing: %s\n", prefix, following->meta.id); + if (u->meta.fragment_path) fprintf(f, "%s\tFragment Path: %s\n", prefix, u->meta.fragment_path); + if (u->meta.job_timeout > 0) + fprintf(f, "%s\tJob Timeout: %s\n", prefix, format_timespan(timespan, sizeof(timespan), u->meta.job_timeout)); + for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++) { Unit *other; @@ -625,11 +647,13 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { "%s\tRecursive Stop: %s\n" "%s\tStopWhenUnneeded: %s\n" "%s\tOnlyByDependency: %s\n" - "%s\tDefaultDependencies: %s\n", + "%s\tDefaultDependencies: %s\n" + "%s\tIgnoreDependencyFailure: %s\n", prefix, yes_no(u->meta.recursive_stop), prefix, yes_no(u->meta.stop_when_unneeded), prefix, yes_no(u->meta.only_by_dependency), - prefix, yes_no(u->meta.default_dependencies)); + prefix, yes_no(u->meta.default_dependencies), + prefix, yes_no(u->meta.ignore_dependency_failure)); LIST_FOREACH(by_unit, b, u->meta.cgroup_bondings) fprintf(f, "%s\tControlGroup: %s:%s\n", @@ -738,7 +762,7 @@ fail: u->meta.load_state = UNIT_FAILED; unit_add_to_dbus_queue(u); - log_debug("Failed to load configuration for %s: %s", u->meta.id, strerror(-r)); + log_notice("Failed to load configuration for %s: %s", u->meta.id, strerror(-r)); return r; } @@ -878,10 +902,10 @@ static void unit_check_uneeded(Unit *u) { if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) return; - log_debug("Service %s is not needed anymore. Stopping.", u->meta.id); + log_info("Service %s is not needed anymore. Stopping.", u->meta.id); /* Ok, nobody needs us anymore. Sniff. Then let's commit suicide */ - manager_add_job(u->meta.manager, JOB_STOP, u, JOB_FAIL, true, NULL); + manager_add_job(u->meta.manager, JOB_STOP, u, JOB_FAIL, true, NULL, NULL); } static void retroactively_start_dependencies(Unit *u) { @@ -893,23 +917,23 @@ static void retroactively_start_dependencies(Unit *u) { SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRES], i) if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other))) - manager_add_job(u->meta.manager, JOB_START, other, JOB_REPLACE, true, NULL); + manager_add_job(u->meta.manager, JOB_START, other, JOB_REPLACE, true, NULL, NULL); SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRES_OVERRIDABLE], i) if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other))) - manager_add_job(u->meta.manager, JOB_START, other, JOB_FAIL, false, NULL); + manager_add_job(u->meta.manager, JOB_START, other, JOB_FAIL, false, NULL, NULL); SET_FOREACH(other, u->meta.dependencies[UNIT_REQUISITE], i) if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other))) - manager_add_job(u->meta.manager, JOB_START, other, JOB_REPLACE, true, NULL); + manager_add_job(u->meta.manager, JOB_START, other, JOB_REPLACE, true, NULL, NULL); SET_FOREACH(other, u->meta.dependencies[UNIT_WANTS], i) if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other))) - manager_add_job(u->meta.manager, JOB_START, other, JOB_FAIL, false, NULL); + manager_add_job(u->meta.manager, JOB_START, other, JOB_FAIL, false, NULL, NULL); SET_FOREACH(other, u->meta.dependencies[UNIT_CONFLICTS], i) if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other))) - manager_add_job(u->meta.manager, JOB_STOP, other, JOB_REPLACE, true, NULL); + manager_add_job(u->meta.manager, JOB_STOP, other, JOB_REPLACE, true, NULL, NULL); } static void retroactively_stop_dependencies(Unit *u) { @@ -923,7 +947,7 @@ static void retroactively_stop_dependencies(Unit *u) { /* Pull down units need us recursively if enabled */ SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRED_BY], i) if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) - manager_add_job(u->meta.manager, JOB_STOP, other, JOB_REPLACE, true, NULL); + manager_add_job(u->meta.manager, JOB_STOP, other, JOB_REPLACE, true, NULL, NULL); } /* Garbage collect services that might not be needed anymore, if enabled */ @@ -946,6 +970,7 @@ static void retroactively_stop_dependencies(Unit *u) { void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns) { dual_timestamp ts; + bool unexpected; assert(u); assert(os < _UNIT_ACTIVE_STATE_MAX); @@ -970,11 +995,14 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns) { else if (UNIT_IS_ACTIVE_OR_RELOADING(os) && !UNIT_IS_ACTIVE_OR_RELOADING(ns)) u->meta.active_exit_timestamp = ts; + if (UNIT_IS_INACTIVE_OR_MAINTENANCE(ns)) + cgroup_bonding_trim_list(u->meta.cgroup_bondings, true); + timer_unit_notify(u, ns); path_unit_notify(u, ns); if (u->meta.job) { - bool unexpected = false; + unexpected = false; if (u->meta.job->state == JOB_WAITING) @@ -983,7 +1011,6 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns) { * failed previously due to EAGAIN. */ job_add_to_run_queue(u->meta.job); - /* Let's check whether this state change constitutes a * finished job, or maybe cotradicts a running job and * hence needs to invalidate jobs. */ @@ -1020,10 +1047,8 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns) { case JOB_RESTART: case JOB_TRY_RESTART: - if (ns == UNIT_INACTIVE) + if (ns == UNIT_INACTIVE || ns == UNIT_MAINTENANCE) job_finish_and_invalidate(u->meta.job, true); - else if (ns == UNIT_MAINTENANCE) - job_finish_and_invalidate(u->meta.job, false); else if (u->meta.job->state == JOB_RUNNING && ns != UNIT_DEACTIVATING) { unexpected = true; job_finish_and_invalidate(u->meta.job, false); @@ -1035,16 +1060,30 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns) { assert_not_reached("Job type unknown"); } - /* If this state change happened without being - * requested by a job, then let's retroactively start - * or stop dependencies */ + } else + unexpected = true; + + /* If this state change happened without being requested by a + * job, then let's retroactively start or stop + * dependencies. We skip that step when deserializing, since + * we don't want to create any additional jobs just because + * something is already activated. */ + + if (unexpected && u->meta.manager->n_deserializing <= 0) { + if (UNIT_IS_INACTIVE_OR_DEACTIVATING(os) && UNIT_IS_ACTIVE_OR_ACTIVATING(ns)) + retroactively_start_dependencies(u); + else if (UNIT_IS_ACTIVE_OR_ACTIVATING(os) && UNIT_IS_INACTIVE_OR_DEACTIVATING(ns)) + retroactively_stop_dependencies(u); + } - if (unexpected) { - if (UNIT_IS_INACTIVE_OR_DEACTIVATING(os) && UNIT_IS_ACTIVE_OR_ACTIVATING(ns)) - retroactively_start_dependencies(u); - else if (UNIT_IS_ACTIVE_OR_ACTIVATING(os) && UNIT_IS_INACTIVE_OR_DEACTIVATING(ns)) - retroactively_stop_dependencies(u); - } + if (ns != os && ns == UNIT_MAINTENANCE) { + Iterator i; + Unit *other; + + SET_FOREACH(other, u->meta.dependencies[UNIT_ON_FAILURE], i) + manager_add_job(u->meta.manager, JOB_START, other, JOB_REPLACE, true, NULL, NULL); + + log_notice("Unit %s entered maintenance state.", u->meta.id); } /* Some names are special */ @@ -1140,14 +1179,14 @@ int unit_watch_pid(Unit *u, pid_t pid) { /* 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); + return hashmap_put(u->meta.manager->watch_pids, LONG_TO_PTR(pid), u); } void unit_unwatch_pid(Unit *u, pid_t pid) { assert(u); assert(pid >= 1); - hashmap_remove_value(u->meta.manager->watch_pids, UINT32_TO_PTR(pid), u); + hashmap_remove_value(u->meta.manager->watch_pids, LONG_TO_PTR(pid), u); } int unit_watch_timer(Unit *u, usec_t delay, Watch *w) { @@ -1157,18 +1196,23 @@ int unit_watch_timer(Unit *u, usec_t delay, Watch *w) { assert(u); assert(w); - assert(w->type == WATCH_INVALID || (w->type == WATCH_TIMER && w->data.unit == u)); + assert(w->type == WATCH_INVALID || (w->type == WATCH_UNIT_TIMER && w->data.unit == u)); /* This will try to reuse the old timer if there is one */ - if (w->type == WATCH_TIMER) { + if (w->type == WATCH_UNIT_TIMER) { + assert(w->data.unit == u); + assert(w->fd >= 0); + ours = false; fd = w->fd; - } else { + } else if (w->type == WATCH_INVALID) { + ours = true; if ((fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC)) < 0) return -errno; - } + } else + assert_not_reached("Invalid watch type"); zero(its); @@ -1199,8 +1243,8 @@ int unit_watch_timer(Unit *u, usec_t delay, Watch *w) { goto fail; } + w->type = WATCH_UNIT_TIMER; w->fd = fd; - w->type = WATCH_TIMER; w->data.unit = u; return 0; @@ -1219,7 +1263,9 @@ void unit_unwatch_timer(Unit *u, Watch *w) { if (w->type == WATCH_INVALID) return; - assert(w->type == WATCH_TIMER && w->data.unit == u); + assert(w->type == WATCH_UNIT_TIMER); + assert(w->data.unit == u); + assert(w->fd >= 0); assert_se(epoll_ctl(u->meta.manager->epoll_fd, EPOLL_CTL_DEL, w->fd, NULL) >= 0); close_nointr_nofail(w->fd); @@ -1269,6 +1315,7 @@ int unit_add_dependency(Unit *u, UnitDependency d, Unit *other, bool add_referen [UNIT_CONFLICTS] = UNIT_CONFLICTS, [UNIT_BEFORE] = UNIT_AFTER, [UNIT_AFTER] = UNIT_BEFORE, + [UNIT_ON_FAILURE] = _UNIT_DEPENDENCY_INVALID, [UNIT_REFERENCES] = UNIT_REFERENCED_BY, [UNIT_REFERENCED_BY] = UNIT_REFERENCES }; @@ -1276,7 +1323,6 @@ int unit_add_dependency(Unit *u, UnitDependency d, Unit *other, bool add_referen assert(u); assert(d >= 0 && d < _UNIT_DEPENDENCY_MAX); - assert(inverse_table[d] != _UNIT_DEPENDENCY_INVALID); assert(other); /* We won't allow dependencies on ourselves. We will not @@ -1292,10 +1338,13 @@ int unit_add_dependency(Unit *u, UnitDependency d, Unit *other, bool add_referen return -EINVAL; } - if ((r = set_ensure_allocated(&u->meta.dependencies[d], trivial_hash_func, trivial_compare_func)) < 0 || - (r = set_ensure_allocated(&other->meta.dependencies[inverse_table[d]], trivial_hash_func, trivial_compare_func)) < 0) + if ((r = set_ensure_allocated(&u->meta.dependencies[d], trivial_hash_func, trivial_compare_func)) < 0) return r; + if (inverse_table[d] != _UNIT_DEPENDENCY_INVALID) + if ((r = set_ensure_allocated(&other->meta.dependencies[inverse_table[d]], trivial_hash_func, trivial_compare_func)) < 0) + return r; + if (add_reference) if ((r = set_ensure_allocated(&u->meta.dependencies[UNIT_REFERENCES], trivial_hash_func, trivial_compare_func)) < 0 || (r = set_ensure_allocated(&other->meta.dependencies[UNIT_REFERENCED_BY], trivial_hash_func, trivial_compare_func)) < 0) @@ -1304,10 +1353,11 @@ int unit_add_dependency(Unit *u, UnitDependency d, Unit *other, bool add_referen if ((q = set_put(u->meta.dependencies[d], other)) < 0) return q; - if ((v = set_put(other->meta.dependencies[inverse_table[d]], u)) < 0) { - r = v; - goto fail; - } + if (inverse_table[d] != _UNIT_DEPENDENCY_INVALID) + if ((v = set_put(other->meta.dependencies[inverse_table[d]], u)) < 0) { + r = v; + goto fail; + } if (add_reference) { if ((w = set_put(u->meta.dependencies[UNIT_REFERENCES], other)) < 0) { @@ -1393,7 +1443,7 @@ int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name, con if (!(name = resolve_template(u, name, path, &s))) return -ENOMEM; - if ((r = manager_load_unit(u->meta.manager, name, path, &other)) < 0) + if ((r = manager_load_unit(u->meta.manager, name, path, NULL, &other)) < 0) goto finish; r = unit_add_dependency(u, d, other, add_reference); @@ -1414,7 +1464,7 @@ int unit_add_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency if (!(name = resolve_template(u, name, path, &s))) return -ENOMEM; - if ((r = manager_load_unit(u->meta.manager, name, path, &other)) < 0) + if ((r = manager_load_unit(u->meta.manager, name, path, NULL, &other)) < 0) goto finish; r = unit_add_two_dependencies(u, d, e, other, add_reference); @@ -1435,7 +1485,7 @@ int unit_add_dependency_by_name_inverse(Unit *u, UnitDependency d, const char *n if (!(name = resolve_template(u, name, path, &s))) return -ENOMEM; - if ((r = manager_load_unit(u->meta.manager, name, path, &other)) < 0) + if ((r = manager_load_unit(u->meta.manager, name, path, NULL, &other)) < 0) goto finish; r = unit_add_dependency(other, d, u, add_reference); @@ -1456,7 +1506,7 @@ int unit_add_two_dependencies_by_name_inverse(Unit *u, UnitDependency d, UnitDep if (!(name = resolve_template(u, name, path, &s))) return -ENOMEM; - if ((r = manager_load_unit(u->meta.manager, name, path, &other)) < 0) + if ((r = manager_load_unit(u->meta.manager, name, path, NULL, &other)) < 0) goto finish; if ((r = unit_add_two_dependencies(other, d, e, u, add_reference)) < 0) @@ -1504,12 +1554,9 @@ char *unit_dbus_path(Unit *u) { if (!(e = bus_path_escape(u->meta.id))) return NULL; - if (asprintf(&p, "/org/freedesktop/systemd1/unit/%s", e) < 0) { - free(e); - return NULL; - } - + p = strappend("/org/freedesktop/systemd1/unit/", e); free(e); + return p; } @@ -1519,8 +1566,13 @@ int unit_add_cgroup(Unit *u, CGroupBonding *b) { assert(u); assert(b); + assert(b->path); + if (!b->controller) + if (!(b->controller = strdup(SYSTEMD_CGROUP_CONTROLLER))) + return -ENOMEM; + /* Ensure this hasn't been added yet */ assert(!b->unit); @@ -1559,7 +1611,6 @@ static char *default_cgroup_path(Unit *u) { } int unit_add_cgroup_from_text(Unit *u, const char *name) { - size_t n; char *controller = NULL, *path = NULL; CGroupBonding *b = NULL; int r; @@ -1567,38 +1618,20 @@ int unit_add_cgroup_from_text(Unit *u, const char *name) { assert(u); assert(name); - /* Detect controller name */ - n = strcspn(name, ":"); - - if (name[n] == 0 || - (name[n] == ':' && name[n+1] == 0)) { - - /* Only controller name, no path? */ - - if (!(path = default_cgroup_path(u))) - return -ENOMEM; + if ((r = cg_split_spec(name, &controller, &path)) < 0) + return r; - } else { - const char *p; + if (!path) + path = default_cgroup_path(u); - /* Controller name, and path. */ - p = name+n+1; + if (!controller) + controller = strdup(SYSTEMD_CGROUP_CONTROLLER); - if (!path_is_absolute(p)) - return -EINVAL; + if (!path || !controller) { + free(path); + free(controller); - if (!(path = strdup(p))) - return -ENOMEM; - } - - if (n > 0) - controller = strndup(name, n); - else - controller = strdup(u->meta.manager->cgroup_controller); - - if (!controller) { - r = -ENOMEM; - goto fail; + return -ENOMEM; } if (cgroup_bonding_find_list(u->meta.cgroup_bondings, controller)) { @@ -1643,9 +1676,6 @@ int unit_add_default_cgroup(Unit *u) { if (!(b = new0(CGroupBonding, 1))) return -ENOMEM; - if (!(b->controller = strdup(u->meta.manager->cgroup_controller))) - goto fail; - if (!(b->path = default_cgroup_path(u))) goto fail; @@ -1668,7 +1698,7 @@ fail: CGroupBonding* unit_get_default_cgroup(Unit *u) { assert(u); - return cgroup_bonding_find_list(u->meta.cgroup_bondings, u->meta.manager->cgroup_controller); + return cgroup_bonding_find_list(u->meta.cgroup_bondings, SYSTEMD_CGROUP_CONTROLLER); } int unit_load_related_unit(Unit *u, const char *type, Unit **_found) { @@ -1684,7 +1714,7 @@ int unit_load_related_unit(Unit *u, const char *type, Unit **_found) { assert(!unit_has_name(u, t)); - r = manager_load_unit(u->meta.manager, t, NULL, _found); + r = manager_load_unit(u->meta.manager, t, NULL, NULL, _found); free(t); assert(r < 0 || *_found != u); @@ -1969,7 +1999,7 @@ int unit_add_node_link(Unit *u, const char *what, bool wants) { if (!(e = unit_name_build_escape(what+1, NULL, ".device"))) return -ENOMEM; - r = manager_load_unit(u->meta.manager, e, NULL, &device); + r = manager_load_unit(u->meta.manager, e, NULL, NULL, &device); free(e); if (r < 0) @@ -1995,7 +2025,7 @@ int unit_coldplug(Unit *u) { return r; if (u->meta.deserialized_job >= 0) { - if ((r = manager_add_job(u->meta.manager, u->meta.deserialized_job, u, JOB_FAIL, false, NULL)) < 0) + if ((r = manager_add_job(u->meta.manager, u->meta.deserialized_job, u, JOB_FAIL, false, NULL, NULL)) < 0) return r; u->meta.deserialized_job = _JOB_TYPE_INVALID; @@ -2027,6 +2057,40 @@ void unit_status_printf(Unit *u, const char *format, ...) { va_end(ap); } +bool unit_need_daemon_reload(Unit *u) { + struct stat st; + + assert(u); + + if (!u->meta.fragment_path) + return false; + + zero(st); + if (stat(u->meta.fragment_path, &st) < 0) + /* What, cannot access this anymore? */ + return true; + + return + u->meta.fragment_mtime && + timespec_load(&st.st_mtim) != u->meta.fragment_mtime; +} + +void unit_reset_maintenance(Unit *u) { + assert(u); + + if (UNIT_VTABLE(u)->reset_maintenance) + UNIT_VTABLE(u)->reset_maintenance(u); +} + +Unit *unit_following(Unit *u) { + assert(u); + + if (UNIT_VTABLE(u)->following) + return UNIT_VTABLE(u)->following(u); + + return NULL; +} + static const char* const unit_type_table[_UNIT_TYPE_MAX] = { [UNIT_SERVICE] = "service", [UNIT_TIMER] = "timer", @@ -2074,7 +2138,8 @@ static const char* const unit_dependency_table[_UNIT_DEPENDENCY_MAX] = { [UNIT_BEFORE] = "Before", [UNIT_AFTER] = "After", [UNIT_REFERENCES] = "References", - [UNIT_REFERENCED_BY] = "ReferencedBy" + [UNIT_REFERENCED_BY] = "ReferencedBy", + [UNIT_ON_FAILURE] = "OnFailure" }; DEFINE_STRING_TABLE_LOOKUP(unit_dependency, UnitDependency);