]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/log.c
log: add new log output mode, that prints to console, but prefixes with syslog priority
[thirdparty/systemd.git] / src / shared / log.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
5899f3b7 2
a7334b09
LP
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
a7334b09
LP
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 16 Lesser General Public License for more details.
a7334b09 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
a7334b09
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
5899f3b7
LP
22#include <stdarg.h>
23#include <stdio.h>
c9b97d2a 24#include <errno.h>
16801e90
LP
25#include <unistd.h>
26#include <fcntl.h>
27#include <sys/socket.h>
28#include <sys/un.h>
5ba081b0 29#include <stddef.h>
963ddb91 30#include <printf.h>
5899f3b7
LP
31
32#include "log.h"
16801e90 33#include "util.h"
4db17f29 34#include "missing.h"
16801e90 35#include "macro.h"
5ba081b0 36#include "socket-util.h"
5899f3b7 37
bb99a35a
LP
38#define SNDBUF_SIZE (8*1024*1024)
39
16801e90 40static LogTarget log_target = LOG_TARGET_CONSOLE;
bbe63281 41static int log_max_level = LOG_INFO;
3eff4208 42static int log_facility = LOG_DAEMON;
16801e90 43
843d2643 44static int console_fd = STDERR_FILENO;
16801e90
LP
45static int syslog_fd = -1;
46static int kmsg_fd = -1;
5ba081b0 47static int journal_fd = -1;
16801e90 48
c31e1495
LP
49static bool syslog_is_stream = false;
50
bbe63281
LP
51static bool show_color = false;
52static bool show_location = false;
53
c1dc6153
LP
54static bool upgrade_syslog_to_journal = false;
55
35b8ca3a 56/* Akin to glibc's __abort_msg; which is private and we hence cannot
185986c6
LP
57 * use here. */
58static char *log_abort_msg = NULL;
59
843d2643
LP
60void log_close_console(void) {
61
62 if (console_fd < 0)
63 return;
16801e90 64
c8513d54
LP
65 if (getpid() == 1) {
66 if (console_fd >= 3)
03e334a1 67 safe_close(console_fd);
c8513d54 68
843d2643 69 console_fd = -1;
16801e90
LP
70 }
71}
72
843d2643 73static int log_open_console(void) {
16801e90 74
843d2643 75 if (console_fd >= 0)
16801e90 76 return 0;
843d2643
LP
77
78 if (getpid() == 1) {
5ba081b0 79 console_fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
cd15c418 80 if (console_fd < 0)
843d2643 81 return console_fd;
843d2643
LP
82 } else
83 console_fd = STDERR_FILENO;
84
85 return 0;
86}
87
88void log_close_kmsg(void) {
03e334a1 89 kmsg_fd = safe_close(kmsg_fd);
843d2643
LP
90}
91
92static int log_open_kmsg(void) {
16801e90
LP
93
94 if (kmsg_fd >= 0)
95 return 0;
96
674f8283 97 kmsg_fd = open("/dev/kmsg", O_WRONLY|O_NOCTTY|O_CLOEXEC);
cd15c418 98 if (kmsg_fd < 0)
16801e90 99 return -errno;
0dae83f9 100
16801e90
LP
101 return 0;
102}
103
104void log_close_syslog(void) {
03e334a1 105 syslog_fd = safe_close(syslog_fd);
16801e90
LP
106}
107
c31e1495 108static int create_log_socket(int type) {
8b18fdc1 109 struct timeval tv;
95066a90 110 int fd;
c31e1495 111
8b18fdc1 112 fd = socket(AF_UNIX, type|SOCK_CLOEXEC, 0);
5ba081b0 113 if (fd < 0)
c31e1495
LP
114 return -errno;
115
bb99a35a
LP
116 fd_inc_sndbuf(fd, SNDBUF_SIZE);
117
8b18fdc1
LP
118 /* We need a blocking fd here since we'd otherwise lose
119 messages way too early. However, let's not hang forever in the
120 unlikely case of a deadlock. */
4d89874a
ZJS
121 if (getpid() == 1)
122 timeval_store(&tv, 10 * USEC_PER_MSEC);
123 else
124 timeval_store(&tv, 10 * USEC_PER_SEC);
086891e5 125 (void) setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
8b18fdc1 126
c31e1495
LP
127 return fd;
128}
129
843d2643 130static int log_open_syslog(void) {
95066a90
LP
131
132 static const union sockaddr_union sa = {
b92bea5d
ZJS
133 .un.sun_family = AF_UNIX,
134 .un.sun_path = "/dev/log",
135 };
16801e90 136
95066a90
LP
137 int r;
138
16801e90
LP
139 if (syslog_fd >= 0)
140 return 0;
141
5ba081b0
LP
142 syslog_fd = create_log_socket(SOCK_DGRAM);
143 if (syslog_fd < 0) {
144 r = syslog_fd;
843d2643 145 goto fail;
16801e90
LP
146 }
147
3338b959 148 if (connect(syslog_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
03e334a1 149 safe_close(syslog_fd);
c31e1495
LP
150
151 /* Some legacy syslog systems still use stream
152 * sockets. They really shouldn't. But what can we
153 * do... */
5ba081b0
LP
154 syslog_fd = create_log_socket(SOCK_STREAM);
155 if (syslog_fd < 0) {
156 r = syslog_fd;
c31e1495
LP
157 goto fail;
158 }
159
3338b959 160 if (connect(syslog_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
c31e1495
LP
161 r = -errno;
162 goto fail;
163 }
164
165 syslog_is_stream = true;
166 } else
167 syslog_is_stream = false;
168
16801e90 169 return 0;
843d2643
LP
170
171fail:
172 log_close_syslog();
843d2643
LP
173 return r;
174}
175
5ba081b0 176void log_close_journal(void) {
03e334a1 177 journal_fd = safe_close(journal_fd);
5ba081b0
LP
178}
179
180static int log_open_journal(void) {
95066a90
LP
181
182 static const union sockaddr_union sa = {
b92bea5d
ZJS
183 .un.sun_family = AF_UNIX,
184 .un.sun_path = "/run/systemd/journal/socket",
185 };
95066a90 186
5ba081b0
LP
187 int r;
188
189 if (journal_fd >= 0)
190 return 0;
191
192 journal_fd = create_log_socket(SOCK_DGRAM);
193 if (journal_fd < 0) {
194 r = journal_fd;
195 goto fail;
196 }
197
5ba081b0
LP
198 if (connect(journal_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
199 r = -errno;
200 goto fail;
201 }
202
5ba081b0
LP
203 return 0;
204
205fail:
206 log_close_journal();
5ba081b0
LP
207 return r;
208}
209
843d2643
LP
210int log_open(void) {
211 int r;
212
213 /* If we don't use the console we close it here, to not get
214 * killed by SAK. If we don't use syslog we close it here so
215 * that we are not confused by somebody deleting the socket in
216 * the fs. If we don't use /dev/kmsg we still keep it open,
217 * because there is no reason to close it. */
218
9fae33d2 219 if (log_target == LOG_TARGET_NULL) {
5ba081b0 220 log_close_journal();
9fae33d2
LP
221 log_close_syslog();
222 log_close_console();
223 return 0;
224 }
225
a6903061 226 if ((log_target != LOG_TARGET_AUTO && log_target != LOG_TARGET_SAFE) ||
bb7df0da 227 getpid() == 1 ||
f41c094c 228 isatty(STDERR_FILENO) <= 0) {
bb7df0da
LP
229
230 if (log_target == LOG_TARGET_AUTO ||
5ba081b0
LP
231 log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
232 log_target == LOG_TARGET_JOURNAL) {
233 r = log_open_journal();
234 if (r >= 0) {
235 log_close_syslog();
bb7df0da
LP
236 log_close_console();
237 return r;
238 }
5ba081b0
LP
239 }
240
241 if (log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
242 log_target == LOG_TARGET_SYSLOG) {
243 r = log_open_syslog();
244 if (r >= 0) {
245 log_close_journal();
246 log_close_console();
247 return r;
248 }
249 }
250
bb7df0da 251 if (log_target == LOG_TARGET_AUTO ||
a6903061 252 log_target == LOG_TARGET_SAFE ||
5ba081b0 253 log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
bb7df0da 254 log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
5ba081b0
LP
255 log_target == LOG_TARGET_KMSG) {
256 r = log_open_kmsg();
257 if (r >= 0) {
258 log_close_journal();
bb7df0da
LP
259 log_close_syslog();
260 log_close_console();
261 return r;
262 }
5ba081b0 263 }
bb7df0da 264 }
843d2643 265
5ba081b0 266 log_close_journal();
843d2643 267 log_close_syslog();
dcdf86bb 268
843d2643 269 return log_open_console();
16801e90
LP
270}
271
272void log_set_target(LogTarget target) {
273 assert(target >= 0);
274 assert(target < _LOG_TARGET_MAX);
275
c1dc6153
LP
276 if (upgrade_syslog_to_journal) {
277 if (target == LOG_TARGET_SYSLOG)
278 target = LOG_TARGET_JOURNAL;
279 else if (target == LOG_TARGET_SYSLOG_OR_KMSG)
280 target = LOG_TARGET_JOURNAL_OR_KMSG;
281 }
282
16801e90
LP
283 log_target = target;
284}
285
871e5809 286void log_close(void) {
5ba081b0 287 log_close_journal();
871e5809 288 log_close_syslog();
5ba081b0
LP
289 log_close_kmsg();
290 log_close_console();
871e5809
LP
291}
292
4d8a7798 293void log_forget_fds(void) {
5ba081b0 294 console_fd = kmsg_fd = syslog_fd = journal_fd = -1;
4d8a7798
MS
295}
296
16801e90
LP
297void log_set_max_level(int level) {
298 assert((level & LOG_PRIMASK) == level);
299
300 log_max_level = level;
301}
302
3eff4208
LP
303void log_set_facility(int facility) {
304 log_facility = facility;
305}
306
843d2643 307static int write_to_console(
20c03b7b 308 int level,
086891e5 309 int error,
95066a90 310 const char *file,
20c03b7b
LP
311 int line,
312 const char *func,
086891e5 313 const char *object_field,
fdf9f9bb 314 const char *object,
20c03b7b 315 const char *buffer) {
5899f3b7 316
aca83a53
LP
317 char location[64], prefix[1 + DECIMAL_STR_MAX(int) + 2];
318 struct iovec iovec[6] = {};
843d2643
LP
319 unsigned n = 0;
320 bool highlight;
5899f3b7 321
843d2643
LP
322 if (console_fd < 0)
323 return 0;
324
aca83a53
LP
325 if (log_target == LOG_TARGET_CONSOLE_PREFIXED) {
326 sprintf(prefix, "<%i>", level);
327 IOVEC_SET_STRING(iovec[n++], prefix);
328 }
329
bbe63281 330 highlight = LOG_PRI(level) <= LOG_ERR && show_color;
843d2643 331
674f8283
LP
332 if (show_location) {
333 snprintf(location, sizeof(location), "(%s:%u) ", file, line);
334 char_array_0(location);
bbe63281 335 IOVEC_SET_STRING(iovec[n++], location);
674f8283
LP
336 }
337
843d2643 338 if (highlight)
c1072ea0 339 IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_RED_ON);
843d2643
LP
340 IOVEC_SET_STRING(iovec[n++], buffer);
341 if (highlight)
61cbdc4b 342 IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_OFF);
843d2643
LP
343 IOVEC_SET_STRING(iovec[n++], "\n");
344
0e6eaa2d
LP
345 if (writev(console_fd, iovec, n) < 0) {
346
347 if (errno == EIO && getpid() == 1) {
348
349 /* If somebody tried to kick us from our
350 * console tty (via vhangup() or suchlike),
351 * try to reconnect */
352
353 log_close_console();
354 log_open_console();
355
356 if (console_fd < 0)
357 return 0;
358
359 if (writev(console_fd, iovec, n) < 0)
360 return -errno;
361 } else
362 return -errno;
363 }
5899f3b7 364
843d2643 365 return 1;
16801e90 366}
5899f3b7 367
16801e90 368static int write_to_syslog(
086891e5
LP
369 int level,
370 int error,
95066a90 371 const char *file,
086891e5
LP
372 int line,
373 const char *func,
374 const char *object_field,
375 const char *object,
376 const char *buffer) {
16801e90 377
e09ca588 378 char header_priority[1 + DECIMAL_STR_MAX(int) + 2], header_time[64], header_pid[1 + DECIMAL_STR_MAX(pid_t) + 4];
b92bea5d
ZJS
379 struct iovec iovec[5] = {};
380 struct msghdr msghdr = {
381 .msg_iov = iovec,
382 .msg_iovlen = ELEMENTSOF(iovec),
383 };
16801e90
LP
384 time_t t;
385 struct tm *tm;
386
387 if (syslog_fd < 0)
843d2643 388 return 0;
16801e90 389
29db5834 390 snprintf(header_priority, sizeof(header_priority), "<%i>", level);
16801e90
LP
391 char_array_0(header_priority);
392
393 t = (time_t) (now(CLOCK_REALTIME) / USEC_PER_SEC);
fdf9f9bb
ZJS
394 tm = localtime(&t);
395 if (!tm)
16801e90
LP
396 return -EINVAL;
397
398 if (strftime(header_time, sizeof(header_time), "%h %e %T ", tm) <= 0)
399 return -EINVAL;
400
de0671ee 401 snprintf(header_pid, sizeof(header_pid), "["PID_FMT"]: ", getpid());
16801e90
LP
402 char_array_0(header_pid);
403
16801e90
LP
404 IOVEC_SET_STRING(iovec[0], header_priority);
405 IOVEC_SET_STRING(iovec[1], header_time);
5b6319dc 406 IOVEC_SET_STRING(iovec[2], program_invocation_short_name);
16801e90
LP
407 IOVEC_SET_STRING(iovec[3], header_pid);
408 IOVEC_SET_STRING(iovec[4], buffer);
409
c899f8c6 410 /* When using syslog via SOCK_STREAM separate the messages by NUL chars */
c31e1495
LP
411 if (syslog_is_stream)
412 iovec[4].iov_len++;
413
c31e1495
LP
414 for (;;) {
415 ssize_t n;
416
8f7f7a1b
MS
417 n = sendmsg(syslog_fd, &msghdr, MSG_NOSIGNAL);
418 if (n < 0)
c31e1495
LP
419 return -errno;
420
421 if (!syslog_is_stream ||
422 (size_t) n >= IOVEC_TOTAL_SIZE(iovec, ELEMENTSOF(iovec)))
423 break;
424
425 IOVEC_INCREMENT(iovec, ELEMENTSOF(iovec), n);
426 }
16801e90 427
843d2643 428 return 1;
16801e90
LP
429}
430
431static int write_to_kmsg(
086891e5
LP
432 int level,
433 int error,
434 const char*file,
435 int line,
436 const char *func,
437 const char *object_field,
438 const char *object,
439 const char *buffer) {
16801e90 440
e09ca588 441 char header_priority[1 + DECIMAL_STR_MAX(int) + 2], header_pid[1 + DECIMAL_STR_MAX(pid_t) + 4];
b92bea5d 442 struct iovec iovec[5] = {};
16801e90
LP
443
444 if (kmsg_fd < 0)
843d2643 445 return 0;
16801e90 446
29db5834 447 snprintf(header_priority, sizeof(header_priority), "<%i>", level);
16801e90
LP
448 char_array_0(header_priority);
449
de0671ee 450 snprintf(header_pid, sizeof(header_pid), "["PID_FMT"]: ", getpid());
16801e90
LP
451 char_array_0(header_pid);
452
16801e90 453 IOVEC_SET_STRING(iovec[0], header_priority);
5b6319dc 454 IOVEC_SET_STRING(iovec[1], program_invocation_short_name);
16801e90
LP
455 IOVEC_SET_STRING(iovec[2], header_pid);
456 IOVEC_SET_STRING(iovec[3], buffer);
843d2643 457 IOVEC_SET_STRING(iovec[4], "\n");
16801e90
LP
458
459 if (writev(kmsg_fd, iovec, ELEMENTSOF(iovec)) < 0)
460 return -errno;
461
843d2643 462 return 1;
16801e90
LP
463}
464
086891e5
LP
465static int log_do_header(
466 char *header,
467 size_t size,
468 int level,
469 int error,
470 const char *file, int line, const char *func,
471 const char *object_field, const char *object) {
472
41a79f10 473 snprintf(header, size,
5ba081b0 474 "PRIORITY=%i\n"
3eff4208 475 "SYSLOG_FACILITY=%i\n"
086891e5 476 "%s%s%s"
e429981b 477 "%s%.*i%s"
086891e5
LP
478 "%s%s%s"
479 "%s%.*i%s"
480 "%s%s%s"
41a79f10 481 "SYSLOG_IDENTIFIER=%s\n",
5ba081b0 482 LOG_PRI(level),
3eff4208 483 LOG_FAC(level),
086891e5
LP
484 isempty(file) ? "" : "CODE_FILE=",
485 isempty(file) ? "" : file,
486 isempty(file) ? "" : "\n",
e429981b
ZJS
487 line ? "CODE_LINE=" : "",
488 line ? 1 : 0, line, /* %.0d means no output too, special case for 0 */
489 line ? "\n" : "",
086891e5
LP
490 isempty(func) ? "" : "CODE_FUNCTION=",
491 isempty(func) ? "" : func,
492 isempty(func) ? "" : "\n",
493 error ? "ERRNO=" : "",
494 error ? 1 : 0, error,
495 error ? "\n" : "",
496 isempty(object) ? "" : object_field,
497 isempty(object) ? "" : object,
498 isempty(object) ? "" : "\n",
d29b05a4 499 program_invocation_short_name);
41a79f10 500 header[size - 1] = '\0';
086891e5 501
41a79f10
ZJS
502 return 0;
503}
5ba081b0 504
41a79f10 505static int write_to_journal(
086891e5
LP
506 int level,
507 int error,
508 const char*file,
509 int line,
510 const char *func,
511 const char *object_field,
512 const char *object,
513 const char *buffer) {
41a79f10
ZJS
514
515 char header[LINE_MAX];
b92bea5d
ZJS
516 struct iovec iovec[4] = {};
517 struct msghdr mh = {};
41a79f10
ZJS
518
519 if (journal_fd < 0)
520 return 0;
521
086891e5 522 log_do_header(header, sizeof(header), level, error, file, line, func, object_field, object);
5ba081b0 523
5ba081b0 524 IOVEC_SET_STRING(iovec[0], header);
41a79f10
ZJS
525 IOVEC_SET_STRING(iovec[1], "MESSAGE=");
526 IOVEC_SET_STRING(iovec[2], buffer);
527 IOVEC_SET_STRING(iovec[3], "\n");
5ba081b0 528
5ba081b0
LP
529 mh.msg_iov = iovec;
530 mh.msg_iovlen = ELEMENTSOF(iovec);
531
532 if (sendmsg(journal_fd, &mh, MSG_NOSIGNAL) < 0)
533 return -errno;
534
535 return 1;
536}
537
843d2643 538static int log_dispatch(
086891e5
LP
539 int level,
540 int error,
95066a90 541 const char *file,
086891e5
LP
542 int line,
543 const char *func,
544 const char *object_field,
545 const char *object,
546 char *buffer) {
843d2643 547
bf371116 548 assert(buffer);
843d2643 549
9fae33d2 550 if (log_target == LOG_TARGET_NULL)
bf371116 551 return -error;
9fae33d2 552
29db5834 553 /* Patch in LOG_DAEMON facility if necessary */
7d76f312 554 if ((level & LOG_FACMASK) == 0)
3eff4208 555 level = log_facility | LOG_PRI(level);
29db5834 556
8f16f51d
LP
557 if (error < 0)
558 error = -error;
559
9726b29e
LP
560 do {
561 char *e;
9499b235 562 int k = 0;
843d2643 563
9726b29e 564 buffer += strspn(buffer, NEWLINE);
843d2643 565
9726b29e
LP
566 if (buffer[0] == 0)
567 break;
843d2643 568
9726b29e
LP
569 if ((e = strpbrk(buffer, NEWLINE)))
570 *(e++) = 0;
843d2643 571
bb7df0da 572 if (log_target == LOG_TARGET_AUTO ||
5ba081b0
LP
573 log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
574 log_target == LOG_TARGET_JOURNAL) {
575
086891e5 576 k = write_to_journal(level, error, file, line, func, object_field, object, buffer);
4e7bc3f3
LP
577 if (k < 0) {
578 if (k != -EAGAIN)
5ba081b0
LP
579 log_close_journal();
580 log_open_kmsg();
bf371116 581 }
5ba081b0
LP
582 }
583
584 if (log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
9726b29e
LP
585 log_target == LOG_TARGET_SYSLOG) {
586
086891e5 587 k = write_to_syslog(level, error, file, line, func, object_field, object, buffer);
4e7bc3f3
LP
588 if (k < 0) {
589 if (k != -EAGAIN)
8f7f7a1b 590 log_close_syslog();
9726b29e 591 log_open_kmsg();
bf371116 592 }
9726b29e
LP
593 }
594
9499b235 595 if (k <= 0 &&
bb7df0da 596 (log_target == LOG_TARGET_AUTO ||
a6903061 597 log_target == LOG_TARGET_SAFE ||
bb7df0da 598 log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
678d485a 599 log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
9499b235 600 log_target == LOG_TARGET_KMSG)) {
9726b29e 601
086891e5 602 k = write_to_kmsg(level, error, file, line, func, object_field, object, buffer);
4e7bc3f3
LP
603 if (k < 0) {
604 log_close_kmsg();
9726b29e 605 log_open_console();
bf371116 606 }
9726b29e
LP
607 }
608
bf371116
LP
609 if (k <= 0)
610 (void) write_to_console(level, error, file, line, func, object_field, object, buffer);
9726b29e
LP
611
612 buffer = e;
613 } while (buffer);
614
bf371116 615 return -error;
843d2643
LP
616}
617
2149e37c
LP
618int log_dump_internal(
619 int level,
086891e5 620 int error,
bf371116 621 const char *file,
2149e37c
LP
622 int line,
623 const char *func,
624 char *buffer) {
625
5c0aa72a 626 PROTECT_ERRNO;
2149e37c
LP
627
628 /* This modifies the buffer... */
629
bf371116
LP
630 if (error < 0)
631 error = -error;
632
2149e37c 633 if (_likely_(LOG_PRI(level) > log_max_level))
bf371116 634 return -error;
2149e37c 635
086891e5 636 return log_dispatch(level, error, file, line, func, NULL, NULL, buffer);
2149e37c
LP
637}
638
79008bdd 639int log_internalv(
086891e5
LP
640 int level,
641 int error,
642 const char*file,
643 int line,
644 const char *func,
645 const char *format,
646 va_list ap) {
16801e90 647
5c0aa72a 648 PROTECT_ERRNO;
addab137 649 char buffer[LINE_MAX];
16801e90 650
bf371116
LP
651 if (error < 0)
652 error = -error;
653
93a46b0b 654 if (_likely_(LOG_PRI(level) > log_max_level))
bf371116 655 return -error;
16801e90 656
086891e5
LP
657 /* Make sure that %m maps to the specified error */
658 if (error != 0)
bf371116 659 errno = error;
086891e5 660
843d2643 661 vsnprintf(buffer, sizeof(buffer), format, ap);
843d2643
LP
662 char_array_0(buffer);
663
086891e5 664 return log_dispatch(level, error, file, line, func, NULL, NULL, buffer);
185986c6 665}
16801e90 666
79008bdd 667int log_internal(
086891e5
LP
668 int level,
669 int error,
670 const char*file,
671 int line,
672 const char *func,
673 const char *format, ...) {
17a94911 674
17a94911 675 va_list ap;
bf371116 676 int r;
17a94911
LP
677
678 va_start(ap, format);
79008bdd 679 r = log_internalv(level, error, file, line, func, format, ap);
17a94911
LP
680 va_end(ap);
681
682 return r;
683}
684
79008bdd 685int log_object_internalv(
086891e5
LP
686 int level,
687 int error,
688 const char*file,
689 int line,
690 const char *func,
691 const char *object_field,
692 const char *object,
693 const char *format,
694 va_list ap) {
fdf9f9bb 695
5c0aa72a 696 PROTECT_ERRNO;
fdf9f9bb 697 char buffer[LINE_MAX];
fdf9f9bb 698
bf371116
LP
699 if (error < 0)
700 error = -error;
701
fdf9f9bb 702 if (_likely_(LOG_PRI(level) > log_max_level))
bf371116 703 return -error;
fdf9f9bb 704
086891e5
LP
705 /* Make sure that %m maps to the specified error */
706 if (error != 0)
bf371116 707 errno = error;
086891e5 708
fdf9f9bb
ZJS
709 vsnprintf(buffer, sizeof(buffer), format, ap);
710 char_array_0(buffer);
711
086891e5 712 return log_dispatch(level, error, file, line, func, object_field, object, buffer);
fdf9f9bb
ZJS
713}
714
79008bdd 715int log_object_internal(
086891e5
LP
716 int level,
717 int error,
718 const char*file,
719 int line,
720 const char *func,
721 const char *object_field,
722 const char *object,
723 const char *format, ...) {
fdf9f9bb 724
fdf9f9bb 725 va_list ap;
bf371116 726 int r;
fdf9f9bb
ZJS
727
728 va_start(ap, format);
79008bdd 729 r = log_object_internalv(level, error, file, line, func, object_field, object, format, ap);
fdf9f9bb
ZJS
730 va_end(ap);
731
732 return r;
733}
734
086891e5
LP
735static void log_assert(
736 int level,
737 const char *text,
738 const char *file,
739 int line,
740 const char *func,
741 const char *format) {
742
addab137 743 static char buffer[LINE_MAX];
185986c6 744
50f72bca
ZJS
745 if (_likely_(LOG_PRI(level) > log_max_level))
746 return;
747
bcfce235 748 DISABLE_WARNING_FORMAT_NONLITERAL;
b7f33638 749 snprintf(buffer, sizeof(buffer), format, text, file, line, func);
bcfce235 750 REENABLE_WARNING;
185986c6
LP
751
752 char_array_0(buffer);
753 log_abort_msg = buffer;
754
086891e5 755 log_dispatch(level, 0, file, line, func, NULL, NULL, buffer);
5899f3b7 756}
34f0e866 757
919ce0b7 758noreturn void log_assert_failed(const char *text, const char *file, int line, const char *func) {
80514f9c
LP
759 log_assert(LOG_CRIT, text, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Aborting.");
760 abort();
b7f33638
MS
761}
762
919ce0b7 763noreturn void log_assert_failed_unreachable(const char *text, const char *file, int line, const char *func) {
80514f9c
LP
764 log_assert(LOG_CRIT, text, file, line, func, "Code should not be reached '%s' at %s:%u, function %s(). Aborting.");
765 abort();
766}
767
768void log_assert_failed_return(const char *text, const char *file, int line, const char *func) {
e5ca092c 769 PROTECT_ERRNO;
80514f9c 770 log_assert(LOG_DEBUG, text, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Ignoring.");
b7f33638
MS
771}
772
877d54e9 773int log_oom_internal(const char *file, int line, const char *func) {
79008bdd 774 log_internal(LOG_ERR, ENOMEM, file, line, func, "Out of memory.");
6dc1e7e0
MS
775 return -ENOMEM;
776}
777
877d54e9
LP
778int log_struct_internal(
779 int level,
086891e5 780 int error,
877d54e9
LP
781 const char *file,
782 int line,
783 const char *func,
784 const char *format, ...) {
785
bf371116
LP
786 char buf[LINE_MAX];
787 bool found = false;
5c0aa72a 788 PROTECT_ERRNO;
877d54e9 789 va_list ap;
bf371116
LP
790
791 if (error < 0)
792 error = -error;
877d54e9
LP
793
794 if (_likely_(LOG_PRI(level) > log_max_level))
bf371116 795 return -error;
877d54e9
LP
796
797 if (log_target == LOG_TARGET_NULL)
bf371116 798 return -error;
877d54e9
LP
799
800 if ((level & LOG_FACMASK) == 0)
801 level = log_facility | LOG_PRI(level);
802
877d54e9
LP
803 if ((log_target == LOG_TARGET_AUTO ||
804 log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
805 log_target == LOG_TARGET_JOURNAL) &&
806 journal_fd >= 0) {
877d54e9 807 char header[LINE_MAX];
b92bea5d 808 struct iovec iovec[17] = {};
877d54e9 809 unsigned n = 0, i;
543295ad
ZJS
810 struct msghdr mh = {
811 .msg_iov = iovec,
812 };
41a79f10 813 static const char nl = '\n';
bf371116 814 bool fallback = false;
877d54e9
LP
815
816 /* If the journal is available do structured logging */
086891e5 817 log_do_header(header, sizeof(header), level, error, file, line, func, NULL, NULL);
877d54e9
LP
818 IOVEC_SET_STRING(iovec[n++], header);
819
820 va_start(ap, format);
821 while (format && n + 1 < ELEMENTSOF(iovec)) {
963ddb91 822 va_list aq;
bf371116 823 char *m;
877d54e9 824
963ddb91
LP
825 /* We need to copy the va_list structure,
826 * since vasprintf() leaves it afterwards at
827 * an undefined location */
828
6357ac66
LP
829 if (error != 0)
830 errno = error;
831
963ddb91 832 va_copy(aq, ap);
bf371116 833 if (vasprintf(&m, format, aq) < 0) {
963ddb91 834 va_end(aq);
bf371116 835 fallback = true;
877d54e9
LP
836 goto finish;
837 }
963ddb91
LP
838 va_end(aq);
839
840 /* Now, jump enough ahead, so that we point to
841 * the next format string */
842 VA_FORMAT_ADVANCE(format, ap);
877d54e9 843
bf371116 844 IOVEC_SET_STRING(iovec[n++], m);
877d54e9
LP
845
846 iovec[n].iov_base = (char*) &nl;
847 iovec[n].iov_len = 1;
848 n++;
849
850 format = va_arg(ap, char *);
851 }
877d54e9 852
877d54e9
LP
853 mh.msg_iovlen = n;
854
bf371116 855 (void) sendmsg(journal_fd, &mh, MSG_NOSIGNAL);
877d54e9
LP
856
857 finish:
e98055de 858 va_end(ap);
877d54e9
LP
859 for (i = 1; i < n; i += 2)
860 free(iovec[i].iov_base);
861
bf371116
LP
862 if (!fallback)
863 return -error;
864 }
877d54e9 865
bf371116 866 /* Fallback if journal logging is not available or didn't work. */
6357ac66 867
bf371116
LP
868 va_start(ap, format);
869 while (format) {
870 va_list aq;
877d54e9 871
bf371116
LP
872 if (error != 0)
873 errno = error;
877d54e9 874
bf371116
LP
875 va_copy(aq, ap);
876 vsnprintf(buf, sizeof(buf), format, aq);
877 va_end(aq);
878 char_array_0(buf);
963ddb91 879
bf371116
LP
880 if (startswith(buf, "MESSAGE=")) {
881 found = true;
882 break;
877d54e9 883 }
877d54e9 884
bf371116
LP
885 VA_FORMAT_ADVANCE(format, ap);
886
887 format = va_arg(ap, char *);
877d54e9 888 }
bf371116 889 va_end(ap);
877d54e9 890
bf371116
LP
891 if (!found)
892 return -error;
893
894 return log_dispatch(level, error, file, line, func, NULL, NULL, buf + 8);
877d54e9
LP
895}
896
34f0e866
LP
897int log_set_target_from_string(const char *e) {
898 LogTarget t;
899
5ba081b0
LP
900 t = log_target_from_string(e);
901 if (t < 0)
34f0e866
LP
902 return -EINVAL;
903
904 log_set_target(t);
905 return 0;
906}
907
908int log_set_max_level_from_string(const char *e) {
909 int t;
910
5ba081b0
LP
911 t = log_level_from_string(e);
912 if (t < 0)
913 return t;
34f0e866
LP
914
915 log_set_max_level(t);
916 return 0;
917}
918
1de1c9c3
LP
919static int parse_proc_cmdline_item(const char *key, const char *value) {
920
921 /*
922 * The systemd.log_xyz= settings are parsed by all tools, and
923 * so is "debug".
924 *
925 * However, "quiet" is only parsed by PID 1!
926 */
927
928 if (streq(key, "debug") && !value)
929 log_set_max_level(LOG_DEBUG);
930
931 else if (streq(key, "systemd.log_target") && value) {
932
933 if (log_set_target_from_string(value) < 0)
934 log_warning("Failed to parse log target '%s'. Ignoring.", value);
935
936 } else if (streq(key, "systemd.log_level") && value) {
937
938 if (log_set_max_level_from_string(value) < 0)
939 log_warning("Failed to parse log level '%s'. Ignoring.", value);
940
941 } else if (streq(key, "systemd.log_color") && value) {
942
943 if (log_show_color_from_string(value) < 0)
944 log_warning("Failed to parse log color setting '%s'. Ignoring.", value);
945
946 } else if (streq(key, "systemd.log_location") && value) {
947
948 if (log_show_location_from_string(value) < 0)
949 log_warning("Failed to parse log location setting '%s'. Ignoring.", value);
950 }
951
952 return 0;
953}
954
34f0e866
LP
955void log_parse_environment(void) {
956 const char *e;
b8d0ffc2 957
f9aa5413 958 (void) parse_proc_cmdline(parse_proc_cmdline_item);
34f0e866 959
4db17f29 960 e = secure_getenv("SYSTEMD_LOG_TARGET");
88fae6e0 961 if (e && log_set_target_from_string(e) < 0)
f0ea29ea 962 log_warning("Failed to parse log target '%s'. Ignoring.", e);
34f0e866 963
4db17f29 964 e = secure_getenv("SYSTEMD_LOG_LEVEL");
88fae6e0 965 if (e && log_set_max_level_from_string(e) < 0)
f0ea29ea 966 log_warning("Failed to parse log level '%s'. Ignoring.", e);
bbe63281 967
4db17f29 968 e = secure_getenv("SYSTEMD_LOG_COLOR");
88fae6e0 969 if (e && log_show_color_from_string(e) < 0)
f0ea29ea 970 log_warning("Failed to parse bool '%s'. Ignoring.", e);
bbe63281 971
4db17f29 972 e = secure_getenv("SYSTEMD_LOG_LOCATION");
88fae6e0 973 if (e && log_show_location_from_string(e) < 0)
f0ea29ea 974 log_warning("Failed to parse bool '%s'. Ignoring.", e);
34f0e866
LP
975}
976
1adf1049
LP
977LogTarget log_get_target(void) {
978 return log_target;
979}
980
981int log_get_max_level(void) {
982 return log_max_level;
983}
984
bbe63281
LP
985void log_show_color(bool b) {
986 show_color = b;
987}
988
b1e90ec5
ZJS
989bool log_get_show_color(void) {
990 return show_color;
991}
992
bbe63281
LP
993void log_show_location(bool b) {
994 show_location = b;
995}
996
b1e90ec5
ZJS
997bool log_get_show_location(void) {
998 return show_location;
999}
1000
bbe63281
LP
1001int log_show_color_from_string(const char *e) {
1002 int t;
1003
5ba081b0
LP
1004 t = parse_boolean(e);
1005 if (t < 0)
1006 return t;
bbe63281
LP
1007
1008 log_show_color(t);
1009 return 0;
1010}
1011
1012int log_show_location_from_string(const char *e) {
1013 int t;
1014
5ba081b0
LP
1015 t = parse_boolean(e);
1016 if (t < 0)
1017 return t;
bbe63281
LP
1018
1019 log_show_location(t);
1020 return 0;
1021}
1022
81270860 1023bool log_on_console(void) {
aca83a53
LP
1024 if (log_target == LOG_TARGET_CONSOLE ||
1025 log_target == LOG_TARGET_CONSOLE_PREFIXED)
81270860
LP
1026 return true;
1027
1028 return syslog_fd < 0 && kmsg_fd < 0 && journal_fd < 0;
1029}
1030
2c5859af 1031static const char *const log_target_table[_LOG_TARGET_MAX] = {
34f0e866 1032 [LOG_TARGET_CONSOLE] = "console",
aca83a53 1033 [LOG_TARGET_CONSOLE_PREFIXED] = "console-prefixed",
34f0e866 1034 [LOG_TARGET_KMSG] = "kmsg",
5ba081b0
LP
1035 [LOG_TARGET_JOURNAL] = "journal",
1036 [LOG_TARGET_JOURNAL_OR_KMSG] = "journal-or-kmsg",
1037 [LOG_TARGET_SYSLOG] = "syslog",
843d2643 1038 [LOG_TARGET_SYSLOG_OR_KMSG] = "syslog-or-kmsg",
5ba081b0 1039 [LOG_TARGET_AUTO] = "auto",
a6903061 1040 [LOG_TARGET_SAFE] = "safe",
5ba081b0 1041 [LOG_TARGET_NULL] = "null"
34f0e866
LP
1042};
1043
1044DEFINE_STRING_TABLE_LOOKUP(log_target, LogTarget);
4daf54a8
ZJS
1045
1046void log_received_signal(int level, const struct signalfd_siginfo *si) {
1047 if (si->ssi_pid > 0) {
1048 _cleanup_free_ char *p = NULL;
1049
1050 get_process_comm(si->ssi_pid, &p);
1051
1052 log_full(level,
1053 "Received SIG%s from PID "PID_FMT" (%s).",
1054 signal_to_string(si->ssi_signo),
1055 si->ssi_pid, strna(p));
1056 } else
1057 log_full(level,
1058 "Received SIG%s.",
1059 signal_to_string(si->ssi_signo));
1060
1061}
c1dc6153
LP
1062
1063void log_set_upgrade_syslog_to_journal(bool b) {
1064 upgrade_syslog_to_journal = b;
1065}