]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/log.c
log: pass the correct length to vsnprintf (#6168)
[thirdparty/systemd.git] / src / basic / log.c
CommitLineData
a7334b09
LP
1/***
2 This file is part of systemd.
3
4 Copyright 2010 Lennart Poettering
5
6 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
a7334b09
LP
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 14 Lesser General Public License for more details.
a7334b09 15
5430f7f2 16 You should have received a copy of the GNU Lesser General Public License
a7334b09
LP
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18***/
19
c9b97d2a 20#include <errno.h>
16801e90 21#include <fcntl.h>
11c3a366
TA
22#include <inttypes.h>
23#include <limits.h>
07630cea
LP
24#include <stdarg.h>
25#include <stddef.h>
26#include <stdio.h>
11c3a366
TA
27#include <string.h>
28#include <sys/signalfd.h>
16801e90 29#include <sys/socket.h>
11c3a366
TA
30#include <sys/time.h>
31#include <sys/uio.h>
16801e90 32#include <sys/un.h>
11c3a366 33#include <time.h>
07630cea 34#include <unistd.h>
5899f3b7 35
158350e8 36#include "sd-messages.h"
07630cea 37
b5efdb8a 38#include "alloc-util.h"
3ffd4af2 39#include "fd-util.h"
f97b34a6 40#include "format-util.h"
afc5dbf3 41#include "io-util.h"
3ffd4af2 42#include "log.h"
07630cea
LP
43#include "macro.h"
44#include "missing.h"
4e731273
LP
45#include "parse-util.h"
46#include "proc-cmdline.h"
0b452006 47#include "process-util.h"
24882e06 48#include "signal-util.h"
07630cea 49#include "socket-util.h"
15a5e950 50#include "stdio-util.h"
8b43440b 51#include "string-table.h"
07630cea 52#include "string-util.h"
7ccbd1ae 53#include "syslog-util.h"
07630cea 54#include "terminal-util.h"
93cc7779 55#include "time-util.h"
07630cea 56#include "util.h"
5899f3b7 57
bb99a35a
LP
58#define SNDBUF_SIZE (8*1024*1024)
59
16801e90 60static LogTarget log_target = LOG_TARGET_CONSOLE;
ff524019
ZJS
61static int log_max_level[] = {LOG_INFO, LOG_INFO};
62assert_cc(ELEMENTSOF(log_max_level) == _LOG_REALM_MAX);
3eff4208 63static int log_facility = LOG_DAEMON;
16801e90 64
843d2643 65static int console_fd = STDERR_FILENO;
16801e90
LP
66static int syslog_fd = -1;
67static int kmsg_fd = -1;
5ba081b0 68static int journal_fd = -1;
16801e90 69
c31e1495
LP
70static bool syslog_is_stream = false;
71
bbe63281
LP
72static bool show_color = false;
73static bool show_location = false;
74
c1dc6153 75static bool upgrade_syslog_to_journal = false;
48a601fe 76static bool always_reopen_console = false;
c1dc6153 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 99
48a601fe 100 if (always_reopen_console) {
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
0474ef7b 138 (void) fd_inc_sndbuf(fd, SNDBUF_SIZE);
bb99a35a 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
fc2fffe7 170 if (connect(syslog_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 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
fc2fffe7 182 if (connect(syslog_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 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
fc2fffe7 220 if (connect(journal_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) {
5ba081b0
LP
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
5b5688af 248 if (!IN_SET(log_target, LOG_TARGET_AUTO, LOG_TARGET_SAFE) ||
bb7df0da 249 getpid() == 1 ||
f41c094c 250 isatty(STDERR_FILENO) <= 0) {
bb7df0da 251
5b5688af
ZJS
252 if (IN_SET(log_target, LOG_TARGET_AUTO,
253 LOG_TARGET_JOURNAL_OR_KMSG,
254 LOG_TARGET_JOURNAL)) {
5ba081b0
LP
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
5b5688af
ZJS
263 if (IN_SET(log_target, LOG_TARGET_SYSLOG_OR_KMSG,
264 LOG_TARGET_SYSLOG)) {
5ba081b0
LP
265 r = log_open_syslog();
266 if (r >= 0) {
267 log_close_journal();
268 log_close_console();
269 return r;
270 }
271 }
272
5b5688af
ZJS
273 if (IN_SET(log_target, LOG_TARGET_AUTO,
274 LOG_TARGET_SAFE,
275 LOG_TARGET_JOURNAL_OR_KMSG,
276 LOG_TARGET_SYSLOG_OR_KMSG,
277 LOG_TARGET_KMSG)) {
5ba081b0
LP
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
ff524019 319void log_set_max_level_realm(LogRealm realm, int level) {
16801e90 320 assert((level & LOG_PRIMASK) == level);
ff524019 321 assert(realm < ELEMENTSOF(log_max_level));
16801e90 322
ff524019 323 log_max_level[realm] = level;
16801e90
LP
324}
325
3eff4208
LP
326void log_set_facility(int facility) {
327 log_facility = facility;
328}
329
843d2643 330static int write_to_console(
20c03b7b 331 int level,
086891e5 332 int error,
95066a90 333 const char *file,
20c03b7b
LP
334 int line,
335 const char *func,
336 const char *buffer) {
5899f3b7 337
79c95440 338 char location[256], prefix[1 + DECIMAL_STR_MAX(int) + 2];
aca83a53 339 struct iovec iovec[6] = {};
843d2643
LP
340 unsigned n = 0;
341 bool highlight;
5899f3b7 342
843d2643
LP
343 if (console_fd < 0)
344 return 0;
345
aca83a53 346 if (log_target == LOG_TARGET_CONSOLE_PREFIXED) {
0474ef7b 347 xsprintf(prefix, "<%i>", level);
aca83a53
LP
348 IOVEC_SET_STRING(iovec[n++], prefix);
349 }
350
bbe63281 351 highlight = LOG_PRI(level) <= LOG_ERR && show_color;
843d2643 352
674f8283 353 if (show_location) {
79c95440 354 snprintf(location, sizeof(location), "(%s:%i) ", file, line);
bbe63281 355 IOVEC_SET_STRING(iovec[n++], location);
674f8283
LP
356 }
357
843d2643 358 if (highlight)
1fc464f6 359 IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_RED);
843d2643
LP
360 IOVEC_SET_STRING(iovec[n++], buffer);
361 if (highlight)
1fc464f6 362 IOVEC_SET_STRING(iovec[n++], ANSI_NORMAL);
843d2643
LP
363 IOVEC_SET_STRING(iovec[n++], "\n");
364
0e6eaa2d
LP
365 if (writev(console_fd, iovec, n) < 0) {
366
367 if (errno == EIO && getpid() == 1) {
368
369 /* If somebody tried to kick us from our
370 * console tty (via vhangup() or suchlike),
371 * try to reconnect */
372
373 log_close_console();
374 log_open_console();
375
376 if (console_fd < 0)
377 return 0;
378
379 if (writev(console_fd, iovec, n) < 0)
380 return -errno;
381 } else
382 return -errno;
383 }
5899f3b7 384
843d2643 385 return 1;
16801e90 386}
5899f3b7 387
16801e90 388static int write_to_syslog(
086891e5
LP
389 int level,
390 int error,
95066a90 391 const char *file,
086891e5
LP
392 int line,
393 const char *func,
086891e5 394 const char *buffer) {
16801e90 395
5ffa8c81
ZJS
396 char header_priority[2 + DECIMAL_STR_MAX(int) + 1],
397 header_time[64],
398 header_pid[4 + DECIMAL_STR_MAX(pid_t) + 1];
b92bea5d
ZJS
399 struct iovec iovec[5] = {};
400 struct msghdr msghdr = {
401 .msg_iov = iovec,
402 .msg_iovlen = ELEMENTSOF(iovec),
403 };
16801e90
LP
404 time_t t;
405 struct tm *tm;
406
407 if (syslog_fd < 0)
843d2643 408 return 0;
16801e90 409
5ffa8c81 410 xsprintf(header_priority, "<%i>", level);
16801e90
LP
411
412 t = (time_t) (now(CLOCK_REALTIME) / USEC_PER_SEC);
fdf9f9bb
ZJS
413 tm = localtime(&t);
414 if (!tm)
16801e90
LP
415 return -EINVAL;
416
417 if (strftime(header_time, sizeof(header_time), "%h %e %T ", tm) <= 0)
418 return -EINVAL;
419
5ffa8c81 420 xsprintf(header_pid, "["PID_FMT"]: ", getpid());
16801e90 421
16801e90
LP
422 IOVEC_SET_STRING(iovec[0], header_priority);
423 IOVEC_SET_STRING(iovec[1], header_time);
5b6319dc 424 IOVEC_SET_STRING(iovec[2], program_invocation_short_name);
16801e90
LP
425 IOVEC_SET_STRING(iovec[3], header_pid);
426 IOVEC_SET_STRING(iovec[4], buffer);
427
c899f8c6 428 /* When using syslog via SOCK_STREAM separate the messages by NUL chars */
c31e1495
LP
429 if (syslog_is_stream)
430 iovec[4].iov_len++;
431
c31e1495
LP
432 for (;;) {
433 ssize_t n;
434
8f7f7a1b
MS
435 n = sendmsg(syslog_fd, &msghdr, MSG_NOSIGNAL);
436 if (n < 0)
c31e1495
LP
437 return -errno;
438
439 if (!syslog_is_stream ||
440 (size_t) n >= IOVEC_TOTAL_SIZE(iovec, ELEMENTSOF(iovec)))
441 break;
442
443 IOVEC_INCREMENT(iovec, ELEMENTSOF(iovec), n);
444 }
16801e90 445
843d2643 446 return 1;
16801e90
LP
447}
448
449static int write_to_kmsg(
086891e5
LP
450 int level,
451 int error,
bcf5c276 452 const char *file,
086891e5
LP
453 int line,
454 const char *func,
086891e5 455 const char *buffer) {
16801e90 456
5ffa8c81
ZJS
457 char header_priority[2 + DECIMAL_STR_MAX(int) + 1],
458 header_pid[4 + DECIMAL_STR_MAX(pid_t) + 1];
b92bea5d 459 struct iovec iovec[5] = {};
16801e90
LP
460
461 if (kmsg_fd < 0)
843d2643 462 return 0;
16801e90 463
5ffa8c81
ZJS
464 xsprintf(header_priority, "<%i>", level);
465 xsprintf(header_pid, "["PID_FMT"]: ", getpid());
16801e90 466
16801e90 467 IOVEC_SET_STRING(iovec[0], header_priority);
5b6319dc 468 IOVEC_SET_STRING(iovec[1], program_invocation_short_name);
16801e90
LP
469 IOVEC_SET_STRING(iovec[2], header_pid);
470 IOVEC_SET_STRING(iovec[3], buffer);
843d2643 471 IOVEC_SET_STRING(iovec[4], "\n");
16801e90
LP
472
473 if (writev(kmsg_fd, iovec, ELEMENTSOF(iovec)) < 0)
474 return -errno;
475
843d2643 476 return 1;
16801e90
LP
477}
478
086891e5
LP
479static int log_do_header(
480 char *header,
481 size_t size,
482 int level,
483 int error,
484 const char *file, int line, const char *func,
4b58153d
LP
485 const char *object_field, const char *object,
486 const char *extra_field, const char *extra) {
086891e5 487
41a79f10 488 snprintf(header, size,
5ba081b0 489 "PRIORITY=%i\n"
3eff4208 490 "SYSLOG_FACILITY=%i\n"
086891e5 491 "%s%s%s"
e429981b 492 "%s%.*i%s"
086891e5
LP
493 "%s%s%s"
494 "%s%.*i%s"
495 "%s%s%s"
4b58153d 496 "%s%s%s"
41a79f10 497 "SYSLOG_IDENTIFIER=%s\n",
5ba081b0 498 LOG_PRI(level),
3eff4208 499 LOG_FAC(level),
086891e5
LP
500 isempty(file) ? "" : "CODE_FILE=",
501 isempty(file) ? "" : file,
502 isempty(file) ? "" : "\n",
e429981b
ZJS
503 line ? "CODE_LINE=" : "",
504 line ? 1 : 0, line, /* %.0d means no output too, special case for 0 */
505 line ? "\n" : "",
b457b33d 506 isempty(func) ? "" : "CODE_FUNC=",
086891e5
LP
507 isempty(func) ? "" : func,
508 isempty(func) ? "" : "\n",
509 error ? "ERRNO=" : "",
510 error ? 1 : 0, error,
511 error ? "\n" : "",
512 isempty(object) ? "" : object_field,
513 isempty(object) ? "" : object,
514 isempty(object) ? "" : "\n",
4b58153d
LP
515 isempty(extra) ? "" : extra_field,
516 isempty(extra) ? "" : extra,
517 isempty(extra) ? "" : "\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,
4b58153d
LP
531 const char *extra_field,
532 const char *extra,
086891e5 533 const char *buffer) {
41a79f10
ZJS
534
535 char header[LINE_MAX];
b92bea5d
ZJS
536 struct iovec iovec[4] = {};
537 struct msghdr mh = {};
41a79f10
ZJS
538
539 if (journal_fd < 0)
540 return 0;
541
4b58153d 542 log_do_header(header, sizeof(header), level, error, file, line, func, object_field, object, extra_field, extra);
5ba081b0 543
5ba081b0 544 IOVEC_SET_STRING(iovec[0], header);
41a79f10
ZJS
545 IOVEC_SET_STRING(iovec[1], "MESSAGE=");
546 IOVEC_SET_STRING(iovec[2], buffer);
547 IOVEC_SET_STRING(iovec[3], "\n");
5ba081b0 548
5ba081b0
LP
549 mh.msg_iov = iovec;
550 mh.msg_iovlen = ELEMENTSOF(iovec);
551
552 if (sendmsg(journal_fd, &mh, MSG_NOSIGNAL) < 0)
553 return -errno;
554
555 return 1;
556}
557
93484b47 558int log_dispatch_internal(
086891e5
LP
559 int level,
560 int error,
95066a90 561 const char *file,
086891e5
LP
562 int line,
563 const char *func,
564 const char *object_field,
565 const char *object,
4b58153d
LP
566 const char *extra,
567 const char *extra_field,
086891e5 568 char *buffer) {
843d2643 569
bf371116 570 assert(buffer);
843d2643 571
0474ef7b
LP
572 if (error < 0)
573 error = -error;
574
9fae33d2 575 if (log_target == LOG_TARGET_NULL)
bf371116 576 return -error;
9fae33d2 577
29db5834 578 /* Patch in LOG_DAEMON facility if necessary */
7d76f312 579 if ((level & LOG_FACMASK) == 0)
3eff4208 580 level = log_facility | LOG_PRI(level);
29db5834 581
9726b29e
LP
582 do {
583 char *e;
9499b235 584 int k = 0;
843d2643 585
9726b29e 586 buffer += strspn(buffer, NEWLINE);
843d2643 587
9726b29e
LP
588 if (buffer[0] == 0)
589 break;
843d2643 590
9726b29e
LP
591 if ((e = strpbrk(buffer, NEWLINE)))
592 *(e++) = 0;
843d2643 593
5b5688af
ZJS
594 if (IN_SET(log_target, LOG_TARGET_AUTO,
595 LOG_TARGET_JOURNAL_OR_KMSG,
596 LOG_TARGET_JOURNAL)) {
5ba081b0 597
4b58153d 598 k = write_to_journal(level, error, file, line, func, object_field, object, extra_field, extra, buffer);
4e7bc3f3
LP
599 if (k < 0) {
600 if (k != -EAGAIN)
5ba081b0
LP
601 log_close_journal();
602 log_open_kmsg();
bf371116 603 }
5ba081b0
LP
604 }
605
5b5688af
ZJS
606 if (IN_SET(log_target, LOG_TARGET_SYSLOG_OR_KMSG,
607 LOG_TARGET_SYSLOG)) {
9726b29e 608
4b58153d 609 k = write_to_syslog(level, error, file, line, func, buffer);
4e7bc3f3
LP
610 if (k < 0) {
611 if (k != -EAGAIN)
8f7f7a1b 612 log_close_syslog();
9726b29e 613 log_open_kmsg();
bf371116 614 }
9726b29e
LP
615 }
616
9499b235 617 if (k <= 0 &&
5b5688af
ZJS
618 IN_SET(log_target, LOG_TARGET_AUTO,
619 LOG_TARGET_SAFE,
620 LOG_TARGET_SYSLOG_OR_KMSG,
621 LOG_TARGET_JOURNAL_OR_KMSG,
622 LOG_TARGET_KMSG)) {
9726b29e 623
4b58153d 624 k = write_to_kmsg(level, error, file, line, func, buffer);
4e7bc3f3
LP
625 if (k < 0) {
626 log_close_kmsg();
9726b29e 627 log_open_console();
bf371116 628 }
9726b29e
LP
629 }
630
bf371116 631 if (k <= 0)
4b58153d 632 (void) write_to_console(level, error, file, line, func, buffer);
9726b29e
LP
633
634 buffer = e;
635 } while (buffer);
636
bf371116 637 return -error;
843d2643
LP
638}
639
2149e37c 640int log_dump_internal(
ff524019
ZJS
641 int level,
642 int error,
643 const char *file,
644 int line,
645 const char *func,
646 char *buffer) {
2149e37c 647
ff524019 648 LogRealm realm = LOG_REALM_REMOVE_LEVEL(level);
5c0aa72a 649 PROTECT_ERRNO;
2149e37c
LP
650
651 /* This modifies the buffer... */
652
bf371116
LP
653 if (error < 0)
654 error = -error;
655
ff524019 656 if (_likely_(LOG_PRI(level) > log_max_level[realm]))
bf371116 657 return -error;
2149e37c 658
93484b47 659 return log_dispatch_internal(level, error, file, line, func, NULL, NULL, NULL, NULL, buffer);
2149e37c
LP
660}
661
ff524019 662int log_internalv_realm(
086891e5
LP
663 int level,
664 int error,
bcf5c276 665 const char *file,
086891e5
LP
666 int line,
667 const char *func,
668 const char *format,
669 va_list ap) {
16801e90 670
ff524019 671 LogRealm realm = LOG_REALM_REMOVE_LEVEL(level);
addab137 672 char buffer[LINE_MAX];
ff524019 673 PROTECT_ERRNO;
16801e90 674
bf371116
LP
675 if (error < 0)
676 error = -error;
677
ff524019 678 if (_likely_(LOG_PRI(level) > log_max_level[realm]))
bf371116 679 return -error;
16801e90 680
086891e5
LP
681 /* Make sure that %m maps to the specified error */
682 if (error != 0)
bf371116 683 errno = error;
086891e5 684
843d2643 685 vsnprintf(buffer, sizeof(buffer), format, ap);
843d2643 686
93484b47 687 return log_dispatch_internal(level, error, file, line, func, NULL, NULL, NULL, NULL, buffer);
185986c6 688}
16801e90 689
ff524019 690int log_internal_realm(
086891e5
LP
691 int level,
692 int error,
bcf5c276 693 const char *file,
086891e5
LP
694 int line,
695 const char *func,
696 const char *format, ...) {
17a94911 697
17a94911 698 va_list ap;
bf371116 699 int r;
17a94911
LP
700
701 va_start(ap, format);
ff524019 702 r = log_internalv_realm(level, error, file, line, func, format, ap);
17a94911
LP
703 va_end(ap);
704
705 return r;
706}
707
79008bdd 708int log_object_internalv(
086891e5
LP
709 int level,
710 int error,
bcf5c276 711 const char *file,
086891e5
LP
712 int line,
713 const char *func,
714 const char *object_field,
715 const char *object,
4b58153d
LP
716 const char *extra_field,
717 const char *extra,
086891e5
LP
718 const char *format,
719 va_list ap) {
fdf9f9bb 720
5c0aa72a 721 PROTECT_ERRNO;
f2341e0a 722 char *buffer, *b;
fdf9f9bb 723
bf371116
LP
724 if (error < 0)
725 error = -error;
726
ff524019 727 if (_likely_(LOG_PRI(level) > log_max_level[LOG_REALM_SYSTEMD]))
bf371116 728 return -error;
fdf9f9bb 729
086891e5
LP
730 /* Make sure that %m maps to the specified error */
731 if (error != 0)
bf371116 732 errno = error;
086891e5 733
f2341e0a
LP
734 /* Prepend the object name before the message */
735 if (object) {
736 size_t n;
737
738 n = strlen(object);
1741b25c 739 buffer = newa(char, n + 2 + LINE_MAX);
f2341e0a 740 b = stpcpy(stpcpy(buffer, object), ": ");
1741b25c
EV
741 } else
742 b = buffer = newa(char, LINE_MAX);
f2341e0a 743
1741b25c 744 vsnprintf(b, LINE_MAX, format, ap);
fdf9f9bb 745
93484b47
ZJS
746 return log_dispatch_internal(level, error, file, line, func,
747 object_field, object, extra_field, extra, buffer);
fdf9f9bb
ZJS
748}
749
79008bdd 750int log_object_internal(
086891e5
LP
751 int level,
752 int error,
bcf5c276 753 const char *file,
086891e5
LP
754 int line,
755 const char *func,
756 const char *object_field,
757 const char *object,
4b58153d
LP
758 const char *extra_field,
759 const char *extra,
086891e5 760 const char *format, ...) {
fdf9f9bb 761
fdf9f9bb 762 va_list ap;
bf371116 763 int r;
fdf9f9bb
ZJS
764
765 va_start(ap, format);
4b58153d 766 r = log_object_internalv(level, error, file, line, func, object_field, object, extra_field, extra, format, ap);
fdf9f9bb
ZJS
767 va_end(ap);
768
769 return r;
770}
771
086891e5
LP
772static void log_assert(
773 int level,
774 const char *text,
775 const char *file,
776 int line,
777 const char *func,
778 const char *format) {
779
addab137 780 static char buffer[LINE_MAX];
ff524019 781 LogRealm realm = LOG_REALM_REMOVE_LEVEL(level);
185986c6 782
ff524019 783 if (_likely_(LOG_PRI(level) > log_max_level[realm]))
50f72bca
ZJS
784 return;
785
bcfce235 786 DISABLE_WARNING_FORMAT_NONLITERAL;
e68eedbb 787 snprintf(buffer, sizeof buffer, format, text, file, line, func);
bcfce235 788 REENABLE_WARNING;
185986c6 789
185986c6
LP
790 log_abort_msg = buffer;
791
93484b47 792 log_dispatch_internal(level, 0, file, line, func, NULL, NULL, NULL, NULL, buffer);
5899f3b7 793}
34f0e866 794
ff524019
ZJS
795noreturn void log_assert_failed_realm(
796 LogRealm realm,
797 const char *text,
798 const char *file,
799 int line,
800 const char *func) {
801 log_assert(LOG_REALM_PLUS_LEVEL(realm, LOG_CRIT), text, file, line, func,
802 "Assertion '%s' failed at %s:%u, function %s(). Aborting.");
80514f9c 803 abort();
b7f33638
MS
804}
805
ff524019
ZJS
806noreturn void log_assert_failed_unreachable_realm(
807 LogRealm realm,
808 const char *text,
809 const char *file,
810 int line,
811 const char *func) {
812 log_assert(LOG_REALM_PLUS_LEVEL(realm, LOG_CRIT), text, file, line, func,
813 "Code should not be reached '%s' at %s:%u, function %s(). Aborting.");
80514f9c
LP
814 abort();
815}
816
ff524019
ZJS
817void log_assert_failed_return_realm(
818 LogRealm realm,
819 const char *text,
820 const char *file,
821 int line,
822 const char *func) {
e5ca092c 823 PROTECT_ERRNO;
ff524019
ZJS
824 log_assert(LOG_REALM_PLUS_LEVEL(realm, LOG_DEBUG), text, file, line, func,
825 "Assertion '%s' failed at %s:%u, function %s(). Ignoring.");
b7f33638
MS
826}
827
ff524019
ZJS
828int log_oom_internal(LogRealm realm, const char *file, int line, const char *func) {
829 log_internal_realm(LOG_REALM_PLUS_LEVEL(realm, LOG_ERR),
830 ENOMEM, file, line, func, "Out of memory.");
6dc1e7e0
MS
831 return -ENOMEM;
832}
833
8a03c9ef
ZJS
834int log_format_iovec(
835 struct iovec *iovec,
836 unsigned iovec_len,
837 unsigned *n,
838 bool newline_separator,
839 int error,
840 const char *format,
841 va_list ap) {
842
843 static const char nl = '\n';
844
845 while (format && *n + 1 < iovec_len) {
846 va_list aq;
847 char *m;
848 int r;
849
850 /* We need to copy the va_list structure,
851 * since vasprintf() leaves it afterwards at
852 * an undefined location */
853
854 if (error != 0)
855 errno = error;
856
857 va_copy(aq, ap);
858 r = vasprintf(&m, format, aq);
859 va_end(aq);
860 if (r < 0)
861 return -EINVAL;
862
863 /* Now, jump enough ahead, so that we point to
864 * the next format string */
865 VA_FORMAT_ADVANCE(format, ap);
866
867 IOVEC_SET_STRING(iovec[(*n)++], m);
868
869 if (newline_separator) {
870 iovec[*n].iov_base = (char*) &nl;
871 iovec[*n].iov_len = 1;
872 (*n)++;
873 }
874
875 format = va_arg(ap, char *);
876 }
877 return 0;
878}
879
877d54e9
LP
880int log_struct_internal(
881 int level,
086891e5 882 int error,
877d54e9
LP
883 const char *file,
884 int line,
885 const char *func,
886 const char *format, ...) {
887
bf371116
LP
888 char buf[LINE_MAX];
889 bool found = false;
ff524019 890 LogRealm realm = LOG_REALM_REMOVE_LEVEL(level);
5c0aa72a 891 PROTECT_ERRNO;
877d54e9 892 va_list ap;
bf371116
LP
893
894 if (error < 0)
895 error = -error;
877d54e9 896
ff524019 897 if (_likely_(LOG_PRI(level) > log_max_level[realm]))
bf371116 898 return -error;
877d54e9
LP
899
900 if (log_target == LOG_TARGET_NULL)
bf371116 901 return -error;
877d54e9
LP
902
903 if ((level & LOG_FACMASK) == 0)
904 level = log_facility | LOG_PRI(level);
905
5b5688af
ZJS
906 if (IN_SET(log_target, LOG_TARGET_AUTO,
907 LOG_TARGET_JOURNAL_OR_KMSG,
908 LOG_TARGET_JOURNAL) &&
877d54e9 909 journal_fd >= 0) {
877d54e9 910 char header[LINE_MAX];
b92bea5d 911 struct iovec iovec[17] = {};
877d54e9 912 unsigned n = 0, i;
8a03c9ef 913 int r;
543295ad
ZJS
914 struct msghdr mh = {
915 .msg_iov = iovec,
916 };
bf371116 917 bool fallback = false;
877d54e9
LP
918
919 /* If the journal is available do structured logging */
4b58153d 920 log_do_header(header, sizeof(header), level, error, file, line, func, NULL, NULL, NULL, NULL);
877d54e9
LP
921 IOVEC_SET_STRING(iovec[n++], header);
922
923 va_start(ap, format);
8a03c9ef
ZJS
924 r = log_format_iovec(iovec, ELEMENTSOF(iovec), &n, true, error, format, ap);
925 if (r < 0)
926 fallback = true;
927 else {
928 mh.msg_iovlen = n;
929 (void) sendmsg(journal_fd, &mh, MSG_NOSIGNAL);
877d54e9 930 }
877d54e9 931
e98055de 932 va_end(ap);
877d54e9
LP
933 for (i = 1; i < n; i += 2)
934 free(iovec[i].iov_base);
935
bf371116
LP
936 if (!fallback)
937 return -error;
938 }
877d54e9 939
bf371116 940 /* Fallback if journal logging is not available or didn't work. */
6357ac66 941
bf371116
LP
942 va_start(ap, format);
943 while (format) {
944 va_list aq;
877d54e9 945
bf371116
LP
946 if (error != 0)
947 errno = error;
877d54e9 948
bf371116
LP
949 va_copy(aq, ap);
950 vsnprintf(buf, sizeof(buf), format, aq);
951 va_end(aq);
963ddb91 952
bf371116
LP
953 if (startswith(buf, "MESSAGE=")) {
954 found = true;
955 break;
877d54e9 956 }
877d54e9 957
bf371116
LP
958 VA_FORMAT_ADVANCE(format, ap);
959
960 format = va_arg(ap, char *);
877d54e9 961 }
bf371116 962 va_end(ap);
877d54e9 963
bf371116
LP
964 if (!found)
965 return -error;
966
93484b47 967 return log_dispatch_internal(level, error, file, line, func, NULL, NULL, NULL, NULL, buf + 8);
877d54e9
LP
968}
969
34f0e866
LP
970int log_set_target_from_string(const char *e) {
971 LogTarget t;
972
5ba081b0
LP
973 t = log_target_from_string(e);
974 if (t < 0)
34f0e866
LP
975 return -EINVAL;
976
977 log_set_target(t);
978 return 0;
979}
980
ff524019 981int log_set_max_level_from_string_realm(LogRealm realm, const char *e) {
34f0e866
LP
982 int t;
983
5ba081b0
LP
984 t = log_level_from_string(e);
985 if (t < 0)
737af734 986 return -EINVAL;
34f0e866 987
ff524019 988 log_set_max_level_realm(realm, t);
34f0e866
LP
989 return 0;
990}
991
96287a49 992static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
1de1c9c3
LP
993
994 /*
995 * The systemd.log_xyz= settings are parsed by all tools, and
996 * so is "debug".
997 *
5e07a79e
LP
998 * However, "quiet" is only parsed by PID 1, and only turns of
999 * status output to /dev/console, but does not alter the log
1000 * level.
1de1c9c3
LP
1001 */
1002
1003 if (streq(key, "debug") && !value)
1004 log_set_max_level(LOG_DEBUG);
1005
1d84ad94
LP
1006 else if (proc_cmdline_key_streq(key, "systemd.log_target")) {
1007
1008 if (proc_cmdline_value_missing(key, value))
1009 return 0;
1de1c9c3
LP
1010
1011 if (log_set_target_from_string(value) < 0)
1012 log_warning("Failed to parse log target '%s'. Ignoring.", value);
1013
1d84ad94
LP
1014 } else if (proc_cmdline_key_streq(key, "systemd.log_level")) {
1015
1016 if (proc_cmdline_value_missing(key, value))
1017 return 0;
1de1c9c3
LP
1018
1019 if (log_set_max_level_from_string(value) < 0)
1020 log_warning("Failed to parse log level '%s'. Ignoring.", value);
1021
1d84ad94 1022 } else if (proc_cmdline_key_streq(key, "systemd.log_color")) {
1de1c9c3 1023
1d84ad94 1024 if (log_show_color_from_string(value ?: "1") < 0)
1de1c9c3
LP
1025 log_warning("Failed to parse log color setting '%s'. Ignoring.", value);
1026
1d84ad94 1027 } else if (proc_cmdline_key_streq(key, "systemd.log_location")) {
1de1c9c3 1028
1d84ad94 1029 if (log_show_location_from_string(value ?: "1") < 0)
1de1c9c3
LP
1030 log_warning("Failed to parse log location setting '%s'. Ignoring.", value);
1031 }
1032
1033 return 0;
1034}
1035
ff524019 1036void log_parse_environment_realm(LogRealm realm) {
34f0e866 1037 const char *e;
b8d0ffc2 1038
ee46e555 1039 if (get_ctty_devnr(0, NULL) < 0)
1d84ad94
LP
1040 /* Only try to read the command line in daemons. We assume that anything that has a controlling tty is
1041 user stuff. */
1042 (void) proc_cmdline_parse(parse_proc_cmdline_item, NULL, PROC_CMDLINE_STRIP_RD_PREFIX);
34f0e866 1043
4db17f29 1044 e = secure_getenv("SYSTEMD_LOG_TARGET");
88fae6e0 1045 if (e && log_set_target_from_string(e) < 0)
f0ea29ea 1046 log_warning("Failed to parse log target '%s'. Ignoring.", e);
34f0e866 1047
4db17f29 1048 e = secure_getenv("SYSTEMD_LOG_LEVEL");
ff524019 1049 if (e && log_set_max_level_from_string_realm(realm, e) < 0)
f0ea29ea 1050 log_warning("Failed to parse log level '%s'. Ignoring.", e);
bbe63281 1051
4db17f29 1052 e = secure_getenv("SYSTEMD_LOG_COLOR");
88fae6e0 1053 if (e && log_show_color_from_string(e) < 0)
f0ea29ea 1054 log_warning("Failed to parse bool '%s'. Ignoring.", e);
bbe63281 1055
4db17f29 1056 e = secure_getenv("SYSTEMD_LOG_LOCATION");
88fae6e0 1057 if (e && log_show_location_from_string(e) < 0)
f0ea29ea 1058 log_warning("Failed to parse bool '%s'. Ignoring.", e);
34f0e866
LP
1059}
1060
1adf1049
LP
1061LogTarget log_get_target(void) {
1062 return log_target;
1063}
1064
ff524019
ZJS
1065int log_get_max_level_realm(LogRealm realm) {
1066 return log_max_level[realm];
1adf1049
LP
1067}
1068
bbe63281
LP
1069void log_show_color(bool b) {
1070 show_color = b;
1071}
1072
b1e90ec5
ZJS
1073bool log_get_show_color(void) {
1074 return show_color;
1075}
1076
bbe63281
LP
1077void log_show_location(bool b) {
1078 show_location = b;
1079}
1080
b1e90ec5
ZJS
1081bool log_get_show_location(void) {
1082 return show_location;
1083}
1084
bbe63281
LP
1085int log_show_color_from_string(const char *e) {
1086 int t;
1087
5ba081b0
LP
1088 t = parse_boolean(e);
1089 if (t < 0)
1090 return t;
bbe63281
LP
1091
1092 log_show_color(t);
1093 return 0;
1094}
1095
1096int log_show_location_from_string(const char *e) {
1097 int t;
1098
5ba081b0
LP
1099 t = parse_boolean(e);
1100 if (t < 0)
1101 return t;
bbe63281
LP
1102
1103 log_show_location(t);
1104 return 0;
1105}
1106
81270860 1107bool log_on_console(void) {
5b5688af
ZJS
1108 if (IN_SET(log_target, LOG_TARGET_CONSOLE,
1109 LOG_TARGET_CONSOLE_PREFIXED))
81270860
LP
1110 return true;
1111
1112 return syslog_fd < 0 && kmsg_fd < 0 && journal_fd < 0;
1113}
1114
2c5859af 1115static const char *const log_target_table[_LOG_TARGET_MAX] = {
34f0e866 1116 [LOG_TARGET_CONSOLE] = "console",
aca83a53 1117 [LOG_TARGET_CONSOLE_PREFIXED] = "console-prefixed",
34f0e866 1118 [LOG_TARGET_KMSG] = "kmsg",
5ba081b0
LP
1119 [LOG_TARGET_JOURNAL] = "journal",
1120 [LOG_TARGET_JOURNAL_OR_KMSG] = "journal-or-kmsg",
1121 [LOG_TARGET_SYSLOG] = "syslog",
843d2643 1122 [LOG_TARGET_SYSLOG_OR_KMSG] = "syslog-or-kmsg",
5ba081b0 1123 [LOG_TARGET_AUTO] = "auto",
a6903061 1124 [LOG_TARGET_SAFE] = "safe",
5ba081b0 1125 [LOG_TARGET_NULL] = "null"
34f0e866
LP
1126};
1127
1128DEFINE_STRING_TABLE_LOOKUP(log_target, LogTarget);
4daf54a8
ZJS
1129
1130void log_received_signal(int level, const struct signalfd_siginfo *si) {
1131 if (si->ssi_pid > 0) {
1132 _cleanup_free_ char *p = NULL;
1133
1134 get_process_comm(si->ssi_pid, &p);
1135
1136 log_full(level,
1fa2f38f 1137 "Received SIG%s from PID %"PRIu32" (%s).",
4daf54a8
ZJS
1138 signal_to_string(si->ssi_signo),
1139 si->ssi_pid, strna(p));
1140 } else
1141 log_full(level,
1142 "Received SIG%s.",
1143 signal_to_string(si->ssi_signo));
1144
1145}
c1dc6153
LP
1146
1147void log_set_upgrade_syslog_to_journal(bool b) {
1148 upgrade_syslog_to_journal = b;
1149}
158350e8
LP
1150
1151int log_syntax_internal(
1152 const char *unit,
1153 int level,
1154 const char *config_file,
1155 unsigned config_line,
1156 int error,
1157 const char *file,
1158 int line,
1159 const char *func,
1160 const char *format, ...) {
1161
1162 PROTECT_ERRNO;
1163 char buffer[LINE_MAX];
158350e8 1164 va_list ap;
c2dec702 1165 const char *unit_fmt = NULL;
158350e8
LP
1166
1167 if (error < 0)
1168 error = -error;
1169
ff524019 1170 if (_likely_(LOG_PRI(level) > log_max_level[LOG_REALM_SYSTEMD]))
158350e8
LP
1171 return -error;
1172
1173 if (log_target == LOG_TARGET_NULL)
1174 return -error;
1175
1176 if (error != 0)
1177 errno = error;
1178
1179 va_start(ap, format);
1180 vsnprintf(buffer, sizeof(buffer), format, ap);
1181 va_end(ap);
1182
1183 if (unit)
c2dec702
ZJS
1184 unit_fmt = getpid() == 1 ? "UNIT=%s" : "USER_UNIT=%s";
1185
1186 return log_struct_internal(
ff524019
ZJS
1187 LOG_REALM_PLUS_LEVEL(LOG_REALM_SYSTEMD, level),
1188 error,
c2dec702 1189 file, line, func,
2b044526 1190 "MESSAGE_ID=" SD_MESSAGE_INVALID_CONFIGURATION_STR,
c2dec702
ZJS
1191 "CONFIG_FILE=%s", config_file,
1192 "CONFIG_LINE=%u", config_line,
e697dfef 1193 LOG_MESSAGE("%s:%u: %s", config_file, config_line, buffer),
c2dec702
ZJS
1194 unit_fmt, unit,
1195 NULL);
158350e8 1196}
48a601fe
LP
1197
1198void log_set_always_reopen_console(bool b) {
1199 always_reopen_console = b;
1200}