journal-send.c revision 6c045c0b4c49c88a1d3b9360c05efa5084796d2d
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/>.
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen char **_f = &(f); \
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering } while(false)
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering/* We open a single fd, and we'll share it with the current process,
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering * all its threads, and all its subprocesses. This means we need to
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering * initialize it atomically, and need to operate on it atomically
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering * never assuming we are the only user */
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poetteringstatic int journal_fd(void) {
e56056e93d33619a3acf13e483900b4f8938228fThomas Hindoe Paaboel Andersen fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart 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, ...) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = sd_journal_printv(priority, format, ap);
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering_public_ int sd_journal_printv(int priority, const char *format, va_list ap) {
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering /* FIXME: Instead of limiting things to LINE_MAX we could do a
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering C99 variable-length array on the stack here in a loop. */
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering char buffer[8 + LINE_MAX], p[11]; struct iovec iov[2];
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering snprintf(p, sizeof(p), "PRIORITY=%i", priority & LOG_PRIMASK);
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering_printf_(1, 0) static int fill_iovec_sprintf(const char *format, va_list ap, int extra, struct iovec **_iov) {
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering int r, n = 0, i = 0, j;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (i >= n) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (vasprintf(&buffer, format, aq) < 0) {
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering for (j = 0; j < i; j++)
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering_public_ int sd_journal_send(const char *format, ...) {
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering for (j = 0; j < i; j++)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering_public_ int sd_journal_sendv(const struct iovec *iov, int n) {
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poettering .sun_path = "/run/systemd/journal/socket",
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering .msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(sa.sun_path),
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering /* We use /dev/shm instead of /tmp here, since we want this to
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering * be a tmpfs, and one that is available from early boot on
c19de71113f956809995fc68817e055e9f61f607Lennart Poettering * and where unprivileged users can create files. */
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poettering w = alloca(sizeof(struct iovec) * n * 5 + 3);
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering for (i = 0; i < n; i++) {
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering if (_unlikely_(!iov[i].iov_base || iov[i].iov_len <= 1))
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering c = memchr(iov[i].iov_base, '=', iov[i].iov_len);
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering if (_unlikely_(!c || c == iov[i].iov_base))
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering have_syslog_identifier = have_syslog_identifier ||
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering startswith(iov[i].iov_base, "SYSLOG_IDENTIFIER"));
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering nl = memchr(iov[i].iov_base, '\n', iov[i].iov_len);
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering /* Already includes a newline? Bummer, then
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering * let's write the variable name, then a
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering * newline, then the size (64bit LE), followed
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering * by the data and a final newline */
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering w[j].iov_len = c - (char*) iov[i].iov_base;
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering l[i] = htole64(iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1);
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering w[j].iov_len = iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1;
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poettering /* Nothing special? Then just add the line and
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering * append a newline */
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poettering string_is_safe(program_invocation_short_name)) {
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poettering /* Implicitly add program_invocation_short_name, if it
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poettering * is not set explicitly. We only do this for
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poettering * program_invocation_short_name, and nothing else
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering * since everything else is much nicer to retrieve
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poettering * from the outside. */
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poettering IOVEC_SET_STRING(w[j++], "SYSLOG_IDENTIFIER=");
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering IOVEC_SET_STRING(w[j++], program_invocation_short_name);
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering /* Fail silently if the journal is not available */
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering if (errno != EMSGSIZE && errno != ENOBUFS)
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poettering /* Message doesn't fit... Let's dump the data in a temporary
c19de71113f956809995fc68817e055e9f61f607Lennart Poettering * file and just pass a file descriptor of it to the other
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering buffer_fd = mkostemp(path, O_CLOEXEC|O_RDWR);
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering memcpy(CMSG_DATA(cmsg), &buffer_fd, sizeof(int));
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poetteringstatic int fill_iovec_perror_and_send(const char *message, int skip, struct iovec iov[]) {
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering k = isempty(message) ? 0 : strlen(message) + 2;
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering j = strerror_r(_saved_errno_, buffer + 8 + k, n - 8 - k);
5b30bef856e89a571df57b7b953e9a1409d9acedLennart Poettering char error[6 + 10 + 1]; /* for a 32bit value */
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering snprintf(error, sizeof(error), "ERRNO=%u", _saved_errno_);
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering IOVEC_SET_STRING(iov[skip+0], "PRIORITY=3");
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering_public_ int sd_journal_perror(const char *message) {
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering return fill_iovec_perror_and_send(message, 0, iovec);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering_public_ int sd_journal_stream_fd(const char *identifier, int priority, int level_prefix) {
0dd25fb9f005d8ab7ac4bc10a609d00569f8c56aLennart Poettering .un.sun_path = "/run/systemd/journal/stdout",
0dd25fb9f005d8ab7ac4bc10a609d00569f8c56aLennart Poettering fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering r = connect(fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering header = alloca(l + 1 + 1 + 2 + 2 + 2 + 2 + 2);
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering return (int) r;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering if ((size_t) r != l) {
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering_public_ int sd_journal_print_with_location(int priority, const char *file, const char *line, const char *func, const char *format, ...) {
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering r = sd_journal_printv_with_location(priority, file, line, func, format, ap);
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart 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) {
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering snprintf(p, sizeof(p), "PRIORITY=%i", priority & LOG_PRIMASK);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering /* func is initialized from __func__ which is not a macro, but
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers * a static const char[], hence cannot easily be prefixed with
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * CODE_FUNC=, hence let's do it manually here. */
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart 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, ...) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering i = fill_iovec_sprintf(format, ap, 3, &iov);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering for (j = 3; j < i; j++)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering_public_ int sd_journal_sendv_with_location(
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering niov = alloca(sizeof(struct iovec) * (n + 3));
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering memcpy(niov, iov, sizeof(struct iovec) * n);
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering_public_ int sd_journal_perror_with_location(