#include "sd-daemon.h"
#include "tcpwrap.h"
-#define STREAMS_MAX 256
+#define STREAMS_MAX 4096
#define SERVER_FD_MAX 16
-#define TIMEOUT ((int) (10*MSEC_PER_SEC))
+#define TIMEOUT ((int) (5*60*MSEC_PER_SEC))
typedef struct Stream Stream;
unsigned n_server_fd;
+ bool syslog_is_stream;
+
LIST_HEAD(Stream, streams);
unsigned n_streams;
} Server;
uid_t uid;
gid_t gid;
- bool prefix;
+ bool prefix:1;
+ bool tee_console:1;
char buffer[LINE_MAX];
size_t length;
IOVEC_SET_STRING(iovec[3], header_pid);
IOVEC_SET_STRING(iovec[4], p);
+ /* When using syslog via SOCK_STREAM separate the messages by NUL chars */
+ if (s->server->syslog_is_stream)
+ iovec[4].iov_len++;
+
zero(msghdr);
msghdr.msg_iov = iovec;
msghdr.msg_iovlen = ELEMENTSOF(iovec);
msghdr.msg_control = &control;
msghdr.msg_controllen = control.cmsghdr.cmsg_len;
- if (sendmsg(s->server->syslog_fd, &msghdr, MSG_NOSIGNAL) < 0)
- return -errno;
+ for (;;) {
+ ssize_t n;
+
+ if ((n = sendmsg(s->server->syslog_fd, &msghdr, MSG_NOSIGNAL)) < 0) {
+
+ if (errno == ESRCH) {
+ pid_t our_pid;
+
+ /* Hmm, maybe the process this
+ * line originates from is
+ * dead? Then let's patch in
+ * our own pid and retry,
+ * since we have nothing
+ * better */
+
+ our_pid = getpid();
+
+ if (ucred->pid != our_pid) {
+ ucred->pid = our_pid;
+ continue;
+ }
+ }
+
+ return -errno;
+ }
+
+ if (!s->server->syslog_is_stream ||
+ (size_t) n >= IOVEC_TOTAL_SIZE(iovec, ELEMENTSOF(iovec)))
+ break;
+
+ IOVEC_INCREMENT(iovec, ELEMENTSOF(iovec), n);
+ }
} else if (s->target == STREAM_KMSG) {
IOVEC_SET_STRING(iovec[1], s->process);
} else
assert_not_reached("Unknown log target");
+ if (s->tee_console) {
+ int console;
+
+ if ((console = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC)) >= 0) {
+ IOVEC_SET_STRING(iovec[0], s->process);
+ IOVEC_SET_STRING(iovec[1], header_pid);
+ IOVEC_SET_STRING(iovec[2], p);
+ IOVEC_SET_STRING(iovec[3], (char*) "\n");
+
+ writev(console, iovec, 4);
+ }
+
+ }
+
return 0;
}
switch (s->state) {
case STREAM_TARGET:
- if (streq(p, "syslog"))
+ if (streq(p, "syslog") || streq(p, "syslog+console"))
s->target = STREAM_SYSLOG;
- else if (streq(p, "kmsg")) {
+ else if (streq(p, "kmsg") || streq(p, "kmsg+console")) {
if (s->server->kmsg_fd >= 0 && s->uid == 0)
s->target = STREAM_KMSG;
log_warning("Failed to parse log target line.");
return -EBADMSG;
}
+
+ if (endswith(p, "+console"))
+ s->tee_console = true;
+
s->state = STREAM_PRIORITY;
return 0;
return 0;
log_warning("Failed to read from stream: %m");
- return -1;
+ return -errno;
}
/* We use ev.data.ptr instead of ev.data.fd here,
* since on 64bit archs fd is 32bit while a pointer is
- * 64bit. To make sure we can easily distuingish fd
+ * 64bit. To make sure we can easily distinguish fd
* values and pointer values we want to make sure to
* write the full field unconditionally. */
}
}
- if ((s->syslog_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0)) < 0) {
- r = -errno;
- log_error("Failed to create log fd: %m");
- goto fail;
- }
-
zero(sa);
sa.un.sun_family = AF_UNIX;
strncpy(sa.un.sun_path, "/dev/log", sizeof(sa.un.sun_path));
- if (connect(s->syslog_fd, &sa.sa, sizeof(sa)) < 0) {
+ if ((s->syslog_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0)) < 0) {
r = -errno;
- log_error("Failed to connect log socket to /dev/log: %m");
+ log_error("Failed to create log fd: %m");
goto fail;
}
+ if (connect(s->syslog_fd, &sa.sa, sizeof(sa)) < 0) {
+ close_nointr_nofail(s->syslog_fd);
+
+ if ((s->syslog_fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0)) < 0) {
+ r = -errno;
+ log_error("Failed to create log fd: %m");
+ goto fail;
+ }
+
+ if (connect(s->syslog_fd, &sa.sa, sizeof(sa)) < 0) {
+ r = -errno;
+ log_error("Failed to connect log socket to /dev/log: %m");
+ goto fail;
+ }
+
+ s->syslog_is_stream = true;
+ } else
+ s->syslog_is_stream = false;
+
/* /dev/kmsg logging is strictly optional */
if ((s->kmsg_fd = open("/dev/kmsg", O_WRONLY|O_NOCTTY|O_CLOEXEC)) < 0)
log_warning("Failed to open /dev/kmsg for logging, disabling kernel log buffer support: %m");