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