1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2011 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
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 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
26 #include <selinux/selinux.h>
29 #include "sd-daemon.h"
32 #include "dirent-util.h"
37 #include "journald-console.h"
38 #include "journald-kmsg.h"
39 #include "journald-server.h"
40 #include "journald-stream.h"
41 #include "journald-syslog.h"
42 #include "journald-wall.h"
44 #include "parse-util.h"
45 #include "selinux-util.h"
46 #include "socket-util.h"
47 #include "stdio-util.h"
48 #include "string-util.h"
49 #include "syslog-util.h"
51 #define STDOUT_STREAMS_MAX 4096
53 typedef enum StdoutStreamState
{
54 STDOUT_STREAM_IDENTIFIER
,
55 STDOUT_STREAM_UNIT_ID
,
56 STDOUT_STREAM_PRIORITY
,
57 STDOUT_STREAM_LEVEL_PREFIX
,
58 STDOUT_STREAM_FORWARD_TO_SYSLOG
,
59 STDOUT_STREAM_FORWARD_TO_KMSG
,
60 STDOUT_STREAM_FORWARD_TO_CONSOLE
,
66 StdoutStreamState state
;
76 bool forward_to_syslog
:1;
77 bool forward_to_kmsg
:1;
78 bool forward_to_console
:1;
82 char buffer
[LINE_MAX
+1];
85 sd_event_source
*event_source
;
89 LIST_FIELDS(StdoutStream
, stdout_stream
);
92 void stdout_stream_free(StdoutStream
*s
) {
97 assert(s
->server
->n_stdout_streams
> 0);
98 s
->server
->n_stdout_streams
--;
99 LIST_REMOVE(stdout_stream
, s
->server
->stdout_streams
, s
);
102 if (s
->event_source
) {
103 sd_event_source_set_enabled(s
->event_source
, SD_EVENT_OFF
);
104 s
->event_source
= sd_event_source_unref(s
->event_source
);
116 DEFINE_TRIVIAL_CLEANUP_FUNC(StdoutStream
*, stdout_stream_free
);
118 static void stdout_stream_destroy(StdoutStream
*s
) {
123 unlink(s
->state_file
);
125 stdout_stream_free(s
);
128 static int stdout_stream_save(StdoutStream
*s
) {
129 _cleanup_free_
char *temp_path
= NULL
;
130 _cleanup_fclose_
FILE *f
= NULL
;
135 if (s
->state
!= STDOUT_STREAM_RUNNING
)
138 if (!s
->state_file
) {
141 r
= fstat(s
->fd
, &st
);
143 return log_warning_errno(errno
, "Failed to stat connected stream: %m");
145 /* We use device and inode numbers as identifier for the stream */
146 if (asprintf(&s
->state_file
, "/run/systemd/journal/streams/%lu:%lu", (unsigned long) st
.st_dev
, (unsigned long) st
.st_ino
) < 0)
150 mkdir_p("/run/systemd/journal/streams", 0755);
152 r
= fopen_temporary(s
->state_file
, &f
, &temp_path
);
157 "# This is private data. Do not parse\n"
160 "FORWARD_TO_SYSLOG=%i\n"
161 "FORWARD_TO_KMSG=%i\n"
162 "FORWARD_TO_CONSOLE=%i\n",
165 s
->forward_to_syslog
,
167 s
->forward_to_console
);
169 if (!isempty(s
->identifier
)) {
170 _cleanup_free_
char *escaped
;
172 escaped
= cescape(s
->identifier
);
178 fprintf(f
, "IDENTIFIER=%s\n", escaped
);
181 if (!isempty(s
->unit_id
)) {
182 _cleanup_free_
char *escaped
;
184 escaped
= cescape(s
->unit_id
);
190 fprintf(f
, "UNIT=%s\n", escaped
);
193 r
= fflush_and_check(f
);
197 if (rename(temp_path
, s
->state_file
) < 0) {
202 /* Store the connection fd in PID 1, so that we get it passed
203 * in again on next start */
205 sd_pid_notify_with_fds(0, false, "FDSTORE=1", &s
->fd
, 1);
212 (void) unlink(s
->state_file
);
215 (void) unlink(temp_path
);
217 return log_error_errno(r
, "Failed to save stream data %s: %m", s
->state_file
);
220 static int stdout_stream_log(StdoutStream
*s
, const char *p
) {
221 struct iovec iovec
[N_IOVEC_META_FIELDS
+ 5];
223 char syslog_priority
[] = "PRIORITY=\0";
224 char syslog_facility
[sizeof("SYSLOG_FACILITY=")-1 + DECIMAL_STR_MAX(int) + 1];
225 _cleanup_free_
char *message
= NULL
, *syslog_identifier
= NULL
;
235 priority
= s
->priority
;
238 syslog_parse_priority(&p
, &priority
, false);
240 if (s
->forward_to_syslog
|| s
->server
->forward_to_syslog
)
241 server_forward_syslog(s
->server
, syslog_fixup_facility(priority
), s
->identifier
, p
, &s
->ucred
, NULL
);
243 if (s
->forward_to_kmsg
|| s
->server
->forward_to_kmsg
)
244 server_forward_kmsg(s
->server
, priority
, s
->identifier
, p
, &s
->ucred
);
246 if (s
->forward_to_console
|| s
->server
->forward_to_console
)
247 server_forward_console(s
->server
, priority
, s
->identifier
, p
, &s
->ucred
);
249 if (s
->server
->forward_to_wall
)
250 server_forward_wall(s
->server
, priority
, s
->identifier
, p
, &s
->ucred
);
252 IOVEC_SET_STRING(iovec
[n
++], "_TRANSPORT=stdout");
254 syslog_priority
[strlen("PRIORITY=")] = '0' + LOG_PRI(priority
);
255 IOVEC_SET_STRING(iovec
[n
++], syslog_priority
);
257 if (priority
& LOG_FACMASK
) {
258 xsprintf(syslog_facility
, "SYSLOG_FACILITY=%i", LOG_FAC(priority
));
259 IOVEC_SET_STRING(iovec
[n
++], syslog_facility
);
263 syslog_identifier
= strappend("SYSLOG_IDENTIFIER=", s
->identifier
);
264 if (syslog_identifier
)
265 IOVEC_SET_STRING(iovec
[n
++], syslog_identifier
);
268 message
= strappend("MESSAGE=", p
);
270 IOVEC_SET_STRING(iovec
[n
++], message
);
272 label_len
= s
->label
? strlen(s
->label
) : 0;
273 server_dispatch_message(s
->server
, iovec
, n
, ELEMENTSOF(iovec
), &s
->ucred
, NULL
, s
->label
, label_len
, s
->unit_id
, priority
, 0);
277 static int stdout_stream_line(StdoutStream
*s
, char *p
) {
287 case STDOUT_STREAM_IDENTIFIER
:
289 s
->identifier
= NULL
;
291 s
->identifier
= strdup(p
);
296 s
->state
= STDOUT_STREAM_UNIT_ID
;
299 case STDOUT_STREAM_UNIT_ID
:
300 if (s
->ucred
.uid
== 0) {
304 s
->unit_id
= strdup(p
);
310 s
->state
= STDOUT_STREAM_PRIORITY
;
313 case STDOUT_STREAM_PRIORITY
:
314 r
= safe_atoi(p
, &s
->priority
);
315 if (r
< 0 || s
->priority
< 0 || s
->priority
> 999) {
316 log_warning("Failed to parse log priority line.");
320 s
->state
= STDOUT_STREAM_LEVEL_PREFIX
;
323 case STDOUT_STREAM_LEVEL_PREFIX
:
324 r
= parse_boolean(p
);
326 log_warning("Failed to parse level prefix line.");
330 s
->level_prefix
= !!r
;
331 s
->state
= STDOUT_STREAM_FORWARD_TO_SYSLOG
;
334 case STDOUT_STREAM_FORWARD_TO_SYSLOG
:
335 r
= parse_boolean(p
);
337 log_warning("Failed to parse forward to syslog line.");
341 s
->forward_to_syslog
= !!r
;
342 s
->state
= STDOUT_STREAM_FORWARD_TO_KMSG
;
345 case STDOUT_STREAM_FORWARD_TO_KMSG
:
346 r
= parse_boolean(p
);
348 log_warning("Failed to parse copy to kmsg line.");
352 s
->forward_to_kmsg
= !!r
;
353 s
->state
= STDOUT_STREAM_FORWARD_TO_CONSOLE
;
356 case STDOUT_STREAM_FORWARD_TO_CONSOLE
:
357 r
= parse_boolean(p
);
359 log_warning("Failed to parse copy to console line.");
363 s
->forward_to_console
= !!r
;
364 s
->state
= STDOUT_STREAM_RUNNING
;
366 /* Try to save the stream, so that journald can be restarted and we can recover */
367 (void) stdout_stream_save(s
);
370 case STDOUT_STREAM_RUNNING
:
371 return stdout_stream_log(s
, p
);
374 assert_not_reached("Unknown stream state");
377 static int stdout_stream_scan(StdoutStream
*s
, bool force_flush
) {
385 remaining
= s
->length
;
390 end
= memchr(p
, '\n', remaining
);
393 else if (remaining
>= sizeof(s
->buffer
) - 1) {
394 end
= p
+ sizeof(s
->buffer
) - 1;
401 r
= stdout_stream_line(s
, p
);
409 if (force_flush
&& remaining
> 0) {
411 r
= stdout_stream_line(s
, p
);
420 memmove(s
->buffer
, p
, remaining
);
421 s
->length
= remaining
;
427 static int stdout_stream_process(sd_event_source
*es
, int fd
, uint32_t revents
, void *userdata
) {
428 StdoutStream
*s
= userdata
;
434 if ((revents
|EPOLLIN
|EPOLLHUP
) != (EPOLLIN
|EPOLLHUP
)) {
435 log_error("Got invalid event from epoll for stdout stream: %"PRIx32
, revents
);
439 l
= read(s
->fd
, s
->buffer
+s
->length
, sizeof(s
->buffer
)-1-s
->length
);
445 log_warning_errno(errno
, "Failed to read from stream: %m");
450 stdout_stream_scan(s
, true);
455 r
= stdout_stream_scan(s
, false);
462 stdout_stream_destroy(s
);
466 static int stdout_stream_install(Server
*s
, int fd
, StdoutStream
**ret
) {
467 _cleanup_(stdout_stream_freep
) StdoutStream
*stream
= NULL
;
473 stream
= new0(StdoutStream
, 1);
478 stream
->priority
= LOG_INFO
;
480 r
= getpeercred(fd
, &stream
->ucred
);
482 return log_error_errno(r
, "Failed to determine peer credentials: %m");
484 if (mac_selinux_use()) {
485 r
= getpeersec(fd
, &stream
->label
);
486 if (r
< 0 && r
!= -EOPNOTSUPP
)
487 (void) log_warning_errno(r
, "Failed to determine peer security context: %m");
490 (void) shutdown(fd
, SHUT_WR
);
492 r
= sd_event_add_io(s
->event
, &stream
->event_source
, fd
, EPOLLIN
, stdout_stream_process
, stream
);
494 return log_error_errno(r
, "Failed to add stream to event loop: %m");
496 r
= sd_event_source_set_priority(stream
->event_source
, SD_EVENT_PRIORITY_NORMAL
+5);
498 return log_error_errno(r
, "Failed to adjust stdout event source priority: %m");
503 LIST_PREPEND(stdout_stream
, s
->stdout_streams
, stream
);
504 s
->n_stdout_streams
++;
514 static int stdout_stream_new(sd_event_source
*es
, int listen_fd
, uint32_t revents
, void *userdata
) {
515 _cleanup_close_
int fd
= -1;
516 Server
*s
= userdata
;
521 if (revents
!= EPOLLIN
) {
522 log_error("Got invalid event from epoll for stdout server fd: %"PRIx32
, revents
);
526 fd
= accept4(s
->stdout_fd
, NULL
, NULL
, SOCK_NONBLOCK
|SOCK_CLOEXEC
);
531 log_error_errno(errno
, "Failed to accept stdout connection: %m");
535 if (s
->n_stdout_streams
>= STDOUT_STREAMS_MAX
) {
536 log_warning("Too many stdout streams, refusing connection.");
540 r
= stdout_stream_install(s
, fd
, NULL
);
548 static int stdout_stream_load(StdoutStream
*stream
, const char *fname
) {
551 *level_prefix
= NULL
,
552 *forward_to_syslog
= NULL
,
553 *forward_to_kmsg
= NULL
,
554 *forward_to_console
= NULL
;
560 if (!stream
->state_file
) {
561 stream
->state_file
= strappend("/run/systemd/journal/streams/", fname
);
562 if (!stream
->state_file
)
566 r
= parse_env_file(stream
->state_file
, NEWLINE
,
567 "PRIORITY", &priority
,
568 "LEVEL_PREFIX", &level_prefix
,
569 "FORWARD_TO_SYSLOG", &forward_to_syslog
,
570 "FORWARD_TO_KMSG", &forward_to_kmsg
,
571 "FORWARD_TO_CONSOLE", &forward_to_console
,
572 "IDENTIFIER", &stream
->identifier
,
573 "UNIT", &stream
->unit_id
,
576 return log_error_errno(r
, "Failed to read: %s", stream
->state_file
);
581 p
= log_level_from_string(priority
);
583 stream
->priority
= p
;
587 r
= parse_boolean(level_prefix
);
589 stream
->level_prefix
= r
;
592 if (forward_to_syslog
) {
593 r
= parse_boolean(forward_to_syslog
);
595 stream
->forward_to_syslog
= r
;
598 if (forward_to_kmsg
) {
599 r
= parse_boolean(forward_to_kmsg
);
601 stream
->forward_to_kmsg
= r
;
604 if (forward_to_console
) {
605 r
= parse_boolean(forward_to_console
);
607 stream
->forward_to_console
= r
;
613 static int stdout_stream_restore(Server
*s
, const char *fname
, int fd
) {
614 StdoutStream
*stream
;
621 if (s
->n_stdout_streams
>= STDOUT_STREAMS_MAX
) {
622 log_warning("Too many stdout streams, refusing restoring of stream.");
626 r
= stdout_stream_install(s
, fd
, &stream
);
630 stream
->state
= STDOUT_STREAM_RUNNING
;
631 stream
->fdstore
= true;
633 /* Ignore all parsing errors */
634 (void) stdout_stream_load(stream
, fname
);
639 int server_restore_streams(Server
*s
, FDSet
*fds
) {
640 _cleanup_closedir_
DIR *d
= NULL
;
644 d
= opendir("/run/systemd/journal/streams");
649 return log_warning_errno(errno
, "Failed to enumerate /run/systemd/journal/streams: %m");
652 FOREACH_DIRENT(de
, d
, goto fail
) {
653 unsigned long st_dev
, st_ino
;
658 if (sscanf(de
->d_name
, "%lu:%lu", &st_dev
, &st_ino
) != 2)
661 FDSET_FOREACH(fd
, fds
, i
) {
664 if (fstat(fd
, &st
) < 0)
665 return log_error_errno(errno
, "Failed to stat %s: %m", de
->d_name
);
667 if (S_ISSOCK(st
.st_mode
) && st
.st_dev
== st_dev
&& st
.st_ino
== st_ino
) {
674 /* No file descriptor? Then let's delete the state file */
675 log_debug("Cannot restore stream file %s", de
->d_name
);
676 unlinkat(dirfd(d
), de
->d_name
, 0);
680 fdset_remove(fds
, fd
);
682 r
= stdout_stream_restore(s
, de
->d_name
, fd
);
690 return log_error_errno(errno
, "Failed to read streams directory: %m");
693 int server_open_stdout_socket(Server
*s
) {
698 if (s
->stdout_fd
< 0) {
699 union sockaddr_union sa
= {
700 .un
.sun_family
= AF_UNIX
,
701 .un
.sun_path
= "/run/systemd/journal/stdout",
704 s
->stdout_fd
= socket(AF_UNIX
, SOCK_STREAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
705 if (s
->stdout_fd
< 0)
706 return log_error_errno(errno
, "socket() failed: %m");
708 unlink(sa
.un
.sun_path
);
710 r
= bind(s
->stdout_fd
, &sa
.sa
, offsetof(union sockaddr_union
, un
.sun_path
) + strlen(sa
.un
.sun_path
));
712 return log_error_errno(errno
, "bind(%s) failed: %m", sa
.un
.sun_path
);
714 (void) chmod(sa
.un
.sun_path
, 0666);
716 if (listen(s
->stdout_fd
, SOMAXCONN
) < 0)
717 return log_error_errno(errno
, "listen(%s) failed: %m", sa
.un
.sun_path
);
719 fd_nonblock(s
->stdout_fd
, 1);
721 r
= sd_event_add_io(s
->event
, &s
->stdout_event_source
, s
->stdout_fd
, EPOLLIN
, stdout_stream_new
, s
);
723 return log_error_errno(r
, "Failed to add stdout server fd to event source: %m");
725 r
= sd_event_source_set_priority(s
->stdout_event_source
, SD_EVENT_PRIORITY_NORMAL
+10);
727 return log_error_errno(r
, "Failed to adjust priority of stdout server event source: %m");