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