if (ec) {
exec_context_init(ec);
- ec->keyring_mode = MANAGER_IS_SYSTEM(u->manager) ?
- EXEC_KEYRING_SHARED : EXEC_KEYRING_INHERIT;
+ if (MANAGER_IS_SYSTEM(u->manager))
+ ec->keyring_mode = EXEC_KEYRING_SHARED;
+ else {
+ ec->keyring_mode = EXEC_KEYRING_INHERIT;
+
+ /* User manager might have its umask redefined by PAM or UMask=. In this
+ * case let the units it manages inherit this value by default. They can
+ * still tune this value through their own unit file */
+ (void) get_process_umask(getpid_cached(), &ec->umask);
+ }
}
kc = unit_get_kill_context(u);
if (unit_name_is_valid(text, UNIT_NAME_TEMPLATE)) {
if (!u->instance)
- return -EINVAL;
+ return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EINVAL),
+ "instance is not set when adding name '%s': %m", text);
r = unit_name_replace_instance(text, u->instance, &s);
if (r < 0)
- return r;
+ return log_unit_debug_errno(u, r,
+ "failed to build instance name from '%s': %m", text);
} else {
s = strdup(text);
if (!s)
if (set_contains(u->names, s))
return 0;
if (hashmap_contains(u->manager->units, s))
- return -EEXIST;
+ return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EEXIST),
+ "unit already exist when adding name '%s': %m", text);
if (!unit_name_is_valid(s, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE))
- return -EINVAL;
+ return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EINVAL),
+ "name '%s' is invalid: %m", text);
t = unit_name_to_type(s);
if (t < 0)
- return -EINVAL;
+ return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EINVAL),
+ "failed to to derive unit type from name '%s': %m", text);
if (u->type != _UNIT_TYPE_INVALID && t != u->type)
- return -EINVAL;
+ return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EINVAL),
+ "unit type is illegal: u->type(%d) and t(%d) for name '%s': %m",
+ u->type, t, text);
r = unit_name_to_instance(s, &i);
if (r < 0)
- return r;
+ return log_unit_debug_errno(u, r, "failed to extract instance from name '%s': %m", text);
if (i && !unit_type_may_template(t))
- return -EINVAL;
+ return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EINVAL), "templates are not allowed for name '%s': %m", text);
/* Ensure that this unit is either instanced or not instanced,
* but not both. Note that we do allow names with different
* instance names however! */
if (u->type != _UNIT_TYPE_INVALID && !u->instance != !i)
- return -EINVAL;
+ return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EINVAL),
+ "instance is illegal: u->type(%d), u->instance(%s) and i(%s) for name '%s': %m",
+ u->type, u->instance, i, text);
if (!unit_type_may_alias(t) && !set_isempty(u->names))
- return -EEXIST;
+ return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EEXIST), "symlinks are not allowed for name '%s': %m", text);
if (hashmap_size(u->manager->units) >= MANAGER_MAX_NAMES)
- return -E2BIG;
+ return log_unit_debug_errno(u, SYNTHETIC_ERRNO(E2BIG), "too many units: %m");
r = set_put(u->names, s);
if (r < 0)
r = hashmap_put(u->manager->units, s, u);
if (r < 0) {
(void) set_remove(u->names, s);
- return r;
+ return log_unit_debug_errno(u, r, "add unit to hashmap failed for name '%s': %m", text);
}
if (u->type == _UNIT_TYPE_INVALID) {
!IN_SET(c->std_error,
EXEC_OUTPUT_JOURNAL, EXEC_OUTPUT_JOURNAL_AND_CONSOLE,
EXEC_OUTPUT_KMSG, EXEC_OUTPUT_KMSG_AND_CONSOLE,
- EXEC_OUTPUT_SYSLOG, EXEC_OUTPUT_SYSLOG_AND_CONSOLE))
+ EXEC_OUTPUT_SYSLOG, EXEC_OUTPUT_SYSLOG_AND_CONSOLE) &&
+ !c->log_namespace)
return 0;
- /* If syslog or kernel logging is requested, make sure our own
- * logging daemon is run first. */
+ /* If syslog or kernel logging is requested (or log namespacing is), make sure our own logging daemon
+ * is run first. */
+
+ if (c->log_namespace) {
+ _cleanup_free_ char *socket_unit = NULL, *varlink_socket_unit = NULL;
+
+ r = unit_name_build_from_type("systemd-journald", c->log_namespace, UNIT_SOCKET, &socket_unit);
+ if (r < 0)
+ return r;
+
+ r = unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_REQUIRES, socket_unit, true, UNIT_DEPENDENCY_FILE);
+ if (r < 0)
+ return r;
- r = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_JOURNALD_SOCKET, true, UNIT_DEPENDENCY_FILE);
+ r = unit_name_build_from_type("systemd-journald-varlink", c->log_namespace, UNIT_SOCKET, &varlink_socket_unit);
+ if (r < 0)
+ return r;
+
+ r = unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_REQUIRES, varlink_socket_unit, true, UNIT_DEPENDENCY_FILE);
+ if (r < 0)
+ return r;
+ } else
+ r = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_JOURNALD_SOCKET, true, UNIT_DEPENDENCY_FILE);
if (r < 0)
return r;
return u->assert_result;
}
-void unit_status_printf(Unit *u, const char *status, const char *unit_status_msg_format) {
+void unit_status_printf(Unit *u, StatusType status_type, const char *status, const char *unit_status_msg_format) {
const char *d;
d = unit_status_string(u);
d = strjoina(ANSI_HIGHLIGHT, d, ANSI_NORMAL);
DISABLE_WARNING_FORMAT_NONLITERAL;
- manager_status_printf(u->manager, STATUS_TYPE_NORMAL, status, unit_status_msg_format, d);
+ manager_status_printf(u->manager, status_type, status, unit_status_msg_format, d);
REENABLE_WARNING;
}
return 0;
}
- if ((d == UNIT_BEFORE && other->type == UNIT_DEVICE) ||
- (d == UNIT_AFTER && u->type == UNIT_DEVICE)) {
- log_unit_warning(u, "Dependency Before=%s ignored (.device units cannot be delayed)", other->id);
+ if (d == UNIT_AFTER && UNIT_VTABLE(u)->refuse_after) {
+ log_unit_warning(u, "Requested dependency After=%s ignored (%s units cannot be delayed).", other->id, unit_type_to_string(u->type));
+ return 0;
+ }
+
+ if (d == UNIT_BEFORE && UNIT_VTABLE(other)->refuse_after) {
+ log_unit_warning(u, "Requested dependency Before=%s ignored (%s units cannot be delayed).", other->id, unit_type_to_string(other->type));
+ return 0;
+ }
+
+ if (d == UNIT_ON_FAILURE && !UNIT_VTABLE(u)->can_fail) {
+ log_unit_warning(u, "Requested dependency OnFailure=%s ignored (%s units cannot fail).", other->id, unit_type_to_string(u->type));
return 0;
}
+ if (d == UNIT_TRIGGERS && !UNIT_VTABLE(u)->can_trigger)
+ return log_unit_error_errno(u, SYNTHETIC_ERRNO(EINVAL),
+ "Requested dependency Triggers=%s refused (%s units cannot trigger other units).", other->id, unit_type_to_string(u->type));
+ if (d == UNIT_TRIGGERED_BY && !UNIT_VTABLE(other)->can_trigger)
+ return log_unit_error_errno(u, SYNTHETIC_ERRNO(EINVAL),
+ "Requested dependency TriggeredBy=%s refused (%s units cannot trigger other units).", other->id, unit_type_to_string(other->type));
+
r = unit_add_dependency_hashmap(u->dependencies + d, other, mask, 0);
if (r < 0)
return r;
}
static int signal_name_owner_changed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- const char *name, *old_owner, *new_owner;
+ const char *new_owner;
Unit *u = userdata;
int r;
assert(message);
assert(u);
- r = sd_bus_message_read(message, "sss", &name, &old_owner, &new_owner);
+ r = sd_bus_message_read(message, "sss", NULL, NULL, &new_owner);
if (r < 0) {
bus_log_parse_error(r);
return 0;
}
- old_owner = empty_to_null(old_owner);
- new_owner = empty_to_null(new_owner);
-
if (UNIT_VTABLE(u)->bus_name_owner_change)
- UNIT_VTABLE(u)->bus_name_owner_change(u, old_owner, new_owner);
+ UNIT_VTABLE(u)->bus_name_owner_change(u, empty_to_null(new_owner));
return 0;
}
if (!sd_bus_error_has_name(e, "org.freedesktop.DBus.Error.NameHasNoOwner"))
log_unit_error(u, "Unexpected error response from GetNameOwner(): %s", e->message);
- return 0;
- }
+ new_owner = NULL;
+ } else {
+ r = sd_bus_message_read(message, "s", &new_owner);
+ if (r < 0)
+ return bus_log_parse_error(r);
- r = sd_bus_message_read(message, "s", &new_owner);
- if (r < 0)
- return bus_log_parse_error(r);
+ assert(!isempty(new_owner));
+ }
if (UNIT_VTABLE(u)->bus_name_owner_change)
- UNIT_VTABLE(u)->bus_name_owner_change(u, NULL, new_owner);
+ UNIT_VTABLE(u)->bus_name_owner_change(u, new_owner);
return 0;
}
int unit_install_bus_match(Unit *u, sd_bus *bus, const char *name) {
const char *match;
+ int r;
assert(u);
assert(bus);
assert(name);
- if (u->match_bus_slot)
+ if (u->match_bus_slot || u->get_name_owner_slot)
return -EBUSY;
match = strjoina("type='signal',"
"member='NameOwnerChanged',"
"arg0='", name, "'");
- int r = sd_bus_add_match_async(bus, &u->match_bus_slot, match, signal_name_owner_changed, NULL, u);
+ r = sd_bus_add_match_async(bus, &u->match_bus_slot, match, signal_name_owner_changed, NULL, u);
if (r < 0)
return r;
- return sd_bus_call_method_async(bus,
- &u->get_name_owner_slot,
- "org.freedesktop.DBus",
- "/org/freedesktop/DBus",
- "org.freedesktop.DBus",
- "GetNameOwner",
- get_name_owner_handler,
- u,
- "s", name);
+ r = sd_bus_call_method_async(
+ bus,
+ &u->get_name_owner_slot,
+ "org.freedesktop.DBus",
+ "/org/freedesktop/DBus",
+ "org.freedesktop.DBus",
+ "GetNameOwner",
+ get_name_owner_handler,
+ u,
+ "s", name);
+ if (r < 0) {
+ u->match_bus_slot = sd_bus_slot_unref(u->match_bus_slot);
+ return r;
+ }
+
+ log_unit_debug(u, "Watching D-Bus name '%s'.", name);
+ return 0;
}
int unit_watch_bus_name(Unit *u, const char *name) {
r = hashmap_put(u->manager->watch_bus, name, u);
if (r < 0) {
u->match_bus_slot = sd_bus_slot_unref(u->match_bus_slot);
+ u->get_name_owner_slot = sd_bus_slot_unref(u->get_name_owner_slot);
return log_warning_errno(r, "Failed to put bus name to hashmap: %m");
}
}
int unit_add_node_dependency(Unit *u, const char *what, UnitDependency dep, UnitDependencyMask mask) {
- Unit *device;
_cleanup_free_ char *e = NULL;
+ Unit *device;
int r;
assert(u);
if (!is_device_path(what))
return 0;
- /* When device units aren't supported (such as in a
- * container), don't create dependencies on them. */
+ /* When device units aren't supported (such as in a container), don't create dependencies on them. */
if (!unit_type_supported(UNIT_DEVICE))
return 0;
device, true, mask);
}
+int unit_add_blockdev_dependency(Unit *u, const char *what, UnitDependencyMask mask) {
+ _cleanup_free_ char *escaped = NULL, *target = NULL;
+ int r;
+
+ assert(u);
+
+ if (isempty(what))
+ return 0;
+
+ if (!path_startswith(what, "/dev/"))
+ return 0;
+
+ /* If we don't support devices, then also don't bother with blockdev@.target */
+ if (!unit_type_supported(UNIT_DEVICE))
+ return 0;
+
+ r = unit_name_path_escape(what, &escaped);
+ if (r < 0)
+ return r;
+
+ r = unit_name_build("blockdev", escaped, ".target", &target);
+ if (r < 0)
+ return r;
+
+ return unit_add_dependency_by_name(u, UNIT_AFTER, target, true, mask);
+}
+
int unit_coldplug(Unit *u) {
int r = 0, q;
char **i;
if (r < 0)
return r;
- if (valid_user_group_name(n)) {
+ if (valid_user_group_name(n, 0)) {
*ret = TAKE_PTR(n);
return 0;
}
if (ec->protect_kernel_logs)
ec->capability_bounding_set &= ~(UINT64_C(1) << CAP_SYSLOG);
+ if (ec->protect_clock)
+ ec->capability_bounding_set &= ~((UINT64_C(1) << CAP_SYS_TIME) | (UINT64_C(1) << CAP_WAKE_ALARM));
+
if (ec->dynamic_user) {
if (!ec->user) {
r = user_from_unit_name(u, &ec->user);
r = cgroup_add_device_allow(cc, "block-blkext", "rwm");
if (r < 0)
return r;
+
+ /* Make sure "block-loop" can be resolved, i.e. make sure "loop" shows up in /proc/devices */
+ r = unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_WANTS, "modprobe@loop.service", true, UNIT_DEPENDENCY_FILE);
+ if (r < 0)
+ return r;
+ }
+
+ if (ec->protect_clock) {
+ r = cgroup_add_device_allow(cc, "char-rtc", "r");
+ if (r < 0)
+ return r;
}
}
*ref_uid = UID_INVALID;
}
-void unit_unref_uid(Unit *u, bool destroy_now) {
+static void unit_unref_uid(Unit *u, bool destroy_now) {
unit_unref_uid_internal(u, &u->ref_uid, destroy_now, manager_unref_uid);
}
-void unit_unref_gid(Unit *u, bool destroy_now) {
+static void unit_unref_gid(Unit *u, bool destroy_now) {
unit_unref_uid_internal(u, (uid_t*) &u->ref_gid, destroy_now, manager_unref_gid);
}
+void unit_unref_uid_gid(Unit *u, bool destroy_now) {
+ assert(u);
+
+ unit_unref_uid(u, destroy_now);
+ unit_unref_gid(u, destroy_now);
+}
+
static int unit_ref_uid_internal(
Unit *u,
uid_t *ref_uid,
return 1;
}
-int unit_ref_uid(Unit *u, uid_t uid, bool clean_ipc) {
+static int unit_ref_uid(Unit *u, uid_t uid, bool clean_ipc) {
return unit_ref_uid_internal(u, &u->ref_uid, uid, clean_ipc, manager_ref_uid);
}
-int unit_ref_gid(Unit *u, gid_t gid, bool clean_ipc) {
+static int unit_ref_gid(Unit *u, gid_t gid, bool clean_ipc) {
return unit_ref_uid_internal(u, (uid_t*) &u->ref_gid, (uid_t) gid, clean_ipc, manager_ref_gid);
}
return r;
}
-void unit_unref_uid_gid(Unit *u, bool destroy_now) {
- assert(u);
-
- unit_unref_uid(u, destroy_now);
- unit_unref_gid(u, destroy_now);
-}
-
void unit_notify_user_lookup(Unit *u, uid_t uid, gid_t gid) {
int r;
if (di.origin_mask == 0 && di.destination_mask == 0) {
/* No bit set anymore, let's drop the whole entry */
assert_se(hashmap_remove(u->dependencies[d], other));
- log_unit_debug(u, "%s lost dependency %s=%s", u->id, unit_dependency_to_string(d), other->id);
+ log_unit_debug(u, "lost dependency %s=%s", unit_dependency_to_string(d), other->id);
} else
/* Mask was reduced, let's update the entry */
assert_se(hashmap_update(u->dependencies[d], other, di.data) == 0);
return exec_context_may_touch_console(ec);
}
-const char *unit_label_path(Unit *u) {
+const char *unit_label_path(const Unit *u) {
const char *p;
+ assert(u);
+
/* Returns the file system path to use for MAC access decisions, i.e. the file to read the SELinux label off
* when validating access checks. */