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