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/>.
23 #include <sys/epoll.h>
25 #include "socket-util.h"
27 #include "journald-syslog.h"
28 #include "journald-kmsg.h"
30 static void forward_syslog_iovec(Server *s, const struct iovec *iovec, unsigned n_iovec, struct ucred *ucred, struct timeval *tv) {
34 struct cmsghdr cmsghdr;
35 uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
37 union sockaddr_union sa;
44 msghdr.msg_iov = (struct iovec*) iovec;
45 msghdr.msg_iovlen = n_iovec;
48 sa.un.sun_family = AF_UNIX;
49 strncpy(sa.un.sun_path, "/run/systemd/journal/syslog", sizeof(sa.un.sun_path));
50 msghdr.msg_name = &sa;
51 msghdr.msg_namelen = offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path);
55 msghdr.msg_control = &control;
56 msghdr.msg_controllen = sizeof(control);
58 cmsg = CMSG_FIRSTHDR(&msghdr);
59 cmsg->cmsg_level = SOL_SOCKET;
60 cmsg->cmsg_type = SCM_CREDENTIALS;
61 cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
62 memcpy(CMSG_DATA(cmsg), ucred, sizeof(struct ucred));
63 msghdr.msg_controllen = cmsg->cmsg_len;
66 /* Forward the syslog message we received via /dev/log to
67 * /run/systemd/syslog. Unfortunately we currently can't set
68 * the SO_TIMESTAMP auxiliary data, and hence we don't. */
70 if (sendmsg(s->syslog_fd, &msghdr, MSG_NOSIGNAL) >= 0)
73 /* The socket is full? I guess the syslog implementation is
74 * too slow, and we shouldn't wait for that... */
78 if (ucred && errno == ESRCH) {
81 /* Hmm, presumably the sender process vanished
82 * by now, so let's fix it as good as we
87 memcpy(CMSG_DATA(cmsg), &u, sizeof(struct ucred));
89 if (sendmsg(s->syslog_fd, &msghdr, MSG_NOSIGNAL) >= 0)
97 log_debug("Failed to forward syslog message: %m");
100 static void forward_syslog_raw(Server *s, int priority, const char *buffer, struct ucred *ucred, struct timeval *tv) {
106 if (LOG_PRI(priority) > s->max_level_syslog)
109 IOVEC_SET_STRING(iovec, buffer);
110 forward_syslog_iovec(s, &iovec, 1, ucred, tv);
113 void server_forward_syslog(Server *s, int priority, const char *identifier, const char *message, struct ucred *ucred, struct timeval *tv) {
114 struct iovec iovec[5];
115 char header_priority[6], header_time[64], header_pid[16];
119 char *ident_buf = NULL;
122 assert(priority >= 0);
123 assert(priority <= 999);
126 if (LOG_PRI(priority) > s->max_level_syslog)
129 /* First: priority field */
130 snprintf(header_priority, sizeof(header_priority), "<%i>", priority);
131 char_array_0(header_priority);
132 IOVEC_SET_STRING(iovec[n++], header_priority);
134 /* Second: timestamp */
135 t = tv ? tv->tv_sec : ((time_t) (now(CLOCK_REALTIME) / USEC_PER_SEC));
139 if (strftime(header_time, sizeof(header_time), "%h %e %T ", tm) <= 0)
141 IOVEC_SET_STRING(iovec[n++], header_time);
143 /* Third: identifier and PID */
146 get_process_comm(ucred->pid, &ident_buf);
147 identifier = ident_buf;
150 snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) ucred->pid);
151 char_array_0(header_pid);
154 IOVEC_SET_STRING(iovec[n++], identifier);
156 IOVEC_SET_STRING(iovec[n++], header_pid);
157 } else if (identifier) {
158 IOVEC_SET_STRING(iovec[n++], identifier);
159 IOVEC_SET_STRING(iovec[n++], ": ");
162 /* Fourth: message */
163 IOVEC_SET_STRING(iovec[n++], message);
165 forward_syslog_iovec(s, iovec, n, ucred, tv);
170 int syslog_fixup_facility(int priority) {
172 if ((priority & LOG_FACMASK) == 0)
173 return (priority & LOG_PRIMASK) | LOG_USER;
178 void syslog_read_identifier(const char **buf, char **identifier, char **pid) {
189 p += strspn(p, WHITESPACE);
190 l = strcspn(p, WHITESPACE);
205 t = strndup(p+k+1, l-k-2);
225 *buf += strspn(*buf, WHITESPACE);
228 void server_process_syslog_message(
236 char *message = NULL, *syslog_priority = NULL, *syslog_facility = NULL, *syslog_identifier = NULL, *syslog_pid = NULL;
237 struct iovec iovec[N_IOVEC_META_FIELDS + 6];
239 int priority = LOG_USER | LOG_INFO;
240 char *identifier = NULL, *pid = NULL;
247 syslog_parse_priority((char**) &buf, &priority);
249 if (s->forward_to_syslog)
250 forward_syslog_raw(s, priority, orig, ucred, tv);
252 syslog_skip_date((char**) &buf);
253 syslog_read_identifier(&buf, &identifier, &pid);
255 if (s->forward_to_kmsg)
256 server_forward_kmsg(s, priority, identifier, buf, ucred);
258 if (s->forward_to_console)
259 server_forward_console(s, priority, identifier, buf, ucred);
261 IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=syslog");
263 if (asprintf(&syslog_priority, "PRIORITY=%i", priority & LOG_PRIMASK) >= 0)
264 IOVEC_SET_STRING(iovec[n++], syslog_priority);
266 if (priority & LOG_FACMASK)
267 if (asprintf(&syslog_facility, "SYSLOG_FACILITY=%i", LOG_FAC(priority)) >= 0)
268 IOVEC_SET_STRING(iovec[n++], syslog_facility);
271 syslog_identifier = strappend("SYSLOG_IDENTIFIER=", identifier);
272 if (syslog_identifier)
273 IOVEC_SET_STRING(iovec[n++], syslog_identifier);
277 syslog_pid = strappend("SYSLOG_PID=", pid);
279 IOVEC_SET_STRING(iovec[n++], syslog_pid);
282 message = strappend("MESSAGE=", buf);
284 IOVEC_SET_STRING(iovec[n++], message);
286 server_dispatch_message(s, iovec, n, ELEMENTSOF(iovec), ucred, tv, label, label_len, NULL, priority);
291 free(syslog_priority);
292 free(syslog_facility);
293 free(syslog_identifier);
297 int server_open_syslog_socket(Server *s) {
298 union sockaddr_union sa;
300 struct epoll_event ev;
304 if (s->syslog_fd < 0) {
306 s->syslog_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
307 if (s->syslog_fd < 0) {
308 log_error("socket() failed: %m");
313 sa.un.sun_family = AF_UNIX;
314 strncpy(sa.un.sun_path, "/dev/log", sizeof(sa.un.sun_path));
316 unlink(sa.un.sun_path);
318 r = bind(s->syslog_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
320 log_error("bind() failed: %m");
324 chmod(sa.un.sun_path, 0666);
326 fd_nonblock(s->syslog_fd, 1);
329 r = setsockopt(s->syslog_fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
331 log_error("SO_PASSCRED failed: %m");
337 r = setsockopt(s->syslog_fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one));
339 log_warning("SO_PASSSEC failed: %m");
343 r = setsockopt(s->syslog_fd, SOL_SOCKET, SO_TIMESTAMP, &one, sizeof(one));
345 log_error("SO_TIMESTAMP failed: %m");
351 ev.data.fd = s->syslog_fd;
352 if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, s->syslog_fd, &ev) < 0) {
353 log_error("Failed to add syslog server fd to epoll object: %m");