This file is part of systemd.
Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <errno.h>
if (r < 0)
return r;
- *ret = u;
- u = NULL;
+ *ret = TAKE_PTR(u);
+
return r;
}
if (u->type == _UNIT_TYPE_INVALID) {
u->type = t;
u->id = s;
- u->instance = i;
+ u->instance = TAKE_PTR(i);
LIST_PREPEND(units_by_type, u->manager->units_by_type[t], u);
unit_init(u);
-
- i = NULL;
}
s = NULL;
if (u->in_cleanup_queue)
LIST_REMOVE(cleanup_queue, u->manager->cleanup_queue, u);
+ if (u->in_target_deps_queue)
+ LIST_REMOVE(target_deps_queue, u->manager->target_deps_queue, u);
+
safe_close(u->ip_accounting_ingress_map_fd);
safe_close(u->ip_accounting_egress_map_fd);
if (*s)
return set_move(*s, *other);
- else {
- *s = *other;
- *other = NULL;
- }
+ else
+ *s = TAKE_PTR(*other);
return 0;
}
if (*s)
return hashmap_move(*s, *other);
- else {
- *s = *other;
- *other = NULL;
- }
+ else
+ *s = TAKE_PTR(*other);
return 0;
}
/* Same as unit_load_fragment_and_dropin(), but whether
* something can be loaded or not doesn't matter. */
- /* Load a .service file */
+ /* Load a .service/.socket/.slice/… file */
r = unit_load_fragment(u);
if (r < 0)
return r;
return unit_load_dropin(unit_follow_merge(u));
}
+void unit_add_to_target_deps_queue(Unit *u) {
+ Manager *m = u->manager;
+
+ assert(u);
+
+ if (u->in_target_deps_queue)
+ return;
+
+ LIST_PREPEND(target_deps_queue, m->target_deps_queue, u);
+ u->in_target_deps_queue = true;
+}
+
int unit_add_default_target_dependency(Unit *u, Unit *target) {
assert(u);
assert(target);
return unit_add_dependency(target, UNIT_AFTER, u, true, UNIT_DEPENDENCY_DEFAULT);
}
-static int unit_add_target_dependencies(Unit *u) {
-
- static const UnitDependency deps[] = {
- UNIT_REQUIRED_BY,
- UNIT_REQUISITE_OF,
- UNIT_WANTED_BY,
- UNIT_BOUND_BY
- };
-
- unsigned k;
- int r = 0;
-
- assert(u);
-
- for (k = 0; k < ELEMENTSOF(deps); k++) {
- Unit *target;
- Iterator i;
- void *v;
-
- HASHMAP_FOREACH_KEY(v, target, u->dependencies[deps[k]], i) {
- r = unit_add_default_target_dependency(u, target);
- if (r < 0)
- return r;
- }
- }
-
- return r;
-}
-
static int unit_add_slice_dependencies(Unit *u) {
UnitDependencyMask mask;
assert(u);
}
if (u->load_state == UNIT_LOADED) {
-
- r = unit_add_target_dependencies(u);
- if (r < 0)
- goto fail;
+ unit_add_to_target_deps_queue(u);
r = unit_add_slice_dependencies(u);
if (r < 0)
int unit_start_limit_test(Unit *u) {
assert(u);
- if (ratelimit_test(&u->start_limit)) {
+ if (ratelimit_below(&u->start_limit)) {
u->start_limit_hit = false;
return 0;
}
* -EINVAL: Unit not loaded
* -EOPNOTSUPP: Unit type not supported
* -ENOLINK: The necessary dependencies are not fulfilled.
+ * -ESTALE: This unit has been started before and can't be started a second time
*/
int unit_start(Unit *u) {
UnitActiveState state;
if (u->load_state != UNIT_LOADED)
return -EINVAL;
+ /* Refuse starting scope units more than once */
+ if (UNIT_VTABLE(u)->once_only && dual_timestamp_is_set(&u->inactive_enter_timestamp))
+ return -ESTALE;
+
/* If the conditions failed, don't do anything at all. If we
* already are activating this call might still be useful to
* speed up activation in case there is some hold-off time,
if (!unit_supported(u))
return false;
+ /* Scope units may be started only once */
+ if (UNIT_VTABLE(u)->once_only && dual_timestamp_is_set(&u->inactive_exit_timestamp))
+ return false;
+
return !!UNIT_VTABLE(u)->start;
}
/* If stopping a unit fails continuously we might enter a stop
* loop here, hence stop acting on the service being
* unnecessary after a while. */
- if (!ratelimit_test(&u->auto_stop_ratelimit)) {
+ if (!ratelimit_below(&u->auto_stop_ratelimit)) {
log_unit_warning(u, "Unit not needed anymore, but not stopping since we tried this too often recently.");
return;
}
/* If stopping a unit fails continuously we might enter a stop
* loop here, hence stop acting on the service being
* unnecessary after a while. */
- if (!ratelimit_test(&u->auto_stop_ratelimit)) {
+ if (!ratelimit_below(&u->auto_stop_ratelimit)) {
log_unit_warning(u, "Unit is bound to inactive unit %s, but not stopping since we tried this too often recently.", other->id);
return;
}
}
}
- if (!MANAGER_IS_RELOADING(u->manager)) {
- manager_recheck_journal(m);
- manager_recheck_dbus(m);
- }
+ manager_recheck_journal(m);
+ manager_recheck_dbus(m);
unit_trigger_notify(u);
}
}
-
int unit_add_node_dependency(Unit *u, const char *what, bool wants, UnitDependency dep, UnitDependencyMask mask) {
Unit *device;
_cleanup_free_ char *e = NULL;
}
static Set *unit_pid_set(pid_t main_pid, pid_t control_pid) {
- Set *pid_set;
+ _cleanup_(set_freep) Set *pid_set = NULL;
int r;
pid_set = set_new(NULL);
if (main_pid > 0) {
r = set_put(pid_set, PID_TO_PTR(main_pid));
if (r < 0)
- goto fail;
+ return NULL;
}
if (control_pid > 0) {
r = set_put(pid_set, PID_TO_PTR(control_pid));
if (r < 0)
- goto fail;
+ return NULL;
}
- return pid_set;
-
-fail:
- set_free(pid_set);
- return NULL;
+ return TAKE_PTR(pid_set);
}
int unit_kill_common(
return r;
if (valid_user_group_name(n)) {
- *ret = n;
- n = NULL;
+ *ret = TAKE_PTR(n);
return 0;
}
char* unit_concat_strv(char **l, UnitWriteFlags flags) {
_cleanup_free_ char *result = NULL;
size_t n = 0, allocated = 0;
- char **i, *ret;
+ char **i;
/* Takes a list of strings, escapes them, and concatenates them. This may be used to format command lines in a
* way suitable for ExecStart= stanzas */
result[n] = 0;
- ret = result;
- result = NULL;
-
- return ret;
+ return TAKE_PTR(result);
}
int unit_write_setting(Unit *u, UnitWriteFlags flags, const char *name, const char *data) {
}
int unit_require_mounts_for(Unit *u, const char *path, UnitDependencyMask mask) {
- char prefix[strlen(path) + 1], *p;
+ _cleanup_free_ char *p = NULL;
+ char *prefix;
UnitDependencyInfo di;
int r;
if (!p)
return -ENOMEM;
- path_kill_slashes(p);
+ path = path_kill_slashes(p);
- if (!path_is_normalized(p)) {
- free(p);
+ if (!path_is_normalized(path))
return -EPERM;
- }
- if (hashmap_contains(u->requires_mounts_for, p)) {
- free(p);
+ if (hashmap_contains(u->requires_mounts_for, path))
return 0;
- }
di = (UnitDependencyInfo) {
.origin_mask = mask
};
- r = hashmap_put(u->requires_mounts_for, p, di.data);
- if (r < 0) {
- free(p);
+ r = hashmap_put(u->requires_mounts_for, path, di.data);
+ if (r < 0)
return r;
- }
+ p = NULL;
- PATH_FOREACH_PREFIX_MORE(prefix, p) {
+ prefix = alloca(strlen(path) + 1);
+ PATH_FOREACH_PREFIX_MORE(prefix, path) {
Set *x;
x = hashmap_get(u->manager->units_requiring_mounts_for, prefix);
if (!x) {
- char *q;
+ _cleanup_free_ char *q = NULL;
r = hashmap_ensure_allocated(&u->manager->units_requiring_mounts_for, &path_hash_ops);
if (r < 0)
return -ENOMEM;
x = set_new(NULL);
- if (!x) {
- free(q);
+ if (!x)
return -ENOMEM;
- }
r = hashmap_put(u->manager->units_requiring_mounts_for, q, x);
if (r < 0) {
- free(q);
set_free(x);
return r;
}
+ q = NULL;
}
r = set_put(x, u);
/* Check if the unit already exists or is already around,
* in a number of different ways. Note that to cater for unit
* types such as slice, we are generally fine with units that
- * are marked UNIT_LOADED even though nothing was
- * actually loaded, as those unit types don't require a file
- * on disk to validly load. */
+ * are marked UNIT_LOADED even though nothing was actually
+ * loaded, as those unit types don't require a file on disk. */
return !(!IN_SET(u->load_state, UNIT_NOT_FOUND, UNIT_LOADED) ||
u->fragment_path ||
if (!MANAGER_IS_SYSTEM(u->manager))
return;
+ if (u->manager->test_run_flags != 0)
+ return;
+
/* Exports a couple of unit properties to /run/systemd/units/, so that journald can quickly query this data
* from there. Ideally, journald would use IPC to query this, like everybody else, but that's hard, as long as
* the IPC system itself and PID 1 also log to the journal.