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