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.
10 #include <sys/types.h>
21 #include "internals.h"
30 static unsigned thread_check( register struct service *sp,unsigned running_servers, unsigned retry_servers );
31 static unsigned refcount_check( struct service *sp, unsigned *running_servers, unsigned *retry_servers );
32 static unsigned service_count_check( register struct service *sp, unsigned running_servers, unsigned retry_servers );
33 static void periodic_check(void);
36 static void dump_services( int fd )
41 * Dump the current configuration (services + defaults)
43 Sprint( fd, "Services + defaults:\n" ) ;
44 sc_dump( DEFAULTS( ps ), fd, 0, TRUE ) ;
46 for ( u = 0 ; u < pset_count( SERVICES( ps ) ) ; u++ )
47 svc_dump( SP( pset_pointer( SERVICES( ps ), u ) ), fd ) ;
50 void dump_internal_state(void)
53 const char *dump_file = DUMP_FILE ;
57 const char *func = "dump_internal_state" ;
60 msg( LOG_DEBUG, func, "Dumping State" ) ;
62 dump_fd = open( dump_file, O_WRONLY | O_CREAT | O_APPEND, DUMP_FILE_MODE);
65 msg( LOG_ERR, func, "failed to open %s: %m", dump_file ) ;
69 if (Sbuftype( dump_fd, SIO_LINEBUF ) == SIO_ERR )
72 * If the above function failed, Sprint will most likely
73 * fail, too. Output a message for troubleshooting and quit.
76 "failed setting up sio buffering: %m fd:%d", dump_fd ) ;
82 * Print the program name, version, and timestamp.
83 * Note that the program_version variable contains the program name.
85 (void) time( ¤t_time ) ;
86 Sprint( dump_fd, "INTERNAL STATE DUMP: %s\n", program_version ) ;
87 Sprint( dump_fd, "Current time: %s\n", ctime( ¤t_time ) ) ;
89 dump_services( dump_fd ) ;
92 * Dump the server table
94 Sprint( dump_fd, "Server table dump:\n" ) ;
95 for ( u = 0 ; u < pset_count( SERVERS( ps ) ) ; u++ )
96 server_dump( SERP( pset_pointer( SERVERS( ps ), u ) ), dump_fd ) ;
97 Sputchar( dump_fd, '\n' ) ;
100 * Dump the retry_table
102 Sprint( dump_fd, "Retry table dump:\n" ) ;
103 for ( u = 0 ; u < pset_count( RETRIES( ps ) ) ; u++ )
104 server_dump( SERP( pset_pointer( RETRIES( ps ), u ) ), dump_fd ) ;
105 Sputchar( dump_fd, '\n' ) ;
108 * Dump the socket mask
110 Sprint( dump_fd, "Socket mask:" ) ;
111 for ( fd = 0 ; (unsigned)fd < ps.ros.max_descriptors ; fd++ )
112 if ( FD_ISSET( fd, &ps.rws.socket_mask ) )
113 Sprint( dump_fd, " %d", fd ) ;
114 Sputchar( dump_fd, '\n' ) ;
115 Sprint( dump_fd, "mask_max = %d\n", ps.rws.mask_max ) ;
118 * Dump the descriptors that are open and are *not* in the socket mask
120 Sprint( dump_fd, "Open descriptors (not in socket mask):" ) ;
121 for ( fd = 0 ; (unsigned)fd < ps.ros.max_descriptors ; fd++ )
125 if ( FD_ISSET( fd, &ps.rws.socket_mask ) )
127 if ( fstat( fd, &st ) == -1 )
129 Sprint( dump_fd, " %d", fd ) ;
131 Sputchar( dump_fd, '\n' ) ;
132 Sputchar( dump_fd, '\n' ) ;
134 Sprint( dump_fd, "active_services = %d\n", ps.rws.active_services ) ;
135 Sprint( dump_fd, "available_services = %d\n", ps.rws.available_services ) ;
136 Sprint( dump_fd, "descriptors_free = %d\n", ps.rws.descriptors_free ) ;
137 Sprint( dump_fd, "running_servers = %d\n", pset_count( SERVERS( ps ) ) ) ;
138 Sprint( dump_fd, "Logging service = %s\n",
139 LOG_SERVICE( ps ) != NULL ? "enabled" : "not enabled" ) ;
140 Sputchar( dump_fd, '\n' ) ;
142 Sprint( dump_fd, "max_descriptors = %d\n", (int)ps.ros.max_descriptors ) ;
143 Sprint( dump_fd, "process_limit = %d\n", (int)ps.ros.process_limit ) ;
144 Sprint( dump_fd, "config_file = %s\n", ps.ros.config_file ) ;
146 Sprint( dump_fd, "debug_fd = %d\n", debug.fd ) ;
147 Sputchar( dump_fd, '\n' ) ;
149 Sprint( dump_fd, "END OF DUMP\n\n" ) ;
152 msg( LOG_INFO, func, "generated state dump in file %s", dump_file ) ;
157 * Types of consistency checks
159 enum check_type { PERIODIC, USER_REQUESTED } ;
162 static void consistency_check( enum check_type type )
165 fd_set socket_mask_copy ;
168 unsigned total_running_servers = 0 ;
169 unsigned total_retry_servers = 0 ;
170 unsigned error_count = 0 ;
171 bool_int service_count_check_failed = FALSE ;
172 const char *func = "consistency_check" ;
174 socket_mask_copy = ps.rws.socket_mask ;
176 for ( u = 0 ; u < pset_count( SERVICES( ps ) ) ; u++ )
178 register struct service *sp = SP( pset_pointer( SERVICES( ps ), u ) ) ;
179 char *sid = SVC_ID( sp ) ;
180 unsigned running_servers ;
181 unsigned retry_servers ;
183 error_count += refcount_check( sp, &running_servers, &retry_servers ) ;
185 if ( SVC_IS_AVAILABLE( sp ) || SVC_IS_DISABLED ( sp ) )
188 * In this case, there may be some servers running
190 if ( FD_ISSET( SVC_FD( sp ), &socket_mask_copy ) )
192 if ( SVC_IS_DISABLED( sp ) )
195 "fd of disabled service %s still in socket mask", sid ) ;
198 FD_CLR( SVC_FD( sp ), &socket_mask_copy ) ;
200 error_count += thread_check( sp, running_servers, retry_servers ) ;
202 errors = service_count_check( sp, running_servers, retry_servers ) ;
203 if ( ! errors && ! service_count_check_failed )
205 total_retry_servers += retry_servers ;
206 total_running_servers += running_servers ;
210 service_count_check_failed = TRUE ;
211 error_count += errors ;
214 if ( SVC_IS_DISABLED( sp ) && SVC_RUNNING_SERVERS( sp ) == 0 )
217 "disabled service %s has 0 running servers\n", sid ) ;
222 /* TCPMUX client programs are always stopped until they run. */
223 else if ( ! SVC_IS_MUXCLIENT( sp ) )
225 msg( LOG_ERR, func, "service %s not started", SVC_ID( sp ) ) ;
230 if ( ! service_count_check_failed )
232 if ( total_running_servers != pset_count( SERVERS( ps ) ) )
235 "total running servers (%d) != number of running servers (%d)",
236 total_running_servers, pset_count( SERVERS( ps ) ) ) ;
239 if ( total_retry_servers != pset_count( RETRIES( ps ) ) )
242 "total retry servers (%d) != number of retry servers (%d)",
243 total_retry_servers, pset_count( RETRIES( ps ) ) ) ;
249 * Check if there are any descriptors set in socket_mask_copy
251 for ( fd = 0 ; (unsigned)fd < ps.ros.max_descriptors ; fd++ )
252 if ( FD_ISSET( fd, &socket_mask_copy ) && ((fd != signals_pending[0]) && fd != signals_pending[1]))
255 "descriptor %d set in socket mask but there is no service for it",
260 if ( error_count != 0 )
261 msg( LOG_WARNING, func,
262 "Consistency check detected %d errors", error_count ) ;
264 if ( type == USER_REQUESTED || debug.on )
265 msg( LOG_INFO, func, "Consistency check passed" ) ;
267 if( type == PERIODIC )
268 if ( xtimer_add( periodic_check, ps.ros.cc_interval ) == -1 )
269 msg( LOG_ERR, func, "Failed to start consistency timer" ) ;
274 * Check that the counts of running and retry servers stored in struct service
277 static unsigned service_count_check( struct service *sp,
278 unsigned running_servers,
279 unsigned retry_servers )
281 char *sid = SVC_ID( sp ) ;
282 int error_count = 0 ;
283 const char *func = "service_count_check" ;
285 if ( SVC_RUNNING_SERVERS( sp ) != running_servers )
288 "service %s: actual running servers = %d, known running servers = %d",
289 sid, running_servers, SVC_RUNNING_SERVERS( sp ) ) ;
292 if ( SVC_RETRIES( sp ) != retry_servers )
295 "service %s: actual retry servers = %d, known retry servers = %d",
296 sid, retry_servers, SVC_RETRIES( sp ) ) ;
300 if ( error_count && debug.on )
301 msg( LOG_DEBUG, func, "%s: %d errors detected", sid, error_count ) ;
303 return( error_count ) ;
309 * If the service is single-threaded:
310 * if the descriptor is set in the socket mask, there must
311 * be a server running (or to be retried)
312 * If the service is multi-threaded:
313 * the descriptor must be always set
315 static unsigned thread_check( struct service *sp,
316 unsigned running_servers,
317 unsigned retry_servers )
319 unsigned error_count = 0 ;
320 int sd = SVC_FD( sp ) ;
321 char *sid = SVC_ID( sp ) ;
322 const char *func = "thread_check" ;
324 if ( SVC_WAITS( sp ) )
326 bool_int has_servers = ( running_servers + retry_servers != 0 ) ;
328 if ( has_servers && FD_ISSET( sd, &ps.rws.socket_mask ) )
331 "Active single-threaded service %s: server running, descriptor set", sid ) ;
334 if ( !has_servers && !FD_ISSET( sd, &ps.rws.socket_mask ) )
337 "Active single-threaded service %s: no server running, descriptor not set",
343 if ( ! FD_ISSET( sd, &ps.rws.socket_mask ) )
346 "Active multi-threaded service %s: descriptor not set", sid ) ;
350 if ( error_count && debug.on )
351 msg( LOG_DEBUG, func, "%s: %d errors detected", sid, error_count ) ;
353 return( error_count ) ;
359 * Count the number of references to the specified service contained
360 * in the specified table of servers; put the number of servers
363 static int count_refs( struct service *sp, pset_h servers, unsigned *countp )
366 struct server *serp ;
370 for ( u = 0 ; u < pset_count( servers ) ; u++ )
372 serp = SERP( pset_pointer( SERVERS( ps ), u ) ) ;
373 if ( SERVER_SERVICE( serp ) == sp )
378 if ( SERVER_CONNSERVICE( serp ) == sp )
381 * XXX: in the future we may want to check if the given service
382 * is any of the alternative services (currently only SPECIAL
383 * services can be alternative services and SPECIAL services
384 * are not included in the service table)
393 * Check for reference counting errors.
394 * Returns number of errors found.
395 * Always set the number of running and retry servers.
397 static unsigned refcount_check( struct service *sp,
398 unsigned *running_servers,
399 unsigned *retry_servers )
401 char *sid = SVC_ID( sp ) ;
402 unsigned errors = 0 ;
404 int refcount = SVC_REFCOUNT( sp ) ;
405 const char *func = "refcount_check" ;
409 msg( LOG_ERR, func, "%s service has bad refcount: %d",
415 * The service table holds a reference to the service. The remaining
416 * references must be from servers and connections.
420 refs = count_refs( sp, SERVERS( ps ), running_servers ) ;
421 if ( ! errors && refs > refcount )
424 "running servers: too many references for %s (%d with max=%d)",
425 sid, refs, refcount ) ;
429 refs = count_refs( sp, RETRIES( ps ), retry_servers ) ;
430 if ( ! errors && refs > refcount )
433 "retry servers: too many references for %s (%d with max=%d)",
434 sid, refs, refcount ) ;
438 if ( errors && debug.on )
439 msg( LOG_DEBUG, func, "%s: %d errors detected", sid, errors ) ;
445 void user_requested_check(void)
447 consistency_check( USER_REQUESTED ) ;
451 static void periodic_check(void)
453 consistency_check( PERIODIC ) ;
456 /* This actually gets called during initialization, so be careful what
459 void enable_periodic_check( unsigned interval )
461 const char *func = "enable_periodic_check" ;
463 if ( xtimer_add( periodic_check, interval ) == -1 )
465 msg( LOG_ERR, func, "Failed to start consistency timer" ) ;