#include "analyze-calendar.h"
#include "analyze-capability.h"
#include "analyze-cat-config.h"
+#include "analyze-compare-versions.h"
#include "analyze-condition.h"
#include "analyze-critical-chain.h"
#include "analyze-dot.h"
#include "analyze-dump.h"
#include "analyze-exit-status.h"
+#include "analyze-fdstore.h"
#include "analyze-filesystems.h"
#include "analyze-inspect-elf.h"
#include "analyze-log-control.h"
+#include "analyze-malloc.h"
#include "analyze-plot.h"
#include "analyze-security.h"
#include "analyze-service-watchdogs.h"
#include "analyze-timestamp.h"
#include "analyze-unit-files.h"
#include "analyze-unit-paths.h"
-#include "analyze-compare-versions.h"
#include "analyze-verify.h"
+#include "build.h"
#include "bus-error.h"
#include "bus-locator.h"
#include "bus-map-properties.h"
#include "capability-util.h"
#include "conf-files.h"
#include "copy.h"
-#include "def.h"
+#include "constants.h"
#include "exit-status.h"
#include "extract-word.h"
#include "fd-util.h"
#include "time-util.h"
#include "tmpfile-util.h"
#include "unit-name.h"
-#include "util.h"
#include "verb-log-control.h"
#include "verbs.h"
#include "version.h"
PagerFlags arg_pager_flags = 0;
BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
const char *arg_host = NULL;
-LookupScope arg_scope = LOOKUP_SCOPE_SYSTEM;
+RuntimeScope arg_runtime_scope = RUNTIME_SCOPE_SYSTEM;
RecursiveErrors arg_recursive_errors = _RECURSIVE_ERRORS_INVALID;
bool arg_man = true;
bool arg_generators = false;
JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF;
bool arg_quiet = false;
char *arg_profile = NULL;
+bool arg_legend = true;
+bool arg_table = false;
+ImagePolicy *arg_image_policy = NULL;
STATIC_DESTRUCTOR_REGISTER(arg_dot_from_patterns, strv_freep);
STATIC_DESTRUCTOR_REGISTER(arg_dot_to_patterns, strv_freep);
STATIC_DESTRUCTOR_REGISTER(arg_security_policy, freep);
STATIC_DESTRUCTOR_REGISTER(arg_unit, freep);
STATIC_DESTRUCTOR_REGISTER(arg_profile, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep);
int acquire_bus(sd_bus **bus, bool *use_full_bus) {
- bool user = arg_scope != LOOKUP_SCOPE_SYSTEM;
int r;
if (use_full_bus && *use_full_bus) {
- r = bus_connect_transport(arg_transport, arg_host, user, bus);
+ r = bus_connect_transport(arg_transport, arg_host, arg_runtime_scope, bus);
if (IN_SET(r, 0, -EHOSTDOWN))
return r;
*use_full_bus = false;
}
- return bus_connect_transport_systemd(arg_transport, arg_host, user, bus);
+ return bus_connect_transport_systemd(arg_transport, arg_host, arg_runtime_scope, bus);
}
int bus_get_unit_property_strv(sd_bus *bus, const char *path, const char *property, char ***strv) {
"Use 'systemd-analyze timespan \"%s\"' instead?", p);
}
+int dump_fd_reply(sd_bus_message *message) {
+ int fd, r;
+
+ assert(message);
+
+ r = sd_bus_message_read(message, "h", &fd);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ fflush(stdout);
+ r = copy_bytes(fd, STDOUT_FILENO, UINT64_MAX, 0);
+ if (r < 0)
+ return r;
+
+ return 1; /* Success */
+}
+
static int help(int argc, char *argv[], void *userdata) {
_cleanup_free_ char *link = NULL, *dot_link = NULL;
int r;
" timespan SPAN... Validate a time span\n"
" security [UNIT...] Analyze security of unit\n"
" inspect-elf FILE... Parse and print ELF package metadata\n"
+ " malloc [D-BUS SERVICE...] Dump malloc stats of a D-Bus service\n"
+ " fdstore SERVICE... Show file descriptor store contents of service\n"
"\nOptions:\n"
" --recursive-errors=MODE Control which units are verified\n"
" --offline=BOOL Perform a security review on unit file(s)\n"
" --security-policy=PATH Use custom JSON security policy instead\n"
" of built-in one\n"
" --json=pretty|short|off Generate JSON output of the security\n"
- " analysis table\n"
+ " analysis table, or plot's raw time data\n"
" --no-pager Do not pipe output into a pager\n"
+ " --no-legend Disable column headers and hints in plot\n"
+ " with either --table or --json=\n"
" --system Operate on system systemd instance\n"
" --user Operate on user systemd instance\n"
" --global Operate on global user configuration\n"
" specified time\n"
" --profile=name|PATH Include the specified profile in the\n"
" security review of the unit(s)\n"
+ " --table Output plot's raw time data as a table\n"
" -h --help Show this help\n"
" --version Show package version\n"
" -q --quiet Do not emit hints\n"
" --root=PATH Operate on an alternate filesystem root\n"
" --image=PATH Operate on disk image as filesystem root\n"
+ " --image-policy=POLICY Specify disk image dissection policy\n"
"\nSee the %s for details.\n",
program_invocation_short_name,
ansi_highlight(),
ARG_SECURITY_POLICY,
ARG_JSON,
ARG_PROFILE,
+ ARG_TABLE,
+ ARG_NO_LEGEND,
+ ARG_IMAGE_POLICY,
};
static const struct option options[] = {
{ "unit", required_argument, NULL, 'U' },
{ "json", required_argument, NULL, ARG_JSON },
{ "profile", required_argument, NULL, ARG_PROFILE },
+ { "table", optional_argument, NULL, ARG_TABLE },
+ { "no-legend", optional_argument, NULL, ARG_NO_LEGEND },
+ { "image-policy", required_argument, NULL, ARG_IMAGE_POLICY },
{}
};
break;
case ARG_SYSTEM:
- arg_scope = LOOKUP_SCOPE_SYSTEM;
+ arg_runtime_scope = RUNTIME_SCOPE_SYSTEM;
break;
case ARG_USER:
- arg_scope = LOOKUP_SCOPE_USER;
+ arg_runtime_scope = RUNTIME_SCOPE_USER;
break;
case ARG_GLOBAL:
- arg_scope = LOOKUP_SCOPE_GLOBAL;
+ arg_runtime_scope = RUNTIME_SCOPE_GLOBAL;
break;
case ARG_ORDER:
r = safe_atou(optarg, &arg_iterations);
if (r < 0)
return log_error_errno(r, "Failed to parse iterations: %s", optarg);
-
break;
case ARG_BASE_TIME:
r = parse_timestamp(optarg, &arg_base_time);
if (r < 0)
return log_error_errno(r, "Failed to parse --base-time= parameter: %s", optarg);
-
break;
case ARG_PROFILE:
free_and_replace(arg_unit, mangled);
break;
}
+
+ case ARG_TABLE:
+ arg_table = true;
+ break;
+
+ case ARG_NO_LEGEND:
+ arg_legend = false;
+ break;
+
+ case ARG_IMAGE_POLICY: {
+ _cleanup_(image_policy_freep) ImagePolicy *p = NULL;
+
+ r = image_policy_from_string(optarg, &p);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse image policy: %s", optarg);
+
+ image_policy_free(arg_image_policy);
+ arg_image_policy = TAKE_PTR(p);
+ break;
+ }
+
case '?':
return -EINVAL;
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Option --offline= is only supported for security right now.");
- if (arg_json_format_flags != JSON_FORMAT_OFF && !STRPTR_IN_SET(argv[optind], "security", "inspect-elf"))
+ if (arg_json_format_flags != JSON_FORMAT_OFF && !STRPTR_IN_SET(argv[optind], "security", "inspect-elf", "plot", "fdstore"))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "Option --json= is only supported for security and inspect-elf right now.");
+ "Option --json= is only supported for security, inspect-elf, plot, and fdstore right now.");
if (arg_threshold != 100 && !streq_ptr(argv[optind], "security"))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Option --threshold= is only supported for security right now.");
- if (arg_scope == LOOKUP_SCOPE_GLOBAL &&
+ if (arg_runtime_scope == RUNTIME_SCOPE_GLOBAL &&
!STR_IN_SET(argv[optind] ?: "time", "dot", "unit-paths", "verify"))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Option --global only makes sense with verbs dot, unit-paths, verify.");
- if (streq_ptr(argv[optind], "cat-config") && arg_scope == LOOKUP_SCOPE_USER)
+ if (streq_ptr(argv[optind], "cat-config") && arg_runtime_scope == RUNTIME_SCOPE_USER)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Option --user is not supported for cat-config right now.");
if (streq_ptr(argv[optind], "condition") && arg_unit && optind < argc - 1)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No conditions can be passed if --unit= is used.");
+ if ((!arg_legend && !streq_ptr(argv[optind], "plot")) ||
+ (streq_ptr(argv[optind], "plot") && !arg_legend && !arg_table && FLAGS_SET(arg_json_format_flags, JSON_FORMAT_OFF)))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Option --no-legend is only supported for plot with either --table or --json=.");
+
+ if (arg_table && !streq_ptr(argv[optind], "plot"))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Option --table is only supported for plot right now.");
+
+ if (arg_table && !FLAGS_SET(arg_json_format_flags, JSON_FORMAT_OFF))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--table and --json= are mutually exclusive.");
+
return 1; /* work to do */
}
{ "timespan", 2, VERB_ANY, 0, verb_timespan },
{ "security", VERB_ANY, VERB_ANY, 0, verb_security },
{ "inspect-elf", 2, VERB_ANY, 0, verb_elf_inspection },
+ { "malloc", VERB_ANY, VERB_ANY, 0, verb_malloc },
+ { "fdstore", 2, VERB_ANY, 0, verb_fdstore },
{}
};
r = mount_image_privately_interactively(
arg_image,
+ arg_image_policy,
DISSECT_IMAGE_GENERIC_ROOT |
DISSECT_IMAGE_RELAX_VAR_CHECK |
DISSECT_IMAGE_READ_ONLY,
&unlink_dir,
+ /* ret_dir_fd= */ NULL,
&loop_device);
if (r < 0)
return r;