chiark / gitweb /
relicense to LGPLv2.1 (with exceptions)
[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_KMSG)) {
550
551                         k = write_to_kmsg(level, file, line, func, buffer);
552                         if (k < 0) {
553                                 log_close_kmsg();
554                                 log_open_console();
555                         } else if (k > 0)
556                                 r++;
557                 }
558
559                 if (k <= 0) {
560                         k = write_to_console(level, file, line, func, buffer);
561                         if (k < 0)
562                                 return k;
563                 }
564
565                 buffer = e;
566         } while (buffer);
567
568         return r;
569 }
570
571 int log_dump_internal(
572         int level,
573         const char*file,
574         int line,
575         const char *func,
576         char *buffer) {
577
578         int saved_errno, r;
579
580         /* This modifies the buffer... */
581
582         if (_likely_(LOG_PRI(level) > log_max_level))
583                 return 0;
584
585         saved_errno = errno;
586         r = log_dispatch(level, file, line, func, buffer);
587         errno = saved_errno;
588
589         return r;
590 }
591
592 int log_metav(
593         int level,
594         const char*file,
595         int line,
596         const char *func,
597         const char *format,
598         va_list ap) {
599
600         char buffer[LINE_MAX];
601         int saved_errno, r;
602
603         if (_likely_(LOG_PRI(level) > log_max_level))
604                 return 0;
605
606         saved_errno = errno;
607         vsnprintf(buffer, sizeof(buffer), format, ap);
608         char_array_0(buffer);
609
610         r = log_dispatch(level, file, line, func, buffer);
611         errno = saved_errno;
612
613         return r;
614 }
615
616 int log_meta(
617         int level,
618         const char*file,
619         int line,
620         const char *func,
621         const char *format, ...) {
622
623         int r;
624         va_list ap;
625
626         va_start(ap, format);
627         r = log_metav(level, file, line, func, format, ap);
628         va_end(ap);
629
630         return r;
631 }
632
633 #pragma GCC diagnostic push
634 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
635 _noreturn_ static void log_assert(const char *text, const char *file, int line, const char *func, const char *format) {
636         static char buffer[LINE_MAX];
637
638         snprintf(buffer, sizeof(buffer), format, text, file, line, func);
639
640         char_array_0(buffer);
641         log_abort_msg = buffer;
642
643         log_dispatch(LOG_CRIT, file, line, func, buffer);
644         abort();
645 }
646 #pragma GCC diagnostic pop
647
648 _noreturn_ void log_assert_failed(const char *text, const char *file, int line, const char *func) {
649         log_assert(text, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Aborting.");
650 }
651
652 _noreturn_ void log_assert_failed_unreachable(const char *text, const char *file, int line, const char *func) {
653         log_assert(text, file, line, func, "Code should not be reached '%s' at %s:%u, function %s(). Aborting.");
654 }
655
656 int log_set_target_from_string(const char *e) {
657         LogTarget t;
658
659         t = log_target_from_string(e);
660         if (t < 0)
661                 return -EINVAL;
662
663         log_set_target(t);
664         return 0;
665 }
666
667 int log_set_max_level_from_string(const char *e) {
668         int t;
669
670         t = log_level_from_string(e);
671         if (t < 0)
672                 return t;
673
674         log_set_max_level(t);
675         return 0;
676 }
677
678 void log_parse_environment(void) {
679         const char *e;
680
681         if ((e = getenv("SYSTEMD_LOG_TARGET")))
682                 if (log_set_target_from_string(e) < 0)
683                         log_warning("Failed to parse log target %s. Ignoring.", e);
684
685         if ((e = getenv("SYSTEMD_LOG_LEVEL")))
686                 if (log_set_max_level_from_string(e) < 0)
687                         log_warning("Failed to parse log level %s. Ignoring.", e);
688
689         if ((e = getenv("SYSTEMD_LOG_COLOR")))
690                 if (log_show_color_from_string(e) < 0)
691                         log_warning("Failed to parse bool %s. Ignoring.", e);
692
693         if ((e = getenv("SYSTEMD_LOG_LOCATION")))
694                 if (log_show_location_from_string(e) < 0)
695                         log_warning("Failed to parse bool %s. Ignoring.", e);
696 }
697
698 LogTarget log_get_target(void) {
699         return log_target;
700 }
701
702 int log_get_max_level(void) {
703         return log_max_level;
704 }
705
706 void log_show_color(bool b) {
707         show_color = b;
708 }
709
710 void log_show_location(bool b) {
711         show_location = b;
712 }
713
714 int log_show_color_from_string(const char *e) {
715         int t;
716
717         t = parse_boolean(e);
718         if (t < 0)
719                 return t;
720
721         log_show_color(t);
722         return 0;
723 }
724
725 int log_show_location_from_string(const char *e) {
726         int t;
727
728         t = parse_boolean(e);
729         if (t < 0)
730                 return t;
731
732         log_show_location(t);
733         return 0;
734 }
735
736 static const char *const log_target_table[] = {
737         [LOG_TARGET_CONSOLE] = "console",
738         [LOG_TARGET_KMSG] = "kmsg",
739         [LOG_TARGET_JOURNAL] = "journal",
740         [LOG_TARGET_JOURNAL_OR_KMSG] = "journal-or-kmsg",
741         [LOG_TARGET_SYSLOG] = "syslog",
742         [LOG_TARGET_SYSLOG_OR_KMSG] = "syslog-or-kmsg",
743         [LOG_TARGET_AUTO] = "auto",
744         [LOG_TARGET_NULL] = "null"
745 };
746
747 DEFINE_STRING_TABLE_LOOKUP(log_target, LogTarget);