Merge pull request #45 from sdaoden/notify
Notify handle Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
commit
23a6d81ea2
@ -105,6 +105,17 @@ cron or a separate log rotate daemon.
|
|||||||
Comments, lines starting with a hash mark ('#'), and empty lines are
|
Comments, lines starting with a hash mark ('#'), and empty lines are
|
||||||
ignored. If an error occurs during parsing the whole line is ignored.
|
ignored. If an error occurs during parsing the whole line is ignored.
|
||||||
.Pp
|
.Pp
|
||||||
|
The special keyword
|
||||||
|
.Em notify
|
||||||
|
specifies the path to an executable program which will get called
|
||||||
|
whenever a log file has been rotated, with the name of the file, less
|
||||||
|
its rotation suffix
|
||||||
|
.Ql .0 ,
|
||||||
|
as an argument.
|
||||||
|
For example:
|
||||||
|
.Ql notify /sbin/on-log-rotate.sh .
|
||||||
|
Any number of notifiers may be installed.
|
||||||
|
.Pp
|
||||||
A special
|
A special
|
||||||
.Em include
|
.Em include
|
||||||
keyword can be used to include all files with names ending in '.conf'
|
keyword can be used to include all files with names ending in '.conf'
|
||||||
|
105
src/syslogd.c
105
src/syslogd.c
@ -147,6 +147,11 @@ static int KeepKernTime; /* Keep kernel timestamp, evern after initial read
|
|||||||
static off_t RotateSz = 0; /* Max file size (bytes) before rotating, disabled by default */
|
static off_t RotateSz = 0; /* Max file size (bytes) before rotating, disabled by default */
|
||||||
static int RotateCnt = 5; /* Max number (count) of log files to keep, set with -c <NUM> */
|
static int RotateCnt = 5; /* Max number (count) of log files to keep, set with -c <NUM> */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* List of notifiers
|
||||||
|
*/
|
||||||
|
static SIMPLEQ_HEAD(notifiers, notifier) nothead = SIMPLEQ_HEAD_INITIALIZER(nothead);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* List of peers and sockets for binding.
|
* List of peers and sockets for binding.
|
||||||
*/
|
*/
|
||||||
@ -180,9 +185,12 @@ static void signal_init(void);
|
|||||||
static void boot_time_init(void);
|
static void boot_time_init(void);
|
||||||
static void init(void);
|
static void init(void);
|
||||||
static int strtobytes(char *arg);
|
static int strtobytes(char *arg);
|
||||||
static int cfparse(FILE *fp, struct files *newf);
|
static int cfparse(FILE *fp, struct files *newf, struct notifiers *newn);
|
||||||
int decode(char *name, struct _code *codetab);
|
int decode(char *name, struct _code *codetab);
|
||||||
static void logit(char *, ...);
|
static void logit(char *, ...);
|
||||||
|
static void notifier_add(struct notifiers *newn, const char *program);
|
||||||
|
static void notifier_invoke(const char *logfile);
|
||||||
|
static void notifier_free_all(void);
|
||||||
void reload(int);
|
void reload(int);
|
||||||
static int validate(struct sockaddr *sa, const char *hname);
|
static int validate(struct sockaddr *sa, const char *hname);
|
||||||
static int waitdaemon(int);
|
static int waitdaemon(int);
|
||||||
@ -1604,6 +1612,9 @@ void logrotate(struct filed *f)
|
|||||||
ERR("Failed re-opening log file %s after rotation", f->f_un.f_fname);
|
ERR("Failed re-opening log file %s after rotation", f->f_un.f_fname);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!SIMPLEQ_EMPTY(¬head))
|
||||||
|
notifier_invoke(f->f_un.f_fname);
|
||||||
}
|
}
|
||||||
ftruncate(f->f_file, 0);
|
ftruncate(f->f_file, 0);
|
||||||
}
|
}
|
||||||
@ -2455,6 +2466,7 @@ static void boot_time_init(void)
|
|||||||
static void init(void)
|
static void init(void)
|
||||||
{
|
{
|
||||||
static int once = 1;
|
static int once = 1;
|
||||||
|
struct notifiers newn = SIMPLEQ_HEAD_INITIALIZER(newn);
|
||||||
struct filed *f;
|
struct filed *f;
|
||||||
struct files newf = SIMPLEQ_HEAD_INITIALIZER(newf);
|
struct files newf = SIMPLEQ_HEAD_INITIALIZER(newf);
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
@ -2538,7 +2550,7 @@ static void init(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cfparse(fp, &newf)) {
|
if (cfparse(fp, &newf, &newn)) {
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -2548,11 +2560,27 @@ static void init(void)
|
|||||||
* Close all open log files.
|
* Close all open log files.
|
||||||
*/
|
*/
|
||||||
close_open_log_files();
|
close_open_log_files();
|
||||||
|
|
||||||
fhead = newf;
|
fhead = newf;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Free all notifiers
|
||||||
|
*/
|
||||||
|
notifier_free_all();
|
||||||
|
|
||||||
|
nothead = newn;
|
||||||
|
|
||||||
Initialized = 1;
|
Initialized = 1;
|
||||||
|
|
||||||
if (Debug) {
|
if (Debug) {
|
||||||
|
if (!SIMPLEQ_EMPTY(¬head)) {
|
||||||
|
struct notifier *np;
|
||||||
|
|
||||||
|
SIMPLEQ_FOREACH(np, ¬head, n_link)
|
||||||
|
printf("notify %s\n", np->n_program);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
SIMPLEQ_FOREACH(f, &fhead, f_link) {
|
SIMPLEQ_FOREACH(f, &fhead, f_link) {
|
||||||
if (f->f_type == F_UNUSED)
|
if (f->f_type == F_UNUSED)
|
||||||
continue;
|
continue;
|
||||||
@ -2923,7 +2951,7 @@ static struct filed *cfline(char *line)
|
|||||||
/*
|
/*
|
||||||
* Parse .conf file and append to list
|
* Parse .conf file and append to list
|
||||||
*/
|
*/
|
||||||
static int cfparse(FILE *fp, struct files *newf)
|
static int cfparse(FILE *fp, struct files *newf, struct notifiers *newn)
|
||||||
{
|
{
|
||||||
struct filed *f;
|
struct filed *f;
|
||||||
char cbuf[BUFSIZ];
|
char cbuf[BUFSIZ];
|
||||||
@ -2988,13 +3016,18 @@ static int cfparse(FILE *fp, struct files *newf)
|
|||||||
}
|
}
|
||||||
|
|
||||||
logit("Parsing %s ...", gl.gl_pathv[i]);
|
logit("Parsing %s ...", gl.gl_pathv[i]);
|
||||||
cfparse(fpi, newf);
|
cfparse(fpi, newf, newn);
|
||||||
fclose(fpi);
|
fclose(fpi);
|
||||||
}
|
}
|
||||||
globfree(&gl);
|
globfree(&gl);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!strncmp(cbuf, "notify", 6)) {
|
||||||
|
notifier_add(newn, &cbuf[6]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
f = cfline(cbuf);
|
f = cfline(cbuf);
|
||||||
if (!f)
|
if (!f)
|
||||||
continue;
|
continue;
|
||||||
@ -3337,6 +3370,70 @@ static void logit(char *fmt, ...)
|
|||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void notifier_add(struct notifiers *newn, const char *program)
|
||||||
|
{
|
||||||
|
while (*program && isspace(*program))
|
||||||
|
++program;
|
||||||
|
|
||||||
|
/* Check whether it is accessible, regardless of TOCTOU */
|
||||||
|
if (!access(program, X_OK)) {
|
||||||
|
struct notifier *np;
|
||||||
|
|
||||||
|
np = calloc(1, sizeof(*np));
|
||||||
|
if (!np) {
|
||||||
|
ERR("Cannot allocate memory for a notify program");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
np->n_program = strdup(program);
|
||||||
|
if (!np->n_program) {
|
||||||
|
free (np);
|
||||||
|
ERR("Cannot allocate memory for a notify program");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SIMPLEQ_INSERT_TAIL(newn, np, n_link);
|
||||||
|
} else
|
||||||
|
logit("notify: non-existing, or not executable program\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void notifier_invoke(const char *logfile)
|
||||||
|
{
|
||||||
|
char *argv[3];
|
||||||
|
int childpid;
|
||||||
|
struct notifier *np;
|
||||||
|
|
||||||
|
logit("notify: rotated %s, invoking hooks\n", logfile);
|
||||||
|
|
||||||
|
SIMPLEQ_FOREACH(np, ¬head, n_link) {
|
||||||
|
childpid = fork();
|
||||||
|
|
||||||
|
switch (childpid) {
|
||||||
|
case -1:
|
||||||
|
ERR("Cannot start notifier %s", np->n_program);
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
argv[0] = np->n_program;
|
||||||
|
argv[1] = (char*)logfile;
|
||||||
|
argv[2] = NULL;
|
||||||
|
execv(argv[0], argv);
|
||||||
|
_exit(1);
|
||||||
|
default:
|
||||||
|
logit("notify: forked child pid %d for %s\n",
|
||||||
|
childpid, np->n_program);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void notifier_free_all(void)
|
||||||
|
{
|
||||||
|
struct notifier *np, *npnext;
|
||||||
|
|
||||||
|
SIMPLEQ_FOREACH_SAFE(np, ¬head, n_link, npnext) {
|
||||||
|
free(np->n_program);
|
||||||
|
free(np);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The following function is resposible for handling a SIGHUP signal. Since
|
* The following function is resposible for handling a SIGHUP signal. Since
|
||||||
* we are now doing mallocs/free as part of init we had better not being
|
* we are now doing mallocs/free as part of init we had better not being
|
||||||
|
@ -305,6 +305,14 @@ struct filed {
|
|||||||
int f_rotatesz;
|
int f_rotatesz;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Log rotation notifiers
|
||||||
|
*/
|
||||||
|
struct notifier {
|
||||||
|
SIMPLEQ_ENTRY(notifier) n_link;
|
||||||
|
char *n_program;
|
||||||
|
};
|
||||||
|
|
||||||
void flog(int pri, char *fmt, ...);
|
void flog(int pri, char *fmt, ...);
|
||||||
|
|
||||||
#endif /* SYSKLOGD_SYSLOGD_H_ */
|
#endif /* SYSKLOGD_SYSLOGD_H_ */
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
EXTRA_DIST = lib.sh opts.sh
|
EXTRA_DIST = lib.sh opts.sh
|
||||||
EXTRA_DIST += api.sh local.sh unicode.sh remote.sh fwd.sh mark.sh
|
EXTRA_DIST += api.sh local.sh unicode.sh remote.sh fwd.sh mark.sh notify.sh
|
||||||
CLEANFILES = *~ *.trs *.log
|
CLEANFILES = *~ *.trs *.log
|
||||||
TEST_EXTENSIONS = .sh
|
TEST_EXTENSIONS = .sh
|
||||||
TESTS_ENVIRONMENT= unshare -mrun
|
TESTS_ENVIRONMENT= unshare -mrun
|
||||||
@ -17,5 +17,6 @@ TESTS += remote.sh
|
|||||||
TESTS += api.sh
|
TESTS += api.sh
|
||||||
TESTS += fwd.sh
|
TESTS += fwd.sh
|
||||||
TESTS += mark.sh
|
TESTS += mark.sh
|
||||||
|
TESTS += notify.sh
|
||||||
|
|
||||||
programs: $(check_PROGRAMS)
|
programs: $(check_PROGRAMS)
|
||||||
|
41
test/notify.sh
Executable file
41
test/notify.sh
Executable file
@ -0,0 +1,41 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -x
|
||||||
|
|
||||||
|
if [ x"${srcdir}" = x ]; then
|
||||||
|
srcdir=.
|
||||||
|
fi
|
||||||
|
. ${srcdir}/lib.sh
|
||||||
|
|
||||||
|
[ -x ../src/logger ] || SKIP 'logger missing'
|
||||||
|
|
||||||
|
NOT1=${DIR}/${NM}-1.sh
|
||||||
|
NOT1STAMP=${DIR}/${NM}-1.stamp
|
||||||
|
NOT2=${DIR}/${NM}-2.sh
|
||||||
|
NOT2STAMP=${DIR}/${NM}-2.stamp
|
||||||
|
|
||||||
|
printf '#!/bin/sh -\necho script 1: $* > '${NOT1STAMP}'\n' > ${NOT1}
|
||||||
|
printf '#!/bin/sh -\necho script 2: $* > '${NOT2STAMP}'\n' > ${NOT2}
|
||||||
|
chmod 0755 ${NOT1} ${NOT2}
|
||||||
|
|
||||||
|
cat <<EOF > ${CONFD}/notifier.conf
|
||||||
|
notify ${NOT1}
|
||||||
|
# Match all log messages, store in RC5424 format and rotate every 1 KiB
|
||||||
|
*.* -${LOG} ;rotate=1k:2,RFC5424
|
||||||
|
notify ${NOT2}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
setup
|
||||||
|
|
||||||
|
MSG=01234567890123456789012345678901234567890123456789
|
||||||
|
MSG=$MSG$MSG$MSG$MSG$MSG$MSG$MSG$MSG$MSG$MSG
|
||||||
|
../src/logger -u ${SOCK} ${MSG}
|
||||||
|
../src/logger -u ${SOCK} 1${MSG}
|
||||||
|
../src/logger -u ${SOCK} 2${MSG}
|
||||||
|
|
||||||
|
if [ -f ${LOG}.0 ] &&
|
||||||
|
grep 'script 1' ${NOT1STAMP} &&
|
||||||
|
grep 'script 2' ${NOT2STAMP}; then
|
||||||
|
OK
|
||||||
|
else
|
||||||
|
FAIL 'Notifier did not run.'
|
||||||
|
fi
|
Loading…
Reference in New Issue
Block a user