log.c revision 1.7
1/* $OpenBSD: log.c,v 1.7 1999/07/07 22:11:14 niklas Exp $ */ 2/* $EOM: log.c,v 1.24 1999/06/26 23:26:56 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 = stderr; 55static int log_level[LOG_ENDCLASS]; 56 57void 58log_to (FILE *f) 59{ 60 if (!log_output && f) 61 closelog (); 62 log_output = f; 63 if (!f) 64 openlog ("isakmpd", LOG_CONS, LOG_DAEMON); 65} 66 67FILE * 68log_current (void) 69{ 70 return log_output; 71} 72 73static char * 74_log_get_class (int error_class) 75{ 76 /* XXX For test purposes. To be removed later on? */ 77 static char *class_text[] = LOG_CLASSES_TEXT; 78 79 if (error_class < 0) 80 return "Dflt"; 81 else if (error_class >= LOG_ENDCLASS) 82 return "Unkn"; 83 else 84 return class_text[error_class]; 85} 86 87static void 88_log_print (int error, int syslog_level, const char *fmt, va_list ap, 89 int class, int level) 90{ 91 char buffer[LOG_SIZE], nbuf[LOG_SIZE + 32]; 92 static const char fallback_msg[] = 93 "write to log file failed (errno %d), redirecting output to syslog"; 94 int len; 95 struct tm *tm; 96 struct timeval now; 97 time_t t; 98 99 len = vsnprintf (buffer, LOG_SIZE, fmt, ap); 100 if (len < LOG_SIZE - 1 && error) 101 snprintf (buffer + len, LOG_SIZE - len, ": %s", strerror (errno)); 102 if (log_output) 103 { 104 gettimeofday (&now, 0); 105 t = now.tv_sec; 106 tm = localtime (&t); 107 if (class >= 0) 108 sprintf (nbuf, "%02d%02d%02d.%06ld %s %02d ", tm->tm_hour, 109 tm->tm_min, tm->tm_sec, now.tv_usec, _log_get_class (class), 110 level); 111 else /* LOG_PRINT (-1) or LOG_REPORT (-2) */ 112 sprintf (nbuf, "%02d%02d%02d.%06ld %s ", tm->tm_hour, 113 tm->tm_min, tm->tm_sec, now.tv_usec, 114 class == LOG_PRINT ? "Default" : "Report>"); 115 strcat (nbuf, buffer); 116 strcat (nbuf, "\n"); 117 118 if (fwrite (nbuf, strlen (nbuf), 1, log_output) == 0) 119 { 120 /* Report fallback. */ 121 syslog (LOG_ALERT, fallback_msg, errno); 122 fprintf (log_output, fallback_msg, errno); 123 124 /* 125 * Close log_output to prevent isakmpd from locking the file. 126 * We may need to explicitly close stdout to do this properly. 127 * XXX - Figure out how to match two FILE *'s and rewrite. 128 */ 129 if (log_output->_file != -1) 130 if (stdout->_file == log_output->_file) 131 fclose (stdout); 132 fclose (log_output); 133 134 /* Fallback to syslog. */ 135 log_to (0); 136 137 /* (Re)send current message to syslog(). */ 138 syslog (class == LOG_REPORT ? LOG_ALERT : syslog_level, buffer); 139 } 140 } 141 else 142 syslog (class == LOG_REPORT ? LOG_ALERT : syslog_level, buffer); 143} 144 145void 146#ifdef __STDC__ 147log_debug (int cls, int level, const char *fmt, ...) 148#else 149log_debug (cls, level, fmt, va_alist) 150 int cls; 151 int level; 152 const char *fmt; 153 va_dcl 154#endif 155{ 156 va_list ap; 157 158 /* 159 * If we are not debugging this class, or the level is too low, just return. 160 */ 161 if (cls >= 0 && (log_level[cls] == 0 || level > log_level[cls])) 162 return; 163#ifdef __STDC__ 164 va_start (ap, fmt); 165#else 166 va_start (ap); 167 fmt = va_arg (ap, const char *); 168#endif 169 _log_print (0, LOG_DEBUG, fmt, ap, cls, level); 170 va_end (ap); 171} 172 173void 174log_debug_buf (int cls, int level, const char *header, const u_int8_t *buf, 175 size_t sz) 176{ 177 char s[73]; 178 int i, j; 179 180 /* 181 * If we are not debugging this class, or the level is too low, just return. 182 */ 183 if (cls >= 0 && (log_level[cls] == 0 || level > log_level[cls])) 184 return; 185 186 log_debug (cls, level, "%s:", header); 187 for (i = j = 0; i < sz;) 188 { 189 sprintf (s + j, "%02x", buf[i++]); 190 j += 2; 191 if (i % 4 == 0) 192 { 193 if (i % 32 == 0) 194 { 195 s[j] = '\0'; 196 log_debug (cls, level, "%s", s); 197 j = 0; 198 } 199 else 200 s[j++] = ' '; 201 } 202 } 203 if (j) 204 { 205 s[j] = '\0'; 206 log_debug (cls, level, "%s", s); 207 } 208} 209 210void 211#ifdef __STDC__ 212log_print (const char *fmt, ...) 213#else 214log_print (fmt, va_alist) 215 const char *fmt; 216 va_dcl 217#endif 218{ 219 va_list ap; 220 221#ifdef __STDC__ 222 va_start (ap, fmt); 223#else 224 va_start (ap); 225 fmt = va_arg (ap, const char *); 226#endif 227 _log_print (0, LOG_NOTICE, fmt, ap, LOG_PRINT, 0); 228 va_end (ap); 229} 230 231void 232#ifdef __STDC__ 233log_error (const char *fmt, ...) 234#else 235log_error (fmt, va_alist) 236 const char *fmt; 237 va_dcl 238#endif 239{ 240 va_list ap; 241 242#ifdef __STDC__ 243 va_start (ap, fmt); 244#else 245 va_start (ap); 246 fmt = va_arg (ap, const char *); 247#endif 248 _log_print (1, LOG_ERR, fmt, ap, LOG_PRINT, 0); 249 va_end (ap); 250} 251 252void 253#ifdef __STDC__ 254log_fatal (const char *fmt, ...) 255#else 256log_fatal (fmt, va_alist) 257 const char *fmt; 258 va_dcl 259#endif 260{ 261 va_list ap; 262 263#ifdef __STDC__ 264 va_start (ap, fmt); 265#else 266 va_start (ap); 267 fmt = va_arg (ap, const char *); 268#endif 269 _log_print (1, LOG_CRIT, fmt, ap, LOG_PRINT, 0); 270 va_end (ap); 271 exit (1); 272} 273 274void 275log_debug_cmd (int cls, int level) 276{ 277 if (cls < 0 || cls >= LOG_ENDCLASS) 278 { 279 log_print ("log_debug_cmd: invalid debugging class %d", cls); 280 return; 281 } 282 283 if (level < 0) 284 { 285 log_print ("log_debug_cmd: invalid debugging level %d for class %d", 286 level, cls); 287 return; 288 } 289 290 if (level == log_level[cls]) 291 log_print ("log_debug_cmd: log level unchanged for class %d", cls); 292 else 293 { 294 log_print ("log_debug_cmd: log level changed from %d to %d for class %d", 295 log_level[cls], level, cls); 296 log_level[cls] = level; 297 } 298} 299