2 * (c) Copyright 1992 by Panagiotis Tsirigotis
3 * (c) Sections Copyright 1998-2001 by Rob Braun
4 * All rights reserved. The file named COPYRIGHT specifies the terms
5 * and conditions for redistribution.
12 #ifdef HAVE_SYS_RESOURCE_H
13 #include <sys/resource.h>
27 #include "confparse.h"
33 #include "internals.h"
34 #include "libportable.h"
39 status_e (*initializer)() ;
44 static const struct module program_modules[] =
46 { "signal", signal_init },
47 { "environment", initenv },
52 static bool_int have_stderr ;
56 static void set_fd_limit(void);
59 * This function is invoked when a system call fails during initialization.
60 * A message is printed to stderr, and the program is terminated
63 __attribute__ ((noreturn))
65 static void syscall_failed( const char *call )
71 err = strerror(errno);
72 Sprint( STDERR_FD, "%s: %s failed: %s\n", program_name, call, err ) ;
80 * Close all descriptors except STDERR_FD. We need this to report
81 * errors and the process pid of the daemon.
82 * Open all descriptors in the range 0..MAX_PASS_FD (except STDERR_FD)
84 * STDERR_FD should not be 0.
86 * msg() cannot be used from this function, as it has not been initialized yet.
88 static void setup_file_descriptors(void)
94 if ( Smorefds(3) == SIO_ERR )
96 syscall_failed("Smorefds");
103 * Close all unneeded descriptors
105 for ( fd = STDERR_FD + 1 ; (unsigned)fd < ps.ros.max_descriptors ; fd++ )
106 if ( Sclose( fd ) && errno != EBADF )
108 syscall_failed("Sclose");
113 * Check if the STDERR_FD descriptor is open.
115 new_fd = dup( STDERR_FD ) ;
119 (void) Sclose( new_fd ) ;
122 if ( ( null_fd = open( "/dev/null", O_RDONLY ) ) == -1 )
123 syscall_failed( "open of '/dev/null'" ) ;
125 for ( fd = 0 ; fd <= MAX_PASS_FD ; fd++ )
127 if ( have_stderr && fd == STDERR_FD )
129 if ( fd != null_fd && dup2( null_fd, fd ) == -1 )
130 syscall_failed( "dup2" ) ;
133 if ( null_fd > MAX_PASS_FD )
134 (void) Sclose( null_fd ) ;
138 /* msg() cannot be used in this function, as it has not been initialized yet. */
139 static void set_fd_limit(void)
146 * Set the soft file descriptor limit to the hard limit.
148 if ( getrlimit( RLIMIT_NOFILE, &rl ) == -1 )
150 syscall_failed("getrlimit(RLIMIT_NOFILE)");
155 if ( rl.rlim_max == RLIM_INFINITY )
156 rl.rlim_max = FD_SETSIZE;
158 /* XXX: a dumb way to prevent fd_set overflow possibilities; the rest
159 * of xinetd should be changed to use an OpenBSD inetd-like fd_grow(). */
160 if ( rl.rlim_max > FD_SETSIZE )
161 rl.rlim_max = FD_SETSIZE;
163 rl.rlim_cur = rl.rlim_max ;
164 if ( setrlimit( RLIMIT_NOFILE, &rl ) == -1 )
166 syscall_failed("setrlimit(RLIMIT_NOFILE)");
167 ps.ros.max_descriptors = FD_SETSIZE;
168 ps.ros.orig_max_descriptors = FD_SETSIZE;
172 ps.ros.orig_max_descriptors = maxfd ;
173 ps.ros.max_descriptors = rl.rlim_max ;
174 #else /* ! RLIMIT_NOFILE */
175 ps.ros.max_descriptors = getdtablesize() ;
176 #endif /* RLIMIT_NOFILE */
180 static void init_common( int argc, char *argv[] )
182 const struct module *mp = NULL;
183 const char *func = "init_common" ;
186 * Initialize the program state
191 ps.ros.is_superuser = ( geteuid() == 0 ) ;
194 * Initialize the program modules
196 for ( mp = program_modules ; mp->name ; mp++ )
197 if ( (*mp->initializer)() == FAILED )
200 "Initialization of %s facility failed. Exiting...", mp->name ) ;
203 (void) umask( umask( 077 ) | 022 ) ;
206 /* Create the pidfile.
207 * This is called after msg_init(), and potentially after
208 * we've become_daemon() (depending on if we're in debug or not-forking)
210 static void create_pidfile(void)
215 if ( ps.ros.pid_file ) {
216 unlink(ps.ros.pid_file);
217 pidfd = open(ps.ros.pid_file, O_EXCL|O_CREAT|O_WRONLY,
218 S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
219 if (pidfd >= 0) { /* successfully created file */
220 pidfile = fdopen(pidfd, "w");
222 fchmod(pidfd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
223 fprintf(pidfile, "%d\n", getpid());
226 msg(LOG_DEBUG, "create_pidfile", "fdopen failed: %m");
230 msg(LOG_DEBUG, "create_pidfile", "open failed: %m");
235 * Become a daemon by forking a new process. The parent process exits.
237 static void become_daemon(void)
241 const char *func = "become_daemon" ;
244 * First fork so that the parent will think we have exited
246 for ( tries = 0 ;; tries++ )
250 msg( LOG_CRIT, func, "fork: %m. Exiting..." ) ;
258 sleep( 1 ) ; /* wait for a second */
259 continue ; /* and then retry */
267 (void) dup2( 0, STDERR_FD ) ;
271 sleep( 20 ) ; /* XXX: timers will probably not work after this */
276 static pset_h new_table( unsigned size )
278 const char *func = "new_table" ;
279 pset_h tab = pset_create( size, 0 ) ;
283 msg( LOG_CRIT, func, "Failed to create table" ) ;
293 static void init_rw_state( void )
295 SERVERS( ps ) = new_table( 0 ) ;
296 RETRIES( ps ) = new_table( 0 ) ;
297 SERVICES( ps ) = new_table( 0 ) ;
299 ps.rws.descriptors_free = ps.ros.max_descriptors - DESCRIPTORS_RESERVED ;
301 FD_ZERO( &ps.rws.socket_mask ) ;
302 ps.rws.mask_max = 0 ;
308 * Perform all necessary initializations
310 void init_daemon( int argc, char *argv[] )
312 const char *fail = NULL;
315 memset(&ps, 0, sizeof(ps));
317 setup_file_descriptors() ;
318 ps.ros.config_file = DEFAULT_CONFIG_FILE ;
319 (void) opt_recognize( argc, argv ) ;
322 * XXX: we only use xlog_parms on XLOG_SYSLOG-type logs but in general
323 * we should do it for all types of xlog's we may use. We can get
324 * away with this now, because xlog_parms for XLOG_FILELOG is a noop.
326 (void) xlog_parms( XLOG_SYSLOG,
327 program_name, LOG_PID + LOG_NOWAIT, LOG_DAEMON ) ;
330 * Initialize the message facility; after this everything can use the
333 if ( (fail = msg_init()) )
336 Sprint( STDERR_FD, "%s: msg_init failed: %s\n", program_name, fail ) ;
340 init_common( argc, argv ) ;
342 if ( ! debug.on && !dont_fork )
351 * Initialize all services
353 * This function is either successful in starting some services
354 * or it terminates the program.
356 void init_services( void )
358 struct configuration conf ;
359 const char *func = "init_services" ;
361 if ( cnf_get( &conf ) == FAILED )
363 msg( LOG_CRIT, func, "couldn't get configuration. Exiting..." ) ;
367 DEFAULTS( ps ) = CNF_DEFAULTS( &conf ) ;
368 (void) cnf_start_services( &conf ) ;
369 CNF_DEFAULTS( &conf ) = NULL ; /* to avoid the free by cnf_free */
373 * The number of available/active services is kept by the service functions
375 if ( stayalive_option == 0 ) {
376 if ( ps.rws.available_services == 0 )
378 msg( LOG_CRIT, func, "no services. Exiting..." ) ;
379 if ( ps.ros.pid_file ) {
380 unlink(ps.ros.pid_file);
386 spec_include() ; /* include special services */