]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/journald-console.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / journal / journald-console.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
3b7124a8
LP
2/***
3 This file is part of systemd.
4
5 Copyright 2011 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
21#include <fcntl.h>
4871690d 22#include <sys/socket.h>
cf0fbc49 23#include <time.h>
3b7124a8 24
b5efdb8a 25#include "alloc-util.h"
6bedfcbb 26#include "fd-util.h"
ad79565d 27#include "fileio.h"
f97b34a6 28#include "format-util.h"
afc5dbf3 29#include "io-util.h"
6bedfcbb
LP
30#include "journald-console.h"
31#include "journald-server.h"
32#include "parse-util.h"
0b452006 33#include "process-util.h"
15a5e950 34#include "stdio-util.h"
288a74cc 35#include "terminal-util.h"
3b7124a8 36
ad79565d
UTL
37static bool prefix_timestamp(void) {
38
39 static int cached_printk_time = -1;
40
41 if (_unlikely_(cached_printk_time < 0)) {
42 _cleanup_free_ char *p = NULL;
43
44 cached_printk_time =
45 read_one_line_file("/sys/module/printk/parameters/time", &p) >= 0
46 && parse_boolean(p) > 0;
47 }
48
49 return cached_printk_time;
50}
51
3b7124a8
LP
52void server_forward_console(
53 Server *s,
54 int priority,
55 const char *identifier,
56 const char *message,
3b3154df 57 const struct ucred *ucred) {
3b7124a8 58
ad79565d 59 struct iovec iovec[5];
ad79565d 60 struct timespec ts;
5ffa8c81
ZJS
61 char tbuf[sizeof("[] ")-1 + DECIMAL_STR_MAX(ts.tv_sec) + DECIMAL_STR_MAX(ts.tv_nsec)-3 + 1];
62 char header_pid[sizeof("[]: ")-1 + DECIMAL_STR_MAX(pid_t)];
fb472900 63 _cleanup_free_ char *ident_buf = NULL;
e6a7ec4b 64 _cleanup_close_ int fd = -1;
3b7124a8 65 const char *tty;
e6a7ec4b 66 int n = 0;
3b7124a8
LP
67
68 assert(s);
69 assert(message);
70
71 if (LOG_PRI(priority) > s->max_level_console)
72 return;
73
ad79565d
UTL
74 /* First: timestamp */
75 if (prefix_timestamp()) {
76 assert_se(clock_gettime(CLOCK_MONOTONIC, &ts) == 0);
b123d975 77 xsprintf(tbuf, "[%5"PRI_TIME".%06"PRI_NSEC"] ",
de0671ee 78 ts.tv_sec,
b123d975 79 (nsec_t)ts.tv_nsec / 1000);
e6a7ec4b
LP
80
81 iovec[n++] = IOVEC_MAKE_STRING(tbuf);
ad79565d
UTL
82 }
83
84 /* Second: identifier and PID */
3b7124a8
LP
85 if (ucred) {
86 if (!identifier) {
87 get_process_comm(ucred->pid, &ident_buf);
88 identifier = ident_buf;
89 }
90
5ffa8c81 91 xsprintf(header_pid, "["PID_FMT"]: ", ucred->pid);
3b7124a8
LP
92
93 if (identifier)
e6a7ec4b 94 iovec[n++] = IOVEC_MAKE_STRING(identifier);
3b7124a8 95
e6a7ec4b 96 iovec[n++] = IOVEC_MAKE_STRING(header_pid);
3b7124a8 97 } else if (identifier) {
e6a7ec4b
LP
98 iovec[n++] = IOVEC_MAKE_STRING(identifier);
99 iovec[n++] = IOVEC_MAKE_STRING(": ");
3b7124a8
LP
100 }
101
ad79565d 102 /* Fourth: message */
e6a7ec4b
LP
103 iovec[n++] = IOVEC_MAKE_STRING(message);
104 iovec[n++] = IOVEC_MAKE_STRING("\n");
3b7124a8 105
e6a7ec4b 106 tty = s->tty_path ?: "/dev/console";
3b7124a8 107
8ae2c630
LP
108 /* Before you ask: yes, on purpose we open/close the console for each log line we write individually. This is a
109 * good strategy to avoid journald getting killed by the kernel's SAK concept (it doesn't fix this entirely,
110 * but minimizes the time window the kernel might end up killing journald due to SAK). It also makes things
111 * easier for us so that we don't have to recover from hangups and suchlike triggered on the console. */
112
3b7124a8
LP
113 fd = open_terminal(tty, O_WRONLY|O_NOCTTY|O_CLOEXEC);
114 if (fd < 0) {
709f6e46 115 log_debug_errno(fd, "Failed to open %s for logging: %m", tty);
fb472900 116 return;
3b7124a8
LP
117 }
118
119 if (writev(fd, iovec, n) < 0)
56f64d95 120 log_debug_errno(errno, "Failed to write to %s for logging: %m", tty);
3b7124a8 121}