summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/busname.c28
-rw-r--r--src/core/dbus-execute.c86
-rw-r--r--src/core/dbus-manager.c10
-rw-r--r--src/core/dbus-service.c16
-rw-r--r--src/core/dbus-timer.c14
-rw-r--r--src/core/dbus-unit.c21
-rw-r--r--src/core/dbus.c66
-rw-r--r--src/core/dbus.h2
-rw-r--r--src/core/device.c21
-rw-r--r--src/core/execute.c201
-rw-r--r--src/core/execute.h6
-rw-r--r--src/core/job.c50
-rw-r--r--src/core/job.h7
-rw-r--r--src/core/killall.c21
-rw-r--r--src/core/load-dropin.c1
-rw-r--r--src/core/load-fragment-gperf.gperf.m424
-rw-r--r--src/core/load-fragment.c257
-rw-r--r--src/core/load-fragment.h5
-rw-r--r--src/core/machine-id-setup.c23
-rw-r--r--src/core/machine-id-setup.h2
-rw-r--r--src/core/main.c107
-rw-r--r--src/core/manager.c28
-rw-r--r--src/core/mount-setup.c58
-rw-r--r--src/core/mount.c41
-rw-r--r--src/core/scope.c45
-rw-r--r--src/core/service.c248
-rw-r--r--src/core/service.h2
-rw-r--r--src/core/smack-setup.c101
-rw-r--r--src/core/socket.c69
-rw-r--r--src/core/swap.c28
-rw-r--r--src/core/transaction.c40
-rw-r--r--src/core/unit.c44
-rw-r--r--src/core/unit.h7
33 files changed, 997 insertions, 682 deletions
diff --git a/src/core/busname.c b/src/core/busname.c
index a949cd6d3f..4b0cad8db4 100644
--- a/src/core/busname.c
+++ b/src/core/busname.c
@@ -112,29 +112,27 @@ static void busname_done(Unit *u) {
n->timer_event_source = sd_event_source_unref(n->timer_event_source);
}
-static int busname_arm_timer(BusName *n) {
+static int busname_arm_timer(BusName *n, usec_t usec) {
int r;
assert(n);
- if (n->timeout_usec <= 0) {
- n->timer_event_source = sd_event_source_unref(n->timer_event_source);
- return 0;
- }
-
if (n->timer_event_source) {
- r = sd_event_source_set_time(n->timer_event_source, now(CLOCK_MONOTONIC) + n->timeout_usec);
+ r = sd_event_source_set_time(n->timer_event_source, usec);
if (r < 0)
return r;
return sd_event_source_set_enabled(n->timer_event_source, SD_EVENT_ONESHOT);
}
+ if (usec == USEC_INFINITY)
+ return 0;
+
r = sd_event_add_time(
UNIT(n)->manager->event,
&n->timer_event_source,
CLOCK_MONOTONIC,
- now(CLOCK_MONOTONIC) + n->timeout_usec, 0,
+ usec, 0,
busname_dispatch_timer, n);
if (r < 0)
return r;
@@ -372,7 +370,7 @@ static int busname_coldplug(Unit *u) {
if (r < 0)
return r;
- r = busname_arm_timer(n);
+ r = busname_arm_timer(n, usec_add(u->state_change_timestamp.monotonic, n->timeout_usec));
if (r < 0)
return r;
}
@@ -397,7 +395,7 @@ static int busname_make_starter(BusName *n, pid_t *_pid) {
pid_t pid;
int r;
- r = busname_arm_timer(n);
+ r = busname_arm_timer(n, usec_add(now(CLOCK_MONOTONIC), n->timeout_usec));
if (r < 0)
goto fail;
@@ -475,7 +473,7 @@ static void busname_enter_signal(BusName *n, BusNameState state, BusNameResult f
}
if (r > 0) {
- r = busname_arm_timer(n);
+ r = busname_arm_timer(n, usec_add(now(CLOCK_MONOTONIC), n->timeout_usec));
if (r < 0) {
log_unit_warning_errno(UNIT(n), r, "Failed to arm timer: %m");
goto fail;
@@ -974,17 +972,21 @@ static int busname_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
return unit_kill_common(u, who, signo, -1, BUSNAME(u)->control_pid, error);
}
-static int busname_get_timeout(Unit *u, uint64_t *timeout) {
+static int busname_get_timeout(Unit *u, usec_t *timeout) {
BusName *n = BUSNAME(u);
+ usec_t t;
int r;
if (!n->timer_event_source)
return 0;
- r = sd_event_source_get_time(n->timer_event_source, timeout);
+ r = sd_event_source_get_time(n->timer_event_source, &t);
if (r < 0)
return r;
+ if (t == USEC_INFINITY)
+ return 0;
+ *timeout = t;
return 1;
}
diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
index 1f736b2686..2de28f43e1 100644
--- a/src/core/dbus-execute.c
+++ b/src/core/dbus-execute.c
@@ -141,7 +141,7 @@ static int property_get_nice(
else {
errno = 0;
n = getpriority(PRIO_PROCESS, 0);
- if (errno != 0)
+ if (errno > 0)
n = 0;
}
@@ -293,9 +293,25 @@ static int property_get_capability_bounding_set(
assert(reply);
assert(c);
- /* We store this negated internally, to match the kernel, but
- * we expose it normalized. */
- return sd_bus_message_append(reply, "t", ~c->capability_bounding_set_drop);
+ return sd_bus_message_append(reply, "t", c->capability_bounding_set);
+}
+
+static int property_get_ambient_capabilities(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ ExecContext *c = userdata;
+
+ assert(bus);
+ assert(reply);
+ assert(c);
+
+ return sd_bus_message_append(reply, "t", c->capability_ambient_set);
}
static int property_get_capabilities(
@@ -689,6 +705,7 @@ const sd_bus_vtable bus_exec_vtable[] = {
SD_BUS_PROPERTY("Capabilities", "s", property_get_capabilities, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SecureBits", "i", bus_property_get_int, offsetof(ExecContext, secure_bits), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("CapabilityBoundingSet", "t", property_get_capability_bounding_set, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("AmbientCapabilities", "t", property_get_ambient_capabilities, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("User", "s", NULL, offsetof(ExecContext, user), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Group", "s", NULL, offsetof(ExecContext, group), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SupplementaryGroups", "as", NULL, offsetof(ExecContext, supplementary_groups), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -818,7 +835,8 @@ int bus_exec_context_set_transient_property(
UnitSetPropertiesMode mode,
sd_bus_error *error) {
- int r;
+ const char *soft = NULL;
+ int r, ri;
assert(u);
assert(c);
@@ -1365,7 +1383,7 @@ int bus_exec_context_set_transient_property(
dirs = &c->read_write_dirs;
else if (streq(name, "ReadOnlyDirectories"))
dirs = &c->read_only_dirs;
- else if (streq(name, "InaccessibleDirectories"))
+ else /* "InaccessibleDirectories" */
dirs = &c->inaccessible_dirs;
if (strv_length(l) == 0) {
@@ -1475,7 +1493,23 @@ int bus_exec_context_set_transient_property(
return 1;
- } else if (rlimit_from_string(name) >= 0) {
+ }
+
+ ri = rlimit_from_string(name);
+ if (ri < 0) {
+ soft = endswith(name, "Soft");
+ if (soft) {
+ const char *n;
+
+ n = strndupa(name, soft - name);
+ ri = rlimit_from_string(n);
+ if (ri >= 0)
+ name = n;
+
+ }
+ }
+
+ if (ri >= 0) {
uint64_t rl;
rlim_t x;
@@ -1493,22 +1527,36 @@ int bus_exec_context_set_transient_property(
}
if (mode != UNIT_CHECK) {
- int z;
-
- z = rlimit_from_string(name);
+ _cleanup_free_ char *f = NULL;
+ struct rlimit nl;
+
+ if (c->rlimit[ri]) {
+ nl = *c->rlimit[ri];
+
+ if (soft)
+ nl.rlim_cur = x;
+ else
+ nl.rlim_max = x;
+ } else
+ /* When the resource limit is not initialized yet, then assign the value to both fields */
+ nl = (struct rlimit) {
+ .rlim_cur = x,
+ .rlim_max = x,
+ };
+
+ r = rlimit_format(&nl, &f);
+ if (r < 0)
+ return r;
- if (!c->rlimit[z]) {
- c->rlimit[z] = new(struct rlimit, 1);
- if (!c->rlimit[z])
+ if (c->rlimit[ri])
+ *c->rlimit[ri] = nl;
+ else {
+ c->rlimit[ri] = newdup(struct rlimit, &nl, 1);
+ if (!c->rlimit[ri])
return -ENOMEM;
}
- c->rlimit[z]->rlim_cur = c->rlimit[z]->rlim_max = x;
-
- if (x == RLIM_INFINITY)
- unit_write_drop_in_private_format(u, mode, name, "%s=infinity\n", name);
- else
- unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu64 "\n", name, rl);
+ unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, f);
}
return 1;
diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
index 61bd0f8d5f..c5c672a0a2 100644
--- a/src/core/dbus-manager.c
+++ b/src/core/dbus-manager.c
@@ -229,7 +229,10 @@ static int property_set_log_level(
if (r < 0)
return r;
- return log_set_max_level_from_string(t);
+ r = log_set_max_level_from_string(t);
+ if (r == 0)
+ log_info("Setting log level to %s.", t);
+ return r;
}
static int property_get_n_names(
@@ -1604,6 +1607,7 @@ static int reply_unit_file_changes_and_free(
if (r < 0)
goto fail;
+ unit_file_changes_free(changes, n_changes);
return sd_bus_send(NULL, reply, NULL);
fail:
@@ -1840,8 +1844,10 @@ static int method_preset_all_unit_files(sd_bus_message *message, void *userdata,
scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
r = unit_file_preset_all(scope, runtime, NULL, mm, force, &changes, &n_changes);
- if (r < 0)
+ if (r < 0) {
+ unit_file_changes_free(changes, n_changes);
return r;
+ }
return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes);
}
diff --git a/src/core/dbus-service.c b/src/core/dbus-service.c
index 24f611a593..16f50238a1 100644
--- a/src/core/dbus-service.c
+++ b/src/core/dbus-service.c
@@ -49,6 +49,7 @@ const sd_bus_vtable bus_service_vtable[] = {
SD_BUS_PROPERTY("RestartUSec", "t", bus_property_get_usec, offsetof(Service, restart_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("TimeoutStartUSec", "t", bus_property_get_usec, offsetof(Service, timeout_start_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("TimeoutStopUSec", "t", bus_property_get_usec, offsetof(Service, timeout_stop_usec), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("RuntimeMaxUSec", "t", bus_property_get_usec, offsetof(Service, runtime_max_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("WatchdogUSec", "t", bus_property_get_usec, offsetof(Service, watchdog_usec), SD_BUS_VTABLE_PROPERTY_CONST),
BUS_PROPERTY_DUAL_TIMESTAMP("WatchdogTimestamp", offsetof(Service, watchdog_timestamp), 0),
SD_BUS_PROPERTY("StartLimitInterval", "t", bus_property_get_usec, offsetof(Service, start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -125,6 +126,19 @@ static int bus_service_set_transient_property(
}
return 1;
+ } else if (streq(name, "RuntimeMaxUSec")) {
+ usec_t u;
+
+ r = sd_bus_message_read(message, "t", &u);
+ if (r < 0)
+ return r;
+
+ if (mode != UNIT_CHECK) {
+ s->runtime_max_usec = u;
+ unit_write_drop_in_private_format(UNIT(s), mode, name, "RuntimeMaxSec=" USEC_FMT "us\n", u);
+ }
+
+ return 1;
} else if (STR_IN_SET(name,
"StandardInputFileDescriptor",
@@ -153,6 +167,8 @@ static int bus_service_set_transient_property(
asynchronous_close(s->stderr_fd);
s->stderr_fd = copy;
}
+
+ s->exec_context.stdio_as_fds = true;
}
return 1;
diff --git a/src/core/dbus-timer.c b/src/core/dbus-timer.c
index ec301df6d7..321ed5da37 100644
--- a/src/core/dbus-timer.c
+++ b/src/core/dbus-timer.c
@@ -267,19 +267,19 @@ static int bus_timer_set_transient_property(
return 1;
- } else if (streq(name, "AccuracySec")) {
-
+ } else if (STR_IN_SET(name, "AccuracyUSec", "AccuracySec")) {
usec_t u = 0;
+ if (streq(name, "AccuracySec"))
+ log_notice("Client is using obsolete AccuracySec= transient property, please use AccuracyUSec= instead.");
+
r = sd_bus_message_read(message, "t", &u);
if (r < 0)
return r;
if (mode != UNIT_CHECK) {
- char time[FORMAT_TIMESPAN_MAX];
-
t->accuracy_usec = u;
- unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s\n", name, format_timespan(time, sizeof(time), u, USEC_PER_MSEC));
+ unit_write_drop_in_private_format(UNIT(t), mode, name, "AccuracySec=" USEC_FMT "us\n", u);
}
return 1;
@@ -292,10 +292,8 @@ static int bus_timer_set_transient_property(
return r;
if (mode != UNIT_CHECK) {
- char time[FORMAT_TIMESPAN_MAX];
-
t->random_usec = u;
- unit_write_drop_in_private_format(UNIT(t), mode, name, "RandomizedDelaySec=%s\n", format_timespan(time, sizeof(time), u, USEC_PER_MSEC));
+ unit_write_drop_in_private_format(UNIT(t), mode, name, "RandomizedDelaySec=" USEC_FMT "us\n", u);
}
return 1;
diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c
index e4d2c08972..d7929e5566 100644
--- a/src/core/dbus-unit.c
+++ b/src/core/dbus-unit.c
@@ -458,7 +458,10 @@ int bus_unit_method_start_generic(
assert(u);
assert(job_type >= 0 && job_type < _JOB_TYPE_MAX);
- r = mac_selinux_unit_access_check(u, message, job_type == JOB_STOP ? "stop" : "start", error);
+ r = mac_selinux_unit_access_check(
+ u, message,
+ job_type_to_access_method(job_type),
+ error);
if (r < 0)
return r;
@@ -671,6 +674,7 @@ const sd_bus_vtable bus_unit_vtable[] = {
SD_BUS_PROPERTY("DropInPaths", "as", NULL, offsetof(Unit, dropin_paths), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("UnitFileState", "s", property_get_unit_file_state, 0, 0),
SD_BUS_PROPERTY("UnitFilePreset", "s", property_get_unit_file_preset, 0, 0),
+ BUS_PROPERTY_DUAL_TIMESTAMP("StateChangeTimestamp", offsetof(Unit, state_change_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
BUS_PROPERTY_DUAL_TIMESTAMP("InactiveExitTimestamp", offsetof(Unit, inactive_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
BUS_PROPERTY_DUAL_TIMESTAMP("ActiveEnterTimestamp", offsetof(Unit, active_enter_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
BUS_PROPERTY_DUAL_TIMESTAMP("ActiveExitTimestamp", offsetof(Unit, active_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
@@ -983,19 +987,20 @@ int bus_unit_queue_job(
assert(type >= 0 && type < _JOB_TYPE_MAX);
assert(mode >= 0 && mode < _JOB_MODE_MAX);
+ r = mac_selinux_unit_access_check(
+ u, message,
+ job_type_to_access_method(type),
+ error);
+ if (r < 0)
+ return r;
+
if (reload_if_possible && unit_can_reload(u)) {
if (type == JOB_RESTART)
type = JOB_RELOAD_OR_START;
else if (type == JOB_TRY_RESTART)
- type = JOB_RELOAD;
+ type = JOB_TRY_RELOAD;
}
- r = mac_selinux_unit_access_check(
- u, message,
- (type == JOB_START || type == JOB_RESTART || type == JOB_TRY_RESTART) ? "start" :
- type == JOB_STOP ? "stop" : "reload", error);
- if (r < 0)
- return r;
if (type == JOB_STOP &&
(u->load_state == UNIT_NOT_FOUND || u->load_state == UNIT_ERROR) &&
diff --git a/src/core/dbus.c b/src/core/dbus.c
index e7ee216f0e..1d89b9e250 100644
--- a/src/core/dbus.c
+++ b/src/core/dbus.c
@@ -734,9 +734,11 @@ static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void
return 0;
}
-static int bus_list_names(Manager *m, sd_bus *bus) {
+int manager_sync_bus_names(Manager *m, sd_bus *bus) {
_cleanup_strv_free_ char **names = NULL;
- char **i;
+ const char *name;
+ Iterator i;
+ Unit *u;
int r;
assert(m);
@@ -746,15 +748,55 @@ static int bus_list_names(Manager *m, sd_bus *bus) {
if (r < 0)
return log_error_errno(r, "Failed to get initial list of names: %m");
- /* This is a bit hacky, we say the owner of the name is the
- * name itself, because we don't want the extra traffic to
- * figure out the real owner. */
- STRV_FOREACH(i, names) {
- Unit *u;
+ /* We have to synchronize the current bus names with the
+ * list of active services. To do this, walk the list of
+ * all units with bus names. */
+ HASHMAP_FOREACH_KEY(u, name, m->watch_bus, i) {
+ Service *s = SERVICE(u);
+
+ assert(s);
- u = hashmap_get(m->watch_bus, *i);
- if (u)
- UNIT_VTABLE(u)->bus_name_owner_change(u, *i, NULL, *i);
+ if (!streq_ptr(s->bus_name, name)) {
+ log_unit_warning(u, "Bus name has changed from %s → %s, ignoring.", s->bus_name, name);
+ continue;
+ }
+
+ /* Check if a service's bus name is in the list of currently
+ * active names */
+ if (strv_contains(names, name)) {
+ _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
+ const char *unique;
+
+ /* If it is, determine its current owner */
+ r = sd_bus_get_name_creds(bus, name, SD_BUS_CREDS_UNIQUE_NAME, &creds);
+ if (r < 0) {
+ log_error_errno(r, "Failed to get bus name owner %s: %m", name);
+ continue;
+ }
+
+ r = sd_bus_creds_get_unique_name(creds, &unique);
+ if (r < 0) {
+ log_error_errno(r, "Failed to get unique name for %s: %m", name);
+ continue;
+ }
+
+ /* Now, let's compare that to the previous bus owner, and
+ * if it's still the same, all is fine, so just don't
+ * bother the service. Otherwise, the name has apparently
+ * changed, so synthesize a name owner changed signal. */
+
+ if (!streq_ptr(unique, s->bus_name_owner))
+ UNIT_VTABLE(u)->bus_name_owner_change(u, name, s->bus_name_owner, unique);
+ } else {
+ /* So, the name we're watching is not on the bus.
+ * This either means it simply hasn't appeared yet,
+ * or it was lost during the daemon reload.
+ * Check if the service has a stored name owner,
+ * and synthesize a name loss signal in this case. */
+
+ if (s->bus_name_owner)
+ UNIT_VTABLE(u)->bus_name_owner_change(u, name, s->bus_name_owner, NULL);
+ }
}
return 0;
@@ -808,7 +850,9 @@ static int bus_setup_api(Manager *m, sd_bus *bus) {
if (r < 0)
return log_error_errno(r, "Failed to register name: %m");
- bus_list_names(m, bus);
+ r = manager_sync_bus_names(m, bus);
+ if (r < 0)
+ return r;
log_debug("Successfully connected to API bus.");
return 0;
diff --git a/src/core/dbus.h b/src/core/dbus.h
index 4f06ad11c4..ff761668f3 100644
--- a/src/core/dbus.h
+++ b/src/core/dbus.h
@@ -34,6 +34,8 @@ void bus_track_serialize(sd_bus_track *t, FILE *f);
int bus_track_deserialize_item(char ***l, const char *line);
int bus_track_coldplug(Manager *m, sd_bus_track **t, char ***l);
+int manager_sync_bus_names(Manager *m, sd_bus *bus);
+
int bus_foreach_bus(Manager *m, sd_bus_track *subscribed2, int (*send_message)(sd_bus *bus, void *userdata), void *userdata);
int bus_verify_manage_units_async(Manager *m, sd_bus_message *call, sd_bus_error *error);
diff --git a/src/core/device.c b/src/core/device.c
index bcd4d1146b..807547c87f 100644
--- a/src/core/device.c
+++ b/src/core/device.c
@@ -267,7 +267,7 @@ static int device_add_udev_wants(Unit *u, struct udev_device *dev) {
assert(u);
assert(dev);
- property = u->manager->running_as == MANAGER_USER ? "MANAGER_USER_WANTS" : "SYSTEMD_WANTS";
+ property = u->manager->running_as == MANAGER_USER ? "SYSTEMD_USER_WANTS" : "SYSTEMD_WANTS";
wants = udev_device_get_property_value(dev, property);
if (!wants)
return 0;
@@ -315,12 +315,19 @@ static int device_setup_unit(Manager *m, struct udev_device *dev, const char *pa
u = manager_get_unit(m, e);
- if (u &&
- sysfs &&
- DEVICE(u)->sysfs &&
- !path_equal(DEVICE(u)->sysfs, sysfs)) {
- log_unit_debug(u, "Device %s appeared twice with different sysfs paths %s and %s", e, DEVICE(u)->sysfs, sysfs);
- return -EEXIST;
+ /* The device unit can still be present even if the device was
+ * unplugged: a mount unit can reference it hence preventing
+ * the GC to have garbaged it. That's desired since the device
+ * unit may have a dependency on the mount unit which was
+ * added during the loading of the later. */
+ if (u && DEVICE(u)->state == DEVICE_PLUGGED) {
+ /* This unit is in plugged state: we're sure it's
+ * attached to a device. */
+ if (!path_equal(DEVICE(u)->sysfs, sysfs)) {
+ log_unit_error(u, "Dev %s appeared twice with different sysfs paths %s and %s",
+ e, DEVICE(u)->sysfs, sysfs);
+ return -EEXIST;
+ }
}
if (!u) {
diff --git a/src/core/execute.c b/src/core/execute.c
index 9b76861919..80db62131c 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -183,26 +183,41 @@ static int flags_fds(const int fds[], unsigned n_fds, bool nonblock) {
return 0;
}
-_pure_ static const char *tty_path(const ExecContext *context) {
+static const char *exec_context_tty_path(const ExecContext *context) {
assert(context);
+ if (context->stdio_as_fds)
+ return NULL;
+
if (context->tty_path)
return context->tty_path;
return "/dev/console";
}
-static void exec_context_tty_reset(const ExecContext *context) {
+static void exec_context_tty_reset(const ExecContext *context, const ExecParameters *p) {
+ const char *path;
+
assert(context);
- if (context->tty_vhangup)
- terminal_vhangup(tty_path(context));
+ path = exec_context_tty_path(context);
- if (context->tty_reset)
- reset_terminal(tty_path(context));
+ if (context->tty_vhangup) {
+ if (p && p->stdin_fd >= 0)
+ (void) terminal_vhangup_fd(p->stdin_fd);
+ else if (path)
+ (void) terminal_vhangup(path);
+ }
+
+ if (context->tty_reset) {
+ if (p && p->stdin_fd >= 0)
+ (void) reset_terminal_fd(p->stdin_fd, true);
+ else if (path)
+ (void) reset_terminal(path);
+ }
- if (context->tty_vt_disallocate && context->tty_path)
- vt_disallocate(context->tty_path);
+ if (context->tty_vt_disallocate && path)
+ (void) vt_disallocate(path);
}
static bool is_terminal_output(ExecOutput o) {
@@ -400,7 +415,7 @@ static int setup_input(
case EXEC_INPUT_TTY_FAIL: {
int fd, r;
- fd = acquire_terminal(tty_path(context),
+ fd = acquire_terminal(exec_context_tty_path(context),
i == EXEC_INPUT_TTY_FAIL,
i == EXEC_INPUT_TTY_FORCE,
false,
@@ -485,7 +500,7 @@ static int setup_output(
} else if (o == EXEC_OUTPUT_INHERIT) {
/* If input got downgraded, inherit the original value */
if (i == EXEC_INPUT_NULL && is_terminal_input(context->std_input))
- return open_terminal_as(tty_path(context), O_WRONLY, fileno);
+ return open_terminal_as(exec_context_tty_path(context), O_WRONLY, fileno);
/* If the input is connected to anything that's not a /dev/null, inherit that... */
if (i != EXEC_INPUT_NULL)
@@ -509,7 +524,7 @@ static int setup_output(
return dup2(STDIN_FILENO, fileno) < 0 ? -errno : fileno;
/* We don't reset the terminal if this is just about output */
- return open_terminal_as(tty_path(context), O_WRONLY, fileno);
+ return open_terminal_as(exec_context_tty_path(context), O_WRONLY, fileno);
case EXEC_OUTPUT_SYSLOG:
case EXEC_OUTPUT_SYSLOG_AND_CONSOLE:
@@ -737,12 +752,7 @@ static int enforce_user(const ExecContext *context, uid_t uid) {
/* Sets (but doesn't lookup) the uid and make sure we keep the
* capabilities while doing so. */
- if (context->capabilities) {
- _cleanup_cap_free_ cap_t d = NULL;
- static const cap_value_t bits[] = {
- CAP_SETUID, /* Necessary so that we can run setresuid() below */
- CAP_SETPCAP /* Necessary so that we can set PR_SET_SECUREBITS later on */
- };
+ if (context->capabilities || context->capability_ambient_set != 0) {
/* First step: If we need to keep capabilities but
* drop privileges we need to make sure we keep our
@@ -758,16 +768,24 @@ static int enforce_user(const ExecContext *context, uid_t uid) {
/* Second step: set the capabilities. This will reduce
* the capabilities to the minimum we need. */
- d = cap_dup(context->capabilities);
- if (!d)
- return -errno;
+ if (context->capabilities) {
+ _cleanup_cap_free_ cap_t d = NULL;
+ static const cap_value_t bits[] = {
+ CAP_SETUID, /* Necessary so that we can run setresuid() below */
+ CAP_SETPCAP /* Necessary so that we can set PR_SET_SECUREBITS later on */
+ };
- if (cap_set_flag(d, CAP_EFFECTIVE, ELEMENTSOF(bits), bits, CAP_SET) < 0 ||
- cap_set_flag(d, CAP_PERMITTED, ELEMENTSOF(bits), bits, CAP_SET) < 0)
- return -errno;
+ d = cap_dup(context->capabilities);
+ if (!d)
+ return -errno;
- if (cap_set_proc(d) < 0)
- return -errno;
+ if (cap_set_flag(d, CAP_EFFECTIVE, ELEMENTSOF(bits), bits, CAP_SET) < 0 ||
+ cap_set_flag(d, CAP_PERMITTED, ELEMENTSOF(bits), bits, CAP_SET) < 0)
+ return -errno;
+
+ if (cap_set_proc(d) < 0)
+ return -errno;
+ }
}
/* Third step: actually set the uids */
@@ -811,8 +829,7 @@ static int setup_pam(
_cleanup_(barrier_destroy) Barrier barrier = BARRIER_NULL;
pam_handle_t *handle = NULL;
sigset_t old_ss;
- int pam_code = PAM_SUCCESS;
- int err = 0;
+ int pam_code = PAM_SUCCESS, r;
char **e = NULL;
bool close_session = false;
pid_t pam_pid = 0, parent_pid;
@@ -829,8 +846,8 @@ static int setup_pam(
* daemon. We do things this way to ensure that the main PID
* of the daemon is the one we initially fork()ed. */
- err = barrier_create(&barrier);
- if (err < 0)
+ r = barrier_create(&barrier);
+ if (r < 0)
goto fail;
if (log_get_max_level() < LOG_DEBUG)
@@ -872,12 +889,13 @@ static int setup_pam(
parent_pid = getpid();
pam_pid = fork();
- if (pam_pid < 0)
+ if (pam_pid < 0) {
+ r = -errno;
goto fail;
+ }
if (pam_pid == 0) {
- int sig;
- int r = EXIT_PAM;
+ int sig, ret = EXIT_PAM;
/* The child's job is to reset the PAM session on
* termination */
@@ -942,11 +960,11 @@ static int setup_pam(
goto child_finish;
}
- r = 0;
+ ret = 0;
child_finish:
pam_end(handle, pam_code | flags);
- _exit(r);
+ _exit(ret);
}
barrier_set_role(&barrier, BARRIER_PARENT);
@@ -975,10 +993,9 @@ static int setup_pam(
fail:
if (pam_code != PAM_SUCCESS) {
log_error("PAM failed: %s", pam_strerror(handle, pam_code));
- err = -EPERM; /* PAM errors do not map to errno */
- } else {
- err = log_error_errno(err < 0 ? err : errno, "PAM failed: %m");
- }
+ r = -EPERM; /* PAM errors do not map to errno */
+ } else
+ log_error_errno(r, "PAM failed: %m");
if (handle) {
if (close_session)
@@ -988,15 +1005,9 @@ fail:
}
strv_free(e);
-
closelog();
- if (pam_pid > 1) {
- kill(pam_pid, SIGTERM);
- kill(pam_pid, SIGCONT);
- }
-
- return err;
+ return r;
}
#endif
@@ -1236,9 +1247,8 @@ static void do_idle_pipe_dance(int idle_pipe[4]) {
static int build_environment(
const ExecContext *c,
+ const ExecParameters *p,
unsigned n_fds,
- char ** fd_names,
- usec_t watchdog_usec,
const char *home,
const char *username,
const char *shell,
@@ -1266,7 +1276,7 @@ static int build_environment(
return -ENOMEM;
our_env[n_env++] = x;
- joined = strv_join(fd_names, ":");
+ joined = strv_join(p->fd_names, ":");
if (!joined)
return -ENOMEM;
@@ -1276,12 +1286,12 @@ static int build_environment(
our_env[n_env++] = x;
}
- if (watchdog_usec > 0) {
+ if (p->watchdog_usec > 0) {
if (asprintf(&x, "WATCHDOG_PID="PID_FMT, getpid()) < 0)
return -ENOMEM;
our_env[n_env++] = x;
- if (asprintf(&x, "WATCHDOG_USEC="USEC_FMT, watchdog_usec) < 0)
+ if (asprintf(&x, "WATCHDOG_USEC="USEC_FMT, p->watchdog_usec) < 0)
return -ENOMEM;
our_env[n_env++] = x;
}
@@ -1317,7 +1327,7 @@ static int build_environment(
c->std_error == EXEC_OUTPUT_TTY ||
c->tty_path) {
- x = strdup(default_term_for_tty(tty_path(c)));
+ x = strdup(default_term_for_tty(exec_context_tty_path(c)));
if (!x)
return -ENOMEM;
our_env[n_env++] = x;
@@ -1494,7 +1504,7 @@ static int exec_child(
return -errno;
}
- exec_context_tty_reset(context);
+ exec_context_tty_reset(context, params);
if (params->confirm_spawn) {
char response;
@@ -1856,6 +1866,8 @@ static int exec_child(
if (params->apply_permissions) {
+ int secure_bits = context->secure_bits;
+
for (i = 0; i < _RLIMIT_MAX; i++) {
if (!context->rlimit[i])
continue;
@@ -1866,12 +1878,37 @@ static int exec_child(
}
}
- if (context->capability_bounding_set_drop) {
- r = capability_bounding_set_drop(context->capability_bounding_set_drop, false);
+ if (!cap_test_all(context->capability_bounding_set)) {
+ r = capability_bounding_set_drop(context->capability_bounding_set, false);
+ if (r < 0) {
+ *exit_status = EXIT_CAPABILITIES;
+ return r;
+ }
+ }
+
+ /* This is done before enforce_user, but ambient set
+ * does not survive over setresuid() if keep_caps is not set. */
+ if (context->capability_ambient_set != 0) {
+ r = capability_ambient_set_apply(context->capability_ambient_set, true);
if (r < 0) {
*exit_status = EXIT_CAPABILITIES;
return r;
}
+
+ if (context->capabilities) {
+
+ /* The capabilities in ambient set need to be also in the inherited
+ * set. If they aren't, trying to get them will fail. Add the ambient
+ * set inherited capabilities to the capability set in the context.
+ * This is needed because if capabilities are set (using "Capabilities="
+ * keyword), they will override whatever we set now. */
+
+ r = capability_update_inherited_set(context->capabilities, context->capability_ambient_set);
+ if (r < 0) {
+ *exit_status = EXIT_CAPABILITIES;
+ return r;
+ }
+ }
}
if (context->user) {
@@ -1880,14 +1917,32 @@ static int exec_child(
*exit_status = EXIT_USER;
return r;
}
+ if (context->capability_ambient_set != 0) {
+
+ /* Fix the ambient capabilities after user change. */
+ r = capability_ambient_set_apply(context->capability_ambient_set, false);
+ if (r < 0) {
+ *exit_status = EXIT_CAPABILITIES;
+ return r;
+ }
+
+ /* If we were asked to change user and ambient capabilities
+ * were requested, we had to add keep-caps to the securebits
+ * so that we would maintain the inherited capability set
+ * through the setresuid(). Make sure that the bit is added
+ * also to the context secure_bits so that we don't try to
+ * drop the bit away next. */
+
+ secure_bits |= 1<<SECURE_KEEP_CAPS;
+ }
}
/* PR_GET_SECUREBITS is not privileged, while
* PR_SET_SECUREBITS is. So to suppress
* potential EPERMs we'll try not to call
* PR_SET_SECUREBITS unless necessary. */
- if (prctl(PR_GET_SECUREBITS) != context->secure_bits)
- if (prctl(PR_SET_SECUREBITS, context->secure_bits) < 0) {
+ if (prctl(PR_GET_SECUREBITS) != secure_bits)
+ if (prctl(PR_SET_SECUREBITS, secure_bits) < 0) {
*exit_status = EXIT_SECUREBITS;
return -errno;
}
@@ -1950,7 +2005,7 @@ static int exec_child(
#endif
}
- r = build_environment(context, n_fds, params->fd_names, params->watchdog_usec, home, username, shell, &our_env);
+ r = build_environment(context, params, n_fds, home, username, shell, &our_env);
if (r < 0) {
*exit_status = EXIT_MEMORY;
return r;
@@ -2114,6 +2169,7 @@ void exec_context_init(ExecContext *c) {
c->timer_slack_nsec = NSEC_INFINITY;
c->personality = PERSONALITY_INVALID;
c->runtime_directory_mode = 0755;
+ c->capability_bounding_set = CAP_ALL;
}
void exec_context_done(ExecContext *c) {
@@ -2270,7 +2326,7 @@ int exec_context_load_environment(Unit *unit, const ExecContext *c, char ***l) {
continue;
strv_free(r);
- return errno ? -errno : -EINVAL;
+ return errno > 0 ? -errno : -EINVAL;
}
count = pglob.gl_pathc;
if (count == 0) {
@@ -2324,6 +2380,9 @@ static bool tty_may_match_dev_console(const char *tty) {
_cleanup_free_ char *active = NULL;
char *console;
+ if (!tty)
+ return true;
+
if (startswith(tty, "/dev/"))
tty += 5;
@@ -2341,11 +2400,14 @@ static bool tty_may_match_dev_console(const char *tty) {
}
bool exec_context_may_touch_console(ExecContext *ec) {
- return (ec->tty_reset || ec->tty_vhangup || ec->tty_vt_disallocate ||
+
+ return (ec->tty_reset ||
+ ec->tty_vhangup ||
+ ec->tty_vt_disallocate ||
is_terminal_input(ec->std_input) ||
is_terminal_output(ec->std_output) ||
is_terminal_output(ec->std_error)) &&
- tty_may_match_dev_console(tty_path(ec));
+ tty_may_match_dev_console(exec_context_tty_path(ec));
}
static void strv_fprintf(FILE *f, char **l) {
@@ -2517,12 +2579,23 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
(c->secure_bits & 1<<SECURE_NOROOT) ? " noroot" : "",
(c->secure_bits & 1<<SECURE_NOROOT_LOCKED) ? "noroot-locked" : "");
- if (c->capability_bounding_set_drop) {
+ if (c->capability_bounding_set != CAP_ALL) {
unsigned long l;
fprintf(f, "%sCapabilityBoundingSet:", prefix);
for (l = 0; l <= cap_last_cap(); l++)
- if (!(c->capability_bounding_set_drop & ((uint64_t) 1ULL << (uint64_t) l)))
+ if (c->capability_bounding_set & (UINT64_C(1) << l))
+ fprintf(f, " %s", strna(capability_to_name(l)));
+
+ fputs("\n", f);
+ }
+
+ if (c->capability_ambient_set != 0) {
+ unsigned long l;
+ fprintf(f, "%sAmbientCapabilities:", prefix);
+
+ for (l = 0; l <= cap_last_cap(); l++)
+ if (c->capability_ambient_set & (UINT64_C(1) << l))
fprintf(f, " %s", strna(capability_to_name(l)));
fputs("\n", f);
@@ -2623,7 +2696,7 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
fputc('\n', f);
}
- if (c->syscall_errno != 0)
+ if (c->syscall_errno > 0)
fprintf(f,
"%sSystemCallErrorNumber: %s\n",
prefix, strna(errno_to_name(c->syscall_errno)));
@@ -2673,7 +2746,7 @@ void exec_status_exit(ExecStatus *s, ExecContext *context, pid_t pid, int code,
if (context->utmp_id)
utmp_put_dead_process(context->utmp_id, pid, code, status);
- exec_context_tty_reset(context);
+ exec_context_tty_reset(context, NULL);
}
}
diff --git a/src/core/execute.h b/src/core/execute.h
index be5be9f531..e4b93b603d 100644
--- a/src/core/execute.h
+++ b/src/core/execute.h
@@ -122,6 +122,8 @@ struct ExecContext {
nsec_t timer_slack_nsec;
+ bool stdio_as_fds;
+
char *tty_path;
bool tty_reset;
@@ -155,7 +157,9 @@ struct ExecContext {
char **read_write_dirs, **read_only_dirs, **inaccessible_dirs;
unsigned long mount_flags;
- uint64_t capability_bounding_set_drop;
+ uint64_t capability_bounding_set;
+
+ uint64_t capability_ambient_set;
cap_t capabilities;
int secure_bits;
diff --git a/src/core/job.c b/src/core/job.c
index 9654590635..b1737c8110 100644
--- a/src/core/job.c
+++ b/src/core/job.c
@@ -35,6 +35,7 @@
#include "parse-util.h"
#include "set.h"
#include "special.h"
+#include "stdio-util.h"
#include "string-table.h"
#include "string-util.h"
#include "strv.h"
@@ -404,6 +405,13 @@ JobType job_type_collapse(JobType t, Unit *u) {
return JOB_RESTART;
+ case JOB_TRY_RELOAD:
+ s = unit_active_state(u);
+ if (UNIT_IS_INACTIVE_OR_DEACTIVATING(s))
+ return JOB_NOP;
+
+ return JOB_RELOAD;
+
case JOB_RELOAD_OR_START:
s = unit_active_state(u);
if (UNIT_IS_INACTIVE_OR_DEACTIVATING(s))
@@ -754,7 +762,7 @@ static void job_log_status_message(Unit *u, JobType t, JobResult result) {
return;
DISABLE_WARNING_FORMAT_NONLITERAL;
- snprintf(buf, sizeof(buf), format, unit_description(u));
+ xsprintf(buf, format, unit_description(u));
REENABLE_WARNING;
switch (t) {
@@ -924,14 +932,14 @@ int job_start_timer(Job *j) {
j->begin_usec = now(CLOCK_MONOTONIC);
- if (j->unit->job_timeout <= 0)
+ if (j->unit->job_timeout == USEC_INFINITY)
return 0;
r = sd_event_add_time(
j->manager->event,
&j->timer_event_source,
CLOCK_MONOTONIC,
- j->begin_usec + j->unit->job_timeout, 0,
+ usec_add(j->begin_usec, j->unit->job_timeout), 0,
job_dispatch_timer, j);
if (r < 0)
return r;
@@ -1109,17 +1117,16 @@ int job_coldplug(Job *j) {
if (j->state == JOB_WAITING)
job_add_to_run_queue(j);
- if (j->begin_usec == 0 || j->unit->job_timeout == 0)
+ if (j->begin_usec == 0 || j->unit->job_timeout == USEC_INFINITY)
return 0;
- if (j->timer_event_source)
- j->timer_event_source = sd_event_source_unref(j->timer_event_source);
+ j->timer_event_source = sd_event_source_unref(j->timer_event_source);
r = sd_event_add_time(
j->manager->event,
&j->timer_event_source,
CLOCK_MONOTONIC,
- j->begin_usec + j->unit->job_timeout, 0,
+ usec_add(j->begin_usec, j->unit->job_timeout), 0,
job_dispatch_timer, j);
if (r < 0)
log_debug_errno(r, "Failed to restart timeout for job: %m");
@@ -1158,10 +1165,10 @@ void job_shutdown_magic(Job *j) {
asynchronous_sync();
}
-int job_get_timeout(Job *j, uint64_t *timeout) {
+int job_get_timeout(Job *j, usec_t *timeout) {
+ usec_t x = USEC_INFINITY, y = USEC_INFINITY;
Unit *u = j->unit;
- uint64_t x = -1, y = -1;
- int r = 0, q = 0;
+ int r;
assert(u);
@@ -1169,20 +1176,18 @@ int job_get_timeout(Job *j, uint64_t *timeout) {
r = sd_event_source_get_time(j->timer_event_source, &x);
if (r < 0)
return r;
- r = 1;
}
if (UNIT_VTABLE(u)->get_timeout) {
- q = UNIT_VTABLE(u)->get_timeout(u, &y);
- if (q < 0)
- return q;
+ r = UNIT_VTABLE(u)->get_timeout(u, &y);
+ if (r < 0)
+ return r;
}
- if (r == 0 && q == 0)
+ if (x == USEC_INFINITY && y == USEC_INFINITY)
return 0;
*timeout = MIN(x, y);
-
return 1;
}
@@ -1201,6 +1206,7 @@ static const char* const job_type_table[_JOB_TYPE_MAX] = {
[JOB_RELOAD_OR_START] = "reload-or-start",
[JOB_RESTART] = "restart",
[JOB_TRY_RESTART] = "try-restart",
+ [JOB_TRY_RELOAD] = "try-reload",
[JOB_NOP] = "nop",
};
@@ -1231,3 +1237,15 @@ static const char* const job_result_table[_JOB_RESULT_MAX] = {
};
DEFINE_STRING_TABLE_LOOKUP(job_result, JobResult);
+
+const char* job_type_to_access_method(JobType t) {
+ assert(t >= 0);
+ assert(t < _JOB_TYPE_MAX);
+
+ if (IN_SET(t, JOB_START, JOB_RESTART, JOB_TRY_RESTART))
+ return "start";
+ else if (t == JOB_STOP)
+ return "stop";
+ else
+ return "reload";
+}
diff --git a/src/core/job.h b/src/core/job.h
index 118b24e5b7..4c19ad0c6a 100644
--- a/src/core/job.h
+++ b/src/core/job.h
@@ -66,6 +66,9 @@ enum JobType {
* Thus we never need to merge it with anything. */
JOB_TRY_RESTART = _JOB_TYPE_MAX_IN_TRANSACTION, /* if running, stop and then start */
+ /* Similar to JOB_TRY_RESTART but collapses to JOB_RELOAD or JOB_NOP */
+ JOB_TRY_RELOAD,
+
/* JOB_RELOAD_OR_START won't enter into a transaction and cannot result
* from transaction merging (there's no way for JOB_RELOAD and
* JOB_START to meet in one transaction). It can result from a merge
@@ -224,6 +227,8 @@ char *job_dbus_path(Job *j);
void job_shutdown_magic(Job *j);
+int job_get_timeout(Job *j, usec_t *timeout) _pure_;
+
const char* job_type_to_string(JobType t) _const_;
JobType job_type_from_string(const char *s) _pure_;
@@ -236,4 +241,4 @@ JobMode job_mode_from_string(const char *s) _pure_;
const char* job_result_to_string(JobResult t) _const_;
JobResult job_result_from_string(const char *s) _pure_;
-int job_get_timeout(Job *j, uint64_t *timeout) _pure_;
+const char* job_type_to_access_method(JobType t);
diff --git a/src/core/killall.c b/src/core/killall.c
index 77f145b4d1..d0c7c89670 100644
--- a/src/core/killall.c
+++ b/src/core/killall.c
@@ -37,7 +37,7 @@
#define TIMEOUT_USEC (10 * USEC_PER_SEC)
-static bool ignore_proc(pid_t pid) {
+static bool ignore_proc(pid_t pid, bool warn_rootfs) {
_cleanup_fclose_ FILE *f = NULL;
char c;
const char *p;
@@ -72,7 +72,22 @@ static bool ignore_proc(pid_t pid) {
* spree.
*
* http://www.freedesktop.org/wiki/Software/systemd/RootStorageDaemons */
- if (count == 1 && c == '@')
+ if (c == '@' && warn_rootfs) {
+ _cleanup_free_ char *comm = NULL;
+
+ r = pid_from_same_root_fs(pid);
+ if (r < 0)
+ return true;
+
+ get_process_comm(pid, &comm);
+
+ if (r)
+ log_notice("Process " PID_FMT " (%s) has been been marked to be excluded from killing. It is "
+ "running from the root file system, and thus likely to block re-mounting of the "
+ "root file system to read-only. Please consider moving it into an initrd file "
+ "system instead.", pid, strna(comm));
+ return true;
+ } else if (c == '@')
return true;
return false;
@@ -171,7 +186,7 @@ static int killall(int sig, Set *pids, bool send_sighup) {
if (parse_pid(d->d_name, &pid) < 0)
continue;
- if (ignore_proc(pid))
+ if (ignore_proc(pid, sig == SIGKILL && !in_initrd()))
continue;
if (sig == SIGKILL) {
diff --git a/src/core/load-dropin.c b/src/core/load-dropin.c
index 3fa66f91aa..569632e13b 100644
--- a/src/core/load-dropin.c
+++ b/src/core/load-dropin.c
@@ -65,6 +65,7 @@ int unit_load_dropin(Unit *u) {
}
}
+ u->dropin_paths = strv_free(u->dropin_paths);
r = unit_find_dropin_paths(u, &u->dropin_paths);
if (r <= 0)
return 0;
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
index 0408b9a829..2507db1932 100644
--- a/src/core/load-fragment-gperf.gperf.m4
+++ b/src/core/load-fragment-gperf.gperf.m4
@@ -47,7 +47,8 @@ $1.SyslogLevel, config_parse_log_level, 0,
$1.SyslogLevelPrefix, config_parse_bool, 0, offsetof($1, exec_context.syslog_level_prefix)
$1.Capabilities, config_parse_exec_capabilities, 0, offsetof($1, exec_context)
$1.SecureBits, config_parse_exec_secure_bits, 0, offsetof($1, exec_context)
-$1.CapabilityBoundingSet, config_parse_bounding_set, 0, offsetof($1, exec_context.capability_bounding_set_drop)
+$1.CapabilityBoundingSet, config_parse_capability_set, 0, offsetof($1, exec_context.capability_bounding_set)
+$1.AmbientCapabilities, config_parse_capability_set, 0, offsetof($1, exec_context.capability_ambient_set)
$1.TimerSlackNSec, config_parse_nsec, 0, offsetof($1, exec_context.timer_slack_nsec)
$1.NoNewPrivileges, config_parse_no_new_privileges, 0, offsetof($1, exec_context)
m4_ifdef(`HAVE_SECCOMP',
@@ -59,22 +60,22 @@ $1.RestrictAddressFamilies, config_parse_address_families, 0,
$1.SystemCallArchitectures, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
$1.SystemCallErrorNumber, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
$1.RestrictAddressFamilies, config_parse_warn_compat, DISABLED_CONFIGURATION, 0')
-$1.LimitCPU, config_parse_sec_limit, RLIMIT_CPU, offsetof($1, exec_context.rlimit)
-$1.LimitFSIZE, config_parse_bytes_limit, RLIMIT_FSIZE, offsetof($1, exec_context.rlimit)
-$1.LimitDATA, config_parse_bytes_limit, RLIMIT_DATA, offsetof($1, exec_context.rlimit)
-$1.LimitSTACK, config_parse_bytes_limit, RLIMIT_STACK, offsetof($1, exec_context.rlimit)
-$1.LimitCORE, config_parse_bytes_limit, RLIMIT_CORE, offsetof($1, exec_context.rlimit)
-$1.LimitRSS, config_parse_bytes_limit, RLIMIT_RSS, offsetof($1, exec_context.rlimit)
+$1.LimitCPU, config_parse_limit, RLIMIT_CPU, offsetof($1, exec_context.rlimit)
+$1.LimitFSIZE, config_parse_limit, RLIMIT_FSIZE, offsetof($1, exec_context.rlimit)
+$1.LimitDATA, config_parse_limit, RLIMIT_DATA, offsetof($1, exec_context.rlimit)
+$1.LimitSTACK, config_parse_limit, RLIMIT_STACK, offsetof($1, exec_context.rlimit)
+$1.LimitCORE, config_parse_limit, RLIMIT_CORE, offsetof($1, exec_context.rlimit)
+$1.LimitRSS, config_parse_limit, RLIMIT_RSS, offsetof($1, exec_context.rlimit)
$1.LimitNOFILE, config_parse_limit, RLIMIT_NOFILE, offsetof($1, exec_context.rlimit)
-$1.LimitAS, config_parse_bytes_limit, RLIMIT_AS, offsetof($1, exec_context.rlimit)
+$1.LimitAS, config_parse_limit, RLIMIT_AS, offsetof($1, exec_context.rlimit)
$1.LimitNPROC, config_parse_limit, RLIMIT_NPROC, offsetof($1, exec_context.rlimit)
-$1.LimitMEMLOCK, config_parse_bytes_limit, RLIMIT_MEMLOCK, offsetof($1, exec_context.rlimit)
+$1.LimitMEMLOCK, config_parse_limit, RLIMIT_MEMLOCK, offsetof($1, exec_context.rlimit)
$1.LimitLOCKS, config_parse_limit, RLIMIT_LOCKS, offsetof($1, exec_context.rlimit)
$1.LimitSIGPENDING, config_parse_limit, RLIMIT_SIGPENDING, offsetof($1, exec_context.rlimit)
-$1.LimitMSGQUEUE, config_parse_bytes_limit, RLIMIT_MSGQUEUE, offsetof($1, exec_context.rlimit)
+$1.LimitMSGQUEUE, config_parse_limit, RLIMIT_MSGQUEUE, offsetof($1, exec_context.rlimit)
$1.LimitNICE, config_parse_limit, RLIMIT_NICE, offsetof($1, exec_context.rlimit)
$1.LimitRTPRIO, config_parse_limit, RLIMIT_RTPRIO, offsetof($1, exec_context.rlimit)
-$1.LimitRTTIME, config_parse_usec_limit, RLIMIT_RTTIME, offsetof($1, exec_context.rlimit)
+$1.LimitRTTIME, config_parse_limit, RLIMIT_RTTIME, offsetof($1, exec_context.rlimit)
$1.ReadWriteDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_write_dirs)
$1.ReadOnlyDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_only_dirs)
$1.InaccessibleDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.inaccessible_dirs)
@@ -213,6 +214,7 @@ Service.RestartSec, config_parse_sec, 0,
Service.TimeoutSec, config_parse_service_timeout, 0, offsetof(Service, timeout_start_usec)
Service.TimeoutStartSec, config_parse_service_timeout, 0, offsetof(Service, timeout_start_usec)
Service.TimeoutStopSec, config_parse_service_timeout, 0, offsetof(Service, timeout_stop_usec)
+Service.RuntimeMaxSec, config_parse_sec, 0, offsetof(Service, runtime_max_usec)
Service.WatchdogSec, config_parse_sec, 0, offsetof(Service, watchdog_usec)
Service.StartLimitInterval, config_parse_sec, 0, offsetof(Service, start_limit.interval)
Service.StartLimitBurst, config_parse_unsigned, 0, offsetof(Service, start_limit.burst)
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index cb553e1252..3b37cc4cda 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -38,6 +38,7 @@
#include "bus-internal.h"
#include "bus-util.h"
#include "cap-list.h"
+#include "capability-util.h"
#include "cgroup.h"
#include "conf-parser.h"
#include "cpu-set-util.h"
@@ -53,6 +54,7 @@
#include "parse-util.h"
#include "path-util.h"
#include "process-util.h"
+#include "rlimit-util.h"
#ifdef HAVE_SECCOMP
#include "seccomp-util.h"
#endif
@@ -574,7 +576,9 @@ int config_parse_exec(
void *data,
void *userdata) {
+ _cleanup_free_ char *cmd = NULL;
ExecCommand **e = data;
+ Unit *u = userdata;
const char *p;
bool semicolon;
int r;
@@ -583,6 +587,7 @@ int config_parse_exec(
assert(lvalue);
assert(rvalue);
assert(e);
+ assert(u);
e += ltype;
rvalue += strspn(rvalue, WHITESPACE);
@@ -593,7 +598,13 @@ int config_parse_exec(
return 0;
}
- p = rvalue;
+ r = unit_full_printf(u, rvalue, &cmd);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
+ return 0;
+ }
+
+ p = cmd;
do {
_cleanup_free_ char *path = NULL, *firstword = NULL;
bool separate_argv0 = false, ignore = false;
@@ -1024,7 +1035,7 @@ int config_parse_exec_secure_bits(const char *unit,
return 0;
}
-int config_parse_bounding_set(
+int config_parse_capability_set(
const char *unit,
const char *filename,
unsigned line,
@@ -1036,8 +1047,8 @@ int config_parse_bounding_set(
void *data,
void *userdata) {
- uint64_t *capability_bounding_set_drop = data;
- uint64_t capability_bounding_set, sum = 0;
+ uint64_t *capability_set = data;
+ uint64_t sum = 0, initial = 0;
bool invert = false;
const char *p;
@@ -1051,10 +1062,9 @@ int config_parse_bounding_set(
rvalue++;
}
- /* Note that we store this inverted internally, since the
- * kernel wants it like this. But we actually expose it
- * non-inverted everywhere to have a fully normalized
- * interface. */
+ if (strcmp(lvalue, "CapabilityBoundingSet") == 0)
+ initial = CAP_ALL; /* initialized to all bits on */
+ /* else "AmbientCapabilities" initialized to all bits off */
p = rvalue;
for (;;) {
@@ -1073,135 +1083,22 @@ int config_parse_bounding_set(
cap = capability_from_name(word);
if (cap < 0) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse capability in bounding set, ignoring: %s", word);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse capability in bounding/ambient set, ignoring: %s", word);
continue;
}
sum |= ((uint64_t) UINT64_C(1)) << (uint64_t) cap;
}
- capability_bounding_set = invert ? ~sum : sum;
- if (*capability_bounding_set_drop != 0 && capability_bounding_set != 0)
- *capability_bounding_set_drop = ~(~*capability_bounding_set_drop | capability_bounding_set);
- else
- *capability_bounding_set_drop = ~capability_bounding_set;
-
- return 0;
-}
-
-static int rlim_parse_u64(const char *val, rlim_t *res) {
- int r = 0;
-
- if (streq(val, "infinity"))
- *res = RLIM_INFINITY;
- else {
- uint64_t u;
-
- /* setrlimit(2) suggests rlim_t is always 64bit on Linux. */
- assert_cc(sizeof(rlim_t) == sizeof(uint64_t));
-
- r = safe_atou64(val, &u);
- if (r >= 0 && u >= (uint64_t) RLIM_INFINITY)
- r = -ERANGE;
- if (r == 0)
- *res = (rlim_t) u;
- }
- return r;
-}
-
-static int rlim_parse_size(const char *val, rlim_t *res) {
- int r = 0;
-
- if (streq(val, "infinity"))
- *res = RLIM_INFINITY;
- else {
- uint64_t u;
-
- r = parse_size(val, 1024, &u);
- if (r >= 0 && u >= (uint64_t) RLIM_INFINITY)
- r = -ERANGE;
- if (r == 0)
- *res = (rlim_t) u;
- }
- return r;
-}
-
-static int rlim_parse_sec(const char *val, rlim_t *res) {
- int r = 0;
-
- if (streq(val, "infinity"))
- *res = RLIM_INFINITY;
- else {
- usec_t t;
-
- r = parse_sec(val, &t);
- if (r < 0)
- return r;
- if (t == USEC_INFINITY)
- *res = RLIM_INFINITY;
- else
- *res = (rlim_t) (DIV_ROUND_UP(t, USEC_PER_SEC));
-
- }
- return r;
-}
-
-static int rlim_parse_usec(const char *val, rlim_t *res) {
- int r = 0;
-
- if (streq(val, "infinity"))
- *res = RLIM_INFINITY;
- else {
- usec_t t;
-
- r = parse_time(val, &t, 1);
- if (r < 0)
- return r;
- if (t == USEC_INFINITY)
- *res = RLIM_INFINITY;
- else
- *res = (rlim_t) t;
- }
- return r;
-}
+ sum = invert ? ~sum : sum;
-static int parse_rlimit_range(
- const char *unit,
- const char *filename,
- unsigned line,
- const char *value,
- struct rlimit **rl,
- int (*rlim_parser)(const char *, rlim_t *)) {
-
- const char *whole_value = value;
- rlim_t soft, hard;
- _cleanup_free_ char *sword = NULL, *hword = NULL;
- int nwords, r;
-
- assert(value);
-
- /* <value> or <soft:hard> */
- nwords = extract_many_words(&value, ":", EXTRACT_DONT_COALESCE_SEPARATORS, &sword, &hword, NULL);
- r = nwords < 0 ? nwords : nwords == 0 ? -EINVAL : 0;
-
- if (r == 0)
- r = rlim_parser(sword, &soft);
- if (r == 0 && nwords == 2)
- r = rlim_parser(hword, &hard);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", whole_value);
- return 0;
- }
- if (nwords == 2 && soft > hard)
- return log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid resource value ("RLIM_FMT" > "RLIM_FMT"), ignoring: %s", soft, hard, whole_value);
+ if (sum == 0 || *capability_set == initial)
+ /* "" or uninitialized data -> replace */
+ *capability_set = sum;
+ else
+ /* previous data -> merge */
+ *capability_set |= sum;
- if (!*rl) {
- *rl = new(struct rlimit, 1);
- if (!*rl)
- return log_oom();
- }
- (*rl)->rlim_cur = soft;
- (*rl)->rlim_max = nwords == 2 ? hard : soft;
return 0;
}
@@ -1217,88 +1114,35 @@ int config_parse_limit(
void *data,
void *userdata) {
- struct rlimit **rl = data;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- rl += ltype;
- return parse_rlimit_range(unit, filename, line, rvalue, rl, rlim_parse_u64);
-}
-
-int config_parse_bytes_limit(
- const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- struct rlimit **rl = data;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- rl += ltype;
- return parse_rlimit_range(unit, filename, line, rvalue, rl, rlim_parse_size);
-}
-
-int config_parse_sec_limit(
- const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- struct rlimit **rl = data;
+ struct rlimit **rl = data, d = {};
+ int r;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
- rl += ltype;
- return parse_rlimit_range(unit, filename, line, rvalue, rl, rlim_parse_sec);
-}
-
-int config_parse_usec_limit(
- const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- struct rlimit **rl = data;
+ r = rlimit_parse(ltype, rvalue, &d);
+ if (r == -EILSEQ) {
+ log_syntax(unit, LOG_WARNING, filename, line, r, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue);
+ return 0;
+ }
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
+ return 0;
+ }
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
+ if (rl[ltype])
+ *rl[ltype] = d;
+ else {
+ rl[ltype] = newdup(struct rlimit, &d, 1);
+ if (!rl[ltype])
+ return log_oom();
+ }
- rl += ltype;
- return parse_rlimit_range(unit, filename, line, rvalue, rl, rlim_parse_usec);
+ return 0;
}
-
-
#ifdef HAVE_SYSV_COMPAT
int config_parse_sysv_priority(const char *unit,
const char *filename,
@@ -1899,6 +1743,15 @@ int config_parse_service_timeout(const char *unit,
} else if (streq(lvalue, "TimeoutStartSec"))
s->start_timeout_defined = true;
+ /* Traditionally, these options accepted 0 to disable the timeouts. However, a timeout of 0 suggests it happens
+ * immediately, hence fix this to become USEC_INFINITY instead. This is in-line with how we internally handle
+ * all other timeouts. */
+
+ if (s->timeout_start_usec <= 0)
+ s->timeout_start_usec = USEC_INFINITY;
+ if (s->timeout_stop_usec <= 0)
+ s->timeout_stop_usec = USEC_INFINITY;
+
return 0;
}
@@ -4002,7 +3855,7 @@ void unit_dump_config_items(FILE *f) {
{ config_parse_log_level, "LEVEL" },
{ config_parse_exec_capabilities, "CAPABILITIES" },
{ config_parse_exec_secure_bits, "SECUREBITS" },
- { config_parse_bounding_set, "BOUNDINGSET" },
+ { config_parse_capability_set, "BOUNDINGSET" },
{ config_parse_limit, "LIMIT" },
{ config_parse_unit_deps, "UNIT [...]" },
{ config_parse_exec, "PATH [ARGUMENT [...]]" },
diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h
index a451fc164a..20dd84ba95 100644
--- a/src/core/load-fragment.h
+++ b/src/core/load-fragment.h
@@ -56,11 +56,8 @@ int config_parse_exec_cpu_sched_prio(const char *unit, const char *filename, uns
int config_parse_exec_cpu_affinity(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_exec_capabilities(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_exec_secure_bits(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_bounding_set(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_capability_set(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_bytes_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_sec_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_usec_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_sysv_priority(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_kill_signal(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_exec_mount_flags(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
diff --git a/src/core/machine-id-setup.c b/src/core/machine-id-setup.c
index 145ba2a28d..09b0449c80 100644
--- a/src/core/machine-id-setup.c
+++ b/src/core/machine-id-setup.c
@@ -198,7 +198,7 @@ static int generate_machine_id(char id[34], const char *root) {
return 0;
}
-int machine_id_setup(const char *root) {
+int machine_id_setup(const char *root, sd_id128_t machine_id) {
const char *etc_machine_id, *run_machine_id;
_cleanup_close_ int fd = -1;
bool writable = true;
@@ -248,15 +248,22 @@ int machine_id_setup(const char *root) {
}
}
- if (read_machine_id(fd, id) >= 0)
- return 0;
+ /* A machine id argument overrides all other machined-ids */
+ if (!sd_id128_is_null(machine_id)) {
+ sd_id128_to_string(machine_id, id);
+ id[32] = '\n';
+ id[33] = 0;
+ } else {
+ if (read_machine_id(fd, id) >= 0)
+ return 0;
- /* Hmm, so, the id currently stored is not useful, then let's
- * generate one */
+ /* Hmm, so, the id currently stored is not useful, then let's
+ * generate one */
- r = generate_machine_id(id, root);
- if (r < 0)
- return r;
+ r = generate_machine_id(id, root);
+ if (r < 0)
+ return r;
+ }
if (writable)
if (write_machine_id(fd, id) >= 0)
diff --git a/src/core/machine-id-setup.h b/src/core/machine-id-setup.h
index f7707c3bf9..a2168a8d4a 100644
--- a/src/core/machine-id-setup.h
+++ b/src/core/machine-id-setup.h
@@ -22,4 +22,4 @@
***/
int machine_id_commit(const char *root);
-int machine_id_setup(const char *root);
+int machine_id_setup(const char *root, sd_id128_t machine_id);
diff --git a/src/core/main.c b/src/core/main.c
index f9de54028e..fb27e897e4 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -117,7 +117,7 @@ static usec_t arg_runtime_watchdog = 0;
static usec_t arg_shutdown_watchdog = 10 * USEC_PER_MINUTE;
static char **arg_default_environment = NULL;
static struct rlimit *arg_default_rlimit[_RLIMIT_MAX] = {};
-static uint64_t arg_capability_bounding_set_drop = 0;
+static uint64_t arg_capability_bounding_set = CAP_ALL;
static nsec_t arg_timer_slack_nsec = NSEC_INFINITY;
static usec_t arg_default_timer_accuracy_usec = 1 * USEC_PER_MINUTE;
static Set* arg_syscall_archs = NULL;
@@ -127,6 +127,7 @@ static bool arg_default_blockio_accounting = false;
static bool arg_default_memory_accounting = false;
static bool arg_default_tasks_accounting = true;
static uint64_t arg_default_tasks_max = UINT64_C(512);
+static sd_id128_t arg_machine_id = {};
static void pager_open_if_enabled(void) {
@@ -300,6 +301,17 @@ static int parse_crash_chvt(const char *value) {
return 0;
}
+static int set_machine_id(const char *m) {
+
+ if (sd_id128_from_string(m, &arg_machine_id) < 0)
+ return -EINVAL;
+
+ if (sd_id128_is_null(arg_machine_id))
+ return -EINVAL;
+
+ return 0;
+}
+
static int parse_proc_cmdline_item(const char *key, const char *value) {
int r;
@@ -388,6 +400,12 @@ static int parse_proc_cmdline_item(const char *key, const char *value) {
} else
log_warning("Environment variable name '%s' is not valid. Ignoring.", value);
+ } else if (streq(key, "systemd.machine_id") && value) {
+
+ r = set_machine_id(value);
+ if (r < 0)
+ log_warning("MachineID '%s' is not valid. Ignoring.", value);
+
} else if (streq(key, "quiet") && !value) {
if (arg_show_status == _SHOW_STATUS_UNSET)
@@ -644,7 +662,7 @@ static int parse_config_file(void) {
{ "Manager", "JoinControllers", config_parse_join_controllers, 0, &arg_join_controllers },
{ "Manager", "RuntimeWatchdogSec", config_parse_sec, 0, &arg_runtime_watchdog },
{ "Manager", "ShutdownWatchdogSec", config_parse_sec, 0, &arg_shutdown_watchdog },
- { "Manager", "CapabilityBoundingSet", config_parse_bounding_set, 0, &arg_capability_bounding_set_drop },
+ { "Manager", "CapabilityBoundingSet", config_parse_capability_set, 0, &arg_capability_bounding_set },
#ifdef HAVE_SECCOMP
{ "Manager", "SystemCallArchitectures", config_parse_syscall_archs, 0, &arg_syscall_archs },
#endif
@@ -658,22 +676,22 @@ static int parse_config_file(void) {
{ "Manager", "DefaultStartLimitInterval", config_parse_sec, 0, &arg_default_start_limit_interval },
{ "Manager", "DefaultStartLimitBurst", config_parse_unsigned, 0, &arg_default_start_limit_burst },
{ "Manager", "DefaultEnvironment", config_parse_environ, 0, &arg_default_environment },
- { "Manager", "DefaultLimitCPU", config_parse_sec_limit, 0, &arg_default_rlimit[RLIMIT_CPU] },
- { "Manager", "DefaultLimitFSIZE", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_FSIZE] },
- { "Manager", "DefaultLimitDATA", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_DATA] },
- { "Manager", "DefaultLimitSTACK", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_STACK] },
- { "Manager", "DefaultLimitCORE", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_CORE] },
- { "Manager", "DefaultLimitRSS", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_RSS] },
- { "Manager", "DefaultLimitNOFILE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_NOFILE] },
- { "Manager", "DefaultLimitAS", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_AS] },
- { "Manager", "DefaultLimitNPROC", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_NPROC] },
- { "Manager", "DefaultLimitMEMLOCK", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_MEMLOCK] },
- { "Manager", "DefaultLimitLOCKS", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_LOCKS] },
- { "Manager", "DefaultLimitSIGPENDING", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_SIGPENDING] },
- { "Manager", "DefaultLimitMSGQUEUE", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_MSGQUEUE] },
- { "Manager", "DefaultLimitNICE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_NICE] },
- { "Manager", "DefaultLimitRTPRIO", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_RTPRIO] },
- { "Manager", "DefaultLimitRTTIME", config_parse_usec_limit, 0, &arg_default_rlimit[RLIMIT_RTTIME] },
+ { "Manager", "DefaultLimitCPU", config_parse_limit, RLIMIT_CPU, arg_default_rlimit },
+ { "Manager", "DefaultLimitFSIZE", config_parse_limit, RLIMIT_FSIZE, arg_default_rlimit },
+ { "Manager", "DefaultLimitDATA", config_parse_limit, RLIMIT_DATA, arg_default_rlimit },
+ { "Manager", "DefaultLimitSTACK", config_parse_limit, RLIMIT_STACK, arg_default_rlimit },
+ { "Manager", "DefaultLimitCORE", config_parse_limit, RLIMIT_CORE, arg_default_rlimit },
+ { "Manager", "DefaultLimitRSS", config_parse_limit, RLIMIT_RSS, arg_default_rlimit },
+ { "Manager", "DefaultLimitNOFILE", config_parse_limit, RLIMIT_NOFILE, arg_default_rlimit },
+ { "Manager", "DefaultLimitAS", config_parse_limit, RLIMIT_AS, arg_default_rlimit },
+ { "Manager", "DefaultLimitNPROC", config_parse_limit, RLIMIT_NPROC, arg_default_rlimit },
+ { "Manager", "DefaultLimitMEMLOCK", config_parse_limit, RLIMIT_MEMLOCK, arg_default_rlimit },
+ { "Manager", "DefaultLimitLOCKS", config_parse_limit, RLIMIT_LOCKS, arg_default_rlimit },
+ { "Manager", "DefaultLimitSIGPENDING", config_parse_limit, RLIMIT_SIGPENDING, arg_default_rlimit },
+ { "Manager", "DefaultLimitMSGQUEUE", config_parse_limit, RLIMIT_MSGQUEUE, arg_default_rlimit },
+ { "Manager", "DefaultLimitNICE", config_parse_limit, RLIMIT_NICE, arg_default_rlimit },
+ { "Manager", "DefaultLimitRTPRIO", config_parse_limit, RLIMIT_RTPRIO, arg_default_rlimit },
+ { "Manager", "DefaultLimitRTTIME", config_parse_limit, RLIMIT_RTTIME, arg_default_rlimit },
{ "Manager", "DefaultCPUAccounting", config_parse_bool, 0, &arg_default_cpu_accounting },
{ "Manager", "DefaultBlockIOAccounting", config_parse_bool, 0, &arg_default_blockio_accounting },
{ "Manager", "DefaultMemoryAccounting", config_parse_bool, 0, &arg_default_memory_accounting },
@@ -692,8 +710,14 @@ static int parse_config_file(void) {
CONF_PATHS_NULSTR("systemd/system.conf.d") :
CONF_PATHS_NULSTR("systemd/user.conf.d");
- config_parse_many(fn, conf_dirs_nulstr, "Manager\0",
- config_item_table_lookup, items, false, NULL);
+ config_parse_many(fn, conf_dirs_nulstr, "Manager\0", config_item_table_lookup, items, false, NULL);
+
+ /* Traditionally "0" was used to turn off the default unit timeouts. Fix this up so that we used USEC_INFINITY
+ * like everywhere else. */
+ if (arg_default_timeout_start_usec <= 0)
+ arg_default_timeout_start_usec = USEC_INFINITY;
+ if (arg_default_timeout_stop_usec <= 0)
+ arg_default_timeout_stop_usec = USEC_INFINITY;
return 0;
}
@@ -743,7 +767,8 @@ static int parse_argv(int argc, char *argv[]) {
ARG_DESERIALIZE,
ARG_SWITCHED_ROOT,
ARG_DEFAULT_STD_OUTPUT,
- ARG_DEFAULT_STD_ERROR
+ ARG_DEFAULT_STD_ERROR,
+ ARG_MACHINE_ID
};
static const struct option options[] = {
@@ -769,6 +794,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "switched-root", no_argument, NULL, ARG_SWITCHED_ROOT },
{ "default-standard-output", required_argument, NULL, ARG_DEFAULT_STD_OUTPUT, },
{ "default-standard-error", required_argument, NULL, ARG_DEFAULT_STD_ERROR, },
+ { "machine-id", required_argument, NULL, ARG_MACHINE_ID },
{}
};
@@ -964,6 +990,14 @@ static int parse_argv(int argc, char *argv[]) {
arg_switched_root = true;
break;
+ case ARG_MACHINE_ID:
+ r = set_machine_id(optarg);
+ if (r < 0) {
+ log_error("MachineID '%s' is not valid.", optarg);
+ return r;
+ }
+ break;
+
case 'h':
arg_action = ACTION_HELP;
if (arg_no_pager < 0)
@@ -1335,7 +1369,11 @@ int main(int argc, char *argv[]) {
initrd_timestamp = userspace_timestamp;
if (!skip_setup) {
- mount_setup_early();
+ r = mount_setup_early();
+ if (r < 0) {
+ error_message = "Failed to early mount API filesystems";
+ goto finish;
+ }
dual_timestamp_get(&security_start_timestamp);
if (mac_selinux_setup(&loaded_policy) < 0) {
error_message = "Failed to load SELinux policy";
@@ -1386,8 +1424,14 @@ int main(int argc, char *argv[]) {
* saving time change. All kernel local time concepts will be treated
* as UTC that way.
*/
- clock_reset_timewarp();
+ (void) clock_reset_timewarp();
}
+
+ r = clock_apply_epoch();
+ if (r < 0)
+ log_error_errno(r, "Current system time is before build time, but cannot correct: %m");
+ else if (r > 0)
+ log_info("System time before build time, advancing clock.");
}
/* Set the default for later on, but don't actually
@@ -1617,7 +1661,7 @@ int main(int argc, char *argv[]) {
status_welcome();
hostname_setup();
- machine_id_setup(NULL);
+ machine_id_setup(NULL, arg_machine_id);
loopback_setup();
bump_unix_max_dgram_qlen();
@@ -1631,14 +1675,14 @@ int main(int argc, char *argv[]) {
if (prctl(PR_SET_TIMERSLACK, arg_timer_slack_nsec) < 0)
log_error_errno(errno, "Failed to adjust timer slack: %m");
- if (arg_capability_bounding_set_drop) {
- r = capability_bounding_set_drop_usermode(arg_capability_bounding_set_drop);
+ if (!cap_test_all(arg_capability_bounding_set)) {
+ r = capability_bounding_set_drop_usermode(arg_capability_bounding_set);
if (r < 0) {
log_emergency_errno(r, "Failed to drop capability bounding set of usermode helpers: %m");
error_message = "Failed to drop capability bounding set of usermode helpers";
goto finish;
}
- r = capability_bounding_set_drop(arg_capability_bounding_set_drop, true);
+ r = capability_bounding_set_drop(arg_capability_bounding_set, true);
if (r < 0) {
log_emergency_errno(r, "Failed to drop capability bounding set: %m");
error_message = "Failed to drop capability bounding set";
@@ -1940,6 +1984,15 @@ finish:
(void) clearenv();
assert(i <= args_size);
+
+ /*
+ * We want valgrind to print its memory usage summary before reexecution.
+ * Valgrind won't do this is on its own on exec(), but it will do it on exit().
+ * Hence, to ensure we get a summary here, fork() off a child, let it exit() cleanly,
+ * so that it prints the summary, and wait() for it in the parent, before proceeding into the exec().
+ */
+ valgrind_summary_hack();
+
(void) execv(args[0], (char* const*) args);
}
diff --git a/src/core/manager.c b/src/core/manager.c
index 34dd715e93..e8fea376ff 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -233,7 +233,7 @@ static int have_ask_password(void) {
errno = 0;
de = readdir(dir);
- if (!de && errno != 0)
+ if (!de && errno > 0)
return -errno;
if (!de)
return false;
@@ -380,6 +380,9 @@ static int enable_special_signals(Manager *m) {
assert(m);
+ if (m->test_run)
+ return 0;
+
/* Enable that we get SIGINT on control-alt-del. In containers
* this will fail with EPERM (older) or EINVAL (newer), so
* ignore that. */
@@ -986,7 +989,7 @@ Manager* manager_free(Manager *m) {
free(m->switch_root_init);
for (i = 0; i < _RLIMIT_MAX; i++)
- free(m->rlimit[i]);
+ m->rlimit[i] = mfree(m->rlimit[i]);
assert(hashmap_isempty(m->units_requiring_mounts_for));
hashmap_free(m->units_requiring_mounts_for);
@@ -1885,23 +1888,21 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t
switch (sfsi.ssi_signo - SIGRTMIN) {
case 20:
- log_debug("Enabling showing of status.");
manager_set_show_status(m, SHOW_STATUS_YES);
break;
case 21:
- log_debug("Disabling showing of status.");
manager_set_show_status(m, SHOW_STATUS_NO);
break;
case 22:
log_set_max_level(LOG_DEBUG);
- log_notice("Setting log level to debug.");
+ log_info("Setting log level to debug.");
break;
case 23:
log_set_max_level(LOG_INFO);
- log_notice("Setting log level to info.");
+ log_info("Setting log level to info.");
break;
case 24:
@@ -2576,6 +2577,10 @@ int manager_reload(Manager *m) {
/* Third, fire things up! */
manager_coldplug(m);
+ /* Sync current state of bus names with our set of listening units */
+ if (m->api_bus)
+ manager_sync_bus_names(m, m->api_bus);
+
assert(m->n_reloading > 0);
m->n_reloading--;
@@ -2918,6 +2923,8 @@ int manager_set_default_rlimits(Manager *m, struct rlimit **default_rlimit) {
assert(m);
for (i = 0; i < _RLIMIT_MAX; i++) {
+ m->rlimit[i] = mfree(m->rlimit[i]);
+
if (!default_rlimit[i])
continue;
@@ -2961,6 +2968,9 @@ void manager_set_show_status(Manager *m, ShowStatus mode) {
if (m->running_as != MANAGER_SYSTEM)
return;
+ if (m->show_status != mode)
+ log_debug("%s showing of status.",
+ mode == SHOW_STATUS_NO ? "Disabling" : "Enabling");
m->show_status = mode;
if (mode > 0)
@@ -3087,18 +3097,18 @@ ManagerState manager_state(Manager *m) {
/* Is the special shutdown target queued? If so, we are in shutdown state */
u = manager_get_unit(m, SPECIAL_SHUTDOWN_TARGET);
- if (u && u->job && IN_SET(u->job->type, JOB_START, JOB_RESTART, JOB_TRY_RESTART, JOB_RELOAD_OR_START))
+ if (u && u->job && IN_SET(u->job->type, JOB_START, JOB_RESTART, JOB_RELOAD_OR_START))
return MANAGER_STOPPING;
/* Are the rescue or emergency targets active or queued? If so we are in maintenance state */
u = manager_get_unit(m, SPECIAL_RESCUE_TARGET);
if (u && (UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u)) ||
- (u->job && IN_SET(u->job->type, JOB_START, JOB_RESTART, JOB_TRY_RESTART, JOB_RELOAD_OR_START))))
+ (u->job && IN_SET(u->job->type, JOB_START, JOB_RESTART, JOB_RELOAD_OR_START))))
return MANAGER_MAINTENANCE;
u = manager_get_unit(m, SPECIAL_EMERGENCY_TARGET);
if (u && (UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u)) ||
- (u->job && IN_SET(u->job->type, JOB_START, JOB_RESTART, JOB_TRY_RESTART, JOB_RELOAD_OR_START))))
+ (u->job && IN_SET(u->job->type, JOB_START, JOB_RESTART, JOB_RELOAD_OR_START))))
return MANAGER_MAINTENANCE;
/* Are there any failed units? If so, we are in degraded mode */
diff --git a/src/core/mount-setup.c b/src/core/mount-setup.c
index 2b8d590ed1..321a52c30e 100644
--- a/src/core/mount-setup.c
+++ b/src/core/mount-setup.c
@@ -158,11 +158,13 @@ static int mount_one(const MountPoint *p, bool relabel) {
/* Relabel first, just in case */
if (relabel)
- label_fix(p->where, true, true);
+ (void) label_fix(p->where, true, true);
r = path_is_mount_point(p->where, AT_SYMLINK_FOLLOW);
- if (r < 0 && r != -ENOENT)
- return r;
+ if (r < 0 && r != -ENOENT) {
+ log_full_errno((p->mode & MNT_FATAL) ? LOG_ERR : LOG_DEBUG, r, "Failed to determine whether %s is a mount point: %m", p->where);
+ return (p->mode & MNT_FATAL) ? r : 0;
+ }
if (r > 0)
return 0;
@@ -173,9 +175,9 @@ static int mount_one(const MountPoint *p, bool relabel) {
/* The access mode here doesn't really matter too much, since
* the mounted file system will take precedence anyway. */
if (relabel)
- mkdir_p_label(p->where, 0755);
+ (void) mkdir_p_label(p->where, 0755);
else
- mkdir_p(p->where, 0755);
+ (void) mkdir_p(p->where, 0755);
log_debug("Mounting %s to %s of type %s with options %s.",
p->what,
@@ -188,29 +190,25 @@ static int mount_one(const MountPoint *p, bool relabel) {
p->type,
p->flags,
p->options) < 0) {
- log_full((p->mode & MNT_FATAL) ? LOG_ERR : LOG_DEBUG, "Failed to mount %s at %s: %m", p->type, p->where);
+ log_full_errno((p->mode & MNT_FATAL) ? LOG_ERR : LOG_DEBUG, errno, "Failed to mount %s at %s: %m", p->type, p->where);
return (p->mode & MNT_FATAL) ? -errno : 0;
}
/* Relabel again, since we now mounted something fresh here */
if (relabel)
- label_fix(p->where, false, false);
+ (void) label_fix(p->where, false, false);
return 1;
}
-int mount_setup_early(void) {
+static int mount_points_setup(unsigned n, bool loaded_policy) {
unsigned i;
int r = 0;
- assert_cc(N_EARLY_MOUNT <= ELEMENTSOF(mount_table));
-
- /* Do a minimal mount of /proc and friends to enable the most
- * basic stuff, such as SELinux */
- for (i = 0; i < N_EARLY_MOUNT; i ++) {
+ for (i = 0; i < n; i ++) {
int j;
- j = mount_one(mount_table + i, false);
+ j = mount_one(mount_table + i, loaded_policy);
if (j != 0 && r >= 0)
r = j;
}
@@ -218,6 +216,14 @@ int mount_setup_early(void) {
return r;
}
+int mount_setup_early(void) {
+ assert_cc(N_EARLY_MOUNT <= ELEMENTSOF(mount_table));
+
+ /* Do a minimal mount of /proc and friends to enable the most
+ * basic stuff, such as SELinux */
+ return mount_points_setup(N_EARLY_MOUNT, false);
+}
+
int mount_cgroup_controllers(char ***join_controllers) {
_cleanup_set_free_free_ Set *controllers = NULL;
int r;
@@ -304,13 +310,18 @@ int mount_cgroup_controllers(char ***join_controllers) {
return log_oom();
r = symlink(options, t);
- if (r < 0 && errno != EEXIST)
- return log_error_errno(errno, "Failed to create symlink %s: %m", t);
+ if (r >= 0) {
#ifdef SMACK_RUN_LABEL
- r = mac_smack_copy(t, options);
- if (r < 0 && r != -EOPNOTSUPP)
- return log_error_errno(r, "Failed to copy smack label from %s to %s: %m", options, t);
+ _cleanup_free_ char *src;
+ src = strappend("/sys/fs/cgroup/", options);
+ if (!src)
+ return log_oom();
+ r = mac_smack_copy(t, src);
+ if (r < 0 && r != -EOPNOTSUPP)
+ return log_error_errno(r, "Failed to copy smack label from %s to %s: %m", src, t);
#endif
+ } else if (errno != EEXIST)
+ return log_error_errno(errno, "Failed to create symlink %s: %m", t);
}
}
}
@@ -347,16 +358,9 @@ static int nftw_cb(
#endif
int mount_setup(bool loaded_policy) {
- unsigned i;
int r = 0;
- for (i = 0; i < ELEMENTSOF(mount_table); i ++) {
- int j;
-
- j = mount_one(mount_table + i, loaded_policy);
- if (j != 0 && r >= 0)
- r = j;
- }
+ r = mount_points_setup(ELEMENTSOF(mount_table), loaded_policy);
if (r < 0)
return r;
diff --git a/src/core/mount.c b/src/core/mount.c
index 2ad4ad4f42..e0bd09bbbb 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -152,29 +152,27 @@ static void mount_init(Unit *u) {
u->ignore_on_isolate = true;
}
-static int mount_arm_timer(Mount *m) {
+static int mount_arm_timer(Mount *m, usec_t usec) {
int r;
assert(m);
- if (m->timeout_usec <= 0) {
- m->timer_event_source = sd_event_source_unref(m->timer_event_source);
- return 0;
- }
-
if (m->timer_event_source) {
- r = sd_event_source_set_time(m->timer_event_source, now(CLOCK_MONOTONIC) + m->timeout_usec);
+ r = sd_event_source_set_time(m->timer_event_source, usec);
if (r < 0)
return r;
return sd_event_source_set_enabled(m->timer_event_source, SD_EVENT_ONESHOT);
}
+ if (usec == USEC_INFINITY)
+ return 0;
+
r = sd_event_add_time(
UNIT(m)->manager->event,
&m->timer_event_source,
CLOCK_MONOTONIC,
- now(CLOCK_MONOTONIC) + m->timeout_usec, 0,
+ usec, 0,
mount_dispatch_timer, m);
if (r < 0)
return r;
@@ -653,7 +651,7 @@ static int mount_coldplug(Unit *u) {
if (r < 0)
return r;
- r = mount_arm_timer(m);
+ r = mount_arm_timer(m, usec_add(u->state_change_timestamp.monotonic, m->timeout_usec));
if (r < 0)
return r;
}
@@ -725,11 +723,11 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
r = unit_setup_exec_runtime(UNIT(m));
if (r < 0)
- goto fail;
+ return r;
- r = mount_arm_timer(m);
+ r = mount_arm_timer(m, usec_add(now(CLOCK_MONOTONIC), m->timeout_usec));
if (r < 0)
- goto fail;
+ return r;
exec_params.environment = UNIT(m)->manager->environment;
exec_params.confirm_spawn = UNIT(m)->manager->confirm_spawn;
@@ -745,21 +743,16 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
m->exec_runtime,
&pid);
if (r < 0)
- goto fail;
+ return r;
r = unit_watch_pid(UNIT(m), pid);
if (r < 0)
/* FIXME: we need to do something here */
- goto fail;
+ return r;
*_pid = pid;
return 0;
-
-fail:
- m->timer_event_source = sd_event_source_unref(m->timer_event_source);
-
- return r;
}
static void mount_enter_dead(Mount *m, MountResult f) {
@@ -805,7 +798,7 @@ static void mount_enter_signal(Mount *m, MountState state, MountResult f) {
goto fail;
if (r > 0) {
- r = mount_arm_timer(m);
+ r = mount_arm_timer(m, usec_add(now(CLOCK_MONOTONIC), m->timeout_usec));
if (r < 0)
goto fail;
@@ -1563,17 +1556,21 @@ static void mount_shutdown(Manager *m) {
m->mount_monitor = NULL;
}
-static int mount_get_timeout(Unit *u, uint64_t *timeout) {
+static int mount_get_timeout(Unit *u, usec_t *timeout) {
Mount *m = MOUNT(u);
+ usec_t t;
int r;
if (!m->timer_event_source)
return 0;
- r = sd_event_source_get_time(m->timer_event_source, timeout);
+ r = sd_event_source_get_time(m->timer_event_source, &t);
if (r < 0)
return r;
+ if (t == USEC_INFINITY)
+ return 0;
+ *timeout = t;
return 1;
}
diff --git a/src/core/scope.c b/src/core/scope.c
index 1953af1f88..7dd437d204 100644
--- a/src/core/scope.c
+++ b/src/core/scope.c
@@ -66,29 +66,27 @@ static void scope_done(Unit *u) {
s->timer_event_source = sd_event_source_unref(s->timer_event_source);
}
-static int scope_arm_timer(Scope *s) {
+static int scope_arm_timer(Scope *s, usec_t usec) {
int r;
assert(s);
- if (s->timeout_stop_usec <= 0) {
- s->timer_event_source = sd_event_source_unref(s->timer_event_source);
- return 0;
- }
-
if (s->timer_event_source) {
- r = sd_event_source_set_time(s->timer_event_source, now(CLOCK_MONOTONIC) + s->timeout_stop_usec);
+ r = sd_event_source_set_time(s->timer_event_source, usec);
if (r < 0)
return r;
return sd_event_source_set_enabled(s->timer_event_source, SD_EVENT_ONESHOT);
}
+ if (usec == USEC_INFINITY)
+ return 0;
+
r = sd_event_add_time(
UNIT(s)->manager->event,
&s->timer_event_source,
CLOCK_MONOTONIC,
- now(CLOCK_MONOTONIC) + s->timeout_stop_usec, 0,
+ usec, 0,
scope_dispatch_timer, s);
if (r < 0)
return r;
@@ -190,20 +188,19 @@ static int scope_coldplug(Unit *u) {
assert(s);
assert(s->state == SCOPE_DEAD);
- if (s->deserialized_state != s->state) {
-
- if (IN_SET(s->deserialized_state, SCOPE_STOP_SIGKILL, SCOPE_STOP_SIGTERM)) {
- r = scope_arm_timer(s);
- if (r < 0)
- return r;
- }
-
- if (!IN_SET(s->deserialized_state, SCOPE_DEAD, SCOPE_FAILED))
- unit_watch_all_pids(UNIT(s));
+ if (s->deserialized_state == s->state)
+ return 0;
- scope_set_state(s, s->deserialized_state);
+ if (IN_SET(s->deserialized_state, SCOPE_STOP_SIGKILL, SCOPE_STOP_SIGTERM)) {
+ r = scope_arm_timer(s, usec_add(u->state_change_timestamp.monotonic, s->timeout_stop_usec));
+ if (r < 0)
+ return r;
}
+ if (!IN_SET(s->deserialized_state, SCOPE_DEAD, SCOPE_FAILED))
+ unit_watch_all_pids(UNIT(s));
+
+ scope_set_state(s, s->deserialized_state);
return 0;
}
@@ -261,7 +258,7 @@ static void scope_enter_signal(Scope *s, ScopeState state, ScopeResult f) {
r = 1;
if (r > 0) {
- r = scope_arm_timer(s);
+ r = scope_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_stop_usec));
if (r < 0)
goto fail;
@@ -348,17 +345,21 @@ static int scope_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
return unit_kill_common(u, who, signo, -1, -1, error);
}
-static int scope_get_timeout(Unit *u, uint64_t *timeout) {
+static int scope_get_timeout(Unit *u, usec_t *timeout) {
Scope *s = SCOPE(u);
+ usec_t t;
int r;
if (!s->timer_event_source)
return 0;
- r = sd_event_source_get_time(s->timer_event_source, timeout);
+ r = sd_event_source_get_time(s->timer_event_source, &t);
if (r < 0)
return r;
+ if (t == USEC_INFINITY)
+ return 0;
+ *timeout = t;
return 1;
}
diff --git a/src/core/service.c b/src/core/service.c
index 41a729c421..02ce1a566a 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -112,6 +112,7 @@ static void service_init(Unit *u) {
s->timeout_start_usec = u->manager->default_timeout_start_usec;
s->timeout_stop_usec = u->manager->default_timeout_stop_usec;
s->restart_usec = u->manager->default_restart_usec;
+ s->runtime_max_usec = USEC_INFINITY;
s->type = _SERVICE_TYPE_INVALID;
s->socket_fd = -1;
s->bus_endpoint_fd = -1;
@@ -216,7 +217,7 @@ static void service_start_watchdog(Service *s) {
return;
if (s->watchdog_event_source) {
- r = sd_event_source_set_time(s->watchdog_event_source, s->watchdog_timestamp.monotonic + s->watchdog_usec);
+ r = sd_event_source_set_time(s->watchdog_event_source, usec_add(s->watchdog_timestamp.monotonic, s->watchdog_usec));
if (r < 0) {
log_unit_warning_errno(UNIT(s), r, "Failed to reset watchdog timer: %m");
return;
@@ -228,7 +229,7 @@ static void service_start_watchdog(Service *s) {
UNIT(s)->manager->event,
&s->watchdog_event_source,
CLOCK_MONOTONIC,
- s->watchdog_timestamp.monotonic + s->watchdog_usec, 0,
+ usec_add(s->watchdog_timestamp.monotonic, s->watchdog_usec), 0,
service_dispatch_watchdog, s);
if (r < 0) {
log_unit_warning_errno(UNIT(s), r, "Failed to add watchdog timer: %m");
@@ -323,6 +324,8 @@ static void service_done(Unit *u) {
s->bus_name = mfree(s->bus_name);
}
+ s->bus_name_owner = mfree(s->bus_name_owner);
+
s->bus_endpoint_fd = safe_close(s->bus_endpoint_fd);
service_close_socket_fd(s);
service_connection_unref(s);
@@ -431,18 +434,21 @@ static int service_arm_timer(Service *s, usec_t usec) {
assert(s);
if (s->timer_event_source) {
- r = sd_event_source_set_time(s->timer_event_source, now(CLOCK_MONOTONIC) + usec);
+ r = sd_event_source_set_time(s->timer_event_source, usec);
if (r < 0)
return r;
return sd_event_source_set_enabled(s->timer_event_source, SD_EVENT_ONESHOT);
}
+ if (usec == USEC_INFINITY)
+ return 0;
+
r = sd_event_add_time(
UNIT(s)->manager->event,
&s->timer_event_source,
CLOCK_MONOTONIC,
- now(CLOCK_MONOTONIC) + usec, 0,
+ usec, 0,
service_dispatch_timer, s);
if (r < 0)
return r;
@@ -507,6 +513,9 @@ static int service_verify(Service *s) {
if (!s->usb_function_descriptors && s->usb_function_strings)
log_unit_warning(UNIT(s), "Service has USBFunctionStrings= setting, but no USBFunctionDescriptors=. Ignoring.");
+ if (s->runtime_max_usec != USEC_INFINITY && s->type == SERVICE_ONESHOT)
+ log_unit_warning(UNIT(s), "MaxRuntimeSec= has no effect in combination with Type=oneshot. Ignoring.");
+
return 0;
}
@@ -622,7 +631,7 @@ static int service_add_extras(Service *s) {
/* Oneshot services have disabled start timeout by default */
if (s->type == SERVICE_ONESHOT && !s->start_timeout_defined)
- s->timeout_start_usec = 0;
+ s->timeout_start_usec = USEC_INFINITY;
service_fix_output(s);
@@ -880,6 +889,7 @@ static void service_set_state(Service *s, ServiceState state) {
if (!IN_SET(state,
SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
+ SERVICE_RUNNING,
SERVICE_RELOAD,
SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
@@ -952,6 +962,37 @@ static void service_set_state(Service *s, ServiceState state) {
unit_notify(UNIT(s), table[old_state], table[state], s->reload_result == SERVICE_SUCCESS);
}
+static usec_t service_coldplug_timeout(Service *s) {
+ assert(s);
+
+ switch (s->deserialized_state) {
+
+ case SERVICE_START_PRE:
+ case SERVICE_START:
+ case SERVICE_START_POST:
+ case SERVICE_RELOAD:
+ return usec_add(UNIT(s)->state_change_timestamp.monotonic, s->timeout_start_usec);
+
+ case SERVICE_RUNNING:
+ return usec_add(UNIT(s)->active_enter_timestamp.monotonic, s->runtime_max_usec);
+
+ case SERVICE_STOP:
+ case SERVICE_STOP_SIGABRT:
+ case SERVICE_STOP_SIGTERM:
+ case SERVICE_STOP_SIGKILL:
+ case SERVICE_STOP_POST:
+ case SERVICE_FINAL_SIGTERM:
+ case SERVICE_FINAL_SIGKILL:
+ return usec_add(UNIT(s)->state_change_timestamp.monotonic, s->timeout_stop_usec);
+
+ case SERVICE_AUTO_RESTART:
+ return usec_add(UNIT(s)->inactive_enter_timestamp.monotonic, s->restart_usec);
+
+ default:
+ return USEC_INFINITY;
+ }
+}
+
static int service_coldplug(Unit *u) {
Service *s = SERVICE(u);
int r;
@@ -962,31 +1003,9 @@ static int service_coldplug(Unit *u) {
if (s->deserialized_state == s->state)
return 0;
- if (IN_SET(s->deserialized_state,
- SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
- SERVICE_RELOAD,
- SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
- SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) {
-
- usec_t k;
-
- k = IN_SET(s->deserialized_state, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_RELOAD) ? s->timeout_start_usec : s->timeout_stop_usec;
-
- /* For the start/stop timeouts 0 means off */
- if (k > 0) {
- r = service_arm_timer(s, k);
- if (r < 0)
- return r;
- }
- }
-
- if (s->deserialized_state == SERVICE_AUTO_RESTART) {
-
- /* The restart timeouts 0 means immediately */
- r = service_arm_timer(s, s->restart_usec);
- if (r < 0)
- return r;
- }
+ r = service_arm_timer(s, service_coldplug_timeout(s));
+ if (r < 0)
+ return r;
if (s->main_pid > 0 &&
pid_is_unwaited(s->main_pid) &&
@@ -1173,7 +1192,7 @@ static int service_spawn(
r = unit_setup_exec_runtime(UNIT(s));
if (r < 0)
- goto fail;
+ return r;
if (pass_fds ||
s->exec_context.std_input == EXEC_INPUT_SOCKET ||
@@ -1182,55 +1201,42 @@ static int service_spawn(
r = service_collect_fds(s, &fds, &fd_names);
if (r < 0)
- goto fail;
+ return r;
n_fds = r;
}
- if (timeout > 0) {
- r = service_arm_timer(s, timeout);
- if (r < 0)
- goto fail;
- } else
- s->timer_event_source = sd_event_source_unref(s->timer_event_source);
+ r = service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), timeout));
+ if (r < 0)
+ return r;
r = unit_full_printf_strv(UNIT(s), c->argv, &argv);
if (r < 0)
- goto fail;
+ return r;
our_env = new0(char*, 6);
- if (!our_env) {
- r = -ENOMEM;
- goto fail;
- }
+ if (!our_env)
+ return -ENOMEM;
if (is_control ? s->notify_access == NOTIFY_ALL : s->notify_access != NOTIFY_NONE)
- if (asprintf(our_env + n_env++, "NOTIFY_SOCKET=%s", UNIT(s)->manager->notify_socket) < 0) {
- r = -ENOMEM;
- goto fail;
- }
+ if (asprintf(our_env + n_env++, "NOTIFY_SOCKET=%s", UNIT(s)->manager->notify_socket) < 0)
+ return -ENOMEM;
if (s->main_pid > 0)
- if (asprintf(our_env + n_env++, "MAINPID="PID_FMT, s->main_pid) < 0) {
- r = -ENOMEM;
- goto fail;
- }
+ if (asprintf(our_env + n_env++, "MAINPID="PID_FMT, s->main_pid) < 0)
+ return -ENOMEM;
if (UNIT(s)->manager->running_as != MANAGER_SYSTEM)
- if (asprintf(our_env + n_env++, "MANAGERPID="PID_FMT, getpid()) < 0) {
- r = -ENOMEM;
- goto fail;
- }
+ if (asprintf(our_env + n_env++, "MANAGERPID="PID_FMT, getpid()) < 0)
+ return -ENOMEM;
if (s->socket_fd >= 0) {
union sockaddr_union sa;
socklen_t salen = sizeof(sa);
r = getpeername(s->socket_fd, &sa.sa, &salen);
- if (r < 0) {
- r = -errno;
- goto fail;
- }
+ if (r < 0)
+ return -errno;
if (IN_SET(sa.sa.sa_family, AF_INET, AF_INET6)) {
_cleanup_free_ char *addr = NULL;
@@ -1239,34 +1245,26 @@ static int service_spawn(
r = sockaddr_pretty(&sa.sa, salen, true, false, &addr);
if (r < 0)
- goto fail;
+ return r;
t = strappend("REMOTE_ADDR=", addr);
- if (!t) {
- r = -ENOMEM;
- goto fail;
- }
+ if (!t)
+ return -ENOMEM;
our_env[n_env++] = t;
port = sockaddr_port(&sa.sa);
- if (port < 0) {
- r = port;
- goto fail;
- }
+ if (port < 0)
+ return port;
- if (asprintf(&t, "REMOTE_PORT=%u", port) < 0) {
- r = -ENOMEM;
- goto fail;
- }
+ if (asprintf(&t, "REMOTE_PORT=%u", port) < 0)
+ return -ENOMEM;
our_env[n_env++] = t;
}
}
final_env = strv_env_merge(2, UNIT(s)->manager->environment, our_env, NULL);
- if (!final_env) {
- r = -ENOMEM;
- goto fail;
- }
+ if (!final_env)
+ return -ENOMEM;
if (is_control && UNIT(s)->cgroup_path) {
path = strjoina(UNIT(s)->cgroup_path, "/control");
@@ -1278,7 +1276,7 @@ static int service_spawn(
r = bus_kernel_create_endpoint(UNIT(s)->manager->running_as == MANAGER_SYSTEM ? "system" : "user",
UNIT(s)->id, &bus_endpoint_path);
if (r < 0)
- goto fail;
+ return r;
/* Pass the fd to the exec_params so that the child process can upload the policy.
* Keep a reference to the fd in the service, so the endpoint is kept alive as long
@@ -1312,22 +1310,16 @@ static int service_spawn(
s->exec_runtime,
&pid);
if (r < 0)
- goto fail;
+ return r;
r = unit_watch_pid(UNIT(s), pid);
if (r < 0)
/* FIXME: we need to do something here */
- goto fail;
+ return r;
*_pid = pid;
return 0;
-
-fail:
- if (timeout)
- s->timer_event_source = sd_event_source_unref(s->timer_event_source);
-
- return r;
}
static int main_pid_good(Service *s) {
@@ -1435,7 +1427,7 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
if (allow_restart && service_shall_restart(s)) {
- r = service_arm_timer(s, s->restart_usec);
+ r = service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->restart_usec));
if (r < 0)
goto fail;
@@ -1456,7 +1448,7 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
* out-of-date, and some software might be confused by it, so
* let's remove it. */
if (s->pid_file)
- unlink_noerrno(s->pid_file);
+ (void) unlink(s->pid_file);
return;
@@ -1543,11 +1535,9 @@ static void service_enter_signal(Service *s, ServiceState state, ServiceResult f
goto fail;
if (r > 0) {
- if (s->timeout_stop_usec > 0) {
- r = service_arm_timer(s, s->timeout_stop_usec);
- if (r < 0)
- goto fail;
- }
+ r = service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_stop_usec));
+ if (r < 0)
+ goto fail;
service_set_state(s, state);
} else if (IN_SET(state, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM) && s->kill_context.send_sigkill)
@@ -1575,8 +1565,7 @@ static void service_enter_stop_by_notify(Service *s) {
unit_watch_all_pids(UNIT(s));
- if (s->timeout_stop_usec > 0)
- service_arm_timer(s, s->timeout_stop_usec);
+ service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_stop_usec));
/* The service told us it's stopping, so it's as if we SIGTERM'd it. */
service_set_state(s, SERVICE_STOP_SIGTERM);
@@ -1646,6 +1635,8 @@ static void service_enter_running(Service *s, ServiceResult f) {
if (f != SERVICE_SUCCESS)
s->result = f;
+ service_unwatch_control_pid(s);
+
if (service_good(s)) {
/* If there are any queued up sd_notify()
@@ -1654,8 +1645,10 @@ static void service_enter_running(Service *s, ServiceResult f) {
service_enter_reload_by_notify(s);
else if (s->notify_state == NOTIFY_STOPPING)
service_enter_stop_by_notify(s);
- else
+ else {
service_set_state(s, SERVICE_RUNNING);
+ service_arm_timer(s, usec_add(UNIT(s)->active_enter_timestamp.monotonic, s->runtime_max_usec));
+ }
} else if (s->remain_after_exit)
service_set_state(s, SERVICE_EXITED);
@@ -1709,6 +1702,7 @@ static void service_kill_control_processes(Service *s) {
static void service_enter_start(Service *s) {
ExecCommand *c;
+ usec_t timeout;
pid_t pid;
int r;
@@ -1740,9 +1734,16 @@ static void service_enter_start(Service *s) {
return;
}
+ if (IN_SET(s->type, SERVICE_SIMPLE, SERVICE_IDLE))
+ /* For simple + idle this is the main process. We don't apply any timeout here, but
+ * service_enter_running() will later apply the .runtime_max_usec timeout. */
+ timeout = USEC_INFINITY;
+ else
+ timeout = s->timeout_start_usec;
+
r = service_spawn(s,
c,
- IN_SET(s->type, SERVICE_FORKING, SERVICE_DBUS, SERVICE_NOTIFY, SERVICE_ONESHOT) ? s->timeout_start_usec : 0,
+ timeout,
true,
true,
true,
@@ -1752,7 +1753,7 @@ static void service_enter_start(Service *s) {
if (r < 0)
goto fail;
- if (s->type == SERVICE_SIMPLE || s->type == SERVICE_IDLE) {
+ if (IN_SET(s->type, SERVICE_SIMPLE, SERVICE_IDLE)) {
/* For simple services we immediately start
* the START_POST binaries. */
@@ -1767,9 +1768,7 @@ static void service_enter_start(Service *s) {
s->control_pid = pid;
service_set_state(s, SERVICE_START);
- } else if (s->type == SERVICE_ONESHOT ||
- s->type == SERVICE_DBUS ||
- s->type == SERVICE_NOTIFY) {
+ } else if (IN_SET(s->type, SERVICE_ONESHOT, SERVICE_DBUS, SERVICE_NOTIFY)) {
/* For oneshot services we wait until the start
* process exited, too, but it is our main process. */
@@ -1838,7 +1837,7 @@ static void service_enter_restart(Service *s) {
/* Don't restart things if we are going down anyway */
log_unit_info(UNIT(s), "Stop job pending for unit, delaying automatic restart.");
- r = service_arm_timer(s, s->restart_usec);
+ r = service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->restart_usec));
if (r < 0)
goto fail;
@@ -1868,9 +1867,7 @@ fail:
static void service_enter_reload_by_notify(Service *s) {
assert(s);
- if (s->timeout_start_usec > 0)
- service_arm_timer(s, s->timeout_start_usec);
-
+ service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_start_usec));
service_set_state(s, SERVICE_RELOAD);
}
@@ -1911,6 +1908,7 @@ fail:
}
static void service_run_next_control(Service *s) {
+ usec_t timeout;
int r;
assert(s);
@@ -1922,9 +1920,14 @@ static void service_run_next_control(Service *s) {
s->control_command = s->control_command->command_next;
service_unwatch_control_pid(s);
+ if (IN_SET(s->state, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD))
+ timeout = s->timeout_start_usec;
+ else
+ timeout = s->timeout_stop_usec;
+
r = service_spawn(s,
s->control_command,
- IN_SET(s->state, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD) ? s->timeout_start_usec : s->timeout_stop_usec,
+ timeout,
false,
!s->permissions_start_only,
!s->root_directory_start_only,
@@ -2122,6 +2125,7 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
unit_serialize_item(u, f, "main-pid-known", yes_no(s->main_pid_known));
unit_serialize_item(u, f, "bus-name-good", yes_no(s->bus_name_good));
+ unit_serialize_item(u, f, "bus-name-owner", s->bus_name_owner);
r = unit_serialize_item_escaped(u, f, "status-text", s->status_text);
if (r < 0)
@@ -2249,6 +2253,10 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
log_unit_debug(u, "Failed to parse bus-name-good value: %s", value);
else
s->bus_name_good = b;
+ } else if (streq(key, "bus-name-owner")) {
+ r = free_and_strdup(&s->bus_name_owner, value);
+ if (r < 0)
+ log_unit_error_errno(u, r, "Unable to deserialize current bus owner %s: %m", value);
} else if (streq(key, "status-text")) {
char *t;
@@ -2356,6 +2364,7 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
else {
asynchronous_close(s->stdin_fd);
s->stdin_fd = fdset_remove(fds, fd);
+ s->exec_context.stdio_as_fds = true;
}
} else if (streq(key, "stdout-fd")) {
int fd;
@@ -2365,6 +2374,7 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
else {
asynchronous_close(s->stdout_fd);
s->stdout_fd = fdset_remove(fds, fd);
+ s->exec_context.stdio_as_fds = true;
}
} else if (streq(key, "stderr-fd")) {
int fd;
@@ -2374,6 +2384,7 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
else {
asynchronous_close(s->stderr_fd);
s->stderr_fd = fdset_remove(fds, fd);
+ s->exec_context.stdio_as_fds = true;
}
} else
log_unit_debug(u, "Unknown serialization key: %s", key);
@@ -2779,7 +2790,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
case SERVICE_START_POST:
if (f != SERVICE_SUCCESS) {
- service_enter_stop(s, f);
+ service_enter_signal(s, SERVICE_STOP_SIGTERM, f);
break;
}
@@ -2869,12 +2880,16 @@ static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *us
case SERVICE_START_POST:
log_unit_warning(UNIT(s), "Start-post operation timed out. Stopping.");
+ service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_TIMEOUT);
+ break;
+
+ case SERVICE_RUNNING:
+ log_unit_warning(UNIT(s), "Service reached runtime time limit. Stopping.");
service_enter_stop(s, SERVICE_FAILURE_TIMEOUT);
break;
case SERVICE_RELOAD:
- log_unit_warning(UNIT(s), "Reload operation timed out. Stopping.");
- service_unwatch_control_pid(s);
+ log_unit_warning(UNIT(s), "Reload operation timed out. Killing reload process.");
service_kill_control_processes(s);
s->reload_result = SERVICE_FAILURE_TIMEOUT;
service_enter_running(s, SERVICE_SUCCESS);
@@ -3096,17 +3111,21 @@ static void service_notify_message(Unit *u, pid_t pid, char **tags, FDSet *fds)
unit_add_to_dbus_queue(u);
}
-static int service_get_timeout(Unit *u, uint64_t *timeout) {
+static int service_get_timeout(Unit *u, usec_t *timeout) {
Service *s = SERVICE(u);
+ uint64_t t;
int r;
if (!s->timer_event_source)
return 0;
- r = sd_event_source_get_time(s->timer_event_source, timeout);
+ r = sd_event_source_get_time(s->timer_event_source, &t);
if (r < 0)
return r;
+ if (t == USEC_INFINITY)
+ return 0;
+ *timeout = t;
return 1;
}
@@ -3134,6 +3153,13 @@ static void service_bus_name_owner_change(
s->bus_name_good = !!new_owner;
+ /* Track the current owner, so we can reconstruct changes after a daemon reload */
+ r = free_and_strdup(&s->bus_name_owner, new_owner);
+ if (r < 0) {
+ log_unit_error_errno(u, r, "Unable to set new bus name owner %s: %m", new_owner);
+ return;
+ }
+
if (s->type == SERVICE_DBUS) {
/* service_enter_running() will figure out what to
@@ -3187,7 +3213,7 @@ int service_set_socket_fd(Service *s, int fd, Socket *sock, bool selinux_context
if (s->state != SERVICE_DEAD)
return -EAGAIN;
- if (getpeername_pretty(fd, &peer) >= 0) {
+ if (getpeername_pretty(fd, true, &peer) >= 0) {
if (UNIT(s)->description) {
_cleanup_free_ char *a;
diff --git a/src/core/service.h b/src/core/service.h
index d0faad88e0..24408940d4 100644
--- a/src/core/service.h
+++ b/src/core/service.h
@@ -118,6 +118,7 @@ struct Service {
usec_t restart_usec;
usec_t timeout_start_usec;
usec_t timeout_stop_usec;
+ usec_t runtime_max_usec;
dual_timestamp watchdog_timestamp;
usec_t watchdog_usec;
@@ -172,6 +173,7 @@ struct Service {
bool reset_cpu_usage:1;
char *bus_name;
+ char *bus_name_owner; /* unique name of the current owner */
char *status_text;
int status_errno;
diff --git a/src/core/smack-setup.c b/src/core/smack-setup.c
index 0661ff9ecd..c9374ca0e8 100644
--- a/src/core/smack-setup.c
+++ b/src/core/smack-setup.c
@@ -197,6 +197,75 @@ static int write_cipso2_rules(const char* srcdir) {
return r;
}
+static int write_netlabel_rules(const char* srcdir) {
+ _cleanup_fclose_ FILE *dst = NULL;
+ _cleanup_closedir_ DIR *dir = NULL;
+ struct dirent *entry;
+ char buf[NAME_MAX];
+ int dfd = -1;
+ int r = 0;
+
+ dst = fopen("/sys/fs/smackfs/netlabel", "we");
+ if (!dst) {
+ if (errno != ENOENT)
+ log_warning_errno(errno, "Failed to open /sys/fs/smackfs/netlabel: %m");
+ return -errno; /* negative error */
+ }
+
+ /* write rules to dst from every file in the directory */
+ dir = opendir(srcdir);
+ if (!dir) {
+ if (errno != ENOENT)
+ log_warning_errno(errno, "Failed to opendir %s: %m", srcdir);
+ return errno; /* positive on purpose */
+ }
+
+ dfd = dirfd(dir);
+ assert(dfd >= 0);
+
+ FOREACH_DIRENT(entry, dir, return 0) {
+ int fd;
+ _cleanup_fclose_ FILE *policy = NULL;
+
+ fd = openat(dfd, entry->d_name, O_RDONLY|O_CLOEXEC);
+ if (fd < 0) {
+ if (r == 0)
+ r = -errno;
+ log_warning_errno(errno, "Failed to open %s: %m", entry->d_name);
+ continue;
+ }
+
+ policy = fdopen(fd, "re");
+ if (!policy) {
+ if (r == 0)
+ r = -errno;
+ safe_close(fd);
+ log_error_errno(errno, "Failed to open %s: %m", entry->d_name);
+ continue;
+ }
+
+ /* load2 write rules in the kernel require a line buffered stream */
+ FOREACH_LINE(buf, policy,
+ log_error_errno(errno, "Failed to read line from %s: %m",
+ entry->d_name)) {
+ if (!fputs(buf, dst)) {
+ if (r == 0)
+ r = -EINVAL;
+ log_error_errno(errno, "Failed to write line to /sys/fs/smackfs/netlabel");
+ break;
+ }
+ if (fflush(dst)) {
+ if (r == 0)
+ r = -errno;
+ log_error_errno(errno, "Failed to flush writes to /sys/fs/smackfs/netlabel: %m");
+ break;
+ }
+ }
+ }
+
+ return r;
+}
+
#endif
int mac_smack_setup(bool *loaded_policy) {
@@ -225,8 +294,18 @@ int mac_smack_setup(bool *loaded_policy) {
#ifdef SMACK_RUN_LABEL
r = write_string_file("/proc/self/attr/current", SMACK_RUN_LABEL, 0);
- if (r)
- log_warning_errno(r, "Failed to set SMACK label \"%s\" on self: %m", SMACK_RUN_LABEL);
+ if (r < 0)
+ log_warning_errno(r, "Failed to set SMACK label \"" SMACK_RUN_LABEL "\" on self: %m");
+ r = write_string_file("/sys/fs/smackfs/ambient", SMACK_RUN_LABEL, 0);
+ if (r < 0)
+ log_warning_errno(r, "Failed to set SMACK ambient label \"" SMACK_RUN_LABEL "\": %m");
+ r = write_string_file("/sys/fs/smackfs/netlabel",
+ "0.0.0.0/0 " SMACK_RUN_LABEL, 0);
+ if (r < 0)
+ log_warning_errno(r, "Failed to set SMACK netlabel rule \"0.0.0.0/0 " SMACK_RUN_LABEL "\": %m");
+ r = write_string_file("/sys/fs/smackfs/netlabel", "127.0.0.1 -CIPSO", 0);
+ if (r < 0)
+ log_warning_errno(r, "Failed to set SMACK netlabel rule \"127.0.0.1 -CIPSO\": %m");
#endif
r = write_cipso2_rules("/etc/smack/cipso.d/");
@@ -236,13 +315,29 @@ int mac_smack_setup(bool *loaded_policy) {
return 0;
case ENOENT:
log_debug("Smack/CIPSO access rules directory '/etc/smack/cipso.d/' not found");
- return 0;
+ break;
case 0:
log_info("Successfully loaded Smack/CIPSO policies.");
break;
default:
log_warning_errno(r, "Failed to load Smack/CIPSO access rules, ignoring: %m");
+ break;
+ }
+
+ r = write_netlabel_rules("/etc/smack/netlabel.d/");
+ switch(r) {
+ case -ENOENT:
+ log_debug("Smack/CIPSO is not enabled in the kernel.");
return 0;
+ case ENOENT:
+ log_debug("Smack network host rules directory '/etc/smack/netlabel.d/' not found");
+ break;
+ case 0:
+ log_info("Successfully loaded Smack network host rules.");
+ break;
+ default:
+ log_warning_errno(r, "Failed to load Smack network host rules: %m, ignoring.");
+ break;
}
*loaded_policy = true;
diff --git a/src/core/socket.c b/src/core/socket.c
index 7beec3644e..f0d65577e3 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -28,9 +28,9 @@
#include <sys/epoll.h>
#include <sys/stat.h>
#include <unistd.h>
+#include <linux/sctp.h>
#include "sd-event.h"
-
#include "alloc-util.h"
#include "bus-error.h"
#include "bus-util.h"
@@ -156,41 +156,41 @@ static void socket_done(Unit *u) {
s->tcp_congestion = mfree(s->tcp_congestion);
s->bind_to_device = mfree(s->bind_to_device);
- free(s->smack);
- free(s->smack_ip_in);
- free(s->smack_ip_out);
+ s->smack = mfree(s->smack);
+ s->smack_ip_in = mfree(s->smack_ip_in);
+ s->smack_ip_out = mfree(s->smack_ip_out);
strv_free(s->symlinks);
- free(s->user);
- free(s->group);
+ s->user = mfree(s->user);
+ s->group = mfree(s->group);
+
+ s->fdname = mfree(s->fdname);
s->timer_event_source = sd_event_source_unref(s->timer_event_source);
}
-static int socket_arm_timer(Socket *s) {
+static int socket_arm_timer(Socket *s, usec_t usec) {
int r;
assert(s);
- if (s->timeout_usec <= 0) {
- s->timer_event_source = sd_event_source_unref(s->timer_event_source);
- return 0;
- }
-
if (s->timer_event_source) {
- r = sd_event_source_set_time(s->timer_event_source, now(CLOCK_MONOTONIC) + s->timeout_usec);
+ r = sd_event_source_set_time(s->timer_event_source, usec);
if (r < 0)
return r;
return sd_event_source_set_enabled(s->timer_event_source, SD_EVENT_ONESHOT);
}
+ if (usec == USEC_INFINITY)
+ return 0;
+
r = sd_event_add_time(
UNIT(s)->manager->event,
&s->timer_event_source,
CLOCK_MONOTONIC,
- now(CLOCK_MONOTONIC) + s->timeout_usec, 0,
+ usec, 0,
socket_dispatch_timer, s);
if (r < 0)
return r;
@@ -875,8 +875,14 @@ static void socket_apply_socket_options(Socket *s, int fd) {
if (s->no_delay) {
int b = s->no_delay;
- if (setsockopt(fd, SOL_TCP, TCP_NODELAY, &b, sizeof(b)) < 0)
- log_unit_warning_errno(UNIT(s), errno, "TCP_NODELAY failed: %m");
+
+ if (s->socket_protocol == IPPROTO_SCTP) {
+ if (setsockopt(fd, SOL_SCTP, SCTP_NODELAY, &b, sizeof(b)) < 0)
+ log_unit_warning_errno(UNIT(s), errno, "SCTP_NODELAY failed: %m");
+ } else {
+ if (setsockopt(fd, SOL_TCP, TCP_NODELAY, &b, sizeof(b)) < 0)
+ log_unit_warning_errno(UNIT(s), errno, "TCP_NODELAY failed: %m");
+ }
}
if (s->broadcast) {
@@ -1486,7 +1492,7 @@ static int socket_coldplug(Unit *u) {
if (r < 0)
return r;
- r = socket_arm_timer(s);
+ r = socket_arm_timer(s, usec_add(u->state_change_timestamp.monotonic, s->timeout_usec));
if (r < 0)
return r;
}
@@ -1499,6 +1505,7 @@ static int socket_coldplug(Unit *u) {
SOCKET_STOP_PRE,
SOCKET_STOP_PRE_SIGTERM,
SOCKET_STOP_PRE_SIGKILL)) {
+
r = socket_open_fds(s);
if (r < 0)
return r;
@@ -1540,15 +1547,15 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
r = unit_setup_exec_runtime(UNIT(s));
if (r < 0)
- goto fail;
+ return r;
- r = socket_arm_timer(s);
+ r = socket_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_usec));
if (r < 0)
- goto fail;
+ return r;
r = unit_full_printf_strv(UNIT(s), c->argv, &argv);
if (r < 0)
- goto fail;
+ return r;
exec_params.argv = argv;
exec_params.environment = UNIT(s)->manager->environment;
@@ -1565,26 +1572,22 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
s->exec_runtime,
&pid);
if (r < 0)
- goto fail;
+ return r;
r = unit_watch_pid(UNIT(s), pid);
if (r < 0)
/* FIXME: we need to do something here */
- goto fail;
+ return r;
*_pid = pid;
return 0;
-
-fail:
- s->timer_event_source = sd_event_source_unref(s->timer_event_source);
- return r;
}
static int socket_chown(Socket *s, pid_t *_pid) {
pid_t pid;
int r;
- r = socket_arm_timer(s);
+ r = socket_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_usec));
if (r < 0)
goto fail;
@@ -1727,7 +1730,7 @@ static void socket_enter_signal(Socket *s, SocketState state, SocketResult f) {
goto fail;
if (r > 0) {
- r = socket_arm_timer(s);
+ r = socket_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_usec));
if (r < 0)
goto fail;
@@ -2767,17 +2770,21 @@ static int socket_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
return unit_kill_common(u, who, signo, -1, SOCKET(u)->control_pid, error);
}
-static int socket_get_timeout(Unit *u, uint64_t *timeout) {
+static int socket_get_timeout(Unit *u, usec_t *timeout) {
Socket *s = SOCKET(u);
+ usec_t t;
int r;
if (!s->timer_event_source)
return 0;
- r = sd_event_source_get_time(s->timer_event_source, timeout);
+ r = sd_event_source_get_time(s->timer_event_source, &t);
if (r < 0)
return r;
+ if (t == USEC_INFINITY)
+ return 0;
+ *timeout = t;
return 1;
}
diff --git a/src/core/swap.c b/src/core/swap.c
index 5568898bd7..b663a029eb 100644
--- a/src/core/swap.c
+++ b/src/core/swap.c
@@ -160,29 +160,27 @@ static void swap_done(Unit *u) {
s->timer_event_source = sd_event_source_unref(s->timer_event_source);
}
-static int swap_arm_timer(Swap *s) {
+static int swap_arm_timer(Swap *s, usec_t usec) {
int r;
assert(s);
- if (s->timeout_usec <= 0) {
- s->timer_event_source = sd_event_source_unref(s->timer_event_source);
- return 0;
- }
-
if (s->timer_event_source) {
- r = sd_event_source_set_time(s->timer_event_source, now(CLOCK_MONOTONIC) + s->timeout_usec);
+ r = sd_event_source_set_time(s->timer_event_source, usec);
if (r < 0)
return r;
return sd_event_source_set_enabled(s->timer_event_source, SD_EVENT_ONESHOT);
}
+ if (usec == USEC_INFINITY)
+ return 0;
+
r = sd_event_add_time(
UNIT(s)->manager->event,
&s->timer_event_source,
CLOCK_MONOTONIC,
- now(CLOCK_MONOTONIC) + s->timeout_usec, 0,
+ usec, 0,
swap_dispatch_timer, s);
if (r < 0)
return r;
@@ -552,7 +550,7 @@ static int swap_coldplug(Unit *u) {
if (r < 0)
return r;
- r = swap_arm_timer(s);
+ r = swap_arm_timer(s, usec_add(u->state_change_timestamp.monotonic, s->timeout_usec));
if (r < 0)
return r;
}
@@ -633,7 +631,7 @@ static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) {
if (r < 0)
goto fail;
- r = swap_arm_timer(s);
+ r = swap_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_usec));
if (r < 0)
goto fail;
@@ -710,7 +708,7 @@ static void swap_enter_signal(Swap *s, SwapState state, SwapResult f) {
goto fail;
if (r > 0) {
- r = swap_arm_timer(s);
+ r = swap_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_usec));
if (r < 0)
goto fail;
@@ -1398,17 +1396,21 @@ static int swap_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
return unit_kill_common(u, who, signo, -1, SWAP(u)->control_pid, error);
}
-static int swap_get_timeout(Unit *u, uint64_t *timeout) {
+static int swap_get_timeout(Unit *u, usec_t *timeout) {
Swap *s = SWAP(u);
+ usec_t t;
int r;
if (!s->timer_event_source)
return 0;
- r = sd_event_source_get_time(s->timer_event_source, timeout);
+ r = sd_event_source_get_time(s->timer_event_source, &t);
if (r < 0)
return r;
+ if (t == USEC_INFINITY)
+ return 0;
+ *timeout = t;
return 1;
}
diff --git a/src/core/transaction.c b/src/core/transaction.c
index 2f163190e9..0d53e4bac0 100644
--- a/src/core/transaction.c
+++ b/src/core/transaction.c
@@ -27,6 +27,7 @@
#include "bus-error.h"
#include "terminal-util.h"
#include "transaction.h"
+#include "dbus-unit.h"
static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependencies);
@@ -860,30 +861,12 @@ int transaction_add_job_and_dependencies(
if (!IN_SET(unit->load_state, UNIT_LOADED, UNIT_ERROR, UNIT_NOT_FOUND, UNIT_MASKED))
return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED, "Unit %s is not loaded properly.", unit->id);
- if (type != JOB_STOP && unit->load_state == UNIT_ERROR) {
- if (unit->load_error == -ENOENT || unit->manager->test_run)
- return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED,
- "Unit %s failed to load: %s.",
- unit->id,
- strerror(-unit->load_error));
- else
- return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED,
- "Unit %s failed to load: %s. "
- "See system logs and 'systemctl status %s' for details.",
- unit->id,
- strerror(-unit->load_error),
- unit->id);
+ if (type != JOB_STOP) {
+ r = bus_unit_check_load_state(unit, e);
+ if (r < 0)
+ return r;
}
- if (type != JOB_STOP && unit->load_state == UNIT_NOT_FOUND)
- return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED,
- "Unit %s failed to load: %s.",
- unit->id, strerror(-unit->load_error));
-
- if (type != JOB_STOP && unit->load_state == UNIT_MASKED)
- return sd_bus_error_setf(e, BUS_ERROR_UNIT_MASKED,
- "Unit %s is masked.", unit->id);
-
if (!unit_job_is_applicable(unit, type))
return sd_bus_error_setf(e, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE,
"Job type %s is not applicable for unit %s.",
@@ -949,9 +932,10 @@ int transaction_add_job_and_dependencies(
SET_FOREACH(dep, ret->unit->dependencies[UNIT_WANTS], i) {
r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, false, false, false, ignore_order, e);
if (r < 0) {
+ /* unit masked and unit not found are not considered as errors. */
log_unit_full(dep,
- r == -EBADR /* unit masked */ ? LOG_DEBUG : LOG_WARNING, r,
- "Cannot add dependency job, ignoring: %s",
+ r == -EBADR || r == -ENOENT ? LOG_DEBUG : LOG_WARNING,
+ r, "Cannot add dependency job, ignoring: %s",
bus_error_message(e, r));
sd_bus_error_free(e);
}
@@ -1026,7 +1010,13 @@ int transaction_add_job_and_dependencies(
if (type == JOB_RELOAD) {
SET_FOREACH(dep, ret->unit->dependencies[UNIT_PROPAGATES_RELOAD_TO], i) {
- r = transaction_add_job_and_dependencies(tr, JOB_RELOAD, dep, ret, false, false, false, ignore_order, e);
+ JobType nt;
+
+ nt = job_type_collapse(JOB_TRY_RELOAD, dep);
+ if (nt == JOB_NOP)
+ continue;
+
+ r = transaction_add_job_and_dependencies(tr, nt, dep, ret, false, false, false, ignore_order, e);
if (r < 0) {
log_unit_warning(dep,
"Cannot add dependency reload job, ignoring: %s",
diff --git a/src/core/unit.c b/src/core/unit.c
index f935b6a601..0c1efc0e16 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -51,6 +51,7 @@
#include "set.h"
#include "special.h"
#include "stat-util.h"
+#include "stdio-util.h"
#include "string-util.h"
#include "strv.h"
#include "unit-name.h"
@@ -98,6 +99,7 @@ Unit *unit_new(Manager *m, size_t size) {
u->unit_file_preset = -1;
u->on_failure_job_mode = JOB_REPLACE;
u->cgroup_inotify_wd = -1;
+ u->job_timeout = USEC_INFINITY;
RATELIMIT_INIT(u->auto_stop_ratelimit, 10 * USEC_PER_SEC, 16);
@@ -868,6 +870,7 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
Iterator i;
const char *prefix2;
char
+ timestamp0[FORMAT_TIMESTAMP_MAX],
timestamp1[FORMAT_TIMESTAMP_MAX],
timestamp2[FORMAT_TIMESTAMP_MAX],
timestamp3[FORMAT_TIMESTAMP_MAX],
@@ -889,6 +892,7 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
"%s\tInstance: %s\n"
"%s\tUnit Load State: %s\n"
"%s\tUnit Active State: %s\n"
+ "%s\nState Change Timestamp: %s\n"
"%s\tInactive Exit Timestamp: %s\n"
"%s\tActive Enter Timestamp: %s\n"
"%s\tActive Exit Timestamp: %s\n"
@@ -906,6 +910,7 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
prefix, strna(u->instance),
prefix, unit_load_state_to_string(u->load_state),
prefix, unit_active_state_to_string(unit_active_state(u)),
+ prefix, strna(format_timestamp(timestamp0, sizeof(timestamp0), u->state_change_timestamp.realtime)),
prefix, strna(format_timestamp(timestamp1, sizeof(timestamp1), u->inactive_exit_timestamp.realtime)),
prefix, strna(format_timestamp(timestamp2, sizeof(timestamp2), u->active_enter_timestamp.realtime)),
prefix, strna(format_timestamp(timestamp3, sizeof(timestamp3), u->active_exit_timestamp.realtime)),
@@ -946,7 +951,7 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
STRV_FOREACH(j, u->dropin_paths)
fprintf(f, "%s\tDropIn Path: %s\n", prefix, *j);
- if (u->job_timeout > 0)
+ if (u->job_timeout != USEC_INFINITY)
fprintf(f, "%s\tJob Timeout: %s\n", prefix, format_timespan(timespan, sizeof(timespan), u->job_timeout, 0));
if (u->job_timeout_action != FAILURE_ACTION_NONE)
@@ -1412,7 +1417,7 @@ static void unit_status_log_starting_stopping_reloading(Unit *u, JobType t) {
format = unit_get_status_message_format(u, t);
DISABLE_WARNING_FORMAT_NONLITERAL;
- snprintf(buf, sizeof(buf), format, unit_description(u));
+ xsprintf(buf, format, unit_description(u));
REENABLE_WARNING;
mid = t == JOB_START ? SD_MESSAGE_UNIT_STARTING :
@@ -1820,19 +1825,17 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
/* Update timestamps for state changes */
if (m->n_reloading <= 0) {
- dual_timestamp ts;
-
- dual_timestamp_get(&ts);
+ dual_timestamp_get(&u->state_change_timestamp);
if (UNIT_IS_INACTIVE_OR_FAILED(os) && !UNIT_IS_INACTIVE_OR_FAILED(ns))
- u->inactive_exit_timestamp = ts;
+ u->inactive_exit_timestamp = u->state_change_timestamp;
else if (!UNIT_IS_INACTIVE_OR_FAILED(os) && UNIT_IS_INACTIVE_OR_FAILED(ns))
- u->inactive_enter_timestamp = ts;
+ u->inactive_enter_timestamp = u->state_change_timestamp;
if (!UNIT_IS_ACTIVE_OR_RELOADING(os) && UNIT_IS_ACTIVE_OR_RELOADING(ns))
- u->active_enter_timestamp = ts;
+ u->active_enter_timestamp = u->state_change_timestamp;
else if (UNIT_IS_ACTIVE_OR_RELOADING(os) && !UNIT_IS_ACTIVE_OR_RELOADING(ns))
- u->active_exit_timestamp = ts;
+ u->active_exit_timestamp = u->state_change_timestamp;
}
/* Keep track of failed units */
@@ -1893,6 +1896,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
case JOB_RELOAD:
case JOB_RELOAD_OR_START:
+ case JOB_TRY_RELOAD:
if (u->job->state == JOB_RUNNING) {
if (ns == UNIT_ACTIVE)
@@ -2106,6 +2110,7 @@ bool unit_job_is_applicable(Unit *u, JobType j) {
return unit_can_start(u);
case JOB_RELOAD:
+ case JOB_TRY_RELOAD:
return unit_can_reload(u);
case JOB_RELOAD_OR_START:
@@ -2550,10 +2555,13 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) {
}
}
+ dual_timestamp_serialize(f, "state-change-timestamp", &u->state_change_timestamp);
+
dual_timestamp_serialize(f, "inactive-exit-timestamp", &u->inactive_exit_timestamp);
dual_timestamp_serialize(f, "active-enter-timestamp", &u->active_enter_timestamp);
dual_timestamp_serialize(f, "active-exit-timestamp", &u->active_exit_timestamp);
dual_timestamp_serialize(f, "inactive-enter-timestamp", &u->inactive_enter_timestamp);
+
dual_timestamp_serialize(f, "condition-timestamp", &u->condition_timestamp);
dual_timestamp_serialize(f, "assert-timestamp", &u->assert_timestamp);
@@ -2692,7 +2700,7 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
/* End marker */
if (isempty(l))
- return 0;
+ break;
k = strcspn(l, "=");
@@ -2732,6 +2740,9 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
} else /* legacy for pre-44 */
log_unit_warning(u, "Update from too old systemd versions are unsupported, cannot deserialize job: %s", v);
continue;
+ } else if (streq(l, "state-change-timestamp")) {
+ dual_timestamp_deserialize(v, &u->state_change_timestamp);
+ continue;
} else if (streq(l, "inactive-exit-timestamp")) {
dual_timestamp_deserialize(v, &u->inactive_exit_timestamp);
continue;
@@ -2838,6 +2849,15 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
log_unit_warning(u, "Failed to deserialize unit parameter '%s', ignoring.", l);
}
}
+
+ /* Versions before 228 did not carry a state change timestamp. In this case, take the current time. This is
+ * useful, so that timeouts based on this timestamp don't trigger too early, and is in-line with the logic from
+ * before 228 where the base for timeouts was not peristet across reboots. */
+
+ if (!dual_timestamp_is_set(&u->state_change_timestamp))
+ dual_timestamp_get(&u->state_change_timestamp);
+
+ return 0;
}
int unit_add_node_link(Unit *u, const char *what, bool wants, UnitDependency dep) {
@@ -3119,7 +3139,7 @@ int unit_kill_common(
killed = true;
}
- if (r == 0 && !killed && IN_SET(who, KILL_ALL_FAIL, KILL_CONTROL_FAIL, KILL_ALL_FAIL))
+ if (r == 0 && !killed && IN_SET(who, KILL_ALL_FAIL, KILL_CONTROL_FAIL))
return -ESRCH;
return r;
@@ -3231,7 +3251,7 @@ int unit_patch_contexts(Unit *u) {
ec->no_new_privileges = true;
if (ec->private_devices)
- ec->capability_bounding_set_drop |= (uint64_t) 1ULL << (uint64_t) CAP_MKNOD;
+ ec->capability_bounding_set &= ~(UINT64_C(1) << CAP_MKNOD);
}
cc = unit_get_cgroup_context(u);
diff --git a/src/core/unit.h b/src/core/unit.h
index 3eb3484fb7..8712e03133 100644
--- a/src/core/unit.h
+++ b/src/core/unit.h
@@ -121,6 +121,10 @@ struct Unit {
dual_timestamp condition_timestamp;
dual_timestamp assert_timestamp;
+ /* Updated whenever the low-level state changes */
+ dual_timestamp state_change_timestamp;
+
+ /* Updated whenever the (high-level) active state enters or leaves the active or inactive states */
dual_timestamp inactive_exit_timestamp;
dual_timestamp active_enter_timestamp;
dual_timestamp active_exit_timestamp;
@@ -375,7 +379,8 @@ struct UnitVTable {
/* Called whenever CLOCK_REALTIME made a jump */
void (*time_change)(Unit *u);
- int (*get_timeout)(Unit *u, uint64_t *timeout);
+ /* Returns the next timeout of a unit */
+ int (*get_timeout)(Unit *u, usec_t *timeout);
/* This is called for each unit type and should be used to
* enumerate existing devices and load them. However,