From c0a1bfacfea9c65ea79fd07682a5b60b5d711a33 Mon Sep 17 00:00:00 2001 From: David Tardon Date: Wed, 9 May 2018 09:35:52 +0200 Subject: [PATCH] systemd-analyze: make dump work for large # of units If there is a large number of units, the size of the generated dump string can overstep DBus message size limit. So let's pass that string via a fd. --- src/analyze/analyze.c | 52 ++++++++++++++++++++++---- src/core/dbus-manager.c | 25 ++++++++++++- src/core/org.freedesktop.systemd1.conf | 4 ++ 3 files changed, 73 insertions(+), 8 deletions(-) diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c index 5e1766b0536..580bc30e121 100644 --- a/src/analyze/analyze.c +++ b/src/analyze/analyze.c @@ -21,6 +21,8 @@ #include "calendarspec.h" #include "def.h" #include "conf-files.h" +#include "copy.h" +#include "fd-util.h" #include "glob-util.h" #include "hashmap.h" #include "locale-util.h" @@ -1279,11 +1281,39 @@ static int dot(int argc, char *argv[], void *userdata) { return 0; } +static int dump_fallback(sd_bus *bus) { + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + const char *text = NULL; + int r; + + assert(bus); + + r = sd_bus_call_method( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "Dump", + &error, + &reply, + NULL); + if (r < 0) + return log_error_errno(r, "Failed to issue method call Dump: %s", bus_error_message(&error, r)); + + r = sd_bus_message_read(reply, "s", &text); + if (r < 0) + return bus_log_parse_error(r); + + fputs(text, stdout); + return 0; +} + static int dump(int argc, char *argv[], void *userdata) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; - const char *text = NULL; + int fd = -1; int r; r = acquire_bus(&bus, NULL); @@ -1292,24 +1322,32 @@ static int dump(int argc, char *argv[], void *userdata) { (void) pager_open(arg_no_pager, false); + if (!sd_bus_can_send(bus, SD_BUS_TYPE_UNIX_FD)) + return dump_fallback(bus); + r = sd_bus_call_method( bus, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", - "Dump", + "DumpByFileDescriptor", &error, &reply, NULL); - if (r < 0) - return log_error_errno(r, "Failed to issue method call: %s", bus_error_message(&error, r)); + if (r < 0) { + /* fall back to Dump if DumpByFileDescriptor is not supported */ + if (!IN_SET(r, -EACCES, -EBADR)) + return log_error_errno(r, "Failed to issue method call DumpByFileDescriptor: %s", bus_error_message(&error, r)); - r = sd_bus_message_read(reply, "s", &text); + return dump_fallback(bus); + } + + r = sd_bus_message_read(reply, "h", &fd); if (r < 0) return bus_log_parse_error(r); - fputs(text, stdout); - return 0; + fflush(stdout); + return copy_bytes(fd, STDOUT_FILENO, (uint64_t) -1, 0); } static int cat_config(int argc, char *argv[], void *userdata) { diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index ced5d06bd4a..8a784747bb4 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -1321,7 +1321,7 @@ static int method_unsubscribe(sd_bus_message *message, void *userdata, sd_bus_er return sd_bus_reply_method_return(message, NULL); } -static int method_dump(sd_bus_message *message, void *userdata, sd_bus_error *error) { +static int dump_impl(sd_bus_message *message, void *userdata, sd_bus_error *error, int (*reply)(sd_bus_message *, char *)) { _cleanup_free_ char *dump = NULL; Manager *m = userdata; int r; @@ -1339,9 +1339,31 @@ static int method_dump(sd_bus_message *message, void *userdata, sd_bus_error *er if (r < 0) return r; + return reply(message, dump); +} + +static int reply_dump(sd_bus_message *message, char *dump) { return sd_bus_reply_method_return(message, "s", dump); } +static int method_dump(sd_bus_message *message, void *userdata, sd_bus_error *error) { + return dump_impl(message, userdata, error, reply_dump); +} + +static int reply_dump_by_fd(sd_bus_message *message, char *dump) { + _cleanup_close_ int fd = -1; + + fd = acquire_data_fd(dump, strlen(dump), 0); + if (fd < 0) + return fd; + + return sd_bus_reply_method_return(message, "h", fd); +} + +static int method_dump_by_fd(sd_bus_message *message, void *userdata, sd_bus_error *error) { + return dump_impl(message, userdata, error, reply_dump_by_fd); +} + static int method_refuse_snapshot(sd_bus_message *message, void *userdata, sd_bus_error *error) { return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Support for snapshots has been removed."); } @@ -2598,6 +2620,7 @@ const sd_bus_vtable bus_manager_vtable[] = { SD_BUS_METHOD("Subscribe", NULL, NULL, method_subscribe, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("Unsubscribe", NULL, NULL, method_unsubscribe, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("Dump", NULL, "s", method_dump, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("DumpByFileDescriptor", NULL, "h", method_dump_by_fd, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("CreateSnapshot", "sb", "o", method_refuse_snapshot, SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_HIDDEN), SD_BUS_METHOD("RemoveSnapshot", "s", NULL, method_refuse_snapshot, SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_HIDDEN), SD_BUS_METHOD("Reload", NULL, NULL, method_reload, SD_BUS_VTABLE_UNPRIVILEGED), diff --git a/src/core/org.freedesktop.systemd1.conf b/src/core/org.freedesktop.systemd1.conf index 0114128a573..415b3f5d84f 100644 --- a/src/core/org.freedesktop.systemd1.conf +++ b/src/core/org.freedesktop.systemd1.conf @@ -116,6 +116,10 @@ send_interface="org.freedesktop.systemd1.Manager" send_member="Dump"/> + + -- 2.47.3