From d187bd3b4805dcb3f9e1d6143ac1cd0531009868 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 19 May 2015 15:57:22 +0200 Subject: add support for executing external commands close #1 --- Makefile | 2 ++ README.md | 12 ++++++- execute/echo.sh | 28 +++++++++++++++ execute/mail.sh | 26 ++++++++++++++ journal-notify.c | 105 +++++++++++++++++++++++++++++++++++++++++++------------ journal-notify.h | 11 ++++++ 6 files changed, 160 insertions(+), 24 deletions(-) create mode 100755 execute/echo.sh create mode 100755 execute/mail.sh diff --git a/Makefile b/Makefile index b3b34ef..9230401 100644 --- a/Makefile +++ b/Makefile @@ -32,6 +32,8 @@ install-bin: journal-notify $(INSTALL) -D -m0755 examples/journal-notify-crit-alert-emerg.desktop $(DESTDIR)/usr/share/journal-notify/examples/journal-notify-crit-alert-emerg.desktop $(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) -D -m0755 execute/echo.sh $(DESTDIR)/usr/share/journal-notify/execute/echo.sh + $(INSTALL) -D -m0755 execute/mail.sh $(DESTDIR)/usr/share/journal-notify/execute/mail.sh install-doc: README.html $(INSTALL) -D -m0644 README.md $(DESTDIR)/usr/share/doc/journal-notify/README.md diff --git a/README.md b/README.md index 3c4f4d1..52b97a7 100644 --- a/README.md +++ b/README.md @@ -61,16 +61,26 @@ Be warned: This can flood your disktop with notifications. * *-r REGEX*: This add a regular expression match for the message field. * *-t SECONDS*: seconds to show the notification, 0 is forever * *-v*: verbose output, can be specified multiple times +* *-x EXECUTABLE*: execute EXECUTABLE +* *-X EXECUTABLE*: execute EXECUTABLE, do not show notification The screenshot shown above resulted from this command: > journal-notify -m SYSLOG_IDENTIFIER=sshd -e -r "^(error:|Accepted)" -i security-high +The command specified by `-x` is called with three options. Make sure +your executable understands these options: + +* *-i*: syslog identifier +* *-p*: priority +* *-m*: message + 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. +there. Example execute scripts are installed to +`/usr/share/journal-notify/execute/`. ### Upstream diff --git a/execute/echo.sh b/execute/echo.sh new file mode 100755 index 0000000..15ca215 --- /dev/null +++ b/execute/echo.sh @@ -0,0 +1,28 @@ +#!/bin/sh +# +# (C) 2015 by Christian Hesse +# +# This software may be used and distributed according to the terms +# of the GNU General Public License, incorporated herein by reference. + +while getopts "i:p:m:" opt; do + case ${opt} in + i) + IDENTIFIER="${OPTARG}" + ;; + p) + PRIORITY="${OPTARG}" + ;; + m) + MESSAGE="${OPTARG}" + ;; + esac +done + +echo "IDENTIFIER: ${IDENTIFIER}" +echo "PRIORITY: ${PRIORITY}" +echo "MESSAGE: ${MESSAGE}" + +exit 0 + +# vim: set syntax=sh: diff --git a/execute/mail.sh b/execute/mail.sh new file mode 100755 index 0000000..2d757db --- /dev/null +++ b/execute/mail.sh @@ -0,0 +1,26 @@ +#!/bin/sh +# +# (C) 2015 by Christian Hesse +# +# This software may be used and distributed according to the terms +# of the GNU General Public License, incorporated herein by reference. + +while getopts "i:p:m:" opt; do + case ${opt} in + i) + IDENTIFIER="${OPTARG}" + ;; + p) + PRIORITY="${OPTARG}" + ;; + m) + MESSAGE="${OPTARG}" + ;; + esac +done + +mail -s "[${PRIORITY}] ${IDENTIFIER}" mail@example.com <<< "${MESSAGE}" + +exit 0 + +# vim: set syntax=sh: diff --git a/journal-notify.c b/journal-notify.c index 73af0f5..8f6e0b1 100644 --- a/journal-notify.c +++ b/journal-notify.c @@ -9,7 +9,7 @@ const char * program = NULL; -const static char optstring[] = "aehi:m:nor:t:v"; +const static char optstring[] = "aehi:m:nor:t:vx:X:"; const static struct option options_long[] = { /* name has_arg flag val */ { "and", no_argument, NULL, 'a' }, @@ -22,6 +22,8 @@ const static struct option options_long[] = { { "regex", required_argument, NULL, 'r' }, { "timeout", required_argument, NULL, 't' }, { "verbose", no_argument, NULL, 'v' }, + { "execute", required_argument, NULL, 'x' }, + { "execute-only", required_argument, NULL, 'X' }, { 0, 0, 0, 0 } }; @@ -102,9 +104,15 @@ int main(int argc, char **argv) { char * identifier, * message; uint8_t priority; - const char * icon = DEFAULTICON; + const char * priorityname, + * icon = DEFAULTICON; int timeout = -1; + uint8_t executeonly = 0; + char * execute = NULL; + pid_t child_pid, wpid; + int status; + program = argv[0]; /* get command line options - part I @@ -209,14 +217,24 @@ int main(int argc, char **argv) { if (verbose > 1) printf("Notifications will be displayed for %d seconds.\n", timeout); + break; + case 'X': + executeonly = 1; + case 'x': + execute = optarg; + if (verbose > 1) + printf("Command used for execution: %s\n", execute); + break; } } - if (notify_init(program) == FALSE) { - fprintf(stderr, "Failed to initialize notify.\n"); - rc = EXIT_FAILURE; - goto out30; + if (executeonly == 0) { + if (notify_init(program) == FALSE) { + fprintf(stderr, "Failed to initialize notify.\n"); + rc = EXIT_FAILURE; + goto out30; + } } while (1) { @@ -266,29 +284,69 @@ int main(int argc, char **argv) { continue; } priority = atoi(data + 9); + priorityname = priorities[priority]; if (verbose > 2) printf("Received message from journal: %s\n", message); - /* show notification */ if (have_regex == 0 || regexec(®ex, message, 0, NULL, 0) == 0) { - for (i = 0; i < 3; i++) { - if (verbose > 0) - printf("Showing notification: %s: %s\n", identifier, message); - - if ((rc = notify(identifier, message, priority, icon, timeout)) == 0) - break; - - fprintf(stderr, "Failed to show notification, reinitializing libnotify.\n"); - notify_uninit(); - usleep(500 * 1000); - if (notify_init(program) == FALSE) { - fprintf(stderr, "Failed to initialize notify.\n"); - rc = EXIT_FAILURE; + /* show notification */ + if (executeonly == 0) { + for (i = 0; i < 3; i++) { + if (verbose > 0) + printf("Showing notification: %s: %s\n", identifier, message); + + if ((rc = notify(identifier, message, priority, icon, timeout)) == 0) + break; + + fprintf(stderr, "Failed to show notification, reinitializing libnotify.\n"); + notify_uninit(); + usleep(500 * 1000); + if (notify_init(program) == FALSE) { + fprintf(stderr, "Failed to initialize notify.\n"); + rc = EXIT_FAILURE; + } + } + if (rc != 0) + goto out40; + } + + /* execute command */ + if (execute) { + if (verbose > 1) + printf("Executing: %s -i %s -p %s -m %s\n", + execute, identifier, priorityname, message); + + if ((child_pid = fork()) < 0) { + fprintf(stderr, "fork() failed\n"); + } else if (child_pid == 0) { /* This is the child */ + rc = execlp(execute, execute, "-i", identifier, + "-p", priorityname, "-m", message, NULL); + /* execlp() should replace the process, so anything failed */ + fprintf(stderr, "Failed to execute '%s': %s\n", execute, strerror(-rc)); + goto out10; + } else { /* This is the parent */ + do { + if ((wpid = waitpid(child_pid, &status, WUNTRACED|WCONTINUED)) < 0) { + perror("waitpid"); + goto out40; + } + + if (WIFEXITED(status)) { + if (WEXITSTATUS(status) > 0 || verbose > 1) + printf("child exited, status %d\n", WEXITSTATUS(status)); + } else if (WIFSIGNALED(status)) { + printf("child killed (signal %d)\n", WTERMSIG(status)); + } else if (WIFSTOPPED(status)) { + printf("child stopped (signal %d)\n", WSTOPSIG(status)); + } else if (WIFCONTINUED(status)) { + printf("child continued\n"); + } else { + printf("Unexpected status (0x%x)\n", status); + } + } while (!WIFEXITED(status) && !WIFSIGNALED(status)); } } - if (rc != 0) - goto out40; } free(identifier); @@ -298,7 +356,8 @@ int main(int argc, char **argv) { rc = EXIT_SUCCESS; out40: - notify_uninit(); + if (executeonly == 0) + notify_uninit(); out30: if (have_regex > 0) diff --git a/journal-notify.h b/journal-notify.h index ee18b7b..0dd2962 100644 --- a/journal-notify.h +++ b/journal-notify.h @@ -16,6 +16,7 @@ #include #include #include +#include #include @@ -25,6 +26,16 @@ #define DEFAULTICON "dialog-information" +const char * priorities[] = { + "EMERG", /* 0 */ + "ALERT", + "CRIT", + "ERR", + "WARNING", + "NOTICE", + "INFO", + "DEBUG" /* 7 */}; + /*** notify ***/ int notify(const char * identifier, const char * message, uint8_t priority, const char * icon, int timeout); -- cgit v1.2.3-54-g00ecf