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