Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Notify handle #45

Merged
merged 4 commits into from
Mar 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions man/syslog.conf.5
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,17 @@ cron or a separate log rotate daemon.
Comments, lines starting with a hash mark ('#'), and empty lines are
ignored. If an error occurs during parsing the whole line is ignored.
.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
.Em include
keyword can be used to include all files with names ending in '.conf'
Expand Down
105 changes: 101 additions & 4 deletions src/syslogd.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 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.
*/
Expand Down Expand Up @@ -180,9 +185,12 @@ static void signal_init(void);
static void boot_time_init(void);
static void init(void);
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);
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);
static int validate(struct sockaddr *sa, const char *hname);
static int waitdaemon(int);
Expand Down Expand Up @@ -1604,6 +1612,9 @@ void logrotate(struct filed *f)
ERR("Failed re-opening log file %s after rotation", f->f_un.f_fname);
return;
}

if (!SIMPLEQ_EMPTY(&nothead))
notifier_invoke(f->f_un.f_fname);
}
ftruncate(f->f_file, 0);
}
Expand Down Expand Up @@ -2455,6 +2466,7 @@ static void boot_time_init(void)
static void init(void)
{
static int once = 1;
struct notifiers newn = SIMPLEQ_HEAD_INITIALIZER(newn);
struct filed *f;
struct files newf = SIMPLEQ_HEAD_INITIALIZER(newf);
FILE *fp;
Expand Down Expand Up @@ -2538,7 +2550,7 @@ static void init(void)
}
}

if (cfparse(fp, &newf)) {
if (cfparse(fp, &newf, &newn)) {
fclose(fp);
return;
}
Expand All @@ -2548,11 +2560,27 @@ static void init(void)
* Close all open log files.
*/
close_open_log_files();

fhead = newf;

/*
* Free all notifiers
*/
notifier_free_all();

nothead = newn;

Initialized = 1;

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) {
if (f->f_type == F_UNUSED)
continue;
Expand Down Expand Up @@ -2923,7 +2951,7 @@ static struct filed *cfline(char *line)
/*
* 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;
char cbuf[BUFSIZ];
Expand Down Expand Up @@ -2988,13 +3016,18 @@ static int cfparse(FILE *fp, struct files *newf)
}

logit("Parsing %s ...", gl.gl_pathv[i]);
cfparse(fpi, newf);
cfparse(fpi, newf, newn);
fclose(fpi);
}
globfree(&gl);
continue;
}

if (!strncmp(cbuf, "notify", 6)) {
notifier_add(newn, &cbuf[6]);
continue;
}

f = cfline(cbuf);
if (!f)
continue;
Expand Down Expand Up @@ -3337,6 +3370,70 @@ static void logit(char *fmt, ...)
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
* we are now doing mallocs/free as part of init we had better not being
Expand Down
8 changes: 8 additions & 0 deletions src/syslogd.h
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,14 @@ struct filed {
int f_rotatesz;
};

/*
* Log rotation notifiers
*/
struct notifier {
SIMPLEQ_ENTRY(notifier) n_link;
char *n_program;
};

void flog(int pri, char *fmt, ...);

#endif /* SYSKLOGD_SYSLOGD_H_ */
3 changes: 2 additions & 1 deletion test/Makefile.am
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
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
TEST_EXTENSIONS = .sh
TESTS_ENVIRONMENT= unshare -mrun
Expand All @@ -17,5 +17,6 @@ TESTS += remote.sh
TESTS += api.sh
TESTS += fwd.sh
TESTS += mark.sh
TESTS += notify.sh

programs: $(check_PROGRAMS)
41 changes: 41 additions & 0 deletions test/notify.sh
Original file line number Diff line number Diff line change
@@ -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