Add "notify" keyword

This commit is contained in:
Steffen Nurpmeso 2022-01-20 14:33:22 +01:00
parent 6022d3c7d0
commit 72f2faef6e
3 changed files with 105 additions and 4 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
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'

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 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.
*/
@ -180,9 +185,11 @@ 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);
void reload(int);
static int validate(struct sockaddr *sa, const char *hname);
static int waitdaemon(int);
@ -1604,6 +1611,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);
}
@ -2250,6 +2260,7 @@ void debug_switch(int signo)
*/
static void close_open_log_files(void)
{
struct notifier *np = NULL, *npnext = NULL;
struct filed *f = NULL, *next = NULL;
SIMPLEQ_FOREACH_SAFE(f, &fhead, f_link, next) {
@ -2276,6 +2287,9 @@ static void close_open_log_files(void)
free(f);
}
SIMPLEQ_FOREACH_SAFE(np, &nothead, n_link, npnext)
free(np);
}
void die(int signo)
@ -2455,6 +2469,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;
@ -2538,7 +2553,7 @@ static void init(void)
}
}
if (cfparse(fp, &newf)) {
if (cfparse(fp, &newf, &newn)) {
fclose(fp);
return;
}
@ -2548,11 +2563,21 @@ static void init(void)
* Close all open log files.
*/
close_open_log_files();
fhead = newf;
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;
@ -2923,7 +2948,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];
@ -2988,13 +3013,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;
@ -3337,6 +3367,58 @@ 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;
size_t len;
len = strlen(program);
np = calloc(1, sizeof(*np) + len +1);
if (np) {
/* xxx Actually wastes space -- vararray? */
np->n_program = (char*)&np[1];
memcpy(np->n_program, program, len);
SIMPLEQ_INSERT_TAIL(newn, np, n_link);
} else
ERR("Cannot allocate memory for a notify program");
} else
logit("notify: non-existing, or not executable program\n");
}
static void notifier_invoke(const char *logfile)
{
char *argv[3];
struct notifier *np;
logit("notify: rotated %s, invoking hooks\n", logfile);
SIMPLEQ_FOREACH(np, &nothead, n_link) {
switch (fork()) {
case -1:
ERR("Cannot start notifier %s", np->n_program);
break;
case 0:
/* No specific I/O setup, just use what we had */
argv[0] = np->n_program;
argv[1] = (char*)logfile; /* logical unconst */
argv[2] = NULL;
execv(argv[0], argv);
_exit(1);
default:
/* Do not care beside that, no special process group
* etc.; it will eventually be reaped via reapchild() */
logit("notify: forked for %s\n", np->n_program);
break;
}
}
}
/*
* 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

View File

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