1 /* $NetBSD: log.c,v 1.1.1.1 2015/07/08 15:37:48 christos Exp $ */ 2 3 /***************************************************************** 4 ** 5 ** @(#) log.c -- The ZKT error logging module 6 ** 7 ** Copyright (c) June 2008, Holger Zuleger HZnet. All rights reserved. 8 ** 9 ** This software is open source. 10 ** 11 ** Redistribution and use in source and binary forms, with or without 12 ** modification, are permitted provided that the following conditions 13 ** are met: 14 ** 15 ** Redistributions of source code must retain the above copyright notice, 16 ** this list of conditions and the following disclaimer. 17 ** 18 ** Redistributions in binary form must reproduce the above copyright notice, 19 ** this list of conditions and the following disclaimer in the documentation 20 ** and/or other materials provided with the distribution. 21 ** 22 ** Neither the name of Holger Zuleger HZnet nor the names of its contributors may 23 ** be used to endorse or promote products derived from this software without 24 ** specific prior written permission. 25 ** 26 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 27 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 ** TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 ** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE 30 ** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 ** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 ** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 ** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 ** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 ** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 ** POSSIBILITY OF SUCH DAMAGE. 37 ** 38 ** 39 *****************************************************************/ 40 # include <stdio.h> 41 # include <string.h> 42 # include <stdlib.h> 43 # include <ctype.h> 44 # include <sys/types.h> 45 # include <sys/stat.h> 46 # include <sys/time.h> 47 # include <time.h> 48 # include <assert.h> 49 # include <errno.h> 50 # include <syslog.h> 51 #ifdef HAVE_CONFIG_H 52 # include <config.h> 53 #endif 54 # include "config_zkt.h" 55 # include "misc.h" 56 # include "debug.h" 57 #define extern 58 # include "log.h" 59 #undef extern 60 61 /***************************************************************** 62 ** module internal vars & declarations 63 *****************************************************************/ 64 static FILE *lg_fp; 65 static FILE *lg_fpsave; 66 static int lg_minfilelevel; 67 static int lg_syslogging; 68 static int lg_minsyslevel; 69 static long lg_errcnt; 70 static const char *lg_progname; 71 72 typedef struct { 73 lg_lvl_t level; 74 const char *str; 75 int syslog_level; 76 } lg_symtbl_t; 77 78 static lg_symtbl_t symtbl[] = { 79 { LG_NONE, "none", -1 }, 80 { LG_DEBUG, "debug", LOG_DEBUG }, 81 { LG_INFO, "info", LOG_INFO }, 82 { LG_NOTICE, "notice", LOG_NOTICE }, 83 { LG_WARNING, "warning", LOG_WARNING }, 84 { LG_ERROR, "error", LOG_ERR }, 85 { LG_FATAL, "fatal", LOG_CRIT }, 86 87 { LG_NONE, "user", LOG_USER }, 88 { LG_NONE, "daemon", LOG_DAEMON }, 89 { LG_NONE, "local0", LOG_LOCAL0 }, 90 { LG_NONE, "local1", LOG_LOCAL1 }, 91 { LG_NONE, "local2", LOG_LOCAL2 }, 92 { LG_NONE, "local3", LOG_LOCAL3 }, 93 { LG_NONE, "local4", LOG_LOCAL4 }, 94 { LG_NONE, "local5", LOG_LOCAL5 }, 95 { LG_NONE, "local6", LOG_LOCAL6 }, 96 { LG_NONE, "local7", LOG_LOCAL7 }, 97 { LG_NONE, NULL, -1 } 98 }; 99 100 # define MAXFNAME (1023) 101 /***************************************************************** 102 ** function definitions (for function declarations see log.h) 103 *****************************************************************/ 104 105 /***************************************************************** 106 ** lg_fileopen (path, name) -- open the log file 107 ** Name is a (absolute or relative) file or directory name. 108 ** If path is given and name is a relative path name then path 109 ** is prepended to name. 110 ** returns the open file pointer or NULL on error 111 *****************************************************************/ 112 static FILE *lg_fileopen (const char *path, const char *name) 113 { 114 int len; 115 FILE *fp; 116 struct tm *t; 117 time_t sec; 118 char fname[MAXFNAME+1]; 119 120 if ( name == NULL || *name == '\0' ) 121 return NULL; 122 else if ( *name == '/' || path == NULL ) 123 snprintf (fname, MAXFNAME, "%s", name); 124 else 125 snprintf (fname, MAXFNAME, "%s/%s", path, name); 126 127 # ifdef LOG_TEST 128 fprintf (stderr, "\t ==> \"%s\"", fname); 129 # endif 130 if ( is_directory (fname) ) 131 { 132 len = strlen (fname); 133 134 time (&sec); 135 t = gmtime (&sec); 136 snprintf (fname+len, MAXFNAME-len, LOG_FNAMETMPL, 137 t->tm_year + 1900, t->tm_mon+1, t->tm_mday, 138 t->tm_hour, t->tm_min, t->tm_sec); 139 # ifdef LOG_TEST 140 fprintf (stderr, " isdir \"%s\"", fname); 141 # endif 142 } 143 144 # ifdef LOG_TEST 145 fprintf (stderr, "\n"); 146 # endif 147 148 if ( (fp = fopen (fname, "a")) == NULL ) 149 return NULL; 150 151 return fp; 152 } 153 154 /***************************************************************** 155 ** lg_str2lvl (level_name) 156 *****************************************************************/ 157 lg_lvl_t lg_str2lvl (const char *name) 158 { 159 lg_symtbl_t *p; 160 161 if ( !name ) 162 return LG_NONE; 163 164 for ( p = symtbl; p->str; p++ ) 165 if ( strcasecmp (name, p->str) == 0 ) 166 return p->level; 167 168 return LG_NONE; 169 } 170 171 /***************************************************************** 172 ** lg_lvl2syslog (level) 173 *****************************************************************/ 174 lg_lvl_t lg_lvl2syslog (lg_lvl_t level) 175 { 176 lg_symtbl_t *p; 177 178 for ( p = symtbl; p->str; p++ ) 179 if ( level == p->level ) 180 return p->syslog_level; 181 182 assert ( p->str != NULL ); /* we assume not to reach this! */ 183 184 return LOG_DEBUG; /* if not found, return DEBUG as default */ 185 } 186 187 /***************************************************************** 188 ** lg_str2syslog (facility_name) 189 *****************************************************************/ 190 int lg_str2syslog (const char *facility) 191 { 192 lg_symtbl_t *p; 193 194 dbg_val1 ("lg_str2syslog (%s)\n", facility); 195 if ( !facility ) 196 return LG_NONE; 197 198 for ( p = symtbl; p->str; p++ ) 199 if ( strcasecmp (facility, p->str) == 0 ) 200 return p->syslog_level; 201 202 return LG_NONE; 203 } 204 205 /***************************************************************** 206 ** lg_lvl2str (level) 207 *****************************************************************/ 208 const char *lg_lvl2str (lg_lvl_t level) 209 { 210 lg_symtbl_t *p; 211 212 if ( level < LG_DEBUG ) 213 return "none"; 214 215 for ( p = symtbl; p->str; p++ ) 216 if ( level == p->level ) 217 return p->str; 218 return "fatal"; 219 } 220 221 /***************************************************************** 222 ** lg_geterrcnt () -- returns the current value of the internal 223 ** error counter 224 *****************************************************************/ 225 long lg_geterrcnt () 226 { 227 return lg_errcnt; 228 } 229 230 /***************************************************************** 231 ** lg_seterrcnt () -- sets the internal error counter 232 ** returns the current value 233 *****************************************************************/ 234 long lg_seterrcnt (long value) 235 { 236 return lg_errcnt = value; 237 } 238 239 /***************************************************************** 240 ** lg_reseterrcnt () -- resets the internal error counter to 0 241 ** returns the current value 242 *****************************************************************/ 243 long lg_reseterrcnt () 244 { 245 return lg_seterrcnt (0L); 246 } 247 248 249 /***************************************************************** 250 ** lg_open (prog, facility, syslevel, path, file, filelevel) 251 ** -- open the log channel 252 ** return values: 253 ** 0 on success 254 ** -1 on file open error 255 *****************************************************************/ 256 int lg_open (const char *progname, const char *facility, const char *syslevel, const char *path, const char *file, const char *filelevel) 257 { 258 int sysfacility; 259 260 dbg_val6 ("lg_open (%s, %s, %s, %s, %s, %s)\n", progname, facility, syslevel, path, file, filelevel); 261 262 lg_minsyslevel = lg_str2lvl (syslevel); 263 lg_minfilelevel = lg_str2lvl (filelevel); 264 265 sysfacility = lg_str2syslog (facility); 266 if ( sysfacility >= 0 ) 267 { 268 lg_syslogging = 1; 269 dbg_val2 ("lg_open: openlog (%s, LOG_NDELAY, %d)\n", progname, lg_str2syslog (facility)); 270 openlog (progname, LOG_NDELAY, lg_str2syslog (facility)); 271 } 272 if ( file && * file ) 273 { 274 if ( (lg_fp = lg_fileopen (path, file)) == NULL ) 275 return -1; 276 lg_progname = progname; 277 } 278 279 return 0; 280 } 281 282 /***************************************************************** 283 ** lg_close () -- close the open filepointer for error logging 284 ** return 0 if no error log file is currently open, 285 ** otherwise the return code of fclose is returned. 286 *****************************************************************/ 287 int lg_close () 288 { 289 int ret = 0; 290 291 if ( lg_syslogging ) 292 { 293 closelog (); 294 lg_syslogging = 0; 295 } 296 if ( lg_fp ) 297 { 298 ret = fclose (lg_fp); 299 lg_fp = NULL; 300 } 301 302 return ret; 303 } 304 305 /***************************************************************** 306 ** lg_zone_start (domain) 307 ** -- reopen the log channel 308 ** return values: 309 ** 0 on success 310 ** -1 on file open error 311 *****************************************************************/ 312 int lg_zone_start (const char *dir, const char *domain) 313 { 314 char fname[255+1]; 315 316 dbg_val2 ("lg_zone_start (%s, %s)\n", dir, domain); 317 318 snprintf (fname, sizeof (fname), LOG_DOMAINTMPL, domain); 319 if ( lg_fp ) 320 lg_fpsave = lg_fp; 321 lg_fp = lg_fileopen (dir, fname); 322 323 return lg_fp != NULL; 324 } 325 326 /***************************************************************** 327 ** lg_zone_end (domain) 328 ** -- close the (reopened) log channel 329 ** return values: 330 ** 0 on success 331 ** -1 on file open error 332 *****************************************************************/ 333 int lg_zone_end () 334 { 335 if ( lg_fp && lg_fpsave ) 336 { 337 lg_close (); 338 lg_fp = lg_fpsave; 339 lg_fpsave = NULL; 340 return 1; 341 } 342 343 return 0; 344 } 345 346 /***************************************************************** 347 ** 348 ** lg_args (level, argc, argv[]) 349 ** log all command line arguments (up to a length of 511 chars) 350 ** with priority level 351 ** 352 *****************************************************************/ 353 void lg_args (lg_lvl_t level, int argc, char * const argv[]) 354 { 355 char cmdline[511+1]; 356 int len; 357 int i; 358 359 len = 0; 360 for ( i = 0; i < argc && len < sizeof (cmdline); i++ ) 361 len += snprintf (cmdline+len, sizeof (cmdline) - len, " %s", argv[i]); 362 363 #if 1 364 lg_mesg (level, "------------------------------------------------------------"); 365 #else 366 lg_mesg (level, ""); 367 #endif 368 lg_mesg (level, "running%s ", cmdline); 369 } 370 371 /***************************************************************** 372 ** 373 ** lg_mesg (level, fmt, ...) 374 ** 375 ** Write a given message to the error log file and counts 376 ** all messages written with an level greater than LOG_ERR. 377 ** 378 ** All messages will be on one line in the logfile, so it's 379 ** not necessary to add an '\n' to the message. 380 ** 381 ** To call this function before an elog_open() is called is 382 ** useless! 383 ** 384 *****************************************************************/ 385 void lg_mesg (int priority, char *fmt, ...) 386 { 387 va_list ap; 388 struct timeval tv; 389 struct tm *t; 390 char format[256]; 391 392 assert (fmt != NULL); 393 assert (priority >= LG_DEBUG && priority <= LG_FATAL); 394 395 format[0] ='\0'; 396 397 dbg_val3 ("syslog = %d prio = %d >= sysmin = %d\n", lg_syslogging, priority, lg_minsyslevel); 398 if ( lg_syslogging && priority >= lg_minsyslevel ) 399 { 400 #if defined (LOG_WITH_LEVEL) && LOG_WITH_LEVEL 401 snprintf (format, sizeof (format), "%s: %s", lg_lvl2str(priority), fmt); 402 fmt = format; 403 #endif 404 va_start(ap, fmt); 405 vsyslog (lg_lvl2syslog (priority), fmt, ap); 406 va_end(ap); 407 } 408 409 dbg_val3 ("filelg = %d prio = %d >= filmin = %d\n", lg_fp!=NULL, priority, lg_minfilelevel); 410 if ( lg_fp && priority >= lg_minfilelevel ) 411 { 412 #if defined (LOG_WITH_TIMESTAMP) && LOG_WITH_TIMESTAMP 413 gettimeofday (&tv, NULL); 414 t = localtime ((time_t *) &tv.tv_sec); 415 fprintf (lg_fp, "%04d-%02d-%02d ", 416 t->tm_year+1900, t->tm_mon+1, t->tm_mday); 417 fprintf (lg_fp, "%02d:%02d:%02d.%03ld: ", 418 t->tm_hour, t->tm_min, t->tm_sec, tv.tv_usec / 1000); 419 #endif 420 #if defined (LOG_WITH_PROGNAME) && LOG_WITH_PROGNAME 421 if ( lg_progname ) 422 fprintf (lg_fp, "%s: ", lg_progname); 423 #endif 424 #if defined (LOG_WITH_LEVEL) && LOG_WITH_LEVEL 425 if ( fmt != format ) /* level is not in fmt string */ 426 fprintf (lg_fp, "%s: ", lg_lvl2str(priority)); 427 #endif 428 va_start(ap, fmt); 429 vfprintf (lg_fp, fmt, ap); 430 va_end(ap); 431 fprintf (lg_fp, "\n"); 432 } 433 434 if ( priority >= LG_ERROR ) 435 lg_errcnt++; 436 } 437 438 439 #ifdef LOG_TEST 440 const char *progname; 441 int main (int argc, char *argv[]) 442 { 443 const char *levelstr; 444 const char *newlevelstr; 445 int level; 446 int err; 447 448 progname = *argv; 449 450 if ( --argc ) 451 levelstr = *++argv; 452 else 453 levelstr = "fatal"; 454 455 level = lg_str2lvl (levelstr); 456 newlevelstr = lg_lvl2str (level+1); 457 dbg_val4 ("base level = %s(%d) newlevel = %s(%d)\n", levelstr, level, newlevelstr, level+1); 458 if ( (err = lg_open (progname, 459 #if 1 460 "user", 461 #else 462 "none", 463 #endif 464 levelstr, ".", 465 #if 1 466 "test.log", 467 #else 468 NULL, 469 #endif 470 newlevelstr)) ) 471 fprintf (stderr, "\topen error %d\n", err); 472 else 473 { 474 lg_mesg (LG_DEBUG, "debug message"); 475 lg_mesg (LG_INFO, "INFO message"); 476 lg_mesg (LG_NOTICE, "Notice message"); 477 lg_mesg (LG_WARNING, "Warning message"); 478 lg_mesg (LG_ERROR, "Error message"); 479 lg_mesg (LG_FATAL, "Fatal message "); 480 } 481 482 if ( (err = lg_close ()) < 0 ) 483 fprintf (stderr, "\tclose error %d\n", err); 484 485 return 0; 486 } 487 #endif 488