~noskcaj/ubuntu/saucy/xinetd/2.3.15

« back to all changes in this revision

Viewing changes to xinetd/main.c

  • Committer: Bazaar Package Importer
  • Author(s): Thomas Seyrat
  • Date: 2004-04-18 13:33:57 UTC
  • Revision ID: james.westby@ubuntu.com-20040418133357-czeqeju37433xvdd
Tags: upstream-2.3.13
ImportĀ upstreamĀ versionĀ 2.3.13

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
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.
 
6
 */
 
7
 
 
8
 
 
9
#include "config.h"
 
10
 
 
11
#include <sys/types.h>
 
12
#include <sys/stat.h>
 
13
#include <sys/time.h>
 
14
#include <errno.h>
 
15
#include <syslog.h>
 
16
#include <unistd.h>
 
17
 
 
18
#include "main.h"
 
19
#include "init.h"
 
20
#include "msg.h"
 
21
#include "internals.h"
 
22
#include "signals.h"
 
23
#include "service.h"
 
24
#include "sconf.h"
 
25
#include "xtimer.h"
 
26
#include "sensor.h"
 
27
 
 
28
#ifdef __GNUC__
 
29
__attribute__ ((noreturn))
 
30
#endif
 
31
static void main_loop(void);
 
32
static void find_bad_fd(void) ;
 
33
 
 
34
/*
 
35
 * The following are the only global variables of this program
 
36
 */
 
37
struct program_state ps ;
 
38
struct debug debug ;
 
39
char program_version[] = XINETD_VERSION ;
 
40
int signals_pending[2] = {-1, -1} ;
 
41
 
 
42
/*
 
43
 * This is where the story starts...
 
44
 */
 
45
int main( int argc, char *argv[] )
 
46
{
 
47
   const char            *func = "main" ;
 
48
 
 
49
   init_daemon( argc, argv ) ;
 
50
   init_services() ;
 
51
 
 
52
   /* Do the chdir after reading the config file.  Relative path names
 
53
    * will work better.  
 
54
    */
 
55
   if (chdir("/") < 0) {
 
56
      msg(LOG_ERR, func, "Can't chdir to /: %m");
 
57
   }
 
58
 
 
59
   /* Print out all the options we're compiled with.  Makes support 
 
60
    * a tad easier.
 
61
    * Also, try to get them all into one syslog message for atomicity
 
62
    */
 
63
   msg( LOG_NOTICE, func, "%s started with "
 
64
#ifdef LIBWRAP
 
65
   "libwrap "
 
66
#endif
 
67
#ifdef HAVE_LOADAVG
 
68
   "loadavg "
 
69
#endif
 
70
#if !defined(LIBWRAP) && !defined(HAVE_LOADAVG)
 
71
   "no "
 
72
#endif
 
73
   "options compiled in."
 
74
   , XINETD_VERSION );
 
75
 
 
76
   msg( LOG_NOTICE, func, "Started working: %d available service%s",
 
77
      ps.rws.available_services,
 
78
         ( ps.rws.available_services != 1 ) ? "s" : "" ) ;
 
79
 
 
80
   /*
 
81
    * The reason for doing the setjmp here instead of in main_loop is
 
82
    * that setjmp is not guaranteed to restore register values which
 
83
    * can cause a problem for register variables
 
84
    */
 
85
   if ( sigsetjmp( ps.rws.env, 1 ) == 0 )
 
86
      ps.rws.env_is_valid = TRUE ;
 
87
 
 
88
   main_loop() ;
 
89
 
 
90
   /* NOTREACHED */
 
91
   exit(1);
 
92
}
 
93
 
 
94
 
 
95
/*
 
96
 * What main_loop does:
 
97
 *
 
98
 *      select on all active services
 
99
 *      for each socket where a request is pending
 
100
 *         try to start a server
 
101
 */
 
102
static void main_loop(void)
 
103
{
 
104
   const char      *func = "main_loop" ;
 
105
   struct timeval   tv, *tvptr = NULL;
 
106
 
 
107
   FD_SET(signals_pending[0], &ps.rws.socket_mask);
 
108
   if ( signals_pending[0] > ps.rws.mask_max )
 
109
      ps.rws.mask_max = signals_pending[0] ;
 
110
   if ( signals_pending[1] > ps.rws.mask_max )
 
111
      ps.rws.mask_max = signals_pending[1] ;
 
112
 
 
113
   for ( ;; )
 
114
   {
 
115
      fd_set read_mask ;
 
116
      int n_active ;
 
117
      unsigned u ;
 
118
 
 
119
      if ( debug.on ) 
 
120
         msg( LOG_DEBUG, func,
 
121
               "active_services = %d", ps.rws.active_services ) ;
 
122
 
 
123
      /* get the next timer value, if there is one, and select for that time */
 
124
      if( (tv.tv_sec = xtimer_nexttime()) >= 0 ) {
 
125
         tv.tv_usec = 0;
 
126
         tvptr = &tv;
 
127
      } else {
 
128
         tvptr = NULL;
 
129
      }
 
130
 
 
131
      read_mask = ps.rws.socket_mask ;
 
132
      n_active = select( ps.rws.mask_max+1, &read_mask,
 
133
                        FD_SET_NULL, FD_SET_NULL, tvptr ) ;
 
134
      if ( n_active == -1 )
 
135
      {
 
136
         if ( errno == EINTR ) {
 
137
            continue ;
 
138
         } else if ( errno == EBADF )
 
139
            find_bad_fd() ;
 
140
         continue ;
 
141
      }
 
142
      else if ( n_active == 0 ) {
 
143
         xtimer_poll();
 
144
         continue ;
 
145
      }
 
146
 
 
147
      if ( debug.on )
 
148
         msg( LOG_DEBUG, func, "select returned %d", n_active ) ;
 
149
 
 
150
      xtimer_poll();
 
151
 
 
152
      if( FD_ISSET(signals_pending[0], &read_mask) ) {
 
153
         check_pipe();
 
154
            if ( --n_active == 0 )
 
155
               continue ;
 
156
      }
 
157
 
 
158
      for ( u = 0 ; u < pset_count( SERVICES( ps ) ) ; u++ )
 
159
      {
 
160
         struct service *sp ;
 
161
 
 
162
         sp = SP( pset_pointer( SERVICES( ps ), u ) ) ;
 
163
 
 
164
         if ( ! SVC_IS_ACTIVE( sp ) )
 
165
            continue ;
 
166
 
 
167
         if ( FD_ISSET( SVC_FD( sp ), &read_mask ) )
 
168
         {
 
169
            svc_request( sp ) ;
 
170
            if ( --n_active == 0 )
 
171
               break ;
 
172
         }
 
173
      }
 
174
      if ( n_active > 0 )
 
175
         msg( LOG_ERR, func, "%d descriptors still set", n_active ) ;
 
176
   }
 
177
}
 
178
 
 
179
 
 
180
/*
 
181
 * This function identifies if any of the fd's in the socket mask
 
182
 * is bad. We use it in case select(2) returns EBADF
 
183
 * When we identify such a bad fd, we remove it from the mask
 
184
 * and deactivate the service.
 
185
 */
 
186
static void find_bad_fd(void)
 
187
{
 
188
   int fd ;
 
189
   struct stat st ;
 
190
   unsigned bad_fd_count = 0 ;
 
191
   const char *func = "find_bad_fd" ;
 
192
 
 
193
   for ( fd = 0 ; (unsigned)fd < ps.ros.max_descriptors ; fd++ )
 
194
      if ( FD_ISSET( fd, &ps.rws.socket_mask ) && fstat( fd, &st ) == -1 )
 
195
      {
 
196
         int found = FALSE ;
 
197
         unsigned u ;
 
198
 
 
199
         for ( u = 0 ; u < pset_count( SERVICES( ps ) ) ; u++ )
 
200
         {
 
201
            register struct service *sp ;
 
202
 
 
203
            sp = SP( pset_pointer( SERVICES( ps ), u ) ) ;
 
204
 
 
205
            if ( ! SVC_IS_AVAILABLE( sp ) )
 
206
               continue ;
 
207
 
 
208
            if ( SVC_FD( sp ) == fd )
 
209
            {
 
210
               msg( LOG_ERR, func,
 
211
                  "file descriptor of service %s has been closed",
 
212
                              SVC_ID( sp ) ) ;
 
213
               svc_deactivate( sp ) ;
 
214
               found = TRUE ;
 
215
               break ;
 
216
            }
 
217
         }
 
218
         if ( ! found )
 
219
         {
 
220
            FD_CLR( fd, &ps.rws.socket_mask ) ;
 
221
            msg( LOG_ERR, func,
 
222
               "No active service for file descriptor %d\n", fd ) ;
 
223
            bad_fd_count++ ;
 
224
         }
 
225
      }
 
226
   if ( bad_fd_count == 0 )
 
227
      msg( LOG_NOTICE, func,
 
228
         "select reported EBADF but no bad file descriptors were found" ) ;
 
229
}
 
230
 
 
231
 
 
232
/*
 
233
 * Deactivates all active processes.
 
234
 * The real reason for doing this instead of just exiting is
 
235
 * to deregister the RPC services
 
236
 */
 
237
void quit_program(void)
 
238
{
 
239
   unsigned u ;
 
240
   struct service_config *scp = NULL;
 
241
   const char *func = "quit_program" ;
 
242
 
 
243
   destroy_global_access_list() ;
 
244
   
 
245
   for ( u = 0 ; u < pset_count( SERVICES( ps ) ) ; u++ ) {
 
246
      scp = SVC_CONF( SP(pset_pointer(SERVICES(ps), u)) );
 
247
      
 
248
      /* This is essentially the same as the following function, 
 
249
       * Except we forcibly deactivate them, rather than just 
 
250
       * send signals.
 
251
       */
 
252
      if( SC_IS_INTERNAL( scp ) )
 
253
         svc_deactivate( SP( pset_pointer( SERVICES( ps ), u ) ) ) ;
 
254
      if( SC_REDIR_ADDR(scp) != NULL )
 
255
         svc_deactivate( SP( pset_pointer( SERVICES( ps ), u ) ) ) ;
 
256
      if( SC_IS_RPC( scp ) )
 
257
         svc_deactivate( SP( pset_pointer( SERVICES( ps ), u ) ) ) ;
 
258
   }
 
259
 
 
260
   if ( ps.ros.pid_file ) {
 
261
      unlink(ps.ros.pid_file);
 
262
   }
 
263
 
 
264
   msg( LOG_WARNING, func, "Exiting..." ) ;
 
265
   exit( 0 ) ;
 
266
}
 
267
 
 
268
 
 
269
void terminate_program(void)
 
270
{
 
271
   unsigned u ;
 
272
   struct service_config *scp = NULL;
 
273
   void terminate_servers(struct service *);
 
274
 
 
275
   for ( u = 0 ; u < pset_count( SERVICES( ps ) ) ; u++ ) {
 
276
      scp = SVC_CONF( SP(pset_pointer(SERVICES(ps), u)) );
 
277
 
 
278
      /* Terminate the service if it is:
 
279
       * 1) internal (if we don't, it'll zombie)
 
280
       * 2) a redirector (again, if we don't it'll zombie)
 
281
       * 3) It's RPC (we must deregister it.
 
282
       */
 
283
      if( SC_IS_INTERNAL( scp ) )
 
284
         terminate_servers( SP( pset_pointer( SERVICES( ps ), u ) ) ) ;
 
285
      if( SC_REDIR_ADDR( scp ) != NULL )
 
286
         terminate_servers( SP( pset_pointer( SERVICES( ps ), u ) ) ) ;
 
287
      if( SC_IS_RPC( scp ) )
 
288
         terminate_servers( SP( pset_pointer( SERVICES( ps ), u ) ) ) ;
 
289
   }
 
290
   quit_program() ;
 
291
}
 
292