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
slapd_opt_slp(const char * val,void * arg)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
parse_syslog_user(const char * arg,int * syslogUser)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
parse_syslog_level(const char * arg,int * levelp)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
parse_debug_unknowns(char ** unknowns,int * levelp)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
parse_debug_level(const char * arg,int * levelp,char *** unknowns)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
usage(char * name)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
ServiceMain(DWORD argc,LPTSTR * argv)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
sigpipe(evutil_socket_t sig,short what,void * arg)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
wait4child(evutil_socket_t sig,short what,void * arg)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