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