report: add metrics source that reports current disk space data
This commit is contained in:
committed by
Lennart Poettering
parent
9336b9ce23
commit
c25226b820
@@ -1209,6 +1209,10 @@ manpages = [
|
|||||||
'ENABLE_RANDOMSEED'],
|
'ENABLE_RANDOMSEED'],
|
||||||
['systemd-remount-fs.service', '8', ['systemd-remount-fs'], ''],
|
['systemd-remount-fs.service', '8', ['systemd-remount-fs'], ''],
|
||||||
['systemd-repart', '8', ['systemd-repart.service'], 'ENABLE_REPART'],
|
['systemd-repart', '8', ['systemd-repart.service'], 'ENABLE_REPART'],
|
||||||
|
['systemd-report-diskspace@.service',
|
||||||
|
'8',
|
||||||
|
['systemd-report-diskspace', 'systemd-report-diskspace.socket'],
|
||||||
|
'HAVE_LIBMOUNT'],
|
||||||
['systemd-report-files@.service',
|
['systemd-report-files@.service',
|
||||||
'8',
|
'8',
|
||||||
['systemd-report-files', 'systemd-report-files.socket'],
|
['systemd-report-files', 'systemd-report-files.socket'],
|
||||||
|
|||||||
@@ -0,0 +1,111 @@
|
|||||||
|
<?xml version="1.0"?> <!--*-nxml-*-->
|
||||||
|
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||||
|
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||||
|
<!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
|
||||||
|
|
||||||
|
<refentry id="systemd-report-diskspace_.service" xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||||
|
conditional='HAVE_LIBMOUNT'>
|
||||||
|
|
||||||
|
<refentryinfo>
|
||||||
|
<title>systemd-report-diskspace@.service</title>
|
||||||
|
<productname>systemd</productname>
|
||||||
|
</refentryinfo>
|
||||||
|
|
||||||
|
<refmeta>
|
||||||
|
<refentrytitle>systemd-report-diskspace@.service</refentrytitle>
|
||||||
|
<manvolnum>8</manvolnum>
|
||||||
|
</refmeta>
|
||||||
|
|
||||||
|
<refnamediv>
|
||||||
|
<refname>systemd-report-diskspace@.service</refname>
|
||||||
|
<refname>systemd-report-diskspace.socket</refname>
|
||||||
|
<refname>systemd-report-diskspace</refname>
|
||||||
|
<refpurpose>Report size and free disk space of mounted file systems as system report metrics</refpurpose>
|
||||||
|
</refnamediv>
|
||||||
|
|
||||||
|
<refsynopsisdiv>
|
||||||
|
<para><filename>systemd-report-diskspace@.service</filename></para>
|
||||||
|
<para><filename>systemd-report-diskspace.socket</filename></para>
|
||||||
|
<para><filename>/usr/lib/systemd/systemd-report-diskspace</filename></para>
|
||||||
|
</refsynopsisdiv>
|
||||||
|
|
||||||
|
<refsect1>
|
||||||
|
<title>Description</title>
|
||||||
|
|
||||||
|
<para><command>systemd-report-diskspace@.service</command> is a metrics source for
|
||||||
|
<citerefentry><refentrytitle>systemd-report</refentrytitle><manvolnum>1</manvolnum></citerefentry>. It
|
||||||
|
reports the size of the mounted file systems and how much disk space is still available on them, by
|
||||||
|
implementing the <constant>io.systemd.Metrics</constant> Varlink interface on a socket linked into the
|
||||||
|
<filename>/run/systemd/report/</filename> directory.</para>
|
||||||
|
|
||||||
|
<para>All mount points of the system are enumerated. Mount points of file systems that are not backed by
|
||||||
|
a block device (i.e. pseudo file systems such as <literal>proc</literal>, <literal>sysfs</literal> or
|
||||||
|
<literal>tmpfs</literal>, network file systems, <literal>overlay</literal>, …) are skipped, as are
|
||||||
|
read-only mount points. For each remaining mount point two gauge metrics are reported, with the mount
|
||||||
|
point path as metric object:</para>
|
||||||
|
|
||||||
|
<variablelist>
|
||||||
|
<varlistentry>
|
||||||
|
<term><literal>io.systemd.DiskSpace.SizeBytes</literal></term>
|
||||||
|
<listitem><para>The total size of the file system, in bytes. This matches the
|
||||||
|
<literal>1K-blocks</literal> column of
|
||||||
|
<citerefentry project='man-pages'><refentrytitle>df</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
||||||
|
(scaled to bytes).</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><literal>io.systemd.DiskSpace.FreeBytes</literal></term>
|
||||||
|
<listitem><para>The disk space still available to unprivileged users on the file system, in
|
||||||
|
bytes. This matches the <literal>Avail</literal> column of
|
||||||
|
<citerefentry project='man-pages'><refentrytitle>df</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||||
|
i.e. space reserved for the superuser (as many file systems do) is not counted as
|
||||||
|
free.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
</variablelist>
|
||||||
|
|
||||||
|
<para>The following metric fields are set on both metrics:</para>
|
||||||
|
|
||||||
|
<variablelist>
|
||||||
|
<varlistentry>
|
||||||
|
<term><varname>fileSystemType</varname></term>
|
||||||
|
<listitem><para>The file system type, for example <literal>ext4</literal> or
|
||||||
|
<literal>btrfs</literal>. Always set.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><varname>source</varname></term>
|
||||||
|
<listitem><para>The mount source, typically the device node the file system is mounted from, for
|
||||||
|
example <literal>/dev/sda1</literal>. Omitted if unknown.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><varname>originatingSource</varname></term>
|
||||||
|
<listitem><para>If the block device the file system is mounted from is a stacked one (for example a
|
||||||
|
LUKS or other device mapper volume), the device node of the block device it ultimately originates
|
||||||
|
from, for example <literal>/dev/sda2</literal> for a file system mounted from
|
||||||
|
<literal>/dev/mapper/root</literal>. Omitted if the source is not a stacked block device, or its
|
||||||
|
origin cannot be determined. Note that stacked devices backed by multiple block devices (e.g. RAID)
|
||||||
|
are not covered by this.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
</variablelist>
|
||||||
|
|
||||||
|
<para>A file system that is mounted multiple times (for example via bind mounts, or as multiple
|
||||||
|
subvolumes of the same volume) is reported only once, under the shortest of its mount point paths (and
|
||||||
|
among equally long ones, the alphabetically first). Mount points that are shadowed by another mount on
|
||||||
|
top of them, or that the service cannot access, are not considered.</para>
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
|
<!-- Note: we do not document the command line switches here. The systemd-report-diskspace binary itself
|
||||||
|
should not be invoked by users, but only as a service. Use systemd-report(1) to acquire metrics. -->
|
||||||
|
|
||||||
|
<refsect1>
|
||||||
|
<title>See Also</title>
|
||||||
|
<para><simplelist type="inline">
|
||||||
|
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||||
|
<member><citerefentry><refentrytitle>systemd-report</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||||
|
<member><citerefentry project='man-pages'><refentrytitle>df</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||||
|
<member><citerefentry project='man-pages'><refentrytitle>statfs</refentrytitle><manvolnum>2</manvolnum></citerefentry></member>
|
||||||
|
</simplelist></para>
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
|
</refentry>
|
||||||
@@ -35,6 +35,7 @@ enable systemd-nsresourced.socket
|
|||||||
enable systemd-pstore.service
|
enable systemd-pstore.service
|
||||||
enable systemd-report-basic.socket
|
enable systemd-report-basic.socket
|
||||||
enable systemd-report-cgroup.socket
|
enable systemd-report-cgroup.socket
|
||||||
|
enable systemd-report-diskspace.socket
|
||||||
enable systemd-report-files.socket
|
enable systemd-report-files.socket
|
||||||
enable systemd-report-hwmon.socket
|
enable systemd-report-hwmon.socket
|
||||||
enable systemd-report-sign-plain.socket
|
enable systemd-report-sign-plain.socket
|
||||||
|
|||||||
@@ -29,6 +29,15 @@ executables += [
|
|||||||
'report-cgroup-server.c',
|
'report-cgroup-server.c',
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
libexec_template + {
|
||||||
|
'name' : 'systemd-report-diskspace',
|
||||||
|
'sources' : files(
|
||||||
|
'report-diskspace.c',
|
||||||
|
'report-diskspace-server.c',
|
||||||
|
),
|
||||||
|
'dependencies' : libmount_cflags,
|
||||||
|
'conditions' : ['HAVE_LIBMOUNT'],
|
||||||
|
},
|
||||||
libexec_template + {
|
libexec_template + {
|
||||||
'name' : 'systemd-report-files',
|
'name' : 'systemd-report-files',
|
||||||
'sources' : files(
|
'sources' : files(
|
||||||
|
|||||||
@@ -0,0 +1,95 @@
|
|||||||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
|
||||||
|
#include "sd-json.h"
|
||||||
|
#include "sd-varlink.h"
|
||||||
|
|
||||||
|
#include "build.h"
|
||||||
|
#include "dlopen-note.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "main-func.h"
|
||||||
|
#include "report-diskspace.h"
|
||||||
|
#include "varlink-io.systemd.Metrics.h"
|
||||||
|
#include "varlink-util.h"
|
||||||
|
#include "verbs.h"
|
||||||
|
|
||||||
|
COMMAND(
|
||||||
|
"systemd-report-diskspace\0",
|
||||||
|
"Report disk space metrics.",
|
||||||
|
);
|
||||||
|
|
||||||
|
static int vl_server(void) {
|
||||||
|
_cleanup_(sd_varlink_server_unrefp) sd_varlink_server *vs = NULL;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = varlink_server_new(&vs, SD_VARLINK_SERVER_INHERIT_USERDATA, /* userdata= */ NULL);
|
||||||
|
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 parse_argv(int argc, char *argv[]) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(argc >= 0);
|
||||||
|
assert(argv);
|
||||||
|
|
||||||
|
OptionParser opts = { argc, argv };
|
||||||
|
|
||||||
|
FOREACH_OPTION_OR_RETURN(c, &opts)
|
||||||
|
switch (c) {
|
||||||
|
|
||||||
|
OPTION_COMMON_HELP:
|
||||||
|
return command_print_help();
|
||||||
|
|
||||||
|
OPTION_COMMON_VERSION:
|
||||||
|
return version();
|
||||||
|
|
||||||
|
OPTION_COMMON_INTROSPECT_CLI:
|
||||||
|
return introspect_cli(SD_JSON_FORMAT_OFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (option_parser_get_n_args(&opts) > 0)
|
||||||
|
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;
|
||||||
|
|
||||||
|
LIBMOUNT_NOTE(required);
|
||||||
|
|
||||||
|
log_setup();
|
||||||
|
|
||||||
|
r = parse_argv(argc, argv);
|
||||||
|
if (r <= 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
return vl_server();
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_MAIN_FUNCTION(run);
|
||||||
@@ -0,0 +1,366 @@
|
|||||||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/statvfs.h>
|
||||||
|
|
||||||
|
#include "sd-device.h"
|
||||||
|
#include "sd-json.h"
|
||||||
|
#include "sd-varlink.h"
|
||||||
|
|
||||||
|
#include "alloc-util.h"
|
||||||
|
#include "blockdev-util.h"
|
||||||
|
#include "device-util.h"
|
||||||
|
#include "devnum-util.h"
|
||||||
|
#include "fd-util.h"
|
||||||
|
#include "hash-funcs.h"
|
||||||
|
#include "hashmap.h"
|
||||||
|
#include "json-util.h"
|
||||||
|
#include "libmount-util.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "metrics.h"
|
||||||
|
#include "mountpoint-util.h"
|
||||||
|
#include "path-util.h"
|
||||||
|
#include "report-diskspace.h"
|
||||||
|
#include "sort-util.h"
|
||||||
|
#include "stat-util.h"
|
||||||
|
|
||||||
|
/* Reports the size of and the disk space still available on all mounted, writable, block device backed file
|
||||||
|
* systems, i.e. roughly what df(1) shows. Pseudo file systems (procfs, sysfs, tmpfs, …), network file
|
||||||
|
* systems and other file systems not backed by a block device are skipped, as are read-only mounts: their
|
||||||
|
* free space is not going to change, and typically is not meaningful anyway (squashfs, erofs, DDIs, …).
|
||||||
|
*
|
||||||
|
* A file system (i.e. a superblock, identified by its device number) that is mounted in multiple places
|
||||||
|
* (bind mounts, btrfs subvolumes, …) is reported only once, under its shortest mount path. */
|
||||||
|
|
||||||
|
typedef struct FileSystem {
|
||||||
|
dev_t devno; /* the hashmap key: device number of the superblock */
|
||||||
|
struct libmnt_fs *fs; /* the mount we report the file system under, owned by the mount table */
|
||||||
|
int fd; /* O_PATH fd to the mount point */
|
||||||
|
uint64_t free_bytes;
|
||||||
|
uint64_t size_bytes;
|
||||||
|
} FileSystem;
|
||||||
|
|
||||||
|
static FileSystem* file_system_free(FileSystem *f) {
|
||||||
|
if (!f)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
safe_close(f->fd);
|
||||||
|
return mfree(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_TRIVIAL_CLEANUP_FUNC(FileSystem*, file_system_free);
|
||||||
|
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
|
||||||
|
file_system_hash_ops,
|
||||||
|
dev_t, devt_hash_func, devt_compare_func,
|
||||||
|
FileSystem, file_system_free);
|
||||||
|
|
||||||
|
static const char* file_system_path(const FileSystem *f) {
|
||||||
|
assert(f);
|
||||||
|
assert(f->fs);
|
||||||
|
|
||||||
|
return ASSERT_PTR(sym_mnt_fs_get_target(f->fs));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Among the mount points of the same file system we prefer the shortest path, and among equally short ones
|
||||||
|
* the alphabetically earlier. */
|
||||||
|
static bool path_is_preferred(const char *a, const char *b) {
|
||||||
|
assert(a);
|
||||||
|
assert(b);
|
||||||
|
|
||||||
|
int ret = CMP(strlen(a), strlen(b));
|
||||||
|
if (ret != 0)
|
||||||
|
return ret < 0;
|
||||||
|
|
||||||
|
return path_compare(a, b) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int file_system_compare(FileSystem *const *a, FileSystem *const *b) {
|
||||||
|
assert(a);
|
||||||
|
assert(b);
|
||||||
|
return path_compare(file_system_path(*a), file_system_path(*b));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mount_collect(Hashmap **file_systems, struct libmnt_fs *fs) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(file_systems);
|
||||||
|
assert(fs);
|
||||||
|
|
||||||
|
const char *target = sym_mnt_fs_get_target(fs);
|
||||||
|
if (!target)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
const char *fstype = sym_mnt_fs_get_fstype(fs);
|
||||||
|
if (!fstype)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!fstype_is_blockdev_backed(fstype)) {
|
||||||
|
log_debug("Mount '%s' of type %s is not backed by a block device, skipping.", target, fstype);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This covers both file systems that are read-only as a whole, and read-only bind mounts of
|
||||||
|
* otherwise writable file systems, since libmount searches both the superblock and the per-mount
|
||||||
|
* options here. */
|
||||||
|
r = sym_mnt_fs_get_option(fs, "ro", /* value= */ NULL, /* valsz= */ NULL);
|
||||||
|
if (r < 0)
|
||||||
|
return log_debug_errno(r, "Failed to check whether '%s' is mounted read-only: %m", target);
|
||||||
|
if (r == 0) {
|
||||||
|
log_debug("Mount '%s' is read-only, skipping.", target);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_t devno = sym_mnt_fs_get_devno(fs);
|
||||||
|
if (devno == 0) {
|
||||||
|
log_debug("Mount '%s' has no device number, skipping.", target);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
FileSystem *existing = hashmap_get(*file_systems, &devno);
|
||||||
|
if (existing && !path_is_preferred(target, file_system_path(existing))) {
|
||||||
|
log_debug("File system mounted on '%s' is already known as '%s', skipping.",
|
||||||
|
target, file_system_path(existing));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mount points below a directory we lack access to (or that have been unmounted since the mount
|
||||||
|
* table was read) are simply not considered. */
|
||||||
|
_cleanup_close_ int fd = open(target, O_PATH|O_CLOEXEC);
|
||||||
|
if (fd < 0) {
|
||||||
|
log_debug_errno(errno, "Failed to open mount point '%s', ignoring: %m", target);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure the path still refers to the mount we are looking at, and not to something that was
|
||||||
|
* mounted on top of it since, shadowing it. Also catches mount points that are hidden entirely. */
|
||||||
|
int mnt_id;
|
||||||
|
r = path_get_mnt_id_at(fd, /* path= */ NULL, &mnt_id);
|
||||||
|
if (r < 0) {
|
||||||
|
log_debug_errno(r, "Failed to get mount ID of '%s', ignoring: %m", target);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (mnt_id != sym_mnt_fs_get_id(fs)) {
|
||||||
|
log_debug("Mount '%s' is shadowed by another mount, skipping.", target);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct statfs sfs;
|
||||||
|
r = xstatfsat(fd, /* path= */ NULL, &sfs);
|
||||||
|
if (r < 0) {
|
||||||
|
log_debug_errno(r, "Failed to statfs() '%s', ignoring: %m", target);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Already excluded above based on the mount table, but let's check again on the authoritative data,
|
||||||
|
* in case things changed in the meantime. */
|
||||||
|
if (FLAGS_SET(sfs.f_flags, ST_RDONLY)) {
|
||||||
|
log_debug("Mount '%s' is read-only, skipping.", target);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sfs.f_blocks == 0) {
|
||||||
|
log_debug("Mount '%s' has zero size, skipping.", target);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Report the space available to unprivileged users as free, matching what df(1) shows as "Avail".
|
||||||
|
* Space reserved for the superuser (typically 5% on ext4) is hence not counted as free. */
|
||||||
|
uint64_t size_bytes, free_bytes;
|
||||||
|
|
||||||
|
if (!MUL_SAFE(&free_bytes, (uint64_t) sfs.f_frsize, (uint64_t) sfs.f_bavail) ||
|
||||||
|
!MUL_SAFE(&size_bytes, (uint64_t) sfs.f_frsize, (uint64_t) sfs.f_blocks)) {
|
||||||
|
log_debug("Sizes of '%s' overflow, skipping.", target);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_cleanup_(file_system_freep) FileSystem *f = new(FileSystem, 1);
|
||||||
|
if (!f)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
*f = (FileSystem) {
|
||||||
|
.devno = devno,
|
||||||
|
.fs = fs,
|
||||||
|
.fd = TAKE_FD(fd),
|
||||||
|
.free_bytes = free_bytes,
|
||||||
|
.size_bytes = size_bytes,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Replace the entry we already have for this file system, if any, by the better one */
|
||||||
|
file_system_free(hashmap_remove(*file_systems, &f->devno));
|
||||||
|
|
||||||
|
if (hashmap_ensure_put(file_systems, &file_system_hash_ops, &f->devno, f) < 0)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
TAKE_PTR(f);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the file system's backing block device is a stacked one (LUKS-style DM, …), returns the device node of
|
||||||
|
* the block device it originates from, chased down through all layers. Returns NULL (and success) if the
|
||||||
|
* backing device is not a stacked block device, or is not a block device at all. */
|
||||||
|
static int file_system_get_originating_source(const FileSystem *f, char **ret) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(f);
|
||||||
|
assert(ret);
|
||||||
|
|
||||||
|
/* NB: We do not use f->devno here, but acquire the devno again from the fd. That's because on btrfs
|
||||||
|
* we want the devnum of the backing device node, and not of the anonymous superblock */
|
||||||
|
dev_t devno;
|
||||||
|
r = get_block_device_fd(f->fd, &devno);
|
||||||
|
if (r < 0) {
|
||||||
|
return log_debug_errno(r, "Failed to get backing block device of '%s', ignoring: %m", file_system_path(f));
|
||||||
|
*ret = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (devno == 0) {
|
||||||
|
log_debug("Path '%s' has no backing block device, ignoring.", file_system_path(f));
|
||||||
|
*ret = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The mount's device number is the backing block device's (except for file systems that use
|
||||||
|
* anonymous device numbers, such as btrfs, which we hence cannot trace this way). */
|
||||||
|
_cleanup_(sd_device_unrefp) sd_device *dev = NULL;
|
||||||
|
r = sd_device_new_from_devnum(&dev, 'b', devno);
|
||||||
|
if (r < 0) {
|
||||||
|
log_debug_errno(r, "Failed to get block device " DEVNUM_FORMAT_STR " backing '%s', ignoring: %m",
|
||||||
|
DEVNUM_FORMAT_VAL(devno), file_system_path(f));
|
||||||
|
*ret = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_cleanup_(sd_device_unrefp) sd_device *origin = NULL;
|
||||||
|
r = block_device_get_originating(dev, &origin, /* recursive= */ true);
|
||||||
|
if (r < 0) {
|
||||||
|
if (r != -ENOENT) /* -ENOENT means: not stacked */
|
||||||
|
log_device_debug_errno(dev, r, "Failed to determine originating block device, ignoring: %m");
|
||||||
|
*ret = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *node;
|
||||||
|
r = sd_device_get_devname(origin, &node);
|
||||||
|
if (r < 0) {
|
||||||
|
log_device_debug_errno(origin, r, "Failed to get device node of originating block device, ignoring: %m");
|
||||||
|
*ret = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return strdup_to(ret, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int file_system_send(
|
||||||
|
const MetricFamily mf[static 2],
|
||||||
|
sd_varlink *link,
|
||||||
|
const FileSystem *f) {
|
||||||
|
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(mf && mf[0].name && mf[1].name);
|
||||||
|
assert(link);
|
||||||
|
assert(f);
|
||||||
|
|
||||||
|
_cleanup_free_ char *originating_source = NULL;
|
||||||
|
r = file_system_get_originating_source(f, &originating_source);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to determine originating source: %m");
|
||||||
|
|
||||||
|
_cleanup_(sd_json_variant_unrefp) sd_json_variant *fields = NULL;
|
||||||
|
r = sd_json_buildo(
|
||||||
|
&fields,
|
||||||
|
JSON_BUILD_PAIR_STRING_NON_EMPTY("source", sym_mnt_fs_get_source(f->fs)),
|
||||||
|
JSON_BUILD_PAIR_STRING_NON_EMPTY("originatingSource", originating_source),
|
||||||
|
SD_JSON_BUILD_PAIR_STRING("fileSystemType", sym_mnt_fs_get_fstype(f->fs)));
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to build metric fields: %m");
|
||||||
|
|
||||||
|
r = metric_build_send_unsigned(mf + 0, link, file_system_path(f), f->free_bytes, fields);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
return metric_build_send_unsigned(mf + 1, link, file_system_path(f), f->size_bytes, fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int diskspace_generate(
|
||||||
|
const MetricFamily mf[static 2],
|
||||||
|
sd_varlink *link,
|
||||||
|
void *userdata) {
|
||||||
|
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(mf);
|
||||||
|
assert(link);
|
||||||
|
|
||||||
|
_cleanup_(mnt_free_tablep) struct libmnt_table *table = NULL;
|
||||||
|
_cleanup_(mnt_free_iterp) struct libmnt_iter *iter = NULL;
|
||||||
|
r = libmount_parse_mountinfo(/* source= */ NULL, &table, &iter);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to parse /proc/self/mountinfo: %m");
|
||||||
|
|
||||||
|
/* First pass: collect all file systems we care about, keyed by superblock */
|
||||||
|
_cleanup_hashmap_free_ Hashmap *file_systems = NULL;
|
||||||
|
for (;;) {
|
||||||
|
struct libmnt_fs *fs;
|
||||||
|
|
||||||
|
r = sym_mnt_table_next_fs(table, iter, &fs);
|
||||||
|
if (r == 1)
|
||||||
|
break;
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to get next entry from /proc/self/mountinfo: %m");
|
||||||
|
|
||||||
|
r = mount_collect(&file_systems, fs);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Second pass: report them, sorted by mount path for stable output */
|
||||||
|
_cleanup_free_ FileSystem **sorted = NULL;
|
||||||
|
size_t n = 0;
|
||||||
|
FileSystem *f;
|
||||||
|
HASHMAP_FOREACH(f, file_systems) {
|
||||||
|
if (!GREEDY_REALLOC(sorted, n + 1))
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
sorted[n++] = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
typesafe_qsort(sorted, n, file_system_compare);
|
||||||
|
|
||||||
|
FOREACH_ARRAY(i, sorted, n) {
|
||||||
|
r = file_system_send(mf, link, *i);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const MetricFamily diskspace_metric_family_table[] = {
|
||||||
|
/* Keep metrics ordered alphabetically. Both are generated by the same function, attached to the
|
||||||
|
* first of them. */
|
||||||
|
{
|
||||||
|
"io.systemd.DiskSpace.FreeBytes",
|
||||||
|
"Per file system metric: disk space available to unprivileged users in bytes, on writable "
|
||||||
|
"block device backed file systems (object=mount point, fileSystemType=file system type, "
|
||||||
|
"source=backing device, originatingSource=device the backing device is stacked on, if any)",
|
||||||
|
METRIC_FAMILY_TYPE_GAUGE,
|
||||||
|
.generate = diskspace_generate,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"io.systemd.DiskSpace.SizeBytes",
|
||||||
|
"Per file system metric: file system size in bytes, on writable block device backed file "
|
||||||
|
"systems (object=mount point, fileSystemType=file system type, source=backing device, "
|
||||||
|
"originatingSource=device the backing device is stacked on, if any)",
|
||||||
|
METRIC_FAMILY_TYPE_GAUGE,
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
int vl_method_describe_metrics(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
|
||||||
|
return metrics_method_describe(diskspace_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) {
|
||||||
|
return metrics_method_list(diskspace_metric_family_table, link, parameters, flags, userdata);
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "forward.h"
|
||||||
|
|
||||||
|
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);
|
||||||
@@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
DLSYM_PROTOTYPE(mnt_free_iter) = NULL;
|
DLSYM_PROTOTYPE(mnt_free_iter) = NULL;
|
||||||
DLSYM_PROTOTYPE(mnt_free_table) = NULL;
|
DLSYM_PROTOTYPE(mnt_free_table) = NULL;
|
||||||
|
DLSYM_PROTOTYPE(mnt_fs_get_devno) = NULL;
|
||||||
DLSYM_PROTOTYPE(mnt_fs_get_fs_options) = NULL;
|
DLSYM_PROTOTYPE(mnt_fs_get_fs_options) = NULL;
|
||||||
DLSYM_PROTOTYPE(mnt_fs_get_fstype) = NULL;
|
DLSYM_PROTOTYPE(mnt_fs_get_fstype) = NULL;
|
||||||
DLSYM_PROTOTYPE(mnt_fs_get_id) = NULL;
|
DLSYM_PROTOTYPE(mnt_fs_get_id) = NULL;
|
||||||
@@ -154,6 +155,7 @@ int dlopen_libmount(int log_level) {
|
|||||||
log_level,
|
log_level,
|
||||||
DLSYM_ARG(mnt_free_iter),
|
DLSYM_ARG(mnt_free_iter),
|
||||||
DLSYM_ARG(mnt_free_table),
|
DLSYM_ARG(mnt_free_table),
|
||||||
|
DLSYM_ARG(mnt_fs_get_devno),
|
||||||
DLSYM_ARG(mnt_fs_get_fs_options),
|
DLSYM_ARG(mnt_fs_get_fs_options),
|
||||||
DLSYM_ARG(mnt_fs_get_fstype),
|
DLSYM_ARG(mnt_fs_get_fstype),
|
||||||
DLSYM_ARG(mnt_fs_get_id),
|
DLSYM_ARG(mnt_fs_get_id),
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
extern DLSYM_PROTOTYPE(mnt_free_iter);
|
extern DLSYM_PROTOTYPE(mnt_free_iter);
|
||||||
extern DLSYM_PROTOTYPE(mnt_free_table);
|
extern DLSYM_PROTOTYPE(mnt_free_table);
|
||||||
|
extern DLSYM_PROTOTYPE(mnt_fs_get_devno);
|
||||||
extern DLSYM_PROTOTYPE(mnt_fs_get_fs_options);
|
extern DLSYM_PROTOTYPE(mnt_fs_get_fs_options);
|
||||||
extern DLSYM_PROTOTYPE(mnt_fs_get_fstype);
|
extern DLSYM_PROTOTYPE(mnt_fs_get_fstype);
|
||||||
extern DLSYM_PROTOTYPE(mnt_fs_get_id);
|
extern DLSYM_PROTOTYPE(mnt_fs_get_id);
|
||||||
|
|||||||
@@ -109,6 +109,7 @@ INTROSPECTABLE=(
|
|||||||
systemd-report
|
systemd-report
|
||||||
systemd-report-basic
|
systemd-report-basic
|
||||||
systemd-report-cgroup
|
systemd-report-cgroup
|
||||||
|
systemd-report-diskspace
|
||||||
systemd-report-files
|
systemd-report-files
|
||||||
systemd-report-hwmon
|
systemd-report-hwmon
|
||||||
systemd-report-sign-plain
|
systemd-report-sign-plain
|
||||||
|
|||||||
@@ -93,6 +93,105 @@ fi
|
|||||||
"$REPORT" describe io.systemd.HWMon
|
"$REPORT" describe io.systemd.HWMon
|
||||||
"$REPORT" metrics io.systemd.HWMon
|
"$REPORT" metrics io.systemd.HWMon
|
||||||
|
|
||||||
|
# test io.systemd.DiskSpace Metrics
|
||||||
|
|
||||||
|
# Mount a scratch ext4 file system and check that it is reported with plausible numbers, that a tmpfs next to
|
||||||
|
# it is not, that additional bind mounts of it do not result in additional rows but the shortest writable
|
||||||
|
# mount path wins regardless of mount order, that it disappears from the report once remounted read-only,
|
||||||
|
# and that a device mapper device stacked on top of it is reported with the loop device as originating
|
||||||
|
# source.
|
||||||
|
diskspace_mount_tests() {
|
||||||
|
# Loop devices and device mapper are not available in containers
|
||||||
|
if systemd-detect-virt --quiet --container; then
|
||||||
|
echo "Skipping io.systemd.DiskSpace mount tests in container."
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
DISKSPACE_WORK="$(mktemp -d /var/tmp/report-diskspace.XXXXXX)"
|
||||||
|
diskspace_cleanup() {
|
||||||
|
set +e
|
||||||
|
umount "$DISKSPACE_WORK/tmpfs" "$DISKSPACE_WORK/a" "$DISKSPACE_WORK/b" "$DISKSPACE_WORK/longer" "$DISKSPACE_WORK/ext4" "$DISKSPACE_WORK/dm"
|
||||||
|
dmsetup remove report-diskspace
|
||||||
|
systemd-dissect --detach "$DISKSPACE_WORK/scratch.raw"
|
||||||
|
rm -rf "$DISKSPACE_WORK"
|
||||||
|
set -e
|
||||||
|
}
|
||||||
|
trap diskspace_cleanup EXIT
|
||||||
|
mkdir "$DISKSPACE_WORK/ext4" "$DISKSPACE_WORK/a" "$DISKSPACE_WORK/b" "$DISKSPACE_WORK/longer" "$DISKSPACE_WORK/dm" "$DISKSPACE_WORK/tmpfs"
|
||||||
|
truncate -s 64M "$DISKSPACE_WORK/scratch.raw"
|
||||||
|
mkfs.ext4 -q "$DISKSPACE_WORK/scratch.raw"
|
||||||
|
DISKSPACE_LOOP="$(systemd-dissect --attach --loop-ref=report-diskspace "$DISKSPACE_WORK/scratch.raw")"
|
||||||
|
mount "$DISKSPACE_LOOP" "$DISKSPACE_WORK/ext4"
|
||||||
|
# "a" sorts before "b" and is just as short, but is read-only, hence "b" must be picked
|
||||||
|
mount --bind -o ro "$DISKSPACE_WORK/ext4" "$DISKSPACE_WORK/a"
|
||||||
|
mount --bind "$DISKSPACE_WORK/ext4" "$DISKSPACE_WORK/b"
|
||||||
|
# "longer" is writable too, but has a longer path, hence must not win even though it is mounted last
|
||||||
|
mount --bind "$DISKSPACE_WORK/ext4" "$DISKSPACE_WORK/longer"
|
||||||
|
mount -t tmpfs tmpfs "$DISKSPACE_WORK/tmpfs"
|
||||||
|
dd if=/dev/urandom of="$DISKSPACE_WORK/ext4/fill" bs=1M count=8
|
||||||
|
sync -f "$DISKSPACE_WORK/ext4"
|
||||||
|
|
||||||
|
diskspace_metrics="$(varlinkctl call --more /run/systemd/report/io.systemd.DiskSpace io.systemd.Metrics.List {} | tr -d '\036')"
|
||||||
|
# Exactly one row per metric for the scratch file system, reported under the shortest writable mount path
|
||||||
|
[[ "$(echo "$diskspace_metrics" | jq -r --arg s "$DISKSPACE_LOOP" 'select(.name == "io.systemd.DiskSpace.SizeBytes" and .fields.source == $s) | .object')" == "$DISKSPACE_WORK/b" ]]
|
||||||
|
[[ "$(echo "$diskspace_metrics" | jq -r --arg s "$DISKSPACE_LOOP" 'select(.name == "io.systemd.DiskSpace.FreeBytes" and .fields.source == $s) | .object')" == "$DISKSPACE_WORK/b" ]]
|
||||||
|
diskspace_size="$(echo "$diskspace_metrics" | jq -r --arg o "$DISKSPACE_WORK/b" 'select(.name == "io.systemd.DiskSpace.SizeBytes" and .object == $o) | .value')"
|
||||||
|
diskspace_free="$(echo "$diskspace_metrics" | jq -r --arg o "$DISKSPACE_WORK/b" 'select(.name == "io.systemd.DiskSpace.FreeBytes" and .object == $o) | .value')"
|
||||||
|
# The file system cannot be larger than the image, and at least the 8M we wrote must be missing from the
|
||||||
|
# free space.
|
||||||
|
[[ "$diskspace_size" -gt 0 ]]
|
||||||
|
[[ "$diskspace_size" -le $((64 * 1024 * 1024)) ]]
|
||||||
|
[[ "$diskspace_free" -gt 0 ]]
|
||||||
|
[[ $((diskspace_free + 8 * 1024 * 1024)) -le "$diskspace_size" ]]
|
||||||
|
# df(1) derives the same two numbers from statfs(), hence they must match exactly.
|
||||||
|
read -r diskspace_df_size diskspace_df_avail < <(df -B1 --output=size,avail "$DISKSPACE_WORK/ext4" | sed 1d)
|
||||||
|
[[ "$diskspace_size" == "$diskspace_df_size" ]]
|
||||||
|
[[ "$diskspace_free" == "$diskspace_df_avail" ]]
|
||||||
|
# Both rows must carry the file system type as field, and no originating source, as a loop device is not
|
||||||
|
# stacked on anything
|
||||||
|
[[ "$(echo "$diskspace_metrics" | jq -r --arg o "$DISKSPACE_WORK/b" 'select(.object == $o) | .fields.fileSystemType' | sort -u)" == "ext4" ]]
|
||||||
|
[[ "$(echo "$diskspace_metrics" | jq -r --arg o "$DISKSPACE_WORK/b" 'select(.object == $o) | .fields | has("originatingSource") | tostring' | sort -u)" == "false" ]]
|
||||||
|
# The tmpfs may not be reported
|
||||||
|
(! echo "$diskspace_metrics" | jq -r '.object' | grep -Fx "$DISKSPACE_WORK/tmpfs" >/dev/null)
|
||||||
|
|
||||||
|
# Once remounted read-only the file system must no longer be reported, regardless of the mount path
|
||||||
|
mount -o remount,ro "$DISKSPACE_WORK/ext4"
|
||||||
|
diskspace_metrics="$(varlinkctl call --more --graceful=io.systemd.Metrics.NoSuchMetric /run/systemd/report/io.systemd.DiskSpace io.systemd.Metrics.List {} | tr -d '\036')"
|
||||||
|
(! echo "$diskspace_metrics" | jq -r '.fields.source' | grep -Fx "$DISKSPACE_LOOP" >/dev/null)
|
||||||
|
|
||||||
|
# Now stack a (linear) device mapper device on top of the loop device, and mount the file system through
|
||||||
|
# that: the DM device must be reported as source, and the loop device it sits on as originating source. The
|
||||||
|
# loop device must be unmounted first, as DM needs exclusive access to it.
|
||||||
|
umount "$DISKSPACE_WORK/a" "$DISKSPACE_WORK/b" "$DISKSPACE_WORK/longer" "$DISKSPACE_WORK/ext4"
|
||||||
|
dmsetup create report-diskspace --table "0 $(blockdev --getsz "$DISKSPACE_LOOP") linear $DISKSPACE_LOOP 0"
|
||||||
|
udevadm wait --timeout=30 --settle /dev/mapper/report-diskspace
|
||||||
|
mount /dev/mapper/report-diskspace "$DISKSPACE_WORK/dm"
|
||||||
|
diskspace_metrics="$(varlinkctl call --more /run/systemd/report/io.systemd.DiskSpace io.systemd.Metrics.List {} | tr -d '\036')"
|
||||||
|
[[ "$(echo "$diskspace_metrics" | jq -r --arg o "$DISKSPACE_WORK/dm" 'select(.object == $o) | .fields.source' | sort -u)" == "/dev/mapper/report-diskspace" ]]
|
||||||
|
[[ "$(echo "$diskspace_metrics" | jq -r --arg o "$DISKSPACE_WORK/dm" 'select(.object == $o) | .fields.originatingSource' | sort -u)" == "$DISKSPACE_LOOP" ]]
|
||||||
|
|
||||||
|
diskspace_cleanup
|
||||||
|
trap - EXIT
|
||||||
|
}
|
||||||
|
|
||||||
|
# The socket and service are only built if libmount is available
|
||||||
|
if ! systemctl cat systemd-report-diskspace.socket &>/dev/null; then
|
||||||
|
echo "systemd-report-diskspace.socket is not installed, skipping io.systemd.DiskSpace tests."
|
||||||
|
else
|
||||||
|
systemctl start systemd-report-diskspace.socket
|
||||||
|
varlinkctl info /run/systemd/report/io.systemd.DiskSpace
|
||||||
|
varlinkctl list-methods /run/systemd/report/io.systemd.DiskSpace
|
||||||
|
# varlinkctl emits a JSON-SEQ stream for --more; strip the record separators so that plain jq can consume it
|
||||||
|
diskspace_describe="$(varlinkctl call --more /run/systemd/report/io.systemd.DiskSpace io.systemd.Metrics.Describe {} | tr -d '\036')"
|
||||||
|
echo "$diskspace_describe" | jq -r 'select(.name == "io.systemd.DiskSpace.FreeBytes") | .type' | grep -wx gauge >/dev/null
|
||||||
|
echo "$diskspace_describe" | jq -r 'select(.name == "io.systemd.DiskSpace.SizeBytes") | .type' | grep -wx gauge >/dev/null
|
||||||
|
|
||||||
|
diskspace_mount_tests
|
||||||
|
|
||||||
|
"$REPORT" describe io.systemd.DiskSpace
|
||||||
|
"$REPORT" metrics io.systemd.DiskSpace
|
||||||
|
fi
|
||||||
|
|
||||||
# test io.systemd.Basic Metrics
|
# test io.systemd.Basic Metrics
|
||||||
# ensure the socket is running, as some distros don't enable it by default
|
# ensure the socket is running, as some distros don't enable it by default
|
||||||
systemctl start systemd-report-basic.socket
|
systemctl start systemd-report-basic.socket
|
||||||
|
|||||||
@@ -588,3 +588,8 @@ systemd.network.xml ./refsect1[title="[ModemManager] Section Options"]/variablel
|
|||||||
systemd-report-hwmon@.service.xml ./refsect1[title="Description"]/variablelist/varlistentry[term="chip"]
|
systemd-report-hwmon@.service.xml ./refsect1[title="Description"]/variablelist/varlistentry[term="chip"]
|
||||||
systemd-report-hwmon@.service.xml ./refsect1[title="Description"]/variablelist/varlistentry[term="sensor"]
|
systemd-report-hwmon@.service.xml ./refsect1[title="Description"]/variablelist/varlistentry[term="sensor"]
|
||||||
systemd-report-hwmon@.service.xml ./refsect1[title="Description"]/variablelist/varlistentry[term="label"]
|
systemd-report-hwmon@.service.xml ./refsect1[title="Description"]/variablelist/varlistentry[term="label"]
|
||||||
|
systemd-report-diskspace@.service.xml ./refsect1[title="Description"]/variablelist[1]/varlistentry[term="io.systemd.DiskSpace.SizeBytes"]
|
||||||
|
systemd-report-diskspace@.service.xml ./refsect1[title="Description"]/variablelist[1]/varlistentry[term="io.systemd.DiskSpace.FreeBytes"]
|
||||||
|
systemd-report-diskspace@.service.xml ./refsect1[title="Description"]/variablelist[2]/varlistentry[term="source"]
|
||||||
|
systemd-report-diskspace@.service.xml ./refsect1[title="Description"]/variablelist[2]/varlistentry[term="originatingSource"]
|
||||||
|
systemd-report-diskspace@.service.xml ./refsect1[title="Description"]/variablelist[2]/varlistentry[term="fileSystemType"]
|
||||||
|
|||||||
@@ -794,6 +794,14 @@ units = [
|
|||||||
},
|
},
|
||||||
{ 'file' : 'systemd-report-cgroup.socket' },
|
{ 'file' : 'systemd-report-cgroup.socket' },
|
||||||
{ 'file' : 'systemd-report-cgroup@.service.in' },
|
{ 'file' : 'systemd-report-cgroup@.service.in' },
|
||||||
|
{
|
||||||
|
'file' : 'systemd-report-diskspace.socket',
|
||||||
|
'conditions' : ['HAVE_LIBMOUNT'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'file' : 'systemd-report-diskspace@.service.in',
|
||||||
|
'conditions' : ['HAVE_LIBMOUNT'],
|
||||||
|
},
|
||||||
{ 'file' : 'systemd-report-files.socket' },
|
{ 'file' : 'systemd-report-files.socket' },
|
||||||
{ 'file' : 'systemd-report-files@.service.in' },
|
{ 'file' : 'systemd-report-files@.service.in' },
|
||||||
{ 'file' : 'systemd-report-hwmon.socket' },
|
{ 'file' : 'systemd-report-hwmon.socket' },
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
# 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=Disk Space Report Varlink Socket
|
||||||
|
Documentation=man:systemd-report-diskspace@.service(8)
|
||||||
|
DefaultDependencies=no
|
||||||
|
Before=sockets.target shutdown.target
|
||||||
|
Conflicts=shutdown.target
|
||||||
|
|
||||||
|
[Socket]
|
||||||
|
ListenStream=/run/systemd/report/io.systemd.DiskSpace
|
||||||
|
FileDescriptorName=varlink
|
||||||
|
SocketMode=0666
|
||||||
|
Accept=yes
|
||||||
|
MaxConnectionsPerSource=16
|
||||||
|
RemoveOnStop=yes
|
||||||
|
XAttrEntryPoint=user.varlink=entrypoint
|
||||||
|
XAttrListen=user.varlink=listen
|
||||||
|
XAttrAccept=user.varlink=server
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=sockets.target
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
# 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=Disk Space Report Service
|
||||||
|
Documentation=man:systemd-report-diskspace@.service(8)
|
||||||
|
DefaultDependencies=no
|
||||||
|
Conflicts=shutdown.target
|
||||||
|
Before=shutdown.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
# Note that DynamicUser=, ProtectSystem=, ProtectHome= and PrivateTmp= are deliberately not used here: they
|
||||||
|
# make the host's file systems appear read-only, or shadow them with private mounts, in the service's mount
|
||||||
|
# namespace, and hence would hide from this service exactly what it is supposed to report on.
|
||||||
|
CapabilityBoundingSet=
|
||||||
|
DeviceAllow=
|
||||||
|
IPAddressDeny=any
|
||||||
|
LockPersonality=yes
|
||||||
|
MemoryDenyWriteExecute=yes
|
||||||
|
NoNewPrivileges=yes
|
||||||
|
PrivateDevices=yes
|
||||||
|
PrivateIPC=yes
|
||||||
|
PrivateNetwork=yes
|
||||||
|
ProtectControlGroups=yes
|
||||||
|
ProtectHostname=yes
|
||||||
|
ProtectKernelLogs=yes
|
||||||
|
ProtectKernelModules=yes
|
||||||
|
ProtectKernelTunables=yes
|
||||||
|
RestrictAddressFamilies=AF_UNIX
|
||||||
|
RestrictNamespaces=yes
|
||||||
|
RestrictRealtime=yes
|
||||||
|
RestrictSUIDSGID=yes
|
||||||
|
RuntimeMaxSec=1min
|
||||||
|
SystemCallArchitectures=native
|
||||||
|
SystemCallErrorNumber=EPERM
|
||||||
|
SystemCallFilter=@system-service
|
||||||
|
ExecStart={{LIBEXECDIR}}/systemd-report-diskspace
|
||||||
Reference in New Issue
Block a user