]> git.sur5r.net Git - openldap/blob - servers/slapd/main.c
Exit loop after matching command is found in openldap_ldap_init_w_conf
[openldap] / servers / slapd / main.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6 #include "portable.h"
7
8 #include <stdio.h>
9
10 #include <ac/signal.h>
11 #include <ac/socket.h>
12 #include <ac/string.h>
13 #include <ac/time.h>
14 #include <ac/unistd.h>
15 #include <ac/wait.h>
16 #include <ac/signal.h>
17 #include <ac/errno.h>
18
19 #include "slap.h"
20 #include "lutil.h"
21
22 #ifdef LDAP_SIGCHLD
23 static RETSIGTYPE wait4child( int sig );
24 #endif
25
26 #ifdef HAVE_NT_SERVICE_MANAGER
27 #define MAIN_RETURN(x) return
28 struct sockaddr_in      bind_addr;
29
30 /* in nt_main.c */
31 LIBLUTIL_F (SERVICE_STATUS)             SLAPDServiceStatus;
32 LIBLUTIL_F (SERVICE_STATUS_HANDLE)      hSLAPDServiceStatus;
33 extern ldap_pvt_thread_cond_t   started_event,          stopped_event;
34 extern int        is_NT_Service;
35
36 void CommenceStartupProcessing( LPCTSTR serviceName,
37                                                            void(*stopper)(int));
38 void ReportSlapdShutdownComplete( void );
39 void *getRegParam( char *svc, char *value );
40
41 #define SERVICE_EXIT( e, n )    do { \
42         if ( is_NT_Service ) { \
43                 SLAPDServiceStatus.dwWin32ExitCode                              = (e); \
44                 SLAPDServiceStatus.dwServiceSpecificExitCode    = (n); \
45         } \
46 } while ( 0 )
47
48 #else
49 #define SERVICE_EXIT( e, n )
50 #define MAIN_RETURN(x) return(x)
51 #endif
52
53 #ifdef HAVE_NT_EVENT_LOG
54 void LogSlapdStartedEvent( char *svc, int slap_debug, char *configfile, char *urls );
55 void LogSlapdStoppedEvent( char *svc );
56 #endif
57
58 /*
59  * when more than one slapd is running on one machine, each one might have
60  * it's own LOCAL for syslogging and must have its own pid/args files
61  */
62
63 #ifndef HAVE_MKVERSION
64 const char Versionstr[] =
65         OPENLDAP_PACKAGE " " OPENLDAP_VERSION " Standalone LDAP Server (slapd)";
66 #endif
67
68 #ifdef LOG_LOCAL4
69
70 #define DEFAULT_SYSLOG_USER  LOG_LOCAL4
71
72 typedef struct _str2intDispatch {
73         char    *stringVal;
74         int      abbr;
75         int      intVal;
76 } STRDISP, *STRDISP_P;
77
78
79 /* table to compute syslog-options to integer */
80 static STRDISP  syslog_types[] = {
81         { "LOCAL0", sizeof("LOCAL0"), LOG_LOCAL0 },
82         { "LOCAL1", sizeof("LOCAL1"), LOG_LOCAL1 },
83         { "LOCAL2", sizeof("LOCAL2"), LOG_LOCAL2 },
84         { "LOCAL3", sizeof("LOCAL3"), LOG_LOCAL3 },
85         { "LOCAL4", sizeof("LOCAL4"), LOG_LOCAL4 },
86         { "LOCAL5", sizeof("LOCAL5"), LOG_LOCAL5 },
87         { "LOCAL6", sizeof("LOCAL6"), LOG_LOCAL6 },
88         { "LOCAL7", sizeof("LOCAL7"), LOG_LOCAL7 },
89         { NULL }
90 };
91
92 static int   cnvt_str2int( char *, STRDISP_P, int );
93
94 #endif  /* LOG_LOCAL4 */
95
96
97 static void
98 usage( char *name )
99 {
100         fprintf( stderr,
101                 "usage: %s options\n", name );
102         fprintf( stderr,
103 #if LDAP_CONNECTIONLESS
104                 "\t-c\t\tEnable (experimental) Connectionless LDAP\n"
105 #endif
106                 "\t-d level\tDebug Level" "\n"
107                 "\t-f filename\tConfiguration File\n"
108 #if defined(HAVE_SETUID) && defined(HAVE_SETGID)
109                 "\t-g group\tGroup (id or name) to ran as\n"
110 #endif
111                 "\t-h URLs\tList of URLs to serve\n"
112 #ifdef LOG_LOCAL4
113                 "\t-l sysloguser\tSyslog User (default: LOCAL4)\n"
114 #endif
115 #ifdef HAVE_NT_EVENT_LOG
116                 "\t-n NTserviceName\tNT service name\n"
117 #endif
118
119                 "\t-s level\tSyslog Level\n"
120 #ifdef SLAPD_BDB2
121                 "\t-t\t\tEnable BDB2 timing\n"
122 #endif
123 #if defined(HAVE_SETUID) && defined(HAVE_SETGID)
124                 "\t-u user\tUser (id or name) to ran as\n"
125 #endif
126     );
127 }
128
129 #ifdef HAVE_NT_SERVICE_MANAGER
130 void WINAPI ServiceMain( DWORD argc, LPTSTR *argv )
131 #else
132 int main( int argc, char **argv )
133 #endif
134 {
135         int             i, no_detach = 0;
136         int             rc;
137         char *urls = NULL;
138 #if defined(HAVE_SETUID) && defined(HAVE_SETGID)
139         char *username = NULL;
140         char *groupname = NULL;
141 #endif
142 #if defined(HAVE_CHROOT)
143         char *sandbox = NULL;
144 #endif
145 #ifdef LOG_LOCAL4
146     int     syslogUser = DEFAULT_SYSLOG_USER;
147 #endif
148
149 #ifdef HAVE_NT_EVENT_LOG
150         char        *NTservice  = SERVICE_NAME;
151 #endif
152 #ifdef HAVE_NT_SERVICE_MANAGER
153         char            *configfile = ".\\slapd.conf";
154 #else
155         char            *configfile = SLAPD_DEFAULT_CONFIGFILE;
156 #endif
157         char        *serverName;
158         int         serverMode = SLAP_SERVER_MODE;
159
160 #ifdef CSRIMALLOC
161         FILE *leakfile;
162         if( ( leakfile = fopen( "slapd.leak", "w" )) == NULL ) {
163                 leakfile = stderr;
164         }
165 #endif
166
167         g_argc = argc;
168         g_argv = argv;
169
170 #ifdef HAVE_NT_SERVICE_MANAGER
171         {
172                 int *i;
173                 char *newConfigFile;
174                 char *newUrls;
175
176                 if ( is_NT_Service ) {
177                         NTservice = argv[0];
178                         CommenceStartupProcessing( NTservice, slap_sig_shutdown );
179                 }
180
181                 i = (int*)getRegParam( NTservice, "DebugLevel" );
182                 if ( i != NULL ) 
183                 {
184                         slap_debug = *i;
185                         Debug( LDAP_DEBUG_ANY, "new debug level from registry is: %d\n", slap_debug, 0, 0 );
186                 }
187
188                 newUrls = (char *) getRegParam(NTservice, "Urls");
189                 if (newUrls)
190                 {
191                     if (urls)
192                         ch_free(urls);
193
194                     urls = ch_strdup(newUrls);
195                     Debug(LDAP_DEBUG_ANY, "new urls from registry: %s\n",
196                           urls, 0, 0);
197                 }
198
199                 newConfigFile = (char*)getRegParam( NTservice, "ConfigFile" );
200                 if ( newConfigFile != NULL ) 
201                 {
202                         configfile = newConfigFile;
203                         Debug ( LDAP_DEBUG_ANY, "new config file from registry is: %s\n", configfile, 0, 0 );
204                 }
205         }
206 #endif
207
208         while ( (i = getopt( argc, argv,
209                              "d:f:h:s:"
210 #ifdef HAVE_CHROOT
211                                 "r:"
212 #endif
213 #ifdef LOG_LOCAL4
214                              "l:"
215 #endif
216 #ifdef SLAPD_BDB2
217                              "t"
218 #endif
219 #if defined(HAVE_SETUID) && defined(HAVE_SETGID)
220                              "u:g:"
221 #endif
222 #ifdef LDAP_CONNECTIONLESS
223                                  "c"
224 #endif
225 #ifdef HAVE_NT_EVENT_LOG
226                                  "n:"
227 #endif
228                              )) != EOF ) {
229                 switch ( i ) {
230                 case 'h':       /* listen URLs */
231                         if ( urls != NULL ) free( urls );
232                         urls = ch_strdup( optarg );
233             break;
234
235                 case 'd':       /* set debug level and 'do not detach' flag */
236                         no_detach = 1;
237 #ifdef LDAP_DEBUG
238                         slap_debug |= atoi( optarg );
239 #else
240                         if ( atoi( optarg ) != 0 )
241                                 fputs( "must compile with LDAP_DEBUG for debugging\n",
242                                        stderr );
243 #endif
244                         break;
245
246                 case 'f':       /* read config file */
247                         configfile = ch_strdup( optarg );
248                         break;
249
250                 case 's':       /* set syslog level */
251                         ldap_syslog = atoi( optarg );
252                         break;
253
254 #ifdef LOG_LOCAL4
255                 case 'l':       /* set syslog local user */
256                         syslogUser = cnvt_str2int( optarg,
257                                 syslog_types, DEFAULT_SYSLOG_USER );
258                         break;
259 #endif
260
261 #ifdef LDAP_CONNECTIONLESS
262                 case 'c':       /* do connectionless (udp) */
263                         /* udp = 1; */
264                         fprintf( stderr, "connectionless support not supported");
265                         exit( EXIT_FAILURE );
266                         break;
267 #endif
268
269 #ifdef SLAPD_BDB2
270                 case 't':  /* timed server */
271                         serverMode |= SLAP_TIMED_MODE;
272                         break;
273 #endif
274
275 #ifdef HAVE_CHROOT
276                 case 'r':
277                         if( sandbox ) free(sandbox);
278                         sandbox = ch_strdup( optarg );
279                         break;
280 #endif
281
282 #if defined(HAVE_SETUID) && defined(HAVE_SETGID)
283                 case 'u':       /* user name */
284                         if( username ) free(username);
285                         username = ch_strdup( optarg );
286                         break;
287
288                 case 'g':       /* group name */
289                         if( groupname ) free(groupname);
290                         groupname = ch_strdup( optarg );
291                         break;
292 #endif /* SETUID && GETUID */
293
294 #ifdef HAVE_NT_EVENT_LOG
295                 case 'n':  /* NT service name */
296                         NTservice = ch_strdup( optarg );
297                         break;
298 #endif
299                 default:
300                         usage( argv[0] );
301                         rc = 1;
302                         SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 15 );
303                         goto stop;
304                 }
305         }
306
307         ber_set_option(NULL, LBER_OPT_DEBUG_LEVEL, &slap_debug);
308         ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &slap_debug);
309         ldif_debug = slap_debug;
310
311         Debug( LDAP_DEBUG_TRACE, "%s", Versionstr, 0, 0 );
312
313         if ( (serverName = strrchr( argv[0], *LDAP_DIRSEP )) == NULL ) {
314                 serverName = ch_strdup( argv[0] );
315         } else {
316                 serverName = ch_strdup( serverName + 1 );
317         }
318
319 #ifdef LOG_LOCAL4
320         openlog( serverName, OPENLOG_OPTIONS, syslogUser );
321 #elif LOG_DEBUG
322         openlog( serverName, OPENLOG_OPTIONS );
323 #endif
324
325         if( slapd_daemon_init( urls ) != 0 ) {
326                 rc = 1;
327                 SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 16 );
328                 goto stop;
329         }
330
331 #if defined(HAVE_CHROOT)
332         if ( sandbox && chroot( sandbox ) ) {
333                 perror("chroot");
334                 rc = 1;
335                 goto stop;
336         }
337 #endif
338
339 #if defined(HAVE_SETUID) && defined(HAVE_SETGID)
340         if ( username != NULL || groupname != NULL ) {
341                 slap_init_user( username, groupname );
342         }
343 #endif
344
345         extops_init();
346
347 #ifdef SLAPD_MODULES
348         if ( module_init() != 0 ) {
349                 rc = 1;
350                 SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 17 );
351                 goto destroy;
352         }
353 #endif
354
355         if ( slap_init( serverMode, serverName ) != 0 ) {
356                 rc = 1;
357                 SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 18 );
358                 goto destroy;
359         }
360
361         if ( read_config( configfile ) != 0 ) {
362                 rc = 1;
363                 SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 19 );
364                 goto destroy;
365         }
366
367 #ifdef HAVE_TLS
368         ldap_pvt_tls_init();
369
370         if (ldap_pvt_tls_init_def_ctx() != 0)
371         {
372                 rc = 1;
373                 SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 20 );
374                 goto destroy;
375         }
376 #endif
377
378         (void) SIGNAL( LDAP_SIGUSR1, slap_sig_wake );
379         (void) SIGNAL( LDAP_SIGUSR2, slap_sig_shutdown );
380
381 #ifdef SIGPIPE
382         (void) SIGNAL( SIGPIPE, SIG_IGN );
383 #endif
384 #ifdef SIGHUP
385         (void) SIGNAL( SIGHUP, slap_sig_shutdown );
386 #endif
387         (void) SIGNAL( SIGINT, slap_sig_shutdown );
388         (void) SIGNAL( SIGTERM, slap_sig_shutdown );
389 #ifdef LDAP_SIGCHLD
390         (void) SIGNAL( LDAP_SIGCHLD, wait4child );
391 #endif
392 #ifdef SIGBREAK
393         /* SIGBREAK is generated when Ctrl-Break is pressed. */
394         (void) SIGNAL( SIGBREAK, slap_sig_shutdown );
395 #endif
396
397 #ifndef HAVE_WINSOCK
398         lutil_detach( no_detach, 0 );
399 #endif /* HAVE_WINSOCK */
400
401 #ifdef CSRIMALLOC
402         mal_leaktrace(1);
403 #endif
404
405         if ( slap_startup( NULL )  != 0 ) {
406                 rc = 1;
407                 SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 21 );
408                 goto shutdown;
409         }
410
411         {
412                 FILE *fp;
413
414                 Debug( LDAP_DEBUG_ANY, "slapd starting\n", 0, 0, 0 );
415
416                 if (( slapd_pid_file != NULL ) &&
417                         (( fp = fopen( slapd_pid_file, "w" )) != NULL ))
418                 {
419                         fprintf( fp, "%d\n", (int) getpid() );
420                         fclose( fp );
421                 }
422
423                 if (( slapd_args_file != NULL ) &&
424                         (( fp = fopen( slapd_args_file, "w" )) != NULL ))
425                 {
426                         for ( i = 0; i < g_argc; i++ ) {
427                                 fprintf( fp, "%s ", g_argv[i] );
428                         }
429                         fprintf( fp, "\n" );
430                         fclose( fp );
431                 }
432         }
433
434 #ifdef HAVE_NT_EVENT_LOG
435         if (is_NT_Service)
436         LogSlapdStartedEvent( NTservice, slap_debug, configfile, urls );
437 #endif
438
439         rc = slapd_daemon();
440
441 #ifdef HAVE_NT_SERVICE_MANAGER
442         /* Throw away the event that we used during the startup process. */
443         if ( is_NT_Service )
444                 ldap_pvt_thread_cond_destroy( &started_event );
445 #endif
446
447 shutdown:
448         /* remember an error during shutdown */
449         rc |= slap_shutdown( NULL );
450
451 destroy:
452         /* remember an error during destroy */
453         rc |= slap_destroy();
454
455 #ifdef SLAPD_MODULES
456         module_kill();
457 #endif
458
459         extops_kill();
460
461 stop:
462 #ifdef HAVE_NT_EVENT_LOG
463         if (is_NT_Service)
464         LogSlapdStoppedEvent( NTservice );
465 #endif
466
467         Debug( LDAP_DEBUG_ANY, "slapd stopped.\n", 0, 0, 0 );
468
469 #ifdef HAVE_NT_SERVICE_MANAGER
470         ReportSlapdShutdownComplete();
471 #endif
472
473 #ifdef LOG_DEBUG
474     closelog();
475 #endif
476         slapd_daemon_destroy();
477
478 #ifdef CSRIMALLOC
479         mal_dumpleaktrace( leakfile );
480 #endif
481
482         MAIN_RETURN(rc);
483 }
484
485
486 #ifdef LDAP_SIGCHLD
487
488 /*
489  *  Catch and discard terminated child processes, to avoid zombies.
490  */
491
492 static RETSIGTYPE
493 wait4child( int sig )
494 {
495     int save_errno = errno;
496
497 #ifdef WNOHANG
498     errno = 0;
499 #ifdef HAVE_WAITPID
500     while ( waitpid( (pid_t)-1, NULL, WNOHANG ) >= 0 || errno == EINTR )
501         ;       /* NULL */
502 #else
503     while ( wait3( NULL, WNOHANG, NULL ) >= 0 || errno == EINTR )
504         ;       /* NULL */
505 #endif
506 #else
507     (void) wait( NULL );
508 #endif
509     (void) SIGNAL( sig, wait4child );
510     errno = save_errno;
511 }
512
513 #endif /* SIGCHLD || SIGCLD */
514
515
516 #ifdef LOG_LOCAL4
517
518 /*
519  *  Convert a string to an integer by means of a dispatcher table
520  *  if the string is not in the table return the default
521  */
522
523 static int
524 cnvt_str2int( char *stringVal, STRDISP_P dispatcher, int defaultVal )
525 {
526     int        retVal = defaultVal;
527     STRDISP_P  disp;
528
529     for (disp = dispatcher; disp->stringVal; disp++) {
530
531         if (!strncasecmp (stringVal, disp->stringVal, disp->abbr)) {
532
533             retVal = disp->intVal;
534             break;
535
536         }
537     }
538
539     return (retVal);
540 }
541
542 #endif  /* LOG_LOCAL4 */