2 * (c) Copyright 1992 by Panagiotis Tsirigotis
3 * (c) Copyright 1998-2001 by Rob Braun
4 * All rights reserved. The file named COPYRIGHT specifies the terms
5 * and conditions for redistribution.
11 #include <sys/types.h>
21 #include "internals.h"
30 __attribute__ ((noreturn))
32 static void main_loop(void);
33 static void find_bad_fd(void) ;
36 * The following are the only global variables of this program
38 struct program_state ps ;
40 char program_version[] = XINETD_VERSION ;
41 int signals_pending[2] = {-1, -1} ;
44 * This is where the story starts...
46 int main( int argc, char *argv[] )
48 const char *func = "main" ;
50 init_daemon( argc, argv ) ;
56 /* Do the chdir after reading the config file. Relative path names
60 msg(LOG_ERR, func, "Can't chdir to /: %m");
63 /* Print out all the options we're compiled with. Makes support
65 * Also, try to get them all into one syslog message for atomicity
67 msg( LOG_NOTICE, func, "%s started with "
80 #ifdef HAVE_DNSREGISTRATION
83 #if !defined(LIBWRAP) && !defined(HAVE_LOADAVG) && !defined(HAVE_MDNS) && !defined(HAVE_HOWL) && !defined(HAVE_DNSREGISTRATION)
86 "options compiled in."
89 msg( LOG_NOTICE, func, "Started working: %d available service%s",
90 ps.rws.available_services,
91 ( ps.rws.available_services != 1 ) ? "s" : "" ) ;
94 * The reason for doing the setjmp here instead of in main_loop is
95 * that setjmp is not guaranteed to restore register values which
96 * can cause a problem for register variables
98 if ( sigsetjmp( ps.rws.env, 1 ) == 0 )
99 ps.rws.env_is_valid = TRUE ;
109 * What main_loop does:
111 * select on all active services
112 * for each socket where a request is pending
113 * try to start a server
115 static void main_loop(void)
117 const char *func = "main_loop" ;
118 struct timeval tv, *tvptr = NULL;
120 FD_SET(signals_pending[0], &ps.rws.socket_mask);
121 if ( signals_pending[0] > ps.rws.mask_max )
122 ps.rws.mask_max = signals_pending[0] ;
123 if ( signals_pending[1] > ps.rws.mask_max )
124 ps.rws.mask_max = signals_pending[1] ;
133 msg( LOG_DEBUG, func,
134 "active_services = %d", ps.rws.active_services ) ;
136 /* get the next timer value, if there is one, and select for that time */
137 if( (tv.tv_sec = xtimer_nexttime()) >= 0 ) {
144 read_mask = ps.rws.socket_mask ;
145 n_active = select( ps.rws.mask_max+1, &read_mask,
146 FD_SET_NULL, FD_SET_NULL, tvptr ) ;
147 if ( n_active == -1 )
149 if ( errno == EINTR ) {
151 } else if ( errno == EBADF )
155 else if ( n_active == 0 ) {
161 msg( LOG_DEBUG, func, "select returned %d", n_active ) ;
165 if( FD_ISSET(signals_pending[0], &read_mask) ) {
167 if ( --n_active == 0 )
172 if( xinetd_mdns_poll() == 0 )
173 if ( --n_active == 0 )
177 for ( u = 0 ; u < pset_count( SERVICES( ps ) ) ; u++ )
181 sp = SP( pset_pointer( SERVICES( ps ), u ) ) ;
183 if ( ! SVC_IS_ACTIVE( sp ) )
186 if ( FD_ISSET( SVC_FD( sp ), &read_mask ) )
189 if ( --n_active == 0 )
194 msg( LOG_ERR, func, "%d descriptors still set", n_active ) ;
200 * This function identifies if any of the fd's in the socket mask
201 * is bad. We use it in case select(2) returns EBADF
202 * When we identify such a bad fd, we remove it from the mask
203 * and deactivate the service.
205 static void find_bad_fd(void)
209 unsigned bad_fd_count = 0 ;
210 const char *func = "find_bad_fd" ;
212 for ( fd = 0 ; (unsigned)fd < ps.ros.max_descriptors ; fd++ )
213 if ( FD_ISSET( fd, &ps.rws.socket_mask ) && fstat( fd, &st ) == -1 )
218 for ( u = 0 ; u < pset_count( SERVICES( ps ) ) ; u++ )
220 register struct service *sp ;
222 sp = SP( pset_pointer( SERVICES( ps ), u ) ) ;
224 if ( ! SVC_IS_AVAILABLE( sp ) )
227 if ( SVC_FD( sp ) == fd )
230 "file descriptor of service %s has been closed",
232 svc_deactivate( sp ) ;
239 FD_CLR( fd, &ps.rws.socket_mask ) ;
241 "No active service for file descriptor %d\n", fd ) ;
245 if ( bad_fd_count == 0 )
246 msg( LOG_NOTICE, func,
247 "select reported EBADF but no bad file descriptors were found" ) ;
252 * Deactivates all active processes.
253 * The real reason for doing this instead of just exiting is
254 * to deregister the RPC services
256 void quit_program(void)
259 struct service_config *scp = NULL;
260 const char *func = "quit_program" ;
262 destroy_global_access_list() ;
264 for ( u = 0 ; u < pset_count( SERVICES( ps ) ) ; u++ ) {
265 scp = SVC_CONF( SP(pset_pointer(SERVICES(ps), u)) );
267 /* This is essentially the same as the following function,
268 * Except we forcibly deactivate them, rather than just
271 if( SC_IS_INTERNAL( scp ) )
272 svc_deactivate( SP( pset_pointer( SERVICES( ps ), u ) ) ) ;
273 if( SC_REDIR_ADDR(scp) != NULL )
274 svc_deactivate( SP( pset_pointer( SERVICES( ps ), u ) ) ) ;
275 if( SC_IS_RPC( scp ) )
276 svc_deactivate( SP( pset_pointer( SERVICES( ps ), u ) ) ) ;
279 if ( ps.ros.pid_file ) {
280 unlink(ps.ros.pid_file);
283 msg( LOG_WARNING, func, "Exiting..." ) ;
288 void terminate_program(void)
291 struct service_config *scp = NULL;
292 void terminate_servers(struct service *);
294 for ( u = 0 ; u < pset_count( SERVICES( ps ) ) ; u++ ) {
295 scp = SVC_CONF( SP(pset_pointer(SERVICES(ps), u)) );
297 /* Terminate the service if it is:
298 * 1) internal (if we don't, it'll zombie)
299 * 2) a redirector (again, if we don't it'll zombie)
300 * 3) It's RPC (we must deregister it.
302 if( SC_IS_INTERNAL( scp ) )
303 terminate_servers( SP( pset_pointer( SERVICES( ps ), u ) ) ) ;
304 if( SC_REDIR_ADDR( scp ) != NULL )
305 terminate_servers( SP( pset_pointer( SERVICES( ps ), u ) ) ) ;
306 if( SC_IS_RPC( scp ) )
307 terminate_servers( SP( pset_pointer( SERVICES( ps ), u ) ) ) ;