Browse Source

notify: Call external notifier program on event.

Georgi Chorbadzhiyski 13 years ago
parent
commit
093d53b431
8 changed files with 286 additions and 8 deletions
  1. 3
    0
      ChangeLog
  2. 1
    1
      Makefile
  3. 10
    0
      data.h
  4. 63
    0
      notify-script.example
  5. 154
    0
      notify.c
  6. 31
    0
      notify.h
  7. 7
    0
      tsdecrypt.1
  8. 17
    7
      tsdecrypt.c

+ 3
- 0
ChangeLog View File

1
+xxxx-xx-xx : Version -next
2
+ * notify: Added option to execute external script on event.
3
+
1
 2011-11-14 : Version 3.2
4
 2011-11-14 : Version 3.2
2
  * Fixed bug that prevented tsdecrypt from working at all :(
5
  * Fixed bug that prevented tsdecrypt from working at all :(
3
 
6
 

+ 1
- 1
Makefile View File

30
 TS_DIR = libtsfuncs
30
 TS_DIR = libtsfuncs
31
 TS_LIB = $(TS_DIR)/libtsfuncs.a
31
 TS_LIB = $(TS_DIR)/libtsfuncs.a
32
 
32
 
33
-tsdecrypt_SRC  = data.c udp.c util.c camd.c process.c tables.c tsdecrypt.c
33
+tsdecrypt_SRC  = data.c udp.c util.c camd.c process.c tables.c notify.c tsdecrypt.c
34
 tsdecrypt_LIBS = -lcrypto -ldvbcsa -lpthread
34
 tsdecrypt_LIBS = -lcrypto -ldvbcsa -lpthread
35
 tsdecrypt_OBJS = $(tsdecrypt_SRC:.c=.o) $(FUNCS_LIB) $(TS_LIB)
35
 tsdecrypt_OBJS = $(tsdecrypt_SRC:.c=.o) $(FUNCS_LIB) $(TS_LIB)
36
 
36
 

+ 10
- 0
data.h View File

35
 // How much seconds to assume the key is valid
35
 // How much seconds to assume the key is valid
36
 #define KEY_VALID_TIME 10
36
 #define KEY_VALID_TIME 10
37
 
37
 
38
+struct notify {
39
+	pthread_t	thread;				/* Thread handle */
40
+	QUEUE		*notifications;		/* Notification queue */
41
+	char		ident[512];			/* tsdecrypt ident (set by -i) */
42
+	char		program[512];		/* What program to exec */
43
+};
44
+
38
 struct key {
45
 struct key {
39
 	uint8_t				cw[16];
46
 	uint8_t				cw[16];
40
 	int					is_valid_cw;
47
 	int					is_valid_cw;
166
 	int					write_stop;
173
 	int					write_stop;
167
 	pthread_t			write_thread;
174
 	pthread_t			write_thread;
168
 	CBUF				*write_buf;
175
 	CBUF				*write_buf;
176
+
177
+	struct notify		*notify;
178
+	char				notify_program[512];
169
 };
179
 };
170
 
180
 
171
 enum msg_type { EMM_MSG, ECM_MSG };
181
 enum msg_type { EMM_MSG, ECM_MSG };

+ 63
- 0
notify-script.example View File

1
+#!/bin/sh
2
+# Example tsdecrypt notify script
3
+# Written by Georgi Chorbadzhiyski
4
+#
5
+# *** Released as PUBLIC DOMAIN ***
6
+# *** Do whatever you want with this code ***
7
+
8
+EMAIL_ENABLED="yes"
9
+EMAIL_TO="georgi@unixsol.org" # !!! Change this !!!
10
+EMAIL_FROM="georgi@unixsol.org" # !!! Change this !!!
11
+EMAIL_SUBJECT_PREFIX="[tsdecrypt]"
12
+EMAIL_PROGRAM="/usr/sbin/sendmail -t -i"
13
+
14
+LOG_ENABLED="yes"
15
+LOG_DIR="."
16
+LOG_FILE="$LOGDIR/notify.${_IDENT}.notify.log"
17
+
18
+# Environmental vars that are set by the calling process (tsdecrypt):
19
+#   _TS             Unix timestamp of the event.
20
+#   _IDENT          tsdecrypt ident (--ident parameter).
21
+#   _MESSAGE_ID     Event message id (For example START, STOP, etc...).
22
+#   _MESSAGE_TEXT   Event message text. Human readable event message.
23
+#   _MESSAGE_MSG    Event message id lower cased and "_" is replaced with " "
24
+
25
+export PATH="/bin:/usr/bin:/usr/local/bin"
26
+export LC_ALL=C
27
+
28
+if [ -z "${_IDENT}" -o -z "${_TS}" ]
29
+then
30
+	echo "This script must be run from tsdecrypt."
31
+	echo "In order for tsdecrypt to run this script use --ident and --notify-prg options."
32
+	echo
33
+	echo "Example:"
34
+	echo "   tsdecrypt --ident SOURCE/CHANNEL --notify-program ./notify-script.example --camd-server x.x.x.x"
35
+	echo
36
+	exit 1
37
+fi
38
+
39
+if [ "$LOG_ENABLED" = "yes" ]
40
+then
41
+	LOG_DATE="$(date +%F\ %T\ %z -d @${_TS})"
42
+	printf "%s | %s | %-16s | %s\n" \
43
+		"$LOG_DATE" \
44
+		"${_IDENT}" \
45
+		"${_MESSAGE_ID}" \
46
+		"${_MESSAGE_TEXT}" \
47
+		  >> $LOG_DIR/$LOG_FILE
48
+fi
49
+
50
+if [ "$EMAIL_ENABLED" = "yes" ]
51
+then
52
+	(
53
+		echo "To: <$EMAIL_TO>"
54
+		echo "From: <$EMAIL_FROM>"
55
+		echo "Return-Path: <$EMAIL_FROM>"
56
+		echo "Subject: $EMAIL_SUBJECT_PREFIX ${_IDENT} ${_MESSAGE_MSG}"
57
+		echo "X-IDENT: ${_IDENT}"
58
+		echo "X-MSG-ID: ${_MESSAGE_ID}"
59
+		echo "X-Mailer: tsdecrypt"
60
+		echo
61
+		echo "${_IDENT} ${_MESSAGE_TEXT}"
62
+	) | $EMAIL_PROGRAM
63
+fi

+ 154
- 0
notify.c View File

1
+/*
2
+ * Exec external program to notify for an event
3
+ * Copyright (C) 2011 Unix Solutions Ltd.
4
+ *
5
+ * This program is free software; you can redistribute it and/or modify
6
+ * it under the terms of the GNU General Public License version 2
7
+ * as published by the Free Software Foundation.
8
+ *
9
+ * This program is distributed in the hope that it will be useful,
10
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
+ * GNU General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
17
+ */
18
+
19
+// Needed for asprintf
20
+#define _GNU_SOURCE 1
21
+
22
+#include <stdlib.h>
23
+#include <stdarg.h>
24
+#include <unistd.h>
25
+#include <string.h>
26
+#include <errno.h>
27
+#include <ctype.h>
28
+#include <pthread.h>
29
+#include <sys/types.h>
30
+#include <sys/wait.h>
31
+#include <sys/mman.h>
32
+
33
+#include "libfuncs/queue.h"
34
+
35
+#include "notify.h"
36
+
37
+struct npriv {
38
+	char	ident[512];
39
+	char	program[512];
40
+	char	msg_id[512];
41
+	char	text[512];
42
+};
43
+
44
+static void *do_notify(void *in) {
45
+	struct npriv *data = in;
46
+	struct npriv *shared = mmap(NULL, sizeof(struct npriv), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
47
+	if (!shared) {
48
+		perror("mmap");
49
+		goto OUT;
50
+	}
51
+	*shared = *data;
52
+	pid_t pid = fork();
53
+	if (pid==0) { // child process
54
+		char *args[] = { shared->program, shared->ident, NULL };
55
+		int e = 0;
56
+		unsigned int i, r;
57
+		char **env = calloc(32, sizeof(char *));
58
+		asprintf(&env[e++], "_TS=%ld"			, time(NULL));
59
+		asprintf(&env[e++], "_IDENT=%s"			, shared->ident);
60
+		asprintf(&env[e++], "_MESSAGE_ID=%s"	, shared->msg_id);
61
+		asprintf(&env[e++], "_MESSAGE_TEXT=%s"	, shared->text);
62
+		r = strlen(shared->msg_id);
63
+		for (i=0; i<r; i++) {
64
+			if (isalpha(shared->msg_id[i]))
65
+				shared->msg_id[i] = tolower(shared->msg_id[i]);
66
+			if (shared->msg_id[i] == '_')
67
+				shared->msg_id[i] = ' ';
68
+		}
69
+		asprintf(&env[e++], "_MESSAGE_MSG=%s"	, shared->msg_id);
70
+		execve(args[0], args, env);
71
+		// We reach here only if there is an error.
72
+		fprintf(stderr, "execve('%s') failed: %s!\n", args[0], strerror(errno));
73
+		do {
74
+			free(env[e--]);
75
+		} while (e);
76
+		free(env);
77
+		exit(127);
78
+	} else {
79
+		waitpid(pid, NULL, 0);
80
+	}
81
+
82
+	munmap(shared, sizeof(struct npriv));
83
+OUT:
84
+	free(data);
85
+	pthread_exit(0);
86
+}
87
+
88
+static void *notify_thread(void *data) {
89
+	struct notify *n = data;
90
+
91
+	while (1) {
92
+		struct npriv *np = queue_get(n->notifications); // Waits...
93
+		if (!np)
94
+			break;
95
+		pthread_t notifier; // The notifier frees the data
96
+		pthread_attr_t attr;
97
+		pthread_attr_init(&attr);
98
+		pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
99
+		if (pthread_create(&notifier, &attr, &do_notify, np) != 0) {
100
+			perror("pthread_create");
101
+			free(np);
102
+		}
103
+		pthread_attr_destroy(&attr);
104
+	}
105
+	pthread_exit(0);
106
+}
107
+
108
+/* ======================================================================== */
109
+
110
+struct notify *notify_alloc(struct ts *ts) {
111
+	unsigned int i;
112
+	if (!ts->ident[0] || !ts->notify_program[0])
113
+		return NULL;
114
+	struct notify *n = calloc(1, sizeof(struct notify));
115
+	n->notifications = queue_new("notifications");
116
+	strncpy(n->ident, ts->ident, sizeof(n->ident) - 1);
117
+	for (i=0; i<strlen(n->ident); i++) {
118
+		if (n->ident[i] == '/')
119
+			n->ident[i] = '-';
120
+	}
121
+	strncpy(n->program, ts->notify_program, sizeof(n->program) - 1);
122
+	pthread_create(&n->thread, NULL , &notify_thread, n);
123
+	return n;
124
+}
125
+
126
+static void npriv_init_defaults(struct notify *n, struct npriv *np) {
127
+	strncpy(np->program, n->program, sizeof(np->program) - 1);
128
+	strncpy(np->ident, n->ident, sizeof(np->ident) - 1);
129
+}
130
+
131
+void notify(struct ts *ts, char *msg_id, char *text_fmt, ...) {
132
+	va_list args;
133
+	struct npriv *np = calloc(1, sizeof(struct npriv));
134
+	if (!ts->notify)
135
+		return;
136
+	npriv_init_defaults(ts->notify, np);
137
+	strncpy(np->msg_id, msg_id, sizeof(np->ident) - 1);
138
+	np->msg_id[sizeof(np->ident) - 1] = 0;
139
+	va_start(args, text_fmt);
140
+	vsnprintf(np->text, sizeof(np->text) - 1, text_fmt, args);
141
+	np->text[sizeof(np->text) - 1] = 0;
142
+	va_end(args);
143
+	queue_add(ts->notify->notifications, np);
144
+}
145
+
146
+void notify_free(struct notify **pn) {
147
+	struct notify *n = *pn;
148
+	if (n) {
149
+		queue_add(n->notifications, NULL);
150
+		pthread_join(n->thread, NULL);
151
+		queue_free(&n->notifications);
152
+		FREE(*pn);
153
+	}
154
+}

+ 31
- 0
notify.h View File

1
+/*
2
+ * Exec external program to notify for an event
3
+ * Copyright (C) 2011 Unix Solutions Ltd.
4
+ *
5
+ * This program is free software; you can redistribute it and/or modify
6
+ * it under the terms of the GNU General Public License version 2
7
+ * as published by the Free Software Foundation.
8
+ *
9
+ * This program is distributed in the hope that it will be useful,
10
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
+ * GNU General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
17
+ */
18
+#ifndef NOTIFY_H
19
+# define NOTIFY_H
20
+
21
+#include "libfuncs/queue.h"
22
+#include "data.h"
23
+
24
+struct notify *notify_alloc(struct ts *ts);
25
+
26
+__attribute__ ((format(printf, 3, 4)))
27
+void notify(struct ts *ts, char *msg_id, char *text_fmt, ...);
28
+
29
+void notify_free(struct notify **pn);
30
+
31
+#endif

+ 7
- 0
tsdecrypt.1 View File

20
 \fB\-d\fR, \fB\-\-daemon\fR <pidfile>
20
 \fB\-d\fR, \fB\-\-daemon\fR <pidfile>
21
 When started become a daemon and write pid file to <pidfile>.
21
 When started become a daemon and write pid file to <pidfile>.
22
 .TP
22
 .TP
23
+\fB\-N\fR, \fB\-\-notify\-program\fR <program>
24
+Execute \fB<program>\fR when predefined events happen. In order for
25
+this option to work \fB\-\-ident\fR should also be used.
26
+
27
+You can use \fBnotify-script.example\fR file as notification program
28
+and an example on how to create your own notification script.
29
+.TP
23
 \fB\-l\fR, \fB\-\-syslog\-host\fR <addr>
30
 \fB\-l\fR, \fB\-\-syslog\-host\fR <addr>
24
 Set syslog host. tsdecrypt sends messages to this host over tcp in
31
 Set syslog host. tsdecrypt sends messages to this host over tcp in
25
 syslog compatible format. syslog-ng was tested as receiving syslog server.
32
 syslog compatible format. syslog-ng was tested as receiving syslog server.

+ 17
- 7
tsdecrypt.c View File

30
 #include "camd.h"
30
 #include "camd.h"
31
 #include "process.h"
31
 #include "process.h"
32
 #include "udp.h"
32
 #include "udp.h"
33
+#include "notify.h"
33
 
34
 
34
 #define FIRST_REPORT_SEC 3
35
 #define FIRST_REPORT_SEC 3
35
 
36
 
53
 	{ "daemon",				required_argument, NULL, 'd' },
54
 	{ "daemon",				required_argument, NULL, 'd' },
54
 	{ "syslog-host",		required_argument, NULL, 'l' },
55
 	{ "syslog-host",		required_argument, NULL, 'l' },
55
 	{ "syslog-port",		required_argument, NULL, 'L' },
56
 	{ "syslog-port",		required_argument, NULL, 'L' },
57
+	{ "notify-program",		required_argument, NULL, 'N' },
56
 
58
 
57
 	{ "input",				required_argument, NULL, 'I' },
59
 	{ "input",				required_argument, NULL, 'I' },
58
 	{ "input-rtp",			no_argument,       NULL, 'R' },
60
 	{ "input-rtp",			no_argument,       NULL, 'R' },
97
 	printf("Daemon options:\n");
99
 	printf("Daemon options:\n");
98
 	printf(" -i --ident <server>        | Format PROVIDER/CHANNEL. Default: empty\n");
100
 	printf(" -i --ident <server>        | Format PROVIDER/CHANNEL. Default: empty\n");
99
 	printf(" -d --daemon <pidfile>      | Daemonize program and write pid file.\n");
101
 	printf(" -d --daemon <pidfile>      | Daemonize program and write pid file.\n");
102
+	printf(" -N --notify-program <prg>  | Execute <prg> to report events. Default: empty\n");
103
+	printf("\n");
100
 	printf(" -l --syslog-host <host>    | Syslog server address. Default: disabled\n");
104
 	printf(" -l --syslog-host <host>    | Syslog server address. Default: disabled\n");
101
 	printf(" -L --syslog-port <port>    | Syslog server port. Default: %d\n", ts->syslog_port);
105
 	printf(" -L --syslog-port <port>    | Syslog server port. Default: %d\n", ts->syslog_port);
102
 	printf("\n");
106
 	printf("\n");
188
 
192
 
189
 static void parse_options(struct ts *ts, int argc, char **argv) {
193
 static void parse_options(struct ts *ts, int argc, char **argv) {
190
 	int j, i, ca_err = 0, server_err = 1, input_addr_err = 0, output_addr_err = 0, output_intf_err = 0, ident_err = 0;
194
 	int j, i, ca_err = 0, server_err = 1, input_addr_err = 0, output_addr_err = 0, output_intf_err = 0, ident_err = 0;
191
-	while ( (j = getopt_long(argc, argv, "i:d:l:L:I:RzO:o:t:pc:C:s:U:P:y:eZ:Ef:X:H:G:KJ:D:hV", long_options, NULL)) != -1 ) {
195
+	while ( (j = getopt_long(argc, argv, "i:d:N:l:L:I:RzO:o:t:pc:C:s:U:P:y:eZ:Ef:X:H:G:KJ:D:hV", long_options, NULL)) != -1 ) {
192
 		char *p = NULL;
196
 		char *p = NULL;
193
 		switch (j) {
197
 		switch (j) {
194
 			case 'i':
198
 			case 'i':
200
 				ts->pidfile[sizeof(ts->pidfile) - 1] = 0;
204
 				ts->pidfile[sizeof(ts->pidfile) - 1] = 0;
201
 				ts->daemonize = 1;
205
 				ts->daemonize = 1;
202
 				break;
206
 				break;
207
+			case 'N':
208
+				strncpy(ts->notify_program, optarg, sizeof(ts->notify_program) - 1);
209
+				ts->notify_program[sizeof(ts->notify_program) - 1] = 0;
210
+				break;
211
+
203
 			case 'l':
212
 			case 'l':
204
 				strncpy(ts->syslog_host, optarg, sizeof(ts->syslog_host) - 1);
213
 				strncpy(ts->syslog_host, optarg, sizeof(ts->syslog_host) - 1);
205
 				ts->syslog_host[sizeof(ts->syslog_host) - 1] = 0;
214
 				ts->syslog_host[sizeof(ts->syslog_host) - 1] = 0;
352
 			fprintf(stderr, "ERROR: Output interface address is invalid.\n");
361
 			fprintf(stderr, "ERROR: Output interface address is invalid.\n");
353
 		exit(1);
362
 		exit(1);
354
 	}
363
 	}
355
-	if (ts->ident[0])
356
-		ts_LOGf("Ident      : %s\n", ts->ident);
357
-	else
358
-		ts_LOGf("Ident      : *NOT SET*\n");
364
+	ts_LOGf("Ident      : %s\n", ts->ident[0] ? ts->ident : "*NOT SET*");
365
+	ts_LOGf("Notify prog: %s\n", ts->notify_program[0] ? ts->notify_program : "*NOT SET*");
359
 	if (ts->pidfile[0])
366
 	if (ts->pidfile[0])
360
 		ts_LOGf("Daemonize  : %s pid file.\n", ts->pidfile);
367
 		ts_LOGf("Daemonize  : %s pid file.\n", ts->pidfile);
361
 	else
368
 	else
530
 		log_init(ts.ident, ts.syslog_active, ts.daemonize != 1, ts.syslog_host, ts.syslog_port);
537
 		log_init(ts.ident, ts.syslog_active, ts.daemonize != 1, ts.syslog_host, ts.syslog_port);
531
 	}
538
 	}
532
 
539
 
540
+	ts.notify = notify_alloc(&ts);
541
+
533
 	ts_LOGf("Start %s\n", program_id);
542
 	ts_LOGf("Start %s\n", program_id);
534
 
543
 
535
 	if (ts.input.type == NET_IO && udp_connect_input(&ts.input) < 1)
544
 	if (ts.input.type == NET_IO && udp_connect_input(&ts.input) < 1)
599
 			pthread_join(ts.write_thread, NULL);
608
 			pthread_join(ts.write_thread, NULL);
600
 	}
609
 	}
601
 
610
 
602
-	data_free(&ts);
603
-
604
 	ts_LOGf("Stop %s\n", program_id);
611
 	ts_LOGf("Stop %s\n", program_id);
605
 
612
 
606
 	if (ts.syslog_active)
613
 	if (ts.syslog_active)
609
 	if (ts.daemonize)
616
 	if (ts.daemonize)
610
 		unlink(ts.pidfile);
617
 		unlink(ts.pidfile);
611
 
618
 
619
+	notify_free(&ts.notify);
620
+	data_free(&ts);
621
+
612
 	exit(0);
622
 	exit(0);
613
 }
623
 }

Loading…
Cancel
Save