1 /* $NetBSD: logging.c,v 1.2 2025/09/05 21:16:25 christos Exp $ */ 2 3 /* $OpenLDAP$ */ 4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 5 * 6 * Copyright 2021-2024 The OpenLDAP Foundation. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted only as authorized by the OpenLDAP 11 * Public License. 12 * 13 * A copy of this license is available in the file LICENSE in the 14 * top-level directory of the distribution or, alternatively, at 15 * <http://www.OpenLDAP.org/license.html>. 16 */ 17 18 #include <sys/cdefs.h> 19 __RCSID("$NetBSD: logging.c,v 1.2 2025/09/05 21:16:25 christos Exp $"); 20 21 #include "portable.h" 22 23 #include <stdio.h> 24 25 #include <ac/errno.h> 26 #include <ac/param.h> 27 #include <ac/string.h> 28 #include <ac/time.h> 29 #include <ac/unistd.h> 30 #include <ac/ctype.h> 31 32 #include <sys/stat.h> 33 #ifndef _WIN32 34 #include <sys/uio.h> 35 #endif 36 #include <fcntl.h> 37 38 #include "slap.h" 39 #include "ldif.h" 40 41 #include "slap-config.h" 42 #include "slap-cfglog.h" 43 44 static int config_syslog, active_syslog; 45 46 static char logfile_suffix[sizeof(".xx.gz")]; 47 static char logfile_path[MAXPATHLEN - sizeof(logfile_suffix) -1]; 48 static long logfile_fslimit; 49 static int logfile_age, logfile_only, logfile_max; 50 static char *syslog_prefix; 51 static int splen; 52 static int logfile_rotfail, logfile_openfail; 53 54 typedef enum { LFMT_DEBUG, LFMT_SYSLOG, LFMT_RFC3339 } LogFormat; 55 static LogFormat logfile_format; 56 57 #define LFMT_LOCALTIME 0x80 58 #define LFMT_DEFAULT LFMT_DEBUG 59 #define LFMT_SYSLOG_LOCAL (LFMT_SYSLOG|LFMT_LOCALTIME) 60 #define LFMT_SYSLOG_UTC (LFMT_SYSLOG) 61 #define LFMT_RFC3339_UTC (LFMT_RFC3339) 62 63 static slap_verbmasks logformat_key[] = { 64 { BER_BVC("default"), LFMT_DEFAULT }, 65 { BER_BVC("debug"), LFMT_DEBUG }, 66 { BER_BVC("syslog-utc"), LFMT_SYSLOG_UTC }, 67 { BER_BVC("syslog-localtime"), LFMT_SYSLOG_LOCAL }, 68 { BER_BVC("rfc3339-utc"), LFMT_RFC3339_UTC }, 69 { BER_BVNULL, 0 } 70 }; 71 72 char *serverName; 73 int slap_debug_orig; 74 75 ldap_pvt_thread_mutex_t logfile_mutex; 76 77 static off_t logfile_fsize; 78 static time_t logfile_fcreated; 79 static int logfile_fd = -1; 80 static char logpaths[2][MAXPATHLEN]; 81 static int logpathlen; 82 83 #define SYSLOG_STAMP "Mmm dd hh:mm:ss" 84 #ifdef HAVE_CLOCK_GETTIME 85 #define RFC3339_FRAC ".fffffffffZ" 86 #else 87 #define RFC3339_FRAC ".ffffffZ" 88 #endif 89 #define RFC3339_BASE "YYYY-mm-ddTHH:MM:SS" 90 #define RFC3339_STAMP RFC3339_BASE RFC3339_FRAC 91 92 void 93 slap_debug_print( const char *data ) 94 { 95 #ifdef _WIN32 96 char msgbuf[4096]; 97 int prefixlen, poffset = 0, datalen; 98 #else 99 char prefix[sizeof("ssssssssssssssss.ffffffff 0xtttttttttttttttt ")]; 100 struct iovec iov[2]; 101 #endif 102 int rotate = 0; 103 #ifdef HAVE_CLOCK_GETTIME 104 struct timespec tv; 105 #define TS "%08x" 106 #define TSf ".%09ldZ" 107 #define Tfrac tv.tv_nsec 108 #define gettime(tv) clock_gettime( CLOCK_REALTIME, tv ) 109 #else 110 struct timeval tv; 111 #define TS "%05x" 112 #define TSf ".%06ldZ" 113 #define Tfrac tv.tv_usec 114 #define gettime(tv) gettimeofday( tv, NULL ) 115 #endif 116 char *ptr; 117 int len; 118 119 120 gettime( &tv ); 121 #ifdef _WIN32 122 ptr = msgbuf; 123 prefixlen = sprintf( ptr, "%lx." TS " %p ", 124 (long)tv.tv_sec, (unsigned int)Tfrac, (void *)ldap_pvt_thread_self() ); 125 if ( prefixlen < splen ) { 126 poffset = splen - prefixlen; 127 AC_MEMCPY( ptr+poffset, ptr, prefixlen ); 128 } 129 130 ptr = lutil_strncopy( ptr+poffset+prefixlen, data, sizeof(msgbuf) - prefixlen); 131 len = ptr - msgbuf - poffset; 132 datalen = len - prefixlen; 133 if ( !logfile_only ) 134 (void)!write( 2, msgbuf+poffset, len ); 135 ptr = msgbuf; 136 #else 137 iov[0].iov_base = prefix; 138 iov[0].iov_len = sprintf( prefix, "%lx." TS " %p ", 139 (long)tv.tv_sec, (unsigned int)Tfrac, (void *)ldap_pvt_thread_self() ); 140 iov[1].iov_base = (void *)data; 141 iov[1].iov_len = strlen( data ); 142 len = iov[0].iov_len + iov[1].iov_len; 143 if ( !logfile_only ) 144 (void)!writev( 2, iov, 2 ); 145 #endif 146 if ( logfile_fd >= 0 ) { 147 if ( logfile_fslimit || logfile_age ) { 148 ldap_pvt_thread_mutex_lock( &logfile_mutex ); 149 if ( logfile_fslimit && logfile_fsize + len > logfile_fslimit ) 150 rotate = 1; 151 if ( logfile_age && tv.tv_sec - logfile_fcreated >= logfile_age ) 152 rotate |= 2; 153 if ( rotate ) { 154 int rc, savefd; 155 strcpy( logpaths[0]+logpathlen, ".tmp" ); 156 if ( rename( logfile_path, logpaths[0] )) { 157 rc = errno; 158 if ( !logfile_rotfail ) { 159 char buf[BUFSIZ]; 160 char ebuf[128]; 161 int len = snprintf(buf, sizeof( buf ), "ERROR! logfile rotate failure, err=%d \"%s\"\n", 162 rc, AC_STRERROR_R( rc, ebuf, sizeof(ebuf) )); 163 if ( !logfile_only ) 164 !write( 2, buf, len ); 165 !write( logfile_fd, buf, len ); 166 logfile_rotfail = 1; 167 } 168 rotate = 0; /* don't bother since it will fail */ 169 } else { 170 logfile_rotfail = 0; 171 } 172 savefd = logfile_fd; 173 logfile_fd = -1; 174 if (( rc = logfile_open( logfile_path ))) { 175 logfile_fd = savefd; 176 if ( !logfile_openfail ) { 177 char buf[BUFSIZ]; 178 char ebuf[128]; 179 int len = snprintf(buf, sizeof( buf ), "ERROR! logfile couldn't be reopened, err=%d \"%s\"\n", 180 rc, AC_STRERROR_R( rc, ebuf, sizeof(ebuf) )); 181 if ( !logfile_only ) 182 !write( 2, buf, len ); 183 !write( logfile_fd, buf, len ); 184 logfile_openfail = 1; 185 } 186 } else { 187 close( savefd ); 188 logfile_openfail = 0; 189 } 190 } 191 } 192 193 if ( logfile_format > LFMT_DEBUG ) { 194 struct tm tm; 195 if ( !( logfile_format & LFMT_LOCALTIME ) ) 196 ldap_pvt_gmtime( &tv.tv_sec, &tm ); 197 else 198 ldap_pvt_localtime( &tv.tv_sec, &tm ); 199 #ifdef _WIN32 200 if ( splen < prefixlen ) 201 ptr += prefixlen - splen; 202 memcpy( ptr, syslog_prefix, splen ); 203 #else 204 ptr = syslog_prefix; 205 #endif 206 if ( logfile_format & LFMT_SYSLOG ) { 207 ptr += strftime( ptr, sizeof( SYSLOG_STAMP ), 208 "%b %d %H:%M:%S", &tm ); 209 } else { 210 ptr += strftime( ptr, sizeof( RFC3339_BASE ), 211 "%Y-%m-%dT%H:%M:%S", &tm ); 212 ptr += snprintf( ptr, sizeof( RFC3339_FRAC ), TSf, Tfrac ); 213 } 214 *ptr = ' '; 215 #ifdef _WIN32 216 len = datalen + splen; 217 #else 218 iov[0].iov_base = syslog_prefix; 219 iov[0].iov_len = splen; 220 #endif 221 } 222 223 #ifdef _WIN32 224 if ( logfile_format <= LFMT_DEBUG ) 225 ptr += poffset; /* only nonzero if logfile-format was explicitly set */ 226 len = write( logfile_fd, ptr, len ); 227 #else 228 len = writev( logfile_fd, iov, 2 ); 229 #endif 230 if ( len > 0 ) 231 logfile_fsize += len; 232 if ( logfile_fslimit || logfile_age ) 233 ldap_pvt_thread_mutex_unlock( &logfile_mutex ); 234 } 235 if ( rotate ) { 236 int i; 237 for (i=logfile_max; i > 1; i--) { 238 sprintf( logpaths[0]+logpathlen, ".%02d", i ); 239 sprintf( logpaths[1]+logpathlen, ".%02d", i-1 ); 240 rename( logpaths[1], logpaths[0] ); 241 } 242 sprintf( logpaths[0]+logpathlen, ".tmp" ); 243 rename( logpaths[0], logpaths[1] ); 244 } 245 } 246 247 void 248 logfile_close() 249 { 250 if ( logfile_fd >= 0 ) { 251 close( logfile_fd ); 252 logfile_fd = -1; 253 } 254 logfile_path[0] = '\0'; 255 } 256 257 int 258 logfile_open( const char *path ) 259 { 260 struct stat st; 261 int fd, saved_errno; 262 263 /* the logfile is for slapd only, not tools */ 264 if ( !( slapMode & SLAP_SERVER_MODE )) 265 return 0; 266 267 fd = open( path, O_CREAT|O_WRONLY|O_APPEND, 0640 ); 268 if ( fd < 0 ) { 269 saved_errno = errno; 270 fail: 271 logfile_only = 0; /* make sure something gets output */ 272 return saved_errno; 273 } 274 275 if ( fstat( fd, &st ) ) { 276 saved_errno = errno; 277 close( fd ); 278 goto fail; 279 } 280 281 if ( !logfile_path[0] ) { 282 logpathlen = strlen( path ); 283 if ( logpathlen >= sizeof(logfile_path) ) { 284 saved_errno = ENAMETOOLONG; 285 goto fail; 286 } 287 strcpy( logfile_path, path ); 288 strcpy( logpaths[0], path ); 289 strcpy( logpaths[1], path ); 290 } 291 292 logfile_fsize = st.st_size; 293 logfile_fcreated = st.st_ctime; /* not strictly true but close enough */ 294 logfile_fd = fd; 295 296 return 0; 297 } 298 299 const char * 300 logfile_name() 301 { 302 return logfile_path[0] ? logfile_path : NULL; 303 } 304 305 #if defined(LDAP_DEBUG) && defined(LDAP_SYSLOG) 306 #ifdef LOG_LOCAL4 307 int 308 slap_parse_syslog_user( const char *arg, int *syslogUser ) 309 { 310 static slap_verbmasks syslogUsers[] = { 311 { BER_BVC( "LOCAL0" ), LOG_LOCAL0 }, 312 { BER_BVC( "LOCAL1" ), LOG_LOCAL1 }, 313 { BER_BVC( "LOCAL2" ), LOG_LOCAL2 }, 314 { BER_BVC( "LOCAL3" ), LOG_LOCAL3 }, 315 { BER_BVC( "LOCAL4" ), LOG_LOCAL4 }, 316 { BER_BVC( "LOCAL5" ), LOG_LOCAL5 }, 317 { BER_BVC( "LOCAL6" ), LOG_LOCAL6 }, 318 { BER_BVC( "LOCAL7" ), LOG_LOCAL7 }, 319 #ifdef LOG_USER 320 { BER_BVC( "USER" ), LOG_USER }, 321 #endif /* LOG_USER */ 322 #ifdef LOG_DAEMON 323 { BER_BVC( "DAEMON" ), LOG_DAEMON }, 324 #endif /* LOG_DAEMON */ 325 { BER_BVNULL, 0 } 326 }; 327 int i = verb_to_mask( arg, syslogUsers ); 328 329 if ( BER_BVISNULL( &syslogUsers[ i ].word ) ) { 330 Debug( LDAP_DEBUG_ANY, 331 "unrecognized syslog user \"%s\".\n", 332 arg ); 333 return 1; 334 } 335 336 *syslogUser = syslogUsers[ i ].mask; 337 338 return 0; 339 } 340 #endif /* LOG_LOCAL4 */ 341 342 int 343 slap_parse_syslog_level( const char *arg, int *levelp ) 344 { 345 static slap_verbmasks str2syslog_level[] = { 346 { BER_BVC( "EMERG" ), LOG_EMERG }, 347 { BER_BVC( "ALERT" ), LOG_ALERT }, 348 { BER_BVC( "CRIT" ), LOG_CRIT }, 349 { BER_BVC( "ERR" ), LOG_ERR }, 350 { BER_BVC( "WARNING" ), LOG_WARNING }, 351 { BER_BVC( "NOTICE" ), LOG_NOTICE }, 352 { BER_BVC( "INFO" ), LOG_INFO }, 353 { BER_BVC( "DEBUG" ), LOG_DEBUG }, 354 { BER_BVNULL, 0 } 355 }; 356 int i = verb_to_mask( arg, str2syslog_level ); 357 if ( BER_BVISNULL( &str2syslog_level[ i ].word ) ) { 358 Debug( LDAP_DEBUG_ANY, 359 "unknown syslog level \"%s\".\n", 360 arg ); 361 return 1; 362 } 363 364 *levelp = str2syslog_level[ i ].mask; 365 366 return 0; 367 } 368 #endif /* LDAP_DEBUG && LDAP_SYSLOG */ 369 370 static char **debug_unknowns; 371 static char **syslog_unknowns; 372 373 static int 374 parse_debug_unknowns( char **unknowns, int *levelp ) 375 { 376 int i, level, rc = 0; 377 378 for ( i = 0; unknowns[ i ] != NULL; i++ ) { 379 level = 0; 380 if ( str2loglevel( unknowns[ i ], &level )) { 381 fprintf( stderr, 382 "unrecognized log level \"%s\"\n", unknowns[ i ] ); 383 rc = 1; 384 } else { 385 *levelp |= level; 386 } 387 } 388 return rc; 389 } 390 391 int 392 slap_parse_debug_level( const char *arg, int *levelp, int which ) 393 { 394 int level; 395 396 if ( arg && arg[ 0 ] != '-' && !isdigit( (unsigned char) arg[ 0 ] ) ) 397 { 398 int i; 399 char **levels; 400 char ***unknowns = which ? &syslog_unknowns : &debug_unknowns; 401 402 levels = ldap_str2charray( arg, "," ); 403 404 for ( i = 0; levels[ i ] != NULL; i++ ) { 405 level = 0; 406 407 if ( str2loglevel( levels[ i ], &level ) ) { 408 /* remember this for later */ 409 ldap_charray_add( unknowns, levels[ i ] ); 410 fprintf( stderr, 411 "unrecognized log level \"%s\" (deferred)\n", 412 levels[ i ] ); 413 } else { 414 *levelp |= level; 415 } 416 } 417 418 ldap_charray_free( levels ); 419 420 } else { 421 int rc; 422 423 if ( arg[0] == '-' ) { 424 rc = lutil_atoix( &level, arg, 0 ); 425 } else { 426 unsigned ulevel; 427 428 rc = lutil_atoux( &ulevel, arg, 0 ); 429 level = (int)ulevel; 430 } 431 432 if ( rc ) { 433 fprintf( stderr, 434 "unrecognized log level " 435 "\"%s\"\n", arg ); 436 return 1; 437 } 438 439 if ( level == 0 ) { 440 *levelp = 0; 441 442 } else { 443 *levelp |= level; 444 } 445 } 446 447 return 0; 448 } 449 450 int 451 slap_parse_debug_unknowns() { 452 int rc = 0; 453 if ( debug_unknowns ) { 454 rc = parse_debug_unknowns( debug_unknowns, &slap_debug ); 455 ldap_charray_free( debug_unknowns ); 456 debug_unknowns = NULL; 457 if ( rc ) 458 goto leave; 459 ber_set_option( NULL, LBER_OPT_DEBUG_LEVEL, &slap_debug ); 460 ldap_set_option( NULL, LDAP_OPT_DEBUG_LEVEL, &slap_debug ); 461 } 462 if ( syslog_unknowns ) { 463 rc = parse_debug_unknowns( syslog_unknowns, &ldap_syslog ); 464 ldap_charray_free( syslog_unknowns ); 465 syslog_unknowns = NULL; 466 } 467 leave: 468 return rc; 469 } 470 471 void slap_check_unknown_level( char *levelstr, int level ) 472 { 473 int i; 474 475 if ( debug_unknowns ) { 476 for ( i = 0; debug_unknowns[ i ]; i++ ) { 477 if ( !strcasecmp( debug_unknowns[ i ], levelstr )) { 478 slap_debug |= level; 479 break; 480 } 481 } 482 } 483 484 if ( syslog_unknowns ) { 485 for ( i = 0; syslog_unknowns[ i ]; i++ ) { 486 if ( !strcasecmp( syslog_unknowns[ i ], levelstr )) { 487 ldap_syslog |= level; 488 break; 489 } 490 } 491 } 492 } 493 494 static slap_verbmasks *loglevel_ops; 495 496 static int 497 loglevel_init( void ) 498 { 499 slap_verbmasks lo[] = { 500 { BER_BVC("Any"), (slap_mask_t) LDAP_DEBUG_ANY }, 501 { BER_BVC("Trace"), LDAP_DEBUG_TRACE }, 502 { BER_BVC("Packets"), LDAP_DEBUG_PACKETS }, 503 { BER_BVC("Args"), LDAP_DEBUG_ARGS }, 504 { BER_BVC("Conns"), LDAP_DEBUG_CONNS }, 505 { BER_BVC("BER"), LDAP_DEBUG_BER }, 506 { BER_BVC("Filter"), LDAP_DEBUG_FILTER }, 507 { BER_BVC("Config"), LDAP_DEBUG_CONFIG }, 508 { BER_BVC("ACL"), LDAP_DEBUG_ACL }, 509 { BER_BVC("Stats"), LDAP_DEBUG_STATS }, 510 { BER_BVC("Stats2"), LDAP_DEBUG_STATS2 }, 511 { BER_BVC("Shell"), LDAP_DEBUG_SHELL }, 512 { BER_BVC("Parse"), LDAP_DEBUG_PARSE }, 513 #if 0 /* no longer used (nor supported) */ 514 { BER_BVC("Cache"), LDAP_DEBUG_CACHE }, 515 { BER_BVC("Index"), LDAP_DEBUG_INDEX }, 516 #endif 517 { BER_BVC("Sync"), LDAP_DEBUG_SYNC }, 518 { BER_BVC("None"), LDAP_DEBUG_NONE }, 519 { BER_BVNULL, 0 } 520 }; 521 522 return slap_verbmasks_init( &loglevel_ops, lo ); 523 } 524 525 void 526 slap_loglevel_destroy( void ) 527 { 528 if ( loglevel_ops ) { 529 (void)slap_verbmasks_destroy( loglevel_ops ); 530 } 531 loglevel_ops = NULL; 532 } 533 534 static slap_mask_t loglevel_ignore[] = { -1, 0 }; 535 536 int 537 slap_loglevel_get( struct berval *s, int *l ) 538 { 539 int rc; 540 slap_mask_t m, i; 541 542 if ( loglevel_ops == NULL ) { 543 loglevel_init(); 544 } 545 546 for ( m = 0, i = 1; !BER_BVISNULL( &loglevel_ops[ i ].word ); i++ ) { 547 m |= loglevel_ops[ i ].mask; 548 } 549 550 for ( i = 1; m & i; i <<= 1 ) 551 ; 552 553 if ( i == 0 ) { 554 return -1; 555 } 556 557 rc = slap_verbmasks_append( &loglevel_ops, i, s, loglevel_ignore ); 558 559 if ( rc != 0 ) { 560 Debug( LDAP_DEBUG_ANY, "slap_loglevel_get(%lu, \"%s\") failed\n", 561 i, s->bv_val ); 562 563 } else { 564 *l = i; 565 slap_check_unknown_level( s->bv_val, i ); 566 } 567 568 return rc; 569 } 570 571 int 572 slap_syslog_get() 573 { 574 return active_syslog; 575 } 576 577 void 578 slap_syslog_set( int l ) 579 { 580 active_syslog = l; 581 if ( logfile_only ) { 582 slap_debug |= active_syslog; 583 ldap_syslog = 0; 584 } else { 585 ldap_syslog = active_syslog; 586 } 587 } 588 589 int 590 slap_debug_get() 591 { 592 return slap_debug_orig; 593 } 594 595 void 596 slap_debug_set( int l ) 597 { 598 slap_debug_orig = l; 599 if ( logfile_only ) 600 slap_debug = slap_debug_orig | active_syslog; 601 else 602 slap_debug = slap_debug_orig; 603 ber_set_option(NULL, LBER_OPT_DEBUG_LEVEL, &slap_debug); 604 ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &slap_debug); 605 ldif_debug = slap_debug; 606 } 607 608 int 609 str2loglevel( const char *s, int *l ) 610 { 611 int i; 612 613 if ( loglevel_ops == NULL ) { 614 loglevel_init(); 615 } 616 617 i = verb_to_mask( s, loglevel_ops ); 618 619 if ( BER_BVISNULL( &loglevel_ops[ i ].word ) ) { 620 return -1; 621 } 622 623 *l = loglevel_ops[ i ].mask; 624 625 return 0; 626 } 627 628 const char * 629 loglevel2str( int l ) 630 { 631 struct berval bv = BER_BVNULL; 632 633 loglevel2bv( l, &bv ); 634 635 return bv.bv_val; 636 } 637 638 int 639 loglevel2bv( int l, struct berval *bv ) 640 { 641 if ( loglevel_ops == NULL ) { 642 loglevel_init(); 643 } 644 645 BER_BVZERO( bv ); 646 647 return enum_to_verb( loglevel_ops, l, bv ) == -1; 648 } 649 650 int 651 loglevel2bvarray( int l, BerVarray *bva ) 652 { 653 if ( loglevel_ops == NULL ) { 654 loglevel_init(); 655 } 656 657 if ( l == 0 ) { 658 struct berval bv = BER_BVC("0"); 659 return value_add_one( bva, &bv ); 660 } 661 662 return mask_to_verbs( loglevel_ops, l, bva ); 663 } 664 665 int 666 loglevel_print( FILE *out ) 667 { 668 int i; 669 670 if ( loglevel_ops == NULL ) { 671 loglevel_init(); 672 } 673 674 fprintf( out, "Installed log subsystems:\n\n" ); 675 for ( i = 0; !BER_BVISNULL( &loglevel_ops[ i ].word ); i++ ) { 676 unsigned mask = loglevel_ops[ i ].mask & 0xffffffffUL; 677 fprintf( out, 678 (mask == ((slap_mask_t) -1 & 0xffffffffUL) 679 ? "\t%-30s (-1, 0xffffffff)\n" : "\t%-30s (%u, 0x%x)\n"), 680 loglevel_ops[ i ].word.bv_val, mask, mask ); 681 } 682 683 fprintf( out, "\nNOTE: custom log subsystems may be later installed " 684 "by specific code\n\n" ); 685 686 return 0; 687 } 688 689 int 690 config_logging(ConfigArgs *c) { 691 int i, rc = 0; 692 693 if ( loglevel_ops == NULL ) { 694 loglevel_init(); 695 } 696 697 if (c->op == SLAP_CONFIG_EMIT) { 698 switch(c->type) { 699 case CFG_LOGLEVEL: 700 /* Get default or commandline slapd setting */ 701 if ( ldap_syslog && !config_syslog ) 702 config_syslog = ldap_syslog; 703 rc = loglevel2bvarray( config_syslog, &c->rvalue_vals ); 704 break; 705 706 case CFG_LOGFILE: { 707 const char *logfileName = logfile_name(); 708 if ( logfileName && *logfileName ) 709 c->value_string = ch_strdup( logfileName ); 710 else 711 rc = 1; 712 } 713 break; 714 case CFG_LOGFILE_FORMAT: 715 if ( logfile_format ) { 716 value_add_one( &c->rvalue_vals, &logformat_key[logfile_format].word ); 717 } else { 718 rc = 1; 719 } 720 break; 721 case CFG_LOGFILE_ONLY: 722 c->value_int = logfile_only; 723 break; 724 case CFG_LOGFILE_ROTATE: 725 rc = 1; 726 if ( logfile_max ) { 727 char buf[64]; 728 struct berval bv; 729 bv.bv_len = snprintf( buf, sizeof(buf), "%d %ld %ld", logfile_max, 730 (long) logfile_fslimit / 1048576, (long) logfile_age / 3600 ); 731 if ( bv.bv_len > 0 && bv.bv_len < sizeof(buf) ) { 732 bv.bv_val = buf; 733 value_add_one( &c->rvalue_vals, &bv ); 734 rc = 0; 735 } 736 } 737 break; 738 default: 739 rc = 1; 740 } 741 return rc; 742 } else if ( c->op == LDAP_MOD_DELETE ) { 743 switch(c->type) { 744 case CFG_LOGLEVEL: 745 if ( !c->line ) { 746 config_syslog = 0; 747 } else { 748 i = verb_to_mask( c->line, loglevel_ops ); 749 config_syslog &= ~loglevel_ops[i].mask; 750 } 751 goto reset; 752 753 case CFG_LOGFILE: 754 logfile_close(); 755 break; 756 757 case CFG_LOGFILE_FORMAT: 758 logfile_format = 0; 759 ch_free( syslog_prefix ); 760 syslog_prefix = NULL; 761 break; 762 763 case CFG_LOGFILE_ONLY: 764 /* remove loglevel from debuglevel */ 765 slap_debug = slap_debug_orig; 766 ldap_syslog = config_syslog; 767 break; 768 769 case CFG_LOGFILE_ROTATE: 770 logfile_max = logfile_fslimit = logfile_age = 0; 771 break; 772 default: 773 rc = 1; 774 } 775 return rc; 776 } 777 778 switch(c->type) { 779 case CFG_LOGLEVEL: 780 for( i=1; i < c->argc; i++ ) { 781 int level; 782 783 if ( isdigit((unsigned char)c->argv[i][0]) || c->argv[i][0] == '-' ) { 784 if( lutil_atoix( &level, c->argv[i], 0 ) != 0 ) { 785 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unable to parse level", c->argv[0] ); 786 Debug( LDAP_DEBUG_ANY, "%s: %s \"%s\"\n", 787 c->log, c->cr_msg, c->argv[i]); 788 return( 1 ); 789 } 790 } else { 791 if ( str2loglevel( c->argv[i], &level ) ) { 792 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unknown level", c->argv[0] ); 793 Debug( LDAP_DEBUG_ANY, "%s: %s \"%s\"\n", 794 c->log, c->cr_msg, c->argv[i]); 795 return( 1 ); 796 } 797 } 798 /* Explicitly setting a zero clears all the levels */ 799 if ( level ) 800 config_syslog |= level; 801 else 802 config_syslog = 0; 803 } 804 805 reset: 806 slap_debug = slap_debug_orig; 807 active_syslog = config_syslog; 808 if ( slapMode & SLAP_SERVER_MODE ) { 809 if ( logfile_only ) { 810 slap_debug |= config_syslog; 811 ldap_syslog = 0; 812 } else { 813 ldap_syslog = config_syslog; 814 } 815 } 816 rc = 0; 817 break; 818 819 case CFG_LOGFILE: 820 rc = logfile_open( c->value_string ); 821 if ( rc ) { 822 char ebuf[128]; 823 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unable to open logfile, err=%d \"%s\"", 824 c->argv[0], rc, AC_STRERROR_R( rc, ebuf, sizeof(ebuf) ) ); 825 Debug( LDAP_DEBUG_ANY, "%s: %s \"%s\"\n", 826 c->log, c->cr_msg, c->argv[1]); 827 return( 1 ); 828 } 829 ch_free( c->value_string ); 830 break; 831 832 case CFG_LOGFILE_FORMAT: { 833 int len; 834 i = verb_to_mask( c->argv[1], logformat_key ); 835 836 if ( BER_BVISNULL( &logformat_key[ i ].word ) ) { 837 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unknown format", c->argv[0] ); 838 Debug( LDAP_DEBUG_ANY, "%s: %s \"%s\"\n", 839 c->log, c->cr_msg, c->argv[1]); 840 return( 1 ); 841 } 842 if ( syslog_prefix ) 843 ch_free( syslog_prefix ); 844 logfile_format = logformat_key[i].mask; 845 len = strlen( global_host ) + 1 + strlen( serverName ) + 1 + sizeof(("[123456789]:")) + 846 (( logfile_format & LFMT_RFC3339) ? sizeof( RFC3339_STAMP ) : sizeof( SYSLOG_STAMP )); 847 syslog_prefix = ch_malloc( len ); 848 splen = sprintf( syslog_prefix, "%s %s %s[%d]: ", ( logfile_format & LFMT_RFC3339 ) ? 849 RFC3339_STAMP : SYSLOG_STAMP, global_host, serverName, getpid() ); 850 } 851 break; 852 853 case CFG_LOGFILE_ONLY: 854 logfile_only = c->value_int; 855 goto reset; 856 857 case CFG_LOGFILE_ROTATE: { 858 unsigned lf_max, lf_mbyte, lf_hour; 859 if ( lutil_atoux( &lf_max, c->argv[1], 0 ) != 0 ) { 860 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> " 861 "invalid max value \"%s\"", c->argv[0], c->argv[1] ); 862 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", 863 c->log, c->cr_msg ); 864 return 1; 865 } 866 if ( !lf_max || lf_max > 99 ) { 867 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> " 868 "invalid max value \"%s\" must be 1-99", c->argv[0], c->argv[1] ); 869 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", 870 c->log, c->cr_msg ); 871 return 1; 872 } 873 if ( lutil_atoux( &lf_mbyte, c->argv[2], 0 ) != 0 ) { 874 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> " 875 "invalid Mbyte value \"%s\"", c->argv[0], c->argv[2] ); 876 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", 877 c->log, c->cr_msg ); 878 return 1; 879 } 880 if ( lutil_atoux( &lf_hour, c->argv[3], 0 ) != 0 ) { 881 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> " 882 "invalid hours value \"%s\"", c->argv[0], c->argv[3] ); 883 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", 884 c->log, c->cr_msg ); 885 return 1; 886 } 887 if ( !lf_mbyte && !lf_hour ) { 888 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> " 889 "Mbyte and hours cannot both be zero", c->argv[0] ); 890 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", 891 c->log, c->cr_msg ); 892 return 1; 893 } 894 logfile_max = lf_max; 895 logfile_fslimit = lf_mbyte * 1048576; /* Megabytes to bytes */ 896 logfile_age = lf_hour * 3600; /* hours to seconds */ 897 } 898 break; 899 default: 900 rc = 1; 901 } 902 return rc; 903 } 904