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/>.
22 #include <sys/socket.h>
29 #define SD_JOURNAL_SUPPRESS_LOCATION
31 #include "sd-journal.h"
33 #include "socket-util.h"
35 #define SNDBUF_SIZE (8*1024*1024)
37 /* We open a single fd, and we'll share it with the current process,
38 * all its threads, and all its subprocesses. This means we need to
39 * initialize it atomically, and need to operate on it atomically
40 * never assuming we are the only user */
42 static int journal_fd(void) {
44 static int fd_plus_one = 0;
48 return fd_plus_one - 1;
50 fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
54 fd_inc_sndbuf(fd, SNDBUF_SIZE);
56 if (!__sync_bool_compare_and_swap(&fd_plus_one, 0, fd+1)) {
57 close_nointr_nofail(fd);
64 _public_ int sd_journal_print(int priority, const char *format, ...) {
69 r = sd_journal_printv(priority, format, ap);
75 _public_ int sd_journal_printv(int priority, const char *format, va_list ap) {
76 char buffer[8 + LINE_MAX], p[11];
79 if (priority < 0 || priority > 7)
85 snprintf(p, sizeof(p), "PRIORITY=%i", priority & LOG_PRIMASK);
88 memcpy(buffer, "MESSAGE=", 8);
89 vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
93 IOVEC_SET_STRING(iov[0], buffer);
94 IOVEC_SET_STRING(iov[1], p);
96 return sd_journal_sendv(iov, 2);
99 static int fill_iovec_sprintf(const char *format, va_list ap, int extra, struct iovec **_iov) {
101 struct iovec *iov = NULL;
108 n = MAX(extra * 2, extra + 4);
109 iov = malloc0(n * sizeof(struct iovec));
125 c = realloc(iov, n * sizeof(struct iovec));
134 if (vasprintf(&buffer, format, ap) < 0) {
139 IOVEC_SET_STRING(iov[i++], buffer);
141 format = va_arg(ap, char *);
150 for (j = 0; j < i; j++)
151 free(iov[j].iov_base);
159 _public_ int sd_journal_send(const char *format, ...) {
162 struct iovec *iov = NULL;
164 va_start(ap, format);
165 i = fill_iovec_sprintf(format, ap, 0, &iov);
168 if (_unlikely_(i < 0)) {
173 r = sd_journal_sendv(iov, i);
176 for (j = 0; j < i; j++)
177 free(iov[j].iov_base);
184 _public_ int sd_journal_sendv(const struct iovec *iov, int n) {
190 struct sockaddr_un sa;
194 struct cmsghdr cmsghdr;
195 uint8_t buf[CMSG_SPACE(sizeof(int))];
197 struct cmsghdr *cmsg;
198 /* We use /dev/shm instead of /tmp here, since we want this to
199 * be a tmpfs, and one that is available from early boot on
200 * and where unprivileged users can create files. */
201 char path[] = "/dev/shm/journal.XXXXXX";
203 if (_unlikely_(!iov))
206 if (_unlikely_(n <= 0))
211 w = alloca(sizeof(struct iovec) * n * 5);
212 l = alloca(sizeof(uint64_t) * n);
214 for (i = 0; i < n; i++) {
217 if (_unlikely_(!iov[i].iov_base || iov[i].iov_len <= 1)) {
222 c = memchr(iov[i].iov_base, '=', iov[i].iov_len);
223 if (_unlikely_(!c || c == iov[i].iov_base)) {
228 nl = memchr(iov[i].iov_base, '\n', iov[i].iov_len);
230 if (_unlikely_(nl < c)) {
235 /* Already includes a newline? Bummer, then
236 * let's write the variable name, then a
237 * newline, then the size (64bit LE), followed
238 * by the data and a final newline */
240 w[j].iov_base = iov[i].iov_base;
241 w[j].iov_len = c - (char*) iov[i].iov_base;
244 IOVEC_SET_STRING(w[j++], "\n");
246 l[i] = htole64(iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1);
247 w[j].iov_base = &l[i];
248 w[j].iov_len = sizeof(uint64_t);
251 w[j].iov_base = c + 1;
252 w[j].iov_len = iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1;
256 /* Nothing special? Then just add the line and
257 * append a newline */
260 IOVEC_SET_STRING(w[j++], "\n");
264 if (_unlikely_(fd < 0)) {
270 sa.sun_family = AF_UNIX;
271 strncpy(sa.sun_path, "/run/systemd/journal/socket", sizeof(sa.sun_path));
275 mh.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(sa.sun_path);
279 k = sendmsg(fd, &mh, MSG_NOSIGNAL);
285 if (errno != EMSGSIZE && errno != ENOBUFS) {
290 /* Message doesn't fit... Let's dump the data in a temporary
291 * file and just pass a file descriptor of it to the other
294 buffer_fd = mkostemp(path, O_CLOEXEC|O_RDWR);
300 if (unlink(path) < 0) {
301 close_nointr_nofail(buffer_fd);
306 n = writev(buffer_fd, w, j);
308 close_nointr_nofail(buffer_fd);
317 mh.msg_control = &control;
318 mh.msg_controllen = sizeof(control);
320 cmsg = CMSG_FIRSTHDR(&mh);
321 cmsg->cmsg_level = SOL_SOCKET;
322 cmsg->cmsg_type = SCM_RIGHTS;
323 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
324 memcpy(CMSG_DATA(cmsg), &buffer_fd, sizeof(int));
326 mh.msg_controllen = cmsg->cmsg_len;
328 k = sendmsg(fd, &mh, MSG_NOSIGNAL);
329 close_nointr_nofail(buffer_fd);
344 _public_ int sd_journal_stream_fd(const char *identifier, int priority, int level_prefix) {
345 union sockaddr_union sa;
351 if (priority < 0 || priority > 7)
354 fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
359 sa.un.sun_family = AF_UNIX;
360 strncpy(sa.un.sun_path, "/run/systemd/journal/stdout", sizeof(sa.un.sun_path));
362 r = connect(fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
364 close_nointr_nofail(fd);
368 if (shutdown(fd, SHUT_RD) < 0) {
369 close_nointr_nofail(fd);
373 fd_inc_sndbuf(fd, SNDBUF_SIZE);
378 l = strlen(identifier);
379 header = alloca(l + 1 + 2 + 2 + 2 + 2 + 2);
381 memcpy(header, identifier, l);
383 header[l++] = '0' + priority;
385 header[l++] = '0' + !!level_prefix;
394 r = loop_write(fd, header, l, false);
396 close_nointr_nofail(fd);
400 if ((size_t) r != l) {
401 close_nointr_nofail(fd);
408 _public_ int sd_journal_print_with_location(int priority, const char *file, const char *line, const char *func, const char *format, ...) {
412 va_start(ap, format);
413 r = sd_journal_printv_with_location(priority, file, line, func, format, ap);
419 _public_ int sd_journal_printv_with_location(int priority, const char *file, const char *line, const char *func, const char *format, va_list ap) {
420 char buffer[8 + LINE_MAX], p[11];
425 if (priority < 0 || priority > 7)
428 if (_unlikely_(!format))
431 snprintf(p, sizeof(p), "PRIORITY=%i", priority & LOG_PRIMASK);
434 memcpy(buffer, "MESSAGE=", 8);
435 vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
436 char_array_0(buffer);
438 /* func is initialized from __func__ which is not a macro, but
439 * a static const char[], hence cannot easily be prefixed with
440 * CODE_FUNC=, hence let's do it manually here. */
443 memcpy(f, "CODE_FUNC=", 10);
444 memcpy(f + 10, func, fl + 1);
447 IOVEC_SET_STRING(iov[0], buffer);
448 IOVEC_SET_STRING(iov[1], p);
449 IOVEC_SET_STRING(iov[2], file);
450 IOVEC_SET_STRING(iov[3], line);
451 IOVEC_SET_STRING(iov[4], f);
453 return sd_journal_sendv(iov, ELEMENTSOF(iov));
456 _public_ int sd_journal_send_with_location(const char *file, const char *line, const char *func, const char *format, ...) {
459 struct iovec *iov = NULL;
463 va_start(ap, format);
464 i = fill_iovec_sprintf(format, ap, 3, &iov);
467 if (_unlikely_(i < 0)) {
474 memcpy(f, "CODE_FUNC=", 10);
475 memcpy(f + 10, func, fl + 1);
477 IOVEC_SET_STRING(iov[0], file);
478 IOVEC_SET_STRING(iov[1], line);
479 IOVEC_SET_STRING(iov[2], f);
481 r = sd_journal_sendv(iov, i);
484 for (j = 3; j < i; j++)
485 free(iov[j].iov_base);
492 _public_ int sd_journal_sendv_with_location(const char *file, const char *line, const char *func, const struct iovec *iov, int n) {
497 if (_unlikely_(!iov))
500 if (_unlikely_(n <= 0))
503 niov = alloca(sizeof(struct iovec) * (n + 3));
504 memcpy(niov, iov, sizeof(struct iovec) * n);
508 memcpy(f, "CODE_FUNC=", 10);
509 memcpy(f + 10, func, fl + 1);
511 IOVEC_SET_STRING(niov[n++], file);
512 IOVEC_SET_STRING(niov[n++], line);
513 IOVEC_SET_STRING(niov[n++], f);
515 return sd_journal_sendv(niov, n);