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"
29 #include "journald-console.h"
31 static void forward_syslog_iovec(Server *s, const struct iovec *iovec, unsigned n_iovec, struct ucred *ucred, struct timeval *tv) {
35 struct cmsghdr cmsghdr;
36 uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
38 union sockaddr_union sa;
45 msghdr.msg_iov = (struct iovec*) iovec;
46 msghdr.msg_iovlen = n_iovec;
49 sa.un.sun_family = AF_UNIX;
50 strncpy(sa.un.sun_path, "/run/systemd/journal/syslog", sizeof(sa.un.sun_path));
51 msghdr.msg_name = &sa;
52 msghdr.msg_namelen = offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path);
56 msghdr.msg_control = &control;
57 msghdr.msg_controllen = sizeof(control);
59 cmsg = CMSG_FIRSTHDR(&msghdr);
60 cmsg->cmsg_level = SOL_SOCKET;
61 cmsg->cmsg_type = SCM_CREDENTIALS;
62 cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
63 memcpy(CMSG_DATA(cmsg), ucred, sizeof(struct ucred));
64 msghdr.msg_controllen = cmsg->cmsg_len;
67 /* Forward the syslog message we received via /dev/log to
68 * /run/systemd/syslog. Unfortunately we currently can't set
69 * the SO_TIMESTAMP auxiliary data, and hence we don't. */
71 if (sendmsg(s->syslog_fd, &msghdr, MSG_NOSIGNAL) >= 0)
74 /* The socket is full? I guess the syslog implementation is
75 * too slow, and we shouldn't wait for that... */
79 if (ucred && errno == ESRCH) {
82 /* Hmm, presumably the sender process vanished
83 * by now, so let's fix it as good as we
88 memcpy(CMSG_DATA(cmsg), &u, sizeof(struct ucred));
90 if (sendmsg(s->syslog_fd, &msghdr, MSG_NOSIGNAL) >= 0)
98 log_debug("Failed to forward syslog message: %m");
101 static void forward_syslog_raw(Server *s, int priority, const char *buffer, struct ucred *ucred, struct timeval *tv) {
107 if (LOG_PRI(priority) > s->max_level_syslog)
110 IOVEC_SET_STRING(iovec, buffer);
111 forward_syslog_iovec(s, &iovec, 1, ucred, tv);
114 void server_forward_syslog(Server *s, int priority, const char *identifier, const char *message, struct ucred *ucred, struct timeval *tv) {
115 struct iovec iovec[5];
116 char header_priority[6], header_time[64], header_pid[16];
120 char *ident_buf = NULL;
123 assert(priority >= 0);
124 assert(priority <= 999);
127 if (LOG_PRI(priority) > s->max_level_syslog)
130 /* First: priority field */
131 snprintf(header_priority, sizeof(header_priority), "<%i>", priority);
132 char_array_0(header_priority);
133 IOVEC_SET_STRING(iovec[n++], header_priority);
135 /* Second: timestamp */
136 t = tv ? tv->tv_sec : ((time_t) (now(CLOCK_REALTIME) / USEC_PER_SEC));
140 if (strftime(header_time, sizeof(header_time), "%h %e %T ", tm) <= 0)
142 IOVEC_SET_STRING(iovec[n++], header_time);
144 /* Third: identifier and PID */
147 get_process_comm(ucred->pid, &ident_buf);
148 identifier = ident_buf;
151 snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) ucred->pid);
152 char_array_0(header_pid);
155 IOVEC_SET_STRING(iovec[n++], identifier);
157 IOVEC_SET_STRING(iovec[n++], header_pid);
158 } else if (identifier) {
159 IOVEC_SET_STRING(iovec[n++], identifier);
160 IOVEC_SET_STRING(iovec[n++], ": ");
163 /* Fourth: message */
164 IOVEC_SET_STRING(iovec[n++], message);
166 forward_syslog_iovec(s, iovec, n, ucred, tv);
171 int syslog_fixup_facility(int priority) {
173 if ((priority & LOG_FACMASK) == 0)
174 return (priority & LOG_PRIMASK) | LOG_USER;
179 void syslog_parse_identifier(const char **buf, char **identifier, char **pid) {
190 p += strspn(p, WHITESPACE);
191 l = strcspn(p, WHITESPACE);
206 t = strndup(p+k+1, l-k-2);
226 *buf += strspn(*buf, WHITESPACE);
229 void syslog_parse_priority(char **p, int *priority) {
230 int a = 0, b = 0, c = 0;
240 if (!strchr(*p, '>'))
243 if ((*p)[2] == '>') {
244 c = undecchar((*p)[1]);
246 } else if ((*p)[3] == '>') {
247 b = undecchar((*p)[1]);
248 c = undecchar((*p)[2]);
250 } else if ((*p)[4] == '>') {
251 a = undecchar((*p)[1]);
252 b = undecchar((*p)[2]);
253 c = undecchar((*p)[3]);
258 if (a < 0 || b < 0 || c < 0)
261 *priority = a*100+b*10+c;
265 static void syslog_skip_date(char **buf) {
273 LETTER, LETTER, LETTER,
275 SPACE_OR_NUMBER, NUMBER,
277 SPACE_OR_NUMBER, NUMBER,
279 SPACE_OR_NUMBER, NUMBER,
281 SPACE_OR_NUMBER, NUMBER,
293 for (i = 0; i < ELEMENTSOF(sequence); i++, p++) {
298 switch (sequence[i]) {
305 case SPACE_OR_NUMBER:
312 if (*p < '0' || *p > '9')
318 if (!(*p >= 'A' && *p <= 'Z') &&
319 !(*p >= 'a' && *p <= 'z'))
335 void server_process_syslog_message(
343 char *message = NULL, *syslog_priority = NULL, *syslog_facility = NULL, *syslog_identifier = NULL, *syslog_pid = NULL;
344 struct iovec iovec[N_IOVEC_META_FIELDS + 6];
346 int priority = LOG_USER | LOG_INFO;
347 char *identifier = NULL, *pid = NULL;
354 syslog_parse_priority((char**) &buf, &priority);
356 if (s->forward_to_syslog)
357 forward_syslog_raw(s, priority, orig, ucred, tv);
359 syslog_skip_date((char**) &buf);
360 syslog_parse_identifier(&buf, &identifier, &pid);
362 if (s->forward_to_kmsg)
363 server_forward_kmsg(s, priority, identifier, buf, ucred);
365 if (s->forward_to_console)
366 server_forward_console(s, priority, identifier, buf, ucred);
368 IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=syslog");
370 if (asprintf(&syslog_priority, "PRIORITY=%i", priority & LOG_PRIMASK) >= 0)
371 IOVEC_SET_STRING(iovec[n++], syslog_priority);
373 if (priority & LOG_FACMASK)
374 if (asprintf(&syslog_facility, "SYSLOG_FACILITY=%i", LOG_FAC(priority)) >= 0)
375 IOVEC_SET_STRING(iovec[n++], syslog_facility);
378 syslog_identifier = strappend("SYSLOG_IDENTIFIER=", identifier);
379 if (syslog_identifier)
380 IOVEC_SET_STRING(iovec[n++], syslog_identifier);
384 syslog_pid = strappend("SYSLOG_PID=", pid);
386 IOVEC_SET_STRING(iovec[n++], syslog_pid);
389 message = strappend("MESSAGE=", buf);
391 IOVEC_SET_STRING(iovec[n++], message);
393 server_dispatch_message(s, iovec, n, ELEMENTSOF(iovec), ucred, tv, label, label_len, NULL, priority);
398 free(syslog_priority);
399 free(syslog_facility);
400 free(syslog_identifier);
404 int server_open_syslog_socket(Server *s) {
405 union sockaddr_union sa;
407 struct epoll_event ev;
411 if (s->syslog_fd < 0) {
413 s->syslog_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
414 if (s->syslog_fd < 0) {
415 log_error("socket() failed: %m");
420 sa.un.sun_family = AF_UNIX;
421 strncpy(sa.un.sun_path, "/dev/log", sizeof(sa.un.sun_path));
423 unlink(sa.un.sun_path);
425 r = bind(s->syslog_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
427 log_error("bind() failed: %m");
431 chmod(sa.un.sun_path, 0666);
433 fd_nonblock(s->syslog_fd, 1);
436 r = setsockopt(s->syslog_fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
438 log_error("SO_PASSCRED failed: %m");
444 r = setsockopt(s->syslog_fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one));
446 log_warning("SO_PASSSEC failed: %m");
450 r = setsockopt(s->syslog_fd, SOL_SOCKET, SO_TIMESTAMP, &one, sizeof(one));
452 log_error("SO_TIMESTAMP failed: %m");
458 ev.data.fd = s->syslog_fd;
459 if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, s->syslog_fd, &ev) < 0) {
460 log_error("Failed to add syslog server fd to epoll object: %m");