Beispiel #1
0
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?");
}
Beispiel #3
0
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 */
}