static int journal_enumerate_data (lua_State *L) { sd_journal *j = check_journal(L, 1); const void *data; size_t length; int err = sd_journal_enumerate_data(j, &data, &length); if (err < 0) return handle_error(L, -err); else if (err == 0) { lua_pushboolean(L, 0); lua_pushnil(L); } else { lua_pushboolean(L, 1); lua_pushlstring(L, data, length); } return 2; }
/** * Write up to size bytes to buf. Return negative on error, and number of * bytes written otherwise. The last case is a kind of an error too. */ static ssize_t write_entry(char *buf, size_t size, Uploader *u) { int r; size_t pos = 0; assert(size <= SSIZE_MAX); while (true) { switch(u->entry_state) { case ENTRY_CURSOR: { free(u->current_cursor); u->current_cursor = NULL; r = sd_journal_get_cursor(u->journal, &u->current_cursor); if (r < 0) return log_error_errno(r, "Failed to get cursor: %m"); r = snprintf(buf + pos, size - pos, "__CURSOR=%s\n", u->current_cursor); if (pos + r > size) /* not enough space */ return pos; u->entry_state ++; if (pos + r == size) { /* exactly one character short, but we don't need it */ buf[size - 1] = '\n'; return size; } pos += r; } /* fall through */ case ENTRY_REALTIME: { usec_t realtime; r = sd_journal_get_realtime_usec(u->journal, &realtime); if (r < 0) return log_error_errno(r, "Failed to get realtime timestamp: %m"); r = snprintf(buf + pos, size - pos, "__REALTIME_TIMESTAMP="USEC_FMT"\n", realtime); if (r + pos > size) /* not enough space */ return pos; u->entry_state ++; if (r + pos == size) { /* exactly one character short, but we don't need it */ buf[size - 1] = '\n'; return size; } pos += r; } /* fall through */ case ENTRY_MONOTONIC: { usec_t monotonic; sd_id128_t boot_id; r = sd_journal_get_monotonic_usec(u->journal, &monotonic, &boot_id); if (r < 0) return log_error_errno(r, "Failed to get monotonic timestamp: %m"); r = snprintf(buf + pos, size - pos, "__MONOTONIC_TIMESTAMP="USEC_FMT"\n", monotonic); if (r + pos > size) /* not enough space */ return pos; u->entry_state ++; if (r + pos == size) { /* exactly one character short, but we don't need it */ buf[size - 1] = '\n'; return size; } pos += r; } /* fall through */ case ENTRY_BOOT_ID: { sd_id128_t boot_id; char sid[33]; r = sd_journal_get_monotonic_usec(u->journal, NULL, &boot_id); if (r < 0) return log_error_errno(r, "Failed to get monotonic timestamp: %m"); r = snprintf(buf + pos, size - pos, "_BOOT_ID=%s\n", sd_id128_to_string(boot_id, sid)); if (r + pos > size) /* not enough space */ return pos; u->entry_state ++; if (r + pos == size) { /* exactly one character short, but we don't need it */ buf[size - 1] = '\n'; return size; } pos += r; } /* fall through */ case ENTRY_NEW_FIELD: { u->field_pos = 0; r = sd_journal_enumerate_data(u->journal, &u->field_data, &u->field_length); if (r < 0) return log_error_errno(r, "Failed to move to next field in entry: %m"); else if (r == 0) { u->entry_state = ENTRY_OUTRO; continue; } if (!utf8_is_printable_newline(u->field_data, u->field_length, false)) { u->entry_state = ENTRY_BINARY_FIELD_START; continue; } u->entry_state ++; } /* fall through */ case ENTRY_TEXT_FIELD: case ENTRY_BINARY_FIELD: { bool done; size_t tocopy; done = size - pos > u->field_length - u->field_pos; if (done) tocopy = u->field_length - u->field_pos; else tocopy = size - pos; memcpy(buf + pos, (char*) u->field_data + u->field_pos, tocopy); if (done) { buf[pos + tocopy] = '\n'; pos += tocopy + 1; u->entry_state = ENTRY_NEW_FIELD; continue; } else { u->field_pos += tocopy; return size; } } case ENTRY_BINARY_FIELD_START: { const char *c; size_t len; c = memchr(u->field_data, '=', u->field_length); if (!c || c == u->field_data) { log_error("Invalid field."); return -EINVAL; } len = c - (const char*)u->field_data; /* need space for label + '\n' */ if (size - pos < len + 1) return pos; memcpy(buf + pos, u->field_data, len); buf[pos + len] = '\n'; pos += len + 1; u->field_pos = len + 1; u->entry_state ++; } /* fall through */ case ENTRY_BINARY_FIELD_SIZE: { uint64_t le64; /* need space for uint64_t */ if (size - pos < 8) return pos; le64 = htole64(u->field_length - u->field_pos); memcpy(buf + pos, &le64, 8); pos += 8; u->entry_state ++; continue; } case ENTRY_OUTRO: /* need space for '\n' */ if (size - pos < 1) return pos; buf[pos++] = '\n'; u->entry_state ++; u->entries_sent ++; return pos; default: assert_not_reached("WTF?"); } } assert_not_reached("WTF?"); }
int systemd_journal_decoder(int eventarray, void *buffer, size_t size, struct timeval *timestamp, void *data) { int sts; pmAtomValue atom; enum journald_field_encoding jfe = * (enum journald_field_encoding *) data; sts = pmdaEventAddRecord(eventarray, timestamp, PM_EVENT_FLAG_POINT); if (sts < 0) return sts; /* Go to the cursor point enqueued for this client. The buffer is already \0-terminated. */ sts = sd_journal_seek_cursor(journald_context_seeky, (char*) buffer); if (sts < 0) { /* But see RHBZ #876654. */ return /* sts */ 0; } sts = sd_journal_next(journald_context_seeky); if (sts < 0) return sts; if (sts == 0) return -ENODATA; /* event got lost between cursor-recording and now */ /* Add the _CURSOR implicit journal field. */ atom.cp = buffer; sts = pmdaEventAddParam(eventarray, METRICTAB_JOURNAL_CURSOR_PMID, PM_TYPE_STRING, &atom); /* Add all the explicit journal fields. */ while (1) { const void *data; size_t data_len; if (sts < 0) break; sts = sd_journal_enumerate_data(journald_context_seeky, &data, &data_len); if (sts <= 0) break; /* Infer string upon absence of embedded \0's. */ if (jfe == JFE_STRING_BLOB_AUTO && (memchr (data, '\0', data_len) == NULL)) { /* Unfortunately, data may not be \0-terminated, so we can't simply pass it to atom.cp. We need to copy the bad boy first. */ atom.cp = strndup(data, data_len); if (atom.cp == NULL) sts = -ENOMEM; else { sts = pmdaEventAddParam(eventarray, METRICTAB_JOURNAL_STRING_PMID, PM_TYPE_STRING, &atom); free (atom.cp); } /* NB: we assume libpcp_pmda will not free() the field. */ } else { pmValueBlock *aggr = (pmValueBlock *)malloc(PM_VAL_HDR_SIZE + data_len); if (aggr == NULL) sts = -ENOMEM; else { aggr->vtype = PM_TYPE_AGGREGATE; if (PM_VAL_HDR_SIZE + data_len >= 1<<24) aggr->vlen = (1U<<24) - 1; /* vlen is a :24 bit field */ else aggr->vlen = PM_VAL_HDR_SIZE + data_len; memcpy (aggr->vbuf, data, data_len); atom.vbp = aggr; sts = pmdaEventAddParam(eventarray, METRICTAB_JOURNAL_BLOB_PMID, PM_TYPE_AGGREGATE, &atom); /* NB: we assume libpcp_pmda will free() aggr. */ } } } return sts < 0 ? sts : 1; /* added one event array */ }