1 /*
2  *  ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3  *
4  *  Copyright (c) 1997-2021 ircd-hybrid development team
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19  *  USA
20  */
21 
22 /*! \file log.c
23  * \brief Logger functions.
24  * \version $Id: log.c 9858 2021-01-01 04:43:42Z michael $
25  */
26 
27 #include "stdinc.h"
28 #include "log.h"
29 #include "conf.h"
30 #include "misc.h"
31 #include "memory.h"
32 
33 
34 static struct LogFile log_type_table[LOG_TYPE_LAST];
35 
36 
37 void
log_set_file(enum log_type type,size_t size,const char * path)38 log_set_file(enum log_type type, size_t size, const char *path)
39 {
40   struct LogFile *log = &log_type_table[type];
41 
42   if (log->path)
43     xfree(log->path);
44 
45   log->path = xstrdup(path);
46   log->size = size;
47 
48   if (type == LOG_TYPE_IRCD)
49     log->file = fopen(log->path, "a");
50 }
51 
52 void
log_free(struct LogFile * log)53 log_free(struct LogFile *log)
54 {
55   xfree(log->path);
56   log->path = NULL;
57 }
58 
59 void
log_reopen(struct LogFile * log)60 log_reopen(struct LogFile *log)
61 {
62   if (log->file)
63   {
64     fclose(log->file);
65     log->file = NULL;
66   }
67 
68   if (log->path)
69     log->file = fopen(log->path, "a");
70 }
71 
72 void
log_iterate(void (* func)(struct LogFile *))73 log_iterate(void (*func)(struct LogFile *))
74 {
75   /* type = 1 to skip LOG_TYPE_IRCD */
76   for (unsigned int type = 1; type < LOG_TYPE_LAST; ++type)
77     func(&log_type_table[type]);
78 }
79 
80 static bool
log_exceed_size(struct LogFile * log)81 log_exceed_size(struct LogFile *log)
82 {
83   struct stat sb;
84 
85   if (log->size == 0)
86     return false;
87 
88   if (stat(log->path, &sb) < 0)
89     return false;
90 
91   return (size_t)sb.st_size > log->size;
92 }
93 
94 static void
log_write(struct LogFile * log,const char * message)95 log_write(struct LogFile *log, const char *message)
96 {
97   fprintf(log->file, "[%s] %s\n", date_iso8601(0), message);
98   fflush(log->file);
99 }
100 
101 void
ilog(enum log_type type,const char * fmt,...)102 ilog(enum log_type type, const char *fmt, ...)
103 {
104   struct LogFile *log = &log_type_table[type];
105   char buf[LOG_BUFSIZE] = "";
106   va_list args;
107 
108   if (log->file == NULL || ConfigLog.use_logging == 0)
109     return;
110 
111   va_start(args, fmt);
112   vsnprintf(buf, sizeof(buf), fmt, args);
113   va_end(args);
114 
115   log_write(log, buf);
116 
117   if (log_exceed_size(log) == false)
118     return;
119 
120   snprintf(buf, sizeof(buf), "Rotating logfile %s", log->path);
121   log_write(log, buf);
122 
123   fclose(log->file);
124   log->file = NULL;
125 
126   snprintf(buf, sizeof(buf), "%s.old", log->path);
127   unlink(buf);
128   rename(log->path, buf);
129 
130   log->file = fopen(log->path, "a");
131 }
132