Fix typo in zombie period start time
[freeradius.git] / src / main / log.c
1 /*
2  * log.c        Logging module.
3  *
4  * Version:     $Id$
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 St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2001,2006  The FreeRADIUS server project
21  * Copyright 2000  Miquel van Smoorenburg <miquels@cistron.nl>
22  * Copyright 2000  Alan DeKok <aland@ox.org>
23  * Copyright 2001  Chad Miller <cmiller@surfsouth.com>
24  */
25
26 #include <freeradius-devel/ident.h>
27 RCSID("$Id$")
28
29 #include <freeradius-devel/radiusd.h>
30
31 #ifdef HAVE_SYS_STAT_H
32 #include <sys/stat.h>
33 #endif
34
35 #ifdef HAVE_SYSLOG_H
36 #       include <syslog.h>
37 #endif
38
39 /*
40  * Logging facility names
41  */
42 static const FR_NAME_NUMBER levels[] = {
43         { ": Debug: ",          L_DBG   },
44         { ": Auth: ",           L_AUTH  },
45         { ": Proxy: ",          L_PROXY },
46         { ": Info: ",           L_INFO  },
47         { ": Acct: ",           L_ACCT  },
48         { ": Error: ",          L_ERR   },
49         { NULL, 0 }
50 };
51
52 /*
53  *      Log the message to the logfile. Include the severity and
54  *      a time stamp.
55  */
56 int vradlog(int lvl, const char *fmt, va_list ap)
57 {
58         struct main_config_t *myconfig = &mainconfig;
59         unsigned char *p;
60         char buffer[8192];
61         int len;
62
63         /*
64          *      NOT debugging, and trying to log debug messages.
65          *
66          *      Throw the message away.
67          */
68         if (!debug_flag && (lvl == L_DBG)) {
69                 return 0;
70         }
71
72         /*
73          *      If we don't want any messages, then
74          *      throw them away.
75          */
76         if (myconfig->radlog_dest == RADLOG_NULL) {
77                 return 0;
78         }
79
80         *buffer = '\0';
81         len = 0;
82
83         /*
84          *      Don't print timestamps to syslog, it does that for us.
85          *      Don't print timestamps for low levels of debugging.
86          *
87          *      Print timestamps for non-debugging, and for high levels
88          *      of debugging.
89          */
90         if ((myconfig->radlog_dest != RADLOG_SYSLOG) &&
91             (debug_flag != 1) && (debug_flag != 2)) {
92                 const char *s;
93                 time_t timeval;
94
95                 timeval = time(NULL);
96                 CTIME_R(&timeval, buffer + len, sizeof(buffer) - len - 1);
97
98                 s = fr_int2str(levels, (lvl & ~L_CONS), ": ");
99
100                 strcat(buffer, s);
101                 len = strlen(buffer);
102         }
103
104         vsnprintf(buffer + len, sizeof(buffer) - len - 1, fmt, ap);
105
106         /*
107          *      Filter out characters not in Latin-1.
108          */
109         for (p = (unsigned char *)buffer; *p != '\0'; p++) {
110                 if (*p == '\r' || *p == '\n')
111                         *p = ' ';
112                 else if (*p == '\t') continue;
113                 else if (*p < 32 || (*p >= 128 && *p <= 160))
114                         *p = '?';
115         }
116         strcat(buffer, "\n");
117
118         switch (myconfig->radlog_dest) {
119
120 #ifdef HAVE_SYSLOG_H
121         case RADLOG_SYSLOG:
122                 switch(lvl & ~L_CONS) {
123                         case L_DBG:
124                                 lvl = LOG_DEBUG;
125                                 break;
126                         case L_AUTH:
127                                 lvl = LOG_NOTICE;
128                                 break;
129                         case L_PROXY:
130                                 lvl = LOG_NOTICE;
131                                 break;
132                         case L_ACCT:
133                                 lvl = LOG_NOTICE;
134                                 break;
135                         case L_INFO:
136                                 lvl = LOG_INFO;
137                                 break;
138                         case L_ERR:
139                                 lvl = LOG_ERR;
140                                 break;
141                 }
142                 syslog(lvl, "%s", buffer);
143                 break;
144 #endif
145
146         case RADLOG_FILES:
147                 write(myconfig->radlog_fd, buffer, strlen(buffer));
148                 break;
149
150         case RADLOG_STDOUT:
151                 write(STDOUT_FILENO, buffer, strlen(buffer));
152                 break;
153
154         case RADLOG_STDERR:
155                 write(STDERR_FILENO, buffer, strlen(buffer));
156                 break;
157
158         default:
159         case RADLOG_NULL:       /* should have been caught above */
160                 break;
161         }
162
163         return 0;
164 }
165
166 int log_debug(const char *msg, ...)
167 {
168         va_list ap;
169         int r;
170
171         va_start(ap, msg);
172         r = vradlog(L_DBG, msg, ap);
173         va_end(ap);
174
175         return r;
176 }
177
178 int radlog(int lvl, const char *msg, ...)
179 {
180         va_list ap;
181         int r;
182
183         va_start(ap, msg);
184         r = vradlog(lvl, msg, ap);
185         va_end(ap);
186
187         return r;
188 }
189
190
191 /*
192  *      Dump a whole list of attributes to DEBUG2
193  */
194 void vp_listdebug(VALUE_PAIR *vp)
195 {
196         char tmpPair[70];
197         for (; vp; vp = vp->next) {
198                 vp_prints(tmpPair, sizeof(tmpPair), vp);
199                 DEBUG2("     %s", tmpPair);
200         }
201 }
202
203 extern char *request_log_file;
204 #ifdef HAVE_SYS_UN_H
205 extern char *debug_log_file;
206 #endif
207
208 void radlog_request(int lvl, int priority, REQUEST *request, const char *msg, ...)
209 {
210         size_t len = 0;
211         const char *filename = request_log_file;
212         FILE *fp = NULL;
213         va_list ap;
214         char buffer[1024];
215
216         va_start(ap, msg);
217
218         /*
219          *      Debug messages get treated specially.
220          */
221         if (lvl == L_DBG) {
222                 /*
223                  *      There is log function, but the debug level
224                  *      isn't high enough.  OR, we're in debug mode,
225                  *      and the debug level isn't high enough.  Return.
226                  */
227                 if ((request && request->radlog &&
228                      (priority > request->options)) ||
229                     ((debug_flag != 0) && (priority > debug_flag))) {
230                         va_end(ap);
231                         return;
232                 }
233
234                 /*
235                  *      Use the debug output file, if specified,
236                  *      otherwise leave it as "request_log_file".
237                  */
238 #ifdef HAVE_SYS_UN_H
239                 filename = debug_log_file;
240                 if (!filename)
241 #endif
242                   filename = request_log_file;
243
244                 /*
245                  *      Debug messages get mashed to L_INFO for
246                  *      radius.log.
247                  */
248                 if (!filename) lvl = L_INFO;
249         }
250
251         if (request && filename) {
252                 char *p;
253                 radlog_func_t rl = request->radlog;
254
255                 request->radlog = NULL;
256
257                 /*
258                  *      This is SLOW!  Doing it for every log message
259                  *      in every request is NOT recommended!
260                  */
261                 
262                 radius_xlat(buffer, sizeof(buffer), filename,
263                             request, NULL); /* FIXME: escape chars! */
264                 request->radlog = rl;
265                 
266                 p = strrchr(buffer, FR_DIR_SEP);
267                 if (p) {
268                         *p = '\0';
269                         if (rad_mkdir(buffer, S_IRWXU) < 0) {
270                                 radlog(L_ERR, "Failed creating %s: %s",
271                                        buffer,strerror(errno));
272                                 va_end(ap);
273                                 return;
274                         }
275                         *p = FR_DIR_SEP;
276                 }
277
278                 fp = fopen(buffer, "a");
279         }
280
281         /*
282          *      Print timestamps to the file.
283          */
284         if (fp) {
285                 char *s;
286                 time_t timeval;
287                 timeval = time(NULL);
288
289                 CTIME_R(&timeval, buffer + len, sizeof(buffer) - len - 1);
290                 
291                 s = strrchr(buffer, '\n');
292                 if (s) {
293                         s[0] = ' ';
294                         s[1] = '\0';
295                 }
296                 
297                 s = fr_int2str(levels, (lvl & ~L_CONS), ": ");
298                 
299                 strcat(buffer, s);
300                 len = strlen(buffer);
301         }
302         
303         if (request && request->module[0]) {
304                 snprintf(buffer + len, sizeof(buffer) + len, "[%s] ", request->module);
305                 len = strlen(buffer);
306         }
307         vsnprintf(buffer + len, sizeof(buffer) - len, msg, ap);
308         
309         if (!fp) {
310                 if (request) {
311                         radlog(lvl, "(%u) %s", request->number, buffer);
312                 } else {
313                         radlog(lvl, "%s", buffer);
314                 }
315         } else {
316                 if (request) fprintf(fp, "(%u) ", request->number);
317                 fputs(buffer, fp);
318                 fputc('\n', fp);
319                 fclose(fp);
320         }
321
322         va_end(ap);
323 }