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