diff --git a/shell-completion/bash/systemd-analyze b/shell-completion/bash/systemd-analyze index d3d3fe4c63..3eeeffd241 100644 --- a/shell-completion/bash/systemd-analyze +++ b/shell-completion/bash/systemd-analyze @@ -62,8 +62,9 @@ _systemd_analyze() { local -A OPTS=( [STANDALONE]='-h --help --version --system --user --global --order --require --no-pager - --man=no --generators=yes -q --quiet' - [ARG]='-H --host -M --machine --fuzz --from-pattern --to-pattern --root --debugger' + --man=no --generators=yes -q --quiet' + [ARG]='-H --host -M --machine --fuzz --from-pattern --to-pattern --root --debugger + -A --debugger-arguments' ) local -A VERBS=( @@ -116,6 +117,12 @@ _systemd_analyze() { --machine|-M) comps=$( __get_machines ) ;; + --debugger) + comps="gdb lldb" + ;; + *) + return 0 + ;; esac COMPREPLY=( $(compgen -W '$comps' -- "$cur") ) return 0 diff --git a/src/analyze/analyze-unit-gdb.c b/src/analyze/analyze-unit-gdb.c index 92b8a5cb5b..7c5da0b948 100644 --- a/src/analyze/analyze-unit-gdb.c +++ b/src/analyze/analyze-unit-gdb.c @@ -32,7 +32,7 @@ int verb_unit_gdb(int argc, char *argv[], void *userdata) { int r; if (arg_transport != BUS_TRANSPORT_LOCAL) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot spawn a debugger for a remote service"); + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot spawn a debugger for a remote service."); r = unit_name_mangle_with_suffix(argv[1], "as unit", UNIT_NAME_MANGLE_WARN, ".service", &unit); if (r < 0) @@ -63,42 +63,49 @@ int verb_unit_gdb(int argc, char *argv[], void *userdata) { if (r < 0) return log_error_errno(r, "Failed to read the main PID of %s from reply: %m", unit); - if (!arg_debugger) - arg_debugger = secure_getenv("SYSTEMD_DEBUGGER") ?: "gdb"; + if (!arg_debugger) { + arg_debugger = strdup(secure_getenv("SYSTEMD_DEBUGGER") ?: "gdb"); + if (!arg_debugger) + return log_oom(); + } + + if (!STR_IN_SET(arg_debugger, "gdb", "lldb")) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "The debugger must be either 'gdb' or 'lldb'."); _cleanup_strv_free_ char **debugger_call = NULL; r = strv_extend(&debugger_call, arg_debugger); if (r < 0) return log_oom(); - if (!STR_IN_SET(arg_debugger, "gdb", "lldb")) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "The debugger must be either 'gdb' or 'lldb'"); - if (streq(arg_debugger, "gdb")) { r = strv_extendf(&debugger_call, "--pid=" PID_FMT, pid); if (r < 0) return log_oom(); - } - if (streq(arg_debugger, "lldb")) { - r = strv_extendf(&debugger_call, "--attach-pid=" PID_FMT, pid); - if (r < 0) - return log_oom(); - } - - if (arg_root) { - if (streq(arg_debugger, "gdb")) { + if (arg_root) { _cleanup_free_ char *sysroot_cmd = strjoin("set sysroot ", arg_root); r = strv_extend_many(&debugger_call, "-iex", sysroot_cmd); if (r < 0) return log_oom(); - } else if (streq(arg_debugger, "lldb")) { + } + + } else if (streq(arg_debugger, "lldb")) { + r = strv_extendf(&debugger_call, "--attach-pid=" PID_FMT, pid); + if (r < 0) + return log_oom(); + + if (arg_root) { _cleanup_free_ char *sysroot_cmd = strjoin("platform select --sysroot ", arg_root, " host"); r = strv_extend_many(&debugger_call, "-O", sysroot_cmd); if (r < 0) return log_oom(); } - } + } else + assert_not_reached(); + + r = strv_extend_strv(&debugger_call, arg_debugger_args, /* filter_duplicates = */ false); + if (r < 0) + return log_oom(); /* Don't interfere with debugger and its handling of SIGINT. */ (void) ignore_signals(SIGINT); diff --git a/src/analyze/analyze-unit-shell.c b/src/analyze/analyze-unit-shell.c index 6d241eb6e1..43eb65932e 100644 --- a/src/analyze/analyze-unit-shell.c +++ b/src/analyze/analyze-unit-shell.c @@ -28,7 +28,7 @@ int verb_unit_shell(int argc, char *argv[], void *userdata) { int r; if (arg_transport != BUS_TRANSPORT_LOCAL) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot spawn a unit shell for a remote service"); + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot spawn a unit shell for a remote service."); r = unit_name_mangle_with_suffix(argv[1], "as unit", UNIT_NAME_MANGLE_WARN, ".service", &unit); if (r < 0) @@ -95,23 +95,22 @@ int verb_unit_shell(int argc, char *argv[], void *userdata) { if (r == 0) { if (args) { - r = execvp(args[0], args); - if (r < 0) - log_error_errno(errno, "Failed to execute '%s': %m", *args); + (void) execvp(args[0], args); + log_error_errno(errno, "Failed to execute '%s': %m", *args); } else { - r = execl(DEFAULT_USER_SHELL, "-" DEFAULT_USER_SHELL_NAME, NULL); - if (r < 0) - log_debug_errno(errno, "Failed to execute '" DEFAULT_USER_SHELL "', ignoring: %m"); + (void) execl(DEFAULT_USER_SHELL, "-" DEFAULT_USER_SHELL_NAME, NULL); + log_debug_errno(errno, "Failed to execute '" DEFAULT_USER_SHELL "', ignoring: %m"); + if (!streq(DEFAULT_USER_SHELL, "/bin/bash")) { - r = execl("/bin/bash", "-bash", NULL); - if (r < 0) - log_debug_errno(errno, "Failed to execute '/bin/bash', ignoring: %m"); + (void) execl("/bin/bash", "-bash", NULL); + log_debug_errno(errno, "Failed to execute '/bin/bash', ignoring: %m"); } + if (!streq(DEFAULT_USER_SHELL, "/bin/sh")) { - r = execl("/bin/sh", "-sh", NULL); - if (r < 0) - log_debug_errno(errno, "Failed to execute '/bin/sh', ignoring: %m"); + (void) execl("/bin/sh", "-sh", NULL); + log_debug_errno(errno, "Failed to execute '/bin/sh', ignoring: %m"); } + log_error_errno(errno, "Failed to execute '" DEFAULT_USER_SHELL "', '/bin/bash', and '/bin/sh': %m"); } _exit(EXIT_FAILURE); diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c index 762317a653..d76c09b520 100644 --- a/src/analyze/analyze.c +++ b/src/analyze/analyze.c @@ -81,8 +81,8 @@ usec_t arg_fuzz = 0; PagerFlags arg_pager_flags = 0; CatFlags arg_cat_flags = 0; BusTransport arg_transport = BUS_TRANSPORT_LOCAL; -const char *arg_debugger = NULL; -static char **arg_debugger_args = NULL; +char *arg_debugger = NULL; +char **arg_debugger_args = NULL; const char *arg_host = NULL; RuntimeScope arg_runtime_scope = RUNTIME_SCOPE_SYSTEM; RecursiveErrors arg_recursive_errors = _RECURSIVE_ERRORS_INVALID; @@ -109,6 +109,8 @@ char *arg_drm_device_path = NULL; STATIC_DESTRUCTOR_REGISTER(arg_dot_from_patterns, strv_freep); STATIC_DESTRUCTOR_REGISTER(arg_dot_to_patterns, strv_freep); +STATIC_DESTRUCTOR_REGISTER(arg_debugger, freep); +STATIC_DESTRUCTOR_REGISTER(arg_debugger_args, strv_freep); STATIC_DESTRUCTOR_REGISTER(arg_root, freep); STATIC_DESTRUCTOR_REGISTER(arg_image, freep); STATIC_DESTRUCTOR_REGISTER(arg_security_policy, freep); @@ -665,7 +667,9 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_DEBUGGER: - arg_debugger = strdup(optarg); + r = free_and_strdup_warn(&arg_debugger, optarg); + if (r < 0) + return r; break; case 'A': { diff --git a/src/analyze/analyze.h b/src/analyze/analyze.h index 1d489b723e..d5b7bfcb82 100644 --- a/src/analyze/analyze.h +++ b/src/analyze/analyze.h @@ -24,7 +24,8 @@ extern PagerFlags arg_pager_flags; extern CatFlags arg_cat_flags; extern BusTransport arg_transport; extern const char *arg_host; -extern const char *arg_debugger; +extern char *arg_debugger; +extern char **arg_debugger_args; extern RuntimeScope arg_runtime_scope; extern RecursiveErrors arg_recursive_errors; extern bool arg_man;