/* SPDX-License-Identifier: LGPL-2.1+ */ #include "bus-error.h" #include "bus-locator.h" #include "pretty-print.h" #include "syslog-util.h" #include "systemctl-log-setting.h" #include "systemctl-util.h" #include "systemctl.h" static void give_log_control1_hint(const char *name) { _cleanup_free_ char *link = NULL; if (arg_quiet) return; (void) terminal_urlify_man("org.freedesktop.LogControl1", "5", &link); log_notice("Hint: the service must declare BusName= and implement the appropriate D-Bus interface.\n" " See the %s for details.", link ?: "org.freedesktop.LogControl1(5) man page"); } static int log_setting_internal(sd_bus *bus, const BusLocator* bloc, const char *verb, const char *value) { assert(bus); assert(STR_IN_SET(verb, "log-level", "log-target", "service-log-level", "service-log-target")); _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; bool level = endswith(verb, "log-level"); int r; if (value) { if (level) { if (log_level_from_string(value) < 0) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "\"%s\" is not a valid log level.", value); } r = bus_set_property(bus, bloc, level ? "LogLevel" : "LogTarget", &error, "s", value); if (r >= 0) return 0; log_error_errno(r, "Failed to set log %s of %s to %s: %s", level ? "level" : "target", bloc->destination, value, bus_error_message(&error, r)); } else { _cleanup_free_ char *t = NULL; r = bus_get_property_string(bus, bloc, level ? "LogLevel" : "LogTarget", &error, &t); if (r >= 0) { puts(t); return 0; } log_error_errno(r, "Failed to get log %s of %s: %s", level ? "level" : "target", bloc->destination, bus_error_message(&error, r)); } if (sd_bus_error_has_names(&error, SD_BUS_ERROR_UNKNOWN_METHOD, SD_BUS_ERROR_UNKNOWN_OBJECT, SD_BUS_ERROR_UNKNOWN_INTERFACE, SD_BUS_ERROR_UNKNOWN_PROPERTY)) give_log_control1_hint(bloc->destination); return r; } int log_setting(int argc, char *argv[], void *userdata) { sd_bus *bus; int r; assert(argc >= 1 && argc <= 2); r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) return r; return log_setting_internal(bus, bus_systemd_mgr, argv[0], argv[1]); } static int service_name_to_dbus(sd_bus *bus, const char *name, char **ret_dbus_name) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_free_ char *bus_name = NULL; int r; /* First, look for the BusName= property */ _cleanup_free_ char *dbus_path = unit_dbus_path_from_name(name); if (!dbus_path) return log_oom(); r = sd_bus_get_property_string( bus, "org.freedesktop.systemd1", dbus_path, "org.freedesktop.systemd1.Service", "BusName", &error, &bus_name); if (r < 0) return log_error_errno(r, "Failed to obtain BusName= property of %s: %s", name, bus_error_message(&error, r)); if (isempty(bus_name)) { log_error("Unit %s doesn't declare BusName=.", name); give_log_control1_hint(name); return -ENOLINK; } *ret_dbus_name = TAKE_PTR(bus_name); return 0; } int service_log_setting(int argc, char *argv[], void *userdata) { sd_bus *bus; _cleanup_free_ char *unit = NULL, *dbus_name = NULL; int r; assert(argc >= 2 && argc <= 3); r = acquire_bus(BUS_FULL, &bus); if (r < 0) return r; r = unit_name_mangle_with_suffix(argv[1], argv[0], arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN, ".service", &unit); if (r < 0) return log_error_errno(r, "Failed to mangle unit name: %m"); r = service_name_to_dbus(bus, unit, &dbus_name); if (r < 0) return r; const BusLocator bloc = { .destination = dbus_name, .path = "/org/freedesktop/LogControl1", .interface = "org.freedesktop.LogControl1", }; return log_setting_internal(bus, &bloc, argv[0], argv[2]); }