From: Lennart Poettering Date: Mon, 27 Mar 2023 16:16:40 +0000 (+0200) Subject: pid1: add DumpFileDescriptorStore() bus call that returns fdstore content info X-Git-Tag: v254-rc1~864^2~7 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=2ea24611b99d12955ba374f072148b9ad6d644dc;p=thirdparty%2Fsystemd.git pid1: add DumpFileDescriptorStore() bus call that returns fdstore content info --- diff --git a/man/org.freedesktop.systemd1.xml b/man/org.freedesktop.systemd1.xml index ab94a90b7cf..1a82a19bbdc 100644 --- a/man/org.freedesktop.systemd1.xml +++ b/man/org.freedesktop.systemd1.xml @@ -273,6 +273,8 @@ node /org/freedesktop/systemd1 { LookupDynamicUserByUID(in u uid, out s name); GetDynamicUsers(out a(us) users); + DumpUnitFileDescriptorStore(in s name, + out a(suuutuusu) entries); signals: UnitNew(s id, o unit); @@ -974,6 +976,8 @@ node /org/freedesktop/systemd1 { + + @@ -1531,6 +1535,11 @@ node /org/freedesktop/systemd1 { New Control Group Interface for more information how to make use of this functionality for resource control purposes. + + DumpUnitFileDescriptorStore() returns an array with information about the + file descriptors currently in the file descriptor store of the specified unit. This call is equivalent + to DumpFileDescriptorStore() on the + org.freedesktop.systemd1.Service. For further details, see below. @@ -2548,6 +2557,7 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { in b read_only, in b mkdir, in a(ss) options); + DumpFileDescriptorStore(out a(suuutuusu) entries); GetProcesses(out a(sus) processes); AttachProcesses(in s subcgroup, in au pids); @@ -3742,6 +3752,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { + + @@ -4393,6 +4405,16 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { directly on the Manager object has the advantage of not requiring a GetUnit() call to get the unit object for a specific unit name. Calling the methods on the Manager object is hence a round trip optimization. + + DumpFileDescriptorStore() returns an array with information about the file + descriptors currently in the file descriptor store of the service. Each entry consists of a file + descriptor name (i.e. the FDNAME= field), the file descriptor inode type and access + mode as integer (i.e. a mode_t value, flags such as S_IFREG, + S_IRUSR, …), the major and minor numbers of the device number of the file system + backing the inode of the file descriptor, the inode number, the major and minor numbers of the device + number if this refers to a character or block device node, a file system path pointing to the inode, + and the file descriptor flags (i.e. O_RDWR, O_RDONLY, + …). diff --git a/src/basic/missing_fcntl.h b/src/basic/missing_fcntl.h index 00937d2af03..79e95a8f6fd 100644 --- a/src/basic/missing_fcntl.h +++ b/src/basic/missing_fcntl.h @@ -58,3 +58,12 @@ #ifndef O_TMPFILE #define O_TMPFILE (__O_TMPFILE | O_DIRECTORY) #endif + +/* So O_LARGEFILE is generally implied by glibc, and defined to zero hence, because we only build in LFS + * mode. However, when invoking fcntl(F_GETFL) the flag is ORed into the result anyway — glibc does not mask + * it away. Which sucks. Let's define the actual value here, so that we can mask it ourselves. */ +#if O_LARGEFILE != 0 +#define RAW_O_LARGEFILE O_LARGEFILE +#else +#define RAW_O_LARGEFILE 0100000 +#endif diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index c88ef93443c..2cb9efc14e1 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -2840,6 +2840,10 @@ static int method_set_show_status(sd_bus_message *message, void *userdata, sd_bu return sd_bus_reply_method_return(message, NULL); } +static int method_dump_unit_descriptor_store(sd_bus_message *message, void *userdata, sd_bus_error *error) { + return method_generic_unit_operation(message, userdata, error, bus_service_method_dump_file_descriptor_store, 0); +} + const sd_bus_vtable bus_manager_vtable[] = { SD_BUS_VTABLE_START(0), @@ -3385,6 +3389,11 @@ const sd_bus_vtable bus_manager_vtable[] = { SD_BUS_RESULT("a(us)", users), method_get_dynamic_users, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("DumpUnitFileDescriptorStore", + SD_BUS_ARGS("s", name), + SD_BUS_RESULT("a(suuutuusu)", entries), + method_dump_unit_descriptor_store, + SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_SIGNAL_WITH_ARGS("UnitNew", SD_BUS_ARGS("s", id, "o", unit), diff --git a/src/core/dbus-service.c b/src/core/dbus-service.c index ddfffe80fd6..742893370f6 100644 --- a/src/core/dbus-service.c +++ b/src/core/dbus-service.c @@ -4,6 +4,7 @@ #include "alloc-util.h" #include "async.h" +#include "bus-common-errors.h" #include "bus-get-properties.h" #include "dbus-cgroup.h" #include "dbus-execute.h" @@ -16,6 +17,7 @@ #include "fd-util.h" #include "fileio.h" #include "locale-util.h" +#include "missing_fcntl.h" #include "mount-util.h" #include "open-file.h" #include "parse-util.h" @@ -218,6 +220,72 @@ int bus_service_method_mount_image(sd_bus_message *message, void *userdata, sd_b return bus_service_method_mount(message, userdata, error, true); } +int bus_service_method_dump_file_descriptor_store(sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + Service *s = ASSERT_PTR(userdata); + int r; + + assert(message); + + r = mac_selinux_unit_access_check(UNIT(s), message, "status", error); + if (r < 0) + return r; + + if (s->n_fd_store_max == 0 && s->n_fd_store == 0) + return sd_bus_error_setf(error, BUS_ERROR_FILE_DESCRIPTOR_STORE_DISABLED, "File descriptor store not enabled for %s.", UNIT(s)->id); + + r = sd_bus_message_new_method_return(message, &reply); + if (r < 0) + return r; + + r = sd_bus_message_open_container(reply, 'a', "(suuutuusu)"); + if (r < 0) + return r; + + LIST_FOREACH(fd_store, i, s->fd_store) { + _cleanup_free_ char *path = NULL; + struct stat st; + int flags; + + if (fstat(i->fd, &st) < 0) { + log_debug_errno(errno, "Failed to stat() file descriptor entry '%s', skipping.", strna(i->fdname)); + continue; + } + + flags = fcntl(i->fd, F_GETFL); + if (flags < 0) { + log_debug_errno(errno, "Failed to issue F_GETFL on file descriptor entry '%s', skipping.", strna(i->fdname)); + continue; + } + + /* glibc implies O_LARGEFILE everywhere on 64bit off_t builds, but forgets to hide it away on + * F_GETFL, but provides no definition to check for that. Let's mask the flag away manually, + * to not confuse clients. */ + flags &= ~RAW_O_LARGEFILE; + + (void) fd_get_path(i->fd, &path); + + r = sd_bus_message_append( + reply, + "(suuutuusu)", + i->fdname, + (uint32_t) st.st_mode, + (uint32_t) major(st.st_dev), (uint32_t) minor(st.st_dev), + (uint64_t) st.st_ino, + (uint32_t) major(st.st_rdev), (uint32_t) minor(st.st_rdev), + path, + (uint32_t) flags); + if (r < 0) + return r; + } + + r = sd_bus_message_close_container(reply); + if (r < 0) + return r; + + return sd_bus_send(NULL, reply, NULL); +} + const sd_bus_vtable bus_service_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Service, type), SD_BUS_VTABLE_PROPERTY_CONST), @@ -292,6 +360,12 @@ const sd_bus_vtable bus_service_vtable[] = { bus_service_method_mount_image, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("DumpFileDescriptorStore", + SD_BUS_NO_ARGS, + SD_BUS_ARGS("a(suuutuusu)", entries), + bus_service_method_dump_file_descriptor_store, + SD_BUS_VTABLE_UNPRIVILEGED), + /* The following four are obsolete, and thus marked hidden here. They moved into the Unit interface */ SD_BUS_PROPERTY("StartLimitInterval", "t", bus_property_get_usec, offsetof(Unit, start_ratelimit.interval), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN), SD_BUS_PROPERTY("StartLimitBurst", "u", bus_property_get_unsigned, offsetof(Unit, start_ratelimit.burst), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN), diff --git a/src/core/dbus-service.h b/src/core/dbus-service.h index 9a054658025..aea6cf77f30 100644 --- a/src/core/dbus-service.h +++ b/src/core/dbus-service.h @@ -12,3 +12,4 @@ int bus_service_set_property(Unit *u, const char *name, sd_bus_message *i, UnitW int bus_service_method_bind_mount(sd_bus_message *message, void *userdata, sd_bus_error *error); int bus_service_method_mount_image(sd_bus_message *message, void *userdata, sd_bus_error *error); int bus_service_commit_properties(Unit *u); +int bus_service_method_dump_file_descriptor_store(sd_bus_message *message, void *userdata, sd_bus_error *error); diff --git a/src/libsystemd/sd-bus/bus-common-errors.c b/src/libsystemd/sd-bus/bus-common-errors.c index 0eaedec87c7..df26fd75cd1 100644 --- a/src/libsystemd/sd-bus/bus-common-errors.c +++ b/src/libsystemd/sd-bus/bus-common-errors.c @@ -32,6 +32,8 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = { SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_DYNAMIC_USER, ESRCH), SD_BUS_ERROR_MAP(BUS_ERROR_NOT_REFERENCED, EUNATCH), SD_BUS_ERROR_MAP(BUS_ERROR_DISK_FULL, ENOSPC), + SD_BUS_ERROR_MAP(BUS_ERROR_FILE_DESCRIPTOR_STORE_DISABLED, + EHOSTDOWN), SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_MACHINE, ENXIO), SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_IMAGE, ENOENT), diff --git a/src/libsystemd/sd-bus/bus-common-errors.h b/src/libsystemd/sd-bus/bus-common-errors.h index b6c2e93ea5b..3a0eef49ef5 100644 --- a/src/libsystemd/sd-bus/bus-common-errors.h +++ b/src/libsystemd/sd-bus/bus-common-errors.h @@ -32,6 +32,8 @@ #define BUS_ERROR_UNIT_BUSY "org.freedesktop.systemd1.UnitBusy" #define BUS_ERROR_UNIT_INACTIVE "org.freedesktop.systemd1.UnitInactive" #define BUS_ERROR_FREEZE_CANCELLED "org.freedesktop.systemd1.FreezeCancelled" +#define BUS_ERROR_FILE_DESCRIPTOR_STORE_DISABLED \ + "org.freedesktop.systemd1.FileDescriptorStoreDisabled" #define BUS_ERROR_NO_SUCH_MACHINE "org.freedesktop.machine1.NoSuchMachine" #define BUS_ERROR_NO_SUCH_IMAGE "org.freedesktop.machine1.NoSuchImage"