Commits (1)
  • Rob Swindell's avatar
    Add configurable log size limit and retention count · 238b0b7c
    Rob Swindell authored
    For the following log files:
      hungup.log
      error.log
      crash.log
      hack.log
      spam.log
      guru.log
    
    ... they can be limited in size, in bytes, by the sysop, along with a maximum retention limit (number of *.#.log files). Configured in SCFG->System->Advanced.
    
    By default, the limit and keep numbers are 0, so "unlimited" (same behavior as before). Once sufficiently tested, I'll change the default in a stock main.cnf file to use a sensible limit (e.g. 10 log files of 10MB each, something like that).
    238b0b7c
......@@ -1541,7 +1541,7 @@ void sbbs_t::guruchat(char* line, char* gurubuf, int gurunum, char* last_answer)
char str[512],cstr[512],*ptr,*answer[100],theanswer[1024]
,mistakes=1,hu=0;
char tmp[512];
int file;
FILE* fp;
uint c,i,j,k,answers;
long len;
struct tm tm;
......@@ -1816,27 +1816,22 @@ void sbbs_t::guruchat(char* line, char* gurubuf, int gurunum, char* last_answer)
}
CRLF;
sprintf(str,"%sguru.log",cfg.logs_dir);
if((file=nopen(str,O_WRONLY|O_CREAT|O_APPEND))==-1)
if((fp = fopenlog(&cfg, str)) == NULL)
errormsg(WHERE,ERR_OPEN,str,O_WRONLY|O_CREAT|O_APPEND);
else {
xpDateTime_to_isoDateTimeStr(xpDateTime_now(), "-", " ", ":", 0, str, sizeof(str)-3);
SAFECAT(str,"\r\n");
write(file,str,strlen(str));
fprintf(fp, "%s\r\n", str);
if(action==NODE_MCHT) {
sprintf(str,"[Multi] ");
write(file,str,strlen(str));
fprintf(fp, "[Multi] ");
}
sprintf(str,"%s:\r\n",sys_status&SS_USERON
fprintf(fp,"%s:\r\n",sys_status&SS_USERON
? useron.alias : "UNKNOWN");
write(file,str,strlen(str));
write(file,line,strlen(line));
fprintf(fp,"%s",line);
if(action!=NODE_MCHT)
write(file,crlf,2);
sprintf(str,"%s:\r\n",cfg.guru[gurunum]->name);
write(file,str,strlen(str));
write(file,theanswer,strlen(theanswer));
write(file,crlf,2);
close(file);
fprintf(fp,"\r\n");
fprintf(fp,"%s:\r\n",cfg.guru[gurunum]->name);
fprintf(fp,"%s\r\n",theanswer);
fcloselog(fp);
}
if(hu)
hangup();
......
......@@ -35,7 +35,7 @@ extern "C" BOOL hacklog(scfg_t* cfg, const char* prot, const char* user, const c
SAFEPRINTF(fname, "%shack.log", cfg->logs_dir);
if((fp = fnopen(NULL, fname, O_WRONLY|O_CREAT|O_APPEND)) == NULL)
if((fp = fopenlog(cfg, fname)) == NULL)
return false;
inet_addrtop(addr, ip, sizeof(ip));
......@@ -52,7 +52,7 @@ extern "C" BOOL hacklog(scfg_t* cfg, const char* prot, const char* user, const c
if(text != NULL)
fprintf(fp, "Details: %s%s", text, log_line_ending);
fputs(log_line_ending, fp);
fclose(fp);
fcloselog(fp);
return true;
}
......@@ -74,7 +74,7 @@ extern "C" BOOL spamlog(scfg_t* cfg, char* prot, char* action
SAFEPRINTF(fname, "%sspam.log", cfg->logs_dir);
if((fp = fnopen(NULL, fname, O_WRONLY|O_CREAT|O_APPEND)) == NULL)
if((fp = fopenlog(cfg, fname)) == NULL)
return false;
if(to==NULL)
......@@ -100,7 +100,7 @@ extern "C" BOOL spamlog(scfg_t* cfg, char* prot, char* action
if(reason != NULL)
fprintf(fp, "Reason: %s%s", reason, log_line_ending);
fputs(log_line_ending, fp);
fclose(fp);
fcloselog(fp);
return true;
}
......@@ -113,7 +113,7 @@ extern "C" int errorlog(scfg_t* cfg, int level, const char* host, const char* te
time_t now = time(NULL);
SAFEPRINTF(path, "%serror.log", cfg->logs_dir);
if((fp = fnopen(NULL,path,O_WRONLY|O_CREAT|O_APPEND))==NULL)
if((fp = fopenlog(cfg, path))==NULL)
return -1;
fprintf(fp,"%.24s %s/%s %s%s%s%s%s"
,ctime_r(&now, buf)
......@@ -125,7 +125,7 @@ extern "C" int errorlog(scfg_t* cfg, int level, const char* host, const char* te
,log_line_ending
,log_line_ending
);
fclose(fp);
fcloselog(fp);
if(cfg->node_erruser && level <= cfg->node_errlevel) {
char subject[128];
SAFEPRINTF2(subject, "%s %sERROR occurred", host == NULL ? "" : host, level <= LOG_CRIT ? "CRITICAL " : "");
......
......@@ -4159,6 +4159,7 @@ void sbbs_t::catsyslog(int crash)
{
char str[MAX_PATH+1] = "node.log";
char *buf;
FILE* fp;
int i,file;
long length;
struct tm tm;
......@@ -4201,18 +4202,18 @@ void sbbs_t::catsyslog(int crash)
if(crash) {
for(i=0;i<2;i++) {
SAFEPRINTF(str,"%scrash.log",i ? cfg.logs_dir : cfg.node_dir);
if((file=nopen(str,O_WRONLY|O_APPEND|O_CREAT))==-1) {
if((fp = fopenlog(&cfg, str)) == NULL) {
errormsg(WHERE,ERR_OPEN,str,O_WRONLY|O_APPEND|O_CREAT);
free((char *)buf);
return;
}
if(lwrite(file,buf,length)!=length) {
close(file);
if(fwrite(buf, sizeof(uint8_t), length, fp) !=length) {
fcloselog(fp);
errormsg(WHERE,ERR_WRITE,str,length);
free((char *)buf);
return;
}
close(file);
fcloselog(fp);
}
}
free((char *)buf);
......
......@@ -22,6 +22,7 @@
#include "filewrap.h"
#include "sockwrap.h"
#include "sbbsdefs.h"
#include "nopen.h"
/****************************************************************************/
/* Network open function. Opens all files DENYALL, DENYWRITE, or DENYNONE */
......@@ -208,3 +209,34 @@ BOOL backup(const char *fname, int backup_level, BOOL ren)
return TRUE;
}
/****************************************************************************/
/* Open a log file for append, supporting log rotation based on size */
/****************************************************************************/
FILE* fopenlog(scfg_t* cfg, const char* path)
{
const int mode = O_WRONLY|O_CREAT|O_APPEND;
FILE* fp;
if((fp = fnopen(NULL, path, mode)) == NULL)
return NULL;
if(cfg->max_log_size && cfg->max_logs_kept && ftello(fp) >= (off_t)cfg->max_log_size) {
#ifdef _WIN32 // Can't rename an open file on Windows
fclose(fp);
#endif
backup(path, cfg->max_logs_kept, /* rename: */TRUE);
#ifndef _WIN32
fclose(fp);
#endif
if((fp = fnopen(NULL, path, mode)) == NULL)
return NULL;
}
return fp;
}
void fcloselog(FILE* fp)
{
fclose(fp);
}
......@@ -38,6 +38,7 @@
#include <stdio.h> /* FILE */
#include "gen_defs.h" /* BOOL (switch to stdbool when we stop using BCB6) */
#include "scfgdefs.h"
#ifdef __cplusplus
extern "C" {
......@@ -49,6 +50,8 @@ BOOL ftouch(const char* fname);
BOOL fmutex(const char* fname, const char* text, long max_age);
BOOL fcompare(const char* fn1, const char* fn2);
BOOL backup(const char* org, int backup_level, BOOL ren);
FILE* fopenlog(scfg_t*, const char* path);
void fcloselog(FILE*);
#ifdef __cplusplus
}
......
......@@ -62,6 +62,7 @@ static void configure_dst(void)
void sys_cfg(void)
{
static int sys_dflt,adv_dflt,tog_dflt,new_dflt;
static int adv_bar;
char str[81],done=0;
int i,j,k,dflt,bar;
char sys_pass[sizeof(cfg.sys_pass)];
......@@ -1369,7 +1370,7 @@ void sys_cfg(void)
,cfg.new_sof);
u32toac(cfg.cdt_per_dollar,str,',');
sprintf(opt[i++],"%-27.27s%s","Credits Per Dollar",str);
sprintf(opt[i++],"%-27.27s%u","Minutes Per 100k Credits"
sprintf(opt[i++],"%-27.27s%u","Minutes Per 100K Credits"
,cfg.cdt_min_value);
sprintf(opt[i++],"%-27.27s%s","Maximum Number of Minutes"
,cfg.max_minutes ? ultoa(cfg.max_minutes,tmp,10) : "Unlimited");
......@@ -1391,6 +1392,14 @@ void sys_cfg(void)
else
strcpy(str,"None");
sprintf(opt[i++],"%-27.27s%s","Mail Database Backups",str);
if(cfg.max_log_size && cfg.max_logs_kept) {
SAFEPRINTF2(str, "%s bytes, keep %lu"
,byte_count_to_str(cfg.max_log_size, tmp, sizeof(tmp))
,cfg.max_logs_kept);
} else {
SAFECOPY(str, "Unlimited");
}
sprintf(opt[i++],"%-27.27s%s","Maximum Log File Size", str);
sprintf(opt[i++],"%-27.27s%"PRIX32,"Control Key Pass-through"
,cfg.ctrlkey_passthru);
opt[i][0]=0;
......@@ -1399,7 +1408,7 @@ void sys_cfg(void)
"\n"
"Care should be taken when modifying any of the options listed here.\n"
;
switch(uifc.list(WIN_ACT|WIN_BOT|WIN_RHT,0,0,60,&adv_dflt,0
switch(uifc.list(WIN_ACT|WIN_BOT|WIN_RHT,0,0,60,&adv_dflt,&adv_bar
,"Advanced Options",opt)) {
case -1:
done=1;
......@@ -1648,6 +1657,38 @@ void sys_cfg(void)
cfg.mail_backup_level=atoi(str);
break;
case 16:
uifc.helpbuf=
"`Maximum Log File Size:`\n"
"\n"
"This option allows you to limit the size of the following log files\n"
"created and appended-to by Synchronet, in the `Logs Directory`:\n"
"\n"
" `hungup.log`\n"
" `error.log`\n"
" `crash.log`\n"
" `hack.log`\n"
" `spam.log`\n"
" `guru.log`\n"
"\n"
"The largest supported log file size limit is 4294967295 (3.99G) bytes.\n"
"Log files that have reached or exceeded the configured size limit are\n"
"retained by renaming the `*.log` file to `*.#.log` beginning with `*.0.log`.\n"
"\n"
"You must also specify the number of older/max-size log files to retain.\n"
"The largest number of supported retained rotated log files is 9999.\n"
"Oldest rotated log files are automatically deleted to save disk space.\n"
;
byte_count_to_str(cfg.max_log_size, str, sizeof(str));
if(uifc.input(WIN_MID|WIN_SAV, 0, 0, "Maximum Log File Size (in bytes, 0=unlimited)", str, 10, K_EDIT|K_UPPER) > 0) {
cfg.max_log_size = (uint32_t)parse_byte_count(str, 1);
if(cfg.max_log_size) {
SAFEPRINTF(str, "%u", cfg.max_logs_kept);
if(uifc.input(WIN_MID|WIN_SAV, 0, 0, "Maximum Number of old Log Files to Keep", str, 4, K_EDIT|K_NUMBER) > 0)
cfg.max_logs_kept = atoi(str);
}
}
break;
case 17:
uifc.helpbuf=
"`Control Key Pass-through:`\n"
"\n"
......
......@@ -545,6 +545,8 @@ typedef struct
uint32_t max_qwkmsgs; /* Maximum messages per QWK packet */
uint16_t max_qwkmsgage; /* Maximum age (in days) of QWK messages to be imported */
uint16_t max_spamage; /* Maximum age (in days) of SPAM-tagged messages */
uint32_t max_log_size;
uint16_t max_logs_kept;
char preqwk_arstr[LEN_ARSTR+1]; /* pre pack QWK */
uchar preqwk_ar[LEN_ARSTR+1];
uint16_t cdt_min_value; /* Minutes per 100k credits */
......
......@@ -198,8 +198,9 @@ BOOL read_main_cfg(scfg_t* cfg, char* error, size_t maxerrlen)
if(cfg->min_pwlen > LEN_PASS)
cfg->min_pwlen = LEN_PASS;
get_int(c, instream);
for(i=0;i<4;i++)
get_int(n,instream);
get_int(n,instream);
get_int(cfg->max_log_size, instream);
get_int(cfg->max_logs_kept, instream);
/*************************/
/* Expired User Settings */
......
......@@ -215,8 +215,9 @@ BOOL write_main_cfg(scfg_t* cfg, int backup_level)
put_int(cfg->min_pwlen, stream);
put_int(c, stream);
n=0;
for(i=0;i<4;i++)
put_int(n,stream);
put_int(n,stream);
put_int(cfg->max_log_size, stream);
put_int(cfg->max_logs_kept, stream);
put_int(cfg->expired_level,stream);
put_int(cfg->expired_flags1,stream);
......
......@@ -1246,7 +1246,6 @@ const char* sbbs_t::xtrn_dropdir(const xtrn_t* xtrn, char* buf, size_t maxlen)
bool sbbs_t::exec_xtrn(uint xtrnnum)
{
char str[256],path[MAX_PATH+1],dropdir[MAX_PATH+1],name[32],c;
int file;
uint i;
long tleft,mode;
node_t node;
......@@ -1433,14 +1432,14 @@ bool sbbs_t::exec_xtrn(uint xtrnnum)
}
else if(!online) {
SAFEPRINTF(str,"%shungup.log",cfg.logs_dir);
if((file=nopen(str,O_WRONLY|O_CREAT|O_APPEND))==-1) {
FILE* fp = fopenlog(&cfg, str);
if(fp == NULL)
errormsg(WHERE,ERR_OPEN,str,O_WRONLY|O_CREAT|O_APPEND);
return(false);
else {
now=time(NULL);
fprintf(fp,hungupstr,useron.alias,cfg.xtrn[xtrnnum]->name,timestr(now));
fcloselog(fp);
}
now=time(NULL);
SAFEPRINTF3(str,hungupstr,useron.alias,cfg.xtrn[xtrnnum]->name,timestr(now));
write(file,str,strlen(str));
close(file);
}
if(cfg.xtrn[xtrnnum]->misc&MODUSERDAT) /* Modify user data */
moduserdat(xtrnnum);
......