|
Packit |
8ea169 |
/*
|
|
Packit |
8ea169 |
* Copyright (C) 2014 ABRT team
|
|
Packit |
8ea169 |
* Copyright (C) 2014 RedHat Inc
|
|
Packit |
8ea169 |
*
|
|
Packit |
8ea169 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
8ea169 |
* it under the terms of the GNU General Public License as published by
|
|
Packit |
8ea169 |
* the Free Software Foundation; either version 2 of the License, or
|
|
Packit |
8ea169 |
* (at your option) any later version.
|
|
Packit |
8ea169 |
*
|
|
Packit |
8ea169 |
* This program is distributed in the hope that it will be useful,
|
|
Packit |
8ea169 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
8ea169 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
8ea169 |
* GNU General Public License for more details.
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
#include <unistd.h>
|
|
Packit |
8ea169 |
#include <signal.h>
|
|
Packit |
8ea169 |
#include <poll.h>
|
|
Packit |
8ea169 |
#include <stdlib.h>
|
|
Packit |
8ea169 |
#include <stdio.h>
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
#include "abrt-journal.h"
|
|
Packit |
8ea169 |
#include "libabrt.h"
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
#include <systemd/sd-journal.h>
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/*
|
|
Packit |
8ea169 |
* http://www.freedesktop.org/software/systemd/man/sd_journal_get_data.html
|
|
Packit |
8ea169 |
* sd_journal_set_data_threshold() : This threshold defaults to 64K by default.
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
#define JOURNALD_MAX_FIELD_SIZE (64*1024)
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
#define ABRT_JOURNAL_WATCH_STATE_FILE_MODE 0600
|
|
Packit |
8ea169 |
#define ABRT_JOURNAL_WATCH_STATE_FILE_MAX_SZ (4 * 1024)
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
struct abrt_journal
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
sd_journal *j;
|
|
Packit |
8ea169 |
};
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static int abrt_journal_new_flags(abrt_journal_t **journal, int flags)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
sd_journal *j;
|
|
Packit |
8ea169 |
const int r = sd_journal_open(&j, flags);
|
|
Packit |
8ea169 |
if (r < 0)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
log_notice("Failed to open journal: %s", strerror(-r));
|
|
Packit |
8ea169 |
return r;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
*journal = xzalloc(sizeof(**journal));
|
|
Packit |
8ea169 |
(*journal)->j = j;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return 0;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
int abrt_journal_new(abrt_journal_t **journal)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
return abrt_journal_new_flags(journal, SD_JOURNAL_LOCAL_ONLY);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
int abrt_journal_new_merged(abrt_journal_t **journal)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
return abrt_journal_new_flags(journal, 0);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static int abrt_journal_open_directory_flags(abrt_journal_t **journal, const char *directory, int flags)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
sd_journal *j;
|
|
Packit |
8ea169 |
const int r = sd_journal_open_directory(&j, directory, flags);
|
|
Packit |
8ea169 |
if (r < 0)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
log_notice("Failed to open journal directory ('%s'): %s", directory, strerror(-r));
|
|
Packit |
8ea169 |
return r;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
*journal = xzalloc(sizeof(**journal));
|
|
Packit |
8ea169 |
(*journal)->j = j;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return 0;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
int abrt_journal_open_directory(abrt_journal_t **journal, const char *directory)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
return abrt_journal_open_directory_flags(journal, directory, 0);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
void abrt_journal_free(abrt_journal_t *journal)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
sd_journal_close(journal->j);
|
|
Packit |
8ea169 |
journal->j = (void *)0xDEADBEAF;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
free(journal);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
int abrt_journal_set_journal_filter(abrt_journal_t *journal, GList *journal_filter_list)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
for (GList *l = journal_filter_list; l != NULL; l = l->next)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
const char *filter = l->data;
|
|
Packit |
8ea169 |
const int r = sd_journal_add_match(journal->j, filter, strlen(filter));
|
|
Packit |
8ea169 |
if (r < 0)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
log_notice("Failed to set journal filter '%s': %s", filter, strerror(-r));
|
|
Packit |
8ea169 |
return r;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
log_debug("Using journal match: '%s'", filter);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return 0;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
int abrt_journal_get_field(abrt_journal_t *journal, const char *field, const void **value, size_t *value_len)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
const int r = sd_journal_get_data(journal->j, field, value, value_len);
|
|
Packit |
8ea169 |
if (r < 0)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
log_notice("Failed to read '%s' field: %s", field, strerror(-r));
|
|
Packit |
8ea169 |
return r;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
const size_t pfx_len = strlen(field) + 1;
|
|
Packit |
8ea169 |
if (*value_len < pfx_len)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
error_msg("Invalid data format from journal: field data are not prefixed with field name");
|
|
Packit |
8ea169 |
return -EINVAL;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
*value = *value + pfx_len;
|
|
Packit |
8ea169 |
*value_len -= pfx_len;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return 0;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static int abrt_journal_get_integer(abrt_journal_t *journal, const char *field, long min, long max, long *value)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
char buffer[sizeof(int)*3 + 2];
|
|
Packit |
8ea169 |
const char *data;
|
|
Packit |
8ea169 |
size_t data_len;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
const int r = abrt_journal_get_field(journal, field, (const void **)&data, &data_len);
|
|
Packit |
8ea169 |
if (r < 0)
|
|
Packit |
8ea169 |
return r;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (data_len >= sizeof(buffer))
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
log_notice("Journald field '%s' is not a number: too long", field);
|
|
Packit |
8ea169 |
return -EINVAL;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
strncpy(buffer, data, data_len);
|
|
Packit |
8ea169 |
buffer[data_len] = '\0';
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
errno = 0;
|
|
Packit |
8ea169 |
char *e = NULL;
|
|
Packit |
8ea169 |
*value = strtol(buffer, &e, 10);
|
|
Packit |
8ea169 |
if (errno || buffer == e || *e != '\0' || *value < min || *value > max)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
log_notice("Journald field '%s' is not a number: '%s'", field, buffer);
|
|
Packit |
8ea169 |
return -EINVAL;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return 0;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
int abrt_journal_get_int_field(abrt_journal_t *journal, const char *field, int *value)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
long v;
|
|
Packit |
8ea169 |
int r = abrt_journal_get_integer(journal, field, INT_MIN, INT_MAX, &v);
|
|
Packit |
8ea169 |
if (r != 0)
|
|
Packit |
8ea169 |
return r;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
*value = (int)v;
|
|
Packit |
8ea169 |
return 0;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
int abrt_journal_get_unsigned_field(abrt_journal_t *journal, const char *field, unsigned *value)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
long v;
|
|
Packit |
8ea169 |
int r = abrt_journal_get_integer(journal, field, 0, UINT_MAX, &v);
|
|
Packit |
8ea169 |
if (r != 0)
|
|
Packit |
8ea169 |
return r;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
*value = (unsigned)v;
|
|
Packit |
8ea169 |
return 0;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
char *abrt_journal_get_string_field(abrt_journal_t *journal, const char *field, char *value)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
size_t data_len;
|
|
Packit |
8ea169 |
const char *data;
|
|
Packit |
8ea169 |
const int r = abrt_journal_get_field(journal, field, (const void **)&data, &data_len);
|
|
Packit |
8ea169 |
if (r < 0)
|
|
Packit |
8ea169 |
return NULL;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (value == NULL)
|
|
Packit |
8ea169 |
return xstrndup(data, data_len);
|
|
Packit |
8ea169 |
/*else*/
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
strncpy(value, data, data_len);
|
|
Packit |
8ea169 |
/* journal data are not NULL terminated strings, so terminate the string */
|
|
Packit |
8ea169 |
value[data_len] = '\0';
|
|
Packit |
8ea169 |
return value;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
char *abrt_journal_get_log_line(abrt_journal_t *journal)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
return abrt_journal_get_string_field(journal, "MESSAGE", NULL);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
char *abrt_journal_get_next_log_line(void *data)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
abrt_journal_t *journal = (abrt_journal_t *)data;
|
|
Packit |
8ea169 |
if (abrt_journal_next(journal) <= 0)
|
|
Packit |
8ea169 |
return NULL;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return abrt_journal_get_log_line(journal);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
int abrt_journal_get_cursor(abrt_journal_t *journal, char **cursor)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
const int r = sd_journal_get_cursor(journal->j, cursor);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (r < 0)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
log_notice("Could not get journal cursor: '%s'", strerror(-r));
|
|
Packit |
8ea169 |
return r;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return 0;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
int abrt_journal_set_cursor(abrt_journal_t *journal, const char *cursor)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
const int r = sd_journal_seek_cursor(journal->j, cursor);
|
|
Packit |
8ea169 |
if (r < 0)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
log_notice("Failed to seek journal to cursor '%s': %s\n", cursor, strerror(-r));
|
|
Packit |
8ea169 |
return r;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return 0;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
int abrt_journal_seek_tail(abrt_journal_t *journal)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
const int r = sd_journal_seek_tail(journal->j);
|
|
Packit |
8ea169 |
if (r < 0)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
log_notice("Failed to seek journal to the end: %s\n", strerror(-r));
|
|
Packit |
8ea169 |
return r;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* BUG: https://bugzilla.redhat.com/show_bug.cgi?id=979487 */
|
|
Packit |
8ea169 |
sd_journal_previous_skip(journal->j, 1);
|
|
Packit |
8ea169 |
return 0;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
int abrt_journal_next(abrt_journal_t *journal)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
const int r = sd_journal_next(journal->j);
|
|
Packit |
8ea169 |
if (r < 0)
|
|
Packit |
8ea169 |
log_notice("Failed to iterate to next entry: %s", strerror(-r));
|
|
Packit |
8ea169 |
return r;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
int abrt_journal_save_current_position(abrt_journal_t *journal, const char *file_name)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
char *crsr = NULL;
|
|
Packit |
8ea169 |
const int r = abrt_journal_get_cursor(journal, &crsr);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (r < 0)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
/* abrt_journal_set_cursor() prints error message in verbose mode */
|
|
Packit |
8ea169 |
error_msg(_("Cannot save journal watch's position"));
|
|
Packit |
8ea169 |
return r;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
int state_fd = open(file_name,
|
|
Packit |
8ea169 |
O_WRONLY | O_CREAT | O_TRUNC | O_NOFOLLOW,
|
|
Packit |
8ea169 |
ABRT_JOURNAL_WATCH_STATE_FILE_MODE);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (state_fd < 0)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
perror_msg(_("Cannot save journal watch's position: open('%s')"), file_name);
|
|
Packit |
8ea169 |
return -1;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
full_write_str(state_fd, crsr);
|
|
Packit |
8ea169 |
close(state_fd);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
free(crsr);
|
|
Packit |
8ea169 |
return 0;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
int abrt_journal_restore_position(abrt_journal_t *journal, const char *file_name)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
struct stat buf;
|
|
Packit |
8ea169 |
if (lstat(file_name, &buf) < 0)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (errno == ENOENT)
|
|
Packit |
8ea169 |
/* Only notice because this is expected */
|
|
Packit |
8ea169 |
log_notice(_("Not restoring journal watch's position: file '%s' does not exist"), file_name);
|
|
Packit |
8ea169 |
else
|
|
Packit |
8ea169 |
perror_msg(_("Cannot restore journal watch's position form file '%s'"), file_name);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return -errno;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (!(buf.st_mode & S_IFREG))
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
error_msg(_("Cannot restore journal watch's position: path '%s' is not regular file"), file_name);
|
|
Packit |
8ea169 |
return -EMEDIUMTYPE;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (buf.st_size > ABRT_JOURNAL_WATCH_STATE_FILE_MAX_SZ)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
error_msg(_("Cannot restore journal watch's position: file '%s' exceeds %dB size limit"),
|
|
Packit |
8ea169 |
file_name, ABRT_JOURNAL_WATCH_STATE_FILE_MAX_SZ);
|
|
Packit |
8ea169 |
return -EFBIG;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
int state_fd = open(file_name, O_RDONLY | O_NOFOLLOW);
|
|
Packit |
8ea169 |
if (state_fd < 0)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
perror_msg(_("Cannot restore journal watch's position: open('%s')"), file_name);
|
|
Packit |
8ea169 |
return -errno;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
char *crsr = xmalloc(buf.st_size + 1);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
const int sz = full_read(state_fd, crsr, buf.st_size);
|
|
Packit |
8ea169 |
if (sz != buf.st_size)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
error_msg(_("Cannot restore journal watch's position: cannot read entire file '%s'"), file_name);
|
|
Packit |
8ea169 |
close(state_fd);
|
|
Packit |
8ea169 |
return -errno;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
crsr[sz] = '\0';
|
|
Packit |
8ea169 |
close(state_fd);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
const int r = abrt_journal_set_cursor(journal, crsr);
|
|
Packit |
8ea169 |
if (r < 0)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
/* abrt_journal_set_cursor() prints error message in verbose mode */
|
|
Packit |
8ea169 |
error_msg(_("Failed to move the journal to a cursor from file '%s'"), file_name);
|
|
Packit |
8ea169 |
return r;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
free(crsr);
|
|
Packit |
8ea169 |
return 0;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/*
|
|
Packit |
8ea169 |
* ABRT systemd-journal wrapper end
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static volatile int s_loop_terminated;
|
|
Packit |
8ea169 |
void signal_loop_to_terminate(int signum)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
signum = signum;
|
|
Packit |
8ea169 |
s_loop_terminated = 1;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
enum abrt_journal_watch_state
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
ABRT_JOURNAL_WATCH_READY,
|
|
Packit |
8ea169 |
ABRT_JOURNAL_WATCH_STOPPED,
|
|
Packit |
8ea169 |
};
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
struct abrt_journal_watch
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
abrt_journal_t *j;
|
|
Packit |
8ea169 |
int state;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
abrt_journal_watch_callback callback;
|
|
Packit |
8ea169 |
void *callback_data;
|
|
Packit |
8ea169 |
};
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
int abrt_journal_watch_new(abrt_journal_watch_t **watch, abrt_journal_t *journal, abrt_journal_watch_callback callback, void *callback_data)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
assert(callback != NULL || !"ABRT watch needs valid callback ptr");
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
*watch = xzalloc(sizeof(**watch));
|
|
Packit |
8ea169 |
(*watch)->j = journal;
|
|
Packit |
8ea169 |
(*watch)->callback = callback;
|
|
Packit |
8ea169 |
(*watch)->callback_data = callback_data;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return 0;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
void abrt_journal_watch_free(abrt_journal_watch_t *watch)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
watch->j = (void *)0xDEADBEAF;
|
|
Packit |
8ea169 |
free(watch);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
abrt_journal_t *abrt_journal_watch_get_journal(abrt_journal_watch_t *watch)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
return watch->j;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
int abrt_journal_watch_run_sync(abrt_journal_watch_t *watch)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
sigset_t mask;
|
|
Packit |
8ea169 |
sigfillset(&mask);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* Exit gracefully: */
|
|
Packit |
8ea169 |
/* services usually exit on SIGTERM and SIGHUP */
|
|
Packit |
8ea169 |
sigdelset(&mask, SIGTERM);
|
|
Packit |
8ea169 |
signal(SIGTERM, signal_loop_to_terminate);
|
|
Packit |
8ea169 |
sigdelset(&mask, SIGHUP);
|
|
Packit |
8ea169 |
signal(SIGHUP, signal_loop_to_terminate);
|
|
Packit |
8ea169 |
/* Ctrl-C for easier debugging */
|
|
Packit |
8ea169 |
sigdelset(&mask, SIGINT);
|
|
Packit |
8ea169 |
signal(SIGINT, signal_loop_to_terminate);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* Die on kill $PID */
|
|
Packit |
8ea169 |
sigdelset(&mask, SIGKILL);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
struct pollfd pollfd;
|
|
Packit |
8ea169 |
pollfd.fd = sd_journal_get_fd(watch->j->j);
|
|
Packit |
8ea169 |
pollfd.events = sd_journal_get_events(watch->j->j);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
int r = 0;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
while (!s_loop_terminated && watch->state == ABRT_JOURNAL_WATCH_READY)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
r = sd_journal_next(watch->j->j);
|
|
Packit |
8ea169 |
if (r < 0)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
log_warning("Failed to iterate to next entry: %s", strerror(-r));
|
|
Packit |
8ea169 |
break;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
else if (r == 0)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
ppoll(&pollfd, 1, NULL, &mask);
|
|
Packit |
8ea169 |
r = sd_journal_process(watch->j->j);
|
|
Packit |
8ea169 |
if (r < 0)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
log_warning("Failed to get journal changes: %s\n", strerror(-r));
|
|
Packit |
8ea169 |
break;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
continue;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
watch->callback(watch, watch->callback_data);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return r;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
void abrt_journal_watch_stop(abrt_journal_watch_t *watch)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
watch->state = ABRT_JOURNAL_WATCH_STOPPED;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/*
|
|
Packit |
8ea169 |
* ABRT systemd-journal watch - end
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
void abrt_journal_watch_notify_strings(abrt_journal_watch_t *watch, void *data)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
struct abrt_journal_watch_notify_strings *conf = (struct abrt_journal_watch_notify_strings *)data;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
char message[JOURNALD_MAX_FIELD_SIZE + 1];
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (abrt_journal_get_string_field(abrt_journal_watch_get_journal(watch), "MESSAGE", (char *)message) == NULL)
|
|
Packit |
8ea169 |
error_msg_and_die("Cannot read journal data.");
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
GList *cur = conf->strings;
|
|
Packit |
8ea169 |
for (; cur; cur = g_list_next(cur))
|
|
Packit |
8ea169 |
if (strstr(message, cur->data) != NULL)
|
|
Packit |
8ea169 |
break;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
GList *blacklist_cur = conf->blacklisted_strings;
|
|
Packit |
8ea169 |
if (cur)
|
|
Packit |
8ea169 |
for (; blacklist_cur; blacklist_cur = g_list_next(blacklist_cur))
|
|
Packit |
8ea169 |
if (strstr(message, blacklist_cur->data) != NULL)
|
|
Packit |
8ea169 |
break;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (cur && !blacklist_cur)
|
|
Packit |
8ea169 |
conf->decorated_cb(watch, conf->decorated_cb_data);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/*
|
|
Packit |
8ea169 |
* ABRT systemd-journal strings notifier - end
|
|
Packit |
8ea169 |
*/
|