chiark / gitweb /
log: fix LOG_TARGET_JOURNAL_OR_KMSG
[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 ||
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_JOURNAL_OR_KMSG ||
270                     log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
271                     log_target == LOG_TARGET_KMSG) {
272                         r = log_open_kmsg();
273                         if (r >= 0) {
274                                 log_close_journal();
275                                 log_close_syslog();
276                                 log_close_console();
277                                 return r;
278                         }
279                 }
280         }
281
282         log_close_journal();
283         log_close_syslog();
284
285         /* Get the real /dev/console if we are PID=1, hence reopen */
286         log_close_console();
287         return log_open_console();
288 }
289
290 void log_set_target(LogTarget target) {
291         assert(target >= 0);
292         assert(target < _LOG_TARGET_MAX);
293
294         log_target = target;
295 }
296
297 void log_close(void) {
298         log_close_journal();
299         log_close_syslog();
300         log_close_kmsg();
301         log_close_console();
302 }
303
304 void log_forget_fds(void) {
305         console_fd = kmsg_fd = syslog_fd = journal_fd = -1;
306 }
307
308 void log_set_max_level(int level) {
309         assert((level & LOG_PRIMASK) == level);
310
311         log_max_level = level;
312 }
313
314 void log_set_facility(int facility) {
315         log_facility = facility;
316 }
317
318 static int write_to_console(
319                 int level,
320                 const char*file,
321                 int line,
322                 const char *func,
323                 const char *buffer) {
324
325         char location[64];
326         struct iovec iovec[5];
327         unsigned n = 0;
328         bool highlight;
329
330         if (console_fd < 0)
331                 return 0;
332
333         highlight = LOG_PRI(level) <= LOG_ERR && show_color;
334
335         zero(iovec);
336
337         if (show_location) {
338                 snprintf(location, sizeof(location), "(%s:%u) ", file, line);
339                 char_array_0(location);
340                 IOVEC_SET_STRING(iovec[n++], location);
341         }
342
343         if (highlight)
344                 IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_RED_ON);
345         IOVEC_SET_STRING(iovec[n++], buffer);
346         if (highlight)
347                 IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_OFF);
348         IOVEC_SET_STRING(iovec[n++], "\n");
349
350         if (writev(console_fd, iovec, n) < 0)
351                 return -errno;
352
353         return 1;
354 }
355
356 static int write_to_syslog(
357         int level,
358         const char*file,
359         int line,
360         const char *func,
361         const char *buffer) {
362
363         char header_priority[16], header_time[64], header_pid[16];
364         struct iovec iovec[5];
365         struct msghdr msghdr;
366         time_t t;
367         struct tm *tm;
368
369         if (syslog_fd < 0)
370                 return 0;
371
372         snprintf(header_priority, sizeof(header_priority), "<%i>", level);
373         char_array_0(header_priority);
374
375         t = (time_t) (now(CLOCK_REALTIME) / USEC_PER_SEC);
376         if (!(tm = localtime(&t)))
377                 return -EINVAL;
378
379         if (strftime(header_time, sizeof(header_time), "%h %e %T ", tm) <= 0)
380                 return -EINVAL;
381
382         snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) getpid());
383         char_array_0(header_pid);
384
385         zero(iovec);
386         IOVEC_SET_STRING(iovec[0], header_priority);
387         IOVEC_SET_STRING(iovec[1], header_time);
388         IOVEC_SET_STRING(iovec[2], program_invocation_short_name);
389         IOVEC_SET_STRING(iovec[3], header_pid);
390         IOVEC_SET_STRING(iovec[4], buffer);
391
392         /* When using syslog via SOCK_STREAM separate the messages by NUL chars */
393         if (syslog_is_stream)
394                 iovec[4].iov_len++;
395
396         zero(msghdr);
397         msghdr.msg_iov = iovec;
398         msghdr.msg_iovlen = ELEMENTSOF(iovec);
399
400         for (;;) {
401                 ssize_t n;
402
403                 n = sendmsg(syslog_fd, &msghdr, MSG_NOSIGNAL);
404                 if (n < 0)
405                         return -errno;
406
407                 if (!syslog_is_stream ||
408                     (size_t) n >= IOVEC_TOTAL_SIZE(iovec, ELEMENTSOF(iovec)))
409                         break;
410
411                 IOVEC_INCREMENT(iovec, ELEMENTSOF(iovec), n);
412         }
413
414         return 1;
415 }
416
417 static int write_to_kmsg(
418         int level,
419         const char*file,
420         int line,
421         const char *func,
422         const char *buffer) {
423
424         char header_priority[16], header_pid[16];
425         struct iovec iovec[5];
426
427         if (kmsg_fd < 0)
428                 return 0;
429
430         snprintf(header_priority, sizeof(header_priority), "<%i>", level);
431         char_array_0(header_priority);
432
433         snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) getpid());
434         char_array_0(header_pid);
435
436         zero(iovec);
437         IOVEC_SET_STRING(iovec[0], header_priority);
438         IOVEC_SET_STRING(iovec[1], program_invocation_short_name);
439         IOVEC_SET_STRING(iovec[2], header_pid);
440         IOVEC_SET_STRING(iovec[3], buffer);
441         IOVEC_SET_STRING(iovec[4], "\n");
442
443         if (writev(kmsg_fd, iovec, ELEMENTSOF(iovec)) < 0)
444                 return -errno;
445
446         return 1;
447 }
448
449 static int write_to_journal(
450         int level,
451         const char*file,
452         int line,
453         const char *func,
454         const char *buffer) {
455
456         char header[LINE_MAX];
457         struct iovec iovec[3];
458         struct msghdr mh;
459
460         if (journal_fd < 0)
461                 return 0;
462
463         snprintf(header, sizeof(header),
464                  "PRIORITY=%i\n"
465                  "SYSLOG_FACILITY=%i\n"
466                  "CODE_FILE=%s\n"
467                  "CODE_LINE=%i\n"
468                  "CODE_FUNCTION=%s\n"
469                  "MESSAGE=",
470                  LOG_PRI(level),
471                  LOG_FAC(level),
472                  file,
473                  line,
474                  func);
475
476         char_array_0(header);
477
478         zero(iovec);
479         IOVEC_SET_STRING(iovec[0], header);
480         IOVEC_SET_STRING(iovec[1], buffer);
481         IOVEC_SET_STRING(iovec[2], "\n");
482
483         zero(mh);
484         mh.msg_iov = iovec;
485         mh.msg_iovlen = ELEMENTSOF(iovec);
486
487         if (sendmsg(journal_fd, &mh, MSG_NOSIGNAL) < 0)
488                 return -errno;
489
490         return 1;
491 }
492
493 static int log_dispatch(
494         int level,
495         const char*file,
496         int line,
497         const char *func,
498         char *buffer) {
499
500         int r = 0;
501
502         if (log_target == LOG_TARGET_NULL)
503                 return 0;
504
505         /* Patch in LOG_DAEMON facility if necessary */
506         if ((level & LOG_FACMASK) == 0)
507                 level = log_facility | LOG_PRI(level);
508
509         do {
510                 char *e;
511                 int k = 0;
512
513                 buffer += strspn(buffer, NEWLINE);
514
515                 if (buffer[0] == 0)
516                         break;
517
518                 if ((e = strpbrk(buffer, NEWLINE)))
519                         *(e++) = 0;
520
521                 if (log_target == LOG_TARGET_AUTO ||
522                     log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
523                     log_target == LOG_TARGET_JOURNAL) {
524
525                         k = write_to_journal(level, file, line, func, buffer);
526                         if (k < 0) {
527                                 if (k != -EAGAIN)
528                                         log_close_journal();
529                                 log_open_kmsg();
530                         } else if (k > 0)
531                                 r++;
532                 }
533
534                 if (log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
535                     log_target == LOG_TARGET_SYSLOG) {
536
537                         k = write_to_syslog(level, file, line, func, buffer);
538                         if (k < 0) {
539                                 if (k != -EAGAIN)
540                                         log_close_syslog();
541                                 log_open_kmsg();
542                         } else if (k > 0)
543                                 r++;
544                 }
545
546                 if (k <= 0 &&
547                     (log_target == LOG_TARGET_AUTO ||
548                      log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
549                      log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
550                      log_target == LOG_TARGET_KMSG)) {
551
552                         k = write_to_kmsg(level, file, line, func, buffer);
553                         if (k < 0) {
554                                 log_close_kmsg();
555                                 log_open_console();
556                         } else if (k > 0)
557                                 r++;
558                 }
559
560                 if (k <= 0) {
561                         k = write_to_console(level, file, line, func, buffer);
562                         if (k < 0)
563                                 return k;
564                 }
565
566                 buffer = e;
567         } while (buffer);
568
569         return r;
570 }
571
572 int log_dump_internal(
573         int level,
574         const char*file,
575         int line,
576         const char *func,
577         char *buffer) {
578
579         int saved_errno, r;
580
581         /* This modifies the buffer... */
582
583         if (_likely_(LOG_PRI(level) > log_max_level))
584                 return 0;
585
586         saved_errno = errno;
587         r = log_dispatch(level, file, line, func, buffer);
588         errno = saved_errno;
589
590         return r;
591 }
592
593 int log_metav(
594         int level,
595         const char*file,
596         int line,
597         const char *func,
598         const char *format,
599         va_list ap) {
600
601         char buffer[LINE_MAX];
602         int saved_errno, r;
603
604         if (_likely_(LOG_PRI(level) > log_max_level))
605                 return 0;
606
607         saved_errno = errno;
608         vsnprintf(buffer, sizeof(buffer), format, ap);
609         char_array_0(buffer);
610
611         r = log_dispatch(level, file, line, func, buffer);
612         errno = saved_errno;
613
614         return r;
615 }
616
617 int log_meta(
618         int level,
619         const char*file,
620         int line,
621         const char *func,
622         const char *format, ...) {
623
624         int r;
625         va_list ap;
626
627         va_start(ap, format);
628         r = log_metav(level, file, line, func, format, ap);
629         va_end(ap);
630
631         return r;
632 }
633
634 #pragma GCC diagnostic push
635 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
636 _noreturn_ static void log_assert(const char *text, const char *file, int line, const char *func, const char *format) {
637         static char buffer[LINE_MAX];
638
639         snprintf(buffer, sizeof(buffer), format, text, file, line, func);
640
641         char_array_0(buffer);
642         log_abort_msg = buffer;
643
644         log_dispatch(LOG_CRIT, file, line, func, buffer);
645         abort();
646 }
647 #pragma GCC diagnostic pop
648
649 _noreturn_ void log_assert_failed(const char *text, const char *file, int line, const char *func) {
650         log_assert(text, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Aborting.");
651 }
652
653 _noreturn_ void log_assert_failed_unreachable(const char *text, const char *file, int line, const char *func) {
654         log_assert(text, file, line, func, "Code should not be reached '%s' at %s:%u, function %s(). Aborting.");
655 }
656
657 int log_set_target_from_string(const char *e) {
658         LogTarget t;
659
660         t = log_target_from_string(e);
661         if (t < 0)
662                 return -EINVAL;
663
664         log_set_target(t);
665         return 0;
666 }
667
668 int log_set_max_level_from_string(const char *e) {
669         int t;
670
671         t = log_level_from_string(e);
672         if (t < 0)
673                 return t;
674
675         log_set_max_level(t);
676         return 0;
677 }
678
679 void log_parse_environment(void) {
680         const char *e;
681
682         if ((e = getenv("SYSTEMD_LOG_TARGET")))
683                 if (log_set_target_from_string(e) < 0)
684                         log_warning("Failed to parse log target %s. Ignoring.", e);
685
686         if ((e = getenv("SYSTEMD_LOG_LEVEL")))
687                 if (log_set_max_level_from_string(e) < 0)
688                         log_warning("Failed to parse log level %s. Ignoring.", e);
689
690         if ((e = getenv("SYSTEMD_LOG_COLOR")))
691                 if (log_show_color_from_string(e) < 0)
692                         log_warning("Failed to parse bool %s. Ignoring.", e);
693
694         if ((e = getenv("SYSTEMD_LOG_LOCATION")))
695                 if (log_show_location_from_string(e) < 0)
696                         log_warning("Failed to parse bool %s. Ignoring.", e);
697 }
698
699 LogTarget log_get_target(void) {
700         return log_target;
701 }
702
703 int log_get_max_level(void) {
704         return log_max_level;
705 }
706
707 void log_show_color(bool b) {
708         show_color = b;
709 }
710
711 void log_show_location(bool b) {
712         show_location = b;
713 }
714
715 int log_show_color_from_string(const char *e) {
716         int t;
717
718         t = parse_boolean(e);
719         if (t < 0)
720                 return t;
721
722         log_show_color(t);
723         return 0;
724 }
725
726 int log_show_location_from_string(const char *e) {
727         int t;
728
729         t = parse_boolean(e);
730         if (t < 0)
731                 return t;
732
733         log_show_location(t);
734         return 0;
735 }
736
737 static const char *const log_target_table[] = {
738         [LOG_TARGET_CONSOLE] = "console",
739         [LOG_TARGET_KMSG] = "kmsg",
740         [LOG_TARGET_JOURNAL] = "journal",
741         [LOG_TARGET_JOURNAL_OR_KMSG] = "journal-or-kmsg",
742         [LOG_TARGET_SYSLOG] = "syslog",
743         [LOG_TARGET_SYSLOG_OR_KMSG] = "syslog-or-kmsg",
744         [LOG_TARGET_AUTO] = "auto",
745         [LOG_TARGET_NULL] = "null"
746 };
747
748 DEFINE_STRING_TABLE_LOOKUP(log_target, LogTarget);