X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fcore%2Funit.c;h=601be60ed0595311910218a2b916f0ae2112bbf5;hp=f7d00b6030d2f9a690c8367da86506447347e3e7;hb=bf6dcfa6a79a459239799a21bdcba115d696a006;hpb=cd2086fe6573df923dc53ef33998c9fff8c2bda5 diff --git a/src/core/unit.c b/src/core/unit.c index f7d00b603..601be60ed 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -46,6 +46,8 @@ #include "missing.h" #include "cgroup-attr.h" #include "mkdir.h" +#include "label.h" +#include "fileio-label.h" const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX] = { [UNIT_SERVICE] = &service_vtable, @@ -614,9 +616,11 @@ int unit_add_exec_dependencies(Unit *u, ExecContext *c) { /* If syslog or kernel logging is requested, make sure our own * logging daemon is run first. */ - if (u->manager->running_as == SYSTEMD_SYSTEM) - if ((r = unit_add_two_dependencies_by_name(u, UNIT_REQUIRES, UNIT_AFTER, SPECIAL_JOURNALD_SOCKET, NULL, true)) < 0) + if (u->manager->running_as == SYSTEMD_SYSTEM) { + r = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_JOURNALD_SOCKET, NULL, true); + if (r < 0) return r; + } return 0; } @@ -745,15 +749,13 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { prefix, b->controller, b->path); LIST_FOREACH(by_unit, a, u->cgroup_attributes) { - char *v = NULL; + _cleanup_free_ char *v = NULL; - if (a->map_callback) - a->map_callback(a->controller, a->name, a->value, &v); + if (a->semantics && a->semantics->map_write) + a->semantics->map_write(a->semantics, a->value, &v); fprintf(f, "%s\tControlGroupAttribute: %s %s \"%s\"\n", prefix, a->controller, a->name, v ? v : a->value); - - free(v); } if (UNIT_VTABLE(u)->dump) @@ -992,7 +994,7 @@ static void unit_status_print_starting_stopping(Unit *u, JobType t) { if (!format) return; - unit_status_printf(u, "", format, unit_description(u)); + unit_status_printf(u, "", format); } #pragma GCC diagnostic push @@ -1318,6 +1320,7 @@ void unit_trigger_on_failure(Unit *u) { } void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_success) { + Manager *m; bool unexpected; assert(u); @@ -1330,7 +1333,9 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su * behavior here. For example: if a mount point is remounted * this function will be called too! */ - if (u->manager->n_reloading <= 0) { + m = u->manager; + + if (m->n_reloading <= 0) { dual_timestamp ts; dual_timestamp_get(&ts); @@ -1352,6 +1357,21 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su if (UNIT_IS_INACTIVE_OR_FAILED(ns)) cgroup_bonding_trim_list(u->cgroup_bondings, true); + if (UNIT_IS_INACTIVE_OR_FAILED(os) != UNIT_IS_INACTIVE_OR_FAILED(ns)) { + ExecContext *ec = unit_get_exec_context(u); + if (ec && exec_context_may_touch_console(ec)) { + /* XXX The counter may get out of sync if the admin edits + * TTY-related unit file properties and issues a daemon-reload + * while the unit is active. No big deal though, because + * it influences only the printing of boot/shutdown + * status messages. */ + if (UNIT_IS_INACTIVE_OR_FAILED(ns)) + m->n_on_console--; + else + m->n_on_console++; + } + } + if (u->job) { unexpected = false; @@ -1418,7 +1438,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su } else unexpected = true; - if (u->manager->n_reloading <= 0) { + if (m->n_reloading <= 0) { /* If this state change happened without being * requested by a job, then let's retroactively start @@ -1454,18 +1474,18 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su /* The bus just might have become available, * hence try to connect to it, if we aren't * yet connected. */ - bus_init(u->manager, true); + bus_init(m, true); if (u->type == UNIT_SERVICE && !UNIT_IS_ACTIVE_OR_RELOADING(os) && - u->manager->n_reloading <= 0) { + m->n_reloading <= 0) { /* Write audit record if we have just finished starting up */ - manager_send_unit_audit(u->manager, u, AUDIT_SERVICE_START, true); + manager_send_unit_audit(m, u, AUDIT_SERVICE_START, true); u->in_audit = true; } if (!UNIT_IS_ACTIVE_OR_RELOADING(os)) - manager_send_unit_plymouth(u->manager, u); + manager_send_unit_plymouth(m, u); } else { @@ -1475,29 +1495,30 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su if (u->type == UNIT_SERVICE && UNIT_IS_INACTIVE_OR_FAILED(ns) && !UNIT_IS_INACTIVE_OR_FAILED(os) && - u->manager->n_reloading <= 0) { + m->n_reloading <= 0) { /* Hmm, if there was no start record written * write it now, so that we always have a nice * pair */ if (!u->in_audit) { - manager_send_unit_audit(u->manager, u, AUDIT_SERVICE_START, ns == UNIT_INACTIVE); + manager_send_unit_audit(m, u, AUDIT_SERVICE_START, ns == UNIT_INACTIVE); if (ns == UNIT_INACTIVE) - manager_send_unit_audit(u->manager, u, AUDIT_SERVICE_STOP, true); + manager_send_unit_audit(m, u, AUDIT_SERVICE_STOP, true); } else /* Write audit record if we have just finished shutting down */ - manager_send_unit_audit(u->manager, u, AUDIT_SERVICE_STOP, ns == UNIT_INACTIVE); + manager_send_unit_audit(m, u, AUDIT_SERVICE_STOP, ns == UNIT_INACTIVE); u->in_audit = false; } } - manager_recheck_journal(u->manager); + manager_recheck_journal(m); /* Maybe we finished startup and are now ready for being * stopped because unneeded? */ - unit_check_unneeded(u); + if (u->manager->n_reloading <= 0) + unit_check_unneeded(u); unit_add_to_dbus_queue(u); unit_add_to_gc_queue(u); @@ -1896,30 +1917,12 @@ finish: } int set_unit_path(const char *p) { - char *cwd, *c; - int r; + _cleanup_free_ char *c = NULL; /* This is mostly for debug purposes */ - - if (path_is_absolute(p)) { - if (!(c = strdup(p))) - return -ENOMEM; - } else { - if (!(cwd = get_current_dir_name())) - return -errno; - - r = asprintf(&c, "%s/%s", cwd, p); - free(cwd); - - if (r < 0) - return -ENOMEM; - } - - if (setenv("SYSTEMD_UNIT_PATH", c, 0) < 0) { - r = -errno; - free(c); - return r; - } + c = path_make_absolute_cwd(p); + if (setenv("SYSTEMD_UNIT_PATH", c, 0) < 0) + return -errno; return 0; } @@ -2105,7 +2108,7 @@ static int unit_add_one_default_cgroup(Unit *u, const char *controller) { if (r < 0) goto fail; - return 0; + return 1; fail: free(b->path); @@ -2149,10 +2152,10 @@ CGroupBonding* unit_get_default_cgroup(Unit *u) { int unit_add_cgroup_attribute( Unit *u, + const CGroupSemantics *semantics, const char *controller, const char *name, const char *value, - CGroupAttributeMapCallback map_callback, CGroupAttribute **ret) { _cleanup_free_ char *c = NULL; @@ -2160,48 +2163,67 @@ int unit_add_cgroup_attribute( int r; assert(u); - assert(name); assert(value); + if (semantics) { + /* Semantics always take precedence */ + if (semantics->name) + name = semantics->name; + + if (semantics->controller) + controller = semantics->controller; + } + + if (!name) + return -EINVAL; + if (!controller) { r = cg_controller_from_attr(name, &c); if (r < 0) return -EINVAL; controller = c; - } else { - if (!filename_is_safe(name)) - return -EINVAL; - - if (!filename_is_safe(controller)) - return -EINVAL; } if (!controller || streq(controller, SYSTEMD_CGROUP_CONTROLLER)) return -EINVAL; + if (!filename_is_safe(name)) + return -EINVAL; + + if (!filename_is_safe(controller)) + return -EINVAL; + + /* Check if this attribute already exists. Note that we will + * explicitly check for the value here too, as there are + * attributes which accept multiple values. */ a = cgroup_attribute_find_list(u->cgroup_attributes, controller, name); if (a) { - char *v; - if (streq(value, a->value)) { + /* Exactly the same value is always OK, let's ignore this */ if (ret) *ret = a; return 0; } - v = strdup(value); - if (!v) - return -ENOMEM; + if (semantics && !semantics->multiple) { + char *v; - free(a->value); - a->value = v; + /* If this is a single-item entry, we can + * simply patch the existing attribute */ + + v = strdup(value); + if (!v) + return -ENOMEM; - if (ret) - *ret = a; + free(a->value); + a->value = v; - return 1; + if (ret) + *ret = a; + return 1; + } } a = new0(CGroupAttribute, 1); @@ -2222,11 +2244,10 @@ int unit_add_cgroup_attribute( free(a->name); free(a->value); free(a); - return -ENOMEM; } - a->map_callback = map_callback; + a->semantics = semantics; a->unit = u; LIST_PREPEND(CGroupAttribute, by_unit, u->cgroup_attributes, a); @@ -2533,21 +2554,8 @@ int unit_coldplug(Unit *u) { return 0; } -void unit_status_printf(Unit *u, const char *status, const char *format, ...) { - va_list ap; - - assert(u); - assert(format); - - if (!manager_get_show_status(u->manager)) - return; - - if (!manager_is_booting_or_shutting_down(u->manager)) - return; - - va_start(ap, format); - status_vprintf(status, true, format, ap); - va_end(ap); +void unit_status_printf(Unit *u, const char *status, const char *unit_status_msg_format) { + manager_status_printf(u->manager, false, status, unit_status_msg_format, unit_description(u)); } bool unit_need_daemon_reload(Unit *u) { @@ -2759,52 +2767,77 @@ ExecContext *unit_get_exec_context(Unit *u) { return (ExecContext*) ((uint8_t*) u + offset); } -int unit_write_drop_in(Unit *u, bool runtime, const char *name, const char *data) { - _cleanup_free_ char *p = NULL, *q = NULL; +static int drop_in_file(Unit *u, bool runtime, const char *name, char **_p, char **_q) { + char *p, *q; + int r; + assert(u); + assert(name); + assert(_p); + assert(_q); - if (u->manager->running_as != SYSTEMD_SYSTEM) + if (u->manager->running_as == SYSTEMD_USER && runtime) return -ENOTSUP; if (!filename_is_safe(name)) return -EINVAL; - p = strjoin(runtime ? "/run/systemd/system/" : "/etc/systemd/system/", u->id, ".d", NULL); + if (u->manager->running_as == SYSTEMD_USER) { + _cleanup_free_ char *c = NULL; + + r = user_config_home(&c); + if (r < 0) + return r; + if (r == 0) + return -ENOENT; + + p = strjoin(c, "/", u->id, ".d", NULL); + } else if (runtime) + p = strjoin("/run/systemd/system/", u->id, ".d", NULL); + else + p = strjoin("/etc/systemd/system/", u->id, ".d", NULL); if (!p) return -ENOMEM; q = strjoin(p, "/50-", name, ".conf", NULL); - if (!q) + if (!q) { + free(p); return -ENOMEM; + } - mkdir_p(p, 0755); - return write_one_line_file_atomic(q, data); + *_p = p; + *_q = q; + return 0; } -int unit_remove_drop_in(Unit *u, bool runtime, const char *name) { +int unit_write_drop_in(Unit *u, bool runtime, const char *name, const char *data) { _cleanup_free_ char *p = NULL, *q = NULL; + int r; assert(u); - if (u->manager->running_as != SYSTEMD_SYSTEM) - return -ENOTSUP; + r = drop_in_file(u, runtime, name, &p, &q); + if (r < 0) + return r; - if (!filename_is_safe(name)) - return -EINVAL; + mkdir_p(p, 0755); + return write_one_line_file_atomic_label(q, data); +} - p = strjoin(runtime ? "/run/systemd/system/" : "/etc/systemd/system/", u->id, ".d", NULL); - if (!p) - return -ENOMEM; +int unit_remove_drop_in(Unit *u, bool runtime, const char *name) { + _cleanup_free_ char *p = NULL, *q = NULL; + int r; - q = strjoin(p, "/50-", name, ".conf", NULL); - if (!q) - return -ENOMEM; + assert(u); + r = drop_in_file(u, runtime, name, &p, &q); if (unlink(q) < 0) - return -errno; + r = -errno; + else + r = 0; rmdir(p); - return 0; + return r; } int unit_kill_context(