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