From 8768b2bfed1163df04d68c2c26b610e7f7f229de Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 2 Jul 2014 21:47:34 +0200 Subject: initial commit --- .gitignore | 8 ++ Makefile | 40 ++++++++ README.md | 70 ++++++++++++++ examples/journal-notify-dhcpd.desktop | 9 ++ examples/journal-notify-sshd.desktop | 9 ++ journal-notify.c | 175 ++++++++++++++++++++++++++++++++++ screenshot.png | Bin 0 -> 6817 bytes 7 files changed, 311 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 README.md create mode 100755 examples/journal-notify-dhcpd.desktop create mode 100755 examples/journal-notify-sshd.desktop create mode 100644 journal-notify.c create mode 100644 screenshot.png diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..efc341b --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +*~ +*.o +config.h +journal-notify +README.html +version.h +journal-notify-*.tar.xz +journal-notify-*.tar.xz.asc diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..974fc39 --- /dev/null +++ b/Makefile @@ -0,0 +1,40 @@ +# journal-notify - Notify about journal log entries + +CC := gcc +MD := markdown +INSTALL := install +CP := cp +RM := rm +CFLAGS += -O2 -Wall -Werror +CFLAGS += $(shell pkg-config --cflags --libs libsystemd) +CFLAGS += $(shell pkg-config --cflags --libs libnotify) +# this is just a fallback in case you do not use git but downloaded +# a release tarball... +VERSION := 0.0.1 + +all: journal-notify README.html + +journal-notify: journal-notify.c + $(CC) $(CFLAGS) -o journal-notify journal-notify.c + +README.html: README.md + $(MD) README.md > README.html + +install: install-bin install-doc + +install-bin: journal-notify + $(INSTALL) -D -m0755 journal-notify $(DESTDIR)/usr/bin/journal-notify + $(INSTALL) -D -m0755 examples/journal-notify-dhcpd.desktop $(DESTDIR)/usr/share/journal-notify/examples/journal-notify-dhcpd.desktop + $(INSTALL) -D -m0755 examples/journal-notify-sshd.desktop $(DESTDIR)/usr/share/journal-notify/examples/journal-notify-sshd.desktop + +install-doc: README.html + $(INSTALL) -D -m0644 README.md $(DESTDIR)/usr/share/doc/journal-notify/README.md + $(INSTALL) -D -m0644 README.html $(DESTDIR)/usr/share/doc/journal-notify/README.html + $(INSTALL) -D -m0644 screenshot.png $(DESTDIR)/usr/share/doc/journal-notify/screenshot.png + +clean: + rm -f *.o *~ README.html journal-notify + +release: + git archive --format=tar.xz --prefix=journal-notify$(VERSION)/ $(VERSION) > journal-notify-$(VERSION).tar.xz + gpg -ab journal-notify-$(VERSION).tar.xz diff --git a/README.md b/README.md new file mode 100644 index 0000000..c28a27d --- /dev/null +++ b/README.md @@ -0,0 +1,70 @@ +journal-notify +============== + +**Notify about journal log entries** + +This runs in background and produces notifications whenever systemd journal +logs an entry. Notifications look like this: + +![Notification](screenshot.png) + +Requirements +------------ + +To compile and run `journal-notify` you need: + +* [libnotify](http://library.gnome.org/devel/notification-spec/) +* [libsystemd](http://www.freedesktop.org/wiki/Software/systemd/) +* [markdown](http://daringfireball.net/projects/markdown/) (HTML + documentation) +* `gnome-icon-theme` (or whatever includes the icons you want to use) + +To use `journal-notify` you probably want `systemd-journald`. + +Some systems may require additional development packages for the libraries. +Look for `libnotify-devel`, `libsystemd-devel` or similar. + +Build and install +----------------- + +Building and installing is very easy. Just run: + +> make + +followed by: + +> make install + +This will place an executable at `/usr/bin/journal-notify`, +documentation can be found in `/usr/share/doc/journal-notify/`. + +Usage +----- + +To use `journal-notify` you need access to the journal log files. Make sure +you get the expexted log entries by running `journalctl`. Possibly you have +to add yourself to group `systemd-journal` or similar. + +Just running `journal-notify` without parameter will show *all* log entries. +Be warned: This can flood your disktop with notifications. + +`journal-notify` accepts some options: + +* *-e*: use extended regular expressions +* *-h*: show help +* *-i ICON*: icon to use +* *-m MATCH*: This can be specified more than once. The option accepts matches + to systemd journal fields. (see `man 7 systemd.journal-fields`) +* *-n*: no case sensitive regular expressions +* *-r REGEX*: This add a regular expression match for the message field. + +The screenshot shown above resulted from this command: + +> journal-notify -m SYSLOG_IDENTIFIER=sshd -e -r "^(error:.\*|Accepted.\*)" +-i security-high + +Additionally example desktop files are installed to +`/usr/share/journal-notify/examples`. You should copy them to +`~/.config/autostart/` to enable autostart or create your own desktop files +there. + diff --git a/examples/journal-notify-dhcpd.desktop b/examples/journal-notify-dhcpd.desktop new file mode 100755 index 0000000..092d6c4 --- /dev/null +++ b/examples/journal-notify-dhcpd.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Name=journal-notify-dhcpd +GenericName=Journal-Notify DHCPD +Comment=Notify about DHCP activities +Exec=journal-notify -m SYSLOG_IDENTIFIER=dhcpd -r "^DHCPN?ACK" -i network-wired +StartupNotify=false +Terminal=false +Type=Application +Categories= diff --git a/examples/journal-notify-sshd.desktop b/examples/journal-notify-sshd.desktop new file mode 100755 index 0000000..688da64 --- /dev/null +++ b/examples/journal-notify-sshd.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Name=journal-notify-sshd +GenericName=Journal-Notify SSHD +Comment=Notify about SSH activities +Exec=journal-notify -m SYSLOG_IDENTIFIER=sshd -e -r "^(error:.*|Accepted.*)" -i security-high +StartupNotify=false +Terminal=false +Type=Application +Categories= 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 + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + */ + +#include +#include +#include +#include + +#include + +#include + +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: diff --git a/screenshot.png b/screenshot.png new file mode 100644 index 0000000..7962f70 Binary files /dev/null and b/screenshot.png differ -- cgit v1.2.3-54-g00ecf