chiark / gitweb /
basic/log: make sure header is printed correctly, add test
[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         int r;
514
515         r = snprintf(header, size,
516                      "PRIORITY=%i\n"
517                      "SYSLOG_FACILITY=%i\n"
518                      "%s%.256s%s"        /* CODE_FILE */
519                      "%s%.*i%s"          /* CODE_LINE */
520                      "%s%.256s%s"        /* CODE_FUNC */
521                      "%s%.*i%s"          /* ERRNO */
522                      "%s%.256s%s"        /* object */
523                      "%s%.256s%s"        /* extra */
524                      "SYSLOG_IDENTIFIER=%.256s\n",
525                      LOG_PRI(level),
526                      LOG_FAC(level),
527                      isempty(file) ? "" : "CODE_FILE=",
528                      isempty(file) ? "" : file,
529                      isempty(file) ? "" : "\n",
530                      line ? "CODE_LINE=" : "",
531                      line ? 1 : 0, line, /* %.0d means no output too, special case for 0 */
532                      line ? "\n" : "",
533                      isempty(func) ? "" : "CODE_FUNC=",
534                      isempty(func) ? "" : func,
535                      isempty(func) ? "" : "\n",
536                      error ? "ERRNO=" : "",
537                      error ? 1 : 0, error,
538                      error ? "\n" : "",
539                      isempty(object) ? "" : object_field,
540                      isempty(object) ? "" : object,
541                      isempty(object) ? "" : "\n",
542                      isempty(extra) ? "" : extra_field,
543                      isempty(extra) ? "" : extra,
544                      isempty(extra) ? "" : "\n",
545                      program_invocation_short_name);
546         assert((size_t) r < size);
547
548         return 0;
549 }
550
551 #if 0 /// UNNEEDED by elogind
552 static int write_to_journal(
553                 int level,
554                 int error,
555                 const char *file,
556                 int line,
557                 const char *func,
558                 const char *object_field,
559                 const char *object,
560                 const char *extra_field,
561                 const char *extra,
562                 const char *buffer) {
563
564         char header[LINE_MAX];
565         struct iovec iovec[4] = {};
566         struct msghdr mh = {};
567
568         if (journal_fd < 0)
569                 return 0;
570
571         log_do_header(header, sizeof(header), level, error, file, line, func, object_field, object, extra_field, extra);
572
573         iovec[0] = IOVEC_MAKE_STRING(header);
574         iovec[1] = IOVEC_MAKE_STRING("MESSAGE=");
575         iovec[2] = IOVEC_MAKE_STRING(buffer);
576         iovec[3] = IOVEC_MAKE_STRING("\n");
577
578         mh.msg_iov = iovec;
579         mh.msg_iovlen = ELEMENTSOF(iovec);
580
581         if (sendmsg(journal_fd, &mh, MSG_NOSIGNAL) < 0)
582                 return -errno;
583
584         return 1;
585 }
586 #endif // 0
587
588 int log_dispatch_internal(
589                 int level,
590                 int error,
591                 const char *file,
592                 int line,
593                 const char *func,
594                 const char *object_field,
595                 const char *object,
596                 const char *extra_field,
597                 const char *extra,
598                 char *buffer) {
599
600         assert(buffer);
601
602         if (error < 0)
603                 error = -error;
604
605         if (log_target == LOG_TARGET_NULL)
606                 return -error;
607
608         /* Patch in LOG_DAEMON facility if necessary */
609         if ((level & LOG_FACMASK) == 0)
610                 level = log_facility | LOG_PRI(level);
611
612         if (open_when_needed)
613                 log_open();
614
615         do {
616                 char *e;
617                 int k = 0;
618
619                 buffer += strspn(buffer, NEWLINE);
620
621                 if (buffer[0] == 0)
622                         break;
623
624                 if ((e = strpbrk(buffer, NEWLINE)))
625                         *(e++) = 0;
626
627 #if 0 /// elogind does not support logging to systemd-journald
628                 if (IN_SET(log_target, LOG_TARGET_AUTO,
629                                        LOG_TARGET_JOURNAL_OR_KMSG,
630                                        LOG_TARGET_JOURNAL)) {
631
632                         k = write_to_journal(level, error, file, line, func, object_field, object, extra_field, extra, buffer);
633                         if (k < 0 && k != -EAGAIN)
634                                 log_close_journal();
635                 }
636 #endif // 0
637
638                 if (IN_SET(log_target, LOG_TARGET_SYSLOG_OR_KMSG,
639                                        LOG_TARGET_SYSLOG)) {
640
641                         k = write_to_syslog(level, error, file, line, func, buffer);
642                         if (k < 0 && k != -EAGAIN)
643                                 log_close_syslog();
644                 }
645
646                 if (k <= 0 &&
647                     IN_SET(log_target, LOG_TARGET_AUTO,
648                                        LOG_TARGET_SYSLOG_OR_KMSG,
649                                        LOG_TARGET_JOURNAL_OR_KMSG,
650                                        LOG_TARGET_KMSG)) {
651
652                         if (k < 0)
653                                 log_open_kmsg();
654
655                         k = write_to_kmsg(level, error, file, line, func, buffer);
656                         if (k < 0) {
657                                 log_close_kmsg();
658                                 log_open_console();
659                         }
660                 }
661
662                 if (k <= 0)
663                         (void) write_to_console(level, error, file, line, func, buffer);
664
665                 buffer = e;
666         } while (buffer);
667
668         if (open_when_needed)
669                 log_close();
670
671         return -error;
672 }
673
674 int log_dump_internal(
675                 int level,
676                 int error,
677                 const char *file,
678                 int line,
679                 const char *func,
680                 char *buffer) {
681
682         LogRealm realm = LOG_REALM_REMOVE_LEVEL(level);
683         PROTECT_ERRNO;
684
685         /* This modifies the buffer... */
686
687         if (error < 0)
688                 error = -error;
689
690         if (_likely_(LOG_PRI(level) > log_max_level[realm]))
691                 return -error;
692
693         return log_dispatch_internal(level, error, file, line, func, NULL, NULL, NULL, NULL, buffer);
694 }
695
696 int log_internalv_realm(
697                 int level,
698                 int error,
699                 const char *file,
700                 int line,
701                 const char *func,
702                 const char *format,
703                 va_list ap) {
704
705         LogRealm realm = LOG_REALM_REMOVE_LEVEL(level);
706         char buffer[LINE_MAX];
707         PROTECT_ERRNO;
708
709         if (error < 0)
710                 error = -error;
711
712         if (_likely_(LOG_PRI(level) > log_max_level[realm]))
713                 return -error;
714
715         /* Make sure that %m maps to the specified error */
716         if (error != 0)
717                 errno = error;
718
719         (void) vsnprintf(buffer, sizeof buffer, format, ap);
720
721         return log_dispatch_internal(level, error, file, line, func, NULL, NULL, NULL, NULL, buffer);
722 }
723
724 int log_internal_realm(
725                 int level,
726                 int error,
727                 const char *file,
728                 int line,
729                 const char *func,
730                 const char *format, ...) {
731
732         va_list ap;
733         int r;
734
735         va_start(ap, format);
736         r = log_internalv_realm(level, error, file, line, func, format, ap);
737         va_end(ap);
738
739         return r;
740 }
741
742 _printf_(10,0)
743 static int log_object_internalv(
744                 int level,
745                 int error,
746                 const char *file,
747                 int line,
748                 const char *func,
749                 const char *object_field,
750                 const char *object,
751                 const char *extra_field,
752                 const char *extra,
753                 const char *format,
754                 va_list ap) {
755
756         PROTECT_ERRNO;
757         char *buffer, *b;
758
759         if (error < 0)
760                 error = -error;
761
762         if (_likely_(LOG_PRI(level) > log_max_level[LOG_REALM_SYSTEMD]))
763                 return -error;
764
765         /* Make sure that %m maps to the specified error */
766         if (error != 0)
767                 errno = error;
768
769         /* Prepend the object name before the message */
770         if (object) {
771                 size_t n;
772
773                 n = strlen(object);
774                 buffer = newa(char, n + 2 + LINE_MAX);
775                 b = stpcpy(stpcpy(buffer, object), ": ");
776         } else
777                 b = buffer = newa(char, LINE_MAX);
778
779         (void) vsnprintf(b, LINE_MAX, format, ap);
780
781         return log_dispatch_internal(level, error, file, line, func,
782                                      object_field, object, extra_field, extra, buffer);
783 }
784
785 int log_object_internal(
786                 int level,
787                 int error,
788                 const char *file,
789                 int line,
790                 const char *func,
791                 const char *object_field,
792                 const char *object,
793                 const char *extra_field,
794                 const char *extra,
795                 const char *format, ...) {
796
797         va_list ap;
798         int r;
799
800         va_start(ap, format);
801         r = log_object_internalv(level, error, file, line, func, object_field, object, extra_field, extra, format, ap);
802         va_end(ap);
803
804         return r;
805 }
806
807 static void log_assert(
808                 int level,
809                 const char *text,
810                 const char *file,
811                 int line,
812                 const char *func,
813                 const char *format) {
814
815         static char buffer[LINE_MAX];
816         LogRealm realm = LOG_REALM_REMOVE_LEVEL(level);
817
818         if (_likely_(LOG_PRI(level) > log_max_level[realm]))
819                 return;
820
821         DISABLE_WARNING_FORMAT_NONLITERAL;
822         (void) snprintf(buffer, sizeof buffer, format, text, file, line, func);
823         REENABLE_WARNING;
824
825         log_abort_msg = buffer;
826
827         log_dispatch_internal(level, 0, file, line, func, NULL, NULL, NULL, NULL, buffer);
828 }
829
830 noreturn void log_assert_failed_realm(
831                 LogRealm realm,
832                 const char *text,
833                 const char *file,
834                 int line,
835                 const char *func) {
836         log_open();
837         log_assert(LOG_REALM_PLUS_LEVEL(realm, LOG_CRIT), text, file, line, func,
838                    "Assertion '%s' failed at %s:%u, function %s(). Aborting.");
839         abort();
840 }
841
842 noreturn void log_assert_failed_unreachable_realm(
843                 LogRealm realm,
844                 const char *text,
845                 const char *file,
846                 int line,
847                 const char *func) {
848         log_open();
849         log_assert(LOG_REALM_PLUS_LEVEL(realm, LOG_CRIT), text, file, line, func,
850                    "Code should not be reached '%s' at %s:%u, function %s(). Aborting.");
851         abort();
852 }
853
854 void log_assert_failed_return_realm(
855                 LogRealm realm,
856                 const char *text,
857                 const char *file,
858                 int line,
859                 const char *func) {
860         PROTECT_ERRNO;
861         log_assert(LOG_REALM_PLUS_LEVEL(realm, LOG_DEBUG), text, file, line, func,
862                    "Assertion '%s' failed at %s:%u, function %s(). Ignoring.");
863 }
864
865 int log_oom_internal(LogRealm realm, const char *file, int line, const char *func) {
866         return log_internal_realm(LOG_REALM_PLUS_LEVEL(realm, LOG_ERR),
867                                   ENOMEM, file, line, func, "Out of memory.");
868 }
869
870 int log_format_iovec(
871                 struct iovec *iovec,
872                 size_t iovec_len,
873                 size_t *n,
874                 bool newline_separator,
875                 int error,
876                 const char *format,
877                 va_list ap) {
878
879         static const char nl = '\n';
880
881         while (format && *n + 1 < iovec_len) {
882                 va_list aq;
883                 char *m;
884                 int r;
885
886                 /* We need to copy the va_list structure,
887                  * since vasprintf() leaves it afterwards at
888                  * an undefined location */
889
890                 if (error != 0)
891                         errno = error;
892
893                 va_copy(aq, ap);
894                 r = vasprintf(&m, format, aq);
895                 va_end(aq);
896                 if (r < 0)
897                         return -EINVAL;
898
899                 /* Now, jump enough ahead, so that we point to
900                  * the next format string */
901                 VA_FORMAT_ADVANCE(format, ap);
902
903                 iovec[(*n)++] = IOVEC_MAKE_STRING(m);
904
905                 if (newline_separator) {
906                         iovec[*n].iov_base = (char*) &nl;
907                         iovec[*n].iov_len = 1;
908                         (*n)++;
909                 }
910
911                 format = va_arg(ap, char *);
912         }
913         return 0;
914 }
915
916 int log_struct_internal(
917                 int level,
918                 int error,
919                 const char *file,
920                 int line,
921                 const char *func,
922                 const char *format, ...) {
923
924         LogRealm realm = LOG_REALM_REMOVE_LEVEL(level);
925         char buf[LINE_MAX];
926         bool found = false;
927         PROTECT_ERRNO;
928         va_list ap;
929
930         if (error < 0)
931                 error = -error;
932
933         if (_likely_(LOG_PRI(level) > log_max_level[realm]))
934                 return -error;
935
936         if (log_target == LOG_TARGET_NULL)
937                 return -error;
938
939         if ((level & LOG_FACMASK) == 0)
940                 level = log_facility | LOG_PRI(level);
941
942 #if 0 /// elogind does not support logging to systemd-journald
943         if (IN_SET(log_target,
944                    LOG_TARGET_AUTO,
945                    LOG_TARGET_JOURNAL_OR_KMSG,
946                    LOG_TARGET_JOURNAL)) {
947
948                 if (open_when_needed)
949                         log_open_journal();
950
951                 if (journal_fd >= 0) {
952                         char header[LINE_MAX];
953                         struct iovec iovec[17] = {};
954                         size_t n = 0, i;
955                         int r;
956                         struct msghdr mh = {
957                                 .msg_iov = iovec,
958                         };
959                         bool fallback = false;
960
961                         /* If the journal is available do structured logging */
962                         log_do_header(header, sizeof(header), level, error, file, line, func, NULL, NULL, NULL, NULL);
963                         iovec[n++] = IOVEC_MAKE_STRING(header);
964
965                         va_start(ap, format);
966                         r = log_format_iovec(iovec, ELEMENTSOF(iovec), &n, true, error, format, ap);
967                         if (r < 0)
968                                 fallback = true;
969                         else {
970                                 mh.msg_iovlen = n;
971                                 (void) sendmsg(journal_fd, &mh, MSG_NOSIGNAL);
972                         }
973
974                         va_end(ap);
975                         for (i = 1; i < n; i += 2)
976                                 free(iovec[i].iov_base);
977
978                         if (!fallback) {
979                                 if (open_when_needed)
980                                         log_close();
981
982                                 return -error;
983                         }
984                 }
985         }
986 #endif // 0
987
988         /* Fallback if journal logging is not available or didn't work. */
989
990         va_start(ap, format);
991         while (format) {
992                 va_list aq;
993
994                 if (error != 0)
995                         errno = error;
996
997                 va_copy(aq, ap);
998                 (void) vsnprintf(buf, sizeof buf, format, aq);
999                 va_end(aq);
1000
1001                 if (startswith(buf, "MESSAGE=")) {
1002                         found = true;
1003                         break;
1004                 }
1005
1006                 VA_FORMAT_ADVANCE(format, ap);
1007
1008                 format = va_arg(ap, char *);
1009         }
1010         va_end(ap);
1011
1012         if (!found) {
1013                 if (open_when_needed)
1014                         log_close();
1015
1016                 return -error;
1017         }
1018
1019         return log_dispatch_internal(level, error, file, line, func, NULL, NULL, NULL, NULL, buf + 8);
1020 }
1021
1022 int log_struct_iovec_internal(
1023                 int level,
1024                 int error,
1025                 const char *file,
1026                 int line,
1027                 const char *func,
1028                 const struct iovec input_iovec[],
1029                 size_t n_input_iovec) {
1030
1031         LogRealm realm = LOG_REALM_REMOVE_LEVEL(level);
1032         PROTECT_ERRNO;
1033         size_t i;
1034         char *m;
1035
1036         if (error < 0)
1037                 error = -error;
1038
1039         if (_likely_(LOG_PRI(level) > log_max_level[realm]))
1040                 return -error;
1041
1042         if (log_target == LOG_TARGET_NULL)
1043                 return -error;
1044
1045         if ((level & LOG_FACMASK) == 0)
1046                 level = log_facility | LOG_PRI(level);
1047
1048         if (IN_SET(log_target, LOG_TARGET_AUTO,
1049                                LOG_TARGET_JOURNAL_OR_KMSG,
1050                                LOG_TARGET_JOURNAL) &&
1051             journal_fd >= 0) {
1052
1053                 struct iovec iovec[1 + n_input_iovec*2];
1054                 char header[LINE_MAX];
1055                 struct msghdr mh = {
1056                         .msg_iov = iovec,
1057                         .msg_iovlen = 1 + n_input_iovec*2,
1058                 };
1059
1060                 log_do_header(header, sizeof(header), level, error, file, line, func, NULL, NULL, NULL, NULL);
1061                 iovec[0] = IOVEC_MAKE_STRING(header);
1062
1063                 for (i = 0; i < n_input_iovec; i++) {
1064                         iovec[1+i*2] = input_iovec[i];
1065                         iovec[1+i*2+1] = IOVEC_MAKE_STRING("\n");
1066                 }
1067
1068                 if (sendmsg(journal_fd, &mh, MSG_NOSIGNAL) >= 0)
1069                         return -error;
1070         }
1071
1072         for (i = 0; i < n_input_iovec; i++) {
1073                 if (input_iovec[i].iov_len < STRLEN("MESSAGE="))
1074                         continue;
1075
1076                 if (memcmp(input_iovec[i].iov_base, "MESSAGE=", STRLEN("MESSAGE=")) == 0)
1077                         break;
1078         }
1079
1080         if (_unlikely_(i >= n_input_iovec)) /* Couldn't find MESSAGE=? */
1081                 return -error;
1082
1083         m = strndupa(input_iovec[i].iov_base + STRLEN("MESSAGE="),
1084                      input_iovec[i].iov_len - STRLEN("MESSAGE="));
1085
1086         return log_dispatch_internal(level, error, file, line, func, NULL, NULL, NULL, NULL, m);
1087 }
1088
1089 int log_set_target_from_string(const char *e) {
1090         LogTarget t;
1091
1092         t = log_target_from_string(e);
1093         if (t < 0)
1094                 return -EINVAL;
1095
1096         log_set_target(t);
1097         return 0;
1098 }
1099
1100 int log_set_max_level_from_string_realm(LogRealm realm, const char *e) {
1101         int t;
1102
1103         t = log_level_from_string(e);
1104         if (t < 0)
1105                 return -EINVAL;
1106
1107         log_set_max_level_realm(realm, t);
1108         return 0;
1109 }
1110
1111 static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
1112
1113         /*
1114          * The systemd.log_xyz= settings are parsed by all tools, and
1115          * so is "debug".
1116          *
1117          * However, "quiet" is only parsed by PID 1, and only turns of
1118          * status output to /dev/console, but does not alter the log
1119          * level.
1120          */
1121
1122         if (streq(key, "debug") && !value)
1123                 log_set_max_level(LOG_DEBUG);
1124
1125         else if (proc_cmdline_key_streq(key, "systemd.log_target")) {
1126
1127                 if (proc_cmdline_value_missing(key, value))
1128                         return 0;
1129
1130                 if (log_set_target_from_string(value) < 0)
1131                         log_warning("Failed to parse log target '%s'. Ignoring.", value);
1132
1133         } else if (proc_cmdline_key_streq(key, "systemd.log_level")) {
1134
1135                 if (proc_cmdline_value_missing(key, value))
1136                         return 0;
1137
1138                 if (log_set_max_level_from_string(value) < 0)
1139                         log_warning("Failed to parse log level '%s'. Ignoring.", value);
1140
1141         } else if (proc_cmdline_key_streq(key, "systemd.log_color")) {
1142
1143                 if (log_show_color_from_string(value ?: "1") < 0)
1144                         log_warning("Failed to parse log color setting '%s'. Ignoring.", value);
1145
1146         } else if (proc_cmdline_key_streq(key, "systemd.log_location")) {
1147
1148                 if (log_show_location_from_string(value ?: "1") < 0)
1149                         log_warning("Failed to parse log location setting '%s'. Ignoring.", value);
1150         }
1151
1152         return 0;
1153 }
1154
1155 void log_parse_environment_realm(LogRealm realm) {
1156         /* Do not call from library code. */
1157
1158         const char *e;
1159
1160         if (get_ctty_devnr(0, NULL) < 0)
1161                 /* Only try to read the command line in daemons.  We assume that anything that has a controlling tty is
1162                    user stuff. */
1163                 (void) proc_cmdline_parse(parse_proc_cmdline_item, NULL, PROC_CMDLINE_STRIP_RD_PREFIX);
1164
1165         e = getenv("SYSTEMD_LOG_TARGET");
1166         if (e && log_set_target_from_string(e) < 0)
1167                 log_warning("Failed to parse log target '%s'. Ignoring.", e);
1168
1169         e = getenv("SYSTEMD_LOG_LEVEL");
1170         if (e && log_set_max_level_from_string_realm(realm, e) < 0)
1171                 log_warning("Failed to parse log level '%s'. Ignoring.", e);
1172
1173         e = getenv("SYSTEMD_LOG_COLOR");
1174         if (e && log_show_color_from_string(e) < 0)
1175                 log_warning("Failed to parse bool '%s'. Ignoring.", e);
1176
1177         e = getenv("SYSTEMD_LOG_LOCATION");
1178         if (e && log_show_location_from_string(e) < 0)
1179                 log_warning("Failed to parse bool '%s'. Ignoring.", e);
1180 }
1181
1182 LogTarget log_get_target(void) {
1183         return log_target;
1184 }
1185
1186 int log_get_max_level_realm(LogRealm realm) {
1187         return log_max_level[realm];
1188 }
1189
1190 void log_show_color(bool b) {
1191         show_color = b;
1192 }
1193
1194 bool log_get_show_color(void) {
1195         return show_color;
1196 }
1197
1198 void log_show_location(bool b) {
1199         show_location = b;
1200 }
1201
1202 bool log_get_show_location(void) {
1203         return show_location;
1204 }
1205
1206 int log_show_color_from_string(const char *e) {
1207         int t;
1208
1209         t = parse_boolean(e);
1210         if (t < 0)
1211                 return t;
1212
1213         log_show_color(t);
1214         return 0;
1215 }
1216
1217 int log_show_location_from_string(const char *e) {
1218         int t;
1219
1220         t = parse_boolean(e);
1221         if (t < 0)
1222                 return t;
1223
1224         log_show_location(t);
1225         return 0;
1226 }
1227
1228 bool log_on_console(void) {
1229         if (IN_SET(log_target, LOG_TARGET_CONSOLE,
1230                                LOG_TARGET_CONSOLE_PREFIXED))
1231                 return true;
1232
1233         return syslog_fd < 0 && kmsg_fd < 0 && journal_fd < 0;
1234 }
1235
1236 static const char *const log_target_table[_LOG_TARGET_MAX] = {
1237         [LOG_TARGET_CONSOLE] = "console",
1238         [LOG_TARGET_CONSOLE_PREFIXED] = "console-prefixed",
1239         [LOG_TARGET_KMSG] = "kmsg",
1240 #if 0 /// elogind does not support logging to systemd-journald
1241         [LOG_TARGET_JOURNAL] = "journal",
1242         [LOG_TARGET_JOURNAL_OR_KMSG] = "journal-or-kmsg",
1243 #endif // 0
1244         [LOG_TARGET_SYSLOG] = "syslog",
1245         [LOG_TARGET_SYSLOG_OR_KMSG] = "syslog-or-kmsg",
1246         [LOG_TARGET_AUTO] = "auto",
1247         [LOG_TARGET_NULL] = "null",
1248 };
1249
1250 DEFINE_STRING_TABLE_LOOKUP(log_target, LogTarget);
1251
1252 #if 0 /// UNNEEDED by elogind
1253 void log_received_signal(int level, const struct signalfd_siginfo *si) {
1254         assert(si);
1255
1256         if (pid_is_valid(si->ssi_pid)) {
1257                 _cleanup_free_ char *p = NULL;
1258
1259                 (void) get_process_comm(si->ssi_pid, &p);
1260
1261                 log_full(level,
1262                          "Received SIG%s from PID %"PRIu32" (%s).",
1263                          signal_to_string(si->ssi_signo),
1264                          si->ssi_pid, strna(p));
1265         } else
1266                 log_full(level,
1267                          "Received SIG%s.",
1268                          signal_to_string(si->ssi_signo));
1269 }
1270
1271 #endif // 0
1272 int log_syntax_internal(
1273                 const char *unit,
1274                 int level,
1275                 const char *config_file,
1276                 unsigned config_line,
1277                 int error,
1278                 const char *file,
1279                 int line,
1280                 const char *func,
1281                 const char *format, ...) {
1282
1283         PROTECT_ERRNO;
1284         char buffer[LINE_MAX];
1285         va_list ap;
1286         const char *unit_fmt = NULL;
1287
1288         if (error < 0)
1289                 error = -error;
1290
1291         if (_likely_(LOG_PRI(level) > log_max_level[LOG_REALM_SYSTEMD]))
1292                 return -error;
1293
1294         if (log_target == LOG_TARGET_NULL)
1295                 return -error;
1296
1297         if (error != 0)
1298                 errno = error;
1299
1300         va_start(ap, format);
1301         (void) vsnprintf(buffer, sizeof buffer, format, ap);
1302         va_end(ap);
1303
1304         if (unit)
1305                 unit_fmt = getpid_cached() == 1 ? "UNIT=%s" : "USER_UNIT=%s";
1306
1307         return log_struct_internal(
1308                         LOG_REALM_PLUS_LEVEL(LOG_REALM_SYSTEMD, level),
1309                         error,
1310                         file, line, func,
1311                         "MESSAGE_ID=" SD_MESSAGE_INVALID_CONFIGURATION_STR,
1312                         "CONFIG_FILE=%s", config_file,
1313                         "CONFIG_LINE=%u", config_line,
1314                         LOG_MESSAGE("%s:%u: %s", config_file, config_line, buffer),
1315                         unit_fmt, unit,
1316                         NULL);
1317 }
1318
1319 int log_syntax_invalid_utf8_internal(
1320                 const char *unit,
1321                 int level,
1322                 const char *config_file,
1323                 unsigned config_line,
1324                 const char *file,
1325                 int line,
1326                 const char *func,
1327                 const char *rvalue) {
1328
1329         _cleanup_free_ char *p = NULL;
1330
1331         if (rvalue)
1332                 p = utf8_escape_invalid(rvalue);
1333
1334         log_syntax_internal(unit, level, config_file, config_line, 0, file, line, func,
1335                             "String is not UTF-8 clean, ignoring assignment: %s", strna(p));
1336
1337         return -EINVAL;
1338 }
1339
1340 #if 0 /// UNNEEDED by elogind
1341 void log_set_upgrade_syslog_to_journal(bool b) {
1342         upgrade_syslog_to_journal = b;
1343
1344         /* Make the change effective immediately */
1345         if (b) {
1346                 if (log_target == LOG_TARGET_SYSLOG)
1347                         log_target = LOG_TARGET_JOURNAL;
1348                 else if (log_target == LOG_TARGET_SYSLOG_OR_KMSG)
1349                         log_target = LOG_TARGET_JOURNAL_OR_KMSG;
1350         }
1351 }
1352
1353 void log_set_always_reopen_console(bool b) {
1354         always_reopen_console = b;
1355 }
1356 #endif // 0
1357
1358 void log_set_open_when_needed(bool b) {
1359         open_when_needed = b;
1360 }
1361
1362 void log_set_prohibit_ipc(bool b) {
1363         prohibit_ipc = b;
1364 }
1365
1366 int log_emergency_level(void) {
1367         /* Returns the log level to use for log_emergency() logging. We use LOG_EMERG only when we are PID 1, as only
1368          * then the system of the whole system is obviously affected. */
1369
1370         return getpid_cached() == 1 ? LOG_EMERG : LOG_ERR;
1371 }