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