chiark / gitweb /
build-sys: fix built with --disable-logind
[elogind.git] / src / shared / 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 <stdarg.h>
23 #include <stdio.h>
24 #include <errno.h>
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <sys/socket.h>
28 #include <sys/un.h>
29 #include <stddef.h>
30
31 #include "log.h"
32 #include "util.h"
33 #include "macro.h"
34 #include "socket-util.h"
35
36 #define SNDBUF_SIZE (8*1024*1024)
37
38 static LogTarget log_target = LOG_TARGET_CONSOLE;
39 static int log_max_level = LOG_INFO;
40 static int log_facility = LOG_DAEMON;
41
42 static int console_fd = STDERR_FILENO;
43 static int syslog_fd = -1;
44 static int kmsg_fd = -1;
45 static int journal_fd = -1;
46
47 static bool syslog_is_stream = false;
48
49 static bool show_color = false;
50 static bool show_location = false;
51
52 /* Akin to glibc's __abort_msg; which is private and we hence cannot
53  * use here. */
54 static char *log_abort_msg = NULL;
55
56 void log_close_console(void) {
57
58         if (console_fd < 0)
59                 return;
60
61         if (getpid() == 1) {
62                 if (console_fd >= 3)
63                         close_nointr_nofail(console_fd);
64
65                 console_fd = -1;
66         }
67 }
68
69 static int log_open_console(void) {
70
71         if (console_fd >= 0)
72                 return 0;
73
74         if (getpid() == 1) {
75
76                 console_fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
77                 if (console_fd < 0) {
78                         log_error("Failed to open /dev/console for logging: %s", strerror(-console_fd));
79                         return console_fd;
80                 }
81
82                 log_debug("Successfully opened /dev/console for logging.");
83         } else
84                 console_fd = STDERR_FILENO;
85
86         return 0;
87 }
88
89 void log_close_kmsg(void) {
90
91         if (kmsg_fd < 0)
92                 return;
93
94         close_nointr_nofail(kmsg_fd);
95         kmsg_fd = -1;
96 }
97
98 static int log_open_kmsg(void) {
99
100         if (kmsg_fd >= 0)
101                 return 0;
102
103         kmsg_fd = open("/dev/kmsg", O_WRONLY|O_NOCTTY|O_CLOEXEC);
104         if (kmsg_fd < 0) {
105                 log_error("Failed to open /dev/kmsg for logging: %s", strerror(errno));
106                 return -errno;
107         }
108
109         log_debug("Successfully opened /dev/kmsg for logging.");
110
111         return 0;
112 }
113
114 void log_close_syslog(void) {
115
116         if (syslog_fd < 0)
117                 return;
118
119         close_nointr_nofail(syslog_fd);
120         syslog_fd = -1;
121 }
122
123 static int create_log_socket(int type) {
124         int fd;
125
126         /* All output to the syslog/journal fds we do asynchronously,
127          * and if the buffers are full we just drop the messages */
128
129         fd = socket(AF_UNIX, type|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
130         if (fd < 0)
131                 return -errno;
132
133         fd_inc_sndbuf(fd, SNDBUF_SIZE);
134
135         return fd;
136 }
137
138 static int log_open_syslog(void) {
139         union sockaddr_union sa;
140         int r;
141
142         if (syslog_fd >= 0)
143                 return 0;
144
145         zero(sa);
146         sa.un.sun_family = AF_UNIX;
147         strncpy(sa.un.sun_path, "/dev/log", sizeof(sa.un.sun_path));
148
149         syslog_fd = create_log_socket(SOCK_DGRAM);
150         if (syslog_fd < 0) {
151                 r = syslog_fd;
152                 goto fail;
153         }
154
155         if (connect(syslog_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
156                 close_nointr_nofail(syslog_fd);
157
158                 /* Some legacy syslog systems still use stream
159                  * sockets. They really shouldn't. But what can we
160                  * do... */
161                 syslog_fd = create_log_socket(SOCK_STREAM);
162                 if (syslog_fd < 0) {
163                         r = syslog_fd;
164                         goto fail;
165                 }
166
167                 if (connect(syslog_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
168                         r = -errno;
169                         goto fail;
170                 }
171
172                 syslog_is_stream = true;
173         } else
174                 syslog_is_stream = false;
175
176         log_debug("Successfully opened syslog for logging.");
177
178         return 0;
179
180 fail:
181         log_close_syslog();
182         log_debug("Failed to open syslog for logging: %s", strerror(-r));
183         return r;
184 }
185
186 void log_close_journal(void) {
187
188         if (journal_fd < 0)
189                 return;
190
191         close_nointr_nofail(journal_fd);
192         journal_fd = -1;
193 }
194
195 static int log_open_journal(void) {
196         union sockaddr_union sa;
197         int r;
198
199         if (journal_fd >= 0)
200                 return 0;
201
202         journal_fd = create_log_socket(SOCK_DGRAM);
203         if (journal_fd < 0) {
204                 r = journal_fd;
205                 goto fail;
206         }
207
208         zero(sa);
209         sa.un.sun_family = AF_UNIX;
210         strncpy(sa.un.sun_path, "/run/systemd/journal/socket", sizeof(sa.un.sun_path));
211
212         if (connect(journal_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
213                 r = -errno;
214                 goto fail;
215         }
216
217         log_debug("Successfully opened journal for logging.");
218
219         return 0;
220
221 fail:
222         log_close_journal();
223         log_debug("Failed to open journal for logging: %s", strerror(-r));
224         return r;
225 }
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                 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                 if (log_target == LOG_TARGET_AUTO ||
248                     log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
249                     log_target == LOG_TARGET_JOURNAL) {
250                         r = log_open_journal();
251                         if (r >= 0) {
252                                 log_close_syslog();
253                                 log_close_console();
254                                 return r;
255                         }
256                 }
257
258                 if (log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
259                     log_target == LOG_TARGET_SYSLOG) {
260                         r = log_open_syslog();
261                         if (r >= 0) {
262                                 log_close_journal();
263                                 log_close_console();
264                                 return r;
265                         }
266                 }
267
268                 if (log_target == LOG_TARGET_AUTO ||
269                     log_target == LOG_TARGET_SAFE ||
270                     log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
271                     log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
272                     log_target == LOG_TARGET_KMSG) {
273                         r = log_open_kmsg();
274                         if (r >= 0) {
275                                 log_close_journal();
276                                 log_close_syslog();
277                                 log_close_console();
278                                 return r;
279                         }
280                 }
281         }
282
283         log_close_journal();
284         log_close_syslog();
285
286         /* Get the real /dev/console if we are PID=1, hence reopen */
287         log_close_console();
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         log_target = target;
296 }
297
298 void log_close(void) {
299         log_close_journal();
300         log_close_syslog();
301         log_close_kmsg();
302         log_close_console();
303 }
304
305 void log_forget_fds(void) {
306         console_fd = kmsg_fd = syslog_fd = journal_fd = -1;
307 }
308
309 void log_set_max_level(int level) {
310         assert((level & LOG_PRIMASK) == level);
311
312         log_max_level = level;
313 }
314
315 void log_set_facility(int facility) {
316         log_facility = facility;
317 }
318
319 static int write_to_console(
320                 int level,
321                 const char*file,
322                 int line,
323                 const char *func,
324                 const char *buffer) {
325
326         char location[64];
327         struct iovec iovec[5];
328         unsigned n = 0;
329         bool highlight;
330
331         if (console_fd < 0)
332                 return 0;
333
334         highlight = LOG_PRI(level) <= LOG_ERR && show_color;
335
336         zero(iovec);
337
338         if (show_location) {
339                 snprintf(location, sizeof(location), "(%s:%u) ", file, line);
340                 char_array_0(location);
341                 IOVEC_SET_STRING(iovec[n++], location);
342         }
343
344         if (highlight)
345                 IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_RED_ON);
346         IOVEC_SET_STRING(iovec[n++], buffer);
347         if (highlight)
348                 IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_OFF);
349         IOVEC_SET_STRING(iovec[n++], "\n");
350
351         if (writev(console_fd, iovec, n) < 0)
352                 return -errno;
353
354         return 1;
355 }
356
357 static int write_to_syslog(
358         int level,
359         const char*file,
360         int line,
361         const char *func,
362         const char *buffer) {
363
364         char header_priority[16], header_time[64], header_pid[16];
365         struct iovec iovec[5];
366         struct msghdr msghdr;
367         time_t t;
368         struct tm *tm;
369
370         if (syslog_fd < 0)
371                 return 0;
372
373         snprintf(header_priority, sizeof(header_priority), "<%i>", level);
374         char_array_0(header_priority);
375
376         t = (time_t) (now(CLOCK_REALTIME) / USEC_PER_SEC);
377         if (!(tm = localtime(&t)))
378                 return -EINVAL;
379
380         if (strftime(header_time, sizeof(header_time), "%h %e %T ", tm) <= 0)
381                 return -EINVAL;
382
383         snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) getpid());
384         char_array_0(header_pid);
385
386         zero(iovec);
387         IOVEC_SET_STRING(iovec[0], header_priority);
388         IOVEC_SET_STRING(iovec[1], header_time);
389         IOVEC_SET_STRING(iovec[2], program_invocation_short_name);
390         IOVEC_SET_STRING(iovec[3], header_pid);
391         IOVEC_SET_STRING(iovec[4], buffer);
392
393         /* When using syslog via SOCK_STREAM separate the messages by NUL chars */
394         if (syslog_is_stream)
395                 iovec[4].iov_len++;
396
397         zero(msghdr);
398         msghdr.msg_iov = iovec;
399         msghdr.msg_iovlen = ELEMENTSOF(iovec);
400
401         for (;;) {
402                 ssize_t n;
403
404                 n = sendmsg(syslog_fd, &msghdr, MSG_NOSIGNAL);
405                 if (n < 0)
406                         return -errno;
407
408                 if (!syslog_is_stream ||
409                     (size_t) n >= IOVEC_TOTAL_SIZE(iovec, ELEMENTSOF(iovec)))
410                         break;
411
412                 IOVEC_INCREMENT(iovec, ELEMENTSOF(iovec), n);
413         }
414
415         return 1;
416 }
417
418 static int write_to_kmsg(
419         int level,
420         const char*file,
421         int line,
422         const char *func,
423         const char *buffer) {
424
425         char header_priority[16], header_pid[16];
426         struct iovec iovec[5];
427
428         if (kmsg_fd < 0)
429                 return 0;
430
431         snprintf(header_priority, sizeof(header_priority), "<%i>", level);
432         char_array_0(header_priority);
433
434         snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) getpid());
435         char_array_0(header_pid);
436
437         zero(iovec);
438         IOVEC_SET_STRING(iovec[0], header_priority);
439         IOVEC_SET_STRING(iovec[1], program_invocation_short_name);
440         IOVEC_SET_STRING(iovec[2], header_pid);
441         IOVEC_SET_STRING(iovec[3], buffer);
442         IOVEC_SET_STRING(iovec[4], "\n");
443
444         if (writev(kmsg_fd, iovec, ELEMENTSOF(iovec)) < 0)
445                 return -errno;
446
447         return 1;
448 }
449
450 static int write_to_journal(
451         int level,
452         const char*file,
453         int line,
454         const char *func,
455         const char *buffer) {
456
457         char header[LINE_MAX];
458         struct iovec iovec[3];
459         struct msghdr mh;
460
461         if (journal_fd < 0)
462                 return 0;
463
464         snprintf(header, sizeof(header),
465                  "PRIORITY=%i\n"
466                  "SYSLOG_FACILITY=%i\n"
467                  "CODE_FILE=%s\n"
468                  "CODE_LINE=%i\n"
469                  "CODE_FUNCTION=%s\n"
470                  "SYSLOG_IDENTIFIER=%s\n"
471                  "MESSAGE=",
472                  LOG_PRI(level),
473                  LOG_FAC(level),
474                  file,
475                  line,
476                  func,
477                  program_invocation_short_name);
478
479         char_array_0(header);
480
481         zero(iovec);
482         IOVEC_SET_STRING(iovec[0], header);
483         IOVEC_SET_STRING(iovec[1], buffer);
484         IOVEC_SET_STRING(iovec[2], "\n");
485
486         zero(mh);
487         mh.msg_iov = iovec;
488         mh.msg_iovlen = ELEMENTSOF(iovec);
489
490         if (sendmsg(journal_fd, &mh, MSG_NOSIGNAL) < 0)
491                 return -errno;
492
493         return 1;
494 }
495
496 static int log_dispatch(
497         int level,
498         const char*file,
499         int line,
500         const char *func,
501         char *buffer) {
502
503         int r = 0;
504
505         if (log_target == LOG_TARGET_NULL)
506                 return 0;
507
508         /* Patch in LOG_DAEMON facility if necessary */
509         if ((level & LOG_FACMASK) == 0)
510                 level = log_facility | LOG_PRI(level);
511
512         do {
513                 char *e;
514                 int k = 0;
515
516                 buffer += strspn(buffer, NEWLINE);
517
518                 if (buffer[0] == 0)
519                         break;
520
521                 if ((e = strpbrk(buffer, NEWLINE)))
522                         *(e++) = 0;
523
524                 if (log_target == LOG_TARGET_AUTO ||
525                     log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
526                     log_target == LOG_TARGET_JOURNAL) {
527
528                         k = write_to_journal(level, file, line, func, buffer);
529                         if (k < 0) {
530                                 if (k != -EAGAIN)
531                                         log_close_journal();
532                                 log_open_kmsg();
533                         } else if (k > 0)
534                                 r++;
535                 }
536
537                 if (log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
538                     log_target == LOG_TARGET_SYSLOG) {
539
540                         k = write_to_syslog(level, file, line, func, buffer);
541                         if (k < 0) {
542                                 if (k != -EAGAIN)
543                                         log_close_syslog();
544                                 log_open_kmsg();
545                         } else if (k > 0)
546                                 r++;
547                 }
548
549                 if (k <= 0 &&
550                     (log_target == LOG_TARGET_AUTO ||
551                      log_target == LOG_TARGET_SAFE ||
552                      log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
553                      log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
554                      log_target == LOG_TARGET_KMSG)) {
555
556                         k = write_to_kmsg(level, file, line, func, buffer);
557                         if (k < 0) {
558                                 log_close_kmsg();
559                                 log_open_console();
560                         } else if (k > 0)
561                                 r++;
562                 }
563
564                 if (k <= 0) {
565                         k = write_to_console(level, file, line, func, buffer);
566                         if (k < 0)
567                                 return k;
568                 }
569
570                 buffer = e;
571         } while (buffer);
572
573         return r;
574 }
575
576 int log_dump_internal(
577         int level,
578         const char*file,
579         int line,
580         const char *func,
581         char *buffer) {
582
583         int saved_errno, r;
584
585         /* This modifies the buffer... */
586
587         if (_likely_(LOG_PRI(level) > log_max_level))
588                 return 0;
589
590         saved_errno = errno;
591         r = log_dispatch(level, file, line, func, buffer);
592         errno = saved_errno;
593
594         return r;
595 }
596
597 int log_metav(
598         int level,
599         const char*file,
600         int line,
601         const char *func,
602         const char *format,
603         va_list ap) {
604
605         char buffer[LINE_MAX];
606         int saved_errno, r;
607
608         if (_likely_(LOG_PRI(level) > log_max_level))
609                 return 0;
610
611         saved_errno = errno;
612         vsnprintf(buffer, sizeof(buffer), format, ap);
613         char_array_0(buffer);
614
615         r = log_dispatch(level, file, line, func, buffer);
616         errno = saved_errno;
617
618         return r;
619 }
620
621 int log_meta(
622         int level,
623         const char*file,
624         int line,
625         const char *func,
626         const char *format, ...) {
627
628         int r;
629         va_list ap;
630
631         va_start(ap, format);
632         r = log_metav(level, file, line, func, format, ap);
633         va_end(ap);
634
635         return r;
636 }
637
638 #pragma GCC diagnostic push
639 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
640 _noreturn_ static void log_assert(const char *text, const char *file, int line, const char *func, const char *format) {
641         static char buffer[LINE_MAX];
642
643         snprintf(buffer, sizeof(buffer), format, text, file, line, func);
644
645         char_array_0(buffer);
646         log_abort_msg = buffer;
647
648         log_dispatch(LOG_CRIT, file, line, func, buffer);
649         abort();
650 }
651 #pragma GCC diagnostic pop
652
653 _noreturn_ void log_assert_failed(const char *text, const char *file, int line, const char *func) {
654         log_assert(text, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Aborting.");
655 }
656
657 _noreturn_ void log_assert_failed_unreachable(const char *text, const char *file, int line, const char *func) {
658         log_assert(text, file, line, func, "Code should not be reached '%s' at %s:%u, function %s(). Aborting.");
659 }
660
661 int log_set_target_from_string(const char *e) {
662         LogTarget t;
663
664         t = log_target_from_string(e);
665         if (t < 0)
666                 return -EINVAL;
667
668         log_set_target(t);
669         return 0;
670 }
671
672 int log_set_max_level_from_string(const char *e) {
673         int t;
674
675         t = log_level_from_string(e);
676         if (t < 0)
677                 return t;
678
679         log_set_max_level(t);
680         return 0;
681 }
682
683 void log_parse_environment(void) {
684         const char *e;
685
686         if ((e = getenv("SYSTEMD_LOG_TARGET")))
687                 if (log_set_target_from_string(e) < 0)
688                         log_warning("Failed to parse log target %s. Ignoring.", e);
689
690         if ((e = getenv("SYSTEMD_LOG_LEVEL")))
691                 if (log_set_max_level_from_string(e) < 0)
692                         log_warning("Failed to parse log level %s. Ignoring.", e);
693
694         if ((e = getenv("SYSTEMD_LOG_COLOR")))
695                 if (log_show_color_from_string(e) < 0)
696                         log_warning("Failed to parse bool %s. Ignoring.", e);
697
698         if ((e = getenv("SYSTEMD_LOG_LOCATION")))
699                 if (log_show_location_from_string(e) < 0)
700                         log_warning("Failed to parse bool %s. Ignoring.", e);
701 }
702
703 LogTarget log_get_target(void) {
704         return log_target;
705 }
706
707 int log_get_max_level(void) {
708         return log_max_level;
709 }
710
711 void log_show_color(bool b) {
712         show_color = b;
713 }
714
715 void log_show_location(bool b) {
716         show_location = b;
717 }
718
719 int log_show_color_from_string(const char *e) {
720         int t;
721
722         t = parse_boolean(e);
723         if (t < 0)
724                 return t;
725
726         log_show_color(t);
727         return 0;
728 }
729
730 int log_show_location_from_string(const char *e) {
731         int t;
732
733         t = parse_boolean(e);
734         if (t < 0)
735                 return t;
736
737         log_show_location(t);
738         return 0;
739 }
740
741 static const char *const log_target_table[] = {
742         [LOG_TARGET_CONSOLE] = "console",
743         [LOG_TARGET_KMSG] = "kmsg",
744         [LOG_TARGET_JOURNAL] = "journal",
745         [LOG_TARGET_JOURNAL_OR_KMSG] = "journal-or-kmsg",
746         [LOG_TARGET_SYSLOG] = "syslog",
747         [LOG_TARGET_SYSLOG_OR_KMSG] = "syslog-or-kmsg",
748         [LOG_TARGET_AUTO] = "auto",
749         [LOG_TARGET_SAFE] = "safe",
750         [LOG_TARGET_NULL] = "null"
751 };
752
753 DEFINE_STRING_TABLE_LOOKUP(log_target, LogTarget);