Author: Kev <klmitch@mit.edu>
[ircu2.10.12-pk.git] / ircd / ircd_log.c
1 /************************************************************************
2  *   IRC - Internet Relay Chat, src/ircd_log.c
3  *   Copyright (C) 1999 Thomas Helvey (BleepSoft)
4  *                     
5  *   See file AUTHORS in IRC package for additional names of
6  *   the programmers. 
7  *
8  *   This program is free software; you can redistribute it and/or modify
9  *   it under the terms of the GNU General Public License as published by
10  *   the Free Software Foundation; either version 1, or (at your option)
11  *   any later version.
12  *
13  *   This program is distributed in the hope that it will be useful,
14  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *   GNU General Public License for more details.
17  *
18  *   You should have received a copy of the GNU General Public License
19  *   along with this program; if not, write to the Free Software
20  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  *
22  *   $Id$
23  */
24 #include "ircd_log.h"
25 #include "client.h"
26 #include "config.h"
27 #include "ircd_snprintf.h"
28 #include "ircd_string.h"
29 #include "ircd.h"
30 #include "s_debug.h"
31 #include "struct.h"
32
33 #include <assert.h>
34 #include <fcntl.h>
35 #include <stdarg.h>
36 #include <stdio.h>
37 #include <sys/stat.h>
38 #include <sys/types.h>
39 #include <sys/uio.h>
40 #include <syslog.h>
41 #include <time.h>
42 #include <unistd.h>
43
44 #define LOG_BUFSIZE 2048 
45
46 /* These constants are present even if we don't use syslog */
47 #ifndef LOG_CRIT
48 # define LOG_CRIT 0
49 #endif
50 #ifndef LOG_ERR
51 # define LOG_ERR 0
52 #endif
53 #ifndef LOG_WARNING
54 # define LOG_WARNING 0
55 #endif
56 #ifndef LOG_NOTICE
57 # define LOG_NOTICE 0
58 #endif
59 #ifndef LOG_INFO
60 # define LOG_INFO 0
61 #endif
62
63 /* Map severity levels to strings and syslog levels */
64 static struct LevelData {
65   enum LogLevel level;
66   char         *string;
67   int           syslog;
68 } levelData[] = {
69 #define L(level, syslog)   { L_ ## level, #level, (syslog) }
70   L(CRIT, LOG_CRIT),
71   L(ERROR, LOG_ERR),
72   L(WARNING, LOG_WARNING),
73   L(NOTICE, LOG_NOTICE),
74   L(TRACE, LOG_INFO),
75   L(INFO, LOG_INFO),
76   L(DEBUG, LOG_INFO),
77 #undef L
78   { L_LAST_LEVEL, 0 }
79 };
80
81 /* Descriptions of all logging subsystems */
82 static struct LogDesc {
83   enum LogSys     subsys;   /* number for subsystem */
84   char           *name;     /* subsystem name */
85   struct LogFile *file;     /* file descriptor for subsystem */
86   int             facility; /* -1 means don't use syslog */
87 } logDesc[] = {
88 #define S(system, defprio) { LS_ ## system, #system, 0, (defprio) }
89   S(GLINE, -1),
90 #undef S
91   { LS_LAST_SYSTEM, 0, 0, -1 }
92 };
93
94 struct LogFile {
95   struct LogFile *next; /* next log file descriptor */
96   int             fd;   /* file's descriptor-- -1 if not open */
97   char           *file; /* file name */
98 };
99
100 static struct LogFile *logFileList = 0; /* list of log files */
101
102 static const char *procname = "ircd"; /* process's name */
103
104 static int logLevel = L_INFO;
105
106 #ifdef USE_SYSLOG
107 static int sysLogLevel[] = {
108   LOG_CRIT,
109   LOG_ERR,
110   LOG_WARNING,
111   LOG_NOTICE,
112   LOG_INFO,
113   LOG_INFO,
114   LOG_INFO
115 };
116 #endif
117
118 void ircd_log(int priority, const char* fmt, ...)
119 {
120 #if defined(USE_SYSLOG) || defined(DEBUGMODE)
121   char    buf[LOG_BUFSIZE];
122   va_list args;
123   assert(-1 < priority);
124   assert(priority < L_LAST_LEVEL);
125   assert(0 != fmt);
126
127   if (priority > logLevel)
128     return;
129
130   va_start(args, fmt);
131   vsprintf(buf, fmt, args);
132   va_end(args);
133 #endif
134 #ifdef USE_SYSLOG
135   syslog(sysLogLevel[priority], "%s", buf);
136 #endif
137 #ifdef DEBUGMODE
138   Debug((DEBUG_INFO, "LOG: %s", buf));
139 #endif
140 }
141
142 void open_log(const char* process_name)
143 {
144 #ifdef USE_SYSLOG
145   if (EmptyString(process_name))
146     process_name = "ircd";
147   openlog(process_name, LOG_PID | LOG_NDELAY, LOG_USER);
148 #endif
149 }
150
151 void close_log(void)
152 {
153 #ifdef USE_SYSLOG
154   closelog();
155 #endif
156 }
157
158 void set_log_level(int level)
159 {
160   if (L_ERROR < level && level < L_LAST_LEVEL)
161     logLevel = level;
162 }
163
164 int get_log_level(void)
165 {
166   return(logLevel);
167 }
168
169 /*
170  * ircd_log_kill - log information about a kill
171  */
172 void ircd_log_kill(const struct Client* victim, const struct Client* killer,
173                    const char* inpath, const char* path)
174 {
175   if (MyUser(victim)) {
176     /*
177      * get more infos when your local clients are killed -- _dl
178      */
179     if (IsServer(killer))
180       ircd_log(L_TRACE,
181                "A local client %s!%s@%s KILLED from %s [%s] Path: %s!%s)",
182                victim->name, victim->user->username, victim->user->host,
183                killer->name, killer->name, inpath, path);
184     else
185       ircd_log(L_TRACE,
186                "A local client %s!%s@%s KILLED by %s [%s!%s@%s] (%s!%s)",
187                victim->name, victim->user->username, victim->user->host,
188                killer->name, killer->name, killer->user->username, killer->user->host,
189                inpath, path);
190   }
191   else
192     ircd_log(L_TRACE, "KILL From %s For %s Path %s!%s",
193              killer->name, victim->name, inpath, path);
194 }
195
196
197 void
198 log_init(const char *process_name)
199 {
200   /* store the process name; probably belongs in ircd.c, but oh well... */
201   if (!EmptyString(process_name))
202     procname = process_name;
203
204 #ifdef USE_SYSLOG
205   /* ok, open syslog; default facility: LOG_USER */
206   openlog(procname, LOG_PID | LOG_NDELAY, LOG_USER);
207 #endif
208 }
209
210 void
211 log_reopen(void)
212 {
213   log_close(); /* close everything...we reopen on demand */
214
215 #ifdef USE_SYSLOG
216   /* reopen syslog, if needed; default facility: LOG_USER */
217   openlog(procname, LOG_PID | LOG_NDELAY, LOG_USER);
218 #endif
219 }
220
221 /* close the log files */
222 void
223 log_close(void)
224 {
225   struct LogFile *ptr;
226
227 #ifdef USE_SYSLOG
228   closelog(); /* close syslog */
229 #endif
230
231   for (ptr = logFileList; ptr; ptr = ptr->next) {
232     if (ptr->fd >= 0)
233       close(ptr->fd);
234
235     ptr->fd = -1;
236   }
237 }
238
239 static void
240 log_open(struct LogFile *lf)
241 {
242   /* only open the file if we haven't already */
243   if (lf && lf->fd < 0) {
244     alarm(3);
245     lf->fd = open(lf->file, O_WRONLY | O_CREAT | O_APPEND,
246                      S_IREAD | S_IWRITE);
247     alarm(0);
248   }
249 }
250
251 /* This writes an entry to a log file */
252 void
253 log_write(enum LogSys subsys, enum LogLevel severity, const char *fmt, ...)
254 {
255   struct VarData vd;
256   struct LogDesc *desc;
257   struct LevelData *ldata;
258   struct tm *tstamp;
259   struct iovec vector[3];
260   time_t curtime;
261   char buf[LOG_BUFSIZE];
262   /* 1234567890123456789012 3 */
263   /* [2000-11-28 16:11:20] \0 */
264   char timebuf[23];
265
266   /* check basic assumptions */
267   assert(-1 < subsys);
268   assert(subsys < LS_LAST_SYSTEM);
269   assert(-1 < severity);
270   assert(severity < L_LAST_LEVEL);
271   assert(0 != fmt);
272
273   /* find the log data and the severity data */
274   desc = &logDesc[subsys];
275   ldata = &levelData[severity];
276
277   /* check the set of ordering assumptions */
278   assert(desc->subsys == subsys);
279   assert(ldata->level == severity);
280
281   /* if we don't have anything to log to, short-circuit */
282   if (!desc->file
283 #ifdef USE_SYSLOG
284       && desc->facility < 0
285 #endif
286       )
287     return;
288
289   /* Build the basic log string */
290   vd.vd_format = fmt;
291   va_start(vd.vd_args, fmt);
292
293   /* save the length for writev */
294   /* Log format: "SYSTEM [SEVERITY] log message */
295   vector[1].iov_len =
296     ircd_snprintf(0, buf, sizeof(buf), "%s [%s] %v", desc->name,
297                   ldata->string, &vd) - 1;
298
299   va_end(vd.vd_args);
300
301   /* open the log file if we haven't already */
302   log_open(desc->file);
303   /* if we have something to write to... */
304   if (desc->file && desc->file->fd >= 0) {
305     curtime = TStime();
306     tstamp = localtime(&curtime); /* build the timestamp */
307
308     vector[0].iov_len =
309       ircd_snprintf(0, timebuf, sizeof(timebuf), "[%d-%d-%d %d:%02d:%02d] ",
310                     tstamp->tm_year + 1900, tstamp->tm_mon + 1,
311                     tstamp->tm_mday, tstamp->tm_hour, tstamp->tm_min,
312                     tstamp->tm_sec) - 1;
313
314     /* set up the remaining parts of the writev vector... */
315     vector[0].iov_base = timebuf;
316     vector[1].iov_base = buf;
317
318     vector[2].iov_base = "\n"; /* terminate lines with a \n */
319     vector[2].iov_len = 1;
320
321     /* write it out to the log file */
322     writev(desc->file->fd, vector, 3);
323   }
324
325 #ifdef USE_SYSLOG
326   /* oh yeah, syslog it too... */
327   if (desc->facility >= 0)
328     syslog(ldata->syslog | desc->facility, "%s", buf);
329 #endif
330 }