log.c revision 92555
1/* 2 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * All rights reserved 5 * 6 * As far as I am concerned, the code I have written for this software 7 * can be used freely for any purpose. Any derived versions of this 8 * software must be clearly marked as such, and if the derived work is 9 * incompatible with the protocol description in the RFC file, it must be 10 * called by a name other than "ssh" or "Secure Shell". 11 */ 12/* 13 * Copyright (c) 2000 Markus Friedl. All rights reserved. 14 * 15 * Redistribution and use in source and binary forms, with or without 16 * modification, are permitted provided that the following conditions 17 * are met: 18 * 1. Redistributions of source code must retain the above copyright 19 * notice, this list of conditions and the following disclaimer. 20 * 2. Redistributions in binary form must reproduce the above copyright 21 * notice, this list of conditions and the following disclaimer in the 22 * documentation and/or other materials provided with the distribution. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 27 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 29 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 30 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 33 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 */ 35 36#include "includes.h" 37RCSID("$OpenBSD: log.c,v 1.22 2002/02/22 12:20:34 markus Exp $"); 38 39#include "log.h" 40#include "xmalloc.h" 41 42#include <syslog.h> 43 44static LogLevel log_level = SYSLOG_LEVEL_INFO; 45static int log_on_stderr = 1; 46static int log_facility = LOG_AUTH; 47static char *argv0; 48 49extern char *__progname; 50 51/* textual representation of log-facilities/levels */ 52 53static struct { 54 const char *name; 55 SyslogFacility val; 56} log_facilities[] = { 57 { "DAEMON", SYSLOG_FACILITY_DAEMON }, 58 { "USER", SYSLOG_FACILITY_USER }, 59 { "AUTH", SYSLOG_FACILITY_AUTH }, 60 { "LOCAL0", SYSLOG_FACILITY_LOCAL0 }, 61 { "LOCAL1", SYSLOG_FACILITY_LOCAL1 }, 62 { "LOCAL2", SYSLOG_FACILITY_LOCAL2 }, 63 { "LOCAL3", SYSLOG_FACILITY_LOCAL3 }, 64 { "LOCAL4", SYSLOG_FACILITY_LOCAL4 }, 65 { "LOCAL5", SYSLOG_FACILITY_LOCAL5 }, 66 { "LOCAL6", SYSLOG_FACILITY_LOCAL6 }, 67 { "LOCAL7", SYSLOG_FACILITY_LOCAL7 }, 68 { NULL, SYSLOG_FACILITY_NOT_SET } 69}; 70 71static struct { 72 const char *name; 73 LogLevel val; 74} log_levels[] = 75{ 76 { "QUIET", SYSLOG_LEVEL_QUIET }, 77 { "FATAL", SYSLOG_LEVEL_FATAL }, 78 { "ERROR", SYSLOG_LEVEL_ERROR }, 79 { "INFO", SYSLOG_LEVEL_INFO }, 80 { "VERBOSE", SYSLOG_LEVEL_VERBOSE }, 81 { "DEBUG", SYSLOG_LEVEL_DEBUG1 }, 82 { "DEBUG1", SYSLOG_LEVEL_DEBUG1 }, 83 { "DEBUG2", SYSLOG_LEVEL_DEBUG2 }, 84 { "DEBUG3", SYSLOG_LEVEL_DEBUG3 }, 85 { NULL, SYSLOG_LEVEL_NOT_SET } 86}; 87 88SyslogFacility 89log_facility_number(char *name) 90{ 91 int i; 92 if (name != NULL) 93 for (i = 0; log_facilities[i].name; i++) 94 if (strcasecmp(log_facilities[i].name, name) == 0) 95 return log_facilities[i].val; 96 return SYSLOG_FACILITY_NOT_SET; 97} 98 99LogLevel 100log_level_number(char *name) 101{ 102 int i; 103 if (name != NULL) 104 for (i = 0; log_levels[i].name; i++) 105 if (strcasecmp(log_levels[i].name, name) == 0) 106 return log_levels[i].val; 107 return SYSLOG_LEVEL_NOT_SET; 108} 109 110/* Error messages that should be logged. */ 111 112void 113error(const char *fmt,...) 114{ 115 va_list args; 116 va_start(args, fmt); 117 do_log(SYSLOG_LEVEL_ERROR, fmt, args); 118 va_end(args); 119} 120 121/* Log this message (information that usually should go to the log). */ 122 123void 124log(const char *fmt,...) 125{ 126 va_list args; 127 va_start(args, fmt); 128 do_log(SYSLOG_LEVEL_INFO, fmt, args); 129 va_end(args); 130} 131 132/* More detailed messages (information that does not need to go to the log). */ 133 134void 135verbose(const char *fmt,...) 136{ 137 va_list args; 138 va_start(args, fmt); 139 do_log(SYSLOG_LEVEL_VERBOSE, fmt, args); 140 va_end(args); 141} 142 143/* Debugging messages that should not be logged during normal operation. */ 144 145void 146debug(const char *fmt,...) 147{ 148 va_list args; 149 va_start(args, fmt); 150 do_log(SYSLOG_LEVEL_DEBUG1, fmt, args); 151 va_end(args); 152} 153 154void 155debug2(const char *fmt,...) 156{ 157 va_list args; 158 va_start(args, fmt); 159 do_log(SYSLOG_LEVEL_DEBUG2, fmt, args); 160 va_end(args); 161} 162 163void 164debug3(const char *fmt,...) 165{ 166 va_list args; 167 va_start(args, fmt); 168 do_log(SYSLOG_LEVEL_DEBUG3, fmt, args); 169 va_end(args); 170} 171 172/* Fatal cleanup */ 173 174struct fatal_cleanup { 175 struct fatal_cleanup *next; 176 void (*proc) (void *); 177 void *context; 178}; 179 180static struct fatal_cleanup *fatal_cleanups = NULL; 181 182/* Registers a cleanup function to be called by fatal() before exiting. */ 183 184void 185fatal_add_cleanup(void (*proc) (void *), void *context) 186{ 187 struct fatal_cleanup *cu; 188 189 cu = xmalloc(sizeof(*cu)); 190 cu->proc = proc; 191 cu->context = context; 192 cu->next = fatal_cleanups; 193 fatal_cleanups = cu; 194} 195 196/* Removes a cleanup frunction to be called at fatal(). */ 197 198void 199fatal_remove_cleanup(void (*proc) (void *context), void *context) 200{ 201 struct fatal_cleanup **cup, *cu; 202 203 for (cup = &fatal_cleanups; *cup; cup = &cu->next) { 204 cu = *cup; 205 if (cu->proc == proc && cu->context == context) { 206 *cup = cu->next; 207 xfree(cu); 208 return; 209 } 210 } 211 fatal("fatal_remove_cleanup: no such cleanup function: 0x%lx 0x%lx", 212 (u_long) proc, (u_long) context); 213} 214 215/* Cleanup and exit */ 216void 217fatal_cleanup(void) 218{ 219 struct fatal_cleanup *cu, *next_cu; 220 static int called = 0; 221 222 if (called) 223 exit(255); 224 called = 1; 225 /* Call cleanup functions. */ 226 for (cu = fatal_cleanups; cu; cu = next_cu) { 227 next_cu = cu->next; 228 debug("Calling cleanup 0x%lx(0x%lx)", 229 (u_long) cu->proc, (u_long) cu->context); 230 (*cu->proc) (cu->context); 231 } 232 exit(255); 233} 234 235 236/* 237 * Initialize the log. 238 */ 239 240void 241log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr) 242{ 243 argv0 = av0; 244 245 switch (level) { 246 case SYSLOG_LEVEL_QUIET: 247 case SYSLOG_LEVEL_FATAL: 248 case SYSLOG_LEVEL_ERROR: 249 case SYSLOG_LEVEL_INFO: 250 case SYSLOG_LEVEL_VERBOSE: 251 case SYSLOG_LEVEL_DEBUG1: 252 case SYSLOG_LEVEL_DEBUG2: 253 case SYSLOG_LEVEL_DEBUG3: 254 log_level = level; 255 break; 256 default: 257 fprintf(stderr, "Unrecognized internal syslog level code %d\n", 258 (int) level); 259 exit(1); 260 } 261 262 log_on_stderr = on_stderr; 263 if (on_stderr) 264 return; 265 266 switch (facility) { 267 case SYSLOG_FACILITY_DAEMON: 268 log_facility = LOG_DAEMON; 269 break; 270 case SYSLOG_FACILITY_USER: 271 log_facility = LOG_USER; 272 break; 273 case SYSLOG_FACILITY_AUTH: 274 log_facility = LOG_AUTH; 275 break; 276 case SYSLOG_FACILITY_LOCAL0: 277 log_facility = LOG_LOCAL0; 278 break; 279 case SYSLOG_FACILITY_LOCAL1: 280 log_facility = LOG_LOCAL1; 281 break; 282 case SYSLOG_FACILITY_LOCAL2: 283 log_facility = LOG_LOCAL2; 284 break; 285 case SYSLOG_FACILITY_LOCAL3: 286 log_facility = LOG_LOCAL3; 287 break; 288 case SYSLOG_FACILITY_LOCAL4: 289 log_facility = LOG_LOCAL4; 290 break; 291 case SYSLOG_FACILITY_LOCAL5: 292 log_facility = LOG_LOCAL5; 293 break; 294 case SYSLOG_FACILITY_LOCAL6: 295 log_facility = LOG_LOCAL6; 296 break; 297 case SYSLOG_FACILITY_LOCAL7: 298 log_facility = LOG_LOCAL7; 299 break; 300 default: 301 fprintf(stderr, 302 "Unrecognized internal syslog facility code %d\n", 303 (int) facility); 304 exit(1); 305 } 306} 307 308#define MSGBUFSIZ 1024 309 310void 311do_log(LogLevel level, const char *fmt, va_list args) 312{ 313 char msgbuf[MSGBUFSIZ]; 314 char fmtbuf[MSGBUFSIZ]; 315 char *txt = NULL; 316 int pri = LOG_INFO; 317 318 if (level > log_level) 319 return; 320 321 switch (level) { 322 case SYSLOG_LEVEL_FATAL: 323 if (!log_on_stderr) 324 txt = "fatal"; 325 pri = LOG_CRIT; 326 break; 327 case SYSLOG_LEVEL_ERROR: 328 if (!log_on_stderr) 329 txt = "error"; 330 pri = LOG_ERR; 331 break; 332 case SYSLOG_LEVEL_INFO: 333 pri = LOG_INFO; 334 break; 335 case SYSLOG_LEVEL_VERBOSE: 336 pri = LOG_INFO; 337 break; 338 case SYSLOG_LEVEL_DEBUG1: 339 txt = "debug1"; 340 pri = LOG_DEBUG; 341 break; 342 case SYSLOG_LEVEL_DEBUG2: 343 txt = "debug2"; 344 pri = LOG_DEBUG; 345 break; 346 case SYSLOG_LEVEL_DEBUG3: 347 txt = "debug3"; 348 pri = LOG_DEBUG; 349 break; 350 default: 351 txt = "internal error"; 352 pri = LOG_ERR; 353 break; 354 } 355 if (txt != NULL) { 356 snprintf(fmtbuf, sizeof(fmtbuf), "%s: %s", txt, fmt); 357 vsnprintf(msgbuf, sizeof(msgbuf), fmtbuf, args); 358 } else { 359 vsnprintf(msgbuf, sizeof(msgbuf), fmt, args); 360 } 361 if (log_on_stderr) { 362 fprintf(stderr, "%s\r\n", msgbuf); 363 } else { 364 openlog(argv0 ? argv0 : __progname, LOG_PID, log_facility); 365 syslog(pri, "%.500s", msgbuf); 366 closelog(); 367 } 368} 369