]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/journald-console.c
tree-wide: drop 'This file is part of systemd' blurb
[thirdparty/systemd.git] / src / journal / journald-console.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
3b7124a8 2/***
3b7124a8 3 Copyright 2011 Lennart Poettering
3b7124a8
LP
4***/
5
6#include <fcntl.h>
4871690d 7#include <sys/socket.h>
cf0fbc49 8#include <time.h>
3b7124a8 9
b5efdb8a 10#include "alloc-util.h"
6bedfcbb 11#include "fd-util.h"
ad79565d 12#include "fileio.h"
f97b34a6 13#include "format-util.h"
afc5dbf3 14#include "io-util.h"
6bedfcbb
LP
15#include "journald-console.h"
16#include "journald-server.h"
17#include "parse-util.h"
0b452006 18#include "process-util.h"
15a5e950 19#include "stdio-util.h"
288a74cc 20#include "terminal-util.h"
3b7124a8 21
ad79565d
UTL
22static bool prefix_timestamp(void) {
23
24 static int cached_printk_time = -1;
25
26 if (_unlikely_(cached_printk_time < 0)) {
27 _cleanup_free_ char *p = NULL;
28
29 cached_printk_time =
30 read_one_line_file("/sys/module/printk/parameters/time", &p) >= 0
31 && parse_boolean(p) > 0;
32 }
33
34 return cached_printk_time;
35}
36
3b7124a8
LP
37void server_forward_console(
38 Server *s,
39 int priority,
40 const char *identifier,
41 const char *message,
3b3154df 42 const struct ucred *ucred) {
3b7124a8 43
ad79565d 44 struct iovec iovec[5];
ad79565d 45 struct timespec ts;
fbd0b64f
LP
46 char tbuf[STRLEN("[] ") + DECIMAL_STR_MAX(ts.tv_sec) + DECIMAL_STR_MAX(ts.tv_nsec)-3 + 1];
47 char header_pid[STRLEN("[]: ") + DECIMAL_STR_MAX(pid_t)];
fb472900 48 _cleanup_free_ char *ident_buf = NULL;
e6a7ec4b 49 _cleanup_close_ int fd = -1;
3b7124a8 50 const char *tty;
e6a7ec4b 51 int n = 0;
3b7124a8
LP
52
53 assert(s);
54 assert(message);
55
56 if (LOG_PRI(priority) > s->max_level_console)
57 return;
58
ad79565d
UTL
59 /* First: timestamp */
60 if (prefix_timestamp()) {
61 assert_se(clock_gettime(CLOCK_MONOTONIC, &ts) == 0);
b123d975 62 xsprintf(tbuf, "[%5"PRI_TIME".%06"PRI_NSEC"] ",
de0671ee 63 ts.tv_sec,
b123d975 64 (nsec_t)ts.tv_nsec / 1000);
e6a7ec4b
LP
65
66 iovec[n++] = IOVEC_MAKE_STRING(tbuf);
ad79565d
UTL
67 }
68
69 /* Second: identifier and PID */
3b7124a8
LP
70 if (ucred) {
71 if (!identifier) {
72 get_process_comm(ucred->pid, &ident_buf);
73 identifier = ident_buf;
74 }
75
5ffa8c81 76 xsprintf(header_pid, "["PID_FMT"]: ", ucred->pid);
3b7124a8
LP
77
78 if (identifier)
e6a7ec4b 79 iovec[n++] = IOVEC_MAKE_STRING(identifier);
3b7124a8 80
e6a7ec4b 81 iovec[n++] = IOVEC_MAKE_STRING(header_pid);
3b7124a8 82 } else if (identifier) {
e6a7ec4b
LP
83 iovec[n++] = IOVEC_MAKE_STRING(identifier);
84 iovec[n++] = IOVEC_MAKE_STRING(": ");
3b7124a8
LP
85 }
86
ad79565d 87 /* Fourth: message */
e6a7ec4b
LP
88 iovec[n++] = IOVEC_MAKE_STRING(message);
89 iovec[n++] = IOVEC_MAKE_STRING("\n");
3b7124a8 90
e6a7ec4b 91 tty = s->tty_path ?: "/dev/console";
3b7124a8 92
8ae2c630
LP
93 /* Before you ask: yes, on purpose we open/close the console for each log line we write individually. This is a
94 * good strategy to avoid journald getting killed by the kernel's SAK concept (it doesn't fix this entirely,
95 * but minimizes the time window the kernel might end up killing journald due to SAK). It also makes things
96 * easier for us so that we don't have to recover from hangups and suchlike triggered on the console. */
97
3b7124a8
LP
98 fd = open_terminal(tty, O_WRONLY|O_NOCTTY|O_CLOEXEC);
99 if (fd < 0) {
709f6e46 100 log_debug_errno(fd, "Failed to open %s for logging: %m", tty);
fb472900 101 return;
3b7124a8
LP
102 }
103
104 if (writev(fd, iovec, n) < 0)
56f64d95 105 log_debug_errno(errno, "Failed to write to %s for logging: %m", tty);
3b7124a8 106}