Merge pull request #31351 from YHNdnzj/exit-status-no-executable

core/exec-invoke: record correct exit status when failed to locate executable
This commit is contained in:
Luca Boccassi 2024-02-19 19:17:31 +00:00 committed by GitHub
commit f927b872d6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 72 additions and 75 deletions

View file

@ -4792,26 +4792,16 @@ int exec_invoke(
_cleanup_close_ int executable_fd = -EBADF;
r = find_executable_full(command->path, /* root= */ NULL, context->exec_search_path, false, &executable, &executable_fd);
if (r < 0) {
if (r != -ENOMEM && (command->flags & EXEC_COMMAND_IGNORE_FAILURE)) {
log_exec_struct_errno(context, params, LOG_INFO, r,
"MESSAGE_ID=" SD_MESSAGE_SPAWN_FAILED_STR,
LOG_EXEC_INVOCATION_ID(params),
LOG_EXEC_MESSAGE(params,
"Executable %s missing, skipping: %m",
command->path),
"EXECUTABLE=%s", command->path);
*exit_status = EXIT_SUCCESS;
return 0;
}
*exit_status = EXIT_EXEC;
return log_exec_struct_errno(context, params, LOG_INFO, r,
"MESSAGE_ID=" SD_MESSAGE_SPAWN_FAILED_STR,
LOG_EXEC_INVOCATION_ID(params),
LOG_EXEC_MESSAGE(params,
"Failed to locate executable %s: %m",
command->path),
"EXECUTABLE=%s", command->path);
log_exec_struct_errno(context, params, LOG_NOTICE, r,
"MESSAGE_ID=" SD_MESSAGE_SPAWN_FAILED_STR,
LOG_EXEC_MESSAGE(params,
"Unable to locate executable '%s': %m",
command->path),
"EXECUTABLE=%s", command->path);
/* If the error will be ignored by manager, tune down the log level here. Missing executable
* is very much expected in this case. */
return r != -ENOMEM && FLAGS_SET(command->flags, EXEC_COMMAND_IGNORE_FAILURE) ? 1 : r;
}
r = add_shifted_fd(keep_fds, ELEMENTSOF(keep_fds), &n_keep_fds, &executable_fd);

View file

@ -616,23 +616,26 @@ bool exec_needs_ipc_namespace(const ExecContext *context);
#define LOG_EXEC_INVOCATION_ID_FIELD_FORMAT(ep) \
((ep)->runtime_scope == RUNTIME_SCOPE_USER ? "USER_INVOCATION_ID=%s" : "INVOCATION_ID=%s")
#define log_exec_full_errno_zerook(ec, ep, level, error, ...) \
({ \
const ExecContext *_c = (ec); \
const ExecParameters *_p = (ep); \
const int _l = (level); \
bool _do_log = !(log_get_max_level() < LOG_PRI(_l) || \
!(_c->log_level_max < 0 || \
_c->log_level_max >= LOG_PRI(_l))); \
LOG_CONTEXT_PUSH_IOV(_c->log_extra_fields, \
_c->n_log_extra_fields); \
!_do_log ? -ERRNO_VALUE(error) : \
log_object_internal(_l, error, PROJECT_FILE, \
__LINE__, __func__, \
LOG_EXEC_ID_FIELD(_p), \
_p->unit_id, \
LOG_EXEC_INVOCATION_ID_FIELD(_p), \
_p->invocation_id_string, ##__VA_ARGS__); \
/* Like LOG_MESSAGE(), but with the unit name prefixed. */
#define LOG_EXEC_MESSAGE(ep, fmt, ...) LOG_MESSAGE("%s: " fmt, (ep)->unit_id, ##__VA_ARGS__)
#define LOG_EXEC_ID(ep) LOG_EXEC_ID_FIELD_FORMAT(ep), (ep)->unit_id
#define LOG_EXEC_INVOCATION_ID(ep) LOG_EXEC_INVOCATION_ID_FIELD_FORMAT(ep), (ep)->invocation_id_string
#define log_exec_full_errno_zerook(ec, ep, level, error, ...) \
({ \
const ExecContext *_c = (ec); \
const ExecParameters *_p = (ep); \
const int _l = (level); \
bool _do_log = _c->log_level_max >= 0 && \
_c->log_level_max < LOG_PRI(_l); \
LOG_CONTEXT_PUSH_IOV(_c->log_extra_fields, \
_c->n_log_extra_fields); \
!_do_log ? -ERRNO_VALUE(error) : \
log_object_internal(_l, error, \
PROJECT_FILE, __LINE__, __func__, \
LOG_EXEC_ID(_p), \
LOG_EXEC_INVOCATION_ID(_p), \
##__VA_ARGS__); \
})
#define log_exec_full_errno(ec, ep, level, error, ...) \
@ -656,48 +659,29 @@ bool exec_needs_ipc_namespace(const ExecContext *context);
#define log_exec_warning_errno(ec, ep, error, ...) log_exec_full_errno(ec, ep, LOG_WARNING, error, __VA_ARGS__)
#define log_exec_error_errno(ec, ep, error, ...) log_exec_full_errno(ec, ep, LOG_ERR, error, __VA_ARGS__)
#define log_exec_struct_errno(ec, ep, level, error, ...) \
({ \
const ExecContext *_c = (ec); \
const ExecParameters *_p = (ep); \
const int _l = (level); \
bool _do_log = !(_c->log_level_max < 0 || \
_c->log_level_max >= LOG_PRI(_l)); \
LOG_CONTEXT_PUSH_IOV(_c->log_extra_fields, \
_c->n_log_extra_fields); \
_do_log ? \
log_struct_errno(_l, error, __VA_ARGS__, LOG_EXEC_ID_FIELD_FORMAT(_p), _p->unit_id) : \
-ERRNO_VALUE(error); \
#define log_exec_struct_errno(ec, ep, level, error, ...) \
({ \
const ExecContext *_c = (ec); \
const ExecParameters *_p = (ep); \
const int _l = (level); \
bool _do_log = _c->log_level_max >= 0 && \
_c->log_level_max < LOG_PRI(_l); \
LOG_CONTEXT_PUSH_IOV(_c->log_extra_fields, \
_c->n_log_extra_fields); \
!_do_log ? -ERRNO_VALUE(error) : \
log_struct_errno(_l, error, \
LOG_EXEC_ID(_p), \
LOG_EXEC_INVOCATION_ID(_p), \
__VA_ARGS__); \
})
#define log_exec_struct(ec, ep, level, ...) log_exec_struct_errno(ec, ep, level, 0, __VA_ARGS__)
#define log_exec_struct_iovec_errno(ec, ep, level, error, iovec, n_iovec) \
({ \
const ExecContext *_c = (ec); \
const ExecParameters *_p = (ep); \
const int _l = (level); \
bool _do_log = !(_c->log_level_max < 0 || \
_c->log_level_max >= LOG_PRI(_l)); \
LOG_CONTEXT_PUSH_IOV(_c->log_extra_fields, \
_c->n_log_extra_fields); \
_do_log ? \
log_struct_iovec_errno(_l, error, iovec, n_iovec) : \
-ERRNO_VALUE(error); \
})
#define log_exec_struct_iovec(ec, ep, level, iovec, n_iovec) log_exec_struct_iovec_errno(ec, ep, level, 0, iovec, n_iovec)
/* Like LOG_MESSAGE(), but with the unit name prefixed. */
#define LOG_EXEC_MESSAGE(ep, fmt, ...) LOG_MESSAGE("%s: " fmt, (ep)->unit_id, ##__VA_ARGS__)
#define LOG_EXEC_ID(ep) LOG_EXEC_ID_FIELD_FORMAT(ep), (ep)->unit_id
#define LOG_EXEC_INVOCATION_ID(ep) LOG_EXEC_INVOCATION_ID_FIELD_FORMAT(ep), (ep)->invocation_id_string
#define _LOG_CONTEXT_PUSH_EXEC(ec, ep, p, c) \
const ExecContext *c = (ec); \
const ExecParameters *p = (ep); \
#define _LOG_CONTEXT_PUSH_EXEC(ec, ep, p, c) \
const ExecContext *c = (ec); \
const ExecParameters *p = (ep); \
LOG_CONTEXT_PUSH_KEY_VALUE(LOG_EXEC_ID_FIELD(p), p->unit_id); \
LOG_CONTEXT_PUSH_KEY_VALUE(LOG_EXEC_INVOCATION_ID_FIELD(p), p->invocation_id_string); \
LOG_CONTEXT_PUSH_KEY_VALUE(LOG_EXEC_INVOCATION_ID_FIELD(p), p->invocation_id_string); \
LOG_CONTEXT_PUSH_IOV(c->log_extra_fields, c->n_log_extra_fields)
#define LOG_CONTEXT_PUSH_EXEC(ec, ep) \

View file

@ -245,12 +245,13 @@ static int run(int argc, char *argv[]) {
log_exec_struct_errno(&context, &params, LOG_ERR, r,
"MESSAGE_ID=" SD_MESSAGE_SPAWN_FAILED_STR,
LOG_EXEC_INVOCATION_ID(&params),
LOG_EXEC_MESSAGE(&params, "Failed at step %s spawning %s: %m",
status, command.path),
"EXECUTABLE=%s", command.path);
} else
assert(exit_status == EXIT_SUCCESS); /* When 'skip' is chosen in the confirm spawn prompt */
/* r == 0: 'skip' is chosen in the confirm spawn prompt
* r > 0: expected/ignored failure, do not log at error level */
assert((r == 0) == (exit_status == EXIT_SUCCESS));
return exit_status;
}

View file

@ -0,0 +1,22 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: LGPL-2.1-or-later
set -eux
set -o pipefail
# shellcheck source=test/units/util.sh
. "$(dirname "$0")"/util.sh
cat >/run/systemd/system/nonexistent-execstart-exit-status.service <<EOF
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=-/foo/bar/not-exist
EOF
systemctl start nonexistent-execstart-exit-status.service
systemctl is-active nonexistent-execstart-exit-status.service
assert_eq "$(systemctl show nonexistent-execstart-exit-status.service -P Result)" "success"
(( $(systemctl show nonexistent-execstart-exit-status.service -P ExecMainStatus) > 0 ))
systemctl stop nonexistent-execstart-exit-status.service
rm /run/systemd/system/nonexistent-execstart-exit-status.service