#include <stddef.h>
#include <unistd.h>
#include <fcntl.h>
+#include <printf.h>
#define SD_JOURNAL_SUPPRESS_LOCATION
#define SNDBUF_SIZE (8*1024*1024)
+#define ALLOCA_CODE_FUNC(f, func) \
+ do { \
+ size_t _fl; \
+ const char *_func = (func); \
+ char **_f = &(f); \
+ _fl = strlen(_func) + 1; \
+ *_f = alloca(_fl + 10); \
+ memcpy(*_f, "CODE_FUNC=", 10); \
+ memcpy(*_f + 10, _func, _fl); \
+ } while(false)
+
/* We open a single fd, and we'll share it with the current process,
* all its threads, and all its subprocesses. This means we need to
* initialize it atomically, and need to operate on it atomically
}
_public_ int sd_journal_printv(int priority, const char *format, va_list ap) {
- char buffer[8 + LINE_MAX], p[11];
- struct iovec iov[2];
+
+ /* FIXME: Instead of limiting things to LINE_MAX we could do a
+ C99 variable-length array on the stack here in a loop. */
+
+ char buffer[8 + LINE_MAX], p[11]; struct iovec iov[2];
if (priority < 0 || priority > 7)
return -EINVAL;
while (format) {
struct iovec *c;
char *buffer;
+ va_list aq;
if (i >= n) {
n = MAX(i*2, 4);
iov = c;
}
- if (vasprintf(&buffer, format, ap) < 0) {
+ va_copy(aq, ap);
+ if (vasprintf(&buffer, format, aq) < 0) {
+ va_end(aq);
r = -ENOMEM;
goto fail;
}
+ va_end(aq);
+
+ VA_FORMAT_ADVANCE(format, ap);
IOVEC_SET_STRING(iov[i++], buffer);
* be a tmpfs, and one that is available from early boot on
* and where unprivileged users can create files. */
char path[] = "/dev/shm/journal.XXXXXX";
+ bool have_syslog_identifier = false;
if (_unlikely_(!iov))
return -EINVAL;
saved_errno = errno;
- w = alloca(sizeof(struct iovec) * n * 5);
+ w = alloca(sizeof(struct iovec) * n * 5 + 3);
l = alloca(sizeof(uint64_t) * n);
for (i = 0; i < n; i++) {
goto finish;
}
+ have_syslog_identifier = have_syslog_identifier ||
+ (c == (char *) iov[i].iov_base + 17 &&
+ memcmp(iov[i].iov_base, "SYSLOG_IDENTIFIER", 17) == 0);
+
nl = memchr(iov[i].iov_base, '\n', iov[i].iov_len);
if (nl) {
if (_unlikely_(nl < c)) {
IOVEC_SET_STRING(w[j++], "\n");
}
+ if (!have_syslog_identifier &&
+ string_is_safe(program_invocation_short_name)) {
+
+ /* Implicitly add program_invocation_short_name, if it
+ * is not set explicitly. We only do this for
+ * program_invocation_short_name, and nothing else
+ * since everything else is much nicer to retrieve
+ * from the outside. */
+
+ IOVEC_SET_STRING(w[j++], "SYSLOG_IDENTIFIER=");
+ IOVEC_SET_STRING(w[j++], program_invocation_short_name);
+ IOVEC_SET_STRING(w[j++], "\n");
+ }
+
fd = journal_fd();
if (_unlikely_(fd < 0)) {
r = fd;
return r;
}
+static int fill_iovec_perror_and_send(const char *message, int skip, struct iovec iov[]) {
+ size_t n, k, r;
+ int saved_errno;
+
+ saved_errno = errno;
+
+ k = isempty(message) ? 0 : strlen(message) + 2;
+ n = 8 + k + 256 + 1;
+
+ for (;;) {
+ char buffer[n];
+ char* j;
+
+ errno = 0;
+ j = strerror_r(saved_errno, buffer + 8 + k, n - 8 - k);
+ if (errno == 0) {
+ char error[6 + 10 + 1]; /* for a 32bit value */
+
+ if (j != buffer + 8 + k)
+ memmove(buffer + 8 + k, j, strlen(j)+1);
+
+ memcpy(buffer, "MESSAGE=", 8);
+
+ if (k > 0) {
+ memcpy(buffer + 8, message, k - 2);
+ memcpy(buffer + 8 + k - 2, ": ", 2);
+ }
+
+ snprintf(error, sizeof(error), "ERRNO=%u", saved_errno);
+ char_array_0(error);
+
+ IOVEC_SET_STRING(iov[skip+0], "PRIORITY=3");
+ IOVEC_SET_STRING(iov[skip+1], buffer);
+ IOVEC_SET_STRING(iov[skip+2], error);
+
+ r = sd_journal_sendv(iov, skip + 3);
+
+ errno = saved_errno;
+ return r;
+ }
+
+ if (errno != ERANGE) {
+ r = -errno;
+ errno = saved_errno;
+ return r;
+ }
+
+ n *= 2;
+ }
+}
+
+_public_ int sd_journal_perror(const char *message) {
+ struct iovec iovec[3];
+
+ return fill_iovec_perror_and_send(message, 0, iovec);
+}
+
_public_ int sd_journal_stream_fd(const char *identifier, int priority, int level_prefix) {
union sockaddr_union sa;
int fd;
identifier = "";
l = strlen(identifier);
- header = alloca(l + 1 + 2 + 2 + 2 + 2 + 2);
+ header = alloca(l + 1 + 1 + 2 + 2 + 2 + 2 + 2);
memcpy(header, identifier, l);
header[l++] = '\n';
+ header[l++] = '\n'; /* unit id */
header[l++] = '0' + priority;
header[l++] = '\n';
header[l++] = '0' + !!level_prefix;
char buffer[8 + LINE_MAX], p[11];
struct iovec iov[5];
char *f;
- size_t fl;
if (priority < 0 || priority > 7)
return -EINVAL;
/* func is initialized from __func__ which is not a macro, but
* a static const char[], hence cannot easily be prefixed with
* CODE_FUNC=, hence let's do it manually here. */
- fl = strlen(func);
- f = alloca(fl + 10);
- memcpy(f, "CODE_FUNC=", 10);
- memcpy(f + 10, func, fl + 1);
+ ALLOCA_CODE_FUNC(f, func);
zero(iov);
IOVEC_SET_STRING(iov[0], buffer);
va_list ap;
struct iovec *iov = NULL;
char *f;
- size_t fl;
va_start(ap, format);
i = fill_iovec_sprintf(format, ap, 3, &iov);
goto finish;
}
- fl = strlen(func);
- f = alloca(fl + 10);
- memcpy(f, "CODE_FUNC=", 10);
- memcpy(f + 10, func, fl + 1);
+ ALLOCA_CODE_FUNC(f, func);
IOVEC_SET_STRING(iov[0], file);
IOVEC_SET_STRING(iov[1], line);
return r;
}
-_public_ int sd_journal_sendv_with_location(const char *file, const char *line, const char *func, const struct iovec *iov, int n) {
+_public_ int sd_journal_sendv_with_location(
+ const char *file, const char *line,
+ const char *func,
+ const struct iovec *iov, int n) {
+
struct iovec *niov;
char *f;
- size_t fl;
if (_unlikely_(!iov))
return -EINVAL;
niov = alloca(sizeof(struct iovec) * (n + 3));
memcpy(niov, iov, sizeof(struct iovec) * n);
- fl = strlen(func);
- f = alloca(fl + 10);
- memcpy(f, "CODE_FUNC=", 10);
- memcpy(f + 10, func, fl + 1);
+ ALLOCA_CODE_FUNC(f, func);
IOVEC_SET_STRING(niov[n++], file);
IOVEC_SET_STRING(niov[n++], line);
return sd_journal_sendv(niov, n);
}
+
+_public_ int sd_journal_perror_with_location(
+ const char *file, const char *line,
+ const char *func,
+ const char *message) {
+
+ struct iovec iov[6];
+ char *f;
+
+ ALLOCA_CODE_FUNC(f, func);
+
+ IOVEC_SET_STRING(iov[0], file);
+ IOVEC_SET_STRING(iov[1], line);
+ IOVEC_SET_STRING(iov[2], f);
+
+ return fill_iovec_perror_and_send(message, 3, iov);
+}