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