diff options
Diffstat (limited to 'journal-notify.c')
-rw-r--r-- | journal-notify.c | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/journal-notify.c b/journal-notify.c new file mode 100644 index 0000000..7e78232 --- /dev/null +++ b/journal-notify.c @@ -0,0 +1,175 @@ +/* + * (C) 2014 by Christian Hesse <mail@eworm.de> + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <regex.h> + +#include <systemd/sd-journal.h> + +#include <libnotify/notify.h> + +const char * program = NULL; + +#define OPTSTRING "ehi:m:nr:" +#define DEFAULTICON "dialog-information" + +void notify(const char * summary, const char * body, const char * icon) { + NotifyNotification * notification = notify_notification_new(summary, body, icon); + notify_notification_show(notification, NULL); + g_object_unref(G_OBJECT(notification)); +} + +int main(int argc, char **argv) { + int i, rc = EXIT_FAILURE; + + uint8_t have_regex = 0; + regex_t regex; + int regex_flags = REG_NOSUB; + + sd_journal * journal; + const void * data; + size_t length; + + char * summary, * message; + const char *summarystr, * messagestr, * icon = DEFAULTICON; + + program = argv[0]; + + /* get command line options - part I + * just get -h (help), -e and -n (regex options) here */ + while ((i = getopt(argc, argv, OPTSTRING)) != -1) { + switch (i) { + case 'e': + regex_flags |= REG_EXTENDED; + break; + case 'h': + fprintf(stderr, "usage: %s [-e] [-h] [-m MATCH] [-n] [-r REGEX]\n", program); + return EXIT_SUCCESS; + case 'n': + regex_flags |= REG_ICASE; + break; + } + } + + /* reinitialize getopt() by resetting optind to 0 */ + optind = 0; + + /* open journal */ + if ((rc = sd_journal_open(&journal, SD_JOURNAL_LOCAL_ONLY + SD_JOURNAL_SYSTEM)) < 0) { + fprintf(stderr, "Failed to open journal: %s\n", strerror(-rc)); + goto out10; + } + + /* get command line options - part II*/ + while ((i = getopt(argc, argv, OPTSTRING)) != -1) { + switch (i) { + case 'i': + icon = optarg; + break; + case 'm': + if ((rc = sd_journal_add_match(journal, optarg, 0)) < 0) { + fprintf(stderr, "Failed to add match '%s': %s\n", optarg, strerror(-rc)); + goto out20; + } + + break; + case 'r': + if (have_regex > 0) { + fprintf(stderr, "Only one regex allowed!\n"); + rc = EXIT_FAILURE; + goto out20; + } + + if ((rc = regcomp(®ex, optarg, regex_flags)) != 0) { + fprintf(stderr, "Could not compile regex\n"); + goto out20; + } + have_regex++; + + break; + } + } + + /* seek to the end of the journal */ + if ((rc = sd_journal_seek_tail(journal)) < 0) { + fprintf(stderr, "Failed to seek to the tail: %s\n", strerror(-rc)); + goto out30; + } + + /* we are behind the last entry, so use previous one */ + if ((rc = sd_journal_previous(journal)) < 0) { + fprintf(stderr, "Failed to iterate to previous entry: %s\n", strerror(-rc)); + goto out30; + } + + if (notify_init(program) == FALSE) { + fprintf(stderr, "Failed to initialize notify.\n"); + rc = EXIT_FAILURE; + goto out30; + } + + while (1) { + if ((rc = sd_journal_next(journal)) < 0) { + fprintf(stderr, "Failed to iterate to next entry: %s\n", strerror(-rc)); + goto out40; + } else if (rc == 0) { + if ((rc = sd_journal_wait(journal, (uint64_t) -1)) < 0) { + fprintf(stderr, "Failed to wait for changes: %s\n", strerror(-rc)); + goto out40; + } + continue; + } + + /* get MESSAGE field */ + if ((rc = sd_journal_get_data(journal, "MESSAGE", &data, &length)) < 0) { + fprintf(stderr, "Failed to read message field: %s\n", strerror(-rc)); + continue; + } + + message = strndup(data, length); + messagestr = message + 8; + + /* get SYSLOG_IDENTIFIER field */ + if ((rc = sd_journal_get_data(journal, "SYSLOG_IDENTIFIER", &data, &length)) < 0) { + fprintf(stderr, "Failed to read syslog identifier field: %s\n", strerror(-rc)); + continue; + } + summary = strndup(data, length); + summarystr = summary + 18; + + /* show notification */ + if (have_regex > 0) { + if (regexec(®ex, messagestr, 0, NULL, 0) == 0) { + notify(summarystr, messagestr, icon); + } + } else { + notify(summarystr, messagestr, icon); + } + + free(summary); + free(message); + } + + rc = EXIT_SUCCESS; + +out40: + notify_uninit(); + +out30: + if (have_regex > 0) + regfree(®ex); + +out20: + sd_journal_close(journal); + +out10: + return rc; +} + +// vim: set syntax=c: |