chiark / gitweb /
util: move all to shared/ and split external dependencies in separate internal libraries
[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 General Public License as published by
10   the Free Software Foundation; either version 2 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   General Public License for more details.
17
18   You should have received a copy of the GNU 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);