mirror of
https://github.com/systemd/systemd
synced 2026-03-08 06:04:45 +01:00
Compare commits
16 Commits
710742270b
...
f9dbf6fd5a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f9dbf6fd5a | ||
|
|
4fae85faea | ||
|
|
31620807e1 | ||
|
|
4fb8cc53b3 | ||
|
|
e757e791b2 | ||
|
|
7a6b6c4d07 | ||
|
|
1a416a47e7 | ||
|
|
2e8cfb7cef | ||
|
|
ce6ea42b69 | ||
|
|
fad273450a | ||
|
|
d9e078fe68 | ||
|
|
b10e5a60aa | ||
|
|
936d864b0b | ||
|
|
48c84fe730 | ||
|
|
0e1c4de235 | ||
|
|
cb7c0950b3 |
@ -970,53 +970,6 @@ 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,
|
||||
@ -1072,74 +1025,6 @@ 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,
|
||||
|
||||
@ -120,28 +120,6 @@ 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,
|
||||
@ -156,8 +134,6 @@ 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);
|
||||
|
||||
@ -203,9 +179,7 @@ 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);
|
||||
|
||||
@ -2121,7 +2121,6 @@ static int bus_unit_set_live_property(
|
||||
|
||||
for (;;) {
|
||||
const char *word;
|
||||
bool b;
|
||||
|
||||
r = sd_bus_message_read(message, "s", &word);
|
||||
if (r < 0)
|
||||
@ -2129,22 +2128,14 @@ static int bus_unit_set_live_property(
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
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)
|
||||
r = parse_unit_marker(word, &settings, &mask);
|
||||
if (r < 0)
|
||||
return sd_bus_error_setf(reterr_error, BUS_ERROR_BAD_UNIT_SETTING,
|
||||
"Unknown marker \"%s\".", word);
|
||||
|
||||
SET_FLAG(settings, 1u << m, b);
|
||||
SET_FLAG(mask, 1u << m, true);
|
||||
if (r > 0)
|
||||
some_plus_minus = true;
|
||||
else
|
||||
some_absolute = true;
|
||||
}
|
||||
|
||||
r = sd_bus_message_exit_container(message);
|
||||
|
||||
@ -7058,3 +7058,26 @@ 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;
|
||||
}
|
||||
|
||||
@ -1094,6 +1094,8 @@ 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, ...) \
|
||||
|
||||
@ -361,6 +361,40 @@ 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;
|
||||
@ -400,9 +434,9 @@ static int lookup_unit_by_parameters(
|
||||
assert(ret);
|
||||
|
||||
if (p->name) {
|
||||
unit = manager_get_unit(manager, p->name);
|
||||
if (!unit)
|
||||
return varlink_error_no_such_unit(link, "name");
|
||||
r = load_unit_and_check(link, manager, p->name, &unit);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (pidref_is_set_or_automatic(&p->pidref)) {
|
||||
@ -534,3 +568,107 @@ 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);
|
||||
}
|
||||
|
||||
@ -17,4 +17,6 @@ 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);
|
||||
|
||||
@ -391,6 +391,7 @@ 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)
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "bus-control.h"
|
||||
#include "bus-error.h"
|
||||
#include "bus-internal.h"
|
||||
#include "bus-message.h"
|
||||
#include "fd-util.h"
|
||||
@ -136,11 +137,14 @@ static int default_request_name_handler(
|
||||
assert(m);
|
||||
|
||||
if (sd_bus_message_is_method_error(m, NULL)) {
|
||||
log_debug_errno(sd_bus_message_get_errno(m),
|
||||
"Unable to request name, failing connection: %s",
|
||||
sd_bus_message_get_error(m)->message);
|
||||
const sd_bus_error *e = ASSERT_PTR(sd_bus_message_get_error(m));
|
||||
r = sd_bus_error_get_errno(e);
|
||||
|
||||
bus_enter_closing(sd_bus_message_get_bus(m), -sd_bus_message_get_errno(m));
|
||||
log_debug_errno(r,
|
||||
"Unable to request name, failing connection: %s",
|
||||
bus_error_message(e, r));
|
||||
|
||||
bus_enter_closing(sd_bus_message_get_bus(m), -r);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -290,11 +294,12 @@ static int default_release_name_handler(
|
||||
assert(m);
|
||||
|
||||
if (sd_bus_message_is_method_error(m, NULL)) {
|
||||
log_debug_errno(sd_bus_message_get_errno(m),
|
||||
"Unable to release name, failing connection: %s",
|
||||
sd_bus_message_get_error(m)->message);
|
||||
const sd_bus_error *e = ASSERT_PTR(sd_bus_message_get_error(m));
|
||||
r = sd_bus_error_get_errno(e);
|
||||
|
||||
bus_enter_closing(sd_bus_message_get_bus(m), -sd_bus_message_get_errno(m));
|
||||
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);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@ -3483,10 +3483,13 @@ static int add_match_callback(
|
||||
sd_bus_slot_ref(match_slot);
|
||||
|
||||
if (sd_bus_message_is_method_error(m, NULL)) {
|
||||
r = log_debug_errno(sd_bus_message_get_errno(m),
|
||||
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,
|
||||
"Unable to add match %s, failing connection: %s",
|
||||
match_slot->match_callback.match_string,
|
||||
sd_bus_message_get_error(m)->message);
|
||||
bus_error_message(e, r));
|
||||
|
||||
failed = true;
|
||||
} else
|
||||
|
||||
@ -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,7 +127,6 @@ static int map_dns(
|
||||
return -ENOMEM;
|
||||
|
||||
b->dns[b->n_dns++] = TAKE_PTR(a);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -477,18 +476,16 @@ 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);
|
||||
|
||||
e = sd_bus_message_get_error(message);
|
||||
const sd_bus_error *e = sd_bus_message_get_error(message);
|
||||
if (e) {
|
||||
r = sd_bus_error_get_errno(e);
|
||||
log_full_errno(LOG_ERR, r,
|
||||
log_error_errno(r,
|
||||
"Could not connect modem %s %s: %s",
|
||||
modem->manufacturer, modem->model,
|
||||
bus_error_message(e, r));
|
||||
@ -497,10 +494,16 @@ static int modem_connect_handler(sd_bus_message *message, void *userdata, sd_bus
|
||||
return 0;
|
||||
}
|
||||
|
||||
sd_bus_message_read(message, "o", &new_bearer);
|
||||
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;
|
||||
}
|
||||
|
||||
log_debug("ModemManager: %s %s connected, bearer is at %s",
|
||||
modem->manufacturer, modem->model, new_bearer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <linux/magic.h>
|
||||
#include <sched.h>
|
||||
#include <sys/mount.h>
|
||||
#include <unistd.h>
|
||||
|
||||
@ -1491,7 +1492,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, rr;
|
||||
int r;
|
||||
|
||||
log_debug("Wiping fully visible API FS");
|
||||
|
||||
@ -1499,23 +1500,13 @@ 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");
|
||||
|
||||
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");
|
||||
if (setns(mntns_fd, CLONE_NEWNS) < 0)
|
||||
return log_error_errno(errno, "Failed to enter mount namespace: %m");
|
||||
|
||||
rr = do_wipe_fully_visible_api_fs();
|
||||
r = do_wipe_fully_visible_api_fs();
|
||||
|
||||
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");
|
||||
if (setns(orig_mntns_fd, CLONE_NEWNS) < 0)
|
||||
return log_error_errno(errno, "Failed to enter original mount namespace: %m");
|
||||
|
||||
return rr;
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
return 0;
|
||||
continue;
|
||||
}
|
||||
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);
|
||||
r = oomd_cgroup_kill_mark(m, selected, "memory-used");
|
||||
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);
|
||||
return 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
r = oomd_cgroup_kill_mark(m, selected);
|
||||
r = oomd_cgroup_kill_mark(m, selected, "memory-pressure");
|
||||
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.
|
||||
* 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. */
|
||||
/* Don't act on all the high pressure cgroups at once; return as soon as we kill one. */
|
||||
m->mem_pressure_post_action_delay_start = usec_now;
|
||||
if (selected && r > 0) {
|
||||
if (selected)
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,6 +27,7 @@
|
||||
typedef struct OomdKillState {
|
||||
Manager *manager;
|
||||
OomdCGroupContext *ctx;
|
||||
const char *reason;
|
||||
/* This holds sd_varlink references */
|
||||
Set *links;
|
||||
} OomdKillState;
|
||||
@ -245,11 +246,12 @@ 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) {
|
||||
int oomd_cgroup_kill(Manager *m, OomdCGroupContext *ctx, bool recurse, const char *reason) {
|
||||
_cleanup_set_free_ Set *pids_killed = NULL;
|
||||
int r;
|
||||
|
||||
assert(ctx);
|
||||
assert(!m || reason);
|
||||
|
||||
pids_killed = set_new(NULL);
|
||||
if (!pids_killed)
|
||||
@ -288,7 +290,7 @@ int oomd_cgroup_kill(Manager *m, OomdCGroupContext *ctx, bool recurse) {
|
||||
"Killed",
|
||||
"ss",
|
||||
ctx->path,
|
||||
"oom");
|
||||
reason);
|
||||
|
||||
return !set_isempty(pids_killed);
|
||||
}
|
||||
@ -334,7 +336,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);
|
||||
r = oomd_cgroup_kill(ks->manager, ks->ctx, /* recurse= */ true, ks->reason);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to kill cgroup '%s', ignoring: %m", ks->ctx->path);
|
||||
oomd_kill_state_free(ks);
|
||||
@ -465,11 +467,12 @@ static int oomd_prekill_hook(Manager *m, OomdKillState *ks) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int oomd_cgroup_kill_mark(Manager *m, OomdCGroupContext *ctx) {
|
||||
int oomd_cgroup_kill_mark(Manager *m, OomdCGroupContext *ctx, const char *reason) {
|
||||
int r;
|
||||
|
||||
assert(ctx);
|
||||
assert(m);
|
||||
assert(reason);
|
||||
|
||||
if (m->dry_run) {
|
||||
_cleanup_free_ char *cg_path = NULL;
|
||||
@ -489,6 +492,7 @@ int oomd_cgroup_kill_mark(Manager *m, OomdCGroupContext *ctx) {
|
||||
*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);
|
||||
|
||||
@ -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);
|
||||
int oomd_cgroup_kill_mark(Manager *m, OomdCGroupContext *ctx);
|
||||
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);
|
||||
|
||||
/* 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,
|
||||
|
||||
@ -1,20 +1,25 @@
|
||||
/* 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"
|
||||
@ -59,6 +64,103 @@ 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;
|
||||
@ -88,7 +190,11 @@ TEST(oomd_cgroup_kill) {
|
||||
ASSERT_OK(fork_and_sleep(5, &two));
|
||||
ASSERT_OK(cg_attach(subcgroup, two.pid));
|
||||
|
||||
ASSERT_OK_POSITIVE(oomd_cgroup_kill(NULL /* manager */, &(OomdCGroupContext){ .path = subcgroup }, false /* recurse */));
|
||||
ASSERT_OK_POSITIVE(oomd_cgroup_kill(
|
||||
/* m= */ NULL,
|
||||
&(OomdCGroupContext){ .path = subcgroup },
|
||||
/* recurse= */ false,
|
||||
/* reason= */ NULL));
|
||||
|
||||
ASSERT_OK(cg_get_xattr(subcgroup, "user.oomd_ooms", &v, /* ret_size= */ NULL));
|
||||
ASSERT_STREQ(v, i == 0 ? "1" : "2");
|
||||
@ -113,6 +219,54 @@ 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;
|
||||
|
||||
@ -286,9 +286,7 @@ 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;
|
||||
|
||||
e = sd_bus_message_get_error(reply);
|
||||
const sd_bus_error *e = ASSERT_PTR(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
|
||||
|
||||
@ -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, 0),
|
||||
SD_VARLINK_DEFINE_FIELD(LoadState, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("Reflects whether the unit is currently active or not"),
|
||||
SD_VARLINK_DEFINE_FIELD(ActiveState, SD_VARLINK_STRING, 0),
|
||||
SD_VARLINK_DEFINE_FIELD(ActiveState, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("Reflects whether the unit is currently frozen or not"),
|
||||
SD_VARLINK_DEFINE_FIELD(FreezerState, SD_VARLINK_STRING, 0),
|
||||
SD_VARLINK_DEFINE_FIELD(FreezerState, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("Reflect more fine-grained state that is unit-type-specific"),
|
||||
SD_VARLINK_DEFINE_FIELD(SubState, SD_VARLINK_STRING, 0),
|
||||
SD_VARLINK_DEFINE_FIELD(SubState, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
|
||||
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, 0),
|
||||
SD_VARLINK_DEFINE_FIELD(CanStart, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("Reflects whether the unit can be stopped or not"),
|
||||
SD_VARLINK_DEFINE_FIELD(CanStop, SD_VARLINK_BOOL, 0),
|
||||
SD_VARLINK_DEFINE_FIELD(CanStop, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("Reflects whether the unit can be reloaded or not"),
|
||||
SD_VARLINK_DEFINE_FIELD(CanReload, SD_VARLINK_BOOL, 0),
|
||||
SD_VARLINK_DEFINE_FIELD(CanReload, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("Reflects whether the unit may be started in isolation mode"),
|
||||
SD_VARLINK_DEFINE_FIELD(CanIsolate, SD_VARLINK_BOOL, 0),
|
||||
SD_VARLINK_DEFINE_FIELD(CanIsolate, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
|
||||
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, 0),
|
||||
SD_VARLINK_DEFINE_FIELD(CanFreeze, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("Whether the unit supports live mounting"),
|
||||
SD_VARLINK_DEFINE_FIELD(CanLiveMount, SD_VARLINK_BOOL, 0),
|
||||
SD_VARLINK_DEFINE_FIELD(CanLiveMount, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
|
||||
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, 0),
|
||||
SD_VARLINK_DEFINE_FIELD(NeedDaemonReload, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
|
||||
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, 0),
|
||||
SD_VARLINK_DEFINE_FIELD(ConditionResult, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
|
||||
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, 0),
|
||||
SD_VARLINK_DEFINE_FIELD(AssertResult, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
|
||||
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,12 +1027,28 @@ 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,
|
||||
@ -1093,6 +1109,12 @@ 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"),
|
||||
|
||||
@ -299,70 +299,6 @@ 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";
|
||||
|
||||
@ -378,7 +378,7 @@ systemctl reload-or-restart --marked
|
||||
|
||||
# again, but with varlinkctl instead
|
||||
systemctl restart "$UNIT_NAME"
|
||||
systemctl set-property "$UNIT_NAME" Markers=needs-restart
|
||||
varlinkctl call /run/systemd/io.systemd.Manager io.systemd.Unit.SetProperties "{\"runtime\": true, \"name\": \"$UNIT_NAME\", \"properties\": {\"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"
|
||||
|
||||
@ -209,6 +209,10 @@ 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)"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user