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