journal-send.c revision a6e87e90ede66815989ba2db92a07102a69906fe
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering This file is part of systemd.
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering Copyright 2011 Lennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering systemd is free software; you can redistribute it and/or modify it
5430f7f2bc7330f3088b894166bf3524a067e3d8Lennart Poettering under the terms of the GNU Lesser General Public License as published by
5430f7f2bc7330f3088b894166bf3524a067e3d8Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering (at your option) any later version.
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering systemd is distributed in the hope that it will be useful, but
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2bc7330f3088b894166bf3524a067e3d8Lennart Poettering Lesser General Public License for more details.
5430f7f2bc7330f3088b894166bf3524a067e3d8Lennart Poettering You should have received a copy of the GNU Lesser General Public License
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering/* We open a single fd, and we'll share it with the current process,
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering * all its threads, and all its subprocesses. This means we need to
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering * initialize it atomically, and need to operate on it atomically
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering * never assuming we are the only user */
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poetteringstatic int journal_fd(void) {
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering if (!__sync_bool_compare_and_swap(&fd_plus_one, 0, fd+1)) {
a5344d2c3b0f14e954ce1c0ef905c5b44bc5bf0aLennart Poettering_public_ int sd_journal_print(int priority, const char *format, ...) {
d0bbc21caa6e68693a47db60c93e99422bf2a858Lennart Poettering r = sd_journal_printv(priority, format, ap);
a5344d2c3b0f14e954ce1c0ef905c5b44bc5bf0aLennart Poettering_public_ int sd_journal_printv(int priority, const char *format, va_list ap) {
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering /* FIXME: Instead of limiting things to LINE_MAX we could do a
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering C99 variable-length array on the stack here in a loop. */
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering char buffer[8 + LINE_MAX], p[11]; struct iovec iov[2];
d0bbc21caa6e68693a47db60c93e99422bf2a858Lennart Poettering snprintf(p, sizeof(p), "PRIORITY=%i", priority & LOG_PRIMASK);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poetteringstatic int fill_iovec_sprintf(const char *format, va_list ap, int extra, struct iovec **_iov) {
25d042e81516246b1ebf706a57c47ac19abb0b8aLennart Poettering int r, n = 0, i = 0, j;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering c = realloc(iov, n * sizeof(struct iovec));
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering if (vasprintf(&buffer, format, ap) < 0) {
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering for (j = 0; j < i; j++)
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering_public_ int sd_journal_send(const char *format, ...) {
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering i = fill_iovec_sprintf(format, ap, 0, &iov);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering for (j = 0; j < i; j++)
a5344d2c3b0f14e954ce1c0ef905c5b44bc5bf0aLennart Poettering_public_ int sd_journal_sendv(const struct iovec *iov, int n) {
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering int r, i, j = 0;
9058851be7821edac08c1fa7ecafe5cba9ab9022Lennart Poettering /* We use /dev/shm instead of /tmp here, since we want this to
9058851be7821edac08c1fa7ecafe5cba9ab9022Lennart Poettering * be a tmpfs, and one that is available from early boot on
9058851be7821edac08c1fa7ecafe5cba9ab9022Lennart Poettering * and where unprivileged users can create files. */
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering w = alloca(sizeof(struct iovec) * n * 5);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering for (i = 0; i < n; i++) {
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering if (_unlikely_(!iov[i].iov_base || iov[i].iov_len <= 1)) {
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering c = memchr(iov[i].iov_base, '=', iov[i].iov_len);
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering if (_unlikely_(!c || c == iov[i].iov_base)) {
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering nl = memchr(iov[i].iov_base, '\n', iov[i].iov_len);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering /* Already includes a newline? Bummer, then
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering * let's write the variable name, then a
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering * newline, then the size (64bit LE), followed
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering * by the data and a final newline */
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering w[j].iov_len = c - (char*) iov[i].iov_base;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering l[i] = htole64(iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering w[j].iov_len = iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering /* Nothing special? Then just add the line and
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering * append a newline */
5ba081b0fb02380cee4c2ff5bc7e05f869eb8415Lennart Poettering strncpy(sa.sun_path, "/run/systemd/journal/socket", sizeof(sa.sun_path));
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering mh.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(sa.sun_path);
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering if (errno != EMSGSIZE && errno != ENOBUFS) {
0dad12c190b7493955cd60d2a1625199b1709f69Lennart Poettering /* Message doesn't fit... Let's dump the data in a temporary
0dad12c190b7493955cd60d2a1625199b1709f69Lennart Poettering * file and just pass a file descriptor of it to the other
0dad12c190b7493955cd60d2a1625199b1709f69Lennart Poettering buffer_fd = mkostemp(path, O_CLOEXEC|O_RDWR);
0dad12c190b7493955cd60d2a1625199b1709f69Lennart Poettering memcpy(CMSG_DATA(cmsg), &buffer_fd, sizeof(int));
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poetteringstatic int fill_iovec_perror_and_send(const char *message, int skip, struct iovec iov[]) {
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering k = isempty(message) ? 0 : strlen(message) + 2;
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering j = strerror_r(saved_errno, buffer + 8 + k, n - 8 - k);
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering char error[6 + 10 + 1]; /* for a 32bit value */
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering snprintf(error, sizeof(error), "ERRNO=%u", saved_errno);
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering IOVEC_SET_STRING(iov[skip+0], "PRIORITY=3");
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering_public_ int sd_journal_perror(const char *message) {
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering return fill_iovec_perror_and_send(message, 0, iovec);
4cd9a9d9ecf3a8835e21930f3215a5f5b74144beLennart Poettering_public_ int sd_journal_stream_fd(const char *identifier, int priority, int level_prefix) {
fe6521272ba203ec8f0d5a94f0729960b3f90525Lennart Poettering fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
259d2e762041d8d50c2a17bfea90b1a96f6b880bLennart Poettering strncpy(sa.un.sun_path, "/run/systemd/journal/stdout", sizeof(sa.un.sun_path));
fe6521272ba203ec8f0d5a94f0729960b3f90525Lennart Poettering r = connect(fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
8b38f3cc3eb73adf9536cb73d0f319e60d42ea0cLennart Poettering header = alloca(l + 1 + 1 + 2 + 2 + 2 + 2 + 2);
fe6521272ba203ec8f0d5a94f0729960b3f90525Lennart Poettering return (int) r;
fe6521272ba203ec8f0d5a94f0729960b3f90525Lennart Poettering if ((size_t) r != l) {
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering_public_ int sd_journal_print_with_location(int priority, const char *file, const char *line, const char *func, const char *format, ...) {
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering r = sd_journal_printv_with_location(priority, file, line, func, format, ap);
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering_public_ int sd_journal_printv_with_location(int priority, const char *file, const char *line, const char *func, const char *format, va_list ap) {
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering snprintf(p, sizeof(p), "PRIORITY=%i", priority & LOG_PRIMASK);
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering /* func is initialized from __func__ which is not a macro, but
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering * a static const char[], hence cannot easily be prefixed with
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering * CODE_FUNC=, hence let's do it manually here. */
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering return sd_journal_sendv(iov, ELEMENTSOF(iov));
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering_public_ int sd_journal_send_with_location(const char *file, const char *line, const char *func, const char *format, ...) {
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering i = fill_iovec_sprintf(format, ap, 3, &iov);
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering for (j = 3; j < i; j++)
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering_public_ int sd_journal_sendv_with_location(
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering niov = alloca(sizeof(struct iovec) * (n + 3));
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering memcpy(niov, iov, sizeof(struct iovec) * n);
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering_public_ int sd_journal_perror_with_location(