Compare commits
9 Commits
6c4da28d7b
...
252b0f4dee
Author | SHA1 | Date |
---|---|---|
Daan De Meyer | 252b0f4dee | |
Yu Watanabe | 5261c521e3 | |
Franck Bui | 514d9e1665 | |
Lennart Poettering | b480a4c15e | |
Lennart Poettering | af3baf174a | |
Ryan Wilson | d8091e1281 | |
Daan De Meyer | 45ce3cf8e7 | |
Daan De Meyer | ad4ad82924 | |
Daan De Meyer | 8c1bff449c |
25
TODO
25
TODO
|
@ -129,6 +129,10 @@ Deprecations and removals:
|
|||
|
||||
Features:
|
||||
|
||||
* format-table: introduce new cell type for strings with ansi sequences in
|
||||
them. display them in regular output mode (via strip_tab_ansi()), but
|
||||
suppress them in json mode.
|
||||
|
||||
* machined: when registering a machine, also take a relative cgroup path,
|
||||
relative to the machine's unit. This is useful when registering unpriv
|
||||
machines, as they might sit down the cgroup tree, below a cgroup delegation
|
||||
|
@ -217,12 +221,8 @@ Features:
|
|||
services where mount propagation from the root fs is off, an still have
|
||||
confext/sysext propagated in.
|
||||
|
||||
* support F_DUDFD_QUERY for comparing fds in same_fd (requires kernel 6.10)
|
||||
|
||||
* generic interface for varlink for setting log level and stuff that all our daemons can implement
|
||||
|
||||
* use pty ioctl to get peer wherever possible (TIOCGPTPEER)
|
||||
|
||||
* maybe teach repart.d/ dropins a new setting MakeMountNodes= or so, which is
|
||||
just like MakeDirectories=, but uses an access mode of 0000 and sets the +i
|
||||
chattr bit. This is useful as protection against early uses of /var/ or /tmp/
|
||||
|
@ -253,8 +253,6 @@ Features:
|
|||
* initrd: when transitioning from initrd to host, validate that
|
||||
/lib/modules/`uname -r` exists, refuse otherwise
|
||||
|
||||
* tmpfiles: add "owning" flag for lines that limits effect of --purge
|
||||
|
||||
* signed bpf loading: to address need for signature verification for bpf
|
||||
programs when they are loaded, and given the bpf folks don't think this is
|
||||
realistic in kernel space, maybe add small daemon that facilitates this
|
||||
|
@ -458,9 +456,6 @@ Features:
|
|||
* introduce mntid_t, and make it 64bit, as apparently the kernel switched to
|
||||
64bit mount ids
|
||||
|
||||
* use udev rule networkd ownership property to take ownership of network
|
||||
interfaces nspawn creates
|
||||
|
||||
* mountfsd/nsresourced
|
||||
- userdb: maybe allow callers to map one uid to their own uid
|
||||
- bpflsm: allow writes if resulting UID on disk would be userns' owner UID
|
||||
|
@ -647,6 +642,7 @@ Features:
|
|||
- openpt_allocate_in_namespace()
|
||||
- unit_attach_pid_to_cgroup_via_bus()
|
||||
- cg_attach() – requires new kernel feature
|
||||
- journald's process cache
|
||||
|
||||
* ddi must be listed as block device fstype
|
||||
|
||||
|
@ -1470,9 +1466,6 @@ Features:
|
|||
|
||||
* in sd-id128: also parse UUIDs in RFC4122 URN syntax (i.e. chop off urn:uuid: prefix)
|
||||
|
||||
* DynamicUser= + StateDirectory= → use uid mapping mounts, too, in order to
|
||||
make dirs appear under right UID.
|
||||
|
||||
* systemd-sysext: optionally, run it in initrd already, before transitioning
|
||||
into host, to open up possibility for services shipped like that.
|
||||
|
||||
|
@ -1644,14 +1637,6 @@ Features:
|
|||
|
||||
* maybe add kernel cmdline params: to force random seed crediting
|
||||
|
||||
* introduce a new per-process uuid, similar to the boot id, the machine id, the
|
||||
invocation id, that is derived from process creds, specifically a hashed
|
||||
combination of AT_RANDOM + getpid() + the starttime from
|
||||
/proc/self/status. Then add these ids implicitly when logging. Deriving this
|
||||
uuid from these three things has the benefit that it can be derived easily
|
||||
from /proc/$PID/ in a stable, and unique way that changes on both fork() and
|
||||
exec().
|
||||
|
||||
* let's not GC a unit while its ratelimits are still pending
|
||||
|
||||
* when killing due to service watchdog timeout maybe detect whether target
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "macro.h"
|
||||
#include "version.h"
|
||||
|
||||
extern const char* const systemd_features;
|
||||
|
||||
#define PROJECT_VERSION_STR STRINGIFY(PROJECT_VERSION)
|
||||
|
||||
int version(void);
|
||||
|
|
|
@ -1131,6 +1131,8 @@ int xopenat_full(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_
|
|||
* • If O_CREAT is used with XO_LABEL, any created file will be immediately relabelled.
|
||||
*
|
||||
* • If the path is specified NULL or empty, behaves like fd_reopen().
|
||||
*
|
||||
* • If XO_NOCOW is specified will turn on the NOCOW btrfs flag on the file, if available.
|
||||
*/
|
||||
|
||||
if (isempty(path)) {
|
||||
|
|
|
@ -3,13 +3,18 @@
|
|||
#include "sd-varlink.h"
|
||||
|
||||
#include "core-varlink.h"
|
||||
#include "format-util.h"
|
||||
#include "json-util.h"
|
||||
#include "manager-json.h"
|
||||
#include "mkdir-label.h"
|
||||
#include "strv.h"
|
||||
#include "unit-json.h"
|
||||
#include "user-util.h"
|
||||
#include "varlink-internal.h"
|
||||
#include "varlink-serialize.h"
|
||||
#include "varlink-io.systemd.UserDatabase.h"
|
||||
#include "varlink-io.systemd.ManagedOOM.h"
|
||||
#include "varlink-io.systemd.Manager.h"
|
||||
#include "varlink-util.h"
|
||||
|
||||
typedef struct LookupParameters {
|
||||
|
@ -22,6 +27,11 @@ typedef struct LookupParameters {
|
|||
const char *service;
|
||||
} LookupParameters;
|
||||
|
||||
typedef struct DescribeUnitsParameters {
|
||||
char **states;
|
||||
char **patterns;
|
||||
} DescribeUnitsParameters;
|
||||
|
||||
static const char* const managed_oom_mode_properties[] = {
|
||||
"ManagedOOMSwap",
|
||||
"ManagedOOMMemoryPressure",
|
||||
|
@ -560,6 +570,139 @@ static int vl_method_get_memberships(sd_varlink *link, sd_json_variant *paramete
|
|||
return sd_varlink_error(link, "io.systemd.UserDatabase.NoRecordFound", NULL);
|
||||
}
|
||||
|
||||
static int vl_method_describe(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
|
||||
Manager *manager = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
assert(parameters);
|
||||
|
||||
if (sd_json_variant_elements(parameters) > 0)
|
||||
return sd_varlink_error_invalid_parameter(link, parameters);
|
||||
|
||||
r = manager_build_json(manager, &v);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to build manager JSON data: %m");
|
||||
|
||||
return sd_varlink_reply(link, v);
|
||||
}
|
||||
|
||||
static int vl_method_list_units(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
|
||||
|
||||
static const sd_json_dispatch_field dispatch_table[] = {
|
||||
{ "states", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_strv, offsetof(DescribeUnitsParameters, states), SD_JSON_STRICT },
|
||||
{ "patterns", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_const_string, offsetof(DescribeUnitsParameters, patterns), SD_JSON_STRICT },
|
||||
{},
|
||||
};
|
||||
|
||||
Manager *m = ASSERT_PTR(userdata);
|
||||
DescribeUnitsParameters p = {};
|
||||
const char *k;
|
||||
Unit *u;
|
||||
int r;
|
||||
|
||||
assert(parameters);
|
||||
|
||||
if (sd_json_variant_elements(parameters) > 0)
|
||||
return sd_varlink_error_invalid_parameter(link, parameters);
|
||||
|
||||
if (!FLAGS_SET(flags, SD_VARLINK_METHOD_MORE))
|
||||
return sd_varlink_error(link, SD_VARLINK_ERROR_EXPECTED_MORE, NULL);
|
||||
|
||||
r = sd_varlink_dispatch(link, parameters, dispatch_table, &p);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *previous = NULL;
|
||||
HASHMAP_FOREACH_KEY(u, k, m->units) {
|
||||
if (k != u->id)
|
||||
continue;
|
||||
|
||||
if (unit_is_filtered(u, p.states, p.patterns))
|
||||
continue;
|
||||
|
||||
if (previous) {
|
||||
r = sd_varlink_notifybo(link, SD_JSON_BUILD_PAIR_VARIANT("unit", previous));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
previous = sd_json_variant_unref(previous);
|
||||
}
|
||||
|
||||
r = unit_build_json(u, &previous);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to build unit JSON data: %m");
|
||||
}
|
||||
|
||||
if (!previous)
|
||||
return sd_varlink_error(link, "io.systemd.Manager.NoSuchUnit", NULL);
|
||||
|
||||
return sd_varlink_replybo(link, SD_JSON_BUILD_PAIR_VARIANT("unit", previous));
|
||||
}
|
||||
|
||||
static int vl_method_list_jobs(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
|
||||
|
||||
struct p {
|
||||
uint32_t id;
|
||||
} p = {
|
||||
.id = 0,
|
||||
};
|
||||
|
||||
static const sd_json_dispatch_field dispatch_table[] = {
|
||||
{ "id", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uint32, offsetof(struct p, id), 0 },
|
||||
{},
|
||||
};
|
||||
|
||||
Manager *m = ASSERT_PTR(userdata);
|
||||
Job *j;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(parameters);
|
||||
|
||||
r = sd_varlink_dispatch(link, parameters, dispatch_table, &p);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
if (p.id > 0) {
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
|
||||
|
||||
j = hashmap_get(m->jobs, UINT_TO_PTR(p.id));
|
||||
if (!j)
|
||||
return sd_varlink_error(link, "io.systemd.Manager.NoSuchJob", NULL);
|
||||
|
||||
r = job_build_json(j, &v);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to build job JSON data: %m");
|
||||
|
||||
return sd_varlink_reply(link, v);
|
||||
|
||||
}
|
||||
|
||||
if (!FLAGS_SET(flags, SD_VARLINK_METHOD_MORE))
|
||||
return sd_varlink_error(link, SD_VARLINK_ERROR_EXPECTED_MORE, NULL);
|
||||
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *previous = NULL;
|
||||
HASHMAP_FOREACH(j, m->jobs) {
|
||||
if (previous) {
|
||||
r = sd_varlink_notify(link, previous);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
previous = sd_json_variant_unref(previous);
|
||||
}
|
||||
|
||||
r = job_build_json(j, &previous);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to build job JSON data: %m");
|
||||
}
|
||||
|
||||
if (!previous)
|
||||
return sd_varlink_error(link, "io.systemd.Manager.NoSuchJob", NULL);
|
||||
|
||||
return sd_varlink_reply(link, previous);
|
||||
}
|
||||
|
||||
static void vl_disconnect(sd_varlink_server *s, sd_varlink *link, void *userdata) {
|
||||
Manager *m = ASSERT_PTR(userdata);
|
||||
|
||||
|
@ -579,34 +722,49 @@ int manager_setup_varlink_server(Manager *m) {
|
|||
if (m->varlink_server)
|
||||
return 0;
|
||||
|
||||
if (!MANAGER_IS_SYSTEM(m))
|
||||
return -EINVAL;
|
||||
sd_varlink_server_flags_t flags = SD_VARLINK_SERVER_INHERIT_USERDATA;
|
||||
if (MANAGER_IS_SYSTEM(m))
|
||||
flags |= SD_VARLINK_SERVER_ACCOUNT_UID;
|
||||
|
||||
r = sd_varlink_server_new(&s, SD_VARLINK_SERVER_ACCOUNT_UID|SD_VARLINK_SERVER_INHERIT_USERDATA);
|
||||
r = sd_varlink_server_new(&s, flags);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to allocate varlink server object: %m");
|
||||
|
||||
sd_varlink_server_set_userdata(s, m);
|
||||
|
||||
r = sd_varlink_server_add_interface_many(
|
||||
s,
|
||||
&vl_interface_io_systemd_UserDatabase,
|
||||
&vl_interface_io_systemd_ManagedOOM);
|
||||
r = sd_varlink_server_add_interface_many(s, &vl_interface_io_systemd_Manager);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to add interfaces to varlink server: %m");
|
||||
|
||||
r = sd_varlink_server_bind_method_many(
|
||||
s,
|
||||
"io.systemd.UserDatabase.GetUserRecord", vl_method_get_user_record,
|
||||
"io.systemd.UserDatabase.GetGroupRecord", vl_method_get_group_record,
|
||||
"io.systemd.UserDatabase.GetMemberships", vl_method_get_memberships,
|
||||
"io.systemd.ManagedOOM.SubscribeManagedOOMCGroups", vl_method_subscribe_managed_oom_cgroups);
|
||||
"io.systemd.Manager.Describe", vl_method_describe,
|
||||
"io.systemd.Manager.ListUnits", vl_method_list_units,
|
||||
"io.systemd.Manager.ListJobs", vl_method_list_jobs);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to register varlink methods: %m");
|
||||
|
||||
r = sd_varlink_server_bind_disconnect(s, vl_disconnect);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to register varlink disconnect handler: %m");
|
||||
if (MANAGER_IS_SYSTEM(m)) {
|
||||
r = sd_varlink_server_add_interface_many(
|
||||
s,
|
||||
&vl_interface_io_systemd_UserDatabase,
|
||||
&vl_interface_io_systemd_ManagedOOM);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to add interfaces to varlink server: %m");
|
||||
|
||||
r = sd_varlink_server_bind_method_many(
|
||||
s,
|
||||
"io.systemd.UserDatabase.GetUserRecord", vl_method_get_user_record,
|
||||
"io.systemd.UserDatabase.GetGroupRecord", vl_method_get_group_record,
|
||||
"io.systemd.UserDatabase.GetMemberships", vl_method_get_memberships,
|
||||
"io.systemd.ManagedOOM.SubscribeManagedOOMCGroups", vl_method_subscribe_managed_oom_cgroups);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to register varlink methods: %m");
|
||||
|
||||
r = sd_varlink_server_bind_disconnect(s, vl_disconnect);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to register varlink disconnect handler: %m");
|
||||
}
|
||||
|
||||
r = sd_varlink_server_attach_event(s, m->event, EVENT_PRIORITY_IPC);
|
||||
if (r < 0)
|
||||
|
@ -632,20 +790,13 @@ static int manager_varlink_init_system(Manager *m) {
|
|||
if (!MANAGER_IS_TEST_RUN(m)) {
|
||||
(void) mkdir_p_label("/run/systemd/userdb", 0755);
|
||||
|
||||
FOREACH_STRING(address, "/run/systemd/userdb/io.systemd.DynamicUser", VARLINK_ADDR_PATH_MANAGED_OOM_SYSTEM) {
|
||||
if (!fresh) {
|
||||
/* We might have got sockets through deserialization. Do not bind to them twice. */
|
||||
|
||||
bool found = false;
|
||||
LIST_FOREACH(sockets, ss, m->varlink_server->sockets)
|
||||
if (path_equal(ss->address, address)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (found)
|
||||
continue;
|
||||
}
|
||||
FOREACH_STRING(address,
|
||||
"/run/systemd/userdb/io.systemd.DynamicUser",
|
||||
VARLINK_ADDR_PATH_MANAGED_OOM_SYSTEM,
|
||||
"/run/systemd/io.systemd.Manager") {
|
||||
/* We might have got sockets through deserialization. Do not bind to them twice. */
|
||||
if (!fresh && varlink_server_contains_socket(m->varlink_server, address))
|
||||
continue;
|
||||
|
||||
r = sd_varlink_server_listen_address(m->varlink_server, address, 0666);
|
||||
if (r < 0)
|
||||
|
@ -657,6 +808,9 @@ static int manager_varlink_init_system(Manager *m) {
|
|||
}
|
||||
|
||||
static int manager_varlink_init_user(Manager *m) {
|
||||
_cleanup_free_ char *address = NULL;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
|
||||
if (!MANAGER_IS_USER(m))
|
||||
|
@ -665,6 +819,22 @@ static int manager_varlink_init_user(Manager *m) {
|
|||
if (MANAGER_IS_TEST_RUN(m))
|
||||
return 0;
|
||||
|
||||
r = manager_setup_varlink_server(m);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to set up varlink server: %m");
|
||||
bool fresh = r > 0;
|
||||
|
||||
address = path_join(m->prefix[EXEC_DIRECTORY_RUNTIME], "systemd/io.systemd.Manager");
|
||||
if (!address)
|
||||
return -ENOMEM;
|
||||
|
||||
/* We might have got sockets through deserialization. Do not bind to them twice. */
|
||||
if (fresh || !varlink_server_contains_socket(m->varlink_server, address)) {
|
||||
r = sd_varlink_server_listen_address(m->varlink_server, address, 0666);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to bind to varlink socket '%s': %m", address);
|
||||
}
|
||||
|
||||
return manager_varlink_managed_oom_connect(m);
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "escape.h"
|
||||
#include "fileio.h"
|
||||
#include "job.h"
|
||||
#include "json-util.h"
|
||||
#include "log.h"
|
||||
#include "macro.h"
|
||||
#include "parse-util.h"
|
||||
|
@ -1347,6 +1348,39 @@ int job_deserialize(Job *j, FILE *f) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int activation_details_build_json(sd_json_variant **ret, const char *name, void *userdata) {
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
|
||||
_cleanup_strv_free_ char **pairs = NULL;
|
||||
ActivationDetails *activation_details = userdata;
|
||||
int r;
|
||||
|
||||
assert(ret);
|
||||
|
||||
r = activation_details_append_pair(activation_details, &pairs);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
STRV_FOREACH_PAIR(key, value, pairs) {
|
||||
r = sd_json_variant_set_field_string(&v, *key, *value);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
*ret = TAKE_PTR(v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int job_build_json(Job *job, sd_json_variant **ret) {
|
||||
assert(job);
|
||||
|
||||
return sd_json_buildo(ret,
|
||||
SD_JSON_BUILD_PAIR_UNSIGNED("id", job->id),
|
||||
SD_JSON_BUILD_PAIR_STRING("unit", job->unit->id),
|
||||
SD_JSON_BUILD_PAIR_STRING("jobType", job_type_to_string(job->type)),
|
||||
SD_JSON_BUILD_PAIR_STRING("state", job_state_to_string(job->state)),
|
||||
JSON_BUILD_PAIR_CALLBACK_NON_NULL("activationDetails", activation_details_build_json, job->activation_details));
|
||||
}
|
||||
|
||||
int job_coldplug(Job *j) {
|
||||
int r;
|
||||
usec_t timeout_time = USEC_INFINITY;
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "sd-bus.h"
|
||||
#include "sd-event.h"
|
||||
#include "sd-json.h"
|
||||
|
||||
#include "list.h"
|
||||
#include "unit-dependency-atom.h"
|
||||
|
@ -185,6 +186,8 @@ void job_uninstall(Job *j);
|
|||
void job_dump(Job *j, FILE *f, const char *prefix);
|
||||
int job_serialize(Job *j, FILE *f);
|
||||
int job_deserialize(Job *j, FILE *f);
|
||||
int activation_details_build_json(sd_json_variant **ret, const char *name, void *userdata);
|
||||
int job_build_json(Job *job, sd_json_variant **ret);
|
||||
int job_coldplug(Job *j);
|
||||
|
||||
JobDependency* job_dependency_new(Job *subject, Job *object, bool matters, bool conflicts);
|
||||
|
|
|
@ -0,0 +1,181 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <sys/prctl.h>
|
||||
|
||||
#include "build.h"
|
||||
#include "confidential-virt.h"
|
||||
#include "json-util.h"
|
||||
#include "manager-json.h"
|
||||
#include "manager.h"
|
||||
#include "rlimit-util.h"
|
||||
#include "syslog-util.h"
|
||||
#include "taint.h"
|
||||
#include "version.h"
|
||||
#include "virt.h"
|
||||
#include "watchdog.h"
|
||||
|
||||
int rlimit_build_json(sd_json_variant **ret, const char *name, void *userdata) {
|
||||
struct rlimit *rl = userdata, buf = {};
|
||||
|
||||
assert(name);
|
||||
assert(ret);
|
||||
|
||||
if (rl)
|
||||
buf = *rl;
|
||||
else {
|
||||
const char *p;
|
||||
int z;
|
||||
|
||||
/* Skip over any prefix, such as "Default" */
|
||||
assert_se(p = strstrafter(name, "Limit"));
|
||||
|
||||
z = rlimit_from_string(p);
|
||||
assert(z >= 0);
|
||||
|
||||
(void) getrlimit(z, &buf);
|
||||
}
|
||||
|
||||
if (buf.rlim_cur == RLIM_INFINITY && buf.rlim_max == RLIM_INFINITY)
|
||||
return 0;
|
||||
|
||||
/* rlim_t might have different sizes, let's map RLIMIT_INFINITY to UINT64_MAX, so that it is the same
|
||||
* on all archs */
|
||||
return sd_json_buildo(ret,
|
||||
JSON_BUILD_PAIR_UNSIGNED_NOT_EQUAL("soft", buf.rlim_cur, RLIM_INFINITY),
|
||||
JSON_BUILD_PAIR_UNSIGNED_NOT_EQUAL("hard", buf.rlim_max, RLIM_INFINITY));
|
||||
}
|
||||
|
||||
static int manager_context_build_json(sd_json_variant **ret, const char *name, void *userdata) {
|
||||
Manager *m = ASSERT_PTR(userdata);
|
||||
|
||||
return sd_json_buildo(ASSERT_PTR(ret),
|
||||
SD_JSON_BUILD_PAIR_STRING("Version", GIT_VERSION),
|
||||
SD_JSON_BUILD_PAIR_STRING("Features", systemd_features),
|
||||
SD_JSON_BUILD_PAIR_BOOLEAN("ShowStatus", manager_get_show_status_on(m)),
|
||||
SD_JSON_BUILD_PAIR_STRV("UnitPath", m->lookup_paths.search_path),
|
||||
SD_JSON_BUILD_PAIR_INTEGER("LogLevel", m->log_level_overridden ? m->original_log_level : log_get_max_level()),
|
||||
SD_JSON_BUILD_PAIR_STRING("LogTarget", log_target_to_string(m->log_target_overridden ? m->original_log_target : log_get_target())),
|
||||
JSON_BUILD_PAIR_STRV_NON_EMPTY("Environment", m->transient_environment),
|
||||
SD_JSON_BUILD_PAIR_STRING("DefaultStandardOutput", exec_output_to_string(m->defaults.std_output)),
|
||||
SD_JSON_BUILD_PAIR_STRING("DefaultStandardError", exec_output_to_string(m->defaults.std_error)),
|
||||
JSON_BUILD_PAIR_FINITE_USEC("RuntimeWatchdogUSec", manager_get_watchdog(m, WATCHDOG_RUNTIME)),
|
||||
JSON_BUILD_PAIR_FINITE_USEC("RuntimeWatchdogPreUSec", manager_get_watchdog(m, WATCHDOG_PRETIMEOUT)),
|
||||
JSON_BUILD_PAIR_STRING_NON_EMPTY("RuntimeWatchdogPreGovernor", m->watchdog_pretimeout_governor),
|
||||
JSON_BUILD_PAIR_FINITE_USEC("RebootWatchdogUSec", manager_get_watchdog(m, WATCHDOG_REBOOT)),
|
||||
JSON_BUILD_PAIR_FINITE_USEC("KExecWatchdogUSec", manager_get_watchdog(m, WATCHDOG_KEXEC)),
|
||||
SD_JSON_BUILD_PAIR_BOOLEAN("ServiceWatchdogs", m->service_watchdogs),
|
||||
JSON_BUILD_PAIR_FINITE_USEC("DefaultTimerAccuracyUSec", m->defaults.timer_accuracy_usec),
|
||||
JSON_BUILD_PAIR_FINITE_USEC("DefaultTimeoutStartUSec", m->defaults.timeout_start_usec),
|
||||
JSON_BUILD_PAIR_FINITE_USEC("DefaultTimeoutStopUSec", m->defaults.timeout_stop_usec),
|
||||
JSON_BUILD_PAIR_FINITE_USEC("DefaultTimeoutAbortUSec", manager_default_timeout_abort_usec(m)),
|
||||
JSON_BUILD_PAIR_FINITE_USEC("DefaultDeviceTimeoutUSec", m->defaults.device_timeout_usec),
|
||||
JSON_BUILD_PAIR_FINITE_USEC("DefaultRestartUSec", m->defaults.restart_usec),
|
||||
JSON_BUILD_PAIR_RATELIMIT("DefaultStartLimit", &m->defaults.start_limit),
|
||||
SD_JSON_BUILD_PAIR_BOOLEAN("DefaultCPUAccounting", m->defaults.cpu_accounting),
|
||||
SD_JSON_BUILD_PAIR_BOOLEAN("DefaultBlockIOAccounting", m->defaults.blockio_accounting),
|
||||
SD_JSON_BUILD_PAIR_BOOLEAN("DefaultIOAccounting", m->defaults.io_accounting),
|
||||
SD_JSON_BUILD_PAIR_BOOLEAN("DefaultIPAccounting", m->defaults.ip_accounting),
|
||||
SD_JSON_BUILD_PAIR_BOOLEAN("DefaultMemoryAccounting", m->defaults.memory_accounting),
|
||||
SD_JSON_BUILD_PAIR_BOOLEAN("DefaultTasksAccounting", m->defaults.tasks_accounting),
|
||||
JSON_BUILD_PAIR_CALLBACK_NON_NULL("DefaultLimitCPU", rlimit_build_json, m->defaults.rlimit[RLIMIT_CPU]),
|
||||
JSON_BUILD_PAIR_CALLBACK_NON_NULL("DefaultLimitFSIZE", rlimit_build_json, m->defaults.rlimit[RLIMIT_FSIZE]),
|
||||
JSON_BUILD_PAIR_CALLBACK_NON_NULL("DefaultLimitDATA", rlimit_build_json, m->defaults.rlimit[RLIMIT_DATA]),
|
||||
JSON_BUILD_PAIR_CALLBACK_NON_NULL("DefaultLimitSTACK", rlimit_build_json, m->defaults.rlimit[RLIMIT_STACK]),
|
||||
JSON_BUILD_PAIR_CALLBACK_NON_NULL("DefaultLimitCORE", rlimit_build_json, m->defaults.rlimit[RLIMIT_CORE]),
|
||||
JSON_BUILD_PAIR_CALLBACK_NON_NULL("DefaultLimitRSS", rlimit_build_json, m->defaults.rlimit[RLIMIT_RSS]),
|
||||
JSON_BUILD_PAIR_CALLBACK_NON_NULL("DefaultLimitNOFILE", rlimit_build_json, m->defaults.rlimit[RLIMIT_NOFILE]),
|
||||
JSON_BUILD_PAIR_CALLBACK_NON_NULL("DefaultLimitAS", rlimit_build_json, m->defaults.rlimit[RLIMIT_AS]),
|
||||
JSON_BUILD_PAIR_CALLBACK_NON_NULL("DefaultLimitNPROC", rlimit_build_json, m->defaults.rlimit[RLIMIT_NPROC]),
|
||||
JSON_BUILD_PAIR_CALLBACK_NON_NULL("DefaultLimitMEMLOCK", rlimit_build_json, m->defaults.rlimit[RLIMIT_MEMLOCK]),
|
||||
JSON_BUILD_PAIR_CALLBACK_NON_NULL("DefaultLimitLOCKS", rlimit_build_json, m->defaults.rlimit[RLIMIT_LOCKS]),
|
||||
JSON_BUILD_PAIR_CALLBACK_NON_NULL("DefaultLimitSIGPENDING", rlimit_build_json, m->defaults.rlimit[RLIMIT_SIGPENDING]),
|
||||
JSON_BUILD_PAIR_CALLBACK_NON_NULL("DefaultLimitMSGQUEUE", rlimit_build_json, m->defaults.rlimit[RLIMIT_MSGQUEUE]),
|
||||
JSON_BUILD_PAIR_CALLBACK_NON_NULL("DefaultLimitNICE", rlimit_build_json, m->defaults.rlimit[RLIMIT_NICE]),
|
||||
JSON_BUILD_PAIR_CALLBACK_NON_NULL("DefaultLimitRTPRIO", rlimit_build_json, m->defaults.rlimit[RLIMIT_RTPRIO]),
|
||||
JSON_BUILD_PAIR_CALLBACK_NON_NULL("DefaultLimitRTTIME", rlimit_build_json, m->defaults.rlimit[RLIMIT_RTTIME]),
|
||||
SD_JSON_BUILD_PAIR_UNSIGNED("DefaultTasksMax", cgroup_tasks_max_resolve(&m->defaults.tasks_max)),
|
||||
JSON_BUILD_PAIR_FINITE_USEC("DefaultMemoryPressureThresholdUSec", m->defaults.memory_pressure_threshold_usec),
|
||||
SD_JSON_BUILD_PAIR_STRING("DefaultMemoryPressureWatch", cgroup_pressure_watch_to_string(m->defaults.memory_pressure_watch)),
|
||||
JSON_BUILD_PAIR_FINITE_USEC("TimerSlackNSec", (uint64_t) prctl(PR_GET_TIMERSLACK)),
|
||||
SD_JSON_BUILD_PAIR_STRING("DefaultOOMPolicy", oom_policy_to_string(m->defaults.oom_policy)),
|
||||
SD_JSON_BUILD_PAIR_INTEGER("DefaultOOMScoreAdjust", m->defaults.oom_score_adjust),
|
||||
SD_JSON_BUILD_PAIR_STRING("CtrlAltDelBurstAction", emergency_action_to_string(m->cad_burst_action)));
|
||||
}
|
||||
|
||||
static int manager_environment_build_json(sd_json_variant **ret, const char *name, void *userdata) {
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
Manager *m = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
assert(ret);
|
||||
|
||||
r = manager_get_effective_environment(m, &l);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (strv_isempty(l))
|
||||
return 0;
|
||||
|
||||
return sd_json_variant_new_array_strv(ret, l);
|
||||
}
|
||||
|
||||
static int manager_runtime_build_json(sd_json_variant **ret, const char *name, void *userdata) {
|
||||
Manager *m = ASSERT_PTR(userdata);
|
||||
dual_timestamp watchdog_last_ping = {
|
||||
.monotonic = watchdog_get_last_ping(CLOCK_MONOTONIC),
|
||||
.realtime = watchdog_get_last_ping(CLOCK_REALTIME),
|
||||
};
|
||||
_cleanup_strv_free_ char **taints = NULL;
|
||||
|
||||
taints = taint_strv();
|
||||
if (!taints)
|
||||
return -ENOMEM;
|
||||
|
||||
return sd_json_buildo(ASSERT_PTR(ret),
|
||||
SD_JSON_BUILD_PAIR_STRING("Architecture", architecture_to_string(uname_architecture())),
|
||||
SD_JSON_BUILD_PAIR_STRING("Virtualization", virtualization_to_string(detect_virtualization())),
|
||||
SD_JSON_BUILD_PAIR_STRING("ConfidentialVirtualization", confidential_virtualization_to_string(detect_confidential_virtualization())),
|
||||
SD_JSON_BUILD_PAIR_STRV("Taints", taints),
|
||||
JSON_BUILD_PAIR_STRING_NON_EMPTY("ConfirmSpawn", manager_get_confirm_spawn(m)),
|
||||
JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL("FirmwareTimestamp", &m->timestamps[MANAGER_TIMESTAMP_FIRMWARE]),
|
||||
JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL("LoaderTimestamp", &m->timestamps[MANAGER_TIMESTAMP_LOADER]),
|
||||
JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL("KernelTimestamp", &m->timestamps[MANAGER_TIMESTAMP_KERNEL]),
|
||||
JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL("InitRDTimestamp", &m->timestamps[MANAGER_TIMESTAMP_INITRD]),
|
||||
JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL("UserspaceTimestamp", &m->timestamps[MANAGER_TIMESTAMP_USERSPACE]),
|
||||
JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL("FinishTimestamp", &m->timestamps[MANAGER_TIMESTAMP_FINISH]),
|
||||
JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL("SecurityStartTimestamp", &m->timestamps[MANAGER_TIMESTAMP_SECURITY_START]),
|
||||
JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL("SecurityFinishTimestamp", &m->timestamps[MANAGER_TIMESTAMP_SECURITY_FINISH]),
|
||||
JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL("GeneratorsStartTimestamp", &m->timestamps[MANAGER_TIMESTAMP_GENERATORS_START]),
|
||||
JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL("GeneratorsFinishTimestamp", &m->timestamps[MANAGER_TIMESTAMP_GENERATORS_FINISH]),
|
||||
JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL("UnitsLoadStartTimestamp", &m->timestamps[MANAGER_TIMESTAMP_UNITS_LOAD_START]),
|
||||
JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL("UnitsLoadFinishTimestamp", &m->timestamps[MANAGER_TIMESTAMP_UNITS_LOAD_FINISH]),
|
||||
JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL("UnitsLoadTimestamp", &m->timestamps[MANAGER_TIMESTAMP_UNITS_LOAD]),
|
||||
JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL("InitRDSecurityStartTimestamp", &m->timestamps[MANAGER_TIMESTAMP_INITRD_SECURITY_START]),
|
||||
JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL("InitRDSecurityFinishTimestamp", &m->timestamps[MANAGER_TIMESTAMP_INITRD_SECURITY_FINISH]),
|
||||
JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL("InitRDGeneratorsStartTimestamp", &m->timestamps[MANAGER_TIMESTAMP_INITRD_GENERATORS_START]),
|
||||
JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL("InitRDGeneratorsFinishTimestamp", &m->timestamps[MANAGER_TIMESTAMP_INITRD_GENERATORS_FINISH]),
|
||||
JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL("InitRDUnitsLoadStartTimestamp", &m->timestamps[MANAGER_TIMESTAMP_INITRD_UNITS_LOAD_START]),
|
||||
JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL("InitRDUnitsLoadFinishTimestamp", &m->timestamps[MANAGER_TIMESTAMP_INITRD_UNITS_LOAD_FINISH]),
|
||||
SD_JSON_BUILD_PAIR_CONDITION(m->log_level_overridden, "LogLevel", SD_JSON_BUILD_INTEGER(log_get_max_level())),
|
||||
SD_JSON_BUILD_PAIR_CONDITION(m->log_target_overridden, "LogTarget", SD_JSON_BUILD_STRING(log_target_to_string(log_get_target()))),
|
||||
SD_JSON_BUILD_PAIR_UNSIGNED("NNames", hashmap_size(m->units)),
|
||||
SD_JSON_BUILD_PAIR_UNSIGNED("NFailedUnits", set_size(m->failed_units)),
|
||||
SD_JSON_BUILD_PAIR_UNSIGNED("NJobs", hashmap_size(m->jobs)),
|
||||
SD_JSON_BUILD_PAIR_UNSIGNED("NInstalledJobs", m->n_installed_jobs),
|
||||
SD_JSON_BUILD_PAIR_UNSIGNED("NFailedJobs", m->n_failed_jobs),
|
||||
SD_JSON_BUILD_PAIR_REAL("Progress", manager_get_progress(m)),
|
||||
JSON_BUILD_PAIR_CALLBACK_NON_NULL("Environment", manager_environment_build_json, m),
|
||||
JSON_BUILD_PAIR_STRING_NON_EMPTY("WatchdogDevice", watchdog_get_device()),
|
||||
JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL("WatchdogLastPingTimestamp", &watchdog_last_ping),
|
||||
JSON_BUILD_PAIR_STRING_NON_EMPTY("ControlGroup", m->cgroup_root),
|
||||
SD_JSON_BUILD_PAIR_STRING("SystemState", manager_state_to_string(manager_state(m))),
|
||||
SD_JSON_BUILD_PAIR_UNSIGNED("ExitCode", m->return_value));
|
||||
}
|
||||
|
||||
int manager_build_json(Manager *m, sd_json_variant **ret) {
|
||||
assert(m);
|
||||
|
||||
return sd_json_buildo(ASSERT_PTR(ret),
|
||||
SD_JSON_BUILD_PAIR_CALLBACK("Context", manager_context_build_json, m),
|
||||
SD_JSON_BUILD_PAIR_CALLBACK("Runtime", manager_runtime_build_json, m));
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "sd-json.h"
|
||||
|
||||
#include "manager.h"
|
||||
|
||||
int rlimit_build_json(sd_json_variant **ret, const char *name, void *userdata);
|
||||
int environment_build_json(sd_json_variant **ret, const char *name, void *userdata);
|
||||
int manager_build_json(Manager *manager, sd_json_variant **ret);
|
|
@ -497,7 +497,7 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
} else if ((val = startswith(l, "varlink-server-socket-address="))) {
|
||||
if (!m->varlink_server && MANAGER_IS_SYSTEM(m)) {
|
||||
if (!m->varlink_server) {
|
||||
r = manager_setup_varlink_server(m);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Failed to setup varlink server, ignoring: %m");
|
||||
|
|
|
@ -44,6 +44,7 @@ libcore_sources = files(
|
|||
'load-dropin.c',
|
||||
'load-fragment.c',
|
||||
'manager-dump.c',
|
||||
'manager-json.c',
|
||||
'manager-serialize.c',
|
||||
'manager.c',
|
||||
'mount.c',
|
||||
|
@ -62,6 +63,7 @@ libcore_sources = files(
|
|||
'transaction.c',
|
||||
'unit-dependency-atom.c',
|
||||
'unit-printf.c',
|
||||
'unit-json.c',
|
||||
'unit-serialize.c',
|
||||
'unit.c',
|
||||
)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,8 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "sd-json.h"
|
||||
|
||||
#include "unit.h"
|
||||
|
||||
int unit_build_json(Unit *unit, sd_json_variant **ret);
|
|
@ -185,6 +185,7 @@ shared_sources = files(
|
|||
'varlink-io.systemd.Machine.c',
|
||||
'varlink-io.systemd.MachineImage.c',
|
||||
'varlink-io.systemd.ManagedOOM.c',
|
||||
'varlink-io.systemd.Manager.c',
|
||||
'varlink-io.systemd.MountFileSystem.c',
|
||||
'varlink-io.systemd.NamespaceResource.c',
|
||||
'varlink-io.systemd.Network.c',
|
||||
|
|
|
@ -1808,63 +1808,81 @@ char* umount_and_unlink_and_free(char *p) {
|
|||
return mfree(p);
|
||||
}
|
||||
|
||||
static int path_get_mount_info(
|
||||
static int path_get_mount_info_at(
|
||||
int dir_fd,
|
||||
const char *path,
|
||||
char **ret_fstype,
|
||||
char **ret_options) {
|
||||
|
||||
_cleanup_(mnt_free_tablep) struct libmnt_table *table = NULL;
|
||||
_cleanup_free_ char *fstype = NULL, *options = NULL;
|
||||
struct libmnt_fs *fs;
|
||||
int r;
|
||||
_cleanup_(mnt_free_iterp) struct libmnt_iter *iter = NULL;
|
||||
int r, mnt_id;
|
||||
|
||||
assert(path);
|
||||
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
|
||||
|
||||
table = mnt_new_table();
|
||||
if (!table)
|
||||
return -ENOMEM;
|
||||
|
||||
r = mnt_table_parse_mtab(table, /* filename = */ NULL);
|
||||
r = path_get_mnt_id_at(dir_fd, path, &mnt_id);
|
||||
if (r < 0)
|
||||
return r;
|
||||
return log_debug_errno(r, "Failed to get mount ID: %m");
|
||||
|
||||
fs = mnt_table_find_mountpoint(table, path, MNT_ITER_FORWARD);
|
||||
if (!fs)
|
||||
return -EINVAL;
|
||||
r = libmount_parse("/proc/self/mountinfo", NULL, &table, &iter);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to parse /proc/self/mountinfo: %m");
|
||||
|
||||
if (ret_fstype) {
|
||||
fstype = strdup(strempty(mnt_fs_get_fstype(fs)));
|
||||
if (!fstype)
|
||||
return -ENOMEM;
|
||||
for (;;) {
|
||||
struct libmnt_fs *fs;
|
||||
|
||||
r = mnt_table_next_fs(table, iter, &fs);
|
||||
if (r == 1)
|
||||
break; /* EOF */
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to get next entry from /proc/self/mountinfo: %m");
|
||||
|
||||
if (mnt_fs_get_id(fs) != mnt_id)
|
||||
continue;
|
||||
|
||||
_cleanup_free_ char *fstype = NULL, *options = NULL;
|
||||
|
||||
if (ret_fstype) {
|
||||
fstype = strdup(strempty(mnt_fs_get_fstype(fs)));
|
||||
if (!fstype)
|
||||
return log_oom_debug();
|
||||
}
|
||||
|
||||
if (ret_options) {
|
||||
options = strdup(strempty(mnt_fs_get_options(fs)));
|
||||
if (!options)
|
||||
return log_oom_debug();
|
||||
}
|
||||
|
||||
if (ret_fstype)
|
||||
*ret_fstype = TAKE_PTR(fstype);
|
||||
if (ret_options)
|
||||
*ret_options = TAKE_PTR(options);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ret_options) {
|
||||
options = strdup(strempty(mnt_fs_get_options(fs)));
|
||||
if (!options)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (ret_fstype)
|
||||
*ret_fstype = TAKE_PTR(fstype);
|
||||
if (ret_options)
|
||||
*ret_options = TAKE_PTR(options);
|
||||
|
||||
return 0;
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(ESTALE), "Cannot find mount ID %i from /proc/self/mountinfo.", mnt_id);
|
||||
}
|
||||
|
||||
int path_is_network_fs_harder(const char *path) {
|
||||
int path_is_network_fs_harder_at(int dir_fd, const char *path) {
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
int r;
|
||||
|
||||
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
|
||||
|
||||
fd = xopenat(dir_fd, path, O_PATH | O_CLOEXEC | O_NOFOLLOW);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
r = fd_is_network_fs(fd);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
_cleanup_free_ char *fstype = NULL, *options = NULL;
|
||||
int r, ret;
|
||||
|
||||
assert(path);
|
||||
|
||||
ret = path_is_network_fs(path);
|
||||
if (ret > 0)
|
||||
return true;
|
||||
|
||||
r = path_get_mount_info(path, &fstype, &options);
|
||||
r = path_get_mount_info_at(fd, /* path = */ NULL, &fstype, &options);
|
||||
if (r < 0)
|
||||
return RET_GATHER(ret, r);
|
||||
return r;
|
||||
|
||||
if (fstype_is_network(fstype))
|
||||
return true;
|
||||
|
|
|
@ -181,4 +181,7 @@ int mount_credentials_fs(const char *path, size_t size, bool ro);
|
|||
|
||||
int make_fsmount(int error_log_level, const char *what, const char *type, unsigned long flags, const char *options, int userns_fd);
|
||||
|
||||
int path_is_network_fs_harder(const char *path);
|
||||
int path_is_network_fs_harder_at(int dir_fd, const char *path);
|
||||
static inline int path_is_network_fs_harder(const char *path) {
|
||||
return path_is_network_fs_harder_at(AT_FDCWD, path);
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "namespace-util.h"
|
||||
#include "nsflags.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
|
||||
int namespace_flags_from_string(const char *name, unsigned long *ret) {
|
||||
unsigned long flags = 0;
|
||||
|
@ -42,19 +43,17 @@ int namespace_flags_from_string(const char *name, unsigned long *ret) {
|
|||
}
|
||||
|
||||
int namespace_flags_to_string(unsigned long flags, char **ret) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
unsigned i;
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
|
||||
for (i = 0; namespace_info[i].proc_name; i++) {
|
||||
if ((flags & namespace_info[i].clone_flag) != namespace_info[i].clone_flag)
|
||||
continue;
|
||||
l = namespace_flags_to_strv(flags);
|
||||
if (!l)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!strextend_with_separator(&s, " ", namespace_info[i].proc_name))
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
*ret = TAKE_PTR(s);
|
||||
char *s = strv_join(l, NULL);
|
||||
if (!s)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret = s;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -65,3 +64,18 @@ const char* namespace_single_flag_to_string(unsigned long flag) {
|
|||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char** namespace_flags_to_strv(unsigned long flags) {
|
||||
_cleanup_strv_free_ char **s = NULL;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; namespace_info[i].proc_name; i++) {
|
||||
if ((flags & namespace_info[i].clone_flag) != namespace_info[i].clone_flag)
|
||||
continue;
|
||||
|
||||
if (strv_extend(&s, namespace_info[i].proc_name) < 0)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return s ? TAKE_PTR(s) : strv_new(NULL);
|
||||
}
|
||||
|
|
|
@ -21,3 +21,5 @@
|
|||
int namespace_flags_from_string(const char *name, unsigned long *ret);
|
||||
int namespace_flags_to_string(unsigned long flags, char **ret);
|
||||
const char* namespace_single_flag_to_string(unsigned long flag);
|
||||
|
||||
char** namespace_flags_to_strv(unsigned long flags);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,6 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "sd-varlink-idl.h"
|
||||
|
||||
extern const sd_varlink_interface vl_interface_io_systemd_Manager;
|
|
@ -1,6 +1,7 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "parse-util.h"
|
||||
#include "path-util.h"
|
||||
#include "varlink-internal.h"
|
||||
#include "varlink-serialize.h"
|
||||
|
||||
|
@ -83,3 +84,14 @@ int varlink_server_deserialize_one(sd_varlink_server *s, const char *value, FDSe
|
|||
LIST_PREPEND(sockets, s->sockets, TAKE_PTR(ss));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int varlink_server_contains_socket(sd_varlink_server *s, const char *address) {
|
||||
assert(s);
|
||||
assert(address);
|
||||
|
||||
LIST_FOREACH(sockets, ss, s->sockets)
|
||||
if (path_equal(ss->address, address))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -9,3 +9,5 @@
|
|||
|
||||
int varlink_server_serialize(sd_varlink_server *s, FILE *f, FDSet *fds);
|
||||
int varlink_server_deserialize_one(sd_varlink_server *s, const char *value, FDSet *fds);
|
||||
|
||||
int varlink_server_contains_socket(sd_varlink_server *s, const char *address);
|
||||
|
|
|
@ -538,9 +538,53 @@ TEST(bind_mount_submounts) {
|
|||
}
|
||||
|
||||
TEST(path_is_network_fs_harder) {
|
||||
ASSERT_OK_ZERO(path_is_network_fs_harder("/dev"));
|
||||
ASSERT_OK_ZERO(path_is_network_fs_harder("/sys"));
|
||||
ASSERT_OK_ZERO(path_is_network_fs_harder("/run"));
|
||||
_cleanup_close_ int dir_fd = -EBADF;
|
||||
int r;
|
||||
|
||||
ASSERT_OK(dir_fd = open("/", O_PATH | O_CLOEXEC));
|
||||
FOREACH_STRING(s,
|
||||
"/", "/dev/", "/proc/", "/run/", "/sys/", "/tmp/", "/usr/", "/var/tmp/",
|
||||
"", ".", "../../../", "/this/path/should/not/exist/for/test-mount-util/") {
|
||||
|
||||
r = path_is_network_fs_harder(s);
|
||||
log_debug("path_is_network_fs_harder(%s) → %i: %s", s, r, r < 0 ? STRERROR(r) : yes_no(r));
|
||||
|
||||
const char *q = path_startswith(s, "/") ?: s;
|
||||
r = path_is_network_fs_harder_at(dir_fd, q);
|
||||
log_debug("path_is_network_fs_harder_at(root, %s) → %i: %s", q, r, r < 0 ? STRERROR(r) : yes_no(r));
|
||||
}
|
||||
|
||||
if (geteuid() != 0 || have_effective_cap(CAP_SYS_ADMIN) <= 0) {
|
||||
(void) log_tests_skipped("not running privileged");
|
||||
return;
|
||||
}
|
||||
|
||||
_cleanup_(rm_rf_physical_and_freep) char *t = NULL;
|
||||
assert_se(mkdtemp_malloc("/tmp/test-mount-util.path_is_network_fs_harder.XXXXXXX", &t) >= 0);
|
||||
|
||||
r = safe_fork("(make_mount-point)",
|
||||
FORK_RESET_SIGNALS |
|
||||
FORK_CLOSE_ALL_FDS |
|
||||
FORK_DEATHSIG_SIGTERM |
|
||||
FORK_WAIT |
|
||||
FORK_REOPEN_LOG |
|
||||
FORK_LOG |
|
||||
FORK_NEW_MOUNTNS |
|
||||
FORK_MOUNTNS_SLAVE,
|
||||
NULL);
|
||||
ASSERT_OK(r);
|
||||
|
||||
if (r == 0) {
|
||||
ASSERT_OK(mount_nofollow_verbose(LOG_INFO, "tmpfs", t, "tmpfs", 0, NULL));
|
||||
ASSERT_OK_ZERO(path_is_network_fs_harder(t));
|
||||
ASSERT_OK_ERRNO(umount(t));
|
||||
|
||||
ASSERT_OK(mount_nofollow_verbose(LOG_INFO, "tmpfs", t, "tmpfs", 0, "x-systemd-growfs,x-systemd-automount"));
|
||||
ASSERT_OK_ZERO(path_is_network_fs_harder(t));
|
||||
ASSERT_OK_ERRNO(umount(t));
|
||||
|
||||
_exit(EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_TEST_MAIN(LOG_DEBUG);
|
||||
|
|
|
@ -142,11 +142,13 @@ endif
|
|||
############################################################
|
||||
|
||||
if install_tests
|
||||
foreach script : ['integration-test-setup.sh', 'run-unit-tests.py']
|
||||
install_data(script,
|
||||
install_mode : 'rwxr-xr-x',
|
||||
install_dir : testsdir)
|
||||
endforeach
|
||||
install_data('run-unit-tests.py',
|
||||
install_mode : 'rwxr-xr-x',
|
||||
install_dir : testsdir)
|
||||
|
||||
install_data('integration-test-setup.sh',
|
||||
install_mode : 'rwxr-xr-x',
|
||||
install_dir : testdata_dir)
|
||||
endif
|
||||
|
||||
############################################################
|
||||
|
|
|
@ -7,9 +7,9 @@ Before=getty-pre.target
|
|||
|
||||
[Service]
|
||||
ExecStartPre=rm -f /failed /testok
|
||||
ExecStartPre=/usr/lib/systemd/tests/integration-test-setup.sh setup
|
||||
ExecStartPre=/usr/lib/systemd/tests/testdata/integration-test-setup.sh setup
|
||||
ExecStart=@command@
|
||||
ExecStopPost=/usr/lib/systemd/tests/integration-test-setup.sh finalize
|
||||
ExecStopPost=/usr/lib/systemd/tests/testdata/integration-test-setup.sh finalize
|
||||
Type=oneshot
|
||||
MemoryAccounting=@memory-accounting@
|
||||
StateDirectory=%N
|
||||
|
|
|
@ -132,10 +132,12 @@ testcase_unpriv() {
|
|||
return 0
|
||||
fi
|
||||
|
||||
# The kernel has a restriction for unprivileged user namespaces where they cannot mount a less restrictive
|
||||
# instance of /proc/. So if /proc/ is masked (e.g. /proc/kmsg is over-mounted with tmpfs as systemd-nspawn does),
|
||||
# then mounting a new /proc/ will fail and we will still see the host's /proc/. Thus, to allow tests to run in
|
||||
# a VM or nspawn, we mount a new proc on a temporary directory with no masking to bypass this kernel restriction.
|
||||
# IMPORTANT: For /proc/ to be remounted in pid namespace within an unprivileged user namespace, there needs to
|
||||
# be at least 1 unmasked procfs mount in ANY directory. Otherwise, if /proc/ is masked (e.g. /proc/scsi is
|
||||
# over-mounted with tmpfs), then mounting a new /proc/ will fail.
|
||||
#
|
||||
# Thus, to guarantee PrivatePIDs=yes tests for unprivileged users pass, we mount a new procfs on a temporary
|
||||
# directory with no masking. This will guarantee an unprivileged user can mount a new /proc/ successfully.
|
||||
mkdir -p /tmp/TEST-07-PID1-private-pids-proc
|
||||
mount -t proc proc /tmp/TEST-07-PID1-private-pids-proc
|
||||
|
||||
|
@ -146,7 +148,16 @@ testcase_unpriv() {
|
|||
umount /tmp/TEST-07-PID1-private-pids-proc
|
||||
rm -rf /tmp/TEST-07-PID1-private-pids-proc
|
||||
|
||||
# Now verify the behavior with masking - units should fail as PrivatePIDs=yes has no graceful fallback.
|
||||
# Now we will mask /proc/ by mounting tmpfs over /proc/scsi. This will guarantee that mounting /proc/ will fail
|
||||
# for unprivileged users when using PrivatePIDs=yes. Now units should fail as PrivatePIDs=yes has no graceful
|
||||
# fallback.
|
||||
#
|
||||
# Note some kernels do not have /proc/scsi so we verify the directory exists prior to running the test.
|
||||
if [ ! -d /proc/scsi ]; then
|
||||
echo "/proc/scsi does not exist, skipping unprivileged PrivatePIDs=yes test with masked /proc/"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ "$HAS_EXISTING_SCSI_MOUNT" == "no" ]]; then
|
||||
mount -t tmpfs tmpfs /proc/scsi
|
||||
fi
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
set -eux
|
||||
set -o pipefail
|
||||
|
||||
# shellcheck source=test/units/util.sh
|
||||
. "$(dirname "$0")"/util.sh
|
||||
|
||||
# Unset $PAGER so we don't have to use --no-pager everywhere
|
||||
export PAGER=
|
||||
|
||||
|
@ -160,3 +163,19 @@ done
|
|||
varlinkctl info /run/systemd/io.systemd.Hostname
|
||||
varlinkctl introspect /run/systemd/io.systemd.Hostname io.systemd.Hostname
|
||||
varlinkctl call /run/systemd/io.systemd.Hostname io.systemd.Hostname.Describe '{}'
|
||||
|
||||
varlinkctl info /run/systemd/io.systemd.Manager
|
||||
varlinkctl introspect /run/systemd/io.systemd.Manager io.systemd.Manager
|
||||
|
||||
for _ in $(seq 3); do
|
||||
systemd-run --service-type=oneshot --no-block sleep infinity
|
||||
done
|
||||
|
||||
varlinkctl call /run/systemd/io.systemd.Manager io.systemd.Manager.Describe '{}'
|
||||
JOB="$(varlinkctl call --more /run/systemd/io.systemd.Manager io.systemd.Manager.ListJobs '{}' | jq --slurp .[0].id)"
|
||||
assert_eq "$(varlinkctl call /run/systemd/io.systemd.Manager io.systemd.Manager.ListJobs "{\"id\": $JOB}" | jq .id)" "$JOB"
|
||||
|
||||
systemctl start user@4711
|
||||
varlinkctl info /run/user/4711/systemd/io.systemd.Manager
|
||||
varlinkctl introspect /run/user/4711/systemd/io.systemd.Manager
|
||||
varlinkctl call /run/user/4711/systemd/io.systemd.Manager io.systemd.Manager.Describe '{}'
|
||||
|
|
Loading…
Reference in New Issue