]> git.sur5r.net Git - openldap/blob - servers/slapd/main.c
Removed XLDFLAGS, unnecessary for modules.
[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
175                 if ( is_NT_Service ) {
176                         CommenceStartupProcessing( NTservice, slap_sig_shutdown );
177                 }
178
179                 i = (int*)getRegParam( NULL, "DebugLevel" );
180                 if ( i != NULL ) 
181                 {
182                         slap_debug = *i;
183                         Debug( LDAP_DEBUG_ANY, "new debug level from registry is: %d\n", slap_debug, 0, 0 );
184                 }
185                 newConfigFile = (char*)getRegParam( NULL, "ConfigFile" );
186                 if ( newConfigFile != NULL ) 
187                 {
188                         configfile = newConfigFile;
189                         Debug ( LDAP_DEBUG_ANY, "new config file from registry is: %s\n", configfile, 0, 0 );
190                 }
191         }
192 #endif
193
194         while ( (i = getopt( argc, argv,
195                              "d:f:h:s:"
196 #ifdef HAVE_CHROOT
197                                 "r:"
198 #endif
199 #ifdef LOG_LOCAL4
200                              "l:"
201 #endif
202 #ifdef SLAPD_BDB2
203                              "t"
204 #endif
205 #if defined(HAVE_SETUID) && defined(HAVE_SETGID)
206                              "u:g:"
207 #endif
208 #ifdef LDAP_CONNECTIONLESS
209                                  "c"
210 #endif
211 #ifdef HAVE_NT_EVENT_LOG
212                                  "n:"
213 #endif
214                              )) != EOF ) {
215                 switch ( i ) {
216                 case 'h':       /* listen URLs */
217                         if ( urls != NULL ) free( urls );
218                         urls = ch_strdup( optarg );
219             break;
220
221                 case 'd':       /* set debug level and 'do not detach' flag */
222                         no_detach = 1;
223 #ifdef LDAP_DEBUG
224                         slap_debug |= atoi( optarg );
225 #else
226                         if ( atoi( optarg ) != 0 )
227                                 fputs( "must compile with LDAP_DEBUG for debugging\n",
228                                        stderr );
229 #endif
230                         break;
231
232                 case 'f':       /* read config file */
233                         configfile = ch_strdup( optarg );
234                         break;
235
236                 case 's':       /* set syslog level */
237                         ldap_syslog = atoi( optarg );
238                         break;
239
240 #ifdef LOG_LOCAL4
241                 case 'l':       /* set syslog local user */
242                         syslogUser = cnvt_str2int( optarg,
243                                 syslog_types, DEFAULT_SYSLOG_USER );
244                         break;
245 #endif
246
247 #ifdef LDAP_CONNECTIONLESS
248                 case 'c':       /* do connectionless (udp) */
249                         /* udp = 1; */
250                         fprintf( stderr, "connectionless support not supported");
251                         exit( EXIT_FAILURE );
252                         break;
253 #endif
254
255 #ifdef SLAPD_BDB2
256                 case 't':  /* timed server */
257                         serverMode |= SLAP_TIMED_MODE;
258                         break;
259 #endif
260
261 #ifdef HAVE_CHROOT
262                 case 'r':
263                         if( sandbox ) free(sandbox);
264                         sandbox = ch_strdup( optarg );
265                         break;
266 #endif
267
268 #if defined(HAVE_SETUID) && defined(HAVE_SETGID)
269                 case 'u':       /* user name */
270                         if( username ) free(username);
271                         username = ch_strdup( optarg );
272                         break;
273
274                 case 'g':       /* group name */
275                         if( groupname ) free(groupname);
276                         groupname = ch_strdup( optarg );
277                         break;
278 #endif /* SETUID && GETUID */
279
280 #ifdef HAVE_NT_EVENT_LOG
281                 case 'n':  /* NT service name */
282                         NTservice = ch_strdup( optarg );
283                         break;
284 #endif
285                 default:
286                         usage( argv[0] );
287                         rc = 1;
288                         SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 15 );
289                         goto stop;
290                 }
291         }
292
293         ber_set_option(NULL, LBER_OPT_DEBUG_LEVEL, &slap_debug);
294         ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &slap_debug);
295         ldif_debug = slap_debug;
296
297         Debug( LDAP_DEBUG_TRACE, "%s", Versionstr, 0, 0 );
298
299         if ( (serverName = strrchr( argv[0], *LDAP_DIRSEP )) == NULL ) {
300                 serverName = ch_strdup( argv[0] );
301         } else {
302                 serverName = ch_strdup( serverName + 1 );
303         }
304
305 #ifdef LOG_LOCAL4
306         openlog( serverName, OPENLOG_OPTIONS, syslogUser );
307 #elif LOG_DEBUG
308         openlog( serverName, OPENLOG_OPTIONS );
309 #endif
310
311         if( slapd_daemon_init( urls ) != 0 ) {
312                 rc = 1;
313                 SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 16 );
314                 goto stop;
315         }
316
317 #if defined(HAVE_CHROOT)
318         if ( sandbox && chroot( sandbox ) ) {
319                 perror("chroot");
320                 rc = 1;
321                 goto stop;
322         }
323 #endif
324
325 #if defined(HAVE_SETUID) && defined(HAVE_SETGID)
326         if ( username != NULL || groupname != NULL ) {
327                 slap_init_user( username, groupname );
328         }
329 #endif
330
331         extops_init();
332
333 #ifdef SLAPD_MODULES
334         if ( module_init() != 0 ) {
335                 rc = 1;
336                 SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 17 );
337                 goto destroy;
338         }
339 #endif
340
341         if ( slap_init( serverMode, serverName ) != 0 ) {
342                 rc = 1;
343                 SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 18 );
344                 goto destroy;
345         }
346
347         if ( read_config( configfile ) != 0 ) {
348                 rc = 1;
349                 SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 19 );
350                 goto destroy;
351         }
352
353 #ifdef HAVE_TLS
354         ldap_pvt_tls_init();
355         ldap_pvt_tls_init_def_ctx();
356 #endif
357
358         (void) SIGNAL( LDAP_SIGUSR1, slap_sig_wake );
359         (void) SIGNAL( LDAP_SIGUSR2, slap_sig_shutdown );
360
361 #ifdef SIGPIPE
362         (void) SIGNAL( SIGPIPE, SIG_IGN );
363 #endif
364 #ifdef SIGHUP
365         (void) SIGNAL( SIGHUP, slap_sig_shutdown );
366 #endif
367         (void) SIGNAL( SIGINT, slap_sig_shutdown );
368         (void) SIGNAL( SIGTERM, slap_sig_shutdown );
369 #ifdef LDAP_SIGCHLD
370         (void) SIGNAL( LDAP_SIGCHLD, wait4child );
371 #endif
372 #ifdef SIGBREAK
373         /* SIGBREAK is generated when Ctrl-Break is pressed. */
374         (void) SIGNAL( SIGBREAK, slap_sig_shutdown );
375 #endif
376
377 #ifndef HAVE_WINSOCK
378         lutil_detach( no_detach, 0 );
379 #endif /* HAVE_WINSOCK */
380
381 #ifdef CSRIMALLOC
382         mal_leaktrace(1);
383 #endif
384
385         if ( slap_startup( NULL )  != 0 ) {
386                 rc = 1;
387                 SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 20 );
388                 goto shutdown;
389         }
390
391         {
392                 FILE *fp;
393
394                 Debug( LDAP_DEBUG_ANY, "slapd starting\n", 0, 0, 0 );
395
396                 if (( slapd_pid_file != NULL ) &&
397                         (( fp = fopen( slapd_pid_file, "w" )) != NULL ))
398                 {
399                         fprintf( fp, "%d\n", (int) getpid() );
400                         fclose( fp );
401                 }
402
403                 if (( slapd_args_file != NULL ) &&
404                         (( fp = fopen( slapd_args_file, "w" )) != NULL ))
405                 {
406                         for ( i = 0; i < g_argc; i++ ) {
407                                 fprintf( fp, "%s ", g_argv[i] );
408                         }
409                         fprintf( fp, "\n" );
410                         fclose( fp );
411                 }
412         }
413
414 #ifdef HAVE_NT_EVENT_LOG
415         LogSlapdStartedEvent( NTservice, slap_debug, configfile, urls );
416 #endif
417
418         rc = slapd_daemon();
419
420 #ifdef HAVE_NT_SERVICE_MANAGER
421         /* Throw away the event that we used during the startup process. */
422         if ( is_NT_Service )
423                 ldap_pvt_thread_cond_destroy( &started_event );
424 #endif
425
426 shutdown:
427         /* remember an error during shutdown */
428         rc |= slap_shutdown( NULL );
429
430 destroy:
431         /* remember an error during destroy */
432         rc |= slap_destroy();
433
434 #ifdef SLAPD_MODULES
435         module_kill();
436 #endif
437
438         extops_kill();
439
440 stop:
441 #ifdef HAVE_NT_EVENT_LOG
442         LogSlapdStoppedEvent( NTservice );
443 #endif
444
445         Debug( LDAP_DEBUG_ANY, "slapd stopped.\n", 0, 0, 0 );
446
447 #ifdef HAVE_NT_SERVICE_MANAGER
448         ReportSlapdShutdownComplete();
449 #endif
450
451 #ifdef LOG_DEBUG
452     closelog();
453 #endif
454         slapd_daemon_destroy();
455
456 #ifdef CSRIMALLOC
457         mal_dumpleaktrace( leakfile );
458 #endif
459
460         MAIN_RETURN(rc);
461 }
462
463
464 #ifdef LDAP_SIGCHLD
465
466 /*
467  *  Catch and discard terminated child processes, to avoid zombies.
468  */
469
470 static RETSIGTYPE
471 wait4child( int sig )
472 {
473     int save_errno = errno;
474
475 #ifdef WNOHANG
476     errno = 0;
477 #ifdef HAVE_WAITPID
478     while ( waitpid( (pid_t)-1, NULL, WNOHANG ) >= 0 || errno == EINTR )
479         ;       /* NULL */
480 #else
481     while ( wait3( NULL, WNOHANG, NULL ) >= 0 || errno == EINTR )
482         ;       /* NULL */
483 #endif
484 #else
485     (void) wait( NULL );
486 #endif
487     (void) SIGNAL( sig, wait4child );
488     errno = save_errno;
489 }
490
491 #endif /* SIGCHLD || SIGCLD */
492
493
494 #ifdef LOG_LOCAL4
495
496 /*
497  *  Convert a string to an integer by means of a dispatcher table
498  *  if the string is not in the table return the default
499  */
500
501 static int
502 cnvt_str2int( char *stringVal, STRDISP_P dispatcher, int defaultVal )
503 {
504     int        retVal = defaultVal;
505     STRDISP_P  disp;
506
507     for (disp = dispatcher; disp->stringVal; disp++) {
508
509         if (!strncasecmp (stringVal, disp->stringVal, disp->abbr)) {
510
511             retVal = disp->intVal;
512             break;
513
514         }
515     }
516
517     return (retVal);
518 }
519
520 #endif  /* LOG_LOCAL4 */