Release bumped to "gts4".
[tac_plus.git] / report.c
1 /*
2    Copyright (c) 1995-1998 by Cisco systems, Inc.
3
4    Permission to use, copy, modify, and distribute this software for
5    any purpose and without fee is hereby granted, provided that this
6    copyright and permission notice appear on all copies of the
7    software and supporting documentation, the name of Cisco Systems,
8    Inc. not be used in advertising or publicity pertaining to
9    distribution of the program without specific prior permission, and
10    notice be given in supporting documentation that modification,
11    copying and distribution is by permission of Cisco Systems, Inc.
12
13    Cisco Systems, Inc. makes no representations about the suitability
14    of this software for any purpose.  THIS SOFTWARE IS PROVIDED ``AS
15    IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
16    WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
17    FITNESS FOR A PARTICULAR PURPOSE.
18 */
19
20
21 #include "tac_plus.h"
22
23 #include <stdio.h>
24 #include <sys/types.h>
25 #include <time.h>
26 #include <sys/stat.h>
27 #ifdef HAVE_FCNTL_H
28 #include <fcntl.h>
29 #endif
30 #include <string.h>
31 #ifdef HAVE_UNISTD_H
32 #include <unistd.h>
33 #endif
34 #ifdef HAVE_SYSLOG_H
35 #include <syslog.h>
36 #endif
37 #ifdef HAVE_SYS_SYSLOG_H
38 #include <sys/syslog.h>
39 #endif
40
41 #include "report.h"
42 #include "utils.h"
43 #include "main.h"
44
45
46 /* Configurable:
47  */
48
49 #define LOGFILE_DEFAULT "/var/log/tac_plus.log"
50
51
52 FILE *ostream = NULL;
53
54 char *logfile = LOGFILE_DEFAULT;
55
56 /* report:
57  *
58  * This routine reports errors and such via stderr and syslog() if
59  * appopriate.  It just helps avoid a lot of if-else in the code.
60  *
61  * LOG_DEBUG messages are ignored unless debugging is on.
62  * All other priorities are always logged to syslog.
63  */
64
65 void report TAC_ARGS((int priority, const char *fmt, ...)) G_GNUC_PRINTF(2, 3);
66
67 #ifdef __STDC__
68
69 #include <stdarg.h>             /* ANSI C, variable length args */
70 void
71 report(int priority, const char *fmt,...)
72
73 #else /* __STDC__ */
74
75 #include <varargs.h>            /* has 'vararg' definitions */
76 /* VARARGS2 */
77 void
78 report(priority, fmt, va_alist)
79 int priority;
80 const char *fmt;
81 va_dcl                          /* no terminating semi-colon */
82
83 #endif /* __STDC__ */
84 {
85     char msg[255];              /* temporary string */
86     const char *fp;
87     char *bufp, *charp = NULL /* GCC paranoia */;
88     int len, m = 0 /* GCC paranoia */, i, n;
89     char digits[16];
90     va_list ap;
91
92 #ifdef __STDC__
93     va_start(ap, fmt);
94 #else
95     va_start(ap);
96 #endif
97
98     /* ensure that msg is never overwritten */
99     n = 255;
100     fp = fmt;
101     len = 0;
102     msg[n-1] = '\0';
103     bufp = msg;
104
105     while (*fp) {
106
107         if (*fp != '%') {
108             if ((len+1) >= n) {
109                 break;
110             }
111             *bufp++ = *fp++;
112             len++;
113             continue;
114         }
115
116         /* seen a '%' */
117         fp++;
118
119         switch (*fp) {
120
121         case 's':
122             fp++;
123             charp = va_arg(ap, char *);
124             m = strlen(charp);
125             break;
126
127         case 'u':
128             fp++;
129             i = va_arg(ap, uint);
130             sprintf(digits, "%u", i);
131             m = strlen(digits);
132             charp = digits;
133             break;
134         case 'x':
135             fp++;
136             i = va_arg(ap, uint);
137             sprintf(digits, "%x", i);
138             m = strlen(digits);
139             charp = digits;
140             break;
141         case 'd':
142             fp++;
143             i = va_arg(ap, int);
144             sprintf(digits, "%d", i);
145             m = strlen(digits);
146             charp = digits;
147             break;
148         default:
149             syslog(LOG_ERR, "Unknown format character '%c', ignoring it", *fp);
150             continue;
151         }
152
153         if ((len + m + 1) >= n) {
154             break;
155         }
156
157         memcpy(bufp, charp, m);
158         bufp += m;
159         len += m;
160         continue;
161     }
162
163     msg[len] = '\0';
164
165     /* check we never overwrote the end of the buffer */
166     if (msg[n-1]) {
167         abort();
168     }
169
170     va_end(ap);
171
172
173     if (console) {
174         extern int errno;
175
176         if (!ostream)
177             ostream = fopen("/dev/console", "w");
178
179         if (ostream) {
180             if (priority == LOG_ERR)
181                 fprintf(ostream, "Error ");
182             fprintf(ostream, "%s\n", msg);
183         }
184         else
185             syslog(LOG_ERR, "Cannot open /dev/console errno=%d", errno);
186     }
187
188     if (debug) {
189         int logfd;
190
191         logfd = open(logfile, O_CREAT | O_WRONLY | O_APPEND, 0640);
192         if (logfd >= 0) {
193             char buf[512];
194             time_t t = time(NULL);
195             char *ct = ctime(&t);
196
197             ct[24] = '\0';
198             tac_lockfd(logfile, logfd);
199             sprintf(buf, "%s [%d]: ", ct, (int) getpid());
200             write(logfd, buf, strlen(buf));
201             if (priority == LOG_ERR)
202                 write(logfd, "Error ", 6);
203             write(logfd, msg, strlen(msg));
204             write(logfd, "\n", 1);
205             close(logfd);
206         }
207     }
208
209     if (single) {
210         fprintf(stderr, "%s\n", msg);
211     }
212
213     if (priority == LOG_DEBUG)
214         return;
215
216     if (priority == LOG_ERR)
217         syslog(priority, "Error %s", msg);
218     else
219         syslog(priority, "%s", msg);
220 }
221
222 void report_hex TAC_ARGS((int priority, u_char *p, int len));
223
224 /* format a hex dump for syslog */
225 void
226 report_hex(priority, p, len)
227 u_char *p;
228 int len;
229 {
230     char buf[256];
231     char digit[10];
232     int buflen;
233     int i;
234
235     if (len <= 0)
236         return;
237
238     buf[0] = '\0';
239     buflen = 0;
240     for (i = 0; i < len && i < 255; i++, p++) {
241
242         sprintf(digit, "0x%x ", *p);
243         strcat(buf, digit);
244         buflen += strlen(digit);
245
246         if (buflen > 75) {
247             report(priority, "%s", buf);
248             buf[0] = '\0';
249             buflen = 0;
250         }
251     }
252
253     if (buf[0]) {
254         report(priority, "%s", buf);
255     }
256 }
257
258
259 void report_string TAC_ARGS((int priority, u_char *p, int len));
260
261 /* format a non-null terminated string for syslog */
262 void
263 report_string(priority, p, len)
264 u_char *p;
265 int len;
266 {
267     char buf[256];
268     char *bufp = buf;
269     int i;
270
271     if (len <= 0)
272         return;
273
274     for (i = 0; i < len && i < 255; i++) {
275         if (32 <= *p && *p <= 126) {
276             *bufp++ = *p++;
277         } else {
278             sprintf(bufp, " 0x%x ", *p);
279             bufp += strlen(bufp);
280             p++;
281         }
282     }
283     *bufp = '\0';
284     report(priority, "%s", buf);
285 }
286
287 void tac_regerror TAC_ARGS((const char *s));
288
289 void
290 tac_regerror(s)
291 const char *s;
292 {
293     report(LOG_ERR, "in regular expression %s", s);
294 }