]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/log.c
fsck: don't be idempotent for root directories
[thirdparty/systemd.git] / src / log.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
5899f3b7 2
a7334b09
LP
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
5899f3b7
LP
22#include <stdarg.h>
23#include <stdio.h>
c9b97d2a 24#include <errno.h>
16801e90
LP
25#include <unistd.h>
26#include <fcntl.h>
27#include <sys/socket.h>
28#include <sys/un.h>
5899f3b7
LP
29
30#include "log.h"
16801e90
LP
31#include "util.h"
32#include "macro.h"
5899f3b7 33
16801e90 34#define SYSLOG_TIMEOUT_USEC (5*USEC_PER_SEC)
16801e90
LP
35
36static LogTarget log_target = LOG_TARGET_CONSOLE;
bbe63281 37static int log_max_level = LOG_INFO;
16801e90 38
843d2643 39static int console_fd = STDERR_FILENO;
16801e90
LP
40static int syslog_fd = -1;
41static int kmsg_fd = -1;
42
c31e1495
LP
43static bool syslog_is_stream = false;
44
bbe63281
LP
45static bool show_color = false;
46static bool show_location = false;
47
185986c6
LP
48/* Akin to glibc's __abort_msg; which is private and we hance cannot
49 * use here. */
50static char *log_abort_msg = NULL;
51
843d2643
LP
52void log_close_console(void) {
53
54 if (console_fd < 0)
55 return;
16801e90 56
c8513d54
LP
57 if (getpid() == 1) {
58 if (console_fd >= 3)
59 close_nointr_nofail(console_fd);
60
843d2643 61 console_fd = -1;
16801e90
LP
62 }
63}
64
843d2643 65static int log_open_console(void) {
16801e90 66
843d2643 67 if (console_fd >= 0)
16801e90 68 return 0;
843d2643
LP
69
70 if (getpid() == 1) {
71
72 if ((console_fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC)) < 0) {
73 log_error("Failed to open /dev/console for logging: %s", strerror(-console_fd));
74 return console_fd;
75 }
76
2396fb04 77 log_debug("Succesfully opened /dev/console for logging.");
843d2643
LP
78 } else
79 console_fd = STDERR_FILENO;
80
81 return 0;
82}
83
84void log_close_kmsg(void) {
85
86 if (kmsg_fd < 0)
87 return;
88
89 close_nointr_nofail(kmsg_fd);
90 kmsg_fd = -1;
91}
92
93static int log_open_kmsg(void) {
16801e90
LP
94
95 if (kmsg_fd >= 0)
96 return 0;
97
c9b80453 98 if ((kmsg_fd = open("/dev/kmsg", O_WRONLY|O_NOCTTY|O_CLOEXEC)) < 0) {
843d2643 99 log_info("Failed to open /dev/kmsg for logging: %s", strerror(errno));
16801e90 100 return -errno;
c9b80453 101 }
16801e90 102
2396fb04 103 log_debug("Succesfully opened /dev/kmsg for logging.");
0dae83f9 104
16801e90
LP
105 return 0;
106}
107
108void log_close_syslog(void) {
109
843d2643
LP
110 if (syslog_fd < 0)
111 return;
112
113 close_nointr_nofail(syslog_fd);
114 syslog_fd = -1;
16801e90
LP
115}
116
c31e1495
LP
117static int create_log_socket(int type) {
118 struct timeval tv;
119 int fd;
120
121 if ((fd = socket(AF_UNIX, type|SOCK_CLOEXEC, 0)) < 0)
122 return -errno;
123
124 /* Make sure we don't block for more than 5s when talking to
125 * syslog */
126 timeval_store(&tv, SYSLOG_TIMEOUT_USEC);
127 if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0) {
128 close_nointr_nofail(fd);
129 return -errno;
130 }
131
132 return fd;
133}
134
843d2643 135static int log_open_syslog(void) {
16801e90
LP
136 union {
137 struct sockaddr sa;
138 struct sockaddr_un un;
139 } sa;
16801e90
LP
140 int r;
141
16801e90
LP
142 if (syslog_fd >= 0)
143 return 0;
144
16801e90
LP
145 zero(sa);
146 sa.un.sun_family = AF_UNIX;
147 strncpy(sa.un.sun_path, "/dev/log", sizeof(sa.un.sun_path));
148
c31e1495 149 if ((syslog_fd = create_log_socket(SOCK_DGRAM)) < 0) {
16801e90 150 r = -errno;
843d2643 151 goto fail;
16801e90
LP
152 }
153
c31e1495
LP
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 if ((syslog_fd = create_log_socket(SOCK_STREAM)) < 0) {
161 r = -errno;
162 goto fail;
163 }
164
165 if (connect(syslog_fd, &sa.sa, sizeof(sa)) < 0) {
166 r = -errno;
167 goto fail;
168 }
169
170 syslog_is_stream = true;
171 } else
172 syslog_is_stream = false;
173
2396fb04 174 log_debug("Succesfully opened syslog for logging.");
0dae83f9 175
16801e90 176 return 0;
843d2643
LP
177
178fail:
179 log_close_syslog();
180 log_info("Failed to open syslog for logging: %s", strerror(-r));
181 return r;
182}
183
184int log_open(void) {
185 int r;
186
187 /* If we don't use the console we close it here, to not get
188 * killed by SAK. If we don't use syslog we close it here so
189 * that we are not confused by somebody deleting the socket in
190 * the fs. If we don't use /dev/kmsg we still keep it open,
191 * because there is no reason to close it. */
192
9fae33d2
LP
193 if (log_target == LOG_TARGET_NULL) {
194 log_close_syslog();
195 log_close_console();
196 return 0;
197 }
198
843d2643
LP
199 if (log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
200 log_target == LOG_TARGET_SYSLOG)
201 if ((r = log_open_syslog()) >= 0) {
202 log_close_console();
203 return r;
204 }
205
206 if (log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
207 log_target == LOG_TARGET_KMSG)
208 if ((r = log_open_kmsg()) >= 0) {
209 log_close_syslog();
210 log_close_console();
211 return r;
212 }
213
214 log_close_syslog();
215 return log_open_console();
16801e90
LP
216}
217
218void log_set_target(LogTarget target) {
219 assert(target >= 0);
220 assert(target < _LOG_TARGET_MAX);
221
222 log_target = target;
223}
224
225void log_set_max_level(int level) {
226 assert((level & LOG_PRIMASK) == level);
227
228 log_max_level = level;
229}
230
843d2643 231static int write_to_console(
5899f3b7
LP
232 int level,
233 const char*file,
234 int line,
235 const char *func,
843d2643 236 const char *buffer) {
5899f3b7 237
843d2643
LP
238 char location[64];
239 struct iovec iovec[5];
240 unsigned n = 0;
241 bool highlight;
5899f3b7 242
843d2643
LP
243 if (console_fd < 0)
244 return 0;
245
246 snprintf(location, sizeof(location), "(%s:%u) ", file, line);
247 char_array_0(location);
248
bbe63281 249 highlight = LOG_PRI(level) <= LOG_ERR && show_color;
843d2643
LP
250
251 zero(iovec);
bbe63281
LP
252 if (show_location)
253 IOVEC_SET_STRING(iovec[n++], location);
843d2643 254 if (highlight)
61cbdc4b 255 IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_ON);
843d2643
LP
256 IOVEC_SET_STRING(iovec[n++], buffer);
257 if (highlight)
61cbdc4b 258 IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_OFF);
843d2643
LP
259 IOVEC_SET_STRING(iovec[n++], "\n");
260
261 if (writev(console_fd, iovec, n) < 0)
262 return -errno;
5899f3b7 263
843d2643 264 return 1;
16801e90 265}
5899f3b7 266
16801e90
LP
267static int write_to_syslog(
268 int level,
269 const char*file,
270 int line,
271 const char *func,
843d2643 272 const char *buffer) {
16801e90
LP
273
274 char header_priority[16], header_time[64], header_pid[16];
16801e90
LP
275 struct iovec iovec[5];
276 struct msghdr msghdr;
277 time_t t;
278 struct tm *tm;
279
280 if (syslog_fd < 0)
843d2643 281 return 0;
16801e90
LP
282
283 snprintf(header_priority, sizeof(header_priority), "<%i>", LOG_MAKEPRI(LOG_DAEMON, LOG_PRI(level)));
284 char_array_0(header_priority);
285
286 t = (time_t) (now(CLOCK_REALTIME) / USEC_PER_SEC);
287 if (!(tm = localtime(&t)))
288 return -EINVAL;
289
290 if (strftime(header_time, sizeof(header_time), "%h %e %T ", tm) <= 0)
291 return -EINVAL;
292
bb00e604 293 snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) getpid());
16801e90
LP
294 char_array_0(header_pid);
295
16801e90
LP
296 zero(iovec);
297 IOVEC_SET_STRING(iovec[0], header_priority);
298 IOVEC_SET_STRING(iovec[1], header_time);
5b6319dc 299 IOVEC_SET_STRING(iovec[2], program_invocation_short_name);
16801e90
LP
300 IOVEC_SET_STRING(iovec[3], header_pid);
301 IOVEC_SET_STRING(iovec[4], buffer);
302
c899f8c6 303 /* When using syslog via SOCK_STREAM separate the messages by NUL chars */
c31e1495
LP
304 if (syslog_is_stream)
305 iovec[4].iov_len++;
306
16801e90
LP
307 zero(msghdr);
308 msghdr.msg_iov = iovec;
309 msghdr.msg_iovlen = ELEMENTSOF(iovec);
310
c31e1495
LP
311 for (;;) {
312 ssize_t n;
313
314 if ((n = sendmsg(syslog_fd, &msghdr, MSG_NOSIGNAL)) < 0)
315 return -errno;
316
317 if (!syslog_is_stream ||
318 (size_t) n >= IOVEC_TOTAL_SIZE(iovec, ELEMENTSOF(iovec)))
319 break;
320
321 IOVEC_INCREMENT(iovec, ELEMENTSOF(iovec), n);
322 }
16801e90 323
843d2643 324 return 1;
16801e90
LP
325}
326
327static int write_to_kmsg(
328 int level,
329 const char*file,
330 int line,
331 const char *func,
843d2643 332 const char *buffer) {
16801e90
LP
333
334 char header_priority[16], header_pid[16];
16801e90
LP
335 struct iovec iovec[5];
336
337 if (kmsg_fd < 0)
843d2643 338 return 0;
16801e90
LP
339
340 snprintf(header_priority, sizeof(header_priority), "<%i>", LOG_PRI(level));
341 char_array_0(header_priority);
342
bb00e604 343 snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) getpid());
16801e90
LP
344 char_array_0(header_pid);
345
16801e90
LP
346 zero(iovec);
347 IOVEC_SET_STRING(iovec[0], header_priority);
5b6319dc 348 IOVEC_SET_STRING(iovec[1], program_invocation_short_name);
16801e90
LP
349 IOVEC_SET_STRING(iovec[2], header_pid);
350 IOVEC_SET_STRING(iovec[3], buffer);
843d2643 351 IOVEC_SET_STRING(iovec[4], "\n");
16801e90
LP
352
353 if (writev(kmsg_fd, iovec, ELEMENTSOF(iovec)) < 0)
354 return -errno;
355
843d2643 356 return 1;
16801e90
LP
357}
358
843d2643
LP
359static int log_dispatch(
360 int level,
361 const char*file,
362 int line,
363 const char *func,
9726b29e 364 char *buffer) {
843d2643 365
9726b29e 366 int r = 0;
843d2643 367
9fae33d2
LP
368 if (log_target == LOG_TARGET_NULL)
369 return 0;
370
9726b29e
LP
371 do {
372 char *e;
9499b235 373 int k = 0;
843d2643 374
9726b29e 375 buffer += strspn(buffer, NEWLINE);
843d2643 376
9726b29e
LP
377 if (buffer[0] == 0)
378 break;
843d2643 379
9726b29e
LP
380 if ((e = strpbrk(buffer, NEWLINE)))
381 *(e++) = 0;
843d2643 382
9726b29e
LP
383 if (log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
384 log_target == LOG_TARGET_SYSLOG) {
385
9499b235 386 if ((k = write_to_syslog(level, file, line, func, buffer)) < 0) {
9726b29e
LP
387 log_close_syslog();
388 log_open_kmsg();
9499b235 389 } else if (k > 0)
9726b29e
LP
390 r++;
391 }
392
9499b235
LP
393 if (k <= 0 &&
394 (log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
395 log_target == LOG_TARGET_KMSG)) {
9726b29e 396
9499b235 397 if ((k = write_to_kmsg(level, file, line, func, buffer)) < 0) {
9726b29e
LP
398 log_close_kmsg();
399 log_open_console();
9499b235 400 } else if (k > 0)
9726b29e
LP
401 r++;
402 }
403
9499b235
LP
404 if (k <= 0 &&
405 (k = write_to_console(level, file, line, func, buffer)) < 0)
9726b29e
LP
406 return k;
407
408 buffer = e;
409 } while (buffer);
410
411 return r;
843d2643
LP
412}
413
2149e37c
LP
414int log_dump_internal(
415 int level,
416 const char*file,
417 int line,
418 const char *func,
419 char *buffer) {
420
421 int saved_errno, r;
422
423 /* This modifies the buffer... */
424
425 if (_likely_(LOG_PRI(level) > log_max_level))
426 return 0;
427
428 saved_errno = errno;
429 r = log_dispatch(level, file, line, func, buffer);
430 errno = saved_errno;
431
432 return r;
433}
434
843d2643 435int log_meta(
16801e90
LP
436 int level,
437 const char*file,
438 int line,
439 const char *func,
440 const char *format, ...) {
441
addab137 442 char buffer[LINE_MAX];
843d2643
LP
443 int saved_errno, r;
444 va_list ap;
16801e90 445
93a46b0b 446 if (_likely_(LOG_PRI(level) > log_max_level))
843d2643 447 return 0;
16801e90
LP
448
449 saved_errno = errno;
843d2643
LP
450
451 va_start(ap, format);
452 vsnprintf(buffer, sizeof(buffer), format, ap);
453 va_end(ap);
454
455 char_array_0(buffer);
456
457 r = log_dispatch(level, file, line, func, buffer);
185986c6 458 errno = saved_errno;
843d2643
LP
459
460 return r;
185986c6 461}
16801e90 462
185986c6
LP
463void log_assert(
464 const char*file,
465 int line,
466 const char *func,
467 const char *format, ...) {
468
addab137 469 static char buffer[LINE_MAX];
185986c6 470 int saved_errno = errno;
843d2643 471 va_list ap;
185986c6
LP
472
473 va_start(ap, format);
474 vsnprintf(buffer, sizeof(buffer), format, ap);
475 va_end(ap);
476
477 char_array_0(buffer);
478 log_abort_msg = buffer;
479
843d2643 480 log_dispatch(LOG_CRIT, file, line, func, buffer);
185986c6 481 abort();
5899f3b7 482
185986c6 483 /* If the user chose to ignore this SIGABRT, we are happy to go on, as if nothing happened. */
c9b97d2a 484 errno = saved_errno;
5899f3b7 485}
34f0e866
LP
486
487int log_set_target_from_string(const char *e) {
488 LogTarget t;
489
490 if ((t = log_target_from_string(e)) < 0)
491 return -EINVAL;
492
493 log_set_target(t);
494 return 0;
495}
496
497int log_set_max_level_from_string(const char *e) {
498 int t;
499
500 if ((t = log_level_from_string(e)) < 0)
501 return -EINVAL;
502
503 log_set_max_level(t);
504 return 0;
505}
506
507void log_parse_environment(void) {
508 const char *e;
509
510 if ((e = getenv("SYSTEMD_LOG_TARGET")))
511 if (log_set_target_from_string(e) < 0)
512 log_warning("Failed to parse log target %s. Ignoring.", e);
513
514 if ((e = getenv("SYSTEMD_LOG_LEVEL")))
515 if (log_set_max_level_from_string(e) < 0)
516 log_warning("Failed to parse log level %s. Ignoring.", e);
bbe63281 517
541d6159 518 if ((e = getenv("SYSTEMD_LOG_COLOR")))
bbe63281
LP
519 if (log_show_color_from_string(e) < 0)
520 log_warning("Failed to parse bool %s. Ignoring.", e);
521
541d6159 522 if ((e = getenv("SYSTEMD_LOG_LOCATION"))) {
bbe63281
LP
523 if (log_show_location_from_string(e) < 0)
524 log_warning("Failed to parse bool %s. Ignoring.", e);
525 }
34f0e866
LP
526}
527
1adf1049
LP
528LogTarget log_get_target(void) {
529 return log_target;
530}
531
532int log_get_max_level(void) {
533 return log_max_level;
534}
535
bbe63281
LP
536void log_show_color(bool b) {
537 show_color = b;
538}
539
540void log_show_location(bool b) {
541 show_location = b;
542}
543
544int log_show_color_from_string(const char *e) {
545 int t;
546
547 if ((t = parse_boolean(e)) < 0)
548 return -EINVAL;
549
550 log_show_color(t);
551 return 0;
552}
553
554int log_show_location_from_string(const char *e) {
555 int t;
556
557 if ((t = parse_boolean(e)) < 0)
558 return -EINVAL;
559
560 log_show_location(t);
561 return 0;
562}
563
34f0e866
LP
564static const char *const log_target_table[] = {
565 [LOG_TARGET_CONSOLE] = "console",
566 [LOG_TARGET_SYSLOG] = "syslog",
567 [LOG_TARGET_KMSG] = "kmsg",
843d2643 568 [LOG_TARGET_SYSLOG_OR_KMSG] = "syslog-or-kmsg",
9fae33d2 569 [LOG_TARGET_NULL] = "null"
34f0e866
LP
570};
571
572DEFINE_STRING_TABLE_LOOKUP(log_target, LogTarget);