summary |
shortlog |
log |
commit | commitdiff |
tree
raw |
patch |
inline | side by side (from parent 1:
3b0810c)
As described in
https://bugs.freedesktop.org/show_bug.cgi?id=50184
the journal currently doesn't set fields such as _SYSTEMD_UNIT
properly for messages coming from processes that have already
terminated. This means among other things that "systemctl status" may
not show some of the output of services that wrote messages just
before they exited.
This patch fixes this by having processes that log to the journal
write their unit identifier to journald when the connection to
/run/systemd/journal/stdout is opened. Journald stores the unit ID
and uses it to fill in _SYSTEMD_UNIT when it cannot be obtained
normally (i.e. from the cgroup). To prevent impersonating another
unit, this information is only used when the caller is root.
This doesn't fix the general problem of getting metadata about
messages from terminated processes (which requires some kernel
support), but it allows "systemctl status" and similar queries to do
the Right Thing for units that log via stdout/stderr.
-static int connect_logger_as(const ExecContext *context, ExecOutput output, const char *ident, int nfd) {
+static int connect_logger_as(const ExecContext *context, ExecOutput output, const char *ident, const char *unit_id, int nfd) {
int fd, r;
union sockaddr_union sa;
int fd, r;
union sockaddr_union sa;
"%i\n"
"%i\n",
context->syslog_identifier ? context->syslog_identifier : ident,
"%i\n"
"%i\n",
context->syslog_identifier ? context->syslog_identifier : ident,
context->syslog_priority,
!!context->syslog_level_prefix,
output == EXEC_OUTPUT_SYSLOG || output == EXEC_OUTPUT_SYSLOG_AND_CONSOLE,
context->syslog_priority,
!!context->syslog_level_prefix,
output == EXEC_OUTPUT_SYSLOG || output == EXEC_OUTPUT_SYSLOG_AND_CONSOLE,
-static int setup_output(const ExecContext *context, int socket_fd, const char *ident, bool apply_tty_stdin) {
+static int setup_output(const ExecContext *context, int socket_fd, const char *ident, const char *unit_id, bool apply_tty_stdin) {
ExecOutput o;
ExecInput i;
ExecOutput o;
ExecInput i;
case EXEC_OUTPUT_KMSG_AND_CONSOLE:
case EXEC_OUTPUT_JOURNAL:
case EXEC_OUTPUT_JOURNAL_AND_CONSOLE:
case EXEC_OUTPUT_KMSG_AND_CONSOLE:
case EXEC_OUTPUT_JOURNAL:
case EXEC_OUTPUT_JOURNAL_AND_CONSOLE:
- return connect_logger_as(context, o, ident, STDOUT_FILENO);
+ return connect_logger_as(context, o, ident, unit_id, STDOUT_FILENO);
case EXEC_OUTPUT_SOCKET:
assert(socket_fd >= 0);
case EXEC_OUTPUT_SOCKET:
assert(socket_fd >= 0);
-static int setup_error(const ExecContext *context, int socket_fd, const char *ident, bool apply_tty_stdin) {
+static int setup_error(const ExecContext *context, int socket_fd, const char *ident, const char *unit_id, bool apply_tty_stdin) {
ExecOutput o, e;
ExecInput i;
ExecOutput o, e;
ExecInput i;
case EXEC_OUTPUT_KMSG_AND_CONSOLE:
case EXEC_OUTPUT_JOURNAL:
case EXEC_OUTPUT_JOURNAL_AND_CONSOLE:
case EXEC_OUTPUT_KMSG_AND_CONSOLE:
case EXEC_OUTPUT_JOURNAL:
case EXEC_OUTPUT_JOURNAL_AND_CONSOLE:
- return connect_logger_as(context, e, ident, STDERR_FILENO);
+ return connect_logger_as(context, e, ident, unit_id, STDERR_FILENO);
case EXEC_OUTPUT_SOCKET:
assert(socket_fd >= 0);
case EXEC_OUTPUT_SOCKET:
assert(socket_fd >= 0);
CGroupBonding *cgroup_bondings,
CGroupAttribute *cgroup_attributes,
const char *cgroup_suffix,
CGroupBonding *cgroup_bondings,
CGroupAttribute *cgroup_attributes,
const char *cgroup_suffix,
int idle_pipe[2],
pid_t *ret) {
int idle_pipe[2],
pid_t *ret) {
- err = setup_output(context, socket_fd, path_get_file_name(command->path), apply_tty_stdin);
+ err = setup_output(context, socket_fd, path_get_file_name(command->path), unit_id, apply_tty_stdin);
if (err < 0) {
r = EXIT_STDOUT;
goto fail_child;
}
}
if (err < 0) {
r = EXIT_STDOUT;
goto fail_child;
}
}
- err = setup_error(context, socket_fd, path_get_file_name(command->path), apply_tty_stdin);
+ err = setup_error(context, socket_fd, path_get_file_name(command->path), unit_id, apply_tty_stdin);
if (err < 0) {
r = EXIT_STDERR;
goto fail_child;
if (err < 0) {
r = EXIT_STDERR;
goto fail_child;
struct CGroupBonding *cgroup_bondings,
struct CGroupAttribute *cgroup_attributes,
const char *cgroup_suffix,
struct CGroupBonding *cgroup_bondings,
struct CGroupAttribute *cgroup_attributes,
const char *cgroup_suffix,
int pipe_fd[2],
pid_t *ret);
int pipe_fd[2],
pid_t *ret);
UNIT(m)->cgroup_bondings,
UNIT(m)->cgroup_attributes,
NULL,
UNIT(m)->cgroup_bondings,
UNIT(m)->cgroup_attributes,
NULL,
NULL,
&pid)) < 0)
goto fail;
NULL,
&pid)) < 0)
goto fail;
UNIT(s)->cgroup_bondings,
UNIT(s)->cgroup_attributes,
is_control ? "control" : NULL,
UNIT(s)->cgroup_bondings,
UNIT(s)->cgroup_attributes,
is_control ? "control" : NULL,
s->type == SERVICE_IDLE ? UNIT(s)->manager->idle_pipe : NULL,
&pid);
s->type == SERVICE_IDLE ? UNIT(s)->manager->idle_pipe : NULL,
&pid);
UNIT(s)->cgroup_bondings,
UNIT(s)->cgroup_attributes,
NULL,
UNIT(s)->cgroup_bondings,
UNIT(s)->cgroup_attributes,
NULL,
UNIT(s)->cgroup_bondings,
UNIT(s)->cgroup_attributes,
NULL,
UNIT(s)->cgroup_bondings,
UNIT(s)->cgroup_attributes,
NULL,
NULL,
&pid)) < 0)
goto fail;
NULL,
&pid)) < 0)
goto fail;
typedef enum StdoutStreamState {
STDOUT_STREAM_IDENTIFIER,
typedef enum StdoutStreamState {
STDOUT_STREAM_IDENTIFIER,
STDOUT_STREAM_PRIORITY,
STDOUT_STREAM_LEVEL_PREFIX,
STDOUT_STREAM_FORWARD_TO_SYSLOG,
STDOUT_STREAM_PRIORITY,
STDOUT_STREAM_LEVEL_PREFIX,
STDOUT_STREAM_FORWARD_TO_SYSLOG,
int priority;
bool level_prefix:1;
bool forward_to_syslog:1;
int priority;
bool level_prefix:1;
bool forward_to_syslog:1;
struct iovec *iovec, unsigned n, unsigned m,
struct ucred *ucred,
struct timeval *tv,
struct iovec *iovec, unsigned n, unsigned m,
struct ucred *ucred,
struct timeval *tv,
- const char *label, size_t label_len) {
+ const char *label, size_t label_len, const char *unit_id) {
char *pid = NULL, *uid = NULL, *gid = NULL,
*source_time = NULL, *boot_id = NULL, *machine_id = NULL,
char *pid = NULL, *uid = NULL, *gid = NULL,
*source_time = NULL, *boot_id = NULL, *machine_id = NULL,
if (cg_pid_get_unit(ucred->pid, &t) >= 0) {
unit = strappend("_SYSTEMD_UNIT=", t);
free(t);
if (cg_pid_get_unit(ucred->pid, &t) >= 0) {
unit = strappend("_SYSTEMD_UNIT=", t);
free(t);
+ } else if (unit_id)
+ unit = strappend("_SYSTEMD_UNIT=", unit_id);
- if (unit)
- IOVEC_SET_STRING(iovec[n++], unit);
- }
+ if (unit)
+ IOVEC_SET_STRING(iovec[n++], unit);
#ifdef HAVE_SELINUX
if (label) {
#ifdef HAVE_SELINUX
if (label) {
ucred.uid = getuid();
ucred.gid = getgid();
ucred.uid = getuid();
ucred.gid = getgid();
- dispatch_message_real(s, iovec, n, ELEMENTSOF(iovec), &ucred, NULL, NULL, 0);
+ dispatch_message_real(s, iovec, n, ELEMENTSOF(iovec), &ucred, NULL, NULL, 0, NULL);
}
static void dispatch_message(Server *s,
}
static void dispatch_message(Server *s,
struct ucred *ucred,
struct timeval *tv,
const char *label, size_t label_len,
struct ucred *ucred,
struct timeval *tv,
const char *label, size_t label_len,
int priority) {
int rl;
char *path = NULL, *c;
int priority) {
int rl;
char *path = NULL, *c;
- dispatch_message_real(s, iovec, n, m, ucred, tv, label, label_len);
+ dispatch_message_real(s, iovec, n, m, ucred, tv, label, label_len, unit_id);
}
static void forward_syslog_iovec(Server *s, const struct iovec *iovec, unsigned n_iovec, struct ucred *ucred, struct timeval *tv) {
}
static void forward_syslog_iovec(Server *s, const struct iovec *iovec, unsigned n_iovec, struct ucred *ucred, struct timeval *tv) {
if (message)
IOVEC_SET_STRING(iovec[n++], message);
if (message)
IOVEC_SET_STRING(iovec[n++], message);
- dispatch_message(s, iovec, n, ELEMENTSOF(iovec), ucred, tv, label, label_len, priority);
+ dispatch_message(s, iovec, n, ELEMENTSOF(iovec), ucred, tv, label, label_len, NULL, priority);
free(message);
free(identifier);
free(message);
free(identifier);
if (e == p) {
/* Entry separator */
if (e == p) {
/* Entry separator */
- dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, priority);
+ dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, NULL, priority);
n = 0;
priority = LOG_INFO;
n = 0;
priority = LOG_INFO;
forward_console(s, priority, identifier, message, ucred);
}
forward_console(s, priority, identifier, message, ucred);
}
- dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, priority);
+ dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, NULL, priority);
finish:
for (j = 0; j < n; j++) {
finish:
for (j = 0; j < n; j++) {
- dispatch_message(s->server, iovec, n, ELEMENTSOF(iovec), &s->ucred, NULL, label, label_len, priority);
+ dispatch_message(s->server, iovec, n, ELEMENTSOF(iovec), &s->ucred, NULL, label, label_len, s->unit_id, priority);
free(message);
free(syslog_priority);
free(message);
free(syslog_priority);
+ s->state = STDOUT_STREAM_UNIT_ID;
+ return 0;
+
+ case STDOUT_STREAM_UNIT_ID:
+ if (s->ucred.uid == 0) {
+ if (isempty(p))
+ s->unit_id = NULL;
+ else {
+ s->unit_id = strdup(p);
+ if (!s->unit_id) {
+ log_error("Out of memory");
+ return -ENOMEM;
+ }
+ }
+ }
+
s->state = STDOUT_STREAM_PRIORITY;
return 0;
s->state = STDOUT_STREAM_PRIORITY;
return 0;
if (message)
IOVEC_SET_STRING(iovec[n++], message);
if (message)
IOVEC_SET_STRING(iovec[n++], message);
- dispatch_message(s, iovec, n, ELEMENTSOF(iovec), NULL, NULL, NULL, 0, priority);
+ dispatch_message(s, iovec, n, ELEMENTSOF(iovec), NULL, NULL, NULL, 0, NULL, priority);