1
0
mirror of https://github.com/systemd/systemd synced 2026-03-09 06:34:45 +01:00

Compare commits

..

No commits in common. "f9dbf6fd5a4a0220e3166f938dfffa80f0ec2047" and "710742270bf9343a36c7cae382f04fd5e8073ce8" have entirely different histories.

21 changed files with 292 additions and 428 deletions

View File

@ -970,6 +970,53 @@ int getpeerpidref(int fd, PidRef *ret) {
return pidref_set_pidfd_consume(ret, pidfd);
}
ssize_t send_many_fds_iov_sa(
int transport_fd,
int *fds_array, size_t n_fds_array,
const struct iovec *iov, size_t iovlen,
const struct sockaddr *sa, socklen_t len,
int flags) {
_cleanup_free_ struct cmsghdr *cmsg = NULL;
struct msghdr mh = {
.msg_name = (struct sockaddr*) sa,
.msg_namelen = len,
.msg_iov = (struct iovec *)iov,
.msg_iovlen = iovlen,
};
ssize_t k;
assert(transport_fd >= 0);
assert(fds_array || n_fds_array == 0);
/* The kernel will reject sending more than SCM_MAX_FD FDs at once */
if (n_fds_array > SCM_MAX_FD)
return -E2BIG;
/* We need either an FD array or data to send. If there's nothing, return an error. */
if (n_fds_array == 0 && !iov)
return -EINVAL;
if (n_fds_array > 0) {
mh.msg_controllen = CMSG_SPACE(sizeof(int) * n_fds_array);
mh.msg_control = cmsg = malloc(mh.msg_controllen);
if (!cmsg)
return -ENOMEM;
*cmsg = (struct cmsghdr) {
.cmsg_len = CMSG_LEN(sizeof(int) * n_fds_array),
.cmsg_level = SOL_SOCKET,
.cmsg_type = SCM_RIGHTS,
};
memcpy(CMSG_DATA(cmsg), fds_array, sizeof(int) * n_fds_array);
}
k = sendmsg(transport_fd, &mh, MSG_NOSIGNAL | flags);
if (k < 0)
return (ssize_t) -errno;
return k;
}
ssize_t send_one_fd_iov_sa(
int transport_fd,
int fd,
@ -1025,6 +1072,74 @@ int send_one_fd_sa(
return (int) send_one_fd_iov_sa(transport_fd, fd, NULL, 0, sa, len, flags);
}
ssize_t receive_many_fds_iov(
int transport_fd,
struct iovec *iov, size_t iovlen,
int **ret_fds_array, size_t *ret_n_fds_array,
int flags) {
CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(int) * SCM_MAX_FD)) control;
struct msghdr mh = {
.msg_control = &control,
.msg_controllen = sizeof(control),
.msg_iov = iov,
.msg_iovlen = iovlen,
};
_cleanup_free_ int *fds_array = NULL;
size_t n_fds_array = 0;
struct cmsghdr *cmsg;
ssize_t k;
assert(transport_fd >= 0);
assert(ret_fds_array);
assert(ret_n_fds_array);
/*
* Receive many FDs via @transport_fd. We don't care for the transport-type. We retrieve all the FDs
* at once. This is best used in combination with send_many_fds().
*/
k = recvmsg_safe(transport_fd, &mh, MSG_CMSG_CLOEXEC | flags);
if (k < 0)
return k;
CMSG_FOREACH(cmsg, &mh)
if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
size_t n = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
if (!GREEDY_REALLOC_APPEND(fds_array, n_fds_array, CMSG_TYPED_DATA(cmsg, int), n)) {
cmsg_close_all(&mh);
return -ENOMEM;
}
}
if (n_fds_array == 0) {
cmsg_close_all(&mh);
/* If didn't receive an FD or any data, return an error. */
if (k == 0)
return -EIO;
}
*ret_fds_array = TAKE_PTR(fds_array);
*ret_n_fds_array = n_fds_array;
return k;
}
int receive_many_fds(int transport_fd, int **ret_fds_array, size_t *ret_n_fds_array, int flags) {
ssize_t k;
k = receive_many_fds_iov(transport_fd, NULL, 0, ret_fds_array, ret_n_fds_array, flags);
if (k == 0)
return 0;
/* k must be negative, since receive_many_fds_iov() only returns a positive value if data was received
* through the iov. */
assert(k < 0);
return (int) k;
}
ssize_t receive_one_fd_iov(
int transport_fd,
struct iovec *iov, size_t iovlen,

View File

@ -120,6 +120,28 @@ int getpeergroups(int fd, gid_t **ret);
int getpeerpidfd(int fd);
int getpeerpidref(int fd, PidRef *ret);
ssize_t send_many_fds_iov_sa(
int transport_fd,
int *fds_array, size_t n_fds_array,
const struct iovec *iov, size_t iovlen,
const struct sockaddr *sa, socklen_t len,
int flags);
static inline ssize_t send_many_fds_iov(
int transport_fd,
int *fds_array, size_t n_fds_array,
const struct iovec *iov, size_t iovlen,
int flags) {
return send_many_fds_iov_sa(transport_fd, fds_array, n_fds_array, iov, iovlen, NULL, 0, flags);
}
static inline int send_many_fds(
int transport_fd,
int *fds_array,
size_t n_fds_array,
int flags) {
return send_many_fds_iov_sa(transport_fd, fds_array, n_fds_array, NULL, 0, NULL, 0, flags);
}
ssize_t send_one_fd_iov_sa(
int transport_fd,
int fd,
@ -134,6 +156,8 @@ int send_one_fd_sa(int transport_fd,
#define send_one_fd(transport_fd, fd, flags) send_one_fd_iov_sa(transport_fd, fd, NULL, 0, NULL, 0, flags)
ssize_t receive_one_fd_iov(int transport_fd, struct iovec *iov, size_t iovlen, int flags, int *ret_fd);
int receive_one_fd(int transport_fd, int flags);
ssize_t receive_many_fds_iov(int transport_fd, struct iovec *iov, size_t iovlen, int **ret_fds_array, size_t *ret_n_fds_array, int flags);
int receive_many_fds(int transport_fd, int **ret_fds_array, size_t *ret_n_fds_array, int flags);
ssize_t next_datagram_size_fd(int fd);
@ -179,7 +203,9 @@ void* cmsg_find_and_copy_data(struct msghdr *mh, int level, int type, void *buf,
}
size_t sockaddr_ll_len(const struct sockaddr_ll *sa);
size_t sockaddr_un_len(const struct sockaddr_un *sa);
size_t sockaddr_len(const union sockaddr_union *sa);
int socket_ioctl_fd(void);

View File

@ -2121,6 +2121,7 @@ static int bus_unit_set_live_property(
for (;;) {
const char *word;
bool b;
r = sd_bus_message_read(message, "s", &word);
if (r < 0)
@ -2128,14 +2129,22 @@ static int bus_unit_set_live_property(
if (r == 0)
break;
r = parse_unit_marker(word, &settings, &mask);
if (r < 0)
if (IN_SET(word[0], '+', '-')) {
b = word[0] == '+';
word++;
some_plus_minus = true;
} else {
b = true;
some_absolute = true;
}
UnitMarker m = unit_marker_from_string(word);
if (m < 0)
return sd_bus_error_setf(reterr_error, BUS_ERROR_BAD_UNIT_SETTING,
"Unknown marker \"%s\".", word);
if (r > 0)
some_plus_minus = true;
else
some_absolute = true;
SET_FLAG(settings, 1u << m, b);
SET_FLAG(mask, 1u << m, true);
}
r = sd_bus_message_exit_container(message);

View File

@ -7058,26 +7058,3 @@ int unit_queue_job_check_and_mangle_type(
return 0;
}
int parse_unit_marker(const char *marker, unsigned *settings, unsigned *mask) {
bool some_plus_minus = false, b = true;
assert(marker);
assert(settings);
assert(mask);
if (IN_SET(marker[0], '+', '-')) {
b = marker[0] == '+';
marker++;
some_plus_minus = true;
}
UnitMarker m = unit_marker_from_string(marker);
if (m < 0)
return -EINVAL;
SET_FLAG(*settings, 1u << m, b);
SET_FLAG(*mask, 1u << m, true);
return some_plus_minus;
}

View File

@ -1094,8 +1094,6 @@ DECLARE_STRING_TABLE_LOOKUP(oom_policy, OOMPolicy);
int unit_queue_job_check_and_mangle_type(Unit *u, JobType *type, bool reload_if_possible, sd_bus_error *reterr_error);
int parse_unit_marker(const char *marker, unsigned *settings, unsigned *mask);
/* Macros which append UNIT= or USER_UNIT= to the message */
#define log_unit_full_errno_zerook(unit, level, error, ...) \

View File

@ -361,40 +361,6 @@ static int lookup_unit_by_pidref(sd_varlink *link, Manager *manager, PidRef *pid
return 0;
}
static int load_unit_and_check(sd_varlink *link, Manager *manager, const char *name, Unit **ret_unit) {
Unit *unit;
int r;
assert(link);
assert(manager);
assert(name);
assert(ret_unit);
r = manager_load_unit(manager, name, /* path= */ NULL, /* e= */ NULL, &unit);
if (r < 0)
return r;
/* manager_load_unit() will create an object regardless of whether the unit actually exists, so
* check the state and refuse if it's not in a good state. */
if (IN_SET(unit->load_state, UNIT_NOT_FOUND, UNIT_STUB, UNIT_MERGED))
return sd_varlink_error(link, "io.systemd.Unit.NoSuchUnit", NULL);
if (unit->load_state == UNIT_BAD_SETTING)
return sd_varlink_error(link, "io.systemd.Unit.UnitError", NULL);
if (unit->load_state == UNIT_ERROR)
return sd_varlink_errorbo(
link,
SD_VARLINK_ERROR_SYSTEM,
SD_JSON_BUILD_PAIR_STRING("origin", "linux"),
SD_JSON_BUILD_PAIR_INTEGER("errno", unit->load_error),
JSON_BUILD_PAIR_STRING_NON_EMPTY("errnoName", "io.systemd.Unit.UnitError"));
if (unit->load_state == UNIT_MASKED)
return sd_varlink_error(link, "io.systemd.Unit.UnitMasked", NULL);
assert(UNIT_IS_LOAD_COMPLETE(unit->load_state));
*ret_unit = unit;
return 0;
}
typedef struct UnitLookupParameters {
const char *name, *cgroup;
PidRef pidref;
@ -434,9 +400,9 @@ static int lookup_unit_by_parameters(
assert(ret);
if (p->name) {
r = load_unit_and_check(link, manager, p->name, &unit);
if (r < 0)
return r;
unit = manager_get_unit(manager, p->name);
if (!unit)
return varlink_error_no_such_unit(link, "name");
}
if (pidref_is_set_or_automatic(&p->pidref)) {
@ -568,107 +534,3 @@ int varlink_error_no_such_unit(sd_varlink *v, const char *name) {
VARLINK_ERROR_UNIT_NO_SUCH_UNIT,
JSON_BUILD_PAIR_STRING_NON_EMPTY("parameter", name));
}
typedef struct UnitSetPropertiesParameters {
const char *unsupported_property; /* For error reporting */
const char *name;
bool runtime;
bool markers_found;
unsigned markers, markers_mask;
} UnitSetPropertiesParameters;
static int parse_unit_markers(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
UnitSetPropertiesParameters *p = ASSERT_PTR(userdata);
bool some_plus_minus = false, some_absolute = false;
unsigned settings = 0, mask = 0;
sd_json_variant *e;
int r;
assert(variant);
JSON_VARIANT_ARRAY_FOREACH(e, variant) {
if (!sd_json_variant_is_string(e))
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "Marker is not an array of strings.");
const char *word = sd_json_variant_string(e);
r = parse_unit_marker(word, &settings, &mask);
if (r < 0)
return json_log(variant, flags, r, "Failed to parse marker '%s'.", word);
if (r > 0)
some_plus_minus = true;
else
some_absolute = true;
}
if (some_plus_minus && some_absolute)
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "Absolute and non-absolute markers in the same setting.");
if (some_absolute || sd_json_variant_elements(variant) == 0)
mask = UINT_MAX;
p->markers = settings;
p->markers_mask = mask;
p->markers_found = true;
return 0;
}
static int unit_dispatch_properties(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
static const sd_json_dispatch_field dispatch_table[] = {
{ "Markers", SD_JSON_VARIANT_ARRAY, parse_unit_markers, 0, 0 },
{}
};
UnitSetPropertiesParameters *p = ASSERT_PTR(userdata);
const char *bad_field = NULL;
int r;
r = sd_json_dispatch_full(variant, dispatch_table, /* bad= */ NULL, flags, userdata, &bad_field);
if (r == -EADDRNOTAVAIL && !isempty(bad_field))
/* When properties contains a valid field, but that we don't currently support, make sure to
* return the offending property, rather than generic invalid argument. */
p->unsupported_property = bad_field;
return r;
}
int vl_method_set_unit_properties(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
static const sd_json_dispatch_field dispatch_table[] = {
{ "name", SD_JSON_VARIANT_STRING, json_dispatch_const_unit_name, offsetof(UnitSetPropertiesParameters, name), SD_JSON_MANDATORY },
{ "runtime", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(UnitSetPropertiesParameters, runtime), SD_JSON_MANDATORY },
{ "properties", SD_JSON_VARIANT_OBJECT, unit_dispatch_properties, 0, SD_JSON_MANDATORY },
{}
};
UnitSetPropertiesParameters p = {};
Manager *manager = ASSERT_PTR(userdata);
const char *bad_field = NULL;
Unit *unit;
int r;
assert(link);
assert(parameters);
r = sd_json_dispatch_full(parameters, dispatch_table, /* bad= */ NULL, /* flags= */ 0, &p, &bad_field);
if (r < 0) {
/* When properties contains a valid field, but that we don't currently support, make sure to
* return a specific error, rather than generic invalid argument. */
if (streq_ptr(bad_field, "properties") && r == -EADDRNOTAVAIL)
return sd_varlink_errorbo(
link,
"io.systemd.Unit.PropertyNotSupported",
SD_JSON_BUILD_PAIR_CONDITION(!!p.unsupported_property, "property", SD_JSON_BUILD_STRING(p.unsupported_property)));
if (bad_field)
return sd_varlink_error_invalid_parameter_name(link, bad_field);
return r;
}
r = load_unit_and_check(link, manager, p.name, &unit);
if (r < 0)
return r;
if (p.markers_found)
unit->markers = p.markers | (unit->markers & ~p.markers_mask);
return sd_varlink_reply(link, NULL);
}

View File

@ -17,6 +17,4 @@ int varlink_unit_queue_job_one(
uint32_t *ret_job_id,
sd_bus_error *reterr_bus_error);
int vl_method_set_unit_properties(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata);
int varlink_error_no_such_unit(sd_varlink *v, const char *name);

View File

@ -391,7 +391,6 @@ int manager_setup_varlink_server(Manager *m) {
"io.systemd.Manager.Reload", vl_method_reload_manager,
"io.systemd.Manager.EnqueueMarkedJobs", vl_method_enqueue_marked_jobs_manager,
"io.systemd.Unit.List", vl_method_list_units,
"io.systemd.Unit.SetProperties", vl_method_set_unit_properties,
"io.systemd.service.Ping", varlink_method_ping,
"io.systemd.service.GetEnvironment", varlink_method_get_environment);
if (r < 0)

View File

@ -4,7 +4,6 @@
#include "alloc-util.h"
#include "bus-control.h"
#include "bus-error.h"
#include "bus-internal.h"
#include "bus-message.h"
#include "fd-util.h"
@ -137,14 +136,11 @@ static int default_request_name_handler(
assert(m);
if (sd_bus_message_is_method_error(m, NULL)) {
const sd_bus_error *e = ASSERT_PTR(sd_bus_message_get_error(m));
r = sd_bus_error_get_errno(e);
log_debug_errno(r,
log_debug_errno(sd_bus_message_get_errno(m),
"Unable to request name, failing connection: %s",
bus_error_message(e, r));
sd_bus_message_get_error(m)->message);
bus_enter_closing(sd_bus_message_get_bus(m), -r);
bus_enter_closing(sd_bus_message_get_bus(m), -sd_bus_message_get_errno(m));
return 1;
}
@ -294,12 +290,11 @@ static int default_release_name_handler(
assert(m);
if (sd_bus_message_is_method_error(m, NULL)) {
const sd_bus_error *e = ASSERT_PTR(sd_bus_message_get_error(m));
r = sd_bus_error_get_errno(e);
log_debug_errno(sd_bus_message_get_errno(m),
"Unable to release name, failing connection: %s",
sd_bus_message_get_error(m)->message);
log_debug_errno(r, "Unable to release name, failing connection: %s", bus_error_message(e, r));
bus_enter_closing(sd_bus_message_get_bus(m), -r);
bus_enter_closing(sd_bus_message_get_bus(m), -sd_bus_message_get_errno(m));
return 1;
}

View File

@ -3483,13 +3483,10 @@ static int add_match_callback(
sd_bus_slot_ref(match_slot);
if (sd_bus_message_is_method_error(m, NULL)) {
const sd_bus_error *e = ASSERT_PTR(sd_bus_message_get_error(m));
r = sd_bus_error_get_errno(e);
r = log_debug_errno(r,
r = log_debug_errno(sd_bus_message_get_errno(m),
"Unable to add match %s, failing connection: %s",
match_slot->match_callback.match_string,
bus_error_message(e, r));
sd_bus_message_get_error(m)->message);
failed = true;
} else

View File

@ -109,16 +109,16 @@ static int map_dns(
void *userdata) {
Bearer *b = ASSERT_PTR(userdata);
struct in_addr_full *a;
const char *s;
int r;
assert(m);
const char *s;
r = sd_bus_message_read_basic(m, 's', &s);
if (r < 0)
return r;
_cleanup_free_ struct in_addr_full *a = NULL;
r = in_addr_full_new_from_string(s, &a);
if (r < 0)
return r;
@ -127,6 +127,7 @@ static int map_dns(
return -ENOMEM;
b->dns[b->n_dns++] = TAKE_PTR(a);
return 0;
}
@ -476,16 +477,18 @@ static int bearer_new_and_initialize(Modem *modem, const char *path) {
static int modem_connect_handler(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) {
Modem *modem = ASSERT_PTR(userdata);
const sd_bus_error *e;
const char *new_bearer;
int r;
assert(message);
modem->slot_connect = sd_bus_slot_unref(modem->slot_connect);
const sd_bus_error *e = sd_bus_message_get_error(message);
e = sd_bus_message_get_error(message);
if (e) {
r = sd_bus_error_get_errno(e);
log_error_errno(r,
log_full_errno(LOG_ERR, r,
"Could not connect modem %s %s: %s",
modem->manufacturer, modem->model,
bus_error_message(e, r));
@ -494,16 +497,10 @@ static int modem_connect_handler(sd_bus_message *message, void *userdata, sd_bus
return 0;
}
const char *new_bearer;
r = sd_bus_message_read(message, "o", &new_bearer);
if (r < 0) {
log_debug_errno(r, "Received connection of %s %s from ModemManager, but bearer not found, ignoring: %m",
modem->manufacturer, modem->model);
return 0;
}
sd_bus_message_read(message, "o", &new_bearer);
log_debug("ModemManager: %s %s connected, bearer is at %s",
modem->manufacturer, modem->model, new_bearer);
return 0;
}

View File

@ -1,7 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <linux/magic.h>
#include <sched.h>
#include <sys/mount.h>
#include <unistd.h>
@ -1492,7 +1491,7 @@ static int do_wipe_fully_visible_api_fs(void) {
int wipe_fully_visible_api_fs(int mntns_fd) {
_cleanup_close_ int orig_mntns_fd = -EBADF;
int r;
int r, rr;
log_debug("Wiping fully visible API FS");
@ -1500,13 +1499,23 @@ int wipe_fully_visible_api_fs(int mntns_fd) {
if (orig_mntns_fd < 0)
return log_error_errno(orig_mntns_fd, "Failed to pin originating mount namespace: %m");
if (setns(mntns_fd, CLONE_NEWNS) < 0)
return log_error_errno(errno, "Failed to enter mount namespace: %m");
r = namespace_enter(/* pidns_fd= */ -EBADF,
mntns_fd,
/* netns_fd= */ -EBADF,
/* userns_fd= */ -EBADF,
/* root_fd= */ -EBADF);
if (r < 0)
return log_error_errno(r, "Failed to enter mount namespace: %m");
r = do_wipe_fully_visible_api_fs();
rr = do_wipe_fully_visible_api_fs();
if (setns(orig_mntns_fd, CLONE_NEWNS) < 0)
return log_error_errno(errno, "Failed to enter original mount namespace: %m");
r = namespace_enter(/* pidns_fd= */ -EBADF,
orig_mntns_fd,
/* netns_fd= */ -EBADF,
/* userns_fd= */ -EBADF,
/* root_fd= */ -EBADF);
if (r < 0)
return log_error_errno(r, "Failed to enter original mount namespace: %m");
return r;
return rr;
}

View File

@ -241,7 +241,7 @@ static int recursively_get_cgroup_context(Hashmap *new_h, const char *path) {
return r;
if (r < 0) {
log_debug_errno(r, "Failed to read memory.oom.group from %s, ignoring: %m", cg_path);
continue;
return 0;
}
if (r > 0)
r = oomd_insert_cgroup_context(NULL, new_h, cg_path);
@ -416,7 +416,7 @@ static int monitor_swap_contexts_handler(sd_event_source *s, uint64_t usec, void
return 0;
}
r = oomd_cgroup_kill_mark(m, selected, "memory-used");
r = oomd_cgroup_kill_mark(m, selected);
if (r == -ENOMEM)
return log_oom();
if (r < 0)
@ -531,28 +531,28 @@ static int monitor_memory_pressure_contexts_handler(sd_event_source *s, uint64_t
return log_error_errno(r, "Failed to select any cgroups based on swap, ignoring: %m");
if (r == 0) {
log_debug("No cgroup candidates found for memory pressure-based OOM action for %s", t->path);
continue;
return 0;
}
r = oomd_cgroup_kill_mark(m, selected, "memory-pressure");
r = oomd_cgroup_kill_mark(m, selected);
if (r == -ENOMEM)
return log_oom();
if (r < 0)
log_error_errno(r, "Failed to select any cgroups under %s based on pressure, ignoring: %m", t->path);
else if (r == 0)
/* Already queued for kill by an earlier iteration, try next target without
* resetting the delay timer. */
continue;
else {
/* Don't act on all the high pressure cgroups at once; return as soon as we kill one. */
/* Don't act on all the high pressure cgroups at once; return as soon as we kill one.
* If r == 0 then the cgroup is already queued for kill by an earlier iteration.
* In either case, go through the event loop again and select a new candidate if
* pressure is still high. */
m->mem_pressure_post_action_delay_start = usec_now;
if (selected)
if (selected && r > 0) {
log_notice("Marked %s for killing due to memory pressure for %s being %lu.%02lu%% > %lu.%02lu%%"
" for > %s with reclaim activity",
selected->path, t->path,
LOADAVG_INT_SIDE(t->memory_pressure.avg10), LOADAVG_DECIMAL_SIDE(t->memory_pressure.avg10),
LOADAVG_INT_SIDE(t->mem_pressure_limit), LOADAVG_DECIMAL_SIDE(t->mem_pressure_limit),
FORMAT_TIMESPAN(t->mem_pressure_duration_usec, USEC_PER_SEC));
}
return 0;
}
}

View File

@ -27,7 +27,6 @@
typedef struct OomdKillState {
Manager *manager;
OomdCGroupContext *ctx;
const char *reason;
/* This holds sd_varlink references */
Set *links;
} OomdKillState;
@ -246,12 +245,11 @@ int oomd_sort_cgroup_contexts(Hashmap *h, oomd_compare_t compare_func, const cha
return (int) k;
}
int oomd_cgroup_kill(Manager *m, OomdCGroupContext *ctx, bool recurse, const char *reason) {
int oomd_cgroup_kill(Manager *m, OomdCGroupContext *ctx, bool recurse) {
_cleanup_set_free_ Set *pids_killed = NULL;
int r;
assert(ctx);
assert(!m || reason);
pids_killed = set_new(NULL);
if (!pids_killed)
@ -290,7 +288,7 @@ int oomd_cgroup_kill(Manager *m, OomdCGroupContext *ctx, bool recurse, const cha
"Killed",
"ss",
ctx->path,
reason);
"oom");
return !set_isempty(pids_killed);
}
@ -336,7 +334,7 @@ static void oomd_kill_state_remove(OomdKillState *ks) {
if (!set_isempty(ks->links))
return;
r = oomd_cgroup_kill(ks->manager, ks->ctx, /* recurse= */ true, ks->reason);
r = oomd_cgroup_kill(ks->manager, ks->ctx, /* recurse= */ true);
if (r < 0)
log_debug_errno(r, "Failed to kill cgroup '%s', ignoring: %m", ks->ctx->path);
oomd_kill_state_free(ks);
@ -467,12 +465,11 @@ static int oomd_prekill_hook(Manager *m, OomdKillState *ks) {
return 0;
}
int oomd_cgroup_kill_mark(Manager *m, OomdCGroupContext *ctx, const char *reason) {
int oomd_cgroup_kill_mark(Manager *m, OomdCGroupContext *ctx) {
int r;
assert(ctx);
assert(m);
assert(reason);
if (m->dry_run) {
_cleanup_free_ char *cg_path = NULL;
@ -492,7 +489,6 @@ int oomd_cgroup_kill_mark(Manager *m, OomdCGroupContext *ctx, const char *reason
*ks = (OomdKillState) {
.manager = m,
.ctx = oomd_cgroup_context_ref(ctx),
.reason = reason,
};
r = set_ensure_put(&m->kill_states, &oomd_kill_state_hash_ops, ks);

View File

@ -124,8 +124,8 @@ int oomd_sort_cgroup_contexts(Hashmap *h, oomd_compare_t compare_func, const cha
int oomd_fetch_cgroup_oom_preference(OomdCGroupContext *ctx, const char *prefix);
/* Returns a negative value on error, 0 if no processes were killed, or 1 if processes were killed. */
int oomd_cgroup_kill(Manager *m, OomdCGroupContext *ctx, bool recurse, const char *reason);
int oomd_cgroup_kill_mark(Manager *m, OomdCGroupContext *ctx, const char *reason);
int oomd_cgroup_kill(Manager *m, OomdCGroupContext *ctx, bool recurse);
int oomd_cgroup_kill_mark(Manager *m, OomdCGroupContext *ctx);
/* The following oomd_kill_by_* functions return 1 if processes were killed, or negative otherwise. */
/* If `prefix` is supplied, only cgroups whose paths start with `prefix` are eligible candidates. Otherwise,

View File

@ -1,25 +1,20 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <stdlib.h>
#include <sys/socket.h>
#include <unistd.h>
#include "sd-bus.h"
#include "alloc-util.h"
#include "cgroup-setup.h"
#include "cgroup-util.h"
#include "errno-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "oomd-manager.h"
#include "oomd-util.h"
#include "parse-util.h"
#include "path-util.h"
#include "pidref.h"
#include "process-util.h"
#include "set.h"
#include "string-util.h"
#include "tests.h"
#include "time-util.h"
#include "tmpfile-util.h"
@ -64,103 +59,6 @@ static int fork_and_sleep(unsigned sleep_min, PidRef *ret) {
return r;
}
static int setup_local_oomd_bus(sd_bus **ret_server, sd_bus **ret_client) {
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *server = NULL, *client = NULL;
_cleanup_close_pair_ int pair[2] = EBADF_PAIR;
int r;
assert(ret_server);
assert(ret_client);
r = socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, pair);
if (r < 0)
return -errno;
r = sd_bus_new(&server);
if (r < 0)
return r;
r = sd_bus_set_fd(server, pair[0], pair[0]);
if (r < 0)
return r;
pair[0] = -EBADF;
r = sd_bus_set_server(server, true, SD_ID128_NULL);
if (r < 0)
return r;
r = sd_bus_set_anonymous(server, true);
if (r < 0)
return r;
r = sd_bus_start(server);
if (r < 0)
return r;
r = sd_bus_new(&client);
if (r < 0)
return r;
r = sd_bus_set_fd(client, pair[1], pair[1]);
if (r < 0)
return r;
pair[1] = -EBADF;
r = sd_bus_set_anonymous(client, true);
if (r < 0)
return r;
r = sd_bus_start(client);
if (r < 0)
return r;
*ret_server = TAKE_PTR(server);
*ret_client = TAKE_PTR(client);
return 0;
}
static int wait_for_killed_signal(sd_bus *server, sd_bus *client, const char *cgroup_path, const char *reason) {
int r;
assert(server);
assert(client);
assert(cgroup_path);
assert(reason);
for (size_t i = 0; i < 200; i++) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m_client = NULL;
r = sd_bus_process(server, NULL);
if (r < 0)
return r;
r = sd_bus_process(client, &m_client);
if (r < 0)
return r;
if (m_client && sd_bus_message_is_signal(m_client, "org.freedesktop.oom1.Manager", "Killed")) {
const char *got_cgroup, *got_reason;
r = sd_bus_message_read(m_client, "ss", &got_cgroup, &got_reason);
if (r < 0)
return r;
if (!streq(got_cgroup, cgroup_path))
return -ENOMSG;
if (!streq(got_reason, reason))
return -ENOMSG;
return 0;
}
r = sd_bus_wait(client, 50 * USEC_PER_MSEC);
if (r < 0)
return r;
}
return -ETIMEDOUT;
}
TEST(oomd_cgroup_kill) {
_cleanup_free_ char *subcgroup = NULL;
int r;
@ -190,11 +88,7 @@ TEST(oomd_cgroup_kill) {
ASSERT_OK(fork_and_sleep(5, &two));
ASSERT_OK(cg_attach(subcgroup, two.pid));
ASSERT_OK_POSITIVE(oomd_cgroup_kill(
/* m= */ NULL,
&(OomdCGroupContext){ .path = subcgroup },
/* recurse= */ false,
/* reason= */ NULL));
ASSERT_OK_POSITIVE(oomd_cgroup_kill(NULL /* manager */, &(OomdCGroupContext){ .path = subcgroup }, false /* recurse */));
ASSERT_OK(cg_get_xattr(subcgroup, "user.oomd_ooms", &v, /* ret_size= */ NULL));
ASSERT_STREQ(v, i == 0 ? "1" : "2");
@ -219,54 +113,6 @@ TEST(oomd_cgroup_kill) {
ASSERT_OK(cg_trim(subcgroup, /* delete_root */ true));
}
TEST(oomd_cgroup_kill_signal_reason) {
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *server = NULL, *client = NULL;
_cleanup_free_ char *subcgroup = NULL;
static const char *reasons[] = {
"memory-used",
"memory-pressure",
};
Manager m = {};
int r;
r = enter_cgroup_root_cached();
if (r < 0)
return (void) log_tests_skipped_errno(r, "Failed to enter cgroup root");
ASSERT_NOT_NULL(subcgroup = path_join(cgroup, "oomdkillsignaltest"));
ASSERT_OK(cg_trim(subcgroup, /* delete_root= */ true));
ASSERT_OK(cg_create(subcgroup));
ASSERT_OK(setup_local_oomd_bus(&server, &client));
m.bus = server;
for (size_t i = 0; i < ELEMENTSOF(reasons); i++) {
_cleanup_(pidref_done) PidRef one = PIDREF_NULL, two = PIDREF_NULL;
const char *reason = reasons[i];
ASSERT_OK(fork_and_sleep(5, &one));
ASSERT_OK(cg_attach(subcgroup, one.pid));
ASSERT_OK(fork_and_sleep(5, &two));
ASSERT_OK(cg_attach(subcgroup, two.pid));
ASSERT_OK_POSITIVE(oomd_cgroup_kill(&m, &(OomdCGroupContext) { .path = subcgroup }, /* recurse= */ false, reason));
ASSERT_OK(wait_for_killed_signal(server, client, subcgroup, reason));
/* Cleanup isn't instantaneous, so give it some grace */
bool empty = false;
for (size_t t = 0; t < 100; t++) {
usleep_safe(100 * USEC_PER_MSEC);
if (ASSERT_OK(cg_is_empty(subcgroup)) > 0) {
empty = true;
break;
}
}
ASSERT_TRUE(empty);
}
ASSERT_OK(cg_trim(subcgroup, /* delete_root= */ true));
}
TEST(oomd_cgroup_context_acquire_and_insert) {
_cleanup_hashmap_free_ Hashmap *h1 = NULL, *h2 = NULL;
_cleanup_(oomd_cgroup_context_unrefp) OomdCGroupContext *ctx = NULL;

View File

@ -286,7 +286,9 @@ static int async_polkit_read_reply(sd_bus_message *reply, AsyncPolkitQuery *q) {
a = ASSERT_PTR(TAKE_PTR(q->action));
if (sd_bus_message_is_method_error(reply, NULL)) {
const sd_bus_error *e = ASSERT_PTR(sd_bus_message_get_error(reply));
const sd_bus_error *e;
e = sd_bus_message_get_error(reply);
if (bus_error_is_unknown_service(e)) {
/* If PK is absent, then store this away, as it depends on the callers flags whether

View File

@ -951,13 +951,13 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE(
SD_VARLINK_FIELD_COMMENT("If not empty, the field contains the name of another unit that this unit follows in state"),
SD_VARLINK_DEFINE_FIELD(Following, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Reflects whether the configuration file of this unit has been loaded"),
SD_VARLINK_DEFINE_FIELD(LoadState, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_FIELD(LoadState, SD_VARLINK_STRING, 0),
SD_VARLINK_FIELD_COMMENT("Reflects whether the unit is currently active or not"),
SD_VARLINK_DEFINE_FIELD(ActiveState, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_FIELD(ActiveState, SD_VARLINK_STRING, 0),
SD_VARLINK_FIELD_COMMENT("Reflects whether the unit is currently frozen or not"),
SD_VARLINK_DEFINE_FIELD(FreezerState, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_FIELD(FreezerState, SD_VARLINK_STRING, 0),
SD_VARLINK_FIELD_COMMENT("Reflect more fine-grained state that is unit-type-specific"),
SD_VARLINK_DEFINE_FIELD(SubState, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_FIELD(SubState, SD_VARLINK_STRING, 0),
SD_VARLINK_FIELD_COMMENT("Reflects the install state of the unit file"),
SD_VARLINK_DEFINE_FIELD(UnitFileState, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Timestamp when the firmware first began execution"),
@ -971,27 +971,27 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE(
SD_VARLINK_FIELD_COMMENT("Timestamp when the unit exited inactive state"),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(InactiveExitTimestamp, Timestamp, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Reflects whether the unit can be started or not"),
SD_VARLINK_DEFINE_FIELD(CanStart, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_FIELD(CanStart, SD_VARLINK_BOOL, 0),
SD_VARLINK_FIELD_COMMENT("Reflects whether the unit can be stopped or not"),
SD_VARLINK_DEFINE_FIELD(CanStop, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_FIELD(CanStop, SD_VARLINK_BOOL, 0),
SD_VARLINK_FIELD_COMMENT("Reflects whether the unit can be reloaded or not"),
SD_VARLINK_DEFINE_FIELD(CanReload, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_FIELD(CanReload, SD_VARLINK_BOOL, 0),
SD_VARLINK_FIELD_COMMENT("Reflects whether the unit may be started in isolation mode"),
SD_VARLINK_DEFINE_FIELD(CanIsolate, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_FIELD(CanIsolate, SD_VARLINK_BOOL, 0),
SD_VARLINK_FIELD_COMMENT("Returns which unit resources can be cleaned up"),
SD_VARLINK_DEFINE_FIELD(CanClean, SD_VARLINK_STRING, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Whether the unit supports the freeze operation"),
SD_VARLINK_DEFINE_FIELD(CanFreeze, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_FIELD(CanFreeze, SD_VARLINK_BOOL, 0),
SD_VARLINK_FIELD_COMMENT("Whether the unit supports live mounting"),
SD_VARLINK_DEFINE_FIELD(CanLiveMount, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_FIELD(CanLiveMount, SD_VARLINK_BOOL, 0),
SD_VARLINK_FIELD_COMMENT("The job ID of the job currently scheduled or being executed for this unit, if there is any."),
SD_VARLINK_DEFINE_FIELD(JobId, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Whether the configuration file this unit is loaded from (i.e. FragmentPath or SourcePath) has changed since the configuration was read and hence whether a configuration reload is recommended"),
SD_VARLINK_DEFINE_FIELD(NeedDaemonReload, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_FIELD(NeedDaemonReload, SD_VARLINK_BOOL, 0),
SD_VARLINK_FIELD_COMMENT("Condition result of the last time the configured conditions of this unit were checked"),
SD_VARLINK_DEFINE_FIELD(ConditionResult, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_FIELD(ConditionResult, SD_VARLINK_BOOL, 0),
SD_VARLINK_FIELD_COMMENT("Assert result of the last time the configured asserts of this unit were checked"),
SD_VARLINK_DEFINE_FIELD(AssertResult, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_FIELD(AssertResult, SD_VARLINK_BOOL, 0),
SD_VARLINK_FIELD_COMMENT("The last time the configured conditions of the unit have been checked"),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(ConditionTimestamp, Timestamp, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("The last time the configured asserts of the unit have been checked"),
@ -1027,28 +1027,12 @@ static SD_VARLINK_DEFINE_ERROR(
static SD_VARLINK_DEFINE_ERROR(OnlyByDependency);
static SD_VARLINK_DEFINE_ERROR(DBusShuttingDown);
static SD_VARLINK_DEFINE_ERROR(UnitMasked);
static SD_VARLINK_DEFINE_ERROR(UnitError);
static SD_VARLINK_DEFINE_ERROR(
PropertyNotSupported,
SD_VARLINK_DEFINE_FIELD(property, SD_VARLINK_STRING, SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_METHOD(
SetProperties,
SD_VARLINK_FIELD_COMMENT("The name of the unit to operate on."),
SD_VARLINK_DEFINE_INPUT(name, SD_VARLINK_STRING, 0),
SD_VARLINK_FIELD_COMMENT("Whether to apply the change ephemerally or persistently."),
SD_VARLINK_DEFINE_INPUT(runtime, SD_VARLINK_BOOL, 0),
SD_VARLINK_FIELD_COMMENT("The runtime properties to set."),
SD_VARLINK_DEFINE_INPUT_BY_TYPE(properties, UnitRuntime, 0));
SD_VARLINK_DEFINE_INTERFACE(
io_systemd_Unit,
"io.systemd.Unit",
SD_VARLINK_SYMBOL_COMMENT("List units"),
&vl_method_List,
SD_VARLINK_SYMBOL_COMMENT("Set unit properties"),
&vl_method_SetProperties,
&vl_type_RateLimit,
SD_VARLINK_SYMBOL_COMMENT("An object to represent a unit's conditions"),
&vl_type_Condition,
@ -1109,12 +1093,6 @@ SD_VARLINK_DEFINE_INTERFACE(
/* Errors */
SD_VARLINK_SYMBOL_COMMENT("No matching unit found"),
&vl_error_NoSuchUnit,
SD_VARLINK_SYMBOL_COMMENT("The unit is masked"),
&vl_error_UnitMasked,
SD_VARLINK_SYMBOL_COMMENT("Unit is in a fatal error state"),
&vl_error_UnitError,
SD_VARLINK_SYMBOL_COMMENT("Changing this property via SetProperties() is not supported"),
&vl_error_PropertyNotSupported,
SD_VARLINK_SYMBOL_COMMENT("Job for the unit may only be enqueued by dependencies"),
&vl_error_OnlyByDependency,
SD_VARLINK_SYMBOL_COMMENT("A unit that requires D-Bus cannot be started as D-Bus is shutting down"),

View File

@ -299,6 +299,70 @@ TEST(passfd_contents_read) {
ASSERT_STREQ(buf, file_contents);
}
TEST(pass_many_fds_contents_read) {
_cleanup_close_pair_ int pair[2] = EBADF_PAIR;
static const char file_contents[][STRLEN("test contents in the fileX") + 1] = {
"test contents in the file0",
"test contents in the file1",
"test contents in the file2"
};
static const char wire_contents[] = "test contents on the wire";
int r;
assert_se(socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) >= 0);
r = ASSERT_OK(pidref_safe_fork("(passfd_contents_read)", FORK_DEATHSIG_SIGTERM|FORK_LOG|FORK_WAIT, NULL));
if (r == 0) {
/* Child */
struct iovec iov = IOVEC_MAKE_STRING(wire_contents);
char tmpfile[][STRLEN("/tmp/test-socket-util-passfd-contents-read-XXXXXX") + 1] = {
"/tmp/test-socket-util-passfd-contents-read-XXXXXX",
"/tmp/test-socket-util-passfd-contents-read-XXXXXX",
"/tmp/test-socket-util-passfd-contents-read-XXXXXX"
};
int tmpfds[3] = EBADF_TRIPLET;
pair[0] = safe_close(pair[0]);
for (size_t i = 0; i < 3; ++i) {
assert_se(write_tmpfile(tmpfile[i], file_contents[i]) == 0);
tmpfds[i] = open(tmpfile[i], O_RDONLY);
assert_se(tmpfds[i] >= 0);
assert_se(unlink(tmpfile[i]) == 0);
}
assert_se(send_many_fds_iov(pair[1], tmpfds, 3, &iov, 1, MSG_DONTWAIT) > 0);
close_many(tmpfds, 3);
_exit(EXIT_SUCCESS);
}
/* Parent */
char buf[64];
struct iovec iov = IOVEC_MAKE(buf, sizeof(buf)-1);
_cleanup_free_ int *fds = NULL;
size_t n_fds = 0;
ssize_t k;
pair[1] = safe_close(pair[1]);
k = receive_many_fds_iov(pair[0], &iov, 1, &fds, &n_fds, MSG_DONTWAIT);
assert_se(k > 0);
buf[k] = 0;
ASSERT_STREQ(buf, wire_contents);
assert_se(n_fds == 3);
for (size_t i = 0; i < 3; ++i) {
assert_se(fds[i] >= 0);
r = read(fds[i], buf, sizeof(buf)-1);
assert_se(r >= 0);
buf[r] = 0;
ASSERT_STREQ(buf, file_contents[i]);
safe_close(fds[i]);
}
}
TEST(receive_nopassfd) {
_cleanup_close_pair_ int pair[2] = EBADF_PAIR;
static const char wire_contents[] = "no fd passed here";

View File

@ -378,7 +378,7 @@ systemctl reload-or-restart --marked
# again, but with varlinkctl instead
systemctl restart "$UNIT_NAME"
varlinkctl call /run/systemd/io.systemd.Manager io.systemd.Unit.SetProperties "{\"runtime\": true, \"name\": \"$UNIT_NAME\", \"properties\": {\"Markers\": [\"needs-restart\"]}}"
systemctl set-property "$UNIT_NAME" Markers=needs-restart
systemctl show -P Markers "$UNIT_NAME" | grep needs-restart
varlinkctl call /run/systemd/io.systemd.Manager io.systemd.Manager.EnqueueMarkedJobs '{}'
timeout 30 bash -c "until systemctl list-jobs $UNIT_NAME | grep \"No jobs\" 2>/dev/null; do sleep 1; done"

View File

@ -209,10 +209,6 @@ varlinkctl call /run/systemd/io.systemd.Manager io.systemd.Unit.List '{"name": "
(! varlinkctl call /run/systemd/io.systemd.Manager io.systemd.Unit.List '{"name": "non-existent.service"}')
(! varlinkctl call /run/systemd/io.systemd.Manager io.systemd.Unit.List '{"pid": {"pid": -1}}' )
(! varlinkctl call /run/systemd/io.systemd.Manager io.systemd.Unit.List '{"name": "multi-user.target", "pid": {"pid": 1}}')
set +o pipefail
varlinkctl call /run/systemd/io.systemd.Manager io.systemd.Unit.SetProperties '{"runtime": true, "name": "non-existent.service", "properties": {"Markers": ["needs-restart"]}}' |& grep "io.systemd.Unit.NoSuchUnit"
varlinkctl call /run/systemd/io.systemd.Manager io.systemd.Unit.SetProperties '{"runtime": true, "name": "systemd-journald.service", "properties": {"LoadState": "foobar"}}' |& grep "io.systemd.Unit.PropertyNotSupported"
set -o pipefail
varlinkctl call /run/systemd/io.systemd.Manager io.systemd.Unit.List '{"cgroup": "/init.scope"}'
invocation_id="$(systemctl show -P InvocationID systemd-journald.service)"