1 /* $NetBSD: main.c,v 1.2 2021/08/14 16:14:58 christos Exp $ */ 2 3 /* $OpenLDAP$ */ 4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 5 * 6 * Copyright 1998-2021 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 /* Portions Copyright (c) 1995 Regents of the University of Michigan. 18 * All rights reserved. 19 * 20 * Redistribution and use in source and binary forms are permitted 21 * provided that this notice is preserved and that due credit is given 22 * to the University of Michigan at Ann Arbor. The name of the University 23 * may not be used to endorse or promote products derived from this 24 * software without specific prior written permission. This software 25 * is provided ``as is'' without express or implied warranty. 26 */ 27 28 #include <sys/cdefs.h> 29 __RCSID("$NetBSD: main.c,v 1.2 2021/08/14 16:14:58 christos Exp $"); 30 31 #include "portable.h" 32 33 #include <stdio.h> 34 35 #include <ac/ctype.h> 36 #include <ac/socket.h> 37 #include <ac/string.h> 38 #include <ac/time.h> 39 #include <ac/unistd.h> 40 #include <ac/wait.h> 41 #include <ac/errno.h> 42 43 #include <event2/event.h> 44 45 #include "lload.h" 46 #include "lutil.h" 47 #include "ldif.h" 48 49 #ifdef LDAP_SIGCHLD 50 static void wait4child( evutil_socket_t sig, short what, void *arg ); 51 #endif 52 53 #ifdef SIGPIPE 54 static void sigpipe( evutil_socket_t sig, short what, void *arg ); 55 #endif 56 57 #ifdef HAVE_NT_SERVICE_MANAGER 58 #define MAIN_RETURN(x) return 59 static struct sockaddr_in bind_addr; 60 61 #define SERVICE_EXIT( e, n ) \ 62 do { \ 63 if ( is_NT_Service ) { \ 64 lutil_ServiceStatus.dwWin32ExitCode = (e); \ 65 lutil_ServiceStatus.dwServiceSpecificExitCode = (n); \ 66 } \ 67 } while (0) 68 69 #else 70 #define SERVICE_EXIT( e, n ) 71 #define MAIN_RETURN(x) return (x) 72 #endif 73 74 struct signal_handler { 75 int signal; 76 event_callback_fn handler; 77 struct event *event; 78 } signal_handlers[] = { 79 { LDAP_SIGUSR2, lload_sig_shutdown }, 80 81 #ifdef SIGPIPE 82 { SIGPIPE, sigpipe }, 83 #endif 84 #ifdef SIGHUP 85 { SIGHUP, lload_sig_shutdown }, 86 #endif 87 { SIGINT, lload_sig_shutdown }, 88 { SIGTERM, lload_sig_shutdown }, 89 #ifdef SIGTRAP 90 { SIGTRAP, lload_sig_shutdown }, 91 #endif 92 #ifdef LDAP_SIGCHLD 93 { LDAP_SIGCHLD, wait4child }, 94 #endif 95 #ifdef SIGBREAK 96 /* SIGBREAK is generated when Ctrl-Break is pressed. */ 97 { SIGBREAK, lload_sig_shutdown }, 98 #endif 99 { 0, NULL } 100 }; 101 102 /* 103 * when more than one lloadd is running on one machine, each one might have 104 * it's own LOCAL for syslogging and must have its own pid/args files 105 */ 106 107 #ifndef HAVE_MKVERSION 108 const char Versionstr[] = OPENLDAP_PACKAGE 109 " " OPENLDAP_VERSION " LDAP Load Balancer Server (lloadd)"; 110 #endif 111 112 #define CHECK_NONE 0x00 113 #define CHECK_CONFIG 0x01 114 #define CHECK_LOGLEVEL 0x02 115 static int check = CHECK_NONE; 116 static int version = 0; 117 118 static int 119 slapd_opt_slp( const char *val, void *arg ) 120 { 121 #ifdef HAVE_SLP 122 /* NULL is default */ 123 if ( val == NULL || *val == '(' || strcasecmp( val, "on" ) == 0 ) { 124 slapd_register_slp = 1; 125 slapd_slp_attrs = ( val != NULL && *val == '(' ) ? val : NULL; 126 127 } else if ( strcasecmp( val, "off" ) == 0 ) { 128 slapd_register_slp = 0; 129 130 /* NOTE: add support for URL specification? */ 131 132 } else { 133 fprintf( stderr, "unrecognized value \"%s\" for SLP option\n", val ); 134 return -1; 135 } 136 137 return 0; 138 139 #else 140 fputs( "lloadd: SLP support is not available\n", stderr ); 141 return 0; 142 #endif 143 } 144 145 /* 146 * Option helper structure: 147 * 148 * oh_nam is left-hand part of <option>[=<value>] 149 * oh_fnc is handler function 150 * oh_arg is an optional arg to oh_fnc 151 * oh_usage is the one-line usage string related to the option, 152 * which is assumed to start with <option>[=<value>] 153 * 154 * please leave valid options in the structure, and optionally #ifdef 155 * their processing inside the helper, so that reasonable and helpful 156 * error messages can be generated if a disabled option is requested. 157 */ 158 struct option_helper { 159 struct berval oh_name; 160 int (*oh_fnc)( const char *val, void *arg ); 161 void *oh_arg; 162 const char *oh_usage; 163 } option_helpers[] = { 164 { BER_BVC("slp"), slapd_opt_slp, NULL, 165 "slp[={on|off|(attrs)}] enable/disable SLP using (attrs)" }, 166 { BER_BVNULL, 0, NULL, NULL } 167 }; 168 169 #if defined(LDAP_DEBUG) && defined(LDAP_SYSLOG) 170 #ifdef LOG_LOCAL4 171 int 172 parse_syslog_user( const char *arg, int *syslogUser ) 173 { 174 static slap_verbmasks syslogUsers[] = { 175 { BER_BVC("LOCAL0"), LOG_LOCAL0 }, 176 { BER_BVC("LOCAL1"), LOG_LOCAL1 }, 177 { BER_BVC("LOCAL2"), LOG_LOCAL2 }, 178 { BER_BVC("LOCAL3"), LOG_LOCAL3 }, 179 { BER_BVC("LOCAL4"), LOG_LOCAL4 }, 180 { BER_BVC("LOCAL5"), LOG_LOCAL5 }, 181 { BER_BVC("LOCAL6"), LOG_LOCAL6 }, 182 { BER_BVC("LOCAL7"), LOG_LOCAL7 }, 183 #ifdef LOG_USER 184 { BER_BVC("USER"), LOG_USER }, 185 #endif /* LOG_USER */ 186 #ifdef LOG_DAEMON 187 { BER_BVC("DAEMON"), LOG_DAEMON }, 188 #endif /* LOG_DAEMON */ 189 { BER_BVNULL, 0 } 190 }; 191 int i = verb_to_mask( arg, syslogUsers ); 192 193 if ( BER_BVISNULL( &syslogUsers[i].word ) ) { 194 Debug( LDAP_DEBUG_ANY, "unrecognized syslog user \"%s\".\n", arg ); 195 return 1; 196 } 197 198 *syslogUser = syslogUsers[i].mask; 199 200 return 0; 201 } 202 #endif /* LOG_LOCAL4 */ 203 204 int 205 parse_syslog_level( const char *arg, int *levelp ) 206 { 207 static slap_verbmasks str2syslog_level[] = { 208 { BER_BVC("EMERG"), LOG_EMERG }, 209 { BER_BVC("ALERT"), LOG_ALERT }, 210 { BER_BVC("CRIT"), LOG_CRIT }, 211 { BER_BVC("ERR"), LOG_ERR }, 212 { BER_BVC("WARNING"), LOG_WARNING }, 213 { BER_BVC("NOTICE"), LOG_NOTICE }, 214 { BER_BVC("INFO"), LOG_INFO }, 215 { BER_BVC("DEBUG"), LOG_DEBUG }, 216 { BER_BVNULL, 0 } 217 }; 218 int i = verb_to_mask( arg, str2syslog_level ); 219 if ( BER_BVISNULL( &str2syslog_level[i].word ) ) { 220 Debug( LDAP_DEBUG_ANY, "unknown syslog level \"%s\".\n", arg ); 221 return 1; 222 } 223 224 *levelp = str2syslog_level[i].mask; 225 226 return 0; 227 } 228 #endif /* LDAP_DEBUG && LDAP_SYSLOG */ 229 230 int 231 parse_debug_unknowns( char **unknowns, int *levelp ) 232 { 233 int i, level, rc = 0; 234 235 for ( i = 0; unknowns[i] != NULL; i++ ) { 236 level = 0; 237 if ( str2loglevel( unknowns[i], &level ) ) { 238 fprintf( stderr, "unrecognized log level \"%s\"\n", unknowns[i] ); 239 rc = 1; 240 } else { 241 *levelp |= level; 242 } 243 } 244 return rc; 245 } 246 247 int 248 parse_debug_level( const char *arg, int *levelp, char ***unknowns ) 249 { 250 int level; 251 252 if ( arg && arg[0] != '-' && !isdigit( (unsigned char)arg[0] ) ) { 253 int i; 254 char **levels; 255 256 levels = ldap_str2charray( arg, "," ); 257 258 for ( i = 0; levels[i] != NULL; i++ ) { 259 level = 0; 260 261 if ( str2loglevel( levels[i], &level ) ) { 262 /* remember this for later */ 263 ldap_charray_add( unknowns, levels[i] ); 264 fprintf( stderr, "unrecognized log level \"%s\" (deferred)\n", 265 levels[i] ); 266 } else { 267 *levelp |= level; 268 } 269 } 270 271 ldap_charray_free( levels ); 272 273 } else { 274 int rc; 275 276 if ( arg[0] == '-' ) { 277 rc = lutil_atoix( &level, arg, 0 ); 278 } else { 279 unsigned ulevel; 280 281 rc = lutil_atoux( &ulevel, arg, 0 ); 282 level = (int)ulevel; 283 } 284 285 if ( rc ) { 286 fprintf( stderr, 287 "unrecognized log level " 288 "\"%s\"\n", 289 arg ); 290 return 1; 291 } 292 293 if ( level == 0 ) { 294 *levelp = 0; 295 296 } else { 297 *levelp |= level; 298 } 299 } 300 301 return 0; 302 } 303 304 static void 305 usage( char *name ) 306 { 307 fprintf( stderr, "usage: %s options\n", name ); 308 fprintf( stderr, 309 "\t-4\t\tIPv4 only\n" 310 "\t-6\t\tIPv6 only\n" 311 "\t-d level\tDebug level" 312 "\n" 313 "\t-f filename\tConfiguration file\n" 314 #if defined(HAVE_SETUID) && defined(HAVE_SETGID) 315 "\t-g group\tGroup (id or name) to run as\n" 316 #endif 317 "\t-h URLs\t\tList of URLs to serve\n" 318 #ifdef SLAP_DEFAULT_SYSLOG_USER 319 "\t-l facility\tSyslog facility (default: LOCAL4)\n" 320 #endif 321 "\t-n serverName\tService name\n" 322 "\t-o <opt>[=val] generic means to specify options" ); 323 if ( !BER_BVISNULL( &option_helpers[0].oh_name ) ) { 324 int i; 325 326 fprintf( stderr, "; supported options:\n" ); 327 for ( i = 0; !BER_BVISNULL( &option_helpers[i].oh_name ); i++ ) { 328 fprintf( stderr, "\t\t%s\n", option_helpers[i].oh_usage ); 329 } 330 } else { 331 fprintf( stderr, "\n" ); 332 } 333 fprintf( stderr, 334 #ifdef HAVE_CHROOT 335 "\t-r directory\tSandbox directory to chroot to\n" 336 #endif 337 "\t-s level\tSyslog level\n" 338 "\t-t\t\tCheck configuration file\n" 339 #if defined(HAVE_SETUID) && defined(HAVE_SETGID) 340 "\t-u user\t\tUser (id or name) to run as\n" 341 #endif 342 "\t-V\t\tprint version info (-VV exit afterwards)\n" ); 343 } 344 345 #ifdef HAVE_NT_SERVICE_MANAGER 346 void WINAPI 347 ServiceMain( DWORD argc, LPTSTR *argv ) 348 #else 349 int 350 main( int argc, char **argv ) 351 #endif 352 { 353 int i, no_detach = 0; 354 int rc = 1; 355 char *urls = NULL; 356 #if defined(HAVE_SETUID) && defined(HAVE_SETGID) 357 char *username = NULL; 358 char *groupname = NULL; 359 #endif 360 #if defined(HAVE_CHROOT) 361 char *sandbox = NULL; 362 #endif 363 #ifdef SLAP_DEFAULT_SYSLOG_USER 364 int syslogUser = SLAP_DEFAULT_SYSLOG_USER; 365 #endif 366 367 #ifndef HAVE_WINSOCK 368 int pid, waitfds[2]; 369 #endif 370 int g_argc = argc; 371 char **g_argv = argv; 372 373 char *configfile = NULL; 374 char *configdir = NULL; 375 char *serverName; 376 int serverMode = SLAP_SERVER_MODE; 377 378 char **debug_unknowns = NULL; 379 char **syslog_unknowns = NULL; 380 381 int slapd_pid_file_unlink = 0, slapd_args_file_unlink = 0; 382 int firstopt = 1; 383 384 slap_sl_mem_init(); 385 386 serverName = lutil_progname( "lloadd", argc, argv ); 387 388 #ifdef HAVE_NT_SERVICE_MANAGER 389 { 390 int *ip; 391 char *newConfigFile; 392 char *newConfigDir; 393 char *newUrls; 394 char *regService = NULL; 395 396 if ( is_NT_Service ) { 397 lutil_CommenceStartupProcessing( serverName, lload_sig_shutdown ); 398 if ( strcmp( serverName, SERVICE_NAME ) ) regService = serverName; 399 } 400 401 ip = (int *)lutil_getRegParam( regService, "DebugLevel" ); 402 if ( ip != NULL ) { 403 slap_debug = *ip; 404 Debug( LDAP_DEBUG_ANY, "new debug level from registry is: %d\n", 405 slap_debug ); 406 } 407 408 newUrls = (char *)lutil_getRegParam( regService, "Urls" ); 409 if ( newUrls ) { 410 if ( urls ) ch_free( urls ); 411 412 urls = ch_strdup( newUrls ); 413 Debug( LDAP_DEBUG_ANY, "new urls from registry: %s\n", urls ); 414 } 415 416 newConfigFile = (char *)lutil_getRegParam( regService, "ConfigFile" ); 417 if ( newConfigFile != NULL ) { 418 configfile = ch_strdup( newConfigFile ); 419 Debug( LDAP_DEBUG_ANY, "new config file from registry is: %s\n", 420 configfile ); 421 } 422 423 newConfigDir = (char *)lutil_getRegParam( regService, "ConfigDir" ); 424 if ( newConfigDir != NULL ) { 425 configdir = ch_strdup( newConfigDir ); 426 Debug( LDAP_DEBUG_ANY, "new config dir from registry is: %s\n", 427 configdir ); 428 } 429 } 430 #endif 431 432 epoch_init(); 433 434 while ( (i = getopt( argc, argv, 435 "c:d:f:F:h:n:o:s:tV" 436 #ifdef LDAP_PF_INET6 437 "46" 438 #endif 439 #ifdef HAVE_CHROOT 440 "r:" 441 #endif 442 #if defined(LDAP_DEBUG) && defined(LDAP_SYSLOG) 443 "S:" 444 #ifdef LOG_LOCAL4 445 "l:" 446 #endif 447 #endif 448 #if defined(HAVE_SETUID) && defined(HAVE_SETGID) 449 "u:g:" 450 #endif 451 )) != EOF ) { 452 switch ( i ) { 453 #ifdef LDAP_PF_INET6 454 case '4': 455 slap_inet4or6 = AF_INET; 456 break; 457 case '6': 458 slap_inet4or6 = AF_INET6; 459 break; 460 #endif 461 462 case 'h': /* listen URLs */ 463 if ( urls != NULL ) free( urls ); 464 urls = ch_strdup( optarg ); 465 break; 466 467 case 'd': { /* set debug level and 'do not detach' flag */ 468 int level = 0; 469 470 if ( strcmp( optarg, "?" ) == 0 ) { 471 check |= CHECK_LOGLEVEL; 472 break; 473 } 474 475 no_detach = 1; 476 if ( parse_debug_level( optarg, &level, &debug_unknowns ) ) { 477 goto destroy; 478 } 479 #ifdef LDAP_DEBUG 480 slap_debug |= level; 481 #else 482 if ( level != 0 ) 483 fputs( "must compile with LDAP_DEBUG for debugging\n", 484 stderr ); 485 #endif 486 } break; 487 488 case 'f': /* read config file */ 489 configfile = ch_strdup( optarg ); 490 break; 491 492 case 'o': { 493 char *val = strchr( optarg, '=' ); 494 struct berval opt; 495 496 opt.bv_val = optarg; 497 498 if ( val ) { 499 opt.bv_len = ( val - optarg ); 500 val++; 501 502 } else { 503 opt.bv_len = strlen( optarg ); 504 } 505 506 for ( i = 0; !BER_BVISNULL( &option_helpers[i].oh_name ); 507 i++ ) { 508 if ( ber_bvstrcasecmp( &option_helpers[i].oh_name, &opt ) == 509 0 ) { 510 assert( option_helpers[i].oh_fnc != NULL ); 511 if ( (*option_helpers[i].oh_fnc)( 512 val, option_helpers[i].oh_arg ) == -1 ) { 513 /* we assume the option parsing helper 514 * issues appropriate and self-explanatory 515 * error messages... */ 516 goto stop; 517 } 518 break; 519 } 520 } 521 522 if ( BER_BVISNULL( &option_helpers[i].oh_name ) ) { 523 goto unhandled_option; 524 } 525 break; 526 } 527 528 case 's': /* set syslog level */ 529 if ( strcmp( optarg, "?" ) == 0 ) { 530 check |= CHECK_LOGLEVEL; 531 break; 532 } 533 534 if ( parse_debug_level( 535 optarg, &ldap_syslog, &syslog_unknowns ) ) { 536 goto destroy; 537 } 538 break; 539 540 #if defined(LDAP_DEBUG) && defined(LDAP_SYSLOG) 541 case 'S': 542 if ( parse_syslog_level( optarg, &ldap_syslog_level ) ) { 543 goto destroy; 544 } 545 break; 546 547 #ifdef LOG_LOCAL4 548 case 'l': /* set syslog local user */ 549 if ( parse_syslog_user( optarg, &syslogUser ) ) { 550 goto destroy; 551 } 552 break; 553 #endif 554 #endif /* LDAP_DEBUG && LDAP_SYSLOG */ 555 556 #ifdef HAVE_CHROOT 557 case 'r': 558 if ( sandbox ) free( sandbox ); 559 sandbox = ch_strdup( optarg ); 560 break; 561 #endif 562 563 #if defined(HAVE_SETUID) && defined(HAVE_SETGID) 564 case 'u': /* user name */ 565 if ( username ) free( username ); 566 username = ch_strdup( optarg ); 567 break; 568 569 case 'g': /* group name */ 570 if ( groupname ) free( groupname ); 571 groupname = ch_strdup( optarg ); 572 break; 573 #endif /* SETUID && GETUID */ 574 575 case 'n': /* NT service name */ 576 serverName = ch_strdup( optarg ); 577 break; 578 579 case 't': 580 check |= CHECK_CONFIG; 581 break; 582 583 case 'V': 584 version++; 585 break; 586 587 default: 588 unhandled_option:; 589 usage( argv[0] ); 590 rc = 1; 591 SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 15 ); 592 goto stop; 593 } 594 595 if ( firstopt ) { 596 firstopt = 0; 597 } 598 } 599 600 if ( optind != argc ) goto unhandled_option; 601 602 ber_set_option( NULL, LBER_OPT_DEBUG_LEVEL, &slap_debug ); 603 ldap_set_option( NULL, LDAP_OPT_DEBUG_LEVEL, &slap_debug ); 604 ldif_debug = slap_debug; 605 606 if ( version ) { 607 fprintf( stderr, "%s\n", Versionstr ); 608 609 if ( version > 1 ) goto stop; 610 } 611 612 #if defined(LDAP_DEBUG) && defined(LDAP_SYSLOG) 613 { 614 char *logName; 615 #ifdef HAVE_EBCDIC 616 logName = ch_strdup( serverName ); 617 __atoe( logName ); 618 #else 619 logName = serverName; 620 #endif 621 622 #ifdef LOG_LOCAL4 623 openlog( logName, OPENLOG_OPTIONS, syslogUser ); 624 #elif defined LOG_DEBUG 625 openlog( logName, OPENLOG_OPTIONS ); 626 #endif 627 #ifdef HAVE_EBCDIC 628 free( logName ); 629 #endif 630 } 631 #endif /* LDAP_DEBUG && LDAP_SYSLOG */ 632 633 Debug( LDAP_DEBUG_ANY, "%s", Versionstr ); 634 635 global_host = ldap_pvt_get_fqdn( NULL ); 636 637 if ( check == CHECK_NONE && lloadd_listeners_init( urls ) != 0 ) { 638 rc = 1; 639 SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 16 ); 640 goto stop; 641 } 642 643 #if defined(HAVE_CHROOT) 644 if ( sandbox ) { 645 if ( chdir( sandbox ) ) { 646 perror( "chdir" ); 647 rc = 1; 648 goto stop; 649 } 650 if ( chroot( sandbox ) ) { 651 perror( "chroot" ); 652 rc = 1; 653 goto stop; 654 } 655 if ( chdir( "/" ) ) { 656 perror( "chdir" ); 657 rc = 1; 658 goto stop; 659 } 660 } 661 #endif 662 663 #if defined(HAVE_SETUID) && defined(HAVE_SETGID) 664 if ( username != NULL || groupname != NULL ) { 665 slap_init_user( username, groupname ); 666 } 667 #endif 668 669 rc = lload_init( serverMode, serverName ); 670 if ( rc ) { 671 SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 18 ); 672 goto destroy; 673 } 674 675 if ( lload_read_config( configfile, configdir ) != 0 ) { 676 rc = 1; 677 SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 19 ); 678 679 if ( check & CHECK_CONFIG ) { 680 fprintf( stderr, "config check failed\n" ); 681 } 682 683 goto destroy; 684 } 685 686 if ( debug_unknowns ) { 687 rc = parse_debug_unknowns( debug_unknowns, &slap_debug ); 688 ldap_charray_free( debug_unknowns ); 689 debug_unknowns = NULL; 690 if ( rc ) goto destroy; 691 } 692 if ( syslog_unknowns ) { 693 rc = parse_debug_unknowns( syslog_unknowns, &ldap_syslog ); 694 ldap_charray_free( syslog_unknowns ); 695 syslog_unknowns = NULL; 696 if ( rc ) goto destroy; 697 } 698 699 if ( check & CHECK_LOGLEVEL ) { 700 rc = 0; 701 goto destroy; 702 } 703 704 if ( check & CHECK_CONFIG ) { 705 fprintf( stderr, "config check succeeded\n" ); 706 707 check &= ~CHECK_CONFIG; 708 if ( check == CHECK_NONE ) { 709 rc = 0; 710 goto destroy; 711 } 712 } 713 714 #ifdef HAVE_TLS 715 rc = ldap_pvt_tls_init( 1 ); 716 if ( rc != 0 ) { 717 Debug( LDAP_DEBUG_ANY, "main: " 718 "TLS init failed: %d\n", 719 rc ); 720 rc = 1; 721 SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 20 ); 722 goto destroy; 723 } 724 725 if ( lload_tls_init() ) { 726 rc = 1; 727 SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 20 ); 728 goto destroy; 729 } 730 #endif 731 732 daemon_base = event_base_new(); 733 if ( !daemon_base ) { 734 Debug( LDAP_DEBUG_ANY, "main: " 735 "main event base allocation failed\n" ); 736 rc = 1; 737 SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 21 ); 738 goto destroy; 739 } 740 741 for ( i = 0; signal_handlers[i].signal; i++ ) { 742 struct event *event; 743 event = evsignal_new( daemon_base, signal_handlers[i].signal, 744 signal_handlers[i].handler, daemon_base ); 745 if ( !event || event_add( event, NULL ) ) { 746 Debug( LDAP_DEBUG_ANY, "main: " 747 "failed to register a handler for signal %d\n", 748 signal_handlers[i].signal ); 749 rc = 1; 750 SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 21 ); 751 goto destroy; 752 } 753 signal_handlers[i].event = event; 754 } 755 756 #ifndef HAVE_WINSOCK 757 if ( !no_detach ) { 758 if ( lutil_pair( waitfds ) < 0 ) { 759 Debug( LDAP_DEBUG_ANY, "main: " 760 "lutil_pair failed\n" ); 761 rc = 1; 762 goto destroy; 763 } 764 pid = lutil_detach( no_detach, 0 ); 765 if ( pid ) { 766 char buf[4]; 767 rc = EXIT_SUCCESS; 768 close( waitfds[1] ); 769 if ( read( waitfds[0], buf, 1 ) != 1 ) rc = EXIT_FAILURE; 770 _exit( rc ); 771 } else { 772 close( waitfds[0] ); 773 } 774 } 775 #endif /* HAVE_WINSOCK */ 776 777 if ( slapd_pid_file != NULL ) { 778 FILE *fp = fopen( slapd_pid_file, "w" ); 779 780 if ( fp == NULL ) { 781 char ebuf[128]; 782 int save_errno = errno; 783 784 Debug( LDAP_DEBUG_ANY, "unable to open pid file " 785 "\"%s\": %d (%s)\n", 786 slapd_pid_file, save_errno, 787 AC_STRERROR_R( save_errno, ebuf, sizeof(ebuf) ) ); 788 789 free( slapd_pid_file ); 790 slapd_pid_file = NULL; 791 792 rc = 1; 793 goto destroy; 794 } 795 fprintf( fp, "%d\n", (int)getpid() ); 796 fclose( fp ); 797 slapd_pid_file_unlink = 1; 798 } 799 800 if ( slapd_args_file != NULL ) { 801 FILE *fp = fopen( slapd_args_file, "w" ); 802 803 if ( fp == NULL ) { 804 char ebuf[128]; 805 int save_errno = errno; 806 807 Debug( LDAP_DEBUG_ANY, "unable to open args file " 808 "\"%s\": %d (%s)\n", 809 slapd_args_file, save_errno, 810 AC_STRERROR_R( save_errno, ebuf, sizeof(ebuf) ) ); 811 812 free( slapd_args_file ); 813 slapd_args_file = NULL; 814 815 rc = 1; 816 goto destroy; 817 } 818 819 for ( i = 0; i < g_argc; i++ ) { 820 fprintf( fp, "%s ", g_argv[i] ); 821 } 822 fprintf( fp, "\n" ); 823 fclose( fp ); 824 slapd_args_file_unlink = 1; 825 } 826 827 /* 828 * FIXME: moved here from lloadd_daemon_task() 829 * because back-monitor db_open() needs it 830 */ 831 time( &starttime ); 832 833 Debug( LDAP_DEBUG_ANY, "lloadd starting\n" ); 834 835 #ifndef HAVE_WINSOCK 836 if ( !no_detach ) { 837 write( waitfds[1], "1", 1 ); 838 close( waitfds[1] ); 839 } 840 #endif 841 842 #ifdef HAVE_NT_EVENT_LOG 843 if ( is_NT_Service ) 844 lutil_LogStartedEvent( serverName, slap_debug, 845 configfile ? configfile : LLOADD_DEFAULT_CONFIGFILE, urls ); 846 #endif 847 848 rc = lloadd_daemon( daemon_base ); 849 850 #ifdef HAVE_NT_SERVICE_MANAGER 851 /* Throw away the event that we used during the startup process. */ 852 if ( is_NT_Service ) ldap_pvt_thread_cond_destroy( &started_event ); 853 #endif 854 855 destroy: 856 if ( daemon_base ) { 857 for ( i = 0; signal_handlers[i].signal; i++ ) { 858 if ( signal_handlers[i].event ) { 859 event_del( signal_handlers[i].event ); 860 event_free( signal_handlers[i].event ); 861 } 862 } 863 event_base_free( daemon_base ); 864 } 865 866 if ( check & CHECK_LOGLEVEL ) { 867 (void)loglevel_print( stdout ); 868 } 869 /* remember an error during destroy */ 870 rc |= lload_destroy(); 871 872 stop: 873 #ifdef HAVE_NT_EVENT_LOG 874 if ( is_NT_Service ) lutil_LogStoppedEvent( serverName ); 875 #endif 876 877 Debug( LDAP_DEBUG_ANY, "lloadd stopped.\n" ); 878 879 #ifdef HAVE_NT_SERVICE_MANAGER 880 lutil_ReportShutdownComplete(); 881 #endif 882 883 #ifdef LOG_DEBUG 884 closelog(); 885 #endif 886 lloadd_daemon_destroy(); 887 888 #ifdef HAVE_TLS 889 if ( lload_tls_ld ) { 890 ldap_pvt_tls_ctx_free( lload_tls_ctx ); 891 ldap_unbind_ext( lload_tls_ld, NULL, NULL ); 892 } 893 ldap_pvt_tls_destroy(); 894 #endif 895 896 if ( slapd_pid_file_unlink ) { 897 unlink( slapd_pid_file ); 898 } 899 if ( slapd_args_file_unlink ) { 900 unlink( slapd_args_file ); 901 } 902 903 lload_config_destroy(); 904 905 if ( configfile ) ch_free( configfile ); 906 if ( configdir ) ch_free( configdir ); 907 if ( urls ) ch_free( urls ); 908 if ( global_host ) ch_free( global_host ); 909 910 /* kludge, get symbols referenced */ 911 ldap_tavl_free( NULL, NULL ); 912 913 MAIN_RETURN(rc); 914 } 915 916 #ifdef SIGPIPE 917 918 /* 919 * Catch and discard terminated child processes, to avoid zombies. 920 */ 921 922 static void 923 sigpipe( evutil_socket_t sig, short what, void *arg ) 924 { 925 } 926 927 #endif /* SIGPIPE */ 928 929 #ifdef LDAP_SIGCHLD 930 931 /* 932 * Catch and discard terminated child processes, to avoid zombies. 933 */ 934 935 static void 936 wait4child( evutil_socket_t sig, short what, void *arg ) 937 { 938 int save_errno = errno; 939 940 #ifdef WNOHANG 941 do 942 errno = 0; 943 #ifdef HAVE_WAITPID 944 while ( waitpid( (pid_t)-1, NULL, WNOHANG ) > 0 || errno == EINTR ); 945 #else 946 while ( wait3( NULL, WNOHANG, NULL ) > 0 || errno == EINTR ); 947 #endif 948 #else 949 (void)wait( NULL ); 950 #endif 951 errno = save_errno; 952 } 953 954 #endif /* LDAP_SIGCHLD */ 955