log.c revision 1.14
1/* $OpenBSD: log.c,v 1.14 2000/12/12 05:12:45 todd Exp $ */ 2/* $EOM: log.c,v 1.30 2000/09/29 08:19:23 niklas Exp $ */ 3 4/* 5 * Copyright (c) 1998, 1999 Niklas Hallqvist. All rights reserved. 6 * Copyright (c) 1999, 2000 H�kan Olsson. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by Ericsson Radio Systems. 19 * 4. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34/* 35 * This code was written under funding by Ericsson Radio Systems. 36 */ 37 38#include <sys/time.h> 39#include <errno.h> 40#include <stdio.h> 41#include <string.h> 42#include <syslog.h> 43#ifdef __STDC__ 44#include <stdarg.h> 45#else 46#include <varargs.h> 47#endif 48 49#include "log.h" 50 51static void _log_print (int, int, const char *, va_list, int, int); 52 53static FILE *log_output; 54#ifdef USE_DEBUG 55static int log_level[LOG_ENDCLASS]; 56#endif 57 58void 59log_init (void) 60{ 61 log_output = stderr; 62} 63 64void 65log_to (FILE *f) 66{ 67 if (!log_output && f) 68 closelog (); 69 log_output = f; 70 if (!f) 71 openlog ("isakmpd", LOG_PID | LOG_CONS, LOG_DAEMON); 72} 73 74FILE * 75log_current (void) 76{ 77 return log_output; 78} 79 80static char * 81_log_get_class (int error_class) 82{ 83 /* XXX For test purposes. To be removed later on? */ 84 static char *class_text[] = LOG_CLASSES_TEXT; 85 86 if (error_class < 0) 87 return "Dflt"; 88 else if (error_class >= LOG_ENDCLASS) 89 return "Unkn"; 90 else 91 return class_text[error_class]; 92} 93 94static void 95_log_print (int error, int syslog_level, const char *fmt, va_list ap, 96 int class, int level) 97{ 98 char buffer[LOG_SIZE], nbuf[LOG_SIZE + 32]; 99 static const char fallback_msg[] = 100 "write to log file failed (errno %d), redirecting output to syslog"; 101 int len; 102 struct tm *tm; 103 struct timeval now; 104 time_t t; 105 106 len = vsnprintf (buffer, LOG_SIZE, fmt, ap); 107 if (len < LOG_SIZE - 1 && error) 108 snprintf (buffer + len, LOG_SIZE - len, ": %s", strerror (errno)); 109 if (log_output) 110 { 111 gettimeofday (&now, 0); 112 t = now.tv_sec; 113 tm = localtime (&t); 114 if (class >= 0) 115 sprintf (nbuf, "%02d%02d%02d.%06ld %s %02d ", tm->tm_hour, 116 tm->tm_min, tm->tm_sec, now.tv_usec, _log_get_class (class), 117 level); 118 else /* LOG_PRINT (-1) or LOG_REPORT (-2) */ 119 sprintf (nbuf, "%02d%02d%02d.%06ld %s ", tm->tm_hour, 120 tm->tm_min, tm->tm_sec, now.tv_usec, 121 class == LOG_PRINT ? "Default" : "Report>"); 122 strcat (nbuf, buffer); 123 strcat (nbuf, "\n"); 124 125 if (fwrite (nbuf, strlen (nbuf), 1, log_output) == 0) 126 { 127 /* Report fallback. */ 128 syslog (LOG_ALERT, fallback_msg, errno); 129 fprintf (log_output, fallback_msg, errno); 130 131 /* 132 * Close log_output to prevent isakmpd from locking the file. 133 * We may need to explicitly close stdout to do this properly. 134 * XXX - Figure out how to match two FILE *'s and rewrite. 135 */ 136 if (fileno (log_output) != -1) 137 if (fileno (stdout) == fileno (log_output)) 138 fclose (stdout); 139 fclose (log_output); 140 141 /* Fallback to syslog. */ 142 log_to (0); 143 144 /* (Re)send current message to syslog(). */ 145 syslog (class == LOG_REPORT ? LOG_ALERT : syslog_level, "%s", buffer); 146 } 147 } 148 else 149 syslog (class == LOG_REPORT ? LOG_ALERT : syslog_level, "%s", buffer); 150} 151 152#ifdef USE_DEBUG 153void 154#ifdef __STDC__ 155log_debug (int cls, int level, const char *fmt, ...) 156#else 157log_debug (cls, level, fmt, va_alist) 158 int cls; 159 int level; 160 const char *fmt; 161 va_dcl 162#endif 163{ 164 va_list ap; 165 166 /* 167 * If we are not debugging this class, or the level is too low, just return. 168 */ 169 if (cls >= 0 && (log_level[cls] == 0 || level > log_level[cls])) 170 return; 171#ifdef __STDC__ 172 va_start (ap, fmt); 173#else 174 va_start (ap); 175 fmt = va_arg (ap, const char *); 176#endif 177 _log_print (0, LOG_DEBUG, fmt, ap, cls, level); 178 va_end (ap); 179} 180 181void 182log_debug_buf (int cls, int level, const char *header, const u_int8_t *buf, 183 size_t sz) 184{ 185 char s[73]; 186 int i, j; 187 188 /* 189 * If we are not debugging this class, or the level is too low, just return. 190 */ 191 if (cls >= 0 && (log_level[cls] == 0 || level > log_level[cls])) 192 return; 193 194 log_debug (cls, level, "%s:", header); 195 for (i = j = 0; i < sz;) 196 { 197 sprintf (s + j, "%02x", buf[i++]); 198 j += 2; 199 if (i % 4 == 0) 200 { 201 if (i % 32 == 0) 202 { 203 s[j] = '\0'; 204 log_debug (cls, level, "%s", s); 205 j = 0; 206 } 207 else 208 s[j++] = ' '; 209 } 210 } 211 if (j) 212 { 213 s[j] = '\0'; 214 log_debug (cls, level, "%s", s); 215 } 216} 217 218void 219log_debug_cmd (int cls, int level) 220{ 221 if (cls < 0 || cls >= LOG_ENDCLASS) 222 { 223 log_print ("log_debug_cmd: invalid debugging class %d", cls); 224 return; 225 } 226 227 if (level < 0) 228 { 229 log_print ("log_debug_cmd: invalid debugging level %d for class %d", 230 level, cls); 231 return; 232 } 233 234 if (level == log_level[cls]) 235 log_print ("log_debug_cmd: log level unchanged for class %d", cls); 236 else 237 { 238 log_print ("log_debug_cmd: log level changed from %d to %d for class %d", 239 log_level[cls], level, cls); 240 log_level[cls] = level; 241 } 242} 243#endif /* USE_DEBUG */ 244 245void 246#ifdef __STDC__ 247log_print (const char *fmt, ...) 248#else 249log_print (fmt, va_alist) 250 const char *fmt; 251 va_dcl 252#endif 253{ 254 va_list ap; 255 256#ifdef __STDC__ 257 va_start (ap, fmt); 258#else 259 va_start (ap); 260 fmt = va_arg (ap, const char *); 261#endif 262 _log_print (0, LOG_NOTICE, fmt, ap, LOG_PRINT, 0); 263 va_end (ap); 264} 265 266void 267#ifdef __STDC__ 268log_error (const char *fmt, ...) 269#else 270log_error (fmt, va_alist) 271 const char *fmt; 272 va_dcl 273#endif 274{ 275 va_list ap; 276 277#ifdef __STDC__ 278 va_start (ap, fmt); 279#else 280 va_start (ap); 281 fmt = va_arg (ap, const char *); 282#endif 283 _log_print (1, LOG_ERR, fmt, ap, LOG_PRINT, 0); 284 va_end (ap); 285} 286 287void 288#ifdef __STDC__ 289log_fatal (const char *fmt, ...) 290#else 291log_fatal (fmt, va_alist) 292 const char *fmt; 293 va_dcl 294#endif 295{ 296 va_list ap; 297 298#ifdef __STDC__ 299 va_start (ap, fmt); 300#else 301 va_start (ap); 302 fmt = va_arg (ap, const char *); 303#endif 304 _log_print (1, LOG_CRIT, fmt, ap, LOG_PRINT, 0); 305 va_end (ap); 306 exit (1); 307} 308