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