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) {
193 /* Store the connection fd in PID 1, so that we get it passed
194 * in again on next start */
196 sd_pid_notify_with_fds(0, false, "FDSTORE=1", &s
->fd
, 1);
203 (void) unlink(s
->state_file
);
206 (void) unlink(temp_path
);
208 return log_error_errno(r
, "Failed to save stream data %s: %m", s
->state_file
);
211 static int stdout_stream_log(StdoutStream
*s
, const char *p
) {
212 struct iovec iovec
[N_IOVEC_META_FIELDS
+ 5];
214 char syslog_priority
[] = "PRIORITY=\0";
215 char syslog_facility
[sizeof("SYSLOG_FACILITY=")-1 + DECIMAL_STR_MAX(int) + 1];
216 _cleanup_free_
char *message
= NULL
, *syslog_identifier
= NULL
;
226 priority
= s
->priority
;
229 syslog_parse_priority(&p
, &priority
, false);
231 if (s
->forward_to_syslog
|| s
->server
->forward_to_syslog
)
232 server_forward_syslog(s
->server
, syslog_fixup_facility(priority
), s
->identifier
, p
, &s
->ucred
, NULL
);
234 if (s
->forward_to_kmsg
|| s
->server
->forward_to_kmsg
)
235 server_forward_kmsg(s
->server
, priority
, s
->identifier
, p
, &s
->ucred
);
237 if (s
->forward_to_console
|| s
->server
->forward_to_console
)
238 server_forward_console(s
->server
, priority
, s
->identifier
, p
, &s
->ucred
);
240 if (s
->server
->forward_to_wall
)
241 server_forward_wall(s
->server
, priority
, s
->identifier
, p
, &s
->ucred
);
243 IOVEC_SET_STRING(iovec
[n
++], "_TRANSPORT=stdout");
245 syslog_priority
[strlen("PRIORITY=")] = '0' + LOG_PRI(priority
);
246 IOVEC_SET_STRING(iovec
[n
++], syslog_priority
);
248 if (priority
& LOG_FACMASK
) {
249 xsprintf(syslog_facility
, "SYSLOG_FACILITY=%i", LOG_FAC(priority
));
250 IOVEC_SET_STRING(iovec
[n
++], syslog_facility
);
254 syslog_identifier
= strappend("SYSLOG_IDENTIFIER=", s
->identifier
);
255 if (syslog_identifier
)
256 IOVEC_SET_STRING(iovec
[n
++], syslog_identifier
);
259 message
= strappend("MESSAGE=", p
);
261 IOVEC_SET_STRING(iovec
[n
++], message
);
263 label_len
= s
->label
? strlen(s
->label
) : 0;
264 server_dispatch_message(s
->server
, iovec
, n
, ELEMENTSOF(iovec
), &s
->ucred
, NULL
, s
->label
, label_len
, s
->unit_id
, priority
, 0);
268 static int stdout_stream_line(StdoutStream
*s
, char *p
) {
278 case STDOUT_STREAM_IDENTIFIER
:
280 s
->identifier
= NULL
;
282 s
->identifier
= strdup(p
);
287 s
->state
= STDOUT_STREAM_UNIT_ID
;
290 case STDOUT_STREAM_UNIT_ID
:
291 if (s
->ucred
.uid
== 0) {
295 s
->unit_id
= strdup(p
);
301 s
->state
= STDOUT_STREAM_PRIORITY
;
304 case STDOUT_STREAM_PRIORITY
:
305 r
= safe_atoi(p
, &s
->priority
);
306 if (r
< 0 || s
->priority
< 0 || s
->priority
> 999) {
307 log_warning("Failed to parse log priority line.");
311 s
->state
= STDOUT_STREAM_LEVEL_PREFIX
;
314 case STDOUT_STREAM_LEVEL_PREFIX
:
315 r
= parse_boolean(p
);
317 log_warning("Failed to parse level prefix line.");
321 s
->level_prefix
= !!r
;
322 s
->state
= STDOUT_STREAM_FORWARD_TO_SYSLOG
;
325 case STDOUT_STREAM_FORWARD_TO_SYSLOG
:
326 r
= parse_boolean(p
);
328 log_warning("Failed to parse forward to syslog line.");
332 s
->forward_to_syslog
= !!r
;
333 s
->state
= STDOUT_STREAM_FORWARD_TO_KMSG
;
336 case STDOUT_STREAM_FORWARD_TO_KMSG
:
337 r
= parse_boolean(p
);
339 log_warning("Failed to parse copy to kmsg line.");
343 s
->forward_to_kmsg
= !!r
;
344 s
->state
= STDOUT_STREAM_FORWARD_TO_CONSOLE
;
347 case STDOUT_STREAM_FORWARD_TO_CONSOLE
:
348 r
= parse_boolean(p
);
350 log_warning("Failed to parse copy to console line.");
354 s
->forward_to_console
= !!r
;
355 s
->state
= STDOUT_STREAM_RUNNING
;
357 /* Try to save the stream, so that journald can be restarted and we can recover */
358 (void) stdout_stream_save(s
);
361 case STDOUT_STREAM_RUNNING
:
362 return stdout_stream_log(s
, p
);
365 assert_not_reached("Unknown stream state");
368 static int stdout_stream_scan(StdoutStream
*s
, bool force_flush
) {
376 remaining
= s
->length
;
381 end
= memchr(p
, '\n', remaining
);
384 else if (remaining
>= sizeof(s
->buffer
) - 1) {
385 end
= p
+ sizeof(s
->buffer
) - 1;
392 r
= stdout_stream_line(s
, p
);
400 if (force_flush
&& remaining
> 0) {
402 r
= stdout_stream_line(s
, p
);
411 memmove(s
->buffer
, p
, remaining
);
412 s
->length
= remaining
;
418 static int stdout_stream_process(sd_event_source
*es
, int fd
, uint32_t revents
, void *userdata
) {
419 StdoutStream
*s
= userdata
;
425 if ((revents
|EPOLLIN
|EPOLLHUP
) != (EPOLLIN
|EPOLLHUP
)) {
426 log_error("Got invalid event from epoll for stdout stream: %"PRIx32
, revents
);
430 l
= read(s
->fd
, s
->buffer
+s
->length
, sizeof(s
->buffer
)-1-s
->length
);
436 log_warning_errno(errno
, "Failed to read from stream: %m");
441 stdout_stream_scan(s
, true);
446 r
= stdout_stream_scan(s
, false);
453 stdout_stream_destroy(s
);
457 static int stdout_stream_install(Server
*s
, int fd
, StdoutStream
**ret
) {
458 _cleanup_(stdout_stream_freep
) StdoutStream
*stream
= NULL
;
464 stream
= new0(StdoutStream
, 1);
469 stream
->priority
= LOG_INFO
;
471 r
= getpeercred(fd
, &stream
->ucred
);
473 return log_error_errno(r
, "Failed to determine peer credentials: %m");
475 if (mac_selinux_use()) {
476 r
= getpeersec(fd
, &stream
->label
);
477 if (r
< 0 && r
!= -EOPNOTSUPP
)
478 (void) log_warning_errno(r
, "Failed to determine peer security context: %m");
481 (void) shutdown(fd
, SHUT_WR
);
483 r
= sd_event_add_io(s
->event
, &stream
->event_source
, fd
, EPOLLIN
, stdout_stream_process
, stream
);
485 return log_error_errno(r
, "Failed to add stream to event loop: %m");
487 r
= sd_event_source_set_priority(stream
->event_source
, SD_EVENT_PRIORITY_NORMAL
+5);
489 return log_error_errno(r
, "Failed to adjust stdout event source priority: %m");
494 LIST_PREPEND(stdout_stream
, s
->stdout_streams
, stream
);
495 s
->n_stdout_streams
++;
505 static int stdout_stream_new(sd_event_source
*es
, int listen_fd
, uint32_t revents
, void *userdata
) {
506 _cleanup_close_
int fd
= -1;
507 Server
*s
= userdata
;
512 if (revents
!= EPOLLIN
) {
513 log_error("Got invalid event from epoll for stdout server fd: %"PRIx32
, revents
);
517 fd
= accept4(s
->stdout_fd
, NULL
, NULL
, SOCK_NONBLOCK
|SOCK_CLOEXEC
);
522 log_error_errno(errno
, "Failed to accept stdout connection: %m");
526 if (s
->n_stdout_streams
>= STDOUT_STREAMS_MAX
) {
527 log_warning("Too many stdout streams, refusing connection.");
531 r
= stdout_stream_install(s
, fd
, NULL
);
539 static int stdout_stream_load(StdoutStream
*stream
, const char *fname
) {
542 *level_prefix
= NULL
,
543 *forward_to_syslog
= NULL
,
544 *forward_to_kmsg
= NULL
,
545 *forward_to_console
= NULL
;
551 if (!stream
->state_file
) {
552 stream
->state_file
= strappend("/run/systemd/journal/streams/", fname
);
553 if (!stream
->state_file
)
557 r
= parse_env_file(stream
->state_file
, NEWLINE
,
558 "PRIORITY", &priority
,
559 "LEVEL_PREFIX", &level_prefix
,
560 "FORWARD_TO_SYSLOG", &forward_to_syslog
,
561 "FORWARD_TO_KMSG", &forward_to_kmsg
,
562 "FORWARD_TO_CONSOLE", &forward_to_console
,
563 "IDENTIFIER", &stream
->identifier
,
564 "UNIT", &stream
->unit_id
,
567 return log_error_errno(r
, "Failed to read: %s", stream
->state_file
);
572 p
= log_level_from_string(priority
);
574 stream
->priority
= p
;
578 r
= parse_boolean(level_prefix
);
580 stream
->level_prefix
= r
;
583 if (forward_to_syslog
) {
584 r
= parse_boolean(forward_to_syslog
);
586 stream
->forward_to_syslog
= r
;
589 if (forward_to_kmsg
) {
590 r
= parse_boolean(forward_to_kmsg
);
592 stream
->forward_to_kmsg
= r
;
595 if (forward_to_console
) {
596 r
= parse_boolean(forward_to_console
);
598 stream
->forward_to_console
= r
;
604 static int stdout_stream_restore(Server
*s
, const char *fname
, int fd
) {
605 StdoutStream
*stream
;
612 if (s
->n_stdout_streams
>= STDOUT_STREAMS_MAX
) {
613 log_warning("Too many stdout streams, refusing restoring of stream.");
617 r
= stdout_stream_install(s
, fd
, &stream
);
621 stream
->state
= STDOUT_STREAM_RUNNING
;
622 stream
->fdstore
= true;
624 /* Ignore all parsing errors */
625 (void) stdout_stream_load(stream
, fname
);
630 int server_restore_streams(Server
*s
, FDSet
*fds
) {
631 _cleanup_closedir_
DIR *d
= NULL
;
635 d
= opendir("/run/systemd/journal/streams");
640 return log_warning_errno(errno
, "Failed to enumerate /run/systemd/journal/streams: %m");
643 FOREACH_DIRENT(de
, d
, goto fail
) {
644 unsigned long st_dev
, st_ino
;
649 if (sscanf(de
->d_name
, "%lu:%lu", &st_dev
, &st_ino
) != 2)
652 FDSET_FOREACH(fd
, fds
, i
) {
655 if (fstat(fd
, &st
) < 0)
656 return log_error_errno(errno
, "Failed to stat %s: %m", de
->d_name
);
658 if (S_ISSOCK(st
.st_mode
) && st
.st_dev
== st_dev
&& st
.st_ino
== st_ino
) {
665 /* No file descriptor? Then let's delete the state file */
666 log_debug("Cannot restore stream file %s", de
->d_name
);
667 unlinkat(dirfd(d
), de
->d_name
, 0);
671 fdset_remove(fds
, fd
);
673 r
= stdout_stream_restore(s
, de
->d_name
, fd
);
681 return log_error_errno(errno
, "Failed to read streams directory: %m");
684 int server_open_stdout_socket(Server
*s
) {
689 if (s
->stdout_fd
< 0) {
690 union sockaddr_union sa
= {
691 .un
.sun_family
= AF_UNIX
,
692 .un
.sun_path
= "/run/systemd/journal/stdout",
695 s
->stdout_fd
= socket(AF_UNIX
, SOCK_STREAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
696 if (s
->stdout_fd
< 0)
697 return log_error_errno(errno
, "socket() failed: %m");
699 unlink(sa
.un
.sun_path
);
701 r
= bind(s
->stdout_fd
, &sa
.sa
, offsetof(union sockaddr_union
, un
.sun_path
) + strlen(sa
.un
.sun_path
));
703 return log_error_errno(errno
, "bind(%s) failed: %m", sa
.un
.sun_path
);
705 (void) chmod(sa
.un
.sun_path
, 0666);
707 if (listen(s
->stdout_fd
, SOMAXCONN
) < 0)
708 return log_error_errno(errno
, "listen(%s) failed: %m", sa
.un
.sun_path
);
710 fd_nonblock(s
->stdout_fd
, 1);
712 r
= sd_event_add_io(s
->event
, &s
->stdout_event_source
, s
->stdout_fd
, EPOLLIN
, stdout_stream_new
, s
);
714 return log_error_errno(r
, "Failed to add stdout server fd to event source: %m");
716 r
= sd_event_source_set_priority(s
->stdout_event_source
, SD_EVENT_PRIORITY_NORMAL
+10);
718 return log_error_errno(r
, "Failed to adjust priority of stdout server event source: %m");