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"
35 #include "journald-console.h"
36 #include "journald-kmsg.h"
37 #include "journald-server.h"
38 #include "journald-stream.h"
39 #include "journald-syslog.h"
40 #include "journald-wall.h"
42 #include "selinux-util.h"
43 #include "socket-util.h"
44 #include "string-util.h"
46 #define STDOUT_STREAMS_MAX 4096
48 typedef enum StdoutStreamState
{
49 STDOUT_STREAM_IDENTIFIER
,
50 STDOUT_STREAM_UNIT_ID
,
51 STDOUT_STREAM_PRIORITY
,
52 STDOUT_STREAM_LEVEL_PREFIX
,
53 STDOUT_STREAM_FORWARD_TO_SYSLOG
,
54 STDOUT_STREAM_FORWARD_TO_KMSG
,
55 STDOUT_STREAM_FORWARD_TO_CONSOLE
,
61 StdoutStreamState state
;
71 bool forward_to_syslog
:1;
72 bool forward_to_kmsg
:1;
73 bool forward_to_console
:1;
77 char buffer
[LINE_MAX
+1];
80 sd_event_source
*event_source
;
84 LIST_FIELDS(StdoutStream
, stdout_stream
);
87 void stdout_stream_free(StdoutStream
*s
) {
92 assert(s
->server
->n_stdout_streams
> 0);
93 s
->server
->n_stdout_streams
--;
94 LIST_REMOVE(stdout_stream
, s
->server
->stdout_streams
, s
);
97 if (s
->event_source
) {
98 sd_event_source_set_enabled(s
->event_source
, SD_EVENT_OFF
);
99 s
->event_source
= sd_event_source_unref(s
->event_source
);
111 DEFINE_TRIVIAL_CLEANUP_FUNC(StdoutStream
*, stdout_stream_free
);
113 static void stdout_stream_destroy(StdoutStream
*s
) {
118 unlink(s
->state_file
);
120 stdout_stream_free(s
);
123 static int stdout_stream_save(StdoutStream
*s
) {
124 _cleanup_free_
char *temp_path
= NULL
;
125 _cleanup_fclose_
FILE *f
= NULL
;
130 if (s
->state
!= STDOUT_STREAM_RUNNING
)
133 if (!s
->state_file
) {
136 r
= fstat(s
->fd
, &st
);
138 return log_warning_errno(errno
, "Failed to stat connected stream: %m");
140 /* We use device and inode numbers as identifier for the stream */
141 if (asprintf(&s
->state_file
, "/run/systemd/journal/streams/%lu:%lu", (unsigned long) st
.st_dev
, (unsigned long) st
.st_ino
) < 0)
145 mkdir_p("/run/systemd/journal/streams", 0755);
147 r
= fopen_temporary(s
->state_file
, &f
, &temp_path
);
152 "# This is private data. Do not parse\n"
155 "FORWARD_TO_SYSLOG=%i\n"
156 "FORWARD_TO_KMSG=%i\n"
157 "FORWARD_TO_CONSOLE=%i\n",
160 s
->forward_to_syslog
,
162 s
->forward_to_console
);
164 if (!isempty(s
->identifier
)) {
165 _cleanup_free_
char *escaped
;
167 escaped
= cescape(s
->identifier
);
173 fprintf(f
, "IDENTIFIER=%s\n", escaped
);
176 if (!isempty(s
->unit_id
)) {
177 _cleanup_free_
char *escaped
;
179 escaped
= cescape(s
->unit_id
);
185 fprintf(f
, "UNIT=%s\n", escaped
);
188 r
= fflush_and_check(f
);
192 if (rename(temp_path
, s
->state_file
) < 0) {
197 /* Store the connection fd in PID 1, so that we get it passed
198 * in again on next start */
200 sd_pid_notify_with_fds(0, false, "FDSTORE=1", &s
->fd
, 1);
207 (void) unlink(s
->state_file
);
210 (void) unlink(temp_path
);
212 return log_error_errno(r
, "Failed to save stream data %s: %m", s
->state_file
);
215 static int stdout_stream_log(StdoutStream
*s
, const char *p
) {
216 struct iovec iovec
[N_IOVEC_META_FIELDS
+ 5];
218 char syslog_priority
[] = "PRIORITY=\0";
219 char syslog_facility
[sizeof("SYSLOG_FACILITY=")-1 + DECIMAL_STR_MAX(int) + 1];
220 _cleanup_free_
char *message
= NULL
, *syslog_identifier
= NULL
;
230 priority
= s
->priority
;
233 syslog_parse_priority(&p
, &priority
, false);
235 if (s
->forward_to_syslog
|| s
->server
->forward_to_syslog
)
236 server_forward_syslog(s
->server
, syslog_fixup_facility(priority
), s
->identifier
, p
, &s
->ucred
, NULL
);
238 if (s
->forward_to_kmsg
|| s
->server
->forward_to_kmsg
)
239 server_forward_kmsg(s
->server
, priority
, s
->identifier
, p
, &s
->ucred
);
241 if (s
->forward_to_console
|| s
->server
->forward_to_console
)
242 server_forward_console(s
->server
, priority
, s
->identifier
, p
, &s
->ucred
);
244 if (s
->server
->forward_to_wall
)
245 server_forward_wall(s
->server
, priority
, s
->identifier
, p
, &s
->ucred
);
247 IOVEC_SET_STRING(iovec
[n
++], "_TRANSPORT=stdout");
249 syslog_priority
[strlen("PRIORITY=")] = '0' + LOG_PRI(priority
);
250 IOVEC_SET_STRING(iovec
[n
++], syslog_priority
);
252 if (priority
& LOG_FACMASK
) {
253 xsprintf(syslog_facility
, "SYSLOG_FACILITY=%i", LOG_FAC(priority
));
254 IOVEC_SET_STRING(iovec
[n
++], syslog_facility
);
258 syslog_identifier
= strappend("SYSLOG_IDENTIFIER=", s
->identifier
);
259 if (syslog_identifier
)
260 IOVEC_SET_STRING(iovec
[n
++], syslog_identifier
);
263 message
= strappend("MESSAGE=", p
);
265 IOVEC_SET_STRING(iovec
[n
++], message
);
267 label_len
= s
->label
? strlen(s
->label
) : 0;
268 server_dispatch_message(s
->server
, iovec
, n
, ELEMENTSOF(iovec
), &s
->ucred
, NULL
, s
->label
, label_len
, s
->unit_id
, priority
, 0);
272 static int stdout_stream_line(StdoutStream
*s
, char *p
) {
282 case STDOUT_STREAM_IDENTIFIER
:
284 s
->identifier
= NULL
;
286 s
->identifier
= strdup(p
);
291 s
->state
= STDOUT_STREAM_UNIT_ID
;
294 case STDOUT_STREAM_UNIT_ID
:
295 if (s
->ucred
.uid
== 0) {
299 s
->unit_id
= strdup(p
);
305 s
->state
= STDOUT_STREAM_PRIORITY
;
308 case STDOUT_STREAM_PRIORITY
:
309 r
= safe_atoi(p
, &s
->priority
);
310 if (r
< 0 || s
->priority
< 0 || s
->priority
> 999) {
311 log_warning("Failed to parse log priority line.");
315 s
->state
= STDOUT_STREAM_LEVEL_PREFIX
;
318 case STDOUT_STREAM_LEVEL_PREFIX
:
319 r
= parse_boolean(p
);
321 log_warning("Failed to parse level prefix line.");
325 s
->level_prefix
= !!r
;
326 s
->state
= STDOUT_STREAM_FORWARD_TO_SYSLOG
;
329 case STDOUT_STREAM_FORWARD_TO_SYSLOG
:
330 r
= parse_boolean(p
);
332 log_warning("Failed to parse forward to syslog line.");
336 s
->forward_to_syslog
= !!r
;
337 s
->state
= STDOUT_STREAM_FORWARD_TO_KMSG
;
340 case STDOUT_STREAM_FORWARD_TO_KMSG
:
341 r
= parse_boolean(p
);
343 log_warning("Failed to parse copy to kmsg line.");
347 s
->forward_to_kmsg
= !!r
;
348 s
->state
= STDOUT_STREAM_FORWARD_TO_CONSOLE
;
351 case STDOUT_STREAM_FORWARD_TO_CONSOLE
:
352 r
= parse_boolean(p
);
354 log_warning("Failed to parse copy to console line.");
358 s
->forward_to_console
= !!r
;
359 s
->state
= STDOUT_STREAM_RUNNING
;
361 /* Try to save the stream, so that journald can be restarted and we can recover */
362 (void) stdout_stream_save(s
);
365 case STDOUT_STREAM_RUNNING
:
366 return stdout_stream_log(s
, p
);
369 assert_not_reached("Unknown stream state");
372 static int stdout_stream_scan(StdoutStream
*s
, bool force_flush
) {
380 remaining
= s
->length
;
385 end
= memchr(p
, '\n', remaining
);
388 else if (remaining
>= sizeof(s
->buffer
) - 1) {
389 end
= p
+ sizeof(s
->buffer
) - 1;
396 r
= stdout_stream_line(s
, p
);
404 if (force_flush
&& remaining
> 0) {
406 r
= stdout_stream_line(s
, p
);
415 memmove(s
->buffer
, p
, remaining
);
416 s
->length
= remaining
;
422 static int stdout_stream_process(sd_event_source
*es
, int fd
, uint32_t revents
, void *userdata
) {
423 StdoutStream
*s
= userdata
;
429 if ((revents
|EPOLLIN
|EPOLLHUP
) != (EPOLLIN
|EPOLLHUP
)) {
430 log_error("Got invalid event from epoll for stdout stream: %"PRIx32
, revents
);
434 l
= read(s
->fd
, s
->buffer
+s
->length
, sizeof(s
->buffer
)-1-s
->length
);
440 log_warning_errno(errno
, "Failed to read from stream: %m");
445 stdout_stream_scan(s
, true);
450 r
= stdout_stream_scan(s
, false);
457 stdout_stream_destroy(s
);
461 static int stdout_stream_install(Server
*s
, int fd
, StdoutStream
**ret
) {
462 _cleanup_(stdout_stream_freep
) StdoutStream
*stream
= NULL
;
468 stream
= new0(StdoutStream
, 1);
473 stream
->priority
= LOG_INFO
;
475 r
= getpeercred(fd
, &stream
->ucred
);
477 return log_error_errno(r
, "Failed to determine peer credentials: %m");
479 if (mac_selinux_use()) {
480 r
= getpeersec(fd
, &stream
->label
);
481 if (r
< 0 && r
!= -EOPNOTSUPP
)
482 (void) log_warning_errno(r
, "Failed to determine peer security context: %m");
485 (void) shutdown(fd
, SHUT_WR
);
487 r
= sd_event_add_io(s
->event
, &stream
->event_source
, fd
, EPOLLIN
, stdout_stream_process
, stream
);
489 return log_error_errno(r
, "Failed to add stream to event loop: %m");
491 r
= sd_event_source_set_priority(stream
->event_source
, SD_EVENT_PRIORITY_NORMAL
+5);
493 return log_error_errno(r
, "Failed to adjust stdout event source priority: %m");
498 LIST_PREPEND(stdout_stream
, s
->stdout_streams
, stream
);
499 s
->n_stdout_streams
++;
509 static int stdout_stream_new(sd_event_source
*es
, int listen_fd
, uint32_t revents
, void *userdata
) {
510 _cleanup_close_
int fd
= -1;
511 Server
*s
= userdata
;
516 if (revents
!= EPOLLIN
) {
517 log_error("Got invalid event from epoll for stdout server fd: %"PRIx32
, revents
);
521 fd
= accept4(s
->stdout_fd
, NULL
, NULL
, SOCK_NONBLOCK
|SOCK_CLOEXEC
);
526 log_error_errno(errno
, "Failed to accept stdout connection: %m");
530 if (s
->n_stdout_streams
>= STDOUT_STREAMS_MAX
) {
531 log_warning("Too many stdout streams, refusing connection.");
535 r
= stdout_stream_install(s
, fd
, NULL
);
543 static int stdout_stream_load(StdoutStream
*stream
, const char *fname
) {
546 *level_prefix
= NULL
,
547 *forward_to_syslog
= NULL
,
548 *forward_to_kmsg
= NULL
,
549 *forward_to_console
= NULL
;
555 if (!stream
->state_file
) {
556 stream
->state_file
= strappend("/run/systemd/journal/streams/", fname
);
557 if (!stream
->state_file
)
561 r
= parse_env_file(stream
->state_file
, NEWLINE
,
562 "PRIORITY", &priority
,
563 "LEVEL_PREFIX", &level_prefix
,
564 "FORWARD_TO_SYSLOG", &forward_to_syslog
,
565 "FORWARD_TO_KMSG", &forward_to_kmsg
,
566 "FORWARD_TO_CONSOLE", &forward_to_console
,
567 "IDENTIFIER", &stream
->identifier
,
568 "UNIT", &stream
->unit_id
,
571 return log_error_errno(r
, "Failed to read: %s", stream
->state_file
);
576 p
= log_level_from_string(priority
);
578 stream
->priority
= p
;
582 r
= parse_boolean(level_prefix
);
584 stream
->level_prefix
= r
;
587 if (forward_to_syslog
) {
588 r
= parse_boolean(forward_to_syslog
);
590 stream
->forward_to_syslog
= r
;
593 if (forward_to_kmsg
) {
594 r
= parse_boolean(forward_to_kmsg
);
596 stream
->forward_to_kmsg
= r
;
599 if (forward_to_console
) {
600 r
= parse_boolean(forward_to_console
);
602 stream
->forward_to_console
= r
;
608 static int stdout_stream_restore(Server
*s
, const char *fname
, int fd
) {
609 StdoutStream
*stream
;
616 if (s
->n_stdout_streams
>= STDOUT_STREAMS_MAX
) {
617 log_warning("Too many stdout streams, refusing restoring of stream.");
621 r
= stdout_stream_install(s
, fd
, &stream
);
625 stream
->state
= STDOUT_STREAM_RUNNING
;
626 stream
->fdstore
= true;
628 /* Ignore all parsing errors */
629 (void) stdout_stream_load(stream
, fname
);
634 int server_restore_streams(Server
*s
, FDSet
*fds
) {
635 _cleanup_closedir_
DIR *d
= NULL
;
639 d
= opendir("/run/systemd/journal/streams");
644 return log_warning_errno(errno
, "Failed to enumerate /run/systemd/journal/streams: %m");
647 FOREACH_DIRENT(de
, d
, goto fail
) {
648 unsigned long st_dev
, st_ino
;
653 if (sscanf(de
->d_name
, "%lu:%lu", &st_dev
, &st_ino
) != 2)
656 FDSET_FOREACH(fd
, fds
, i
) {
659 if (fstat(fd
, &st
) < 0)
660 return log_error_errno(errno
, "Failed to stat %s: %m", de
->d_name
);
662 if (S_ISSOCK(st
.st_mode
) && st
.st_dev
== st_dev
&& st
.st_ino
== st_ino
) {
669 /* No file descriptor? Then let's delete the state file */
670 log_debug("Cannot restore stream file %s", de
->d_name
);
671 unlinkat(dirfd(d
), de
->d_name
, 0);
675 fdset_remove(fds
, fd
);
677 r
= stdout_stream_restore(s
, de
->d_name
, fd
);
685 return log_error_errno(errno
, "Failed to read streams directory: %m");
688 int server_open_stdout_socket(Server
*s
) {
693 if (s
->stdout_fd
< 0) {
694 union sockaddr_union sa
= {
695 .un
.sun_family
= AF_UNIX
,
696 .un
.sun_path
= "/run/systemd/journal/stdout",
699 s
->stdout_fd
= socket(AF_UNIX
, SOCK_STREAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
700 if (s
->stdout_fd
< 0)
701 return log_error_errno(errno
, "socket() failed: %m");
703 unlink(sa
.un
.sun_path
);
705 r
= bind(s
->stdout_fd
, &sa
.sa
, offsetof(union sockaddr_union
, un
.sun_path
) + strlen(sa
.un
.sun_path
));
707 return log_error_errno(errno
, "bind(%s) failed: %m", sa
.un
.sun_path
);
709 (void) chmod(sa
.un
.sun_path
, 0666);
711 if (listen(s
->stdout_fd
, SOMAXCONN
) < 0)
712 return log_error_errno(errno
, "listen(%s) failed: %m", sa
.un
.sun_path
);
714 fd_nonblock(s
->stdout_fd
, 1);
716 r
= sd_event_add_io(s
->event
, &s
->stdout_event_source
, s
->stdout_fd
, EPOLLIN
, stdout_stream_new
, s
);
718 return log_error_errno(r
, "Failed to add stdout server fd to event source: %m");
720 r
= sd_event_source_set_priority(s
->stdout_event_source
, SD_EVENT_PRIORITY_NORMAL
+10);
722 return log_error_errno(r
, "Failed to adjust priority of stdout server event source: %m");