From ee7304df5d23aa43beac28d1ac60bd53f37f3854 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Tue, 17 Oct 2023 16:03:42 +0200 Subject: [PATCH 01/13] mkosi: Use RuntimeTrees= to mount sources Instead of using ExtraTrees=, let's use the new RuntimeTrees= option to mount the full repository into the VM/container. Let's also store the sources under /usr/src/systemd and update the gdbinit file and vscode HACKING guide section to match the new location. --- docs/HACKING.md | 13 +++++-------- mkosi.presets/system/mkosi.conf | 1 - .../usr/share/factory/mkosi/gdbinit.d/systemd.gdb | 2 +- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/docs/HACKING.md b/docs/HACKING.md index fb7caac93cc..0178a43dba0 100644 --- a/docs/HACKING.md +++ b/docs/HACKING.md @@ -234,16 +234,17 @@ QEMU. To allow VSCode's debugger to attach to systemd running in a mkosi image, we have to make sure it can access the virtual machine spawned by mkosi where systemd is running. mkosi makes this possible via a handy SSH option that makes the generated image accessible via SSH when booted. Thus you must build the image with -`mkosi --ssh`. The easiest way to set the option is to create a file 20-local.conf in mkosi.conf.d/ (in the -directory you ran mkosi in) and add the following contents: +`mkosi --ssh`. The easiest way to set the option is to create a file `mkosi.conf` in the root of the +repository and add the following contents: ``` [Host] Ssh=yes +RuntimeTrees=. ``` Also make sure that the SSH agent is running on your system and that you've added your SSH key to it with -`ssh-add`. +`ssh-add`. Also make sure that `virtiofsd` is installed. After rebuilding the image and booting it with `mkosi qemu`, you should now be able to connect to it by running `mkosi ssh` from the same directory in another terminal window. @@ -284,14 +285,10 @@ the directory, and add the following contents: }, "MIMode": "gdb", "sourceFileMap": { - "/work/build/../src": { + "/root/src/systemd": { "editorPath": "${workspaceFolder}", "useForBreakpoints": false }, - "/work/build/*": { - "editorPath": "${workspaceFolder}/mkosi.builddir", - "useForBreakpoints": false - } } } ] diff --git a/mkosi.presets/system/mkosi.conf b/mkosi.presets/system/mkosi.conf index 361bb6af724..08f6fb7dc76 100644 --- a/mkosi.presets/system/mkosi.conf +++ b/mkosi.presets/system/mkosi.conf @@ -7,7 +7,6 @@ Dependencies=base Autologin=yes BaseTrees=../../mkosi.output/base ExtraTrees=../../mkosi.output/base-systemd -ExtraTrees=../../src:/usr/src/src Packages= acl bash-completion diff --git a/mkosi.presets/system/mkosi.extra/usr/share/factory/mkosi/gdbinit.d/systemd.gdb b/mkosi.presets/system/mkosi.extra/usr/share/factory/mkosi/gdbinit.d/systemd.gdb index 598344809c1..26f882bc2bb 100644 --- a/mkosi.presets/system/mkosi.extra/usr/share/factory/mkosi/gdbinit.d/systemd.gdb +++ b/mkosi.presets/system/mkosi.extra/usr/share/factory/mkosi/gdbinit.d/systemd.gdb @@ -1,3 +1,3 @@ set debuginfod enabled off set build-id-verbose 0 -set substitute-path ../src /usr/src +set substitute-path ../src /root/src/systemd From 1b17dd909922b5945b84813ca47ab28040fe0e17 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Thu, 19 Oct 2023 16:34:19 +0200 Subject: [PATCH 02/13] Add unit_type_to_capitalized_string() --- src/basic/unit-def.c | 8 ++++++++ src/basic/unit-def.h | 2 ++ 2 files changed, 10 insertions(+) diff --git a/src/basic/unit-def.c b/src/basic/unit-def.c index 23611329368..908c0cd03f2 100644 --- a/src/basic/unit-def.c +++ b/src/basic/unit-def.c @@ -68,6 +68,14 @@ const char *unit_dbus_interface_from_name(const char *name) { return unit_dbus_interface_from_type(t); } +const char* unit_type_to_capitalized_string(UnitType t) { + const char *di = unit_dbus_interface_from_type(t); + if (!di) + return NULL; + + return ASSERT_PTR(startswith(di, "org.freedesktop.systemd1.")); +} + static const char* const unit_type_table[_UNIT_TYPE_MAX] = { [UNIT_SERVICE] = "service", [UNIT_SOCKET] = "socket", diff --git a/src/basic/unit-def.h b/src/basic/unit-def.h index 345ca533a30..6627da5614c 100644 --- a/src/basic/unit-def.h +++ b/src/basic/unit-def.h @@ -287,6 +287,8 @@ const char *unit_dbus_interface_from_name(const char *name); const char *unit_type_to_string(UnitType i) _const_; UnitType unit_type_from_string(const char *s) _pure_; +const char* unit_type_to_capitalized_string(UnitType t); + const char *unit_load_state_to_string(UnitLoadState i) _const_; UnitLoadState unit_load_state_from_string(const char *s) _pure_; From 435996e63fa4a9d5653e4b3c7df3d5581b07a18c Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Thu, 19 Oct 2023 16:35:52 +0200 Subject: [PATCH 03/13] core: Add two more to_string() functions --- src/core/cgroup.c | 18 ++++++++++++++++++ src/core/cgroup.h | 6 ++++++ src/core/dbus-unit.c | 22 ++++------------------ 3 files changed, 28 insertions(+), 18 deletions(-) diff --git a/src/core/cgroup.c b/src/core/cgroup.c index 65851ae6e82..2199b94d245 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -4543,3 +4543,21 @@ static const char* const cgroup_pressure_watch_table[_CGROUP_PRESSURE_WATCH_MAX] }; DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(cgroup_pressure_watch, CGroupPressureWatch, CGROUP_PRESSURE_WATCH_ON); + +static const char* const cgroup_ip_accounting_metric_table[_CGROUP_IP_ACCOUNTING_METRIC_MAX] = { + [CGROUP_IP_INGRESS_BYTES] = "IPIngressBytes", + [CGROUP_IP_EGRESS_BYTES] = "IPEgressBytes", + [CGROUP_IP_INGRESS_PACKETS] = "IPIngressPackets", + [CGROUP_IP_EGRESS_PACKETS] = "IPEgressPackets", +}; + +DEFINE_STRING_TABLE_LOOKUP(cgroup_ip_accounting_metric, CGroupIPAccountingMetric); + +static const char* const cgroup_io_accounting_metric_table[_CGROUP_IO_ACCOUNTING_METRIC_MAX] = { + [CGROUP_IO_READ_BYTES] = "IOReadBytes", + [CGROUP_IO_WRITE_BYTES] = "IOWriteBytes", + [CGROUP_IO_READ_OPERATIONS] = "IOReadOperations", + [CGROUP_IO_WRITE_OPERATIONS] = "IOWriteOperations", +}; + +DEFINE_STRING_TABLE_LOOKUP(cgroup_io_accounting_metric, CGroupIOAccountingMetric); diff --git a/src/core/cgroup.h b/src/core/cgroup.h index e043c639f89..9816966dbb2 100644 --- a/src/core/cgroup.h +++ b/src/core/cgroup.h @@ -399,3 +399,9 @@ CGroupPressureWatch cgroup_pressure_watch_from_string(const char *s) _pure_; const char *cgroup_device_permissions_to_string(CGroupDevicePermissions p) _const_; CGroupDevicePermissions cgroup_device_permissions_from_string(const char *s) _pure_; + +const char* cgroup_ip_accounting_metric_to_string(CGroupIPAccountingMetric m) _const_; +CGroupIPAccountingMetric cgroup_ip_accounting_metric_from_string(const char *s) _pure_; + +const char* cgroup_io_accounting_metric_to_string(CGroupIOAccountingMetric m) _const_; +CGroupIOAccountingMetric cgroup_io_accounting_metric_from_string(const char *s) _pure_; diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c index 8c9ad0ef9f0..ab72b4e0948 100644 --- a/src/core/dbus-unit.c +++ b/src/core/dbus-unit.c @@ -1397,22 +1397,15 @@ static int property_get_ip_counter( void *userdata, sd_bus_error *error) { - static const char *const table[_CGROUP_IP_ACCOUNTING_METRIC_MAX] = { - [CGROUP_IP_INGRESS_BYTES] = "IPIngressBytes", - [CGROUP_IP_EGRESS_BYTES] = "IPEgressBytes", - [CGROUP_IP_INGRESS_PACKETS] = "IPIngressPackets", - [CGROUP_IP_EGRESS_PACKETS] = "IPEgressPackets", - }; - uint64_t value = UINT64_MAX; Unit *u = ASSERT_PTR(userdata); - ssize_t metric; + CGroupIPAccountingMetric metric; assert(bus); assert(reply); assert(property); - assert_se((metric = string_table_lookup(table, ELEMENTSOF(table), property)) >= 0); + assert_se((metric = cgroup_ip_accounting_metric_from_string(property)) >= 0); (void) unit_get_ip_accounting(u, metric, &value); return sd_bus_message_append(reply, "t", value); } @@ -1426,13 +1419,6 @@ static int property_get_io_counter( void *userdata, sd_bus_error *error) { - static const char *const table[_CGROUP_IO_ACCOUNTING_METRIC_MAX] = { - [CGROUP_IO_READ_BYTES] = "IOReadBytes", - [CGROUP_IO_WRITE_BYTES] = "IOWriteBytes", - [CGROUP_IO_READ_OPERATIONS] = "IOReadOperations", - [CGROUP_IO_WRITE_OPERATIONS] = "IOWriteOperations", - }; - uint64_t value = UINT64_MAX; Unit *u = ASSERT_PTR(userdata); ssize_t metric; @@ -1441,8 +1427,8 @@ static int property_get_io_counter( assert(reply); assert(property); - assert_se((metric = string_table_lookup(table, ELEMENTSOF(table), property)) >= 0); - (void) unit_get_io_accounting(u, metric, false, &value); + assert_se((metric = cgroup_io_accounting_metric_from_string(property)) >= 0); + (void) unit_get_io_accounting(u, metric, /* allow_cache= */ false, &value); return sd_bus_message_append(reply, "t", value); } From ef44aa831f079e4565110ced082e2b622d3851d8 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Thu, 19 Oct 2023 16:37:35 +0200 Subject: [PATCH 04/13] execute: Add more helper functions --- src/core/dbus-execute.c | 275 +++------------------------------------- src/core/execute.c | 241 +++++++++++++++++++++++++++++++++++ src/core/execute.h | 16 +++ 3 files changed, 277 insertions(+), 255 deletions(-) diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index 74322645dec..9644fc3c335 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -61,6 +61,12 @@ static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_empty_string, "s", NULL); static BUS_DEFINE_PROPERTY_GET_REF(property_get_syslog_level, "i", int, LOG_PRI); static BUS_DEFINE_PROPERTY_GET_REF(property_get_syslog_facility, "i", int, LOG_FAC); static BUS_DEFINE_PROPERTY_GET(property_get_cpu_affinity_from_numa, "b", ExecContext, exec_context_get_cpu_affinity_from_numa); +static BUS_DEFINE_PROPERTY_GET(property_get_oom_score_adjust, "i", ExecContext, exec_context_get_oom_score_adjust); +static BUS_DEFINE_PROPERTY_GET(property_get_nice, "i", ExecContext, exec_context_get_nice); +static BUS_DEFINE_PROPERTY_GET(property_get_cpu_sched_policy, "i", ExecContext, exec_context_get_cpu_sched_policy); +static BUS_DEFINE_PROPERTY_GET(property_get_cpu_sched_priority, "i", ExecContext, exec_context_get_cpu_sched_priority); +static BUS_DEFINE_PROPERTY_GET(property_get_coredump_filter, "t", ExecContext, exec_context_get_coredump_filter); +static BUS_DEFINE_PROPERTY_GET(property_get_timer_slack_nsec, "t", ExecContext, exec_context_get_timer_slack_nsec); static int property_get_environment_files( sd_bus *bus, @@ -92,150 +98,6 @@ static int property_get_environment_files( return sd_bus_message_close_container(reply); } -static int property_get_oom_score_adjust( - sd_bus *bus, - const char *path, - const char *interface, - const char *property, - sd_bus_message *reply, - void *userdata, - sd_bus_error *error) { - - ExecContext *c = ASSERT_PTR(userdata); - int r, n; - - assert(bus); - assert(reply); - - if (c->oom_score_adjust_set) - n = c->oom_score_adjust; - else { - n = 0; - r = get_oom_score_adjust(&n); - if (r < 0) - log_debug_errno(r, "Failed to read /proc/self/oom_score_adj, ignoring: %m"); - } - - return sd_bus_message_append(reply, "i", n); -} - -static int property_get_coredump_filter( - sd_bus *bus, - const char *path, - const char *interface, - const char *property, - sd_bus_message *reply, - void *userdata, - sd_bus_error *error) { - - ExecContext *c = ASSERT_PTR(userdata); - uint64_t n; - int r; - - assert(bus); - assert(reply); - - if (c->coredump_filter_set) - n = c->coredump_filter; - else { - _cleanup_free_ char *t = NULL; - - n = COREDUMP_FILTER_MASK_DEFAULT; - r = read_one_line_file("/proc/self/coredump_filter", &t); - if (r < 0) - log_debug_errno(r, "Failed to read /proc/self/coredump_filter, ignoring: %m"); - else { - r = safe_atoux64(t, &n); - if (r < 0) - log_debug_errno(r, "Failed to parse \"%s\" from /proc/self/coredump_filter, ignoring: %m", t); - } - } - - return sd_bus_message_append(reply, "t", n); -} - -static int property_get_nice( - sd_bus *bus, - const char *path, - const char *interface, - const char *property, - sd_bus_message *reply, - void *userdata, - sd_bus_error *error) { - - ExecContext *c = ASSERT_PTR(userdata); - int32_t n; - - assert(bus); - assert(reply); - - if (c->nice_set) - n = c->nice; - else { - errno = 0; - n = getpriority(PRIO_PROCESS, 0); - if (errno > 0) - n = 0; - } - - return sd_bus_message_append(reply, "i", n); -} - -static int property_get_cpu_sched_policy( - sd_bus *bus, - const char *path, - const char *interface, - const char *property, - sd_bus_message *reply, - void *userdata, - sd_bus_error *error) { - - ExecContext *c = ASSERT_PTR(userdata); - int32_t n; - - assert(bus); - assert(reply); - - if (c->cpu_sched_set) - n = c->cpu_sched_policy; - else { - n = sched_getscheduler(0); - if (n < 0) - n = SCHED_OTHER; - } - - return sd_bus_message_append(reply, "i", n); -} - -static int property_get_cpu_sched_priority( - sd_bus *bus, - const char *path, - const char *interface, - const char *property, - sd_bus_message *reply, - void *userdata, - sd_bus_error *error) { - - ExecContext *c = ASSERT_PTR(userdata); - int32_t n; - - assert(bus); - assert(reply); - - if (c->cpu_sched_set) - n = c->cpu_sched_priority; - else { - struct sched_param p = {}; - - if (sched_getparam(0, &p) >= 0) - n = p.sched_priority; - else - n = 0; - } - - return sd_bus_message_append(reply, "i", n); -} - static int property_get_cpu_affinity( sd_bus *bus, const char *path, @@ -306,29 +168,6 @@ static int property_get_numa_policy( return sd_bus_message_append_basic(reply, 'i', &policy); } -static int property_get_timer_slack_nsec( - sd_bus *bus, - const char *path, - const char *interface, - const char *property, - sd_bus_message *reply, - void *userdata, - sd_bus_error *error) { - - ExecContext *c = ASSERT_PTR(userdata); - uint64_t u; - - assert(bus); - assert(reply); - - if (c->timer_slack_nsec != NSEC_INFINITY) - u = (uint64_t) c->timer_slack_nsec; - else - u = (uint64_t) prctl(PR_GET_TIMERSLACK); - - return sd_bus_message_append(reply, "t", u); -} - static int property_get_syscall_filter( sd_bus *bus, const char *path, @@ -353,43 +192,9 @@ static int property_get_syscall_filter( if (r < 0) return r; -#if HAVE_SECCOMP - void *id, *val; - HASHMAP_FOREACH_KEY(val, id, c->syscall_filter) { - _cleanup_free_ char *name = NULL; - const char *e = NULL; - char *s; - int num = PTR_TO_INT(val); - - if (c->syscall_allow_list && num >= 0) - /* syscall with num >= 0 in allow-list is denied. */ - continue; - - name = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1); - if (!name) - continue; - - if (num >= 0) { - e = seccomp_errno_or_action_to_string(num); - if (e) { - s = strjoin(name, ":", e); - if (!s) - return -ENOMEM; - } else { - r = asprintf(&s, "%s:%d", name, num); - if (r < 0) - return -ENOMEM; - } - } else - s = TAKE_PTR(name); - - r = strv_consume(&l, s); - if (r < 0) - return r; - } -#endif - - strv_sort(l); + l = exec_context_get_syscall_filter(c); + if (!l) + return -ENOMEM; r = sd_bus_message_append_strv(reply, l); if (r < 0) @@ -422,22 +227,9 @@ static int property_get_syscall_log( if (r < 0) return r; -#if HAVE_SECCOMP - void *id, *val; - HASHMAP_FOREACH_KEY(val, id, c->syscall_log) { - char *name = NULL; - - name = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1); - if (!name) - continue; - - r = strv_consume(&l, name); - if (r < 0) - return r; - } -#endif - - strv_sort(l); + l = exec_context_get_syscall_log(c); + if (!l) + return -ENOMEM; r = sd_bus_message_append_strv(reply, l); if (r < 0) @@ -455,28 +247,16 @@ static int property_get_syscall_archs( void *userdata, sd_bus_error *error) { + ExecContext *c = ASSERT_PTR(userdata); _cleanup_strv_free_ char **l = NULL; int r; assert(bus); assert(reply); -#if HAVE_SECCOMP - void *id; - SET_FOREACH(id, ASSERT_PTR((ExecContext*) userdata)->syscall_archs) { - const char *name; - - name = seccomp_arch_to_string(PTR_TO_UINT32(id) - 1); - if (!name) - continue; - - r = strv_extend(&l, name); - if (r < 0) - return -ENOMEM; - } -#endif - - strv_sort(l); + l = exec_context_get_syscall_archs(c); + if (!l) + return -ENOMEM; r = sd_bus_message_append_strv(reply, l); if (r < 0) @@ -547,7 +327,6 @@ static int property_get_address_families( ExecContext *c = ASSERT_PTR(userdata); _cleanup_strv_free_ char **l = NULL; - void *af; int r; assert(bus); @@ -561,19 +340,9 @@ static int property_get_address_families( if (r < 0) return r; - SET_FOREACH(af, c->address_families) { - const char *name; - - name = af_to_name(PTR_TO_INT(af)); - if (!name) - continue; - - r = strv_extend(&l, name); - if (r < 0) - return -ENOMEM; - } - - strv_sort(l); + l = exec_context_get_address_families(c); + if (!l) + return -ENOMEM; r = sd_bus_message_append_strv(reply, l); if (r < 0) @@ -678,13 +447,9 @@ static int property_get_restrict_filesystems( if (r < 0) return r; -#if HAVE_LIBBPF - l = set_get_strv(c->restrict_filesystems); + l = exec_context_get_restrict_filesystems(c); if (!l) return -ENOMEM; -#endif - - strv_sort(l); r = sd_bus_message_append_strv(reply, l); if (r < 0) diff --git a/src/core/execute.c b/src/core/execute.c index 46fb8805b3a..d29821345a0 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -1542,6 +1542,237 @@ int exec_context_get_clean_mask(ExecContext *c, ExecCleanMask *ret) { return 0; } +int exec_context_get_oom_score_adjust(const ExecContext *c) { + int n = 0, r; + + assert(c); + + if (c->oom_score_adjust_set) + return c->oom_score_adjust; + + r = get_oom_score_adjust(&n); + if (r < 0) + log_debug_errno(r, "Failed to read /proc/self/oom_score_adj, ignoring: %m"); + + return n; +} + +uint64_t exec_context_get_coredump_filter(const ExecContext *c) { + _cleanup_free_ char *t = NULL; + uint64_t n = COREDUMP_FILTER_MASK_DEFAULT; + int r; + + assert(c); + + if (c->coredump_filter_set) + return c->coredump_filter; + + r = read_one_line_file("/proc/self/coredump_filter", &t); + if (r < 0) + log_debug_errno(r, "Failed to read /proc/self/coredump_filter, ignoring: %m"); + else { + r = safe_atoux64(t, &n); + if (r < 0) + log_debug_errno(r, "Failed to parse \"%s\" from /proc/self/coredump_filter, ignoring: %m", t); + } + + return n; +} + +int exec_context_get_nice(const ExecContext *c) { + int n; + + assert(c); + + if (c->nice_set) + return c->nice; + + errno = 0; + n = getpriority(PRIO_PROCESS, 0); + if (errno > 0) { + log_debug_errno(errno, "Failed to get process nice value, ignoring: %m"); + n = 0; + } + + return n; +} + +int exec_context_get_cpu_sched_policy(const ExecContext *c) { + int n; + + assert(c); + + if (c->cpu_sched_set) + return c->cpu_sched_policy; + + n = sched_getscheduler(0); + if (n < 0) + log_debug_errno(errno, "Failed to get scheduler policy, ignoring: %m"); + + return n < 0 ? SCHED_OTHER : n; +} + +int exec_context_get_cpu_sched_priority(const ExecContext *c) { + struct sched_param p = {}; + int r; + + assert(c); + + if (c->cpu_sched_set) + return c->cpu_sched_priority; + + r = sched_getparam(0, &p); + if (r < 0) + log_debug_errno(errno, "Failed to get scheduler priority, ignoring: %m"); + + return r >= 0 ? p.sched_priority : 0; +} + +uint64_t exec_context_get_timer_slack_nsec(const ExecContext *c) { + int r; + + assert(c); + + if (c->timer_slack_nsec != NSEC_INFINITY) + return c->timer_slack_nsec; + + r = prctl(PR_GET_TIMERSLACK); + if (r < 0) + log_debug_errno(r, "Failed to get timer slack, ignoring: %m"); + + return (uint64_t) MAX(r, 0); +} + +char** exec_context_get_syscall_filter(const ExecContext *c) { + _cleanup_strv_free_ char **l = NULL; + + assert(c); + +#if HAVE_SECCOMP + void *id, *val; + HASHMAP_FOREACH_KEY(val, id, c->syscall_filter) { + _cleanup_free_ char *name = NULL; + const char *e = NULL; + char *s; + int num = PTR_TO_INT(val); + + if (c->syscall_allow_list && num >= 0) + /* syscall with num >= 0 in allow-list is denied. */ + continue; + + name = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1); + if (!name) + continue; + + if (num >= 0) { + e = seccomp_errno_or_action_to_string(num); + if (e) { + s = strjoin(name, ":", e); + if (!s) + return NULL; + } else { + if (asprintf(&s, "%s:%d", name, num) < 0) + return NULL; + } + } else + s = TAKE_PTR(name); + + if (strv_consume(&l, s) < 0) + return NULL; + } + + strv_sort(l); +#endif + + return l ? TAKE_PTR(l) : strv_new(NULL); +} + +char** exec_context_get_syscall_archs(const ExecContext *c) { + _cleanup_strv_free_ char **l = NULL; + + assert(c); + +#if HAVE_SECCOMP + void *id; + SET_FOREACH(id, c->syscall_archs) { + const char *name; + + name = seccomp_arch_to_string(PTR_TO_UINT32(id) - 1); + if (!name) + continue; + + if (strv_extend(&l, name) < 0) + return NULL; + } + + strv_sort(l); +#endif + + return l ? TAKE_PTR(l) : strv_new(NULL); +} + +char** exec_context_get_syscall_log(const ExecContext *c) { + _cleanup_strv_free_ char **l = NULL; + + assert(c); + +#if HAVE_SECCOMP + void *id, *val; + HASHMAP_FOREACH_KEY(val, id, c->syscall_log) { + char *name = NULL; + + name = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1); + if (!name) + continue; + + if (strv_consume(&l, name) < 0) + return NULL; + } + + strv_sort(l); +#endif + + return l ? TAKE_PTR(l) : strv_new(NULL); +} + +char** exec_context_get_address_families(const ExecContext *c) { + _cleanup_strv_free_ char **l = NULL; + void *af; + + assert(c); + + SET_FOREACH(af, c->address_families) { + const char *name; + + name = af_to_name(PTR_TO_INT(af)); + if (!name) + continue; + + if (strv_extend(&l, name) < 0) + return NULL; + } + + strv_sort(l); + + return l ? TAKE_PTR(l) : strv_new(NULL); +} + +char** exec_context_get_restrict_filesystems(const ExecContext *c) { + _cleanup_strv_free_ char **l = NULL; + + assert(c); + +#if HAVE_LIBBPF + l = set_get_strv(c->restrict_filesystems); + if (!l) + return NULL; + + strv_sort(l); +#endif + + return l ? TAKE_PTR(l) : strv_new(NULL); +} + void exec_status_start(ExecStatus *s, pid_t pid) { assert(s); @@ -2454,6 +2685,16 @@ static const char* const exec_directory_type_symlink_table[_EXEC_DIRECTORY_TYPE_ DEFINE_STRING_TABLE_LOOKUP(exec_directory_type_symlink, ExecDirectoryType); +static const char* const exec_directory_type_mode_table[_EXEC_DIRECTORY_TYPE_MAX] = { + [EXEC_DIRECTORY_RUNTIME] = "RuntimeDirectoryMode", + [EXEC_DIRECTORY_STATE] = "StateDirectoryMode", + [EXEC_DIRECTORY_CACHE] = "CacheDirectoryMode", + [EXEC_DIRECTORY_LOGS] = "LogsDirectoryMode", + [EXEC_DIRECTORY_CONFIGURATION] = "ConfigurationDirectoryMode", +}; + +DEFINE_STRING_TABLE_LOOKUP(exec_directory_type_mode, ExecDirectoryType); + /* And this table maps ExecDirectoryType too, but to a generic term identifying the type of resource. This * one is supposed to be generic enough to be used for unit types that don't use ExecContext and per-unit * directories, specifically .timer units with their timestamp touch file. */ diff --git a/src/core/execute.h b/src/core/execute.h index 81e96848709..16295da1864 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -516,6 +516,19 @@ const char *exec_context_tty_path(const ExecContext *context); int exec_context_tty_size(const ExecContext *context, unsigned *ret_rows, unsigned *ret_cols); void exec_context_tty_reset(const ExecContext *context, const ExecParameters *p); +uint64_t exec_context_get_rlimit(const ExecContext *c, const char *name); +int exec_context_get_oom_score_adjust(const ExecContext *c); +uint64_t exec_context_get_coredump_filter(const ExecContext *c); +int exec_context_get_nice(const ExecContext *c); +int exec_context_get_cpu_sched_policy(const ExecContext *c); +int exec_context_get_cpu_sched_priority(const ExecContext *c); +uint64_t exec_context_get_timer_slack_nsec(const ExecContext *c); +char** exec_context_get_syscall_filter(const ExecContext *c); +char** exec_context_get_syscall_archs(const ExecContext *c); +char** exec_context_get_syscall_log(const ExecContext *c); +char** exec_context_get_address_families(const ExecContext *c); +char** exec_context_get_restrict_filesystems(const ExecContext *c); + void exec_status_start(ExecStatus *s, pid_t pid); void exec_status_exit(ExecStatus *s, const ExecContext *context, pid_t pid, int code, int status); void exec_status_dump(const ExecStatus *s, FILE *f, const char *prefix); @@ -573,6 +586,9 @@ ExecDirectoryType exec_directory_type_from_string(const char *s) _pure_; const char* exec_directory_type_symlink_to_string(ExecDirectoryType i) _const_; ExecDirectoryType exec_directory_type_symlink_from_string(const char *s) _pure_; +const char* exec_directory_type_mode_to_string(ExecDirectoryType i) _const_; +ExecDirectoryType exec_directory_type_mode_from_string(const char *s) _pure_; + const char* exec_resource_type_to_string(ExecDirectoryType i) _const_; ExecDirectoryType exec_resource_type_from_string(const char *s) _pure_; From 8dbab37dec924021b9b3398c91e7e0ecf01c9709 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Thu, 19 Oct 2023 16:38:47 +0200 Subject: [PATCH 05/13] mount: Add more helpers --- src/core/dbus-mount.c | 36 +++++------------------------ src/core/mount.c | 53 +++++++++++++++++++++++++++++++++++++++++++ src/core/mount.h | 4 ++++ 3 files changed, 63 insertions(+), 30 deletions(-) diff --git a/src/core/dbus-mount.c b/src/core/dbus-mount.c index 89f7d4fa0f9..7dbbdd07f50 100644 --- a/src/core/dbus-mount.c +++ b/src/core/dbus-mount.c @@ -22,21 +22,13 @@ static int property_get_what( _cleanup_free_ char *escaped = NULL; Mount *m = ASSERT_PTR(userdata); - const char *s = NULL; assert(bus); assert(reply); - if (m->from_proc_self_mountinfo && m->parameters_proc_self_mountinfo.what) - s = m->parameters_proc_self_mountinfo.what; - else if (m->from_fragment && m->parameters_fragment.what) - s = m->parameters_fragment.what; - - if (s) { - escaped = utf8_escape_invalid(s); - if (!escaped) - return -ENOMEM; - } + escaped = mount_get_what_escaped(m); + if (!escaped) + return -ENOMEM; return sd_bus_message_append_basic(reply, 's', escaped); } @@ -52,33 +44,17 @@ static int property_get_options( _cleanup_free_ char *escaped = NULL; Mount *m = ASSERT_PTR(userdata); - const char *s = NULL; assert(bus); assert(reply); - if (m->from_proc_self_mountinfo && m->parameters_proc_self_mountinfo.options) - s = m->parameters_proc_self_mountinfo.options; - else if (m->from_fragment && m->parameters_fragment.options) - s = m->parameters_fragment.options; - - if (s) { - escaped = utf8_escape_invalid(s); - if (!escaped) - return -ENOMEM; - } + escaped = mount_get_options_escaped(m); + if (!escaped) + return -ENOMEM; return sd_bus_message_append_basic(reply, 's', escaped); } -static const char *mount_get_fstype(const Mount *m) { - if (m->from_proc_self_mountinfo && m->parameters_proc_self_mountinfo.fstype) - return m->parameters_proc_self_mountinfo.fstype; - else if (m->from_fragment && m->parameters_fragment.fstype) - return m->parameters_fragment.fstype; - return NULL; -} - static BUS_DEFINE_PROPERTY_GET(property_get_type, "s", Mount, mount_get_fstype); static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, mount_result, MountResult); diff --git a/src/core/mount.c b/src/core/mount.c index 123c87ea1af..140286792a2 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -34,6 +34,7 @@ #include "strv.h" #include "unit-name.h" #include "unit.h" +#include "utf8.h" #define RETRY_UMOUNT_MAX 32 @@ -2345,6 +2346,58 @@ static int mount_subsystem_ratelimited(Manager *m) { return sd_event_source_is_ratelimited(m->mount_event_source); } +char* mount_get_what_escaped(const Mount *m) { + _cleanup_free_ char *escaped = NULL; + const char *s = NULL; + + assert(m); + + if (m->from_proc_self_mountinfo && m->parameters_proc_self_mountinfo.what) + s = m->parameters_proc_self_mountinfo.what; + else if (m->from_fragment && m->parameters_fragment.what) + s = m->parameters_fragment.what; + + if (s) { + escaped = utf8_escape_invalid(s); + if (!escaped) + return NULL; + } + + return escaped ? TAKE_PTR(escaped) : strdup(""); +} + +char* mount_get_options_escaped(const Mount *m) { + _cleanup_free_ char *escaped = NULL; + const char *s = NULL; + + assert(m); + + if (m->from_proc_self_mountinfo && m->parameters_proc_self_mountinfo.options) + s = m->parameters_proc_self_mountinfo.options; + else if (m->from_fragment && m->parameters_fragment.options) + s = m->parameters_fragment.options; + + if (s) { + escaped = utf8_escape_invalid(s); + if (!escaped) + return NULL; + } + + return escaped ? TAKE_PTR(escaped) : strdup(""); +} + +const char* mount_get_fstype(const Mount *m) { + assert(m); + + if (m->from_proc_self_mountinfo && m->parameters_proc_self_mountinfo.fstype) + return m->parameters_proc_self_mountinfo.fstype; + + if (m->from_fragment && m->parameters_fragment.fstype) + return m->parameters_fragment.fstype; + + return NULL; +} + static const char* const mount_exec_command_table[_MOUNT_EXEC_COMMAND_MAX] = { [MOUNT_EXEC_MOUNT] = "ExecMount", [MOUNT_EXEC_UNMOUNT] = "ExecUnmount", diff --git a/src/core/mount.h b/src/core/mount.h index 2c48d32b07d..6712c16811f 100644 --- a/src/core/mount.h +++ b/src/core/mount.h @@ -97,6 +97,10 @@ void mount_fd_event(Manager *m, int events); int mount_invalidate_state_by_path(Manager *manager, const char *path); +char* mount_get_what_escaped(const Mount *m); +char* mount_get_options_escaped(const Mount *m); +const char* mount_get_fstype(const Mount *m); + const char* mount_exec_command_to_string(MountExecCommand i) _const_; MountExecCommand mount_exec_command_from_string(const char *s) _pure_; From e49b211073bed96be0dcb9846a3a94f85498fe76 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Thu, 19 Oct 2023 16:41:04 +0200 Subject: [PATCH 06/13] socket: Add one more helper --- src/core/dbus-socket.c | 26 ++++---------------------- src/core/socket.c | 34 ++++++++++++++++++++++++++++++++++ src/core/socket.h | 2 ++ 3 files changed, 40 insertions(+), 22 deletions(-) diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c index 5e5b715e906..e77e9e5ccd2 100644 --- a/src/core/dbus-socket.c +++ b/src/core/dbus-socket.c @@ -44,30 +44,12 @@ static int property_get_listen( LIST_FOREACH(port, p, s->ports) { _cleanup_free_ char *address = NULL; - const char *a; - switch (p->type) { - case SOCKET_SOCKET: { - r = socket_address_print(&p->address, &address); - if (r) - return r; + r = socket_port_to_address(p, &address); + if (r < 0) + return r; - a = address; - break; - } - - case SOCKET_SPECIAL: - case SOCKET_MQUEUE: - case SOCKET_FIFO: - case SOCKET_USB_FUNCTION: - a = p->path; - break; - - default: - assert_not_reached(); - } - - r = sd_bus_message_append(reply, "(ss)", socket_port_type_to_string(p), a); + r = sd_bus_message_append(reply, "(ss)", socket_port_type_to_string(p), address); if (r < 0) return r; } diff --git a/src/core/socket.c b/src/core/socket.c index 62ce29076ee..bb7164d255b 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -2866,6 +2866,40 @@ static const char *socket_sub_state_to_string(Unit *u) { return socket_state_to_string(SOCKET(u)->state); } +int socket_port_to_address(const SocketPort *p, char **ret) { + _cleanup_free_ char *address = NULL; + int r; + + assert(p); + assert(ret); + + switch (p->type) { + case SOCKET_SOCKET: { + r = socket_address_print(&p->address, &address); + if (r < 0) + return r; + + break; + } + + case SOCKET_SPECIAL: + case SOCKET_MQUEUE: + case SOCKET_FIFO: + case SOCKET_USB_FUNCTION: + address = strdup(p->path); + if (!address) + return -ENOMEM; + break; + + default: + assert_not_reached(); + } + + *ret = TAKE_PTR(address); + + return 0; +} + const char* socket_port_type_to_string(SocketPort *p) { assert(p); diff --git a/src/core/socket.h b/src/core/socket.h index 0b82141659a..0983e8c9d0f 100644 --- a/src/core/socket.h +++ b/src/core/socket.h @@ -180,6 +180,8 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(SocketPort*, socket_port_free); void socket_free_ports(Socket *s); +int socket_port_to_address(const SocketPort *s, char **ret); + int socket_load_service_unit(Socket *s, int cfd, Unit **ret); char *socket_fdname(Socket *s); From f57cc32fa1c74c1eaecc52a085133a38952a255f Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Thu, 19 Oct 2023 16:41:52 +0200 Subject: [PATCH 07/13] swap: Move two functions to swap.h --- src/core/dbus-swap.c | 21 --------------------- src/core/swap.c | 21 +++++++++++++++++++++ src/core/swap.h | 3 +++ 3 files changed, 24 insertions(+), 21 deletions(-) diff --git a/src/core/dbus-swap.c b/src/core/dbus-swap.c index 443f84aab40..7230352e9cb 100644 --- a/src/core/dbus-swap.c +++ b/src/core/dbus-swap.c @@ -11,27 +11,6 @@ #include "swap.h" #include "unit.h" -static int swap_get_priority(Swap *s) { - assert(s); - - if (s->from_proc_swaps && s->parameters_proc_swaps.priority_set) - return s->parameters_proc_swaps.priority; - - if (s->from_fragment && s->parameters_fragment.priority_set) - return s->parameters_fragment.priority; - - return -1; -} - -static const char *swap_get_options(Swap *s) { - assert(s); - - if (s->from_fragment) - return s->parameters_fragment.options; - - return NULL; -} - static BUS_DEFINE_PROPERTY_GET(property_get_priority, "i", Swap, swap_get_priority); static BUS_DEFINE_PROPERTY_GET(property_get_options, "s", Swap, swap_get_options); static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, swap_result, SwapResult); diff --git a/src/core/swap.c b/src/core/swap.c index d0aae9a5343..3a9f0e798dd 100644 --- a/src/core/swap.c +++ b/src/core/swap.c @@ -1559,6 +1559,27 @@ static int swap_can_start(Unit *u) { return 1; } +int swap_get_priority(const Swap *s) { + assert(s); + + if (s->from_proc_swaps && s->parameters_proc_swaps.priority_set) + return s->parameters_proc_swaps.priority; + + if (s->from_fragment && s->parameters_fragment.priority_set) + return s->parameters_fragment.priority; + + return -1; +} + +const char* swap_get_options(const Swap *s) { + assert(s); + + if (s->from_fragment) + return s->parameters_fragment.options; + + return NULL; +} + static const char* const swap_exec_command_table[_SWAP_EXEC_COMMAND_MAX] = { [SWAP_EXEC_ACTIVATE] = "ExecActivate", [SWAP_EXEC_DEACTIVATE] = "ExecDeactivate", diff --git a/src/core/swap.h b/src/core/swap.h index f2cae6766b8..ef20f0f7647 100644 --- a/src/core/swap.h +++ b/src/core/swap.h @@ -91,6 +91,9 @@ extern const UnitVTable swap_vtable; int swap_process_device_new(Manager *m, sd_device *dev); int swap_process_device_remove(Manager *m, sd_device *dev); +int swap_get_priority(const Swap *s); +const char* swap_get_options(const Swap *s); + const char* swap_exec_command_to_string(SwapExecCommand i) _const_; SwapExecCommand swap_exec_command_from_string(const char *s) _pure_; From f8a990a0a14f714c689e24c8d34df74f2f73c3ca Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Thu, 19 Oct 2023 16:42:38 +0200 Subject: [PATCH 08/13] timer: Add two more helper functions --- src/core/dbus-timer.c | 22 +++++----------------- src/core/timer.c | 32 ++++++++++++++++++++++++++++++++ src/core/timer.h | 4 ++++ 3 files changed, 41 insertions(+), 17 deletions(-) diff --git a/src/core/dbus-timer.c b/src/core/dbus-timer.c index 80dd40a16a4..4f78a521de2 100644 --- a/src/core/dbus-timer.c +++ b/src/core/dbus-timer.c @@ -30,26 +30,16 @@ static int property_get_monotonic_timers( return r; LIST_FOREACH(value, v, t->values) { - _cleanup_free_ char *buf = NULL; - const char *s; - size_t l; + _cleanup_free_ char *usec = NULL; if (v->base == TIMER_CALENDAR) continue; - s = timer_base_to_string(v->base); - assert(endswith(s, "Sec")); - - /* s/Sec/USec/ */ - l = strlen(s); - buf = new(char, l+2); - if (!buf) + usec = timer_base_to_usec_string(v->base); + if (!usec) return -ENOMEM; - memcpy(buf, s, l-3); - memcpy(buf+l-3, "USec", 5); - - r = sd_bus_message_append(reply, "(stt)", buf, v->value, v->next_elapse); + r = sd_bus_message_append(reply, "(stt)", usec, v->value, v->next_elapse); if (r < 0) return r; } @@ -108,9 +98,7 @@ static int property_get_next_elapse_monotonic( assert(bus); assert(reply); - return sd_bus_message_append(reply, "t", - (uint64_t) usec_shift_clock(t->next_elapse_monotonic_or_boottime, - TIMER_MONOTONIC_CLOCK(t), CLOCK_MONOTONIC)); + return sd_bus_message_append(reply, "t", timer_next_elapse_monotonic(t)); } const sd_bus_vtable bus_timer_vtable[] = { diff --git a/src/core/timer.c b/src/core/timer.c index ba18691cec8..97233a88f69 100644 --- a/src/core/timer.c +++ b/src/core/timer.c @@ -1001,6 +1001,13 @@ static int activation_details_timer_append_pair(ActivationDetails *details, char return 2; /* Return the number of pairs added to the env block */ } +uint64_t timer_next_elapse_monotonic(const Timer *t) { + assert(t); + + return (uint64_t) usec_shift_clock(t->next_elapse_monotonic_or_boottime, + TIMER_MONOTONIC_CLOCK(t), CLOCK_MONOTONIC); +} + static const char* const timer_base_table[_TIMER_BASE_MAX] = { [TIMER_ACTIVE] = "OnActiveSec", [TIMER_BOOT] = "OnBootSec", @@ -1012,6 +1019,31 @@ static const char* const timer_base_table[_TIMER_BASE_MAX] = { DEFINE_STRING_TABLE_LOOKUP(timer_base, TimerBase); +char* timer_base_to_usec_string(TimerBase i) { + _cleanup_free_ char *buf = NULL; + const char *s; + size_t l; + + s = timer_base_to_string(i); + + if (endswith(s, "Sec")) { + /* s/Sec/USec/ */ + l = strlen(s); + buf = new(char, l+2); + if (!buf) + return NULL; + + memcpy(buf, s, l-3); + memcpy(buf+l-3, "USec", 5); + } else { + buf = strdup(s); + if (!buf) + return NULL; + } + + return TAKE_PTR(buf); +} + static const char* const timer_result_table[_TIMER_RESULT_MAX] = { [TIMER_SUCCESS] = "success", [TIMER_FAILURE_RESOURCES] = "resources", diff --git a/src/core/timer.h b/src/core/timer.h index 914e42580e3..76d45b2ae1d 100644 --- a/src/core/timer.h +++ b/src/core/timer.h @@ -72,6 +72,8 @@ struct ActivationDetailsTimer { #define TIMER_MONOTONIC_CLOCK(t) ((t)->wake_system ? CLOCK_BOOTTIME_ALARM : CLOCK_MONOTONIC) +uint64_t timer_next_elapse_monotonic(const Timer *t); + void timer_free_values(Timer *t); extern const UnitVTable timer_vtable; @@ -80,6 +82,8 @@ extern const ActivationDetailsVTable activation_details_timer_vtable; const char *timer_base_to_string(TimerBase i) _const_; TimerBase timer_base_from_string(const char *s) _pure_; +char* timer_base_to_usec_string(TimerBase i); + const char* timer_result_to_string(TimerResult i) _const_; TimerResult timer_result_from_string(const char *s) _pure_; From f882c1029daa63d7e99e8d3b5dd8dea3233bccfc Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Thu, 19 Oct 2023 16:45:23 +0200 Subject: [PATCH 09/13] unit: Move three helpers to unit.h --- src/core/dbus-unit.c | 12 ------------ src/core/unit.c | 12 ++++++++++++ src/core/unit.h | 4 ++++ 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c index ab72b4e0948..2fff6e135d3 100644 --- a/src/core/dbus-unit.c +++ b/src/core/dbus-unit.c @@ -30,18 +30,6 @@ #include "user-util.h" #include "web-util.h" -static bool unit_can_start_refuse_manual(Unit *u) { - return unit_can_start(u) && !u->refuse_manual_start; -} - -static bool unit_can_stop_refuse_manual(Unit *u) { - return unit_can_stop(u) && !u->refuse_manual_stop; -} - -static bool unit_can_isolate_refuse_manual(Unit *u) { - return unit_can_isolate(u) && !u->refuse_manual_start; -} - static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_collect_mode, collect_mode, CollectMode); static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_load_state, unit_load_state, UnitLoadState); static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_job_mode, job_mode, JobMode); diff --git a/src/core/unit.c b/src/core/unit.c index a60656709ad..d76e86e5f30 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -6167,6 +6167,18 @@ int unit_can_clean(Unit *u, ExecCleanMask *ret) { return UNIT_VTABLE(u)->can_clean(u, ret); } +bool unit_can_start_refuse_manual(Unit *u) { + return unit_can_start(u) && !u->refuse_manual_start; +} + +bool unit_can_stop_refuse_manual(Unit *u) { + return unit_can_stop(u) && !u->refuse_manual_stop; +} + +bool unit_can_isolate_refuse_manual(Unit *u) { + return unit_can_isolate(u) && !u->refuse_manual_start; +} + bool unit_can_freeze(Unit *u) { assert(u); diff --git a/src/core/unit.h b/src/core/unit.h index 2427e2e765b..44d0cd2e41b 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -1078,6 +1078,10 @@ void unit_destroy_runtime_data(Unit *u, const ExecContext *context); int unit_clean(Unit *u, ExecCleanMask mask); int unit_can_clean(Unit *u, ExecCleanMask *ret_mask); +bool unit_can_start_refuse_manual(Unit *u); +bool unit_can_stop_refuse_manual(Unit *u); +bool unit_can_isolate_refuse_manual(Unit *u); + bool unit_can_freeze(Unit *u); int unit_freeze(Unit *u); void unit_frozen(Unit *u); From cc156539d993f9b1b2a96e0ea184b742564273b0 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Thu, 19 Oct 2023 16:49:08 +0200 Subject: [PATCH 10/13] manager: Introduce manager_get_progress() helper --- src/core/dbus-manager.c | 24 +----------------------- src/core/manager.c | 9 +++++++++ src/core/manager.h | 2 ++ 3 files changed, 12 insertions(+), 23 deletions(-) diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index 9917419096b..745f5cc17c6 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -67,6 +67,7 @@ static BUS_DEFINE_PROPERTY_GET(property_get_default_timeout_abort_usec, "t", Man static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_watchdog_device, "s", watchdog_get_device()); static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_watchdog_last_ping_realtime, "t", watchdog_get_last_ping(CLOCK_REALTIME)); static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_watchdog_last_ping_monotonic, "t", watchdog_get_last_ping(CLOCK_MONOTONIC)); +static BUS_DEFINE_PROPERTY_GET(property_get_progress, "d", Manager, manager_get_progress); static int property_get_virtualization( sd_bus *bus, @@ -207,29 +208,6 @@ static int property_set_log_level( return 0; } -static int property_get_progress( - sd_bus *bus, - const char *path, - const char *interface, - const char *property, - sd_bus_message *reply, - void *userdata, - sd_bus_error *error) { - - Manager *m = ASSERT_PTR(userdata); - double d; - - assert(bus); - assert(reply); - - if (MANAGER_IS_FINISHED(m)) - d = 1.0; - else - d = 1.0 - ((double) hashmap_size(m->jobs) / (double) m->n_installed_jobs); - - return sd_bus_message_append(reply, "d", d); -} - static int property_get_environment( sd_bus *bus, const char *path, diff --git a/src/core/manager.c b/src/core/manager.c index 935e6559564..a9cfe9a7fd8 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -866,6 +866,15 @@ void manager_set_switching_root(Manager *m, bool switching_root) { m->switching_root = MANAGER_IS_SYSTEM(m) && switching_root; } +double manager_get_progress(Manager *m) { + assert(m); + + if (MANAGER_IS_FINISHED(m) || m->n_installed_jobs == 0) + return 1.0; + + return 1.0 - ((double) hashmap_size(m->jobs) / (double) m->n_installed_jobs); +} + static int compare_job_priority(const void *a, const void *b) { const Job *x = a, *y = b; diff --git a/src/core/manager.h b/src/core/manager.h index 3b3920078e6..d96eb7b995f 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -592,6 +592,8 @@ void manager_override_show_status(Manager *m, ShowStatus mode, const char *reaso void manager_set_first_boot(Manager *m, bool b); void manager_set_switching_root(Manager *m, bool switching_root); +double manager_get_progress(Manager *m); + void manager_status_printf(Manager *m, StatusType type, const char *status, const char *format, ...) _printf_(4,5); Set *manager_get_units_requiring_mounts_for(Manager *m, const char *path); From b2e9d80956b5300c4bf29c12ea5726f77eaf813d Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Fri, 20 Oct 2023 12:07:32 +0200 Subject: [PATCH 11/13] hashmap: Add extra uncounted entry to returned array from hashmap_dump_sorted() This allows using the returned array as a strv. --- src/basic/hashmap.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/basic/hashmap.c b/src/basic/hashmap.c index ac1c7329788..894760ca609 100644 --- a/src/basic/hashmap.c +++ b/src/basic/hashmap.c @@ -2135,7 +2135,9 @@ int _hashmap_dump_sorted(HashmapBase *h, void ***ret, size_t *ret_n) { return 0; } - entries = new(struct hashmap_base_entry*, _hashmap_size(h)); + /* We append one more element than needed so that the resulting array can be used as a strv. We + * don't count this entry in the returned size. */ + entries = new(struct hashmap_base_entry*, _hashmap_size(h) + 1); if (!entries) return -ENOMEM; @@ -2143,6 +2145,7 @@ int _hashmap_dump_sorted(HashmapBase *h, void ***ret, size_t *ret_n) { entries[n++] = bucket_at(h, idx); assert(n == _hashmap_size(h)); + entries[n] = NULL; typesafe_qsort_r(entries, n, hashmap_entry_compare, h->hash_ops->compare); From a636a058f143425dc03d483c0ccc451eaaa2cb35 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Thu, 19 Oct 2023 16:51:08 +0200 Subject: [PATCH 12/13] json: Introduce JSON_BUILD_STRING_SET --- src/shared/json.c | 35 +++++++++++++++++++++++++++++++++++ src/shared/json.h | 3 +++ 2 files changed, 38 insertions(+) diff --git a/src/shared/json.c b/src/shared/json.c index f7e61f1676c..db3581dfd4a 100644 --- a/src/shared/json.c +++ b/src/shared/json.c @@ -21,6 +21,7 @@ #include "math-util.h" #include "memory-util.h" #include "memstream-util.h" +#include "set.h" #include "string-table.h" #include "string-util.h" #include "strv.h" @@ -3877,6 +3878,40 @@ int json_buildv(JsonVariant **ret, va_list ap) { break; } + case _JSON_BUILD_STRING_SET: { + Set *set; + + if (!IN_SET(current->expect, EXPECT_TOPLEVEL, EXPECT_OBJECT_VALUE, EXPECT_ARRAY_ELEMENT)) { + r = -EINVAL; + goto finish; + } + + set = va_arg(ap, Set*); + + if (current->n_suppress == 0) { + _cleanup_free_ char **sorted = NULL; + + r = set_dump_sorted(set, (void ***) &sorted, NULL); + if (r < 0) + goto finish; + + r = json_variant_new_array_strv(&add, sorted); + if (r < 0) + goto finish; + } + + n_subtract = 1; + + if (current->expect == EXPECT_TOPLEVEL) + current->expect = EXPECT_END; + else if (current->expect == EXPECT_OBJECT_VALUE) + current->expect = EXPECT_OBJECT_KEY; + else + assert(current->expect == EXPECT_ARRAY_ELEMENT); + + break; + } + case _JSON_BUILD_OBJECT_BEGIN: if (!IN_SET(current->expect, EXPECT_TOPLEVEL, EXPECT_OBJECT_VALUE, EXPECT_ARRAY_ELEMENT)) { diff --git a/src/shared/json.h b/src/shared/json.h index 8ddff6be982..4b25d36a325 100644 --- a/src/shared/json.h +++ b/src/shared/json.h @@ -275,6 +275,7 @@ enum { _JSON_BUILD_UUID, _JSON_BUILD_BYTE_ARRAY, _JSON_BUILD_HW_ADDR, + _JSON_BUILD_STRING_SET, _JSON_BUILD_PAIR_UNSIGNED_NON_ZERO, _JSON_BUILD_PAIR_FINITE_USEC, _JSON_BUILD_PAIR_STRING_NON_EMPTY, @@ -319,6 +320,7 @@ enum { #define JSON_BUILD_IN_ADDR(v, f) JSON_BUILD_BYTE_ARRAY(((const union in_addr_union*) { v })->bytes, FAMILY_ADDRESS_SIZE_SAFE(f)) #define JSON_BUILD_ETHER_ADDR(v) JSON_BUILD_BYTE_ARRAY(((const struct ether_addr*) { v })->ether_addr_octet, sizeof(struct ether_addr)) #define JSON_BUILD_HW_ADDR(v) _JSON_BUILD_HW_ADDR, (const struct hw_addr_data*) { v } +#define JSON_BUILD_STRING_SET(s) _JSON_BUILD_STRING_SET, (Set *) { s } #define JSON_BUILD_PAIR_STRING(name, s) JSON_BUILD_PAIR(name, JSON_BUILD_STRING(s)) #define JSON_BUILD_PAIR_INTEGER(name, i) JSON_BUILD_PAIR(name, JSON_BUILD_INTEGER(i)) @@ -344,6 +346,7 @@ enum { #define JSON_BUILD_PAIR_IN_ADDR(name, v, f) JSON_BUILD_PAIR(name, JSON_BUILD_IN_ADDR(v, f)) #define JSON_BUILD_PAIR_ETHER_ADDR(name, v) JSON_BUILD_PAIR(name, JSON_BUILD_ETHER_ADDR(v)) #define JSON_BUILD_PAIR_HW_ADDR(name, v) JSON_BUILD_PAIR(name, JSON_BUILD_HW_ADDR(v)) +#define JSON_BUILD_PAIR_STRING_SET(name, s) JSON_BUILD_PAIR(name, JSON_BUILD_STRING_SET(s)) #define JSON_BUILD_PAIR_UNSIGNED_NON_ZERO(name, u) _JSON_BUILD_PAIR_UNSIGNED_NON_ZERO, (const char*) { name }, (uint64_t) { u } #define JSON_BUILD_PAIR_FINITE_USEC(name, u) _JSON_BUILD_PAIR_FINITE_USEC, (const char*) { name }, (usec_t) { u } From 8eb735b8001585ecfefd61f88eb2246df37aa41a Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Fri, 20 Oct 2023 12:31:56 +0200 Subject: [PATCH 13/13] json: Introduce JSON_BUILD_CALLBACK --- src/shared/json.c | 48 +++++++++++++++++++++++++++++++++++++++++------ src/shared/json.h | 5 +++++ 2 files changed, 47 insertions(+), 6 deletions(-) diff --git a/src/shared/json.c b/src/shared/json.c index db3581dfd4a..592ab356383 100644 --- a/src/shared/json.c +++ b/src/shared/json.c @@ -3351,6 +3351,7 @@ int json_parse_file_at( int json_buildv(JsonVariant **ret, va_list ap) { JsonStack *stack = NULL; size_t n_stack = 1; + const char *name = NULL; int r; assert_return(ret, -EINVAL); @@ -3912,6 +3913,43 @@ int json_buildv(JsonVariant **ret, va_list ap) { break; } + case _JSON_BUILD_CALLBACK: { + JsonBuildCallback cb; + void *userdata; + + if (!IN_SET(current->expect, EXPECT_TOPLEVEL, EXPECT_OBJECT_VALUE, EXPECT_ARRAY_ELEMENT)) { + r = -EINVAL; + goto finish; + } + + cb = va_arg(ap, JsonBuildCallback); + userdata = va_arg(ap, void *); + + if (current->n_suppress == 0) { + if (cb) { + r = cb(&add, name, userdata); + if (r < 0) + goto finish; + } + + if (!add) + add = JSON_VARIANT_MAGIC_NULL; + + name = NULL; + } + + n_subtract = 1; + + if (current->expect == EXPECT_TOPLEVEL) + current->expect = EXPECT_END; + else if (current->expect == EXPECT_OBJECT_VALUE) + current->expect = EXPECT_OBJECT_KEY; + else + assert(current->expect == EXPECT_ARRAY_ELEMENT); + + break; + } + case _JSON_BUILD_OBJECT_BEGIN: if (!IN_SET(current->expect, EXPECT_TOPLEVEL, EXPECT_OBJECT_VALUE, EXPECT_ARRAY_ELEMENT)) { @@ -3965,17 +4003,16 @@ int json_buildv(JsonVariant **ret, va_list ap) { break; case _JSON_BUILD_PAIR: { - const char *n; if (current->expect != EXPECT_OBJECT_KEY) { r = -EINVAL; goto finish; } - n = va_arg(ap, const char *); + name = va_arg(ap, const char *); if (current->n_suppress == 0) { - r = json_variant_new_string(&add, n); + r = json_variant_new_string(&add, name); if (r < 0) goto finish; } @@ -3987,7 +4024,6 @@ int json_buildv(JsonVariant **ret, va_list ap) { } case _JSON_BUILD_PAIR_CONDITION: { - const char *n; bool b; if (current->expect != EXPECT_OBJECT_KEY) { @@ -3996,10 +4032,10 @@ int json_buildv(JsonVariant **ret, va_list ap) { } b = va_arg(ap, int); - n = va_arg(ap, const char *); + name = va_arg(ap, const char *); if (b && current->n_suppress == 0) { - r = json_variant_new_string(&add, n); + r = json_variant_new_string(&add, name); if (r < 0) goto finish; } diff --git a/src/shared/json.h b/src/shared/json.h index 4b25d36a325..f24fabfeb6a 100644 --- a/src/shared/json.h +++ b/src/shared/json.h @@ -276,6 +276,7 @@ enum { _JSON_BUILD_BYTE_ARRAY, _JSON_BUILD_HW_ADDR, _JSON_BUILD_STRING_SET, + _JSON_BUILD_CALLBACK, _JSON_BUILD_PAIR_UNSIGNED_NON_ZERO, _JSON_BUILD_PAIR_FINITE_USEC, _JSON_BUILD_PAIR_STRING_NON_EMPTY, @@ -290,6 +291,8 @@ enum { _JSON_BUILD_MAX, }; +typedef int (*JsonBuildCallback)(JsonVariant **ret, const char *name, void *userdata); + #define JSON_BUILD_STRING(s) _JSON_BUILD_STRING, (const char*) { s } #define JSON_BUILD_INTEGER(i) _JSON_BUILD_INTEGER, (int64_t) { i } #define JSON_BUILD_UNSIGNED(u) _JSON_BUILD_UNSIGNED, (uint64_t) { u } @@ -321,6 +324,7 @@ enum { #define JSON_BUILD_ETHER_ADDR(v) JSON_BUILD_BYTE_ARRAY(((const struct ether_addr*) { v })->ether_addr_octet, sizeof(struct ether_addr)) #define JSON_BUILD_HW_ADDR(v) _JSON_BUILD_HW_ADDR, (const struct hw_addr_data*) { v } #define JSON_BUILD_STRING_SET(s) _JSON_BUILD_STRING_SET, (Set *) { s } +#define JSON_BUILD_CALLBACK(c, u) _JSON_BUILD_CALLBACK, (JsonBuildCallback) { c }, (void*) { u } #define JSON_BUILD_PAIR_STRING(name, s) JSON_BUILD_PAIR(name, JSON_BUILD_STRING(s)) #define JSON_BUILD_PAIR_INTEGER(name, i) JSON_BUILD_PAIR(name, JSON_BUILD_INTEGER(i)) @@ -347,6 +351,7 @@ enum { #define JSON_BUILD_PAIR_ETHER_ADDR(name, v) JSON_BUILD_PAIR(name, JSON_BUILD_ETHER_ADDR(v)) #define JSON_BUILD_PAIR_HW_ADDR(name, v) JSON_BUILD_PAIR(name, JSON_BUILD_HW_ADDR(v)) #define JSON_BUILD_PAIR_STRING_SET(name, s) JSON_BUILD_PAIR(name, JSON_BUILD_STRING_SET(s)) +#define JSON_BUILD_PAIR_CALLBACK(name, c, u) JSON_BUILD_PAIR(name, JSON_BUILD_CALLBACK(c, u)) #define JSON_BUILD_PAIR_UNSIGNED_NON_ZERO(name, u) _JSON_BUILD_PAIR_UNSIGNED_NON_ZERO, (const char*) { name }, (uint64_t) { u } #define JSON_BUILD_PAIR_FINITE_USEC(name, u) _JSON_BUILD_PAIR_FINITE_USEC, (const char*) { name }, (usec_t) { u }