/* 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;
}
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)
if (!format)
return;
- unit_status_printf(u, "", format, unit_description(u));
+ unit_status_printf(u, "", format);
}
#pragma GCC diagnostic push
}
void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_success) {
+ Manager *m;
bool unexpected;
assert(u);
* 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);
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)) {
+ if (UNIT_IS_INACTIVE_OR_FAILED(ns))
+ m->n_on_console--;
+ else
+ m->n_on_console++;
+ }
+ }
+
if (u->job) {
unexpected = false;
} 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
/* 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 {
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);
}
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;
}
if (r < 0)
goto fail;
- return 0;
+ return 1;
fail:
free(b->path);
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;
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 */
- if (ret)
- *ret = a;
+ v = strdup(value);
+ if (!v)
+ return -ENOMEM;
+
+ free(a->value);
+ a->value = v;
- return 1;
+ if (ret)
+ *ret = a;
+ return 1;
+ }
}
a = new0(CGroupAttribute, 1);
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);
job_free(j);
return r;
}
+
+ if (j->state == JOB_RUNNING)
+ u->manager->n_running_jobs++;
} else {
/* legacy */
JobType type = job_type_from_string(v);
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) {
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_label(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(