journal-send.c revision 5430f7f2bc7330f3088b894166bf3524a067e3d8
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering This file is part of systemd.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Copyright 2011 Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering systemd is free software; you can redistribute it and/or modify it
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering under the terms of the GNU Lesser General Public License as published by
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering (at your option) any later version.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering systemd is distributed in the hope that it will be useful, but
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Lesser General Public License for more details.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering You should have received a copy of the GNU Lesser General Public License
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering/* We open a single fd, and we'll share it with the current process,
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen * all its threads, and all its subprocesses. This means we need to
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen * initialize it atomically, and need to operate on it atomically
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * never assuming we are the only user */
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poetteringstatic int journal_fd(void) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!__sync_bool_compare_and_swap(&fd_plus_one, 0, fd+1)) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering_public_ int sd_journal_print(int priority, const char *format, ...) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen_public_ int sd_journal_printv(int priority, const char *format, va_list ap) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen snprintf(p, sizeof(p), "PRIORITY=%i", priority & LOG_PRIMASK);
e56056e93d33619a3acf13e483900b4f8938228fThomas Hindoe Paaboel Andersen vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic int fill_iovec_sprintf(const char *format, va_list ap, int extra, struct iovec **_iov) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int r, n = 0, i, j;
e56056e93d33619a3acf13e483900b4f8938228fThomas Hindoe Paaboel Andersen n = MAX(extra * 2, extra + 4);
e56056e93d33619a3acf13e483900b4f8938228fThomas Hindoe Paaboel Andersen iov = malloc0(n * sizeof(struct iovec));
d21ed1ead18d16d35c30299a69d3366847f8a039Lennart Poettering c = realloc(iov, n * sizeof(struct iovec));
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering if (vasprintf(&buffer, format, ap) < 0) {
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering for (j = 0; j < i; j++)
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering_public_ int sd_journal_send(const char *format, ...) {
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering i = fill_iovec_sprintf(format, ap, 0, &iov);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering for (j = 0; j < i; j++)
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering_public_ int sd_journal_sendv(const struct iovec *iov, int n) {
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering int r, i, j = 0;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering /* We use /dev/shm instead of /tmp here, since we want this to
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering * be a tmpfs, and one that is available from early boot on
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering * and where unprivileged users can create files. */
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering w = alloca(sizeof(struct iovec) * n * 5);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering for (i = 0; i < n; i++) {
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering if (_unlikely_(!iov[i].iov_base || iov[i].iov_len <= 1)) {
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering c = memchr(iov[i].iov_base, '=', iov[i].iov_len);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering if (_unlikely_(!c || c == iov[i].iov_base)) {
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering nl = memchr(iov[i].iov_base, '\n', iov[i].iov_len);
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering /* Already includes a newline? Bummer, then
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering * let's write the variable name, then a
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering * newline, then the size (64bit LE), followed
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering * by the data and a final newline */
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering w[j].iov_len = c - (char*) iov[i].iov_base;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering l[i] = htole64(iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1);
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering w[j].iov_len = iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering /* Nothing special? Then just add the line and
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering * append a newline */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering strncpy(sa.sun_path, "/run/systemd/journal/socket", sizeof(sa.sun_path));
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers mh.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(sa.sun_path);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (k >= 0) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (errno != EMSGSIZE && errno != ENOBUFS) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* Message doesn't fit... Let's dump the data in a temporary
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * file and just pass a file descriptor of it to the other
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering buffer_fd = mkostemp(path, O_CLOEXEC|O_RDWR);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering memcpy(CMSG_DATA(cmsg), &buffer_fd, sizeof(int));
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers_public_ int sd_journal_stream_fd(const char *identifier, int priority, int level_prefix) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers strncpy(sa.un.sun_path, "/run/systemd/journal/stdout", sizeof(sa.un.sun_path));
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen r = connect(fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers if (r < 0) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen return (int) r;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers if ((size_t) r != l) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering_public_ int sd_journal_print_with_location(int priority, const char *file, const char *line, const char *func, const char *format, ...) {
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers r = sd_journal_printv_with_location(priority, file, line, func, format, ap);
1ee306e1248866617c96ed9f4263f375588ad838Lennart 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) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen snprintf(p, sizeof(p), "PRIORITY=%i", priority & LOG_PRIMASK);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
5b30bef856e89a571df57b7b953e9a1409d9acedLennart Poettering /* func is initialized from __func__ which is not a macro, but
5b30bef856e89a571df57b7b953e9a1409d9acedLennart Poettering * a static const char[], hence cannot easily be prefixed with
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * CODE_FUNC=, hence let's do it manually here. */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return sd_journal_sendv(iov, ELEMENTSOF(iov));
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering_public_ int sd_journal_send_with_location(const char *file, const char *line, const char *func, const char *format, ...) {
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering for (j = 3; j < i; j++)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering_public_ int sd_journal_sendv_with_location(const char *file, const char *line, const char *func, const struct iovec *iov, int n) {
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering niov = alloca(sizeof(struct iovec) * (n + 3));
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering memcpy(niov, iov, sizeof(struct iovec) * n);