Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : :
3 : : #include <errno.h>
4 : : #include <fcntl.h>
5 : : #include <inttypes.h>
6 : : #include <limits.h>
7 : : #include <stdarg.h>
8 : : #include <stddef.h>
9 : : #include <stdio.h>
10 : : #include <string.h>
11 : : #include <sys/signalfd.h>
12 : : #include <sys/socket.h>
13 : : #include <sys/time.h>
14 : : #include <sys/uio.h>
15 : : #include <sys/un.h>
16 : : #include <time.h>
17 : : #include <unistd.h>
18 : :
19 : : #include "sd-messages.h"
20 : :
21 : : #include "alloc-util.h"
22 : : #include "errno-util.h"
23 : : #include "fd-util.h"
24 : : #include "format-util.h"
25 : : #include "io-util.h"
26 : : #include "log.h"
27 : : #include "macro.h"
28 : : #include "missing.h"
29 : : #include "parse-util.h"
30 : : #include "proc-cmdline.h"
31 : : #include "process-util.h"
32 : : #include "signal-util.h"
33 : : #include "socket-util.h"
34 : : #include "stdio-util.h"
35 : : #include "string-table.h"
36 : : #include "string-util.h"
37 : : #include "syslog-util.h"
38 : : #include "terminal-util.h"
39 : : #include "time-util.h"
40 : : #include "utf8.h"
41 : :
42 : : #define SNDBUF_SIZE (8*1024*1024)
43 : :
44 : : static LogTarget log_target = LOG_TARGET_CONSOLE;
45 : : static int log_max_level[] = {LOG_INFO, LOG_INFO};
46 : : assert_cc(ELEMENTSOF(log_max_level) == _LOG_REALM_MAX);
47 : : static int log_facility = LOG_DAEMON;
48 : :
49 : : static int console_fd = STDERR_FILENO;
50 : : static int syslog_fd = -1;
51 : : static int kmsg_fd = -1;
52 : : static int journal_fd = -1;
53 : :
54 : : static bool syslog_is_stream = false;
55 : :
56 : : static bool show_color = false;
57 : : static bool show_location = false;
58 : :
59 : : static bool upgrade_syslog_to_journal = false;
60 : : static bool always_reopen_console = false;
61 : : static bool open_when_needed = false;
62 : : static bool prohibit_ipc = false;
63 : :
64 : : /* Akin to glibc's __abort_msg; which is private and we hence cannot
65 : : * use here. */
66 : : static char *log_abort_msg = NULL;
67 : :
68 : : /* An assert to use in logging functions that does not call recursively
69 : : * into our logging functions (since that might lead to a loop). */
70 : : #define assert_raw(expr) \
71 : : do { \
72 : : if (_unlikely_(!(expr))) { \
73 : : fputs(#expr "\n", stderr); \
74 : : abort(); \
75 : : } \
76 : : } while (false)
77 : :
78 : 432 : static void log_close_console(void) {
79 : 432 : console_fd = safe_close_above_stdio(console_fd);
80 : 432 : }
81 : :
82 : 1194 : static int log_open_console(void) {
83 : :
84 [ + - ]: 1194 : if (!always_reopen_console) {
85 : 1194 : console_fd = STDERR_FILENO;
86 : 1194 : return 0;
87 : : }
88 : :
89 [ # # ]: 0 : if (console_fd < 3) {
90 : : int fd;
91 : :
92 : 0 : fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
93 [ # # ]: 0 : if (fd < 0)
94 : 0 : return fd;
95 : :
96 : 0 : console_fd = fd_move_above_stdio(fd);
97 : : }
98 : :
99 : 0 : return 0;
100 : : }
101 : :
102 : 0 : static void log_close_kmsg(void) {
103 : 0 : kmsg_fd = safe_close(kmsg_fd);
104 : 0 : }
105 : :
106 : 4 : static int log_open_kmsg(void) {
107 : :
108 [ - + ]: 4 : if (kmsg_fd >= 0)
109 : 0 : return 0;
110 : :
111 : 4 : kmsg_fd = open("/dev/kmsg", O_WRONLY|O_NOCTTY|O_CLOEXEC);
112 [ + - ]: 4 : if (kmsg_fd < 0)
113 : 4 : return -errno;
114 : :
115 : 0 : kmsg_fd = fd_move_above_stdio(kmsg_fd);
116 : 0 : return 0;
117 : : }
118 : :
119 : 1618 : static void log_close_syslog(void) {
120 : 1618 : syslog_fd = safe_close(syslog_fd);
121 : 1618 : }
122 : :
123 : 404 : static int create_log_socket(int type) {
124 : : struct timeval tv;
125 : : int fd;
126 : :
127 : 404 : fd = socket(AF_UNIX, type|SOCK_CLOEXEC, 0);
128 [ - + ]: 404 : if (fd < 0)
129 : 0 : return -errno;
130 : :
131 : 404 : fd = fd_move_above_stdio(fd);
132 : 404 : (void) fd_inc_sndbuf(fd, SNDBUF_SIZE);
133 : :
134 : : /* We need a blocking fd here since we'd otherwise lose messages way too early. However, let's not hang forever
135 : : * in the unlikely case of a deadlock. */
136 [ - + ]: 404 : if (getpid_cached() == 1)
137 : 0 : timeval_store(&tv, 10 * USEC_PER_MSEC);
138 : : else
139 : 404 : timeval_store(&tv, 10 * USEC_PER_SEC);
140 : 404 : (void) setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
141 : :
142 : 404 : return fd;
143 : : }
144 : :
145 : 8 : static int log_open_syslog(void) {
146 : :
147 : : static const union sockaddr_union sa = {
148 : : .un.sun_family = AF_UNIX,
149 : : .un.sun_path = "/dev/log",
150 : : };
151 : :
152 : : int r;
153 : :
154 [ + + ]: 8 : if (syslog_fd >= 0)
155 : 4 : return 0;
156 : :
157 : 4 : syslog_fd = create_log_socket(SOCK_DGRAM);
158 [ - + ]: 4 : if (syslog_fd < 0) {
159 : 0 : r = syslog_fd;
160 : 0 : goto fail;
161 : : }
162 : :
163 [ - + - + : 4 : if (connect(syslog_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) {
- + ]
164 : 0 : safe_close(syslog_fd);
165 : :
166 : : /* Some legacy syslog systems still use stream
167 : : * sockets. They really shouldn't. But what can we
168 : : * do... */
169 : 0 : syslog_fd = create_log_socket(SOCK_STREAM);
170 [ # # ]: 0 : if (syslog_fd < 0) {
171 : 0 : r = syslog_fd;
172 : 0 : goto fail;
173 : : }
174 : :
175 [ # # # # : 0 : if (connect(syslog_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) {
# # ]
176 : 0 : r = -errno;
177 : 0 : goto fail;
178 : : }
179 : :
180 : 0 : syslog_is_stream = true;
181 : : } else
182 : 4 : syslog_is_stream = false;
183 : :
184 : 4 : return 0;
185 : :
186 : 0 : fail:
187 : 0 : log_close_syslog();
188 : 0 : return r;
189 : : }
190 : :
191 : 1206 : static void log_close_journal(void) {
192 : 1206 : journal_fd = safe_close(journal_fd);
193 : 1206 : }
194 : :
195 : 420 : static int log_open_journal(void) {
196 : :
197 : : static const union sockaddr_union sa = {
198 : : .un.sun_family = AF_UNIX,
199 : : .un.sun_path = "/run/systemd/journal/socket",
200 : : };
201 : :
202 : : int r;
203 : :
204 [ + + ]: 420 : if (journal_fd >= 0)
205 : 20 : return 0;
206 : :
207 : 400 : journal_fd = create_log_socket(SOCK_DGRAM);
208 [ - + ]: 400 : if (journal_fd < 0) {
209 : 0 : r = journal_fd;
210 : 0 : goto fail;
211 : : }
212 : :
213 [ - + - + : 400 : if (connect(journal_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) {
- + ]
214 : 0 : r = -errno;
215 : 0 : goto fail;
216 : : }
217 : :
218 : 400 : return 0;
219 : :
220 : 0 : fail:
221 : 0 : log_close_journal();
222 : 0 : return r;
223 : : }
224 : :
225 : 1626 : int log_open(void) {
226 : : int r;
227 : :
228 : : /* Do not call from library code. */
229 : :
230 : : /* If we don't use the console we close it here, to not get
231 : : * killed by SAK. If we don't use syslog we close it here so
232 : : * that we are not confused by somebody deleting the socket in
233 : : * the fs, and to make sure we don't use it if prohibit_ipc is
234 : : * set. If we don't use /dev/kmsg we still keep it open,
235 : : * because there is no reason to close it. */
236 : :
237 [ + + ]: 1626 : if (log_target == LOG_TARGET_NULL) {
238 : 4 : log_close_journal();
239 : 4 : log_close_syslog();
240 : 4 : log_close_console();
241 : 4 : return 0;
242 : : }
243 : :
244 [ + + + - ]: 2018 : if (log_target != LOG_TARGET_AUTO ||
245 [ + - ]: 792 : getpid_cached() == 1 ||
246 : 396 : isatty(STDERR_FILENO) <= 0) {
247 : :
248 [ + + ]: 1622 : if (!prohibit_ipc &&
249 [ + + + + ]: 1546 : IN_SET(log_target, LOG_TARGET_AUTO,
250 : : LOG_TARGET_JOURNAL_OR_KMSG,
251 : : LOG_TARGET_JOURNAL)) {
252 : 420 : r = log_open_journal();
253 [ + - ]: 420 : if (r >= 0) {
254 : 420 : log_close_syslog();
255 : 420 : log_close_console();
256 : 420 : return r;
257 : : }
258 : : }
259 : :
260 [ + + ]: 1202 : if (!prohibit_ipc &&
261 [ + + + + ]: 1126 : IN_SET(log_target, LOG_TARGET_SYSLOG_OR_KMSG,
262 : : LOG_TARGET_SYSLOG)) {
263 : 8 : r = log_open_syslog();
264 [ + - ]: 8 : if (r >= 0) {
265 : 8 : log_close_journal();
266 : 8 : log_close_console();
267 : 8 : return r;
268 : : }
269 : : }
270 : :
271 [ + + + + ]: 1194 : if (IN_SET(log_target, LOG_TARGET_AUTO,
272 : : LOG_TARGET_JOURNAL_OR_KMSG,
273 : : LOG_TARGET_SYSLOG_OR_KMSG,
274 : : LOG_TARGET_KMSG)) {
275 : 4 : r = log_open_kmsg();
276 [ - + ]: 4 : if (r >= 0) {
277 : 0 : log_close_journal();
278 : 0 : log_close_syslog();
279 : 0 : log_close_console();
280 : 0 : return r;
281 : : }
282 : : }
283 : : }
284 : :
285 : 1194 : log_close_journal();
286 : 1194 : log_close_syslog();
287 : :
288 : 1194 : return log_open_console();
289 : : }
290 : :
291 : 580 : void log_set_target(LogTarget target) {
292 [ - + ]: 580 : assert(target >= 0);
293 [ - + ]: 580 : assert(target < _LOG_TARGET_MAX);
294 : :
295 [ - + ]: 580 : if (upgrade_syslog_to_journal) {
296 [ # # ]: 0 : if (target == LOG_TARGET_SYSLOG)
297 : 0 : target = LOG_TARGET_JOURNAL;
298 [ # # ]: 0 : else if (target == LOG_TARGET_SYSLOG_OR_KMSG)
299 : 0 : target = LOG_TARGET_JOURNAL_OR_KMSG;
300 : : }
301 : :
302 : 580 : log_target = target;
303 : 580 : }
304 : :
305 : 0 : void log_close(void) {
306 : : /* Do not call from library code. */
307 : :
308 : 0 : log_close_journal();
309 : 0 : log_close_syslog();
310 : 0 : log_close_kmsg();
311 : 0 : log_close_console();
312 : 0 : }
313 : :
314 : 0 : void log_forget_fds(void) {
315 : : /* Do not call from library code. */
316 : :
317 : 0 : console_fd = kmsg_fd = syslog_fd = journal_fd = -1;
318 : 0 : }
319 : :
320 : 1235 : void log_set_max_level_realm(LogRealm realm, int level) {
321 [ - + ]: 1235 : assert((level & LOG_PRIMASK) == level);
322 [ - + ]: 1235 : assert(realm < ELEMENTSOF(log_max_level));
323 : :
324 : 1235 : log_max_level[realm] = level;
325 : 1235 : }
326 : :
327 : 0 : void log_set_facility(int facility) {
328 : 0 : log_facility = facility;
329 : 0 : }
330 : :
331 : 134600 : static int write_to_console(
332 : : int level,
333 : : int error,
334 : : const char *file,
335 : : int line,
336 : : const char *func,
337 : : const char *buffer) {
338 : :
339 : : char location[256], prefix[1 + DECIMAL_STR_MAX(int) + 2];
340 : 134600 : struct iovec iovec[6] = {};
341 : 134600 : const char *on = NULL, *off = NULL;
342 : 134600 : size_t n = 0;
343 : :
344 [ - + ]: 134600 : if (console_fd < 0)
345 : 0 : return 0;
346 : :
347 [ + + ]: 134600 : if (log_target == LOG_TARGET_CONSOLE_PREFIXED) {
348 [ - + ]: 32 : xsprintf(prefix, "<%i>", level);
349 : 32 : iovec[n++] = IOVEC_MAKE_STRING(prefix);
350 : : }
351 : :
352 [ + + ]: 134600 : if (show_color)
353 : 4 : get_log_colors(LOG_PRI(level), &on, &off, NULL);
354 : :
355 [ - + ]: 134600 : if (show_location) {
356 : 0 : const char *lon = "", *loff = "";
357 [ # # ]: 0 : if (show_color) {
358 : 0 : lon = ANSI_HIGHLIGHT_YELLOW4;
359 : 0 : loff = ANSI_NORMAL;
360 : : }
361 : :
362 : 0 : (void) snprintf(location, sizeof location, "%s%s:%i%s: ", lon, file, line, loff);
363 : 0 : iovec[n++] = IOVEC_MAKE_STRING(location);
364 : : }
365 : :
366 [ + + ]: 134600 : if (on)
367 : 4 : iovec[n++] = IOVEC_MAKE_STRING(on);
368 : 134600 : iovec[n++] = IOVEC_MAKE_STRING(buffer);
369 [ + + ]: 134600 : if (off)
370 : 4 : iovec[n++] = IOVEC_MAKE_STRING(off);
371 : 134600 : iovec[n++] = IOVEC_MAKE_STRING("\n");
372 : :
373 [ - + ]: 134600 : if (writev(console_fd, iovec, n) < 0) {
374 : :
375 [ # # # # ]: 0 : if (errno == EIO && getpid_cached() == 1) {
376 : :
377 : : /* If somebody tried to kick us from our console tty (via vhangup() or suchlike), try
378 : : * to reconnect. */
379 : :
380 : 0 : log_close_console();
381 : 0 : (void) log_open_console();
382 [ # # ]: 0 : if (console_fd < 0)
383 : 0 : return 0;
384 : :
385 [ # # ]: 0 : if (writev(console_fd, iovec, n) < 0)
386 : 0 : return -errno;
387 : : } else
388 : 0 : return -errno;
389 : : }
390 : :
391 : 134600 : return 1;
392 : : }
393 : :
394 : 64 : static int write_to_syslog(
395 : : int level,
396 : : int error,
397 : : const char *file,
398 : : int line,
399 : : const char *func,
400 : : const char *buffer) {
401 : :
402 : : char header_priority[2 + DECIMAL_STR_MAX(int) + 1],
403 : : header_time[64],
404 : : header_pid[4 + DECIMAL_STR_MAX(pid_t) + 1];
405 : 64 : struct iovec iovec[5] = {};
406 : 64 : struct msghdr msghdr = {
407 : : .msg_iov = iovec,
408 : : .msg_iovlen = ELEMENTSOF(iovec),
409 : : };
410 : : time_t t;
411 : : struct tm tm;
412 : :
413 [ - + ]: 64 : if (syslog_fd < 0)
414 : 0 : return 0;
415 : :
416 [ - + ]: 64 : xsprintf(header_priority, "<%i>", level);
417 : :
418 : 64 : t = (time_t) (now(CLOCK_REALTIME) / USEC_PER_SEC);
419 [ - + ]: 64 : if (!localtime_r(&t, &tm))
420 : 0 : return -EINVAL;
421 : :
422 [ - + ]: 64 : if (strftime(header_time, sizeof(header_time), "%h %e %T ", &tm) <= 0)
423 : 0 : return -EINVAL;
424 : :
425 [ - + ]: 64 : xsprintf(header_pid, "["PID_FMT"]: ", getpid_cached());
426 : :
427 : 64 : iovec[0] = IOVEC_MAKE_STRING(header_priority);
428 : 64 : iovec[1] = IOVEC_MAKE_STRING(header_time);
429 : 64 : iovec[2] = IOVEC_MAKE_STRING(program_invocation_short_name);
430 : 64 : iovec[3] = IOVEC_MAKE_STRING(header_pid);
431 : 64 : iovec[4] = IOVEC_MAKE_STRING(buffer);
432 : :
433 : : /* When using syslog via SOCK_STREAM separate the messages by NUL chars */
434 [ - + ]: 64 : if (syslog_is_stream)
435 : 0 : iovec[4].iov_len++;
436 : :
437 : 0 : for (;;) {
438 : : ssize_t n;
439 : :
440 : 64 : n = sendmsg(syslog_fd, &msghdr, MSG_NOSIGNAL);
441 [ - + ]: 64 : if (n < 0)
442 : 0 : return -errno;
443 : :
444 [ - + ]: 64 : if (!syslog_is_stream ||
445 [ # # ]: 0 : (size_t) n >= IOVEC_TOTAL_SIZE(iovec, ELEMENTSOF(iovec)))
446 : : break;
447 : :
448 : 0 : IOVEC_INCREMENT(iovec, ELEMENTSOF(iovec), n);
449 : : }
450 : :
451 : 64 : return 1;
452 : : }
453 : :
454 : 32 : static int write_to_kmsg(
455 : : int level,
456 : : int error,
457 : : const char *file,
458 : : int line,
459 : : const char *func,
460 : : const char *buffer) {
461 : :
462 : : char header_priority[2 + DECIMAL_STR_MAX(int) + 1],
463 : : header_pid[4 + DECIMAL_STR_MAX(pid_t) + 1];
464 : 32 : struct iovec iovec[5] = {};
465 : :
466 [ + - ]: 32 : if (kmsg_fd < 0)
467 : 32 : return 0;
468 : :
469 [ # # ]: 0 : xsprintf(header_priority, "<%i>", level);
470 [ # # ]: 0 : xsprintf(header_pid, "["PID_FMT"]: ", getpid_cached());
471 : :
472 : 0 : iovec[0] = IOVEC_MAKE_STRING(header_priority);
473 : 0 : iovec[1] = IOVEC_MAKE_STRING(program_invocation_short_name);
474 : 0 : iovec[2] = IOVEC_MAKE_STRING(header_pid);
475 : 0 : iovec[3] = IOVEC_MAKE_STRING(buffer);
476 : 0 : iovec[4] = IOVEC_MAKE_STRING("\n");
477 : :
478 [ # # ]: 0 : if (writev(kmsg_fd, iovec, ELEMENTSOF(iovec)) < 0)
479 : 0 : return -errno;
480 : :
481 : 0 : return 1;
482 : : }
483 : :
484 : 320 : static int log_do_header(
485 : : char *header,
486 : : size_t size,
487 : : int level,
488 : : int error,
489 : : const char *file, int line, const char *func,
490 : : const char *object_field, const char *object,
491 : : const char *extra_field, const char *extra) {
492 : : int r;
493 : :
494 [ + + ]: 320 : error = IS_SYNTHETIC_ERRNO(error) ? 0 : ERRNO_VALUE(error);
495 : :
496 [ + + + + : 3840 : r = snprintf(header, size,
+ + + + +
+ + + + +
+ + - + +
- - + + -
+ - - + +
- - + ]
497 : : "PRIORITY=%i\n"
498 : : "SYSLOG_FACILITY=%i\n"
499 : : "%s%.256s%s" /* CODE_FILE */
500 : : "%s%.*i%s" /* CODE_LINE */
501 : : "%s%.256s%s" /* CODE_FUNC */
502 : : "%s%.*i%s" /* ERRNO */
503 : : "%s%.256s%s" /* object */
504 : : "%s%.256s%s" /* extra */
505 : : "SYSLOG_IDENTIFIER=%.256s\n",
506 : : LOG_PRI(level),
507 : 320 : LOG_FAC(level),
508 : 320 : isempty(file) ? "" : "CODE_FILE=",
509 : 320 : isempty(file) ? "" : file,
510 : 320 : isempty(file) ? "" : "\n",
511 : : line ? "CODE_LINE=" : "",
512 : : line ? 1 : 0, line, /* %.0d means no output too, special case for 0 */
513 : : line ? "\n" : "",
514 : 320 : isempty(func) ? "" : "CODE_FUNC=",
515 : 320 : isempty(func) ? "" : func,
516 : 320 : isempty(func) ? "" : "\n",
517 : : error ? "ERRNO=" : "",
518 : : error ? 1 : 0, error,
519 : : error ? "\n" : "",
520 : 320 : isempty(object) ? "" : object_field,
521 : 320 : isempty(object) ? "" : object,
522 : 320 : isempty(object) ? "" : "\n",
523 : 320 : isempty(extra) ? "" : extra_field,
524 : 320 : isempty(extra) ? "" : extra,
525 : 320 : isempty(extra) ? "" : "\n",
526 : : program_invocation_short_name);
527 [ - + ]: 320 : assert_raw((size_t) r < size);
528 : :
529 : 320 : return 0;
530 : : }
531 : :
532 : 236 : static int write_to_journal(
533 : : int level,
534 : : int error,
535 : : const char *file,
536 : : int line,
537 : : const char *func,
538 : : const char *object_field,
539 : : const char *object,
540 : : const char *extra_field,
541 : : const char *extra,
542 : : const char *buffer) {
543 : :
544 : : char header[LINE_MAX];
545 : 236 : struct iovec iovec[4] = {};
546 : 236 : struct msghdr mh = {};
547 : :
548 [ - + ]: 236 : if (journal_fd < 0)
549 : 0 : return 0;
550 : :
551 : 236 : log_do_header(header, sizeof(header), level, error, file, line, func, object_field, object, extra_field, extra);
552 : :
553 : 236 : iovec[0] = IOVEC_MAKE_STRING(header);
554 : 236 : iovec[1] = IOVEC_MAKE_STRING("MESSAGE=");
555 : 236 : iovec[2] = IOVEC_MAKE_STRING(buffer);
556 : 236 : iovec[3] = IOVEC_MAKE_STRING("\n");
557 : :
558 : 236 : mh.msg_iov = iovec;
559 : 236 : mh.msg_iovlen = ELEMENTSOF(iovec);
560 : :
561 [ - + ]: 236 : if (sendmsg(journal_fd, &mh, MSG_NOSIGNAL) < 0)
562 : 0 : return -errno;
563 : :
564 : 236 : return 1;
565 : : }
566 : :
567 : 134276 : int log_dispatch_internal(
568 : : int level,
569 : : int error,
570 : : const char *file,
571 : : int line,
572 : : const char *func,
573 : : const char *object_field,
574 : : const char *object,
575 : : const char *extra_field,
576 : : const char *extra,
577 : : char *buffer) {
578 : :
579 [ - + ]: 134276 : assert_raw(buffer);
580 : :
581 [ + + ]: 134276 : if (log_target == LOG_TARGET_NULL)
582 : 8 : return -ERRNO_VALUE(error);
583 : :
584 : : /* Patch in LOG_DAEMON facility if necessary */
585 [ + + ]: 134268 : if ((level & LOG_FACMASK) == 0)
586 : 133448 : level |= log_facility;
587 : :
588 [ - + ]: 134268 : if (open_when_needed)
589 : 0 : (void) log_open();
590 : :
591 : : do {
592 : : char *e;
593 : 135468 : int k = 0;
594 : :
595 : 135468 : buffer += strspn(buffer, NEWLINE);
596 : :
597 [ + + ]: 135468 : if (buffer[0] == 0)
598 : 568 : break;
599 : :
600 [ + + ]: 134900 : if ((e = strpbrk(buffer, NEWLINE)))
601 : 1200 : *(e++) = 0;
602 : :
603 [ + + + + ]: 134900 : if (IN_SET(log_target, LOG_TARGET_AUTO,
604 : : LOG_TARGET_JOURNAL_OR_KMSG,
605 : : LOG_TARGET_JOURNAL)) {
606 : :
607 : 236 : k = write_to_journal(level, error, file, line, func, object_field, object, extra_field, extra, buffer);
608 [ - + # # ]: 236 : if (k < 0 && k != -EAGAIN)
609 : 0 : log_close_journal();
610 : : }
611 : :
612 [ + + + + ]: 134900 : if (IN_SET(log_target, LOG_TARGET_SYSLOG_OR_KMSG,
613 : : LOG_TARGET_SYSLOG)) {
614 : :
615 : 64 : k = write_to_syslog(level, error, file, line, func, buffer);
616 [ - + # # ]: 64 : if (k < 0 && k != -EAGAIN)
617 : 0 : log_close_syslog();
618 : : }
619 : :
620 [ + + ]: 134900 : if (k <= 0 &&
621 [ + + + + ]: 134600 : IN_SET(log_target, LOG_TARGET_AUTO,
622 : : LOG_TARGET_SYSLOG_OR_KMSG,
623 : : LOG_TARGET_JOURNAL_OR_KMSG,
624 : : LOG_TARGET_KMSG)) {
625 : :
626 [ - + ]: 32 : if (k < 0)
627 : 0 : log_open_kmsg();
628 : :
629 : 32 : k = write_to_kmsg(level, error, file, line, func, buffer);
630 [ - + ]: 32 : if (k < 0) {
631 : 0 : log_close_kmsg();
632 : 0 : (void) log_open_console();
633 : : }
634 : : }
635 : :
636 [ + + ]: 134900 : if (k <= 0)
637 : 134600 : (void) write_to_console(level, error, file, line, func, buffer);
638 : :
639 : 134900 : buffer = e;
640 [ + + ]: 134900 : } while (buffer);
641 : :
642 [ - + ]: 134268 : if (open_when_needed)
643 : 0 : log_close();
644 : :
645 : 134268 : return -ERRNO_VALUE(error);
646 : : }
647 : :
648 : 0 : int log_dump_internal(
649 : : int level,
650 : : int error,
651 : : const char *file,
652 : : int line,
653 : : const char *func,
654 : : char *buffer) {
655 : :
656 : 0 : LogRealm realm = LOG_REALM_REMOVE_LEVEL(level);
657 : 0 : PROTECT_ERRNO;
658 : :
659 : : /* This modifies the buffer... */
660 : :
661 [ # # ]: 0 : if (_likely_(LOG_PRI(level) > log_max_level[realm]))
662 : 0 : return -ERRNO_VALUE(error);
663 : :
664 : 0 : return log_dispatch_internal(level, error, file, line, func, NULL, NULL, NULL, NULL, buffer);
665 : : }
666 : :
667 : 129964 : int log_internalv_realm(
668 : : int level,
669 : : int error,
670 : : const char *file,
671 : : int line,
672 : : const char *func,
673 : : const char *format,
674 : : va_list ap) {
675 : :
676 : 129964 : LogRealm realm = LOG_REALM_REMOVE_LEVEL(level);
677 : : char buffer[LINE_MAX];
678 : 129964 : PROTECT_ERRNO;
679 : :
680 [ - + ]: 129964 : if (_likely_(LOG_PRI(level) > log_max_level[realm]))
681 : 0 : return -ERRNO_VALUE(error);
682 : :
683 : : /* Make sure that %m maps to the specified error (or "Success"). */
684 : 129964 : errno = ERRNO_VALUE(error);
685 : :
686 : 129964 : (void) vsnprintf(buffer, sizeof buffer, format, ap);
687 : :
688 : 129964 : return log_dispatch_internal(level, error, file, line, func, NULL, NULL, NULL, NULL, buffer);
689 : : }
690 : :
691 : 129964 : int log_internal_realm(
692 : : int level,
693 : : int error,
694 : : const char *file,
695 : : int line,
696 : : const char *func,
697 : : const char *format, ...) {
698 : :
699 : : va_list ap;
700 : : int r;
701 : :
702 : 129964 : va_start(ap, format);
703 : 129964 : r = log_internalv_realm(level, error, file, line, func, format, ap);
704 : 129964 : va_end(ap);
705 : :
706 : 129964 : return r;
707 : : }
708 : :
709 : 9564 : int log_object_internalv(
710 : : int level,
711 : : int error,
712 : : const char *file,
713 : : int line,
714 : : const char *func,
715 : : const char *object_field,
716 : : const char *object,
717 : : const char *extra_field,
718 : : const char *extra,
719 : : const char *format,
720 : : va_list ap) {
721 : :
722 : 9564 : PROTECT_ERRNO;
723 : : char *buffer, *b;
724 : :
725 [ + + ]: 9564 : if (_likely_(LOG_PRI(level) > log_max_level[LOG_REALM_SYSTEMD]))
726 : 6712 : return -ERRNO_VALUE(error);
727 : :
728 : : /* Make sure that %m maps to the specified error (or "Success"). */
729 : 2852 : errno = ERRNO_VALUE(error);
730 : :
731 : : /* Prepend the object name before the message */
732 [ + - ]: 2852 : if (object) {
733 : : size_t n;
734 : :
735 : 2852 : n = strlen(object);
736 [ - + - + ]: 2852 : buffer = newa(char, n + 2 + LINE_MAX);
737 : 2852 : b = stpcpy(stpcpy(buffer, object), ": ");
738 : : } else
739 [ # # # # ]: 0 : b = buffer = newa(char, LINE_MAX);
740 : :
741 : 2852 : (void) vsnprintf(b, LINE_MAX, format, ap);
742 : :
743 : 2852 : return log_dispatch_internal(level, error, file, line, func,
744 : : object_field, object, extra_field, extra, buffer);
745 : : }
746 : :
747 : 9564 : int log_object_internal(
748 : : int level,
749 : : int error,
750 : : const char *file,
751 : : int line,
752 : : const char *func,
753 : : const char *object_field,
754 : : const char *object,
755 : : const char *extra_field,
756 : : const char *extra,
757 : : const char *format, ...) {
758 : :
759 : : va_list ap;
760 : : int r;
761 : :
762 : 9564 : va_start(ap, format);
763 : 9564 : r = log_object_internalv(level, error, file, line, func, object_field, object, extra_field, extra, format, ap);
764 : 9564 : va_end(ap);
765 : :
766 : 9564 : return r;
767 : : }
768 : :
769 : 720 : static void log_assert(
770 : : int level,
771 : : const char *text,
772 : : const char *file,
773 : : int line,
774 : : const char *func,
775 : : const char *format) {
776 : :
777 : : static char buffer[LINE_MAX];
778 : 720 : LogRealm realm = LOG_REALM_REMOVE_LEVEL(level);
779 : :
780 [ + + ]: 720 : if (_likely_(LOG_PRI(level) > log_max_level[realm]))
781 : 80 : return;
782 : :
783 : : DISABLE_WARNING_FORMAT_NONLITERAL;
784 : 640 : (void) snprintf(buffer, sizeof buffer, format, text, file, line, func);
785 : : REENABLE_WARNING;
786 : :
787 : 640 : log_abort_msg = buffer;
788 : :
789 : 640 : log_dispatch_internal(level, 0, file, line, func, NULL, NULL, NULL, NULL, buffer);
790 : : }
791 : :
792 : 0 : _noreturn_ void log_assert_failed_realm(
793 : : LogRealm realm,
794 : : const char *text,
795 : : const char *file,
796 : : int line,
797 : : const char *func) {
798 : 0 : (void) log_open();
799 : 0 : log_assert(LOG_REALM_PLUS_LEVEL(realm, LOG_CRIT), text, file, line, func,
800 : : "Assertion '%s' failed at %s:%u, function %s(). Aborting.");
801 : 0 : abort();
802 : : }
803 : :
804 : 0 : _noreturn_ void log_assert_failed_unreachable_realm(
805 : : LogRealm realm,
806 : : const char *text,
807 : : const char *file,
808 : : int line,
809 : : const char *func) {
810 : 0 : (void) log_open();
811 : 0 : log_assert(LOG_REALM_PLUS_LEVEL(realm, LOG_CRIT), text, file, line, func,
812 : : "Code should not be reached '%s' at %s:%u, function %s(). Aborting.");
813 : 0 : abort();
814 : : }
815 : :
816 : 720 : void log_assert_failed_return_realm(
817 : : LogRealm realm,
818 : : const char *text,
819 : : const char *file,
820 : : int line,
821 : : const char *func) {
822 : 720 : PROTECT_ERRNO;
823 : 720 : log_assert(LOG_REALM_PLUS_LEVEL(realm, LOG_DEBUG), text, file, line, func,
824 : : "Assertion '%s' failed at %s:%u, function %s(). Ignoring.");
825 : 720 : }
826 : :
827 : 0 : int log_oom_internal(LogRealm realm, const char *file, int line, const char *func) {
828 : 0 : return log_internal_realm(LOG_REALM_PLUS_LEVEL(realm, LOG_ERR),
829 : : ENOMEM, file, line, func, "Out of memory.");
830 : : }
831 : :
832 : 84 : int log_format_iovec(
833 : : struct iovec *iovec,
834 : : size_t iovec_len,
835 : : size_t *n,
836 : : bool newline_separator,
837 : : int error,
838 : : const char *format,
839 : : va_list ap) {
840 : :
841 : : static const char nl = '\n';
842 : :
843 [ + + + - ]: 372 : while (format && *n + 1 < iovec_len) {
844 : : va_list aq;
845 : : char *m;
846 : : int r;
847 : :
848 : : /* We need to copy the va_list structure,
849 : : * since vasprintf() leaves it afterwards at
850 : : * an undefined location */
851 : :
852 : 288 : errno = ERRNO_VALUE(error);
853 : :
854 : 288 : va_copy(aq, ap);
855 : 288 : r = vasprintf(&m, format, aq);
856 : 288 : va_end(aq);
857 [ - + ]: 288 : if (r < 0)
858 : 0 : return -EINVAL;
859 : :
860 : : /* Now, jump enough ahead, so that we point to
861 : : * the next format string */
862 [ - + - + : 672 : VA_FORMAT_ADVANCE(format, ap);
+ + - - +
+ + - +
+ ]
863 : :
864 : 288 : iovec[(*n)++] = IOVEC_MAKE_STRING(m);
865 : :
866 [ + - ]: 288 : if (newline_separator) {
867 : 288 : iovec[*n] = IOVEC_MAKE((char *)&nl, 1);
868 : 288 : (*n)++;
869 : : }
870 : :
871 : 288 : format = va_arg(ap, char *);
872 : : }
873 : 84 : return 0;
874 : : }
875 : :
876 : 944 : int log_struct_internal(
877 : : int level,
878 : : int error,
879 : : const char *file,
880 : : int line,
881 : : const char *func,
882 : : const char *format, ...) {
883 : :
884 : 944 : LogRealm realm = LOG_REALM_REMOVE_LEVEL(level);
885 : : char buf[LINE_MAX];
886 : 944 : bool found = false;
887 : 944 : PROTECT_ERRNO;
888 : : va_list ap;
889 : :
890 [ + + ]: 944 : if (_likely_(LOG_PRI(level) > log_max_level[realm]) ||
891 [ + + ]: 920 : log_target == LOG_TARGET_NULL)
892 : 40 : return -ERRNO_VALUE(error);
893 : :
894 [ + - ]: 904 : if ((level & LOG_FACMASK) == 0)
895 : 904 : level |= log_facility;
896 : :
897 [ + + + + ]: 904 : if (IN_SET(log_target,
898 : : LOG_TARGET_AUTO,
899 : : LOG_TARGET_JOURNAL_OR_KMSG,
900 : : LOG_TARGET_JOURNAL)) {
901 : :
902 [ - + ]: 84 : if (open_when_needed)
903 : 0 : log_open_journal();
904 : :
905 [ + - ]: 84 : if (journal_fd >= 0) {
906 : : char header[LINE_MAX];
907 : 84 : struct iovec iovec[17] = {};
908 : 84 : size_t n = 0, i;
909 : : int r;
910 : 84 : struct msghdr mh = {
911 : : .msg_iov = iovec,
912 : : };
913 : 84 : bool fallback = false;
914 : :
915 : : /* If the journal is available do structured logging.
916 : : * Do not report the errno if it is synthetic. */
917 : 84 : log_do_header(header, sizeof(header), level, error, file, line, func, NULL, NULL, NULL, NULL);
918 : 84 : iovec[n++] = IOVEC_MAKE_STRING(header);
919 : :
920 : 84 : va_start(ap, format);
921 : 84 : r = log_format_iovec(iovec, ELEMENTSOF(iovec), &n, true, error, format, ap);
922 [ - + ]: 84 : if (r < 0)
923 : 0 : fallback = true;
924 : : else {
925 : 84 : mh.msg_iovlen = n;
926 : 84 : (void) sendmsg(journal_fd, &mh, MSG_NOSIGNAL);
927 : : }
928 : :
929 : 84 : va_end(ap);
930 [ + + ]: 372 : for (i = 1; i < n; i += 2)
931 : 288 : free(iovec[i].iov_base);
932 : :
933 [ + - ]: 84 : if (!fallback) {
934 [ - + ]: 84 : if (open_when_needed)
935 : 0 : log_close();
936 : :
937 : 84 : return -ERRNO_VALUE(error);
938 : : }
939 : : }
940 : : }
941 : :
942 : : /* Fallback if journal logging is not available or didn't work. */
943 : :
944 : 820 : va_start(ap, format);
945 [ + - ]: 2844 : while (format) {
946 : : va_list aq;
947 : :
948 : 2844 : errno = ERRNO_VALUE(error);
949 : :
950 : 2844 : va_copy(aq, ap);
951 : 2844 : (void) vsnprintf(buf, sizeof buf, format, aq);
952 : 2844 : va_end(aq);
953 : :
954 [ + + ]: 2844 : if (startswith(buf, "MESSAGE=")) {
955 : 820 : found = true;
956 : 820 : break;
957 : : }
958 : :
959 [ - + - + : 3368 : VA_FORMAT_ADVANCE(format, ap);
+ - - - +
- - - +
+ ]
960 : :
961 : 2024 : format = va_arg(ap, char *);
962 : : }
963 : 820 : va_end(ap);
964 : :
965 [ - + ]: 820 : if (!found) {
966 [ # # ]: 0 : if (open_when_needed)
967 : 0 : log_close();
968 : :
969 : 0 : return -ERRNO_VALUE(error);
970 : : }
971 : :
972 : 820 : return log_dispatch_internal(level, error, file, line, func, NULL, NULL, NULL, NULL, buf + 8);
973 : : }
974 : :
975 : 0 : int log_struct_iovec_internal(
976 : : int level,
977 : : int error,
978 : : const char *file,
979 : : int line,
980 : : const char *func,
981 : : const struct iovec input_iovec[],
982 : : size_t n_input_iovec) {
983 : :
984 : 0 : LogRealm realm = LOG_REALM_REMOVE_LEVEL(level);
985 : 0 : PROTECT_ERRNO;
986 : : size_t i;
987 : : char *m;
988 : :
989 [ # # ]: 0 : if (_likely_(LOG_PRI(level) > log_max_level[realm]) ||
990 [ # # ]: 0 : log_target == LOG_TARGET_NULL)
991 : 0 : return -ERRNO_VALUE(error);
992 : :
993 [ # # ]: 0 : if ((level & LOG_FACMASK) == 0)
994 : 0 : level |= log_facility;
995 : :
996 [ # # # # ]: 0 : if (IN_SET(log_target, LOG_TARGET_AUTO,
997 : : LOG_TARGET_JOURNAL_OR_KMSG,
998 : 0 : LOG_TARGET_JOURNAL) &&
999 [ # # ]: 0 : journal_fd >= 0) {
1000 : :
1001 : 0 : struct iovec iovec[1 + n_input_iovec*2];
1002 : : char header[LINE_MAX];
1003 : 0 : struct msghdr mh = {
1004 : : .msg_iov = iovec,
1005 : 0 : .msg_iovlen = 1 + n_input_iovec*2,
1006 : : };
1007 : :
1008 : 0 : log_do_header(header, sizeof(header), level, error, file, line, func, NULL, NULL, NULL, NULL);
1009 : 0 : iovec[0] = IOVEC_MAKE_STRING(header);
1010 : :
1011 [ # # ]: 0 : for (i = 0; i < n_input_iovec; i++) {
1012 : 0 : iovec[1+i*2] = input_iovec[i];
1013 : 0 : iovec[1+i*2+1] = IOVEC_MAKE_STRING("\n");
1014 : : }
1015 : :
1016 [ # # ]: 0 : if (sendmsg(journal_fd, &mh, MSG_NOSIGNAL) >= 0)
1017 : 0 : return -ERRNO_VALUE(error);
1018 : : }
1019 : :
1020 [ # # ]: 0 : for (i = 0; i < n_input_iovec; i++)
1021 [ # # ]: 0 : if (memory_startswith(input_iovec[i].iov_base, input_iovec[i].iov_len, "MESSAGE="))
1022 : 0 : break;
1023 : :
1024 [ # # ]: 0 : if (_unlikely_(i >= n_input_iovec)) /* Couldn't find MESSAGE=? */
1025 : 0 : return -ERRNO_VALUE(error);
1026 : :
1027 : 0 : m = strndupa(input_iovec[i].iov_base + STRLEN("MESSAGE="),
1028 : : input_iovec[i].iov_len - STRLEN("MESSAGE="));
1029 : :
1030 : 0 : return log_dispatch_internal(level, error, file, line, func, NULL, NULL, NULL, NULL, m);
1031 : : }
1032 : :
1033 : 76 : int log_set_target_from_string(const char *e) {
1034 : : LogTarget t;
1035 : :
1036 : 76 : t = log_target_from_string(e);
1037 [ - + ]: 76 : if (t < 0)
1038 : 0 : return -EINVAL;
1039 : :
1040 : 76 : log_set_target(t);
1041 : 76 : return 0;
1042 : : }
1043 : :
1044 : 771 : int log_set_max_level_from_string_realm(LogRealm realm, const char *e) {
1045 : : int t;
1046 : :
1047 : 771 : t = log_level_from_string(e);
1048 [ - + ]: 771 : if (t < 0)
1049 : 0 : return -EINVAL;
1050 : :
1051 : 771 : log_set_max_level_realm(realm, t);
1052 : 771 : return 0;
1053 : : }
1054 : :
1055 : 9636 : static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
1056 : :
1057 : : /*
1058 : : * The systemd.log_xyz= settings are parsed by all tools, and
1059 : : * so is "debug".
1060 : : *
1061 : : * However, "quiet" is only parsed by PID 1, and only turns of
1062 : : * status output to /dev/console, but does not alter the log
1063 : : * level.
1064 : : */
1065 : :
1066 [ - + # # ]: 9636 : if (streq(key, "debug") && !value)
1067 : 0 : log_set_max_level(LOG_DEBUG);
1068 : :
1069 [ - + ]: 9636 : else if (proc_cmdline_key_streq(key, "systemd.log_target")) {
1070 : :
1071 [ # # ]: 0 : if (proc_cmdline_value_missing(key, value))
1072 : 0 : return 0;
1073 : :
1074 [ # # ]: 0 : if (log_set_target_from_string(value) < 0)
1075 [ # # ]: 0 : log_warning("Failed to parse log target '%s'. Ignoring.", value);
1076 : :
1077 [ - + ]: 9636 : } else if (proc_cmdline_key_streq(key, "systemd.log_level")) {
1078 : :
1079 [ # # ]: 0 : if (proc_cmdline_value_missing(key, value))
1080 : 0 : return 0;
1081 : :
1082 [ # # ]: 0 : if (log_set_max_level_from_string(value) < 0)
1083 [ # # ]: 0 : log_warning("Failed to parse log level '%s'. Ignoring.", value);
1084 : :
1085 [ - + ]: 9636 : } else if (proc_cmdline_key_streq(key, "systemd.log_color")) {
1086 : :
1087 [ # # # # ]: 0 : if (log_show_color_from_string(value ?: "1") < 0)
1088 [ # # ]: 0 : log_warning("Failed to parse log color setting '%s'. Ignoring.", value);
1089 : :
1090 [ - + ]: 9636 : } else if (proc_cmdline_key_streq(key, "systemd.log_location")) {
1091 : :
1092 [ # # # # ]: 0 : if (log_show_location_from_string(value ?: "1") < 0)
1093 [ # # ]: 0 : log_warning("Failed to parse log location setting '%s'. Ignoring.", value);
1094 : : }
1095 : :
1096 : 9636 : return 0;
1097 : : }
1098 : :
1099 : 1606 : void log_parse_environment_realm(LogRealm realm) {
1100 : : /* Do not call from library code. */
1101 : :
1102 : : const char *e;
1103 : :
1104 [ + - + - ]: 1606 : if (getpid_cached() == 1 || get_ctty_devnr(0, NULL) < 0)
1105 : : /* Only try to read the command line in daemons. We assume that anything that has a
1106 : : * controlling tty is user stuff. For PID1 we do a special check in case it hasn't
1107 : : * closed the console yet. */
1108 : 1606 : (void) proc_cmdline_parse(parse_proc_cmdline_item, NULL, PROC_CMDLINE_STRIP_RD_PREFIX);
1109 : :
1110 : 1606 : e = getenv("SYSTEMD_LOG_TARGET");
1111 [ + + - + ]: 1606 : if (e && log_set_target_from_string(e) < 0)
1112 [ # # ]: 0 : log_warning("Failed to parse log target '%s'. Ignoring.", e);
1113 : :
1114 : 1606 : e = getenv("SYSTEMD_LOG_LEVEL");
1115 [ + + - + ]: 1606 : if (e && log_set_max_level_from_string_realm(realm, e) < 0)
1116 [ # # ]: 0 : log_warning("Failed to parse log level '%s'. Ignoring.", e);
1117 : :
1118 : 1606 : e = getenv("SYSTEMD_LOG_COLOR");
1119 [ - + # # ]: 1606 : if (e && log_show_color_from_string(e) < 0)
1120 [ # # ]: 0 : log_warning("Failed to parse log color '%s'. Ignoring.", e);
1121 : :
1122 : 1606 : e = getenv("SYSTEMD_LOG_LOCATION");
1123 [ - + # # ]: 1606 : if (e && log_show_location_from_string(e) < 0)
1124 [ # # ]: 0 : log_warning("Failed to parse log location '%s'. Ignoring.", e);
1125 : 1606 : }
1126 : :
1127 : 0 : LogTarget log_get_target(void) {
1128 : 0 : return log_target;
1129 : : }
1130 : :
1131 : 487277 : int log_get_max_level_realm(LogRealm realm) {
1132 : 487277 : return log_max_level[realm];
1133 : : }
1134 : :
1135 : 447 : void log_show_color(bool b) {
1136 : 447 : show_color = b;
1137 : 447 : }
1138 : :
1139 : 184 : bool log_get_show_color(void) {
1140 : 184 : return show_color;
1141 : : }
1142 : :
1143 : 0 : void log_show_location(bool b) {
1144 : 0 : show_location = b;
1145 : 0 : }
1146 : :
1147 : 0 : bool log_get_show_location(void) {
1148 : 0 : return show_location;
1149 : : }
1150 : :
1151 : 0 : int log_show_color_from_string(const char *e) {
1152 : : int t;
1153 : :
1154 : 0 : t = parse_boolean(e);
1155 [ # # ]: 0 : if (t < 0)
1156 : 0 : return t;
1157 : :
1158 : 0 : log_show_color(t);
1159 : 0 : return 0;
1160 : : }
1161 : :
1162 : 0 : int log_show_location_from_string(const char *e) {
1163 : : int t;
1164 : :
1165 : 0 : t = parse_boolean(e);
1166 [ # # ]: 0 : if (t < 0)
1167 : 0 : return t;
1168 : :
1169 : 0 : log_show_location(t);
1170 : 0 : return 0;
1171 : : }
1172 : :
1173 : 200 : bool log_on_console(void) {
1174 [ + - + - ]: 200 : if (IN_SET(log_target, LOG_TARGET_CONSOLE,
1175 : : LOG_TARGET_CONSOLE_PREFIXED))
1176 : 200 : return true;
1177 : :
1178 [ # # # # : 0 : return syslog_fd < 0 && kmsg_fd < 0 && journal_fd < 0;
# # ]
1179 : : }
1180 : :
1181 : : static const char *const log_target_table[_LOG_TARGET_MAX] = {
1182 : : [LOG_TARGET_CONSOLE] = "console",
1183 : : [LOG_TARGET_CONSOLE_PREFIXED] = "console-prefixed",
1184 : : [LOG_TARGET_KMSG] = "kmsg",
1185 : : [LOG_TARGET_JOURNAL] = "journal",
1186 : : [LOG_TARGET_JOURNAL_OR_KMSG] = "journal-or-kmsg",
1187 : : [LOG_TARGET_SYSLOG] = "syslog",
1188 : : [LOG_TARGET_SYSLOG_OR_KMSG] = "syslog-or-kmsg",
1189 : : [LOG_TARGET_AUTO] = "auto",
1190 : : [LOG_TARGET_NULL] = "null",
1191 : : };
1192 : :
1193 [ + + + + ]: 164 : DEFINE_STRING_TABLE_LOOKUP(log_target, LogTarget);
1194 : :
1195 : 3 : void log_received_signal(int level, const struct signalfd_siginfo *si) {
1196 [ - + ]: 3 : assert(si);
1197 : :
1198 [ + - ]: 3 : if (pid_is_valid(si->ssi_pid)) {
1199 : 6 : _cleanup_free_ char *p = NULL;
1200 : :
1201 : 3 : (void) get_process_comm(si->ssi_pid, &p);
1202 : :
1203 [ - + ]: 3 : log_full(level,
1204 : : "Received SIG%s from PID %"PRIu32" (%s).",
1205 : : signal_to_string(si->ssi_signo),
1206 : : si->ssi_pid, strna(p));
1207 : : } else
1208 [ # # ]: 0 : log_full(level,
1209 : : "Received SIG%s.",
1210 : : signal_to_string(si->ssi_signo));
1211 : 3 : }
1212 : :
1213 : 700 : int log_syntax_internal(
1214 : : const char *unit,
1215 : : int level,
1216 : : const char *config_file,
1217 : : unsigned config_line,
1218 : : int error,
1219 : : const char *file,
1220 : : int line,
1221 : : const char *func,
1222 : : const char *format, ...) {
1223 : :
1224 : 700 : PROTECT_ERRNO;
1225 : : char buffer[LINE_MAX];
1226 : : va_list ap;
1227 : 700 : const char *unit_fmt = NULL;
1228 : :
1229 [ + - ]: 700 : if (_likely_(LOG_PRI(level) > log_max_level[LOG_REALM_SYSTEMD]) ||
1230 [ + + ]: 700 : log_target == LOG_TARGET_NULL)
1231 : 12 : return -ERRNO_VALUE(error);
1232 : :
1233 : 688 : errno = ERRNO_VALUE(error);
1234 : :
1235 : 688 : va_start(ap, format);
1236 : 688 : (void) vsnprintf(buffer, sizeof buffer, format, ap);
1237 : 688 : va_end(ap);
1238 : :
1239 [ + + ]: 688 : if (unit)
1240 [ - + ]: 460 : unit_fmt = getpid_cached() == 1 ? "UNIT=%s" : "USER_UNIT=%s";
1241 : :
1242 [ + - ]: 688 : if (config_file) {
1243 [ + + ]: 688 : if (config_line > 0)
1244 : 672 : return log_struct_internal(
1245 : : LOG_REALM_PLUS_LEVEL(LOG_REALM_SYSTEMD, level),
1246 : : error,
1247 : : file, line, func,
1248 : : "MESSAGE_ID=" SD_MESSAGE_INVALID_CONFIGURATION_STR,
1249 : : "CONFIG_FILE=%s", config_file,
1250 : : "CONFIG_LINE=%u", config_line,
1251 : : LOG_MESSAGE("%s:%u: %s", config_file, config_line, buffer),
1252 : : unit_fmt, unit,
1253 : : NULL);
1254 : : else
1255 : 16 : return log_struct_internal(
1256 : : LOG_REALM_PLUS_LEVEL(LOG_REALM_SYSTEMD, level),
1257 : : error,
1258 : : file, line, func,
1259 : : "MESSAGE_ID=" SD_MESSAGE_INVALID_CONFIGURATION_STR,
1260 : : "CONFIG_FILE=%s", config_file,
1261 : : LOG_MESSAGE("%s: %s", config_file, buffer),
1262 : : unit_fmt, unit,
1263 : : NULL);
1264 [ # # ]: 0 : } else if (unit)
1265 : 0 : return log_struct_internal(
1266 : : LOG_REALM_PLUS_LEVEL(LOG_REALM_SYSTEMD, level),
1267 : : error,
1268 : : file, line, func,
1269 : : "MESSAGE_ID=" SD_MESSAGE_INVALID_CONFIGURATION_STR,
1270 : : LOG_MESSAGE("%s: %s", unit, buffer),
1271 : : unit_fmt, unit,
1272 : : NULL);
1273 : : else
1274 : 0 : return log_struct_internal(
1275 : : LOG_REALM_PLUS_LEVEL(LOG_REALM_SYSTEMD, level),
1276 : : error,
1277 : : file, line, func,
1278 : : "MESSAGE_ID=" SD_MESSAGE_INVALID_CONFIGURATION_STR,
1279 : : LOG_MESSAGE("%s", buffer),
1280 : : NULL);
1281 : : }
1282 : :
1283 : 4 : int log_syntax_invalid_utf8_internal(
1284 : : const char *unit,
1285 : : int level,
1286 : : const char *config_file,
1287 : : unsigned config_line,
1288 : : const char *file,
1289 : : int line,
1290 : : const char *func,
1291 : : const char *rvalue) {
1292 : :
1293 : 8 : _cleanup_free_ char *p = NULL;
1294 : :
1295 [ + - ]: 4 : if (rvalue)
1296 : 4 : p = utf8_escape_invalid(rvalue);
1297 : :
1298 : 4 : log_syntax_internal(unit, level, config_file, config_line, 0, file, line, func,
1299 : : "String is not UTF-8 clean, ignoring assignment: %s", strna(p));
1300 : :
1301 : 4 : return -EINVAL;
1302 : : }
1303 : :
1304 : 0 : void log_set_upgrade_syslog_to_journal(bool b) {
1305 : 0 : upgrade_syslog_to_journal = b;
1306 : :
1307 : : /* Make the change effective immediately */
1308 [ # # ]: 0 : if (b) {
1309 [ # # ]: 0 : if (log_target == LOG_TARGET_SYSLOG)
1310 : 0 : log_target = LOG_TARGET_JOURNAL;
1311 [ # # ]: 0 : else if (log_target == LOG_TARGET_SYSLOG_OR_KMSG)
1312 : 0 : log_target = LOG_TARGET_JOURNAL_OR_KMSG;
1313 : : }
1314 : 0 : }
1315 : :
1316 : 0 : void log_set_always_reopen_console(bool b) {
1317 : 0 : always_reopen_console = b;
1318 : 0 : }
1319 : :
1320 : 0 : void log_set_open_when_needed(bool b) {
1321 : 0 : open_when_needed = b;
1322 : 0 : }
1323 : :
1324 : 76 : void log_set_prohibit_ipc(bool b) {
1325 : 76 : prohibit_ipc = b;
1326 : 76 : }
1327 : :
1328 : 0 : int log_emergency_level(void) {
1329 : : /* Returns the log level to use for log_emergency() logging. We use LOG_EMERG only when we are PID 1, as only
1330 : : * then the system of the whole system is obviously affected. */
1331 : :
1332 [ # # ]: 0 : return getpid_cached() == 1 ? LOG_EMERG : LOG_ERR;
1333 : : }
1334 : :
1335 : 0 : int log_dup_console(void) {
1336 : : int copy;
1337 : :
1338 : : /* Duplicate the fd we use for fd logging if it's < 3 and use the copy from now on. This call is useful
1339 : : * whenever we want to continue logging through the original fd, but want to rearrange stderr. */
1340 : :
1341 [ # # ]: 0 : if (console_fd >= 3)
1342 : 0 : return 0;
1343 : :
1344 : 0 : copy = fcntl(console_fd, F_DUPFD_CLOEXEC, 3);
1345 [ # # ]: 0 : if (copy < 0)
1346 : 0 : return -errno;
1347 : :
1348 : 0 : console_fd = copy;
1349 : 0 : return 0;
1350 : : }
1351 : :
1352 : 436 : void log_setup_service(void) {
1353 : : /* Sets up logging the way it is most appropriate for running a program as a service. Note that using this
1354 : : * doesn't make the binary unsuitable for invocation on the command line, as log output will still go to the
1355 : : * terminal if invoked interactively. */
1356 : :
1357 : 436 : log_set_target(LOG_TARGET_AUTO);
1358 : 436 : log_parse_environment();
1359 : 436 : (void) log_open();
1360 : 436 : }
|