chiark / gitweb /
basic/log: fix confusion with parameters to log_dispatch_internal
[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                 (void) 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_field,
595                 const char *extra,
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         (void) 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 _printf_(10,0)
741 static int log_object_internalv(
742                 int level,
743                 int error,
744                 const char *file,
745                 int line,
746                 const char *func,
747                 const char *object_field,
748                 const char *object,
749                 const char *extra_field,
750                 const char *extra,
751                 const char *format,
752                 va_list ap) {
753
754         PROTECT_ERRNO;
755         char *buffer, *b;
756
757         if (error < 0)
758                 error = -error;
759
760         if (_likely_(LOG_PRI(level) > log_max_level[LOG_REALM_SYSTEMD]))
761                 return -error;
762
763         /* Make sure that %m maps to the specified error */
764         if (error != 0)
765                 errno = error;
766
767         /* Prepend the object name before the message */
768         if (object) {
769                 size_t n;
770
771                 n = strlen(object);
772                 buffer = newa(char, n + 2 + LINE_MAX);
773                 b = stpcpy(stpcpy(buffer, object), ": ");
774         } else
775                 b = buffer = newa(char, LINE_MAX);
776
777         (void) vsnprintf(b, LINE_MAX, format, ap);
778
779         return log_dispatch_internal(level, error, file, line, func,
780                                      object_field, object, extra_field, extra, buffer);
781 }
782
783 int log_object_internal(
784                 int level,
785                 int error,
786                 const char *file,
787                 int line,
788                 const char *func,
789                 const char *object_field,
790                 const char *object,
791                 const char *extra_field,
792                 const char *extra,
793                 const char *format, ...) {
794
795         va_list ap;
796         int r;
797
798         va_start(ap, format);
799         r = log_object_internalv(level, error, file, line, func, object_field, object, extra_field, extra, format, ap);
800         va_end(ap);
801
802         return r;
803 }
804
805 static void log_assert(
806                 int level,
807                 const char *text,
808                 const char *file,
809                 int line,
810                 const char *func,
811                 const char *format) {
812
813         static char buffer[LINE_MAX];
814         LogRealm realm = LOG_REALM_REMOVE_LEVEL(level);
815
816         if (_likely_(LOG_PRI(level) > log_max_level[realm]))
817                 return;
818
819         DISABLE_WARNING_FORMAT_NONLITERAL;
820         (void) snprintf(buffer, sizeof buffer, format, text, file, line, func);
821         REENABLE_WARNING;
822
823         log_abort_msg = buffer;
824
825         log_dispatch_internal(level, 0, file, line, func, NULL, NULL, NULL, NULL, buffer);
826 }
827
828 noreturn void log_assert_failed_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                    "Assertion '%s' failed at %s:%u, function %s(). Aborting.");
837         abort();
838 }
839
840 noreturn void log_assert_failed_unreachable_realm(
841                 LogRealm realm,
842                 const char *text,
843                 const char *file,
844                 int line,
845                 const char *func) {
846         log_open();
847         log_assert(LOG_REALM_PLUS_LEVEL(realm, LOG_CRIT), text, file, line, func,
848                    "Code should not be reached '%s' at %s:%u, function %s(). Aborting.");
849         abort();
850 }
851
852 void log_assert_failed_return_realm(
853                 LogRealm realm,
854                 const char *text,
855                 const char *file,
856                 int line,
857                 const char *func) {
858         PROTECT_ERRNO;
859         log_assert(LOG_REALM_PLUS_LEVEL(realm, LOG_DEBUG), text, file, line, func,
860                    "Assertion '%s' failed at %s:%u, function %s(). Ignoring.");
861 }
862
863 int log_oom_internal(LogRealm realm, const char *file, int line, const char *func) {
864         return log_internal_realm(LOG_REALM_PLUS_LEVEL(realm, LOG_ERR),
865                                   ENOMEM, file, line, func, "Out of memory.");
866 }
867
868 int log_format_iovec(
869                 struct iovec *iovec,
870                 size_t iovec_len,
871                 size_t *n,
872                 bool newline_separator,
873                 int error,
874                 const char *format,
875                 va_list ap) {
876
877         static const char nl = '\n';
878
879         while (format && *n + 1 < iovec_len) {
880                 va_list aq;
881                 char *m;
882                 int r;
883
884                 /* We need to copy the va_list structure,
885                  * since vasprintf() leaves it afterwards at
886                  * an undefined location */
887
888                 if (error != 0)
889                         errno = error;
890
891                 va_copy(aq, ap);
892                 r = vasprintf(&m, format, aq);
893                 va_end(aq);
894                 if (r < 0)
895                         return -EINVAL;
896
897                 /* Now, jump enough ahead, so that we point to
898                  * the next format string */
899                 VA_FORMAT_ADVANCE(format, ap);
900
901                 iovec[(*n)++] = IOVEC_MAKE_STRING(m);
902
903                 if (newline_separator) {
904                         iovec[*n].iov_base = (char*) &nl;
905                         iovec[*n].iov_len = 1;
906                         (*n)++;
907                 }
908
909                 format = va_arg(ap, char *);
910         }
911         return 0;
912 }
913
914 int log_struct_internal(
915                 int level,
916                 int error,
917                 const char *file,
918                 int line,
919                 const char *func,
920                 const char *format, ...) {
921
922         LogRealm realm = LOG_REALM_REMOVE_LEVEL(level);
923         char buf[LINE_MAX];
924         bool found = false;
925         PROTECT_ERRNO;
926         va_list ap;
927
928         if (error < 0)
929                 error = -error;
930
931         if (_likely_(LOG_PRI(level) > log_max_level[realm]))
932                 return -error;
933
934         if (log_target == LOG_TARGET_NULL)
935                 return -error;
936
937         if ((level & LOG_FACMASK) == 0)
938                 level = log_facility | LOG_PRI(level);
939
940 #if 0 /// elogind does not support logging to systemd-journald
941         if (IN_SET(log_target,
942                    LOG_TARGET_AUTO,
943                    LOG_TARGET_JOURNAL_OR_KMSG,
944                    LOG_TARGET_JOURNAL)) {
945
946                 if (open_when_needed)
947                         log_open_journal();
948
949                 if (journal_fd >= 0) {
950                         char header[LINE_MAX];
951                         struct iovec iovec[17] = {};
952                         size_t n = 0, i;
953                         int r;
954                         struct msghdr mh = {
955                                 .msg_iov = iovec,
956                         };
957                         bool fallback = false;
958
959                         /* If the journal is available do structured logging */
960                         log_do_header(header, sizeof(header), level, error, file, line, func, NULL, NULL, NULL, NULL);
961                         iovec[n++] = IOVEC_MAKE_STRING(header);
962
963                         va_start(ap, format);
964                         r = log_format_iovec(iovec, ELEMENTSOF(iovec), &n, true, error, format, ap);
965                         if (r < 0)
966                                 fallback = true;
967                         else {
968                                 mh.msg_iovlen = n;
969                                 (void) sendmsg(journal_fd, &mh, MSG_NOSIGNAL);
970                         }
971
972                         va_end(ap);
973                         for (i = 1; i < n; i += 2)
974                                 free(iovec[i].iov_base);
975
976                         if (!fallback) {
977                                 if (open_when_needed)
978                                         log_close();
979
980                                 return -error;
981                         }
982                 }
983         }
984 #endif // 0
985
986         /* Fallback if journal logging is not available or didn't work. */
987
988         va_start(ap, format);
989         while (format) {
990                 va_list aq;
991
992                 if (error != 0)
993                         errno = error;
994
995                 va_copy(aq, ap);
996                 (void) vsnprintf(buf, sizeof buf, format, aq);
997                 va_end(aq);
998
999                 if (startswith(buf, "MESSAGE=")) {
1000                         found = true;
1001                         break;
1002                 }
1003
1004                 VA_FORMAT_ADVANCE(format, ap);
1005
1006                 format = va_arg(ap, char *);
1007         }
1008         va_end(ap);
1009
1010         if (!found) {
1011                 if (open_when_needed)
1012                         log_close();
1013
1014                 return -error;
1015         }
1016
1017         return log_dispatch_internal(level, error, file, line, func, NULL, NULL, NULL, NULL, buf + 8);
1018 }
1019
1020 int log_struct_iovec_internal(
1021                 int level,
1022                 int error,
1023                 const char *file,
1024                 int line,
1025                 const char *func,
1026                 const struct iovec input_iovec[],
1027                 size_t n_input_iovec) {
1028
1029         LogRealm realm = LOG_REALM_REMOVE_LEVEL(level);
1030         PROTECT_ERRNO;
1031         size_t i;
1032         char *m;
1033
1034         if (error < 0)
1035                 error = -error;
1036
1037         if (_likely_(LOG_PRI(level) > log_max_level[realm]))
1038                 return -error;
1039
1040         if (log_target == LOG_TARGET_NULL)
1041                 return -error;
1042
1043         if ((level & LOG_FACMASK) == 0)
1044                 level = log_facility | LOG_PRI(level);
1045
1046         if (IN_SET(log_target, LOG_TARGET_AUTO,
1047                                LOG_TARGET_JOURNAL_OR_KMSG,
1048                                LOG_TARGET_JOURNAL) &&
1049             journal_fd >= 0) {
1050
1051                 struct iovec iovec[1 + n_input_iovec*2];
1052                 char header[LINE_MAX];
1053                 struct msghdr mh = {
1054                         .msg_iov = iovec,
1055                         .msg_iovlen = 1 + n_input_iovec*2,
1056                 };
1057
1058                 log_do_header(header, sizeof(header), level, error, file, line, func, NULL, NULL, NULL, NULL);
1059                 iovec[0] = IOVEC_MAKE_STRING(header);
1060
1061                 for (i = 0; i < n_input_iovec; i++) {
1062                         iovec[1+i*2] = input_iovec[i];
1063                         iovec[1+i*2+1] = IOVEC_MAKE_STRING("\n");
1064                 }
1065
1066                 if (sendmsg(journal_fd, &mh, MSG_NOSIGNAL) >= 0)
1067                         return -error;
1068         }
1069
1070         for (i = 0; i < n_input_iovec; i++) {
1071                 if (input_iovec[i].iov_len < STRLEN("MESSAGE="))
1072                         continue;
1073
1074                 if (memcmp(input_iovec[i].iov_base, "MESSAGE=", STRLEN("MESSAGE=")) == 0)
1075                         break;
1076         }
1077
1078         if (_unlikely_(i >= n_input_iovec)) /* Couldn't find MESSAGE=? */
1079                 return -error;
1080
1081         m = strndupa(input_iovec[i].iov_base + STRLEN("MESSAGE="),
1082                      input_iovec[i].iov_len - STRLEN("MESSAGE="));
1083
1084         return log_dispatch_internal(level, error, file, line, func, NULL, NULL, NULL, NULL, m);
1085 }
1086
1087 int log_set_target_from_string(const char *e) {
1088         LogTarget t;
1089
1090         t = log_target_from_string(e);
1091         if (t < 0)
1092                 return -EINVAL;
1093
1094         log_set_target(t);
1095         return 0;
1096 }
1097
1098 int log_set_max_level_from_string_realm(LogRealm realm, const char *e) {
1099         int t;
1100
1101         t = log_level_from_string(e);
1102         if (t < 0)
1103                 return -EINVAL;
1104
1105         log_set_max_level_realm(realm, t);
1106         return 0;
1107 }
1108
1109 static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
1110
1111         /*
1112          * The systemd.log_xyz= settings are parsed by all tools, and
1113          * so is "debug".
1114          *
1115          * However, "quiet" is only parsed by PID 1, and only turns of
1116          * status output to /dev/console, but does not alter the log
1117          * level.
1118          */
1119
1120         if (streq(key, "debug") && !value)
1121                 log_set_max_level(LOG_DEBUG);
1122
1123         else if (proc_cmdline_key_streq(key, "systemd.log_target")) {
1124
1125                 if (proc_cmdline_value_missing(key, value))
1126                         return 0;
1127
1128                 if (log_set_target_from_string(value) < 0)
1129                         log_warning("Failed to parse log target '%s'. Ignoring.", value);
1130
1131         } else if (proc_cmdline_key_streq(key, "systemd.log_level")) {
1132
1133                 if (proc_cmdline_value_missing(key, value))
1134                         return 0;
1135
1136                 if (log_set_max_level_from_string(value) < 0)
1137                         log_warning("Failed to parse log level '%s'. Ignoring.", value);
1138
1139         } else if (proc_cmdline_key_streq(key, "systemd.log_color")) {
1140
1141                 if (log_show_color_from_string(value ?: "1") < 0)
1142                         log_warning("Failed to parse log color setting '%s'. Ignoring.", value);
1143
1144         } else if (proc_cmdline_key_streq(key, "systemd.log_location")) {
1145
1146                 if (log_show_location_from_string(value ?: "1") < 0)
1147                         log_warning("Failed to parse log location setting '%s'. Ignoring.", value);
1148         }
1149
1150         return 0;
1151 }
1152
1153 void log_parse_environment_realm(LogRealm realm) {
1154         /* Do not call from library code. */
1155
1156         const char *e;
1157
1158         if (get_ctty_devnr(0, NULL) < 0)
1159                 /* Only try to read the command line in daemons.  We assume that anything that has a controlling tty is
1160                    user stuff. */
1161                 (void) proc_cmdline_parse(parse_proc_cmdline_item, NULL, PROC_CMDLINE_STRIP_RD_PREFIX);
1162
1163         e = getenv("SYSTEMD_LOG_TARGET");
1164         if (e && log_set_target_from_string(e) < 0)
1165                 log_warning("Failed to parse log target '%s'. Ignoring.", e);
1166
1167         e = getenv("SYSTEMD_LOG_LEVEL");
1168         if (e && log_set_max_level_from_string_realm(realm, e) < 0)
1169                 log_warning("Failed to parse log level '%s'. Ignoring.", e);
1170
1171         e = getenv("SYSTEMD_LOG_COLOR");
1172         if (e && log_show_color_from_string(e) < 0)
1173                 log_warning("Failed to parse bool '%s'. Ignoring.", e);
1174
1175         e = getenv("SYSTEMD_LOG_LOCATION");
1176         if (e && log_show_location_from_string(e) < 0)
1177                 log_warning("Failed to parse bool '%s'. Ignoring.", e);
1178 }
1179
1180 LogTarget log_get_target(void) {
1181         return log_target;
1182 }
1183
1184 int log_get_max_level_realm(LogRealm realm) {
1185         return log_max_level[realm];
1186 }
1187
1188 void log_show_color(bool b) {
1189         show_color = b;
1190 }
1191
1192 bool log_get_show_color(void) {
1193         return show_color;
1194 }
1195
1196 void log_show_location(bool b) {
1197         show_location = b;
1198 }
1199
1200 bool log_get_show_location(void) {
1201         return show_location;
1202 }
1203
1204 int log_show_color_from_string(const char *e) {
1205         int t;
1206
1207         t = parse_boolean(e);
1208         if (t < 0)
1209                 return t;
1210
1211         log_show_color(t);
1212         return 0;
1213 }
1214
1215 int log_show_location_from_string(const char *e) {
1216         int t;
1217
1218         t = parse_boolean(e);
1219         if (t < 0)
1220                 return t;
1221
1222         log_show_location(t);
1223         return 0;
1224 }
1225
1226 bool log_on_console(void) {
1227         if (IN_SET(log_target, LOG_TARGET_CONSOLE,
1228                                LOG_TARGET_CONSOLE_PREFIXED))
1229                 return true;
1230
1231         return syslog_fd < 0 && kmsg_fd < 0 && journal_fd < 0;
1232 }
1233
1234 static const char *const log_target_table[_LOG_TARGET_MAX] = {
1235         [LOG_TARGET_CONSOLE] = "console",
1236         [LOG_TARGET_CONSOLE_PREFIXED] = "console-prefixed",
1237         [LOG_TARGET_KMSG] = "kmsg",
1238 #if 0 /// elogind does not support logging to systemd-journald
1239         [LOG_TARGET_JOURNAL] = "journal",
1240         [LOG_TARGET_JOURNAL_OR_KMSG] = "journal-or-kmsg",
1241 #endif // 0
1242         [LOG_TARGET_SYSLOG] = "syslog",
1243         [LOG_TARGET_SYSLOG_OR_KMSG] = "syslog-or-kmsg",
1244         [LOG_TARGET_AUTO] = "auto",
1245         [LOG_TARGET_NULL] = "null",
1246 };
1247
1248 DEFINE_STRING_TABLE_LOOKUP(log_target, LogTarget);
1249
1250 #if 0 /// UNNEEDED by elogind
1251 void log_received_signal(int level, const struct signalfd_siginfo *si) {
1252         assert(si);
1253
1254         if (pid_is_valid(si->ssi_pid)) {
1255                 _cleanup_free_ char *p = NULL;
1256
1257                 (void) get_process_comm(si->ssi_pid, &p);
1258
1259                 log_full(level,
1260                          "Received SIG%s from PID %"PRIu32" (%s).",
1261                          signal_to_string(si->ssi_signo),
1262                          si->ssi_pid, strna(p));
1263         } else
1264                 log_full(level,
1265                          "Received SIG%s.",
1266                          signal_to_string(si->ssi_signo));
1267 }
1268
1269 #endif // 0
1270 int log_syntax_internal(
1271                 const char *unit,
1272                 int level,
1273                 const char *config_file,
1274                 unsigned config_line,
1275                 int error,
1276                 const char *file,
1277                 int line,
1278                 const char *func,
1279                 const char *format, ...) {
1280
1281         PROTECT_ERRNO;
1282         char buffer[LINE_MAX];
1283         va_list ap;
1284         const char *unit_fmt = NULL;
1285
1286         if (error < 0)
1287                 error = -error;
1288
1289         if (_likely_(LOG_PRI(level) > log_max_level[LOG_REALM_SYSTEMD]))
1290                 return -error;
1291
1292         if (log_target == LOG_TARGET_NULL)
1293                 return -error;
1294
1295         if (error != 0)
1296                 errno = error;
1297
1298         va_start(ap, format);
1299         (void) vsnprintf(buffer, sizeof buffer, format, ap);
1300         va_end(ap);
1301
1302         if (unit)
1303                 unit_fmt = getpid_cached() == 1 ? "UNIT=%s" : "USER_UNIT=%s";
1304
1305         return log_struct_internal(
1306                         LOG_REALM_PLUS_LEVEL(LOG_REALM_SYSTEMD, level),
1307                         error,
1308                         file, line, func,
1309                         "MESSAGE_ID=" SD_MESSAGE_INVALID_CONFIGURATION_STR,
1310                         "CONFIG_FILE=%s", config_file,
1311                         "CONFIG_LINE=%u", config_line,
1312                         LOG_MESSAGE("%s:%u: %s", config_file, config_line, buffer),
1313                         unit_fmt, unit,
1314                         NULL);
1315 }
1316
1317 int log_syntax_invalid_utf8_internal(
1318                 const char *unit,
1319                 int level,
1320                 const char *config_file,
1321                 unsigned config_line,
1322                 const char *file,
1323                 int line,
1324                 const char *func,
1325                 const char *rvalue) {
1326
1327         _cleanup_free_ char *p = NULL;
1328
1329         if (rvalue)
1330                 p = utf8_escape_invalid(rvalue);
1331
1332         log_syntax_internal(unit, level, config_file, config_line, 0, file, line, func,
1333                             "String is not UTF-8 clean, ignoring assignment: %s", strna(p));
1334
1335         return -EINVAL;
1336 }
1337
1338 #if 0 /// UNNEEDED by elogind
1339 void log_set_upgrade_syslog_to_journal(bool b) {
1340         upgrade_syslog_to_journal = b;
1341
1342         /* Make the change effective immediately */
1343         if (b) {
1344                 if (log_target == LOG_TARGET_SYSLOG)
1345                         log_target = LOG_TARGET_JOURNAL;
1346                 else if (log_target == LOG_TARGET_SYSLOG_OR_KMSG)
1347                         log_target = LOG_TARGET_JOURNAL_OR_KMSG;
1348         }
1349 }
1350
1351 void log_set_always_reopen_console(bool b) {
1352         always_reopen_console = b;
1353 }
1354 #endif // 0
1355
1356 void log_set_open_when_needed(bool b) {
1357         open_when_needed = b;
1358 }
1359
1360 void log_set_prohibit_ipc(bool b) {
1361         prohibit_ipc = b;
1362 }
1363
1364 int log_emergency_level(void) {
1365         /* Returns the log level to use for log_emergency() logging. We use LOG_EMERG only when we are PID 1, as only
1366          * then the system of the whole system is obviously affected. */
1367
1368         return getpid_cached() == 1 ? LOG_EMERG : LOG_ERR;
1369 }