1
0
mirror of https://github.com/systemd/systemd synced 2026-04-12 10:04:50 +02:00

Compare commits

..

No commits in common. "ff6b70fe7e2a1c3f0c88697bfa9ad625cd4c5013" and "d3a1710bc22b9047620d1a05f76dee8590255206" have entirely different histories.

33 changed files with 251 additions and 1299 deletions

View File

@ -256,34 +256,27 @@ jobs:
## Phase 1: Review commits
First, list the directories in `worktrees/` and read `review-schema.json`.
Then, spawn exactly one review subagent per worktree directory, all in a
single message so they run concurrently. Do NOT batch or group multiple
commits into a single agent. Do NOT read any other files before spawning —
the subagents will do that themselves.
Each worktree at `worktrees/<sha>/` contains the full source tree checked
out at that commit, plus `commit.patch` (the diff) and `commit-message.txt`
(the commit message).
List the directories in `worktrees/` — there is one per commit. Each
worktree at `worktrees/<sha>/` contains the full source tree checked out at
that commit, plus `commit.patch` (the diff) and `commit-message.txt`
(the commit message). Spawn one
review subagent per worktree, all in a single message so they run concurrently.
Do NOT pre-compute diffs or read any other files before spawning — the subagents
will do that themselves.
Each reviewer reviews design, code quality, style, potential bugs, and
security implications.
Each subagent must be spawned with `model: "opus"`.
Each subagent prompt must include:
- Instructions to read `pr-context.json` in the repository root for additional
context.
- The contents of `review-schema.json` (paste it into each prompt so the
agent doesn't have to read it separately).
- Instructions to read `review-schema.json` in the repository root and
return a JSON array matching the `comments` items schema from that file.
- The worktree path.
- Instructions to read `commit-message.txt` and `commit.patch` in the
worktree for the commit message and diff.
- Instructions to verify every `line` and `start_line` value
against the hunk ranges in `commit.patch` before returning.
- Instructions to return ONLY a raw JSON array of findings. No markdown,
no explanation, no code fences — just the JSON array. If there are no
findings, return `[]`.
## Phase 2: Collect, deduplicate, and summarize
@ -297,20 +290,26 @@ jobs:
populate the `resolve` array.
- If `tracking_comment` is non-null, use it as the basis for your summary.
Trust the subagent findings — do NOT re-verify them by running your own
bash, grep, sed, or awk commands against the source code. Phase 2 should
only read `pr-context.json` and then produce the structured output.
Then:
1. Collect all issues. Merge duplicates across agents (same file, same
problem, lines within 3 of each other).
2. Drop issues that already have a review comment on the same file about
the same problem, or where the PR author replied disagreeing.
3. Populate the `resolve` array with the `id` of your own review comment
threads (user.login == "github-actions[bot]", body starts with
"Claude: ") that should be resolved — either because the issue was
fixed or because the author dismissed it. Use the first comment `id`
in each thread. Do not resolve threads from human reviewers.
1. Collect all issues. Merge duplicates (same file, lines within 3 of each other, same problem).
2. Drop low-confidence findings.
3. Check the existing inline review comments from `pr-context.json`. Do NOT
include a comment if one already exists on the same file about the same
problem, even if the exact line numbers differ (lines shift between
revisions). Also check for author replies that dismiss or reject a previous
comment — do NOT re-raise an issue the PR author has already responded to
disagreeing with.
Populate the `resolve` array with the REST API `id` (integer) of your own
review comment threads that should be resolved (user.login == "github-actions[bot]"
and body starts with "Claude: "). Do not resolve threads from human reviewers.
A thread should be resolved if:
- The issue it raised has been addressed in the current PR (i.e. your review
no longer flags it), or
- The PR author (or another reviewer) left a reply disagreeing with or
dismissing the comment.
Only include the `id` of the **first** comment in each thread (the one that
started the conversation). Do not resolve threads for issues that are still
present and unaddressed.
4. Write a `summary` field in markdown for a top-level tracking comment.
**If no existing tracking comment was found (first run):**
@ -487,7 +486,7 @@ jobs:
...(c.side != null && { side: c.side }),
...(c.start_line != null && { start_line: c.start_line }),
...(c.start_side != null && { start_side: c.start_side }),
body: c.body,
body: `Claude: **${c.severity}**: ${c.body}`,
});
posted++;
} catch (e) {

3
NEWS
View File

@ -22,9 +22,6 @@ CHANGES WITH 261 in spe:
New features:
* A new tmpfiles.d/root.conf has been added that sets permissions
on the root directory (/) to 0555
* Networking to cloud IMDS services may be locked down for recognized
clouds. This is recommended for secure installations, but typically
conflicts with traditional IMDS clients such as cloud-init, which

9
TODO
View File

@ -122,13 +122,12 @@ Features:
* sysext: make systemd-{sys,conf}ext-sysroot.service work in the split '/var'
configuration.
* introduce a concept of /etc/machine-info "TAGS=" field that allows tagging
machines with zero, one or more roles, states or other forms of
categorization. Then, add a way of using this in sysupdate to automatically
enable certain transfers, one for each role.
* sd-varlink: add fully async modes of the protocol upgrade stuff
* sd-varlink: optimize the read-byte-by-byte mode in case upgrade mode is
enabled, via recvmsg() with MSG_SEEK: first read non-destrictively, look for
NUL byte, and only then flush out
* repart: maybe remove iso9660/eltorito superblock from disk when booting via
gpt, if there is one.

View File

@ -84,15 +84,6 @@
<citerefentry><refentrytitle>org.freedesktop.LogControl1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for information about the D-Bus APIs <filename>systemd-logind</filename> provides.</para>
<para>In addition to the D-Bus interface, <filename>systemd-logind</filename> also provides a Varlink
interface <constant>io.systemd.Shutdown</constant> for shutting down or rebooting the system. It
supports <function>PowerOff</function>, <function>Reboot</function>, <function>Halt</function>,
<function>KExec</function>, and <function>SoftReboot</function> methods. Each method accepts an
optional <varname>skipInhibitors</varname> boolean parameter to bypass active block inhibitors
(matching the <constant>SD_LOGIND_SKIP_INHIBITORS</constant> flag of the D-Bus interface). The
interface can be queried with
<command>varlinkctl introspect /run/systemd/io.systemd.Login io.systemd.Shutdown</command>.</para>
<para>For more information see
<ulink url="https://systemd.io/INHIBITOR_LOCKS">Inhibitor Locks</ulink>.</para>

View File

@ -2896,13 +2896,7 @@ if git.found()
'ls-files', ':/*.[ch]', ':/*.cc',
check : false)
if all_files.returncode() == 0
existing_files = []
foreach f : all_files.stdout().split()
if fs.exists(f)
existing_files += f
endif
endforeach
all_files = files(existing_files)
all_files = files(all_files.stdout().split())
custom_target(
output : 'tags',

View File

@ -1560,24 +1560,6 @@ fail:
return r;
}
int cg_get_keyed_attribute_uint64(const char *path, const char *attribute, const char *key, uint64_t *ret) {
_cleanup_free_ char *val = NULL;
int r;
assert(key);
assert(ret);
r = cg_get_keyed_attribute(path, attribute, STRV_MAKE(key), &val);
if (r < 0)
return r;
r = safe_atou64(val, ret);
if (r < 0)
return log_debug_errno(r, "Failed to parse value '%s' of key '%s' in cgroup attribute '%s': %m", val, key, attribute);
return 0;
}
int cg_mask_to_string(CGroupMask mask, char **ret) {
_cleanup_free_ char *s = NULL;
bool space = false;

View File

@ -165,7 +165,6 @@ int cg_get_attribute_as_uint64(const char *path, const char *attribute, uint64_t
int cg_get_attribute_as_bool(const char *path, const char *attribute);
int cg_get_keyed_attribute(const char *path, const char *attribute, char * const *keys, char **values);
int cg_get_keyed_attribute_uint64(const char *path, const char *attribute, const char *key, uint64_t *ret);
int cg_get_owner(const char *path, uid_t *ret_uid);

View File

@ -285,14 +285,19 @@ static int process_cpu(Group *g, unsigned iteration) {
if (r < 0)
return r;
} else {
_cleanup_free_ char *val = NULL;
uint64_t u;
r = cg_get_keyed_attribute_uint64(g->path, "cpu.stat", "usage_usec", &u);
r = cg_get_keyed_attribute(g->path, "cpu.stat", STRV_MAKE("usage_usec"), &val);
if (IN_SET(r, -ENOENT, -ENXIO))
return 0;
if (r < 0)
return r;
r = safe_atou64(val, &u);
if (r < 0)
return r;
new_usage = u * NSEC_PER_USEC;
}

View File

@ -2996,8 +2996,9 @@ int unit_check_oomd_kill(Unit *u) {
}
int unit_check_oom(Unit *u) {
_cleanup_free_ char *oom_kill = NULL;
bool increased;
uint64_t c = 0;
uint64_t c;
int r;
CGroupRuntime *crt = unit_get_cgroup_runtime(u);
@ -3012,25 +3013,33 @@ int unit_check_oom(Unit *u) {
* back to reading oom_kill if we can't find the file or field. */
if (ctx->memory_oom_group) {
r = cg_get_keyed_attribute_uint64(
r = cg_get_keyed_attribute(
crt->cgroup_path,
"memory.events.local",
"oom_group_kill",
&c);
STRV_MAKE("oom_group_kill"),
&oom_kill);
if (r < 0 && !IN_SET(r, -ENOENT, -ENXIO))
return log_unit_debug_errno(u, r, "Failed to read oom_group_kill field of memory.events.local cgroup attribute, ignoring: %m");
}
if (!ctx->memory_oom_group || r < 0) {
r = cg_get_keyed_attribute_uint64(
if (isempty(oom_kill)) {
r = cg_get_keyed_attribute(
crt->cgroup_path,
"memory.events",
"oom_kill",
&c);
STRV_MAKE("oom_kill"),
&oom_kill);
if (r < 0 && !IN_SET(r, -ENOENT, -ENXIO))
return log_unit_debug_errno(u, r, "Failed to read oom_kill field of memory.events cgroup attribute: %m");
}
if (!oom_kill)
c = 0;
else {
r = safe_atou64(oom_kill, &c);
if (r < 0)
return log_unit_debug_errno(u, r, "Failed to parse memory.events cgroup oom field: %m");
}
increased = c > crt->oom_kill_last;
crt->oom_kill_last = c;
@ -3576,9 +3585,14 @@ static int unit_get_cpu_usage_raw(const Unit *u, const CGroupRuntime *crt, nsec_
if (unit_has_host_root_cgroup(u))
return procfs_cpu_get_usage(ret);
_cleanup_free_ char *val = NULL;
uint64_t us;
r = cg_get_keyed_attribute_uint64(crt->cgroup_path, "cpu.stat", "usage_usec", &us);
r = cg_get_keyed_attribute(crt->cgroup_path, "cpu.stat", STRV_MAKE("usage_usec"), &val);
if (r < 0)
return r;
r = safe_atou64(val, &us);
if (r < 0)
return r;

View File

@ -1238,6 +1238,7 @@ int bus_socket_take_fd(sd_bus *b) {
int bus_socket_write_message(sd_bus *bus, sd_bus_message *m, size_t *idx) {
struct iovec *iov;
ssize_t k;
size_t n;
unsigned j;
int r;
@ -1253,8 +1254,9 @@ int bus_socket_write_message(sd_bus *bus, sd_bus_message *m, size_t *idx) {
if (r < 0)
return r;
iov = newa(struct iovec, m->n_iovec);
memcpy_safe(iov, m->iovec, sizeof(struct iovec) * m->n_iovec);
n = m->n_iovec * sizeof(struct iovec);
iov = newa(struct iovec, n);
memcpy_safe(iov, m->iovec, n);
j = 0;
iovec_advance(iov, &j, *idx);

View File

@ -45,7 +45,6 @@
#include "logind-seat.h"
#include "logind-seat-dbus.h"
#include "logind-session-dbus.h"
#include "logind-shutdown.h"
#include "logind-user.h"
#include "logind-user-dbus.h"
#include "logind-utmp.h"
@ -77,6 +76,10 @@
*/
#define WALL_MESSAGE_MAX 4096U
#define SHUTDOWN_SCHEDULE_FILE "/run/systemd/shutdown/scheduled"
static void reset_scheduled_shutdown(Manager *m);
static int get_sender_session(
Manager *m,
sd_bus_message *message,
@ -1863,6 +1866,24 @@ static int method_flush_devices(sd_bus_message *message, void *userdata, sd_bus_
return sd_bus_reply_method_return(message, NULL);
}
static int have_multiple_sessions(
Manager *m,
uid_t uid) {
Session *session;
assert(m);
/* Check for other users' sessions. Greeter sessions do not
* count, and non-login sessions do not count either. */
HASHMAP_FOREACH(session, m->sessions)
if (SESSION_CLASS_IS_INHIBITOR_LIKE(session->class) &&
session->user->user_record->uid != uid)
return true;
return false;
}
static int bus_manager_log_shutdown(
Manager *m,
const HandleActionData *a) {
@ -2168,6 +2189,121 @@ int bus_manager_shutdown_or_sleep_now_or_later(
return r;
}
static int verify_shutdown_creds(
Manager *m,
sd_bus_message *message,
const HandleActionData *a,
uint64_t flags,
sd_bus_error *error) {
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
bool multiple_sessions, blocked, interactive;
_unused_ bool error_or_denial = false;
Inhibitor *offending = NULL;
uid_t uid;
int r;
assert(m);
assert(a);
assert(message);
r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
if (r < 0)
return r;
r = sd_bus_creds_get_euid(creds, &uid);
if (r < 0)
return r;
r = have_multiple_sessions(m, uid);
if (r < 0)
return r;
multiple_sessions = r > 0;
blocked = manager_is_inhibited(m, a->inhibit_what, NULL, /* flags= */ 0, uid, &offending);
interactive = flags & SD_LOGIND_INTERACTIVE;
if (multiple_sessions) {
r = bus_verify_polkit_async_full(
message,
a->polkit_action_multiple_sessions,
/* details= */ NULL,
/* good_user= */ UID_INVALID,
interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
&m->polkit_registry,
error);
if (r < 0) {
/* If we get -EBUSY, it means a polkit decision was made, but not for
* this action in particular. Assuming we are blocked on inhibitors,
* ignore that error and allow the decision to be revealed below. */
if (blocked && r == -EBUSY)
error_or_denial = true;
else
return r;
}
if (r == 0)
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
}
if (blocked) {
PolkitFlags polkit_flags = 0;
/* With a strong inhibitor, if the skip flag is not set, reject outright.
* With a weak inhibitor, if root is asking and the root flag is set, reject outright.
* All else, check polkit first. */
if (!FLAGS_SET(flags, SD_LOGIND_SKIP_INHIBITORS) &&
(offending->mode != INHIBIT_BLOCK_WEAK ||
(uid == 0 && FLAGS_SET(flags, SD_LOGIND_ROOT_CHECK_INHIBITORS))))
return sd_bus_error_set(error, BUS_ERROR_BLOCKED_BY_INHIBITOR_LOCK,
"Operation denied due to active block inhibitor");
/* We want to always ask here, even for root, to only allow bypassing if explicitly allowed
* by polkit, unless a weak blocker is used, in which case it will be authorized. */
if (offending->mode != INHIBIT_BLOCK_WEAK)
polkit_flags |= POLKIT_ALWAYS_QUERY;
if (interactive)
polkit_flags |= POLKIT_ALLOW_INTERACTIVE;
r = bus_verify_polkit_async_full(
message,
a->polkit_action_ignore_inhibit,
/* details= */ NULL,
/* good_user= */ UID_INVALID,
polkit_flags,
&m->polkit_registry,
error);
if (r < 0)
return r;
if (r == 0)
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
}
if (!multiple_sessions && !blocked) {
r = bus_verify_polkit_async_full(
message,
a->polkit_action,
/* details= */ NULL,
/* good_user= */ UID_INVALID,
interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
&m->polkit_registry,
error);
if (r < 0)
return r;
if (r == 0)
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
}
/* If error_or_denial was set above, it means that a polkit denial or
* error was deferred for a future call to bus_verify_polkit_async_full()
* to catch. In any case, it also means that the payload guarded by
* these polkit calls should never be executed, and hence we should
* never reach this point. */
assert(!error_or_denial);
return 0;
}
static int setup_wall_message_timer(Manager *m, sd_bus_message* message) {
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
int r;
@ -2306,17 +2442,10 @@ static int method_do_shutdown_or_sleep(
} else if (!a)
assert_se(a = handle_action_lookup(action));
r = manager_verify_shutdown_creds(m, message, /* link= */ NULL, a, flags, error);
r = verify_shutdown_creds(m, message, a, flags, error);
if (r != 0)
return r;
{
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
(void) bus_query_sender_pidref(message, &pidref);
log_shutdown_caller(&pidref, handle_action_to_string(a->handle));
}
if (m->delayed_action)
return sd_bus_error_setf(error, BUS_ERROR_OPERATION_IN_PROGRESS,
"Action %s already in progress, refusing requested %s operation.",
@ -2325,7 +2454,7 @@ static int method_do_shutdown_or_sleep(
/* reset case we're shorting a scheduled shutdown */
m->unlink_nologin = false;
manager_reset_scheduled_shutdown(m);
reset_scheduled_shutdown(m);
m->scheduled_shutdown_timeout = 0;
m->scheduled_shutdown_action = action;
@ -2439,6 +2568,29 @@ static usec_t nologin_timeout_usec(usec_t elapse) {
return LESS_BY(elapse, 5 * USEC_PER_MINUTE);
}
static void reset_scheduled_shutdown(Manager *m) {
assert(m);
m->scheduled_shutdown_timeout_source = sd_event_source_disable_unref(m->scheduled_shutdown_timeout_source);
m->wall_message_timeout_source = sd_event_source_disable_unref(m->wall_message_timeout_source);
m->nologin_timeout_source = sd_event_source_disable_unref(m->nologin_timeout_source);
m->scheduled_shutdown_action = _HANDLE_ACTION_INVALID;
m->scheduled_shutdown_timeout = USEC_INFINITY;
m->scheduled_shutdown_uid = UID_INVALID;
m->scheduled_shutdown_tty = mfree(m->scheduled_shutdown_tty);
m->shutdown_dry_run = false;
if (m->unlink_nologin) {
(void) unlink_or_warn("/run/nologin");
m->unlink_nologin = false;
}
(void) unlink(SHUTDOWN_SCHEDULE_FILE);
manager_send_changed(m, "ScheduledShutdown");
}
static int update_schedule_file(Manager *m) {
_cleanup_(unlink_and_freep) char *temp_path = NULL;
_cleanup_fclose_ FILE *f = NULL;
@ -2517,7 +2669,7 @@ static int manager_scheduled_shutdown_handler(
bus_manager_log_shutdown(m, a);
log_info("Running in dry run, suppressing action.");
manager_reset_scheduled_shutdown(m);
reset_scheduled_shutdown(m);
return 0;
}
@ -2531,7 +2683,7 @@ static int manager_scheduled_shutdown_handler(
return 0;
error:
manager_reset_scheduled_shutdown(m);
reset_scheduled_shutdown(m);
return r;
}
@ -2586,7 +2738,7 @@ void manager_load_scheduled_shutdown(Manager *m) {
"TTY", &tty);
/* reset will delete the file */
manager_reset_scheduled_shutdown(m);
reset_scheduled_shutdown(m);
if (r == -ENOENT)
return;
@ -2632,7 +2784,7 @@ void manager_load_scheduled_shutdown(Manager *m) {
r = manager_setup_shutdown_timers(m);
if (r < 0)
return manager_reset_scheduled_shutdown(m);
return reset_scheduled_shutdown(m);
(void) manager_setup_wall_message_timer(m);
(void) update_schedule_file(m);
@ -2667,7 +2819,7 @@ static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_
assert_se(a = handle_action_lookup(handle));
assert(a->polkit_action);
r = manager_verify_shutdown_creds(m, message, /* link= */ NULL, a, 0, error);
r = verify_shutdown_creds(m, message, a, 0, error);
if (r != 0)
return r;
@ -2701,7 +2853,7 @@ static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_
r = update_schedule_file(m);
if (r < 0) {
manager_reset_scheduled_shutdown(m);
reset_scheduled_shutdown(m);
return r;
}
@ -2761,7 +2913,7 @@ static int method_cancel_scheduled_shutdown(sd_bus_message *message, void *userd
}
cancel_delayed_action(m);
manager_reset_scheduled_shutdown(m);
reset_scheduled_shutdown(m);
return sd_bus_reply_method_return(message, "b", true);
}
@ -2817,7 +2969,7 @@ static int method_can_shutdown_or_sleep(
if (r < 0)
return r;
r = manager_have_multiple_sessions(m, uid);
r = have_multiple_sessions(m, uid);
if (r < 0)
return r;

View File

@ -1,250 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <unistd.h>
#include "sd-bus.h"
#include "sd-event.h"
#include "sd-varlink.h"
#include "bus-common-errors.h"
#include "bus-polkit.h"
#include "cgroup-util.h"
#include "format-util.h"
#include "fs-util.h"
#include "hashmap.h"
#include "log.h"
#include "login-util.h"
#include "logind.h"
#include "logind-dbus.h"
#include "logind-inhibit.h"
#include "logind-session.h"
#include "logind-shutdown.h"
#include "logind-user.h"
#include "pidref.h"
#include "process-util.h"
#include "user-record.h"
int manager_have_multiple_sessions(
Manager *m,
uid_t uid) {
Session *session;
assert(m);
/* Check for other users' sessions. Greeter sessions do not
* count, and non-login sessions do not count either. */
HASHMAP_FOREACH(session, m->sessions)
if (SESSION_CLASS_IS_INHIBITOR_LIKE(session->class) &&
session->user->user_record->uid != uid)
return true;
return false;
}
void log_shutdown_caller(const PidRef *caller, const char *method) {
_cleanup_free_ char *comm = NULL, *unit = NULL;
assert(method);
if (!pidref_is_set(caller)) {
return log_notice("%s requested from unknown client PID...", method);
}
(void) pidref_get_comm(caller, &comm);
(void) cg_pidref_get_unit(caller, &unit);
log_notice("%s requested from client PID " PID_FMT "%s%s%s%s%s%s...",
method, caller->pid,
comm ? " ('" : "", strempty(comm), comm ? "')" : "",
unit ? " (unit " : "", strempty(unit), unit ? ")" : "");
}
int manager_verify_shutdown_creds(
Manager *m,
sd_bus_message *message,
sd_varlink *link,
const HandleActionData *a,
uint64_t flags,
sd_bus_error *error) {
bool multiple_sessions, blocked, interactive;
_unused_ bool error_or_denial = false;
Inhibitor *offending = NULL;
uid_t uid;
int r;
assert(m);
assert(a);
assert(!!message != !!link); /* exactly one transport */
assert(!link || !error); /* varlink doesn't use sd_bus_error */
if (message) {
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
if (r < 0)
return r;
r = sd_bus_creds_get_euid(creds, &uid);
if (r < 0)
return r;
} else {
r = sd_varlink_get_peer_uid(link, &uid);
if (r < 0)
return r;
}
r = manager_have_multiple_sessions(m, uid);
if (r < 0)
return r;
multiple_sessions = r > 0;
blocked = manager_is_inhibited(m, a->inhibit_what, NULL, /* flags= */ 0, uid, &offending);
interactive = flags & SD_LOGIND_INTERACTIVE;
if (multiple_sessions) {
if (message)
r = bus_verify_polkit_async_full(
message,
a->polkit_action_multiple_sessions,
/* details= */ NULL,
/* good_user= */ UID_INVALID,
interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
&m->polkit_registry,
error);
else
r = varlink_verify_polkit_async_full(
link,
m->bus,
a->polkit_action_multiple_sessions,
/* details= */ NULL,
/* good_user= */ UID_INVALID,
interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
&m->polkit_registry);
if (r < 0) {
/* If we get -EBUSY, it means a polkit decision was made, but not for
* this action in particular. Assuming we are blocked on inhibitors,
* ignore that error and allow the decision to be revealed below. */
if (blocked && r == -EBUSY)
error_or_denial = true;
else
return r;
}
if (r == 0)
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
}
if (blocked) {
PolkitFlags polkit_flags = 0;
/* With a strong inhibitor, if the skip flag is not set, reject outright.
* With a weak inhibitor, if root is asking and the root flag is set, reject outright.
* All else, check polkit first. */
if (!FLAGS_SET(flags, SD_LOGIND_SKIP_INHIBITORS) &&
(offending->mode != INHIBIT_BLOCK_WEAK ||
(uid == 0 && FLAGS_SET(flags, SD_LOGIND_ROOT_CHECK_INHIBITORS)))) {
if (link)
return sd_varlink_errorbo(
link,
"io.systemd.Shutdown.BlockedByInhibitor",
SD_JSON_BUILD_PAIR_STRING("who", offending->who),
SD_JSON_BUILD_PAIR_STRING("why", offending->why));
if (error)
return sd_bus_error_set(error, BUS_ERROR_BLOCKED_BY_INHIBITOR_LOCK,
"Operation denied due to active block inhibitor");
return -EACCES;
}
/* We want to always ask here, even for root, to only allow bypassing if explicitly allowed
* by polkit, unless a weak blocker is used, in which case it will be authorized. */
if (offending->mode != INHIBIT_BLOCK_WEAK)
polkit_flags |= POLKIT_ALWAYS_QUERY;
if (interactive)
polkit_flags |= POLKIT_ALLOW_INTERACTIVE;
if (message)
r = bus_verify_polkit_async_full(
message,
a->polkit_action_ignore_inhibit,
/* details= */ NULL,
/* good_user= */ UID_INVALID,
polkit_flags,
&m->polkit_registry,
error);
else
r = varlink_verify_polkit_async_full(
link,
m->bus,
a->polkit_action_ignore_inhibit,
/* details= */ NULL,
/* good_user= */ UID_INVALID,
polkit_flags,
&m->polkit_registry);
if (r < 0)
return r;
if (r == 0)
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
}
if (!multiple_sessions && !blocked) {
if (message)
r = bus_verify_polkit_async_full(
message,
a->polkit_action,
/* details= */ NULL,
/* good_user= */ UID_INVALID,
interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
&m->polkit_registry,
error);
else
r = varlink_verify_polkit_async_full(
link,
m->bus,
a->polkit_action,
/* details= */ NULL,
/* good_user= */ UID_INVALID,
interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
&m->polkit_registry);
if (r < 0)
return r;
if (r == 0)
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
}
/* If error_or_denial was set above, it means that a polkit denial or
* error was deferred for a future call to bus_verify_polkit_async_full()
* to catch. In any case, it also means that the payload guarded by
* these polkit calls should never be executed, and hence we should
* never reach this point. */
assert(!error_or_denial);
return 0;
}
void manager_reset_scheduled_shutdown(Manager *m) {
assert(m);
m->scheduled_shutdown_timeout_source = sd_event_source_disable_unref(m->scheduled_shutdown_timeout_source);
m->wall_message_timeout_source = sd_event_source_disable_unref(m->wall_message_timeout_source);
m->nologin_timeout_source = sd_event_source_disable_unref(m->nologin_timeout_source);
m->scheduled_shutdown_action = _HANDLE_ACTION_INVALID;
m->scheduled_shutdown_timeout = USEC_INFINITY;
m->scheduled_shutdown_uid = UID_INVALID;
m->scheduled_shutdown_tty = mfree(m->scheduled_shutdown_tty);
m->shutdown_dry_run = false;
if (m->unlink_nologin) {
(void) unlink_or_warn("/run/nologin");
m->unlink_nologin = false;
}
(void) unlink(SHUTDOWN_SCHEDULE_FILE);
manager_send_changed(m, "ScheduledShutdown");
}

View File

@ -1,17 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "logind-forward.h"
#define SHUTDOWN_SCHEDULE_FILE "/run/systemd/shutdown/scheduled"
int manager_have_multiple_sessions(Manager *m, uid_t uid);
void log_shutdown_caller(const PidRef *caller, const char *method);
/* manager_verify_shutdown_creds() takes *either* a "message" or "link" depending on if it is used
* to validate a D-Bus or Varlink shutdown request. When varlink is used the sd_bus_error *error
* must be NULL */
int manager_verify_shutdown_creds(Manager *m, sd_bus_message *message, sd_varlink *link, const HandleActionData *a, uint64_t flags, sd_bus_error *error);
void manager_reset_scheduled_shutdown(Manager *m);

View File

@ -4,19 +4,15 @@
#include "sd-event.h"
#include "alloc-util.h"
#include "bus-error.h"
#include "bus-polkit.h"
#include "cgroup-util.h"
#include "fd-util.h"
#include "format-util.h"
#include "hashmap.h"
#include "json-util.h"
#include "login-util.h"
#include "logind-session.h"
#include "logind.h"
#include "logind-dbus.h"
#include "logind-seat.h"
#include "logind-session.h"
#include "logind-shutdown.h"
#include "logind-user.h"
#include "logind-varlink.h"
#include "strv.h"
@ -24,7 +20,6 @@
#include "user-record.h"
#include "user-util.h"
#include "varlink-io.systemd.Login.h"
#include "varlink-io.systemd.Shutdown.h"
#include "varlink-io.systemd.service.h"
#include "varlink-util.h"
@ -341,101 +336,6 @@ static int vl_method_release_session(sd_varlink *link, sd_json_variant *paramete
return sd_varlink_reply(link, NULL);
}
static int setup_wall_message_timer(Manager *m, sd_varlink *link) {
uid_t uid = UID_INVALID;
int r;
(void) sd_varlink_get_peer_uid(link, &uid);
m->scheduled_shutdown_uid = uid;
_cleanup_free_ char *tty = NULL;
pid_t pid = 0;
r = sd_varlink_get_peer_pid(link, &pid);
if (r >= 0)
(void) get_ctty(pid, /* ret_devnr= */ NULL, &tty);
r = free_and_strdup_warn(&m->scheduled_shutdown_tty, tty);
if (r < 0)
return log_oom();
return manager_setup_wall_message_timer(m);
}
static int manager_do_shutdown_action(sd_varlink *link, sd_json_variant *parameters, HandleAction action) {
Manager *m = ASSERT_PTR(sd_varlink_get_userdata(link));
int skip_inhibitors = -1;
int r;
static const sd_json_dispatch_field dispatch_table[] = {
{ "skipInhibitors", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_tristate, 0, 0 },
VARLINK_DISPATCH_POLKIT_FIELD,
{}
};
r = sd_varlink_dispatch(link, parameters, dispatch_table, &skip_inhibitors);
if (r != 0)
return r;
uint64_t flags = skip_inhibitors > 0 ? SD_LOGIND_SKIP_INHIBITORS : 0;
const HandleActionData *a = handle_action_lookup(action);
assert(a);
r = manager_verify_shutdown_creds(m, /* message= */ NULL, link, a, flags, /* error= */ NULL);
if (r != 0)
return r;
{
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
(void) varlink_get_peer_pidref(link, &pidref);
log_shutdown_caller(&pidref, handle_action_to_string(action));
}
if (m->delayed_action)
return sd_varlink_error(link, "io.systemd.Shutdown.AlreadyInProgress", /* parameters= */ NULL);
/* Reset in case we're short-circuiting a scheduled shutdown */
m->unlink_nologin = false;
manager_reset_scheduled_shutdown(m);
m->scheduled_shutdown_timeout = 0;
m->scheduled_shutdown_action = action;
(void) setup_wall_message_timer(m, link);
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
r = bus_manager_shutdown_or_sleep_now_or_later(m, a, &error);
if (r < 0) {
log_warning_errno(r, "Failed to execute %s: %s",
handle_action_to_string(action),
bus_error_message(&error, r));
return sd_varlink_error_errno(link, r);
}
return sd_varlink_reply(link, NULL);
}
static int vl_method_power_off(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
return manager_do_shutdown_action(link, parameters, HANDLE_POWEROFF);
}
static int vl_method_reboot(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
return manager_do_shutdown_action(link, parameters, HANDLE_REBOOT);
}
static int vl_method_halt(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
return manager_do_shutdown_action(link, parameters, HANDLE_HALT);
}
static int vl_method_kexec(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
return manager_do_shutdown_action(link, parameters, HANDLE_KEXEC);
}
static int vl_method_soft_reboot(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
return manager_do_shutdown_action(link, parameters, HANDLE_SOFT_REBOOT);
}
int manager_varlink_init(Manager *m, int fd) {
_cleanup_(sd_varlink_server_unrefp) sd_varlink_server *s = NULL;
_unused_ _cleanup_close_ int fd_close = fd;
@ -458,20 +358,14 @@ int manager_varlink_init(Manager *m, int fd) {
r = sd_varlink_server_add_interface_many(
s,
&vl_interface_io_systemd_Login,
&vl_interface_io_systemd_Shutdown,
&vl_interface_io_systemd_service);
if (r < 0)
return log_error_errno(r, "Failed to add varlink interfaces: %m");
return log_error_errno(r, "Failed to add Login interface to varlink server: %m");
r = sd_varlink_server_bind_method_many(
s,
"io.systemd.Login.CreateSession", vl_method_create_session,
"io.systemd.Login.ReleaseSession", vl_method_release_session,
"io.systemd.Shutdown.PowerOff", vl_method_power_off,
"io.systemd.Shutdown.Reboot", vl_method_reboot,
"io.systemd.Shutdown.Halt", vl_method_halt,
"io.systemd.Shutdown.KExec", vl_method_kexec,
"io.systemd.Shutdown.SoftReboot", vl_method_soft_reboot,
"io.systemd.service.Ping", varlink_method_ping,
"io.systemd.service.SetLogLevel", varlink_method_set_log_level,
"io.systemd.service.GetEnvironment", varlink_method_get_environment);

View File

@ -21,7 +21,6 @@ systemd_logind_extract_sources = files(
'logind-session-dbus.c',
'logind-session-device.c',
'logind-session.c',
'logind-shutdown.c',
'logind-user-dbus.c',
'logind-user.c',
'logind-utmp.c',

View File

@ -624,7 +624,7 @@ int oomd_select_by_swap_usage(Hashmap *h, uint64_t threshold_usage, OomdCGroupCo
int oomd_cgroup_context_acquire(const char *path, OomdCGroupContext **ret) {
_cleanup_(oomd_cgroup_context_unrefp) OomdCGroupContext *ctx = NULL;
_cleanup_free_ char *p = NULL;
_cleanup_free_ char *p = NULL, *val = NULL;
bool is_root;
int r;
@ -678,9 +678,13 @@ int oomd_cgroup_context_acquire(const char *path, OomdCGroupContext **ret) {
else if (r < 0)
return log_debug_errno(r, "Error getting memory.swap.current from %s: %m", path);
r = cg_get_keyed_attribute_uint64(path, "memory.stat", "pgscan", &ctx->pgscan);
r = cg_get_keyed_attribute(path, "memory.stat", STRV_MAKE("pgscan"), &val);
if (r < 0)
return log_debug_errno(r, "Error getting pgscan from memory.stat under %s: %m", path);
r = safe_atou64(val, &ctx->pgscan);
if (r < 0)
return log_debug_errno(r, "Error converting pgscan value to uint64_t: %m");
}
*ret = TAKE_PTR(ctx);

View File

@ -15,11 +15,4 @@ executables += [
'report-basic.c',
),
},
libexec_template + {
'name' : 'systemd-report-cgroup',
'sources' : files(
'report-cgroup.c',
'report-cgroup-server.c',
),
},
]

View File

@ -1,131 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <getopt.h>
#include "sd-varlink.h"
#include "alloc-util.h"
#include "ansi-color.h"
#include "build.h"
#include "log.h"
#include "main-func.h"
#include "pretty-print.h"
#include "report-cgroup.h"
#include "varlink-io.systemd.Metrics.h"
#include "varlink-util.h"
static int vl_server(void) {
_cleanup_(sd_varlink_server_unrefp) sd_varlink_server *vs = NULL;
_cleanup_(cgroup_context_freep) CGroupContext *ctx = NULL;
int r;
ctx = new0(CGroupContext, 1);
if (!ctx)
return log_oom();
r = varlink_server_new(&vs, SD_VARLINK_SERVER_INHERIT_USERDATA, ctx);
if (r < 0)
return log_error_errno(r, "Failed to allocate Varlink server: %m");
r = sd_varlink_server_add_interface(vs, &vl_interface_io_systemd_Metrics);
if (r < 0)
return log_error_errno(r, "Failed to add Varlink interface: %m");
r = sd_varlink_server_bind_method_many(
vs,
"io.systemd.Metrics.List", vl_method_list_metrics,
"io.systemd.Metrics.Describe", vl_method_describe_metrics);
if (r < 0)
return log_error_errno(r, "Failed to bind Varlink methods: %m");
r = sd_varlink_server_loop_auto(vs);
if (r < 0)
return log_error_errno(r, "Failed to run Varlink event loop: %m");
return 0;
}
static int help(void) {
_cleanup_free_ char *url = NULL;
int r;
r = terminal_urlify_man("systemd-report-cgroup", "8", &url);
if (r < 0)
return log_oom();
printf("%s [OPTIONS...]\n"
"\n%sReport cgroup metrics.%s\n"
"\n%sOptions:%s\n"
" -h --help Show this help\n"
" --version Show package version\n"
"\nSee the %s for details.\n",
program_invocation_short_name,
ansi_highlight(),
ansi_normal(),
ansi_underline(),
ansi_normal(),
url);
return 0;
}
static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
};
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{}
};
int c, r;
assert(argc >= 0);
assert(argv);
while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
switch (c) {
case 'h':
return help();
case ARG_VERSION:
return version();
case '?':
return -EINVAL;
default:
assert_not_reached();
}
if (optind < argc)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"This program takes no arguments.");
r = sd_varlink_invocation(SD_VARLINK_ALLOW_ACCEPT);
if (r < 0)
return log_error_errno(r, "Failed to check if invoked in Varlink mode: %m");
if (r == 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"This program can only run as a Varlink service.");
return 1;
}
static int run(int argc, char *argv[]) {
int r;
log_setup();
r = parse_argv(argc, argv);
if (r <= 0)
return r;
return vl_server();
}
DEFINE_MAIN_FUNCTION(run);

View File

@ -1,495 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "sd-json.h"
#include "sd-varlink.h"
#include "alloc-util.h"
#include "cgroup-util.h"
#include "extract-word.h"
#include "fd-util.h"
#include "fileio.h"
#include "log.h"
#include "metrics.h"
#include "parse-util.h"
#include "path-util.h"
#include "report-cgroup.h"
#include "string-util.h"
#include "time-util.h"
typedef struct CGroupInfo {
char *unit;
char *path;
uint64_t io_rbytes;
uint64_t io_rios;
int io_stat_cached; /* 0 = not attempted, > 0 = cached, < 0 = -errno */
} CGroupInfo;
static CGroupInfo *cgroup_info_free(CGroupInfo *info) {
if (!info)
return NULL;
free(info->unit);
free(info->path);
return mfree(info);
}
DEFINE_TRIVIAL_CLEANUP_FUNC(CGroupInfo*, cgroup_info_free);
static void cgroup_info_array_free(CGroupInfo **infos, size_t n) {
FOREACH_ARRAY(i, infos, n)
cgroup_info_free(*i);
free(infos);
}
static void cgroup_context_flush(CGroupContext *ctx) {
assert(ctx);
cgroup_info_array_free(ctx->cgroups, ctx->n_cgroups);
ctx->cgroups = NULL;
ctx->n_cgroups = 0;
ctx->cache_populated = false;
}
CGroupContext *cgroup_context_free(CGroupContext *ctx) {
if (!ctx)
return NULL;
cgroup_context_flush(ctx);
return mfree(ctx);
}
static int walk_cgroups_recursive(const char *path, CGroupInfo ***infos, size_t *n_infos) {
_cleanup_closedir_ DIR *d = NULL;
int r;
assert(path);
assert(infos);
assert(n_infos);
/* Collect any unit cgroup we encounter */
_cleanup_free_ char *name = NULL;
r = cg_path_get_unit(path, &name);
if (r >= 0) {
_cleanup_(cgroup_info_freep) CGroupInfo *info = new(CGroupInfo, 1);
if (!info)
return log_oom();
*info = (CGroupInfo) {
.unit = TAKE_PTR(name),
.path = strdup(path),
};
if (!info->path)
return log_oom();
if (!GREEDY_REALLOC(*infos, *n_infos + 1))
return log_oom();
(*infos)[(*n_infos)++] = TAKE_PTR(info);
return 0; /* Unit cgroups are leaf nodes for our purposes */
}
/* Stop at delegation boundaries — don't descend into delegated subtrees */
r = cg_is_delegated(path);
if (r == -ENOENT)
return 0;
if (r < 0)
return log_debug_errno(r, "Failed to check delegation for '%s': %m", path);
if (r > 0)
return 0;
r = cg_enumerate_subgroups(path, &d);
if (r == -ENOENT)
return 0;
if (r < 0)
return log_debug_errno(r, "Failed to enumerate cgroup '%s': %m", path);
for (;;) {
_cleanup_free_ char *fn = NULL, *child = NULL;
r = cg_read_subgroup(d, &fn);
if (r < 0)
return log_debug_errno(r, "Failed to read subgroup from '%s': %m", path);
if (r == 0)
break;
child = path_join(empty_to_root(path), fn);
if (!child)
return log_oom();
path_simplify(child);
r = walk_cgroups_recursive(child, infos, n_infos);
if (r < 0)
return r;
}
return 0;
}
static int walk_cgroups(CGroupContext *ctx, CGroupInfo ***ret, size_t *ret_n) {
int r;
assert(ctx);
assert(ret);
assert(ret_n);
/* Return cached result if available */
if (ctx->cache_populated) {
*ret = ctx->cgroups;
*ret_n = ctx->n_cgroups;
return 0;
}
CGroupInfo **infos = NULL;
size_t n_infos = 0;
CLEANUP_ARRAY(infos, n_infos, cgroup_info_array_free);
r = walk_cgroups_recursive("", &infos, &n_infos);
if (r < 0)
return r;
ctx->cgroups = TAKE_PTR(infos);
ctx->n_cgroups = TAKE_GENERIC(n_infos, size_t, 0);
ctx->cache_populated = true;
*ret = ctx->cgroups;
*ret_n = ctx->n_cgroups;
return 0;
}
static int cpu_usage_build_json(MetricFamilyContext *context, void *userdata) {
CGroupContext *ctx = ASSERT_PTR(userdata);
CGroupInfo **cgroups;
size_t n_cgroups;
int r;
assert(context);
r = walk_cgroups(ctx, &cgroups, &n_cgroups);
if (r < 0)
return 0; /* Skip metric on failure */
FOREACH_ARRAY(c, cgroups, n_cgroups) {
uint64_t us;
r = cg_get_keyed_attribute_uint64((*c)->path, "cpu.stat", "usage_usec", &us);
if (r < 0)
continue;
r = metric_build_send_unsigned(
context,
(*c)->unit,
us * NSEC_PER_USEC,
/* fields= */ NULL);
if (r < 0)
return r;
}
return 0;
}
static int memory_usage_build_json(MetricFamilyContext *context, void *userdata) {
CGroupContext *ctx = ASSERT_PTR(userdata);
CGroupInfo **cgroups;
size_t n_cgroups;
int r;
assert(context);
r = walk_cgroups(ctx, &cgroups, &n_cgroups);
if (r < 0)
return 0;
FOREACH_ARRAY(c, cgroups, n_cgroups) {
uint64_t current = 0, limit = UINT64_MAX;
r = cg_get_attribute_as_uint64((*c)->path, "memory.current", &current);
if (r >= 0) {
/* Walk up the cgroup tree to find the tightest memory limit */
_cleanup_free_ char *path_buf = strdup((*c)->path);
if (!path_buf)
return log_oom();
for (char *p = path_buf;;) {
uint64_t high, max;
r = cg_get_attribute_as_uint64(p, "memory.max", &max);
if (r >= 0 && max < limit)
limit = max;
r = cg_get_attribute_as_uint64(p, "memory.high", &high);
if (r >= 0 && high < limit)
limit = high;
/* Move to parent */
const char *e;
r = path_find_last_component(p, /* accept_dot_dot= */ false, &e, NULL);
if (r <= 0)
break;
p[e - p] = '\0';
}
if (limit != UINT64_MAX && limit > current) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *fields = NULL;
r = sd_json_buildo(&fields, SD_JSON_BUILD_PAIR_STRING("type", "available"));
if (r < 0)
return r;
r = metric_build_send_unsigned(
context,
(*c)->unit,
limit - current,
fields);
if (r < 0)
return r;
}
_cleanup_(sd_json_variant_unrefp) sd_json_variant *fields = NULL;
r = sd_json_buildo(&fields, SD_JSON_BUILD_PAIR_STRING("type", "current"));
if (r < 0)
return r;
r = metric_build_send_unsigned(
context,
(*c)->unit,
current,
fields);
if (r < 0)
return r;
}
uint64_t val;
r = cg_get_attribute_as_uint64((*c)->path, "memory.peak", &val);
if (r >= 0) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *fields = NULL;
r = sd_json_buildo(&fields, SD_JSON_BUILD_PAIR_STRING("type", "peak"));
if (r < 0)
return r;
r = metric_build_send_unsigned(
context,
(*c)->unit,
val,
fields);
if (r < 0)
return r;
}
}
return 0;
}
/* Parse io.stat for a cgroup once, summing both rbytes= and rios= fields in a
* single pass to avoid reading the file twice. */
static int io_stat_parse(const char *cgroup_path, uint64_t *ret_rbytes, uint64_t *ret_rios) {
_cleanup_free_ char *path = NULL;
_cleanup_fclose_ FILE *f = NULL;
uint64_t rbytes = 0, rios = 0;
int r;
r = cg_get_path(cgroup_path, "io.stat", &path);
if (r < 0)
return r;
f = fopen(path, "re");
if (!f)
return -errno;
for (;;) {
_cleanup_free_ char *line = NULL;
const char *p;
r = read_line(f, LONG_LINE_MAX, &line);
if (r < 0)
return r;
if (r == 0)
break;
p = line;
p += strcspn(p, WHITESPACE);
p += strspn(p, WHITESPACE);
for (;;) {
_cleanup_free_ char *word = NULL;
r = extract_first_word(&p, &word, NULL, EXTRACT_RETAIN_ESCAPE);
if (r < 0)
return r;
if (r == 0)
break;
const char *v;
uint64_t val;
v = startswith(word, "rbytes=");
if (v && safe_atou64(v, &val) >= 0) {
rbytes += val;
continue;
}
v = startswith(word, "rios=");
if (v && safe_atou64(v, &val) >= 0)
rios += val;
}
}
*ret_rbytes = rbytes;
*ret_rios = rios;
return 0;
}
static int ensure_io_stat_cached(CGroupInfo *info) {
int r;
assert(info);
if (info->io_stat_cached > 0)
return 0;
if (info->io_stat_cached < 0)
return info->io_stat_cached;
r = io_stat_parse(info->path, &info->io_rbytes, &info->io_rios);
if (r < 0) {
if (r != -ENOENT)
log_debug_errno(r, "Failed to parse IO stats for '%s': %m", info->path);
info->io_stat_cached = r;
return r;
}
info->io_stat_cached = 1;
return 0;
}
static int io_read_bytes_build_json(MetricFamilyContext *context, void *userdata) {
CGroupContext *ctx = ASSERT_PTR(userdata);
CGroupInfo **cgroups;
size_t n_cgroups;
int r;
assert(context);
r = walk_cgroups(ctx, &cgroups, &n_cgroups);
if (r < 0)
return 0;
FOREACH_ARRAY(c, cgroups, n_cgroups) {
if (ensure_io_stat_cached(*c) < 0)
continue;
r = metric_build_send_unsigned(
context,
(*c)->unit,
(*c)->io_rbytes,
/* fields= */ NULL);
if (r < 0)
return r;
}
return 0;
}
static int io_read_operations_build_json(MetricFamilyContext *context, void *userdata) {
CGroupContext *ctx = ASSERT_PTR(userdata);
CGroupInfo **cgroups;
size_t n_cgroups;
int r;
assert(context);
r = walk_cgroups(ctx, &cgroups, &n_cgroups);
if (r < 0)
return 0;
FOREACH_ARRAY(c, cgroups, n_cgroups) {
if (ensure_io_stat_cached(*c) < 0)
continue;
r = metric_build_send_unsigned(
context,
(*c)->unit,
(*c)->io_rios,
/* fields= */ NULL);
if (r < 0)
return r;
}
return 0;
}
static int tasks_current_build_json(MetricFamilyContext *context, void *userdata) {
CGroupContext *ctx = ASSERT_PTR(userdata);
CGroupInfo **cgroups;
size_t n_cgroups;
int r;
assert(context);
r = walk_cgroups(ctx, &cgroups, &n_cgroups);
if (r < 0)
return 0;
FOREACH_ARRAY(c, cgroups, n_cgroups) {
uint64_t val;
r = cg_get_attribute_as_uint64((*c)->path, "pids.current", &val);
if (r < 0)
continue;
r = metric_build_send_unsigned(
context,
(*c)->unit,
val,
/* fields= */ NULL);
if (r < 0)
return r;
}
return 0;
}
static const MetricFamily cgroup_metric_family_table[] = {
/* Keep metrics ordered alphabetically */
{
.name = METRIC_IO_SYSTEMD_CGROUP_PREFIX "CpuUsage",
.description = "Per unit metric: CPU usage in nanoseconds",
.type = METRIC_FAMILY_TYPE_COUNTER,
.generate = cpu_usage_build_json,
},
{
.name = METRIC_IO_SYSTEMD_CGROUP_PREFIX "IOReadBytes",
.description = "Per unit metric: IO bytes read",
.type = METRIC_FAMILY_TYPE_COUNTER,
.generate = io_read_bytes_build_json,
},
{
.name = METRIC_IO_SYSTEMD_CGROUP_PREFIX "IOReadOperations",
.description = "Per unit metric: IO read operations",
.type = METRIC_FAMILY_TYPE_COUNTER,
.generate = io_read_operations_build_json,
},
{
.name = METRIC_IO_SYSTEMD_CGROUP_PREFIX "MemoryUsage",
.description = "Per unit metric: memory usage in bytes",
.type = METRIC_FAMILY_TYPE_GAUGE,
.generate = memory_usage_build_json,
},
{
.name = METRIC_IO_SYSTEMD_CGROUP_PREFIX "TasksCurrent",
.description = "Per unit metric: current number of tasks",
.type = METRIC_FAMILY_TYPE_GAUGE,
.generate = tasks_current_build_json,
},
{}
};
int vl_method_describe_metrics(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
return metrics_method_describe(cgroup_metric_family_table, link, parameters, flags, userdata);
}
int vl_method_list_metrics(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
CGroupContext *ctx = ASSERT_PTR(userdata);
int r;
r = metrics_method_list(cgroup_metric_family_table, link, parameters, flags, userdata);
cgroup_context_flush(ctx);
return r;
}

View File

@ -1,20 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "shared-forward.h"
#define METRIC_IO_SYSTEMD_CGROUP_PREFIX "io.systemd.CGroup."
typedef struct CGroupInfo CGroupInfo;
typedef struct CGroupContext {
CGroupInfo **cgroups;
size_t n_cgroups;
bool cache_populated;
} CGroupContext;
CGroupContext *cgroup_context_free(CGroupContext *ctx);
DEFINE_TRIVIAL_CLEANUP_FUNC(CGroupContext*, cgroup_context_free);
int vl_method_list_metrics(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata);
int vl_method_describe_metrics(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata);

View File

@ -100,8 +100,7 @@ static int dnssec_rsa_verify_raw(
return -EIO;
e = m = NULL;
if ((size_t) RSA_size(rpubkey) != signature_size)
return -EINVAL;
assert((size_t) RSA_size(rpubkey) == signature_size);
epubkey = EVP_PKEY_new();
if (!epubkey)
@ -231,11 +230,9 @@ static int dnssec_ecdsa_verify_raw(
if (EC_KEY_set_public_key(eckey, p) <= 0)
return log_debug_errno(SYNTHETIC_ERRNO(EIO),
"EC_KEY_set_public_key failed: 0x%lx", ERR_get_error());
"EC_POINT_bn2point failed: 0x%lx", ERR_get_error());
if (EC_KEY_check_key(eckey) != 1)
return log_debug_errno(SYNTHETIC_ERRNO(EIO),
"EC_KEY_check_key failed: 0x%lx", ERR_get_error());
assert(EC_KEY_check_key(eckey) == 1);
r = BN_bin2bn(signature_r, signature_r_size, NULL);
if (!r)

View File

@ -1036,8 +1036,7 @@ DnsServer *manager_set_dns_server(Manager *m, DnsServer *s) {
dns_server_unref(m->current_dns_server);
m->current_dns_server = dns_server_ref(s);
/* Skip flushing the cache if server stale feature is enabled. */
if (m->unicast_scope && m->stale_retention_usec == 0)
if (m->unicast_scope)
dns_cache_flush(&m->unicast_scope->cache);
(void) manager_send_changed(m, "CurrentDNSServer");
@ -1156,10 +1155,6 @@ void dns_server_flush_cache(DnsServer *s) {
if (!scope)
return;
/* Skip flushing the cache if server stale feature is enabled. */
if (s->manager->stale_retention_usec > 0)
return;
dns_cache_flush(&scope->cache);
}

View File

@ -230,7 +230,6 @@ shared_sources = files(
'varlink-io.systemd.Resolve.c',
'varlink-io.systemd.Resolve.Hook.c',
'varlink-io.systemd.Resolve.Monitor.c',
'varlink-io.systemd.Shutdown.c',
'varlink-io.systemd.Udev.c',
'varlink-io.systemd.Unit.c',
'varlink-io.systemd.UserDatabase.c',

View File

@ -1,57 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "bus-polkit.h"
#include "varlink-io.systemd.Shutdown.h"
static SD_VARLINK_DEFINE_METHOD(
PowerOff,
VARLINK_DEFINE_POLKIT_INPUT,
SD_VARLINK_FIELD_COMMENT("Skip active inhibitors and force the operation"),
SD_VARLINK_DEFINE_INPUT(skipInhibitors, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_METHOD(
Reboot,
VARLINK_DEFINE_POLKIT_INPUT,
SD_VARLINK_FIELD_COMMENT("Skip active inhibitors and force the operation"),
SD_VARLINK_DEFINE_INPUT(skipInhibitors, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_METHOD(
Halt,
VARLINK_DEFINE_POLKIT_INPUT,
SD_VARLINK_FIELD_COMMENT("Skip active inhibitors and force the operation"),
SD_VARLINK_DEFINE_INPUT(skipInhibitors, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_METHOD(
KExec,
VARLINK_DEFINE_POLKIT_INPUT,
SD_VARLINK_FIELD_COMMENT("Skip active inhibitors and force the operation"),
SD_VARLINK_DEFINE_INPUT(skipInhibitors, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_METHOD(
SoftReboot,
VARLINK_DEFINE_POLKIT_INPUT,
SD_VARLINK_FIELD_COMMENT("Skip active inhibitors and force the operation"),
SD_VARLINK_DEFINE_INPUT(skipInhibitors, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_ERROR(AlreadyInProgress);
static SD_VARLINK_DEFINE_ERROR(
BlockedByInhibitor,
SD_VARLINK_FIELD_COMMENT("Who is holding the inhibitor"),
SD_VARLINK_DEFINE_FIELD(who, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Why the inhibitor is held"),
SD_VARLINK_DEFINE_FIELD(why, SD_VARLINK_STRING, SD_VARLINK_NULLABLE));
SD_VARLINK_DEFINE_INTERFACE(
io_systemd_Shutdown,
"io.systemd.Shutdown",
SD_VARLINK_INTERFACE_COMMENT("APIs for shutting down or rebooting the system."),
SD_VARLINK_SYMBOL_COMMENT("Power off the system"),
&vl_method_PowerOff,
SD_VARLINK_SYMBOL_COMMENT("Reboot the system"),
&vl_method_Reboot,
SD_VARLINK_SYMBOL_COMMENT("Halt the system"),
&vl_method_Halt,
SD_VARLINK_SYMBOL_COMMENT("Reboot the system via kexec"),
&vl_method_KExec,
SD_VARLINK_SYMBOL_COMMENT("Reboot userspace only"),
&vl_method_SoftReboot,
SD_VARLINK_SYMBOL_COMMENT("Another shutdown or sleep operation is already in progress"),
&vl_error_AlreadyInProgress,
SD_VARLINK_SYMBOL_COMMENT("Operation denied due to active block inhibitor"),
&vl_error_BlockedByInhibitor);

View File

@ -1,6 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "sd-varlink-idl.h"
extern const sd_varlink_interface vl_interface_io_systemd_Shutdown;

View File

@ -51,7 +51,7 @@ foreach p : out.stdout().split()
#
# Also, backslashes get mangled, so skip test. See
# https://github.com/mesonbuild/meson/issues/1564.
if p.contains('\\') or not fs.exists(p)
if p.contains('\\')
continue
endif
fuzzer = fs.name(fs.parent(p))

View File

@ -30,13 +30,6 @@ REPORT=/usr/lib/systemd/systemd-report
"$REPORT" describe-metrics io.systemd piff
"$REPORT" describe-metrics piff
# test io.systemd.CGroup Metrics
systemctl start systemd-report-cgroup.socket
varlinkctl info /run/systemd/report/io.systemd.CGroup
varlinkctl list-methods /run/systemd/report/io.systemd.CGroup
varlinkctl --more call /run/systemd/report/io.systemd.CGroup io.systemd.Metrics.List {}
varlinkctl --more call /run/systemd/report/io.systemd.CGroup io.systemd.Metrics.Describe {}
# test io.systemd.Network Metrics
varlinkctl info /run/systemd/report/io.systemd.Network
varlinkctl list-methods /run/systemd/report/io.systemd.Network

View File

@ -6,7 +6,6 @@ endif
files = [['README' ],
['home.conf' ],
['root.conf' ],
['journal-nocow.conf' ],
['portables.conf', 'ENABLE_PORTABLED'],
['systemd-network.conf', 'ENABLE_NETWORKD' ],

View File

@ -1,10 +0,0 @@
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
# See tmpfiles.d(5) for details.
z / 555 - - -

View File

@ -724,8 +724,6 @@ units = [
'file' : 'systemd-repart@.service',
'conditions' : ['ENABLE_REPART'],
},
{ 'file' : 'systemd-report-cgroup.socket' },
{ 'file' : 'systemd-report-cgroup@.service.in' },
{
'file' : 'systemd-resolved.service.in',
'conditions' : ['ENABLE_RESOLVE'],

View File

@ -13,7 +13,7 @@ Documentation=man:systemd-logind.service(8)
[Socket]
ListenStream=/run/systemd/io.systemd.Login
Symlinks=/run/varlink/registry/io.systemd.Login /run/varlink/registry/io.systemd.Shutdown /run/systemd/io.systemd.Shutdown
Symlinks=/run/varlink/registry/io.systemd.Login
FileDescriptorName=varlink
SocketMode=0666
Service=systemd-logind.service

View File

@ -1,25 +0,0 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
#
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[Unit]
Description=CGroup Report Varlink Socket
DefaultDependencies=no
Before=sockets.target shutdown.target
Conflicts=shutdown.target
[Socket]
ListenStream=/run/systemd/report/io.systemd.CGroup
FileDescriptorName=varlink
SocketMode=0666
Accept=yes
MaxConnectionsPerSource=16
RemoveOnStop=yes
[Install]
WantedBy=sockets.target

View File

@ -1,42 +0,0 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
#
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[Unit]
Description=CGroup Report Service
DefaultDependencies=no
Conflicts=shutdown.target
Before=shutdown.target
[Service]
CapabilityBoundingSet=
DeviceAllow=
DynamicUser=yes
IPAddressDeny=any
LockPersonality=yes
MemoryDenyWriteExecute=yes
PrivateDevices=yes
PrivateIPC=yes
PrivateNetwork=yes
PrivateTmp=disconnected
ProtectControlGroups=yes
ProtectHome=yes
ProtectHostname=yes
ProtectKernelLogs=yes
ProtectKernelModules=yes
ProtectKernelTunables=yes
ProtectSystem=strict
RestrictAddressFamilies=AF_UNIX
RestrictNamespaces=yes
RestrictRealtime=yes
RestrictSUIDSGID=yes
RuntimeMaxSec=1min
SystemCallArchitectures=native
SystemCallErrorNumber=EPERM
SystemCallFilter=@system-service
ExecStart={{LIBEXECDIR}}/systemd-report-cgroup