Merge pull request #45 from sdaoden/notify

Notify handle

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
Joachim Wiberg 2022-03-14 05:45:17 +01:00 committed by GitHub
commit 23a6d81ea2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 163 additions and 5 deletions

View File

@ -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'

View File

@ -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(&nothead))
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(&nothead)) {
struct notifier *np;
SIMPLEQ_FOREACH(np, &nothead, 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, &nothead, 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, &nothead, 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

View File

@ -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_ */

View File

@ -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
View 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