Commit 80a4c23b authored by Ondrej Zajicek (work)'s avatar Ondrej Zajicek (work)
Browse files

Unix: Implement log file size limit / log rotation

Allow to specify log file size limit and ensure that log file is rotated
to secondary name to avoid exceeding of log size limit.

The patch also fixes a bug related to keeping old fds open after
reconfiguration and using old fds after 'configure undo'.
parent 9861dba5
Loading
Loading
Loading
Loading
+24 −14
Original line number Diff line number Diff line
@@ -11,13 +11,16 @@ CF_HDR
#include "sysdep/unix/unix.h"
#include <stdio.h>

CF_DEFINES

static struct log_config *this_log;

CF_DECLS

CF_KEYWORDS(LOG, SYSLOG, ALL, DEBUG, TRACE, INFO, REMOTE, WARNING, ERROR, AUTH, FATAL, BUG, STDERR, SOFT)
CF_KEYWORDS(NAME, CONFIRM, UNDO, CHECK, TIMEOUT, DEBUG, LATENCY, LIMIT, WATCHDOG, WARNING)

%type <i> log_mask log_mask_list log_cat cfg_timeout
%type <g> log_file
%type <t> cfg_name
%type <tf> timeformat_which
%type <t> syslog_name
@@ -26,11 +29,11 @@ CF_GRAMMAR

CF_ADDTO(conf, log_config)

log_config: LOG log_file log_mask ';' {
    struct log_config *c = cfg_allocz(sizeof(struct log_config));
    c->fh = $2;
    c->mask = $3;
    add_tail(&new_config->logfiles, &c->n);
log_begin: { this_log = cfg_allocz(sizeof(struct log_config)); };

log_config: LOG log_begin log_file log_mask ';' {
    this_log->mask = $4;
    add_tail(&new_config->logfiles, &this_log->n);
  }
 ;

@@ -39,14 +42,21 @@ syslog_name:
 | { $$ = bird_name; }
 ;

log_limit:
   /* empty */
 | expr text { this_log->limit = $1; this_log->backup = $2; }
 ;

log_file:
   text {
     FILE *f = tracked_fopen(new_config->pool, $1, "a");
     if (!f) cf_error("Unable to open log file `%s': %m", $1);
     $$ = f;
   text log_limit {
     this_log->rf = rf_open(new_config->pool, $1, "a");
     if (!this_log->rf) cf_error("Unable to open log file '%s': %m", $1);
     this_log->fh = rf_file(this_log->rf);
     this_log->pos = -1;
     this_log->filename = $1;
   }
 | SYSLOG syslog_name { $$ = NULL; new_config->syslog_name = $2; }
 | STDERR { $$ = stderr; }
 | SYSLOG syslog_name { this_log->fh = NULL; new_config->syslog_name = $2; }
 | STDERR { this_log->fh = stderr; }
 ;

log_mask:
@@ -77,9 +87,9 @@ CF_ADDTO(conf, mrtdump_base)
mrtdump_base:
   MRTDUMP PROTOCOLS mrtdump_mask ';' { new_config->proto_default_mrtdump = $3; }
 | MRTDUMP text ';' {
     FILE *f = tracked_fopen(new_config->pool, $2, "a");
     struct rfile *f = rf_open(new_config->pool, $2, "a");
     if (!f) cf_error("Unable to open MRTDump file '%s': %m", $2);
     new_config->mrtdump_file = fileno(f);
     new_config->mrtdump_file = rf_fileno(f);
   }
 ;

+21 −8
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@
   this to gen small latencies */
#define MAX_RX_STEPS 4


/*
 *	Tracked Files
 */
@@ -89,17 +90,29 @@ static struct resclass rf_class = {
  NULL
};

void *
tracked_fopen(pool *p, char *name, char *mode)
struct rfile *
rf_open(pool *p, char *name, char *mode)
{
  FILE *f = fopen(name, mode);

  if (f)
    {
  if (!f)
    return NULL;

  struct rfile *r = ralloc(p, &rf_class);
  r->f = f;
  return r;
}

void *
rf_file(struct rfile *f)
{
  return f->f;
}
  return f;

int
rf_fileno(struct rfile *f)
{
  return fileno(f->f);
}


+84 −4
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@
#include <stdlib.h>
#include <stdarg.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>

@@ -86,6 +88,54 @@ static char *class_names[] = {
  "BUG"
};

static inline off_t
log_size(struct log_config *l)
{
  struct stat st;
  return (!fstat(rf_fileno(l->rf), &st) && S_ISREG(st.st_mode)) ? st.st_size : 0;
}

static void
log_close(struct log_config *l)
{
  rfree(l->rf);
  l->rf = NULL;
  l->fh = NULL;
}

static int
log_open(struct log_config *l)
{
  l->rf = rf_open(config->pool, l->filename, "a");
  if (!l->rf)
  {
    /* Well, we cannot do much in case of error as log is closed */
    l->mask = 0;
    return -1;
  }

  l->fh = rf_file(l->rf);
  l->pos = log_size(l);

  return 0;
}

static int
log_rotate(struct log_config *l)
{
  log_close(l);

  /* If we cannot rename the logfile, we at least try to delete it
     in order to continue logging and not exceeding logfile size */
  if ((rename(l->filename, l->backup) < 0) &&
      (unlink(l->filename) < 0))
  {
    l->mask = 0;
    return -1;
  }

  return log_open(l);
}

/**
 * log_commit - commit a log message
@@ -121,6 +171,22 @@ log_commit(int class, buffer *buf)
	    {
	      byte tbuf[TM_DATETIME_BUFFER_SIZE];
	      tm_format_real_time(tbuf, config->tf_log.fmt1, current_real_time());

	      if (l->limit)
	      {
		off_t msg_len = strlen(tbuf) + strlen(class_names[class]) +
		  (buf->pos - buf->start) + 5;

		if (l->pos < 0)
		  l->pos = log_size(l);

		if (l->pos + msg_len > l->limit)
		  if (log_rotate(l) < 0)
		    continue;

		l->pos += msg_len;
	      }

	      fprintf(l->fh, "%s <%s> ", tbuf, class_names[class]);
	    }
	  fputs(buf->start, l->fh);
@@ -279,12 +345,26 @@ default_log_list(int debug, int init, char **syslog_name)
}

void
log_switch(int debug, list *l, char *new_syslog_name)
log_switch(int debug, list *logs, char *new_syslog_name)
{
  if (!l || EMPTY_LIST(*l))
    l = default_log_list(debug, !l, &new_syslog_name);
  struct log_config *l;

  if (!logs || EMPTY_LIST(*logs))
    logs = default_log_list(debug, !logs, &new_syslog_name);

  /* Close the logs to avoid pinning them on disk when deleted */
  if (current_log_list)
    WALK_LIST(l, *current_log_list)
      if (l->rf)
	log_close(l);

  /* Reopen the logs, needed for 'configure undo' */
  if (logs)
    WALK_LIST(l, *logs)
      if (l->filename && !l->rf)
	log_open(l);

  current_log_list = l;
  current_log_list = logs;

#ifdef HAVE_SYSLOG_H
  if (current_syslog_name && new_syslog_name &&
+9 −1
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@
struct pool;
struct iface;
struct birdsock;
struct rfile;

/* main.c */

@@ -102,7 +103,9 @@ void io_init(void);
void io_loop(void);
void io_log_dump(void);
int sk_open_unix(struct birdsock *s, char *name);
void *tracked_fopen(struct pool *, char *name, char *mode);
struct rfile *rf_open(struct pool *, char *name, char *mode);
void *rf_file(struct rfile *f);
int rf_fileno(struct rfile *f);
void test_old_bird(char *path);

/* krt.c bits */
@@ -119,6 +122,11 @@ struct log_config {
  node n;
  uint mask;				/* Classes to log */
  void *fh;				/* FILE to log to, NULL=syslog */
  struct rfile *rf;			/* Resource for log file */
  char *filename;			/* Log filename */
  char *backup;				/* Secondary filename (for log rotation) */
  off_t pos;				/* Position/size of current log */
  off_t limit;				/* Log size limit */
  int terminal_flag;
};