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