• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***
2   This file is part of eudev, forked from systemd.
3 
4   Copyright 2010 Lennart Poettering
5 
6   systemd is free software; you can redistribute it and/or modify it
7   under the terms of the GNU Lesser General Public License as published by
8   the Free Software Foundation; either version 2.1 of the License, or
9   (at your option) any later version.
10 
11   systemd is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   Lesser General Public License for more details.
15 
16   You should have received a copy of the GNU Lesser General Public License
17   along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19 
20 #include <stdarg.h>
21 #include <stdio.h>
22 #include <errno.h>
23 #include <unistd.h>
24 #include <fcntl.h>
25 #include <sys/socket.h>
26 #include <sys/un.h>
27 #include <stddef.h>
28 #include <string.h>
29 
30 #include "log.h"
31 #include "util.h"
32 #include "missing.h"
33 #include "macro.h"
34 #include "socket-util.h"
35 #include "time-util.h"
36 #include "process-util.h"
37 #include "terminal-util.h"
38 
39 #define SNDBUF_SIZE (8*1024*1024)
40 
41 static LogTarget log_target = LOG_TARGET_CONSOLE;
42 static int log_max_level = LOG_INFO;
43 static int log_facility = LOG_DAEMON;
44 
45 static int console_fd = STDERR_FILENO;
46 static int syslog_fd = -1;
47 static int kmsg_fd = -1;
48 
49 static bool syslog_is_stream = false;
50 
51 static bool show_color = false;
52 static bool show_location = false;
53 
54 /* Akin to glibc's __abort_msg; which is private and we hence cannot
55  * use here. */
56 static char *log_abort_msg = NULL;
57 
log_close_console(void)58 void log_close_console(void) {
59 
60         if (console_fd < 0)
61                 return;
62 
63         if (getpid() == 1) {
64                 if (console_fd >= 3)
65                         safe_close(console_fd);
66 
67                 console_fd = -1;
68         }
69 }
70 
log_open_console(void)71 static int log_open_console(void) {
72 
73         if (console_fd >= 0)
74                 return 0;
75 
76         if (getpid() == 1) {
77                 console_fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
78                 if (console_fd < 0)
79                         return console_fd;
80         } else
81                 console_fd = STDERR_FILENO;
82 
83         return 0;
84 }
85 
log_close_kmsg(void)86 void log_close_kmsg(void) {
87         kmsg_fd = safe_close(kmsg_fd);
88 }
89 
log_open_kmsg(void)90 static int log_open_kmsg(void) {
91 
92         if (kmsg_fd >= 0)
93                 return 0;
94 
95         kmsg_fd = open("/dev/kmsg", O_WRONLY|O_NOCTTY|O_CLOEXEC);
96         if (kmsg_fd < 0)
97                 return -errno;
98 
99         return 0;
100 }
101 
log_close_syslog(void)102 void log_close_syslog(void) {
103         syslog_fd = safe_close(syslog_fd);
104 }
105 
create_log_socket(int type)106 static int create_log_socket(int type) {
107         struct timeval tv;
108         int fd;
109 
110         fd = socket(AF_UNIX, type|SOCK_CLOEXEC, 0);
111         if (fd < 0)
112                 return -errno;
113 
114         fd_inc_sndbuf(fd, SNDBUF_SIZE);
115 
116         /* We need a blocking fd here since we'd otherwise lose
117         messages way too early. However, let's not hang forever in the
118         unlikely case of a deadlock. */
119         if (getpid() == 1)
120                 timeval_store(&tv, 10 * USEC_PER_MSEC);
121         else
122                 timeval_store(&tv, 10 * USEC_PER_SEC);
123         (void) setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
124 
125         return fd;
126 }
127 
log_open_syslog(void)128 static int log_open_syslog(void) {
129 
130         static const union sockaddr_union sa = {
131                 .un.sun_family = AF_UNIX,
132                 .un.sun_path = "/dev/log",
133         };
134 
135         int r;
136 
137         if (syslog_fd >= 0)
138                 return 0;
139 
140         syslog_fd = create_log_socket(SOCK_DGRAM);
141         if (syslog_fd < 0) {
142                 r = syslog_fd;
143                 goto fail;
144         }
145 
146         if (connect(syslog_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
147                 safe_close(syslog_fd);
148 
149                 /* Some legacy syslog systems still use stream
150                  * sockets. They really shouldn't. But what can we
151                  * do... */
152                 syslog_fd = create_log_socket(SOCK_STREAM);
153                 if (syslog_fd < 0) {
154                         r = syslog_fd;
155                         goto fail;
156                 }
157 
158                 if (connect(syslog_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
159                         r = -errno;
160                         goto fail;
161                 }
162 
163                 syslog_is_stream = true;
164         } else
165                 syslog_is_stream = false;
166 
167         return 0;
168 
169 fail:
170         log_close_syslog();
171         return r;
172 }
173 
log_open(void)174 int log_open(void) {
175         int r;
176 
177         /* If we don't use the console we close it here, to not get
178          * killed by SAK. If we don't use syslog we close it here so
179          * that we are not confused by somebody deleting the socket in
180          * the fs. If we don't use /dev/kmsg we still keep it open,
181          * because there is no reason to close it. */
182 
183         if (log_target == LOG_TARGET_NULL) {
184                 log_close_syslog();
185                 log_close_console();
186                 return 0;
187         }
188 
189         if ((log_target != LOG_TARGET_AUTO && log_target != LOG_TARGET_SAFE) ||
190             getpid() == 1 ||
191             isatty(STDERR_FILENO) <= 0) {
192 
193                 if (log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
194                     log_target == LOG_TARGET_SYSLOG) {
195                         r = log_open_syslog();
196                         if (r >= 0) {
197                                 log_close_console();
198                                 return r;
199                         }
200                 }
201 
202                 if (log_target == LOG_TARGET_AUTO ||
203                     log_target == LOG_TARGET_SAFE ||
204                     log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
205                     log_target == LOG_TARGET_KMSG) {
206                         r = log_open_kmsg();
207                         if (r >= 0) {
208                                 log_close_syslog();
209                                 log_close_console();
210                                 return r;
211                         }
212                 }
213         }
214 
215         log_close_syslog();
216 
217         return log_open_console();
218 }
219 
log_set_target(LogTarget target)220 void log_set_target(LogTarget target) {
221         assert(target >= 0);
222         assert(target < _LOG_TARGET_MAX);
223 
224         log_target = target;
225 }
226 
log_close(void)227 void log_close(void) {
228         log_close_syslog();
229         log_close_kmsg();
230         log_close_console();
231 }
232 
log_set_max_level(int level)233 void log_set_max_level(int level) {
234         assert((level & LOG_PRIMASK) == level);
235 
236         log_max_level = level;
237 }
238 
write_to_console(int level,int error,const char * file,int line,const char * func,const char * object_field,const char * object,const char * buffer)239 static int write_to_console(
240                 int level,
241                 int error,
242                 const char *file,
243                 int line,
244                 const char *func,
245                 const char *object_field,
246                 const char *object,
247                 const char *buffer) {
248 
249         char location[64], prefix[1 + DECIMAL_STR_MAX(int) + 2];
250         struct iovec iovec[6] = {};
251         unsigned n = 0;
252         bool highlight;
253 
254         if (console_fd < 0)
255                 return 0;
256 
257         if (log_target == LOG_TARGET_CONSOLE_PREFIXED) {
258                 sprintf(prefix, "<%i>", level);
259                 IOVEC_SET_STRING(iovec[n++], prefix);
260         }
261 
262         highlight = LOG_PRI(level) <= LOG_ERR && show_color;
263 
264         if (show_location) {
265                 snprintf(location, sizeof(location), "(%s:%i) ", file, line);
266                 char_array_0(location);
267                 IOVEC_SET_STRING(iovec[n++], location);
268         }
269 
270         if (highlight)
271                 IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_RED_ON);
272         IOVEC_SET_STRING(iovec[n++], buffer);
273         if (highlight)
274                 IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_OFF);
275         IOVEC_SET_STRING(iovec[n++], "\n");
276 
277         if (writev(console_fd, iovec, n) < 0) {
278 
279                 if (errno == EIO && getpid() == 1) {
280 
281                         /* If somebody tried to kick us from our
282                          * console tty (via vhangup() or suchlike),
283                          * try to reconnect */
284 
285                         log_close_console();
286                         log_open_console();
287 
288                         if (console_fd < 0)
289                                 return 0;
290 
291                         if (writev(console_fd, iovec, n) < 0)
292                                 return -errno;
293                 } else
294                         return -errno;
295         }
296 
297         return 1;
298 }
299 
write_to_syslog(int level,int error,const char * file,int line,const char * func,const char * object_field,const char * object,const char * buffer)300 static int write_to_syslog(
301                 int level,
302                 int error,
303                 const char *file,
304                 int line,
305                 const char *func,
306                 const char *object_field,
307                 const char *object,
308                 const char *buffer) {
309 
310         char header_priority[1 + DECIMAL_STR_MAX(int) + 2], header_time[64], header_pid[1 + DECIMAL_STR_MAX(pid_t) + 4];
311         struct iovec iovec[5] = {};
312         struct msghdr msghdr = {
313                 .msg_iov = iovec,
314                 .msg_iovlen = ELEMENTSOF(iovec),
315         };
316         time_t t;
317         struct tm *tm;
318 
319         if (syslog_fd < 0)
320                 return 0;
321 
322         snprintf(header_priority, sizeof(header_priority), "<%i>", level);
323         char_array_0(header_priority);
324 
325         t = (time_t) (now(CLOCK_REALTIME) / USEC_PER_SEC);
326         tm = localtime(&t);
327         if (!tm)
328                 return -EINVAL;
329 
330         if (strftime(header_time, sizeof(header_time), "%h %e %T ", tm) <= 0)
331                 return -EINVAL;
332 
333         snprintf(header_pid, sizeof(header_pid), "["PID_FMT"]: ", getpid());
334         char_array_0(header_pid);
335 
336         IOVEC_SET_STRING(iovec[0], header_priority);
337         IOVEC_SET_STRING(iovec[1], header_time);
338         IOVEC_SET_STRING(iovec[2], program_invocation_short_name);
339         IOVEC_SET_STRING(iovec[3], header_pid);
340         IOVEC_SET_STRING(iovec[4], buffer);
341 
342         /* When using syslog via SOCK_STREAM separate the messages by NUL chars */
343         if (syslog_is_stream)
344                 iovec[4].iov_len++;
345 
346         for (;;) {
347                 ssize_t n;
348 
349                 n = sendmsg(syslog_fd, &msghdr, MSG_NOSIGNAL);
350                 if (n < 0)
351                         return -errno;
352 
353                 if (!syslog_is_stream ||
354                     (size_t) n >= IOVEC_TOTAL_SIZE(iovec, ELEMENTSOF(iovec)))
355                         break;
356 
357                 IOVEC_INCREMENT(iovec, ELEMENTSOF(iovec), n);
358         }
359 
360         return 1;
361 }
362 
write_to_kmsg(int level,int error,const char * file,int line,const char * func,const char * object_field,const char * object,const char * buffer)363 static int write_to_kmsg(
364                 int level,
365                 int error,
366                 const char*file,
367                 int line,
368                 const char *func,
369                 const char *object_field,
370                 const char *object,
371                 const char *buffer) {
372 
373         char header_priority[1 + DECIMAL_STR_MAX(int) + 2], header_pid[1 + DECIMAL_STR_MAX(pid_t) + 4];
374         struct iovec iovec[5] = {};
375 
376         if (kmsg_fd < 0)
377                 return 0;
378 
379         snprintf(header_priority, sizeof(header_priority), "<%i>", level);
380         char_array_0(header_priority);
381 
382         snprintf(header_pid, sizeof(header_pid), "["PID_FMT"]: ", getpid());
383         char_array_0(header_pid);
384 
385         IOVEC_SET_STRING(iovec[0], header_priority);
386         IOVEC_SET_STRING(iovec[1], program_invocation_short_name);
387         IOVEC_SET_STRING(iovec[2], header_pid);
388         IOVEC_SET_STRING(iovec[3], buffer);
389         IOVEC_SET_STRING(iovec[4], "\n");
390 
391         if (writev(kmsg_fd, iovec, ELEMENTSOF(iovec)) < 0)
392                 return -errno;
393 
394         return 1;
395 }
396 
log_dispatch(int level,int error,const char * file,int line,const char * func,const char * object_field,const char * object,char * buffer)397 static int log_dispatch(
398                 int level,
399                 int error,
400                 const char*file,
401                 int line,
402                 const char *func,
403                 const char *object_field,
404                 const char *object,
405                 char *buffer) {
406 
407         int r = 0;
408 
409         if (log_target == LOG_TARGET_NULL)
410                 return 0;
411 
412         /* Patch in LOG_DAEMON facility if necessary */
413         if ((level & LOG_FACMASK) == 0)
414                 level = log_facility | LOG_PRI(level);
415 
416         do {
417                 char *e;
418                 int k = 0;
419 
420                 buffer += strspn(buffer, NEWLINE);
421 
422                 if (buffer[0] == 0)
423                         break;
424 
425                 if ((e = strpbrk(buffer, NEWLINE)))
426                         *(e++) = 0;
427 
428                 if (log_target == LOG_TARGET_AUTO)
429                         log_open_kmsg();
430 
431                 if (log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
432                     log_target == LOG_TARGET_SYSLOG) {
433 
434                         k = write_to_syslog(level, error, file, line, func, object_field, object, buffer);
435                         if (k < 0) {
436                                 if (k != -EAGAIN)
437                                         log_close_syslog();
438                                 log_open_kmsg();
439                         } else if (k > 0)
440                                 r++;
441                 }
442 
443                 if (k <= 0 &&
444                     (log_target == LOG_TARGET_AUTO ||
445                      log_target == LOG_TARGET_SAFE ||
446                      log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
447                      log_target == LOG_TARGET_KMSG)) {
448 
449                         k = write_to_kmsg(level, error, file, line, func, object_field, object, buffer);
450                         if (k < 0) {
451                                 log_close_kmsg();
452                                 log_open_console();
453                         } else if (k > 0)
454                                 r++;
455                 }
456 
457                 if (k <= 0) {
458                         k = write_to_console(level, error, file, line, func, object_field, object, buffer);
459                         if (k < 0)
460                                 return k;
461                 }
462 
463                 buffer = e;
464         } while (buffer);
465 
466         return r;
467 }
468 
log_internalv(int level,int error,const char * file,int line,const char * func,const char * format,va_list ap)469 int log_internalv(
470         int level,
471         int error,
472         const char*file,
473         int line,
474         const char *func,
475         const char *format,
476         va_list ap) {
477 
478         PROTECT_ERRNO;
479         char buffer[LINE_MAX];
480 
481         if (_likely_(LOG_PRI(level) > log_max_level))
482                 return 0;
483 
484         vsnprintf(buffer, sizeof(buffer), format, ap);
485         char_array_0(buffer);
486 
487         return log_dispatch(level, error, file, line, func, NULL, NULL, buffer);
488 }
489 
log_internal(int level,int error,const char * file,int line,const char * func,const char * format,...)490 int log_internal(
491                 int level,
492                 int error,
493                 const char*file,
494                 int line,
495                 const char *func,
496                 const char *format, ...) {
497 
498         int r;
499         va_list ap;
500 
501         va_start(ap, format);
502         r = log_internalv(level, error, file, line, func, format, ap);
503         va_end(ap);
504 
505         return r;
506 }
507 
log_assert(int level,const char * text,const char * file,int line,const char * func,const char * format)508 static void log_assert(
509                 int level,
510                 const char *text,
511                 const char *file,
512                 int line,
513                 const char *func,
514                 const char *format) {
515         static char buffer[LINE_MAX];
516 
517         if (_likely_(LOG_PRI(level) > log_max_level))
518                 return;
519 
520         DISABLE_WARNING_FORMAT_NONLITERAL;
521         snprintf(buffer, sizeof(buffer), format, text, file, line, func);
522         REENABLE_WARNING;
523 
524         char_array_0(buffer);
525         log_abort_msg = buffer;
526 
527         log_dispatch(level, 0, file, line, func, NULL, NULL, buffer);
528 }
529 
log_assert_failed(const char * text,const char * file,int line,const char * func)530 noreturn void log_assert_failed(const char *text, const char *file, int line, const char *func) {
531         log_assert(LOG_CRIT, text, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Aborting.");
532         abort();
533 }
534 
log_assert_failed_unreachable(const char * text,const char * file,int line,const char * func)535 noreturn void log_assert_failed_unreachable(const char *text, const char *file, int line, const char *func) {
536         log_assert(LOG_CRIT, text, file, line, func, "Code should not be reached '%s' at %s:%u, function %s(). Aborting.");
537         abort();
538 }
539 
log_oom_internal(const char * file,int line,const char * func)540 int log_oom_internal(const char *file, int line, const char *func) {
541         log_internal(LOG_ERR, ENOMEM, file, line, func, "Out of memory.");
542         return -ENOMEM;
543 }
544 
log_get_max_level(void)545 int log_get_max_level(void) {
546         return log_max_level;
547 }
548 static const char *const log_target_table[] = {
549         [LOG_TARGET_CONSOLE] = "console",
550         [LOG_TARGET_CONSOLE_PREFIXED] = "console-prefixed",
551         [LOG_TARGET_KMSG] = "kmsg",
552         [LOG_TARGET_SYSLOG] = "syslog",
553         [LOG_TARGET_SYSLOG_OR_KMSG] = "syslog-or-kmsg",
554         [LOG_TARGET_AUTO] = "auto",
555         [LOG_TARGET_SAFE] = "safe",
556         [LOG_TARGET_NULL] = "null"
557 };
558 
559 DEFINE_STRING_TABLE_LOOKUP(log_target, LogTarget);
560