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>
30 #include "sd-daemon.h"
31 #include "socket-util.h"
32 #include "selinux-util.h"
35 #include "journald-server.h"
36 #include "journald-stream.h"
37 #include "journald-syslog.h"
38 #include "journald-kmsg.h"
39 #include "journald-console.h"
40 #include "journald-wall.h"
42 #define STDOUT_STREAMS_MAX 4096
44 typedef enum StdoutStreamState
{
45 STDOUT_STREAM_IDENTIFIER
,
46 STDOUT_STREAM_UNIT_ID
,
47 STDOUT_STREAM_PRIORITY
,
48 STDOUT_STREAM_LEVEL_PREFIX
,
49 STDOUT_STREAM_FORWARD_TO_SYSLOG
,
50 STDOUT_STREAM_FORWARD_TO_KMSG
,
51 STDOUT_STREAM_FORWARD_TO_CONSOLE
,
57 StdoutStreamState state
;
67 bool forward_to_syslog
:1;
68 bool forward_to_kmsg
:1;
69 bool forward_to_console
:1;
73 char buffer
[LINE_MAX
+1];
76 sd_event_source
*event_source
;
80 LIST_FIELDS(StdoutStream
, stdout_stream
);
83 void stdout_stream_free(StdoutStream
*s
) {
88 assert(s
->server
->n_stdout_streams
> 0);
89 s
->server
->n_stdout_streams
--;
90 LIST_REMOVE(stdout_stream
, s
->server
->stdout_streams
, s
);
93 if (s
->event_source
) {
94 sd_event_source_set_enabled(s
->event_source
, SD_EVENT_OFF
);
95 s
->event_source
= sd_event_source_unref(s
->event_source
);
107 DEFINE_TRIVIAL_CLEANUP_FUNC(StdoutStream
*, stdout_stream_free
);
109 static void stdout_stream_destroy(StdoutStream
*s
) {
114 unlink(s
->state_file
);
116 stdout_stream_free(s
);
119 static int stdout_stream_save(StdoutStream
*s
) {
120 _cleanup_free_
char *temp_path
= NULL
;
121 _cleanup_fclose_
FILE *f
= NULL
;
126 if (s
->state
!= STDOUT_STREAM_RUNNING
)
129 if (!s
->state_file
) {
132 r
= fstat(s
->fd
, &st
);
134 return log_warning_errno(errno
, "Failed to stat connected stream: %m");
136 /* We use device and inode numbers as identifier for the stream */
137 if (asprintf(&s
->state_file
, "/run/systemd/journal/streams/%lu:%lu", (unsigned long) st
.st_dev
, (unsigned long) st
.st_ino
) < 0)
141 mkdir_p("/run/systemd/journal/streams", 0755);
143 r
= fopen_temporary(s
->state_file
, &f
, &temp_path
);
148 "# This is private data. Do not parse\n"
151 "FORWARD_TO_SYSLOG=%i\n"
152 "FORWARD_TO_KMSG=%i\n"
153 "FORWARD_TO_CONSOLE=%i\n",
156 s
->forward_to_syslog
,
158 s
->forward_to_console
);
160 if (!isempty(s
->identifier
)) {
161 _cleanup_free_
char *escaped
;
163 escaped
= cescape(s
->identifier
);
169 fprintf(f
, "IDENTIFIER=%s\n", escaped
);
172 if (!isempty(s
->unit_id
)) {
173 _cleanup_free_
char *escaped
;
175 escaped
= cescape(s
->unit_id
);
181 fprintf(f
, "UNIT=%s\n", escaped
);
184 r
= fflush_and_check(f
);
188 if (rename(temp_path
, s
->state_file
) < 0) {
196 /* Store the connection fd in PID 1, so that we get it passed
197 * in again on next start */
199 sd_pid_notify_with_fds(0, false, "FDSTORE=1", &s
->fd
, 1);
208 log_error_errno(r
, "Failed to save stream data %s: %m", s
->state_file
);
213 static int stdout_stream_log(StdoutStream
*s
, const char *p
) {
214 struct iovec iovec
[N_IOVEC_META_FIELDS
+ 5];
216 char syslog_priority
[] = "PRIORITY=\0";
217 char syslog_facility
[sizeof("SYSLOG_FACILITY=")-1 + DECIMAL_STR_MAX(int) + 1];
218 _cleanup_free_
char *message
= NULL
, *syslog_identifier
= NULL
;
228 priority
= s
->priority
;
231 syslog_parse_priority(&p
, &priority
, false);
233 if (s
->forward_to_syslog
|| s
->server
->forward_to_syslog
)
234 server_forward_syslog(s
->server
, syslog_fixup_facility(priority
), s
->identifier
, p
, &s
->ucred
, NULL
);
236 if (s
->forward_to_kmsg
|| s
->server
->forward_to_kmsg
)
237 server_forward_kmsg(s
->server
, priority
, s
->identifier
, p
, &s
->ucred
);
239 if (s
->forward_to_console
|| s
->server
->forward_to_console
)
240 server_forward_console(s
->server
, priority
, s
->identifier
, p
, &s
->ucred
);
242 if (s
->server
->forward_to_wall
)
243 server_forward_wall(s
->server
, priority
, s
->identifier
, p
, &s
->ucred
);
245 IOVEC_SET_STRING(iovec
[n
++], "_TRANSPORT=stdout");
247 syslog_priority
[strlen("PRIORITY=")] = '0' + LOG_PRI(priority
);
248 IOVEC_SET_STRING(iovec
[n
++], syslog_priority
);
250 if (priority
& LOG_FACMASK
) {
251 xsprintf(syslog_facility
, "SYSLOG_FACILITY=%i", LOG_FAC(priority
));
252 IOVEC_SET_STRING(iovec
[n
++], syslog_facility
);
256 syslog_identifier
= strappend("SYSLOG_IDENTIFIER=", s
->identifier
);
257 if (syslog_identifier
)
258 IOVEC_SET_STRING(iovec
[n
++], syslog_identifier
);
261 message
= strappend("MESSAGE=", p
);
263 IOVEC_SET_STRING(iovec
[n
++], message
);
265 label_len
= s
->label
? strlen(s
->label
) : 0;
266 server_dispatch_message(s
->server
, iovec
, n
, ELEMENTSOF(iovec
), &s
->ucred
, NULL
, s
->label
, label_len
, s
->unit_id
, priority
, 0);
270 static int stdout_stream_line(StdoutStream
*s
, char *p
) {
280 case STDOUT_STREAM_IDENTIFIER
:
282 s
->identifier
= NULL
;
284 s
->identifier
= strdup(p
);
289 s
->state
= STDOUT_STREAM_UNIT_ID
;
292 case STDOUT_STREAM_UNIT_ID
:
293 if (s
->ucred
.uid
== 0) {
297 s
->unit_id
= strdup(p
);
303 s
->state
= STDOUT_STREAM_PRIORITY
;
306 case STDOUT_STREAM_PRIORITY
:
307 r
= safe_atoi(p
, &s
->priority
);
308 if (r
< 0 || s
->priority
< 0 || s
->priority
> 999) {
309 log_warning("Failed to parse log priority line.");
313 s
->state
= STDOUT_STREAM_LEVEL_PREFIX
;
316 case STDOUT_STREAM_LEVEL_PREFIX
:
317 r
= parse_boolean(p
);
319 log_warning("Failed to parse level prefix line.");
323 s
->level_prefix
= !!r
;
324 s
->state
= STDOUT_STREAM_FORWARD_TO_SYSLOG
;
327 case STDOUT_STREAM_FORWARD_TO_SYSLOG
:
328 r
= parse_boolean(p
);
330 log_warning("Failed to parse forward to syslog line.");
334 s
->forward_to_syslog
= !!r
;
335 s
->state
= STDOUT_STREAM_FORWARD_TO_KMSG
;
338 case STDOUT_STREAM_FORWARD_TO_KMSG
:
339 r
= parse_boolean(p
);
341 log_warning("Failed to parse copy to kmsg line.");
345 s
->forward_to_kmsg
= !!r
;
346 s
->state
= STDOUT_STREAM_FORWARD_TO_CONSOLE
;
349 case STDOUT_STREAM_FORWARD_TO_CONSOLE
:
350 r
= parse_boolean(p
);
352 log_warning("Failed to parse copy to console line.");
356 s
->forward_to_console
= !!r
;
357 s
->state
= STDOUT_STREAM_RUNNING
;
359 /* Try to save the stream, so that journald can be restarted and we can recover */
360 (void) stdout_stream_save(s
);
363 case STDOUT_STREAM_RUNNING
:
364 return stdout_stream_log(s
, p
);
367 assert_not_reached("Unknown stream state");
370 static int stdout_stream_scan(StdoutStream
*s
, bool force_flush
) {
378 remaining
= s
->length
;
383 end
= memchr(p
, '\n', remaining
);
386 else if (remaining
>= sizeof(s
->buffer
) - 1) {
387 end
= p
+ sizeof(s
->buffer
) - 1;
394 r
= stdout_stream_line(s
, p
);
402 if (force_flush
&& remaining
> 0) {
404 r
= stdout_stream_line(s
, p
);
413 memmove(s
->buffer
, p
, remaining
);
414 s
->length
= remaining
;
420 static int stdout_stream_process(sd_event_source
*es
, int fd
, uint32_t revents
, void *userdata
) {
421 StdoutStream
*s
= userdata
;
427 if ((revents
|EPOLLIN
|EPOLLHUP
) != (EPOLLIN
|EPOLLHUP
)) {
428 log_error("Got invalid event from epoll for stdout stream: %"PRIx32
, revents
);
432 l
= read(s
->fd
, s
->buffer
+s
->length
, sizeof(s
->buffer
)-1-s
->length
);
438 log_warning_errno(errno
, "Failed to read from stream: %m");
443 stdout_stream_scan(s
, true);
448 r
= stdout_stream_scan(s
, false);
455 stdout_stream_destroy(s
);
459 static int stdout_stream_install(Server
*s
, int fd
, StdoutStream
**ret
) {
460 _cleanup_(stdout_stream_freep
) StdoutStream
*stream
= NULL
;
466 stream
= new0(StdoutStream
, 1);
471 stream
->priority
= LOG_INFO
;
473 r
= getpeercred(fd
, &stream
->ucred
);
475 return log_error_errno(r
, "Failed to determine peer credentials: %m");
477 if (mac_selinux_use()) {
478 r
= getpeersec(fd
, &stream
->label
);
479 if (r
< 0 && r
!= -EOPNOTSUPP
)
480 (void) log_warning_errno(r
, "Failed to determine peer security context: %m");
483 (void) shutdown(fd
, SHUT_WR
);
485 r
= sd_event_add_io(s
->event
, &stream
->event_source
, fd
, EPOLLIN
, stdout_stream_process
, stream
);
487 return log_error_errno(r
, "Failed to add stream to event loop: %m");
489 r
= sd_event_source_set_priority(stream
->event_source
, SD_EVENT_PRIORITY_NORMAL
+5);
491 return log_error_errno(r
, "Failed to adjust stdout event source priority: %m");
496 LIST_PREPEND(stdout_stream
, s
->stdout_streams
, stream
);
497 s
->n_stdout_streams
++;
507 static int stdout_stream_new(sd_event_source
*es
, int listen_fd
, uint32_t revents
, void *userdata
) {
508 _cleanup_close_
int fd
= -1;
509 Server
*s
= userdata
;
514 if (revents
!= EPOLLIN
) {
515 log_error("Got invalid event from epoll for stdout server fd: %"PRIx32
, revents
);
519 fd
= accept4(s
->stdout_fd
, NULL
, NULL
, SOCK_NONBLOCK
|SOCK_CLOEXEC
);
524 log_error_errno(errno
, "Failed to accept stdout connection: %m");
528 if (s
->n_stdout_streams
>= STDOUT_STREAMS_MAX
) {
529 log_warning("Too many stdout streams, refusing connection.");
533 r
= stdout_stream_install(s
, fd
, NULL
);
541 static int stdout_stream_load(StdoutStream
*stream
, const char *fname
) {
544 *level_prefix
= NULL
,
545 *forward_to_syslog
= NULL
,
546 *forward_to_kmsg
= NULL
,
547 *forward_to_console
= NULL
;
553 if (!stream
->state_file
) {
554 stream
->state_file
= strappend("/run/systemd/journal/streams/", fname
);
555 if (!stream
->state_file
)
559 r
= parse_env_file(stream
->state_file
, NEWLINE
,
560 "PRIORITY", &priority
,
561 "LEVEL_PREFIX", &level_prefix
,
562 "FORWARD_TO_SYSLOG", &forward_to_syslog
,
563 "FORWARD_TO_KMSG", &forward_to_kmsg
,
564 "FORWARD_TO_CONSOLE", &forward_to_console
,
565 "IDENTIFIER", &stream
->identifier
,
566 "UNIT", &stream
->unit_id
,
569 return log_error_errno(r
, "Failed to read: %s", stream
->state_file
);
574 p
= log_level_from_string(priority
);
576 stream
->priority
= p
;
580 r
= parse_boolean(level_prefix
);
582 stream
->level_prefix
= r
;
585 if (forward_to_syslog
) {
586 r
= parse_boolean(forward_to_syslog
);
588 stream
->forward_to_syslog
= r
;
591 if (forward_to_kmsg
) {
592 r
= parse_boolean(forward_to_kmsg
);
594 stream
->forward_to_kmsg
= r
;
597 if (forward_to_console
) {
598 r
= parse_boolean(forward_to_console
);
600 stream
->forward_to_console
= r
;
606 static int stdout_stream_restore(Server
*s
, const char *fname
, int fd
) {
607 StdoutStream
*stream
;
614 if (s
->n_stdout_streams
>= STDOUT_STREAMS_MAX
) {
615 log_warning("Too many stdout streams, refusing restoring of stream.");
619 r
= stdout_stream_install(s
, fd
, &stream
);
623 stream
->state
= STDOUT_STREAM_RUNNING
;
624 stream
->fdstore
= true;
626 /* Ignore all parsing errors */
627 (void) stdout_stream_load(stream
, fname
);
632 static int server_restore_streams(Server
*s
, FDSet
*fds
) {
633 _cleanup_closedir_
DIR *d
= NULL
;
637 d
= opendir("/run/systemd/journal/streams");
642 return log_warning_errno(errno
, "Failed to enumerate /run/systemd/journal/streams: %m");
645 FOREACH_DIRENT(de
, d
, goto fail
) {
646 unsigned long st_dev
, st_ino
;
651 if (sscanf(de
->d_name
, "%lu:%lu", &st_dev
, &st_ino
) != 2)
654 FDSET_FOREACH(fd
, fds
, i
) {
657 if (fstat(fd
, &st
) < 0)
658 return log_error_errno(errno
, "Failed to stat %s: %m", de
->d_name
);
660 if (S_ISSOCK(st
.st_mode
) && st
.st_dev
== st_dev
&& st
.st_ino
== st_ino
) {
667 /* No file descriptor? Then let's delete the state file */
668 log_debug("Cannot restore stream file %s", de
->d_name
);
669 unlinkat(dirfd(d
), de
->d_name
, 0);
673 fdset_remove(fds
, fd
);
675 r
= stdout_stream_restore(s
, de
->d_name
, fd
);
683 return log_error_errno(errno
, "Failed to read streams directory: %m");
686 int server_open_stdout_socket(Server
*s
, FDSet
*fds
) {
691 if (s
->stdout_fd
< 0) {
692 union sockaddr_union sa
= {
693 .un
.sun_family
= AF_UNIX
,
694 .un
.sun_path
= "/run/systemd/journal/stdout",
697 s
->stdout_fd
= socket(AF_UNIX
, SOCK_STREAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
698 if (s
->stdout_fd
< 0)
699 return log_error_errno(errno
, "socket() failed: %m");
701 unlink(sa
.un
.sun_path
);
703 r
= bind(s
->stdout_fd
, &sa
.sa
, offsetof(union sockaddr_union
, un
.sun_path
) + strlen(sa
.un
.sun_path
));
705 return log_error_errno(errno
, "bind(%s) failed: %m", sa
.un
.sun_path
);
707 (void) chmod(sa
.un
.sun_path
, 0666);
709 if (listen(s
->stdout_fd
, SOMAXCONN
) < 0)
710 return log_error_errno(errno
, "listen(%s) failed: %m", sa
.un
.sun_path
);
712 fd_nonblock(s
->stdout_fd
, 1);
714 r
= sd_event_add_io(s
->event
, &s
->stdout_event_source
, s
->stdout_fd
, EPOLLIN
, stdout_stream_new
, s
);
716 return log_error_errno(r
, "Failed to add stdout server fd to event source: %m");
718 r
= sd_event_source_set_priority(s
->stdout_event_source
, SD_EVENT_PRIORITY_NORMAL
+10);
720 return log_error_errno(r
, "Failed to adjust priority of stdout server event source: %m");
722 /* Try to restore streams, but don't bother if this fails */
723 (void) server_restore_streams(s
, fds
);