home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / unix / volume26 / xinetd21 / part21 < prev    next >
Encoding:
Text File  |  1993-06-26  |  26.6 KB  |  994 lines

  1. Newsgroups: comp.sources.unix
  2. From: panos@cs.colorado.edu (Panos Tsirigotis)
  3. Subject: v26i265: xinetd-2.1.1 - inetd replacement with access control and logging, Part21/31
  4. Sender: unix-sources-moderator@gw.home.vix.com
  5. Approved: vixie@gw.home.vix.com
  6.  
  7. Submitted-By: panos@cs.colorado.edu (Panos Tsirigotis)
  8. Posting-Number: Volume 26, Issue 265
  9. Archive-Name: xinetd-2.1.1/part21
  10.  
  11. #! /bin/sh
  12. # This is a shell archive.  Remove anything before this line, then unpack
  13. # it by saving it into a file and typing "sh file".  To overwrite existing
  14. # files, type "sh file -c".  You can also feed this as standard input via
  15. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  16. # will see the following message at the end:
  17. #        "End of archive 21 (of 31)."
  18. # Contents:  libs/src/timer/ostimer.c xinetd/reconfig.c
  19. # Wrapped by panos@mystique on Mon Jun 21 14:51:26 1993
  20. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  21. if test -f 'libs/src/timer/ostimer.c' -a "${1}" != "-c" ; then 
  22.   echo shar: Will not clobber existing file \"'libs/src/timer/ostimer.c'\"
  23. else
  24. echo shar: Extracting \"'libs/src/timer/ostimer.c'\" \(11927 characters\)
  25. sed "s/^X//" >'libs/src/timer/ostimer.c' <<'END_OF_FILE'
  26. X/*
  27. X * (c) Copyright 1993 by Panagiotis Tsirigotis
  28. X * All rights reserved.  The file named COPYRIGHT specifies the terms 
  29. X * and conditions for redistribution.
  30. X */
  31. X
  32. Xstatic char RCSid[] = "$Id: ostimer.c,v 4.2 1993/05/06 06:46:14 panos Exp $" ;
  33. X
  34. X#include <stdio.h>
  35. X#include <varargs.h>
  36. X
  37. Xextern int errno ;
  38. X
  39. X#include "timemacros.h"
  40. X#include "defs.h"
  41. X#include "impl.h"
  42. X#include "ostimer.h"
  43. X
  44. X
  45. X/*
  46. X * Case 1: DEBUG defined
  47. X *        SET_OSTIMER checks for zero interval and terminates in case of setitimer
  48. X *        error
  49. X * Case 2: DEBUG undefined, NO_TERMINATION undefined
  50. X *        SET_OSTIMER terminates in case of setitimer error
  51. X * Case 3: DEBUG undefined, NO_TERMINATION undefined
  52. X *        SET_OSTIMER ignores setitimer error
  53. X */
  54. X#ifdef DEBUG
  55. X#undef NO_TERMINATION
  56. X#define CHECK_INTERVAL( func, itv )                                                 \
  57. X                        if ( TV_ISZERO( (itv).it_value ) )                            \
  58. X                            terminate( "TIMER %s: zero interval\n", func ) ;
  59. X#else
  60. X#define CHECK_INTERVAL( func, itv )
  61. X#endif
  62. X
  63. X#ifndef NO_TERMINATION
  64. X#define OSTIMER_SET( func, otp, itv )                                                        \
  65. X        if ( setitimer( (otp)->ost_systype, &(itv), ITIMERVAL_NULL ) == -1 )        \
  66. X            terminate( "TIMER %s: setitimer failed. errno = %d\n", func, errno )
  67. X#else
  68. X#define OSTIMER_SET( func, otp, itv )                                                        \
  69. X          (void) setitimer( (otp)->ost_systype, &(itv), ITIMERVAL_NULL )
  70. X#endif
  71. X
  72. X#define SET_OSTIMER( otp, itv, func )            CHECK_INTERVAL( func, itv )     \
  73. X                                                            OSTIMER_SET( func, otp, itv )
  74. X
  75. X
  76. X#ifndef NO_TERMINATION
  77. X
  78. XPRIVATE void terminate( fmt, va_alist )
  79. X   char *fmt ;
  80. X   va_dcl
  81. X{
  82. X   va_list ap ;
  83. X
  84. X   va_start( ap ) ;
  85. X   (void) vfprintf( stderr, fmt, ap ) ;
  86. X   abort() ;
  87. X   _exit( 1 ) ;
  88. X}
  89. X
  90. X#endif   /* ! NO_TERMINATION */
  91. X
  92. X/*
  93. X * Initialize the fields of struct timer that are used by the ostimer code
  94. X */
  95. Xint __ostimer_newtimer( tp, type )
  96. X    timer_s                *tp ;
  97. X    enum timer_types    type ;
  98. X{
  99. X    ostimer_s            *otp = __ostimer_init( tp, type ) ;
  100. X
  101. X    if ( otp == OSTIMER_NULL )
  102. X        return( TIMER_ERR ) ;
  103. X
  104. X    tp->t_ostimer = otp ;
  105. X    TV_ZERO( tp->t_expiration ) ;
  106. X    TV_ZERO( tp->t_interval ) ;
  107. X    tp->t_count = 0 ;
  108. X    return( TIMER_OK ) ;
  109. X}
  110. X
  111. X
  112. X
  113. X
  114. X/*
  115. X * The following variables are used to handle the following scenario:
  116. X *
  117. X *        1. INTERRUPT happens ==> ostimer_interrupt called
  118. X *        2. Timers A and B expire.
  119. X *        3. The function associated with A is invoked and running
  120. X *        4. INTERRUPT happens ==> ostimer_interrupt called
  121. X *        5. Timer C expires.
  122. X *        6. Function of timer C invoked and returns with a jmp_buf.
  123. X *
  124. X * If we longjmp to the jmp_buf returned by the function of timer C the 
  125. X * function of timer B will never be called and the function of timer A 
  126. X * will never finish.
  127. X * What we do instead is have ostimer_interrupt check the call_level
  128. X * and if greater than 1, then just save the jmp_buf returned by the
  129. X * function of timer C (only if there is no other ret_env) and simply return.
  130. X *
  131. X * Notice that there can be only one ret_env (since there is only 1 control 
  132. X * flow).
  133. X *
  134. X * XXX:  this complexity stems from the fact that we allow interrupts while
  135. X *            the timer functions are running. Is there a good reason for this ?
  136. X *            (probably because we have to allow interrupts of other timer types).
  137. X */
  138. Xstatic int call_level ;
  139. Xstatic int have_env ;
  140. Xstatic jmp_buf ret_env ;
  141. X
  142. X#define MAX_EXPIRED                    20
  143. X
  144. X/*
  145. X * ostimer_interrupt invokes the functions of the timers that expired.
  146. X * Since we don't know in advance how many timers expired, we follow a
  147. X * two-step procedure:
  148. X *
  149. X *        Step 1: collect all expired timers
  150. X *        Step 2: invoke timer actions
  151. X *
  152. X * The expired timers are collected in an array stored on the stack.
  153. X * If the array overflows, we arrange for another timer interrupt as
  154. X * soon as possible to service remaining timers. The reason we don't
  155. X * allocate the array using malloc is that malloc is not guaranteed
  156. X * to be reentrant and tracking timing-related dynamic memory allocation 
  157. X * problems is guaranteed to be a nightmare.
  158. X *
  159. X * Notice that *all* timer interrupts are blocked during step 1.
  160. X */
  161. Xvoid __ostimer_interrupt( otp )
  162. X    register ostimer_s *otp ;
  163. X{
  164. X    struct timeval        current_time ;
  165. X    register timer_s    *tp ;
  166. X    timer_s                *expired_timers[ MAX_EXPIRED ] ;
  167. X    unsigned                n_expired = 0 ;
  168. X    int                    i ;
  169. X
  170. X    if ( timer_pq_head( otp->ost_timerq.tq_handle ) == TIMER_NULL )
  171. X        return ;
  172. X    
  173. X    call_level++ ;
  174. X    
  175. X    (*otp->ost_get_current_time)( ¤t_time ) ;
  176. X
  177. X    /*
  178. X     * Get all timers that expired
  179. X     */
  180. X    for ( ;; )
  181. X    {
  182. X        tp = timer_pq_head( otp->ost_timerq.tq_handle ) ;
  183. X
  184. X        if ( tp == TIMER_NULL || TV_GT( tp->t_expiration, current_time ) ||
  185. X                                                                    n_expired == MAX_EXPIRED )
  186. X            break ;
  187. X        
  188. X        tp = timer_pq_extract_head( otp->ost_timerq.tq_handle ) ;
  189. X        if ( tp->t_state == TICKING )
  190. X        {
  191. X            tp->t_state = INACTIVE ;
  192. X
  193. X            tp->t_count++ ;
  194. X            if ( tp->t_blocked )
  195. X            {
  196. X                if ( tp->t_act == IDLE )
  197. X                    tp->t_act = PENDING ;
  198. X                else if ( tp->t_act == INVOKED )
  199. X                    tp->t_act = SCHEDULED ;
  200. X            }
  201. X            else        /* not blocked */
  202. X            {
  203. X                if ( tp->t_act == IDLE || tp->t_act == INVOKED )
  204. X                {
  205. X                    tp->t_act = SCHEDULED ;
  206. X                    expired_timers[ n_expired++ ] = tp ;
  207. X                }
  208. X            }
  209. X        }
  210. X    }
  211. X
  212. X    /*
  213. X     * Check which timers have regular expiration intervals
  214. X     */
  215. X    for ( i = 0 ; i < n_expired ; i++ )
  216. X    {
  217. X        tp = expired_timers[ i ] ;
  218. X
  219. X        if ( ! TV_ISZERO( tp->t_interval ) )
  220. X        {
  221. X            tp->t_state = TICKING ;
  222. X            TV_ADD( tp->t_expiration, tp->t_expiration, tp->t_interval ) ;
  223. X            /*
  224. X             * We shouldn't have an insertion problem since we just extracted
  225. X             * the timers from the queue (i.e. there should be enough room)
  226. X             */
  227. X            (void) timer_pq_insert( otp->ost_timerq.tq_handle, tp ) ;
  228. X        }
  229. X    }
  230. X
  231. X    tp = timer_pq_head( otp->ost_timerq.tq_handle ) ;
  232. X
  233. X    if ( tp != TIMER_NULL )
  234. X    {
  235. X        struct itimerval itv ;
  236. X
  237. X        TV_ZERO( itv.it_interval ) ;
  238. X        /* 
  239. X         * Check if we had too many expired timers
  240. X         */
  241. X        if ( TV_LE( tp->t_expiration, current_time ) )
  242. X        {
  243. X            itv.it_value.tv_sec = 0 ;
  244. X            itv.it_value.tv_usec = 1 ;        /* schedule an interrupt ASAP */
  245. X            /* XXX:    this trick will result in another call to 
  246. X             *            ostimer_interrupt. So why don't we just call it
  247. X             *            recursively, instead of taking another timer interrupt ?
  248. X             */
  249. X        }
  250. X        else
  251. X            TV_SUB( itv.it_value, tp->t_expiration, current_time ) ;
  252. X
  253. X        SET_OSTIMER( otp, itv, "ostimer_interrupt" ) ;
  254. X    }
  255. X
  256. X#ifdef DEBUG_MSGS
  257. X   printf( "\t\t%d timers expired\n", n_expired ) ;
  258. X#endif
  259. X
  260. X   /*
  261. X    * Invoke the functions of all expired timers
  262. X     */
  263. X   for ( i = 0 ; i < n_expired ; i++ )
  264. X   {
  265. X      tp = expired_timers[ i ] ;
  266. X        if ( __timer_invoke( tp ) != DESTROYED &&
  267. X                    ! have_env && ( tp->t_action.ta_flags & TIMER_LONGJMP ) )
  268. X        {
  269. X            (void) memcpy( (char *)ret_env,
  270. X                        (char *)tp->t_action.ta_env, sizeof( jmp_buf ) ) ;
  271. X            have_env = TRUE ;
  272. X        }
  273. X   }
  274. X
  275. X    call_level-- ;
  276. X
  277. X    /*
  278. X     * If this is not a recursive call, and there is a jmp_buf, use it.
  279. X     */
  280. X    if ( call_level == 0 && have_env )
  281. X    {
  282. X        have_env = FALSE ;
  283. X        longjmp( ret_env, 1 ) ;
  284. X    }
  285. X}
  286. X
  287. X
  288. X/*
  289. X * Carry out the timer action.
  290. X * If            the call level is 0
  291. X *        AND    there is not already an environment to longjmp to
  292. X *         AND    this timer has such an environment
  293. X *    then
  294. X *        longjmp to that environment
  295. X *
  296. X * Notice that all timer interrupts are blocked while this function is running.
  297. X * Therefore, none of the global variables checked can change.
  298. X */
  299. XPRIVATE void invoke_protocol( tp )
  300. X    timer_s *tp ;
  301. X{
  302. X    if ( __timer_invoke( tp ) != DESTROYED &&
  303. X                    call_level == 0 && ! have_env &&
  304. X                                    ( tp->t_action.ta_flags & TIMER_LONGJMP ) )
  305. X        longjmp( tp->t_action.ta_env, 1 ) ;
  306. X}
  307. X
  308. X
  309. X/*
  310. X * Add a timer to the specified OS timer's queue
  311. X * We assume that the timer already has a valid state and action
  312. X * associated with it.
  313. X * We also assume that no operations (block etc) are applied to the
  314. X * timer while this function is running.
  315. X */
  316. Xint __ostimer_add( otp, tp, itvp, time_type )
  317. X    ostimer_s                *otp ;
  318. X    register timer_s        *tp ;
  319. X    struct itimerval        *itvp ;
  320. X    enum timer_timetypes time_type ;
  321. X{
  322. X    struct timeval        current_time ;
  323. X    int                    expired ;
  324. X
  325. X    /*
  326. X     * While this function (__ostimer_add) is running, this will be our 
  327. X     * notion of the current time.
  328. X     * In reality, there may be some time skew as this function
  329. X     * is running, possibly because of swapping.
  330. X     */
  331. X    (*otp->ost_get_current_time)( ¤t_time ) ;
  332. X
  333. X   /*
  334. X    * Since we use absolute time for our calculations,
  335. X    * convert the user-specified time to that, if necessary
  336. X    *
  337. X    * Also check if the timer has already expired. There are 2 possibilities:
  338. X    *
  339. X    *    1. a zero interval for TIMER_RELATIVE
  340. X    *    2. a time before current time for TIMER_ABSOLUTE
  341. X     *
  342. X     * Note that we always calculate t_expiration in case the user has
  343. X     * specified an it_interval.
  344. X    */
  345. X    
  346. X    if ( time_type == TIMER_RELATIVE )
  347. X    {
  348. X        /*
  349. X         * timer_start has verified that it_value is not negative
  350. X         */
  351. X        TV_ADD( tp->t_expiration, current_time, itvp->it_value ) ;
  352. X        expired = TV_ISZERO( itvp->it_value ) ;
  353. X    }
  354. X    else
  355. X    {
  356. X        tp->t_expiration = itvp->it_value ;
  357. X        expired = TV_LE( tp->t_expiration, current_time ) ;
  358. X    }
  359. X
  360. X    tp->t_interval = itvp->it_interval ;
  361. X
  362. X    if ( expired )
  363. X    {
  364. X        tp->t_count++ ;
  365. X        tp->t_act = SCHEDULED ;
  366. X
  367. X        if ( TV_ISZERO( tp->t_interval ) )
  368. X        {
  369. X            invoke_protocol( tp ) ;
  370. X            return( TIMER_OK ) ;
  371. X        }
  372. X        
  373. X        /*
  374. X         * Keep expiring the timer until it exceeds the current time
  375. X         */
  376. X        time_type = TIMER_ABSOLUTE ;
  377. X        for ( ;; )
  378. X        {
  379. X            TV_ADD( tp->t_expiration, tp->t_expiration, tp->t_interval ) ;
  380. X            expired = TV_LE( tp->t_expiration, current_time ) ;
  381. X            if ( ! expired )
  382. X                break ;
  383. X            tp->t_act = SCHEDULED ;
  384. X            tp->t_count++ ;
  385. X        }
  386. X        invoke_protocol( tp ) ;
  387. X    }
  388. X
  389. X    if ( timer_pq_insert( otp->ost_timerq.tq_handle, tp ) == PQ_ERR )
  390. X        HANDLE_ERROR( tp->t_flags, TIMER_ERR, tp->t_errnop, TIMER_ECANTINSERT,
  391. X            "TIMER __ostimer_add: can't insert timer in priority queue\n" ) ;
  392. X
  393. X    tp->t_state = TICKING ;
  394. X
  395. X    /*
  396. X     * Now check if we will need to set the timer again
  397. X     */
  398. X    if ( tp == timer_pq_head( otp->ost_timerq.tq_handle ) )
  399. X    {
  400. X      /*
  401. X       * Check if the user specified relative time.
  402. X       * If so, use the value given (for better accuracy), otherwise compute
  403. X       * a new value.
  404. X       * It is possible that by now the timer that was at the head
  405. X       * of the queue expired and a signal is pending. This can happen
  406. X       * if we are swapped out. The signal handling function will
  407. X       * obviously expire both the new timer and the old one, so our
  408. X       * setting a new timer value may cause a signal at a later time
  409. X       * when the queue is empty. The signal handling function should
  410. X       * be able to deal with an empty queue.
  411. X       */
  412. X        struct itimerval itv ;
  413. X
  414. X        TV_ZERO( itv.it_interval ) ;
  415. X        if ( time_type == TIMER_RELATIVE )
  416. X            itv.it_value = itvp->it_value ;
  417. X        else
  418. X            TV_SUB( itv.it_value, tp->t_expiration, current_time ) ;
  419. X        SET_OSTIMER( otp, itv, "__ostimer_add" ) ;
  420. X    }
  421. X
  422. X    return( TIMER_OK ) ;
  423. X}
  424. X
  425. X
  426. X/*
  427. X * Remove the specified timer from the OS timer's queue
  428. X * Timer interrupts should be blocked.
  429. X */
  430. Xvoid __ostimer_remove( otp, tp )
  431. X    ostimer_s    *otp ;
  432. X    timer_s        *tp ;
  433. X{
  434. X    struct itimerval    itv ;
  435. X    struct timeval        current_time ;
  436. X    timer_s                *new_head_timer, *old_head_timer ;
  437. X
  438. X    old_head_timer = timer_pq_head( otp->ost_timerq.tq_handle ) ;
  439. X    timer_pq_delete( otp->ost_timerq.tq_handle, tp ) ;
  440. X    new_head_timer = timer_pq_head( otp->ost_timerq.tq_handle ) ;
  441. X
  442. X    if ( old_head_timer != new_head_timer )
  443. X    {
  444. X        int do_setitimer ;
  445. X
  446. X        if ( new_head_timer != TIMER_NULL )
  447. X        {
  448. X            (*otp->ost_get_current_time)( ¤t_time ) ;
  449. X
  450. X            /*
  451. X             * If the head_timer is less than or equal to the current time, 
  452. X             * the interrupt must be pending, so we leave the OS timer running.
  453. X             * Otherwise, we restart the OS timer.
  454. X             */
  455. X            if ( TV_LE( current_time, new_head_timer->t_expiration ) )
  456. X                do_setitimer = FALSE ;
  457. X            else
  458. X            {
  459. X                do_setitimer = TRUE ;
  460. X                TV_SUB( itv.it_value, new_head_timer->t_expiration, current_time ) ;
  461. X                CHECK_INTERVAL( "__ostimer_remove", itv ) ;
  462. X            }
  463. X        }
  464. X        else                /* queue is empty */
  465. X        {
  466. X            do_setitimer = TRUE ;
  467. X            TV_ZERO( itv.it_value ) ;
  468. X        }
  469. X
  470. X        if ( do_setitimer )
  471. X        {
  472. X            TV_ZERO( itv.it_interval ) ;
  473. X            OSTIMER_SET( "__ostimer_remove", otp, itv ) ;
  474. X        }
  475. X    }
  476. X}
  477. X
  478. END_OF_FILE
  479. if test 11927 -ne `wc -c <'libs/src/timer/ostimer.c'`; then
  480.     echo shar: \"'libs/src/timer/ostimer.c'\" unpacked with wrong size!
  481. fi
  482. # end of 'libs/src/timer/ostimer.c'
  483. fi
  484. if test -f 'xinetd/reconfig.c' -a "${1}" != "-c" ; then 
  485.   echo shar: Will not clobber existing file \"'xinetd/reconfig.c'\"
  486. else
  487. echo shar: Extracting \"'xinetd/reconfig.c'\" \(12082 characters\)
  488. sed "s/^X//" >'xinetd/reconfig.c' <<'END_OF_FILE'
  489. X/*
  490. X * (c) Copyright 1992 by Panagiotis Tsirigotis
  491. X * All rights reserved.  The file named COPYRIGHT specifies the terms 
  492. X * and conditions for redistribution.
  493. X */
  494. X
  495. Xstatic char RCSid[] = "$Id: reconfig.c,v 6.11 1993/06/15 23:25:57 panos Exp $" ;
  496. X
  497. X#include <sys/types.h>
  498. X#include <sys/socket.h>
  499. X#include <syslog.h>
  500. X#include <signal.h>
  501. X#include <memory.h>
  502. X
  503. X#include "state.h"
  504. X#include "access.h"
  505. X#include "defs.h"
  506. X#include "service.h"
  507. X#include "server.h"
  508. X#include "conf.h"
  509. X#include "config.h"
  510. X
  511. Xvoid exit() ;
  512. X
  513. Xvoid msg() ;
  514. Xvoid out_of_memory() ;
  515. X
  516. Xtypedef enum { RECONFIG_SOFT, RECONFIG_HARD } reconfig_e ;
  517. X
  518. X
  519. X#define SWAP( x, y, temp )            (temp) = (x), (x) = (y), (y) = (temp)
  520. X
  521. X
  522. XPRIVATE void do_reconfig() ;
  523. X
  524. X
  525. Xvoid soft_reconfig()
  526. X{
  527. X    do_reconfig( RECONFIG_SOFT ) ;
  528. X}
  529. X
  530. X
  531. Xvoid hard_reconfig()
  532. X{
  533. X    do_reconfig( RECONFIG_HARD ) ;
  534. X}
  535. X
  536. X
  537. X/*
  538. X * Reconfigure the server by rereading the configuration file.
  539. X * Services may be added, deleted or have their attributes changed.
  540. X * All syslog output uses the LOG_NOTICE priority level (except for
  541. X * errors).
  542. X */
  543. XPRIVATE void do_reconfig( reconfig_type )
  544. X    reconfig_e reconfig_type ;
  545. X{
  546. X    struct service                *osp ;
  547. X    struct service_config    *nscp ;
  548. X    struct configuration        new_conf ;
  549. X    psi_h                            iter ;
  550. X    unsigned                        new_services ;
  551. X    unsigned                        old_services        = 0 ;
  552. X    unsigned                        dropped_services    = 0 ;
  553. X    char                            *func                    = "do_reconfig" ;
  554. X    PRIVATE status_e            readjust() ;
  555. X    PRIVATE void                check_servers() ;
  556. X    PRIVATE void                swap_defaults() ;
  557. X    void                            terminate_servers() ;
  558. X    void                            cancel_service_retries() ;
  559. X
  560. X    msg( LOG_NOTICE, func, "Starting %s reconfiguration",
  561. X                ( reconfig_type == RECONFIG_SOFT ) ? "soft" : "hard" ) ;
  562. X
  563. X    if ( cnf_get( &new_conf, (long)CONF_TIMEOUT ) == FAILED )
  564. X    {
  565. X        msg( LOG_WARNING, func, "reconfiguration failed" ) ;
  566. X        return ;
  567. X    }
  568. X
  569. X    iter = psi_create( SERVICES( ps ) ) ;
  570. X    if ( iter == NULL )
  571. X    {
  572. X        out_of_memory( func ) ;
  573. X        cnf_free( &new_conf ) ;
  574. X        return ;
  575. X    }
  576. X
  577. X    swap_defaults( &new_conf ) ;
  578. X
  579. X    /*
  580. X     * Glossary:
  581. X     *        Sconf: service configuration
  582. X     *        Lconf: list of service configurations
  583. X     *
  584. X     * Iterate over all existing services. If the service is included in the 
  585. X     * new Lconf, readjust its attributes (as a side-effect, the new service 
  586. X     * Sconf is removed from the new Lconf).
  587. X     *    Services not in the new Lconf are deactivated.
  588. X     */
  589. X    for ( osp = SP( psi_start( iter ) ) ; osp ; osp = SP( psi_next( iter ) ) )
  590. X    {
  591. X        char *sid = SVC_ID( osp ) ;
  592. X        boolean_e drop_service ;
  593. X
  594. X        if ( ! SVC_IS_AVAILABLE( osp ) )
  595. X            continue ;
  596. X
  597. X        /*
  598. X         * Check if this service is in the new Lconf
  599. X         * Notice that the service Sconf is removed from the new Lconf
  600. X         * if it is found there.
  601. X         */
  602. X        if ( nscp = cnf_extract( &new_conf, SVC_CONF( osp ) ) )
  603. X        {
  604. X            /*
  605. X             * The first action of readjust is to swap the service configuration
  606. X             * with nscp. This is the reason for passing the address of nscp
  607. X             * (so that on return nscp will *always* point to the old service
  608. X             * configuration).
  609. X             */
  610. X            if ( readjust( osp, &nscp, reconfig_type ) == OK )
  611. X            {
  612. X                /*
  613. X                 * Do the access control again
  614. X                 */
  615. X                if ( reconfig_type == RECONFIG_HARD )
  616. X                    check_servers( osp ) ;
  617. X
  618. X                old_services++ ;
  619. X                drop_service = NO ;
  620. X            }
  621. X            else    /* the readjustment failed */
  622. X                drop_service = YES ;
  623. X            sc_free( nscp ) ;
  624. X        }
  625. X        else
  626. X            drop_service = YES ;
  627. X
  628. X        if ( drop_service == YES )
  629. X        {
  630. X            /*
  631. X             * Procedure for disabling a service:
  632. X             *
  633. X             *        a. Terminate running servers and cancel retry attempts, in case
  634. X             *            of hard reconfiguration
  635. X             *        b. Deactivate the service
  636. X             */
  637. X            if ( reconfig_type == RECONFIG_HARD )
  638. X            {
  639. X                terminate_servers( osp ) ;
  640. X                cancel_service_retries( osp ) ;
  641. X            }
  642. X
  643. X            /*
  644. X             * Deactivate the service; the service will be deleted only
  645. X             * if its reference count drops to 0.
  646. X             */
  647. X            svc_deactivate( osp ) ;
  648. X            msg( LOG_NOTICE, func, "service %s deactivated", sid ) ;
  649. X            if ( SVC_RELE( osp ) == 0 )
  650. X                psi_remove( iter ) ;
  651. X            dropped_services++ ;
  652. X        }
  653. X    }
  654. X
  655. X    psi_destroy( iter ) ;
  656. X
  657. X    /*
  658. X     * At this point the new Lconf only contains services that were not
  659. X     * in the old Lconf.
  660. X     */
  661. X    new_services = cnf_start_services( &new_conf ) ;
  662. X
  663. X    msg( LOG_NOTICE, func,
  664. X        "Reconfigured: new=%d old=%d dropped=%d (services)",
  665. X            new_services, old_services, dropped_services ) ;
  666. X
  667. X    if ( ps.rws.available_services == 0 )
  668. X    {
  669. X        msg( LOG_CRIT, func, "No available services. Exiting" ) ;
  670. X        exit( 1 ) ;
  671. X    }
  672. X
  673. X    cnf_free( &new_conf ) ;
  674. X}
  675. X
  676. X
  677. XPRIVATE void swap_defaults( confp )
  678. X    struct configuration *confp ;
  679. X{
  680. X    struct service_config *temp ;
  681. X
  682. X    /*
  683. X     * Close the previous common log file, if one was specified
  684. X     */
  685. X    if ( DEFAULT_LOG( ps ) != NULL )
  686. X    {
  687. X        log_end( SC_LOG( DEFAULTS( ps ) ), DEFAULT_LOG( ps ) ) ;
  688. X        DEFAULT_LOG( ps ) = NULL ;
  689. X    }
  690. X    DEFAULT_LOG_ERROR( ps ) = FALSE ;
  691. X
  692. X    SWAP( DEFAULTS( ps ), CNF_DEFAULTS( confp ), temp ) ;
  693. X}
  694. X
  695. X
  696. X
  697. XPRIVATE void sendsig( serp, sig )
  698. X    register struct server    *serp ;
  699. X    int                            sig ;
  700. X{
  701. X    char        *sid    = SVC_ID( SERVER_SERVICE( serp ) ) ;
  702. X    pid_t        pid    = SERVER_PID( serp ) ;
  703. X    char        *func = "sendsig" ;
  704. X
  705. X    /*
  706. X     * Always use a positive pid, because of the semantics of kill(2)
  707. X     */
  708. X    if ( pid > 0 )
  709. X    {
  710. X        msg( LOG_WARNING, func, "Sending signal %d to %s server %d",
  711. X                                                sig, sid, pid ) ;
  712. X        (void) kill( pid, sig ) ;
  713. X    }
  714. X    else
  715. X        msg( LOG_ERR, func, "Negative server pid = %d. Service %s", pid, sid ) ;
  716. X}
  717. X
  718. X
  719. X/*
  720. X * Send signal sig to all running servers of service sp
  721. X */
  722. XPRIVATE void deliver_signal( sp, sig )
  723. X    register struct service *sp ;
  724. X    int sig ;
  725. X{
  726. X    register unsigned u ;
  727. X
  728. X    for ( u = 0 ; u < pset_count( SERVERS( ps ) ) ; u++ )
  729. X    {
  730. X        register struct server *serp ;
  731. X
  732. X        serp = SERP( pset_pointer( SERVERS( ps ), u ) ) ;
  733. X        if ( SERVER_SERVICE( serp ) == sp )
  734. X            sendsig( serp, sig ) ;
  735. X    }
  736. X}
  737. X
  738. X
  739. X/*
  740. X * Terminate all servers of the specified service
  741. X */
  742. Xvoid terminate_servers( sp )
  743. X    register struct service *sp ;
  744. X{
  745. X    int sig = SC_IS_INTERNAL( SVC_CONF( sp ) ) ? SIGTERM : SIGKILL ;
  746. X
  747. X    deliver_signal( sp, sig ) ;
  748. X}
  749. X
  750. X
  751. XPRIVATE void stop_interception( sp )
  752. X    struct service *sp ;
  753. X{
  754. X    deliver_signal( sp, INTERCEPT_SIG ) ;
  755. X}
  756. X
  757. X
  758. X/*
  759. X * Do access control on all servers of the specified service.
  760. X * If "limit" is 0, we don't mind if the service limit is exceeded.
  761. X * If "limit" is non-zero, we kill servers that exceed the service limit
  762. X * (but at most "limit" servers are killed because of exceeding the 
  763. X * instances limit)
  764. X *
  765. X * Return value: number of servers that failed the check (and were killed)
  766. X */
  767. XPRIVATE int server_check( sp, limit )
  768. X    register struct service        *sp ;
  769. X    int                                limit ;
  770. X{
  771. X    register unsigned        u ;
  772. X    int                        killed_servers    = 0 ;
  773. X    pset_h                    server_set        = SERVERS( ps ) ;
  774. X    char                        *func                = "server_check" ;
  775. X
  776. X    if ( SVC_RUNNING_SERVERS( sp ) == 0 )
  777. X        return( 0 ) ;
  778. X
  779. X    for ( u = 0 ; u < pset_count( server_set ) ; u++ )
  780. X    {
  781. X        register struct server *serp = SERP( pset_pointer( server_set, u ) ) ;
  782. X
  783. X        if ( SERVER_SERVICE( serp ) == sp )
  784. X        {
  785. X            access_e result ;
  786. X            mask_t check_mask = MASK( CF_TIME ) ;
  787. X
  788. X            if ( SVC_SOCKET_TYPE( sp ) != SOCK_DGRAM )
  789. X                M_OR( check_mask, check_mask, MASK( CF_ADDRESS ) ) ;
  790. X            if ( limit != 0 && killed_servers < limit )
  791. X                M_OR( check_mask, check_mask, MASK( CF_SERVICE_LIMIT ) ) ;
  792. X            
  793. X            result = access_control( sp, SERVER_CONNECTION( serp ), &check_mask );
  794. X
  795. X            if ( result == AC_OK )
  796. X                continue ;
  797. X        
  798. X            msg( LOG_NOTICE, func, "%s server %d failed %s check",
  799. X                SVC_ID( sp ), SERVER_PID( serp ), access_explain( result ) ) ;
  800. X            sendsig( serp, SIGKILL ) ;
  801. X            killed_servers++ ;
  802. X        }
  803. X    }
  804. X    return( killed_servers ) ;
  805. X}
  806. X
  807. X
  808. X/*
  809. X * Check if all the running servers of the specified service fit the 
  810. X * new access control specifications. The ones that don't fit are killed.
  811. X * 
  812. X * We go through the server table twice. During the first
  813. X * pass we ignore overruns of the server limit. During the second pass
  814. X * we don't ignore such overruns until a certain number of servers are
  815. X * terminated.
  816. X */
  817. XPRIVATE void check_servers( sp )
  818. X    register struct service *sp ;
  819. X{
  820. X    int existant_servers = SVC_RUNNING_SERVERS( sp ) ;
  821. X    int limit ;
  822. X
  823. X    existant_servers -= server_check( sp, 0 ) ;
  824. X
  825. X    limit = existant_servers - SC_INSTANCES( SVC_CONF( sp ) ) ;
  826. X    if ( limit < 0 )
  827. X        limit = 0 ;
  828. X    (void) server_check( sp, limit ) ;
  829. X}
  830. X
  831. X
  832. X
  833. X/*
  834. X * Stop any logging and restart if necessary.
  835. X * Note that this has the side-effect of using the new common log
  836. X * handle as it should.
  837. X */
  838. XPRIVATE status_e restart_log( sp, old_conf )
  839. X    struct service *sp ;
  840. X    struct service_config *old_conf ;
  841. X{
  842. X    struct log *lp = SC_LOG( old_conf ) ;
  843. X
  844. X    if ( log_get_type( lp ) != L_NONE && SVC_IS_LOGGING( sp ) )
  845. X        log_end( lp, SVC_LOG( sp ) ) ;
  846. X    SVC_LOG( sp ) = NULL ;
  847. X    
  848. X    return( log_start( sp, &SVC_LOG( sp ) ) ) ;
  849. X}
  850. X
  851. X
  852. X/*
  853. X * Unregister past versions, register new ones
  854. X * We do it the dumb way: first unregister; then register
  855. X * We try to be a little smart by checking if there has
  856. X * been any change in version numbers (if not, we do nothing).
  857. X * Also, we save the port number
  858. X */
  859. XPRIVATE status_e readjust_rpc_service( old_scp, new_scp )
  860. X    register struct service_config *old_scp ;
  861. X    register struct service_config *new_scp ;
  862. X{
  863. X    unsigned                long vers ;
  864. X    unsigned short        port                        = SC_PORT( old_scp ) ;
  865. X    struct rpc_data    *new_rdp                    = SC_RPCDATA( new_scp ) ;
  866. X    struct rpc_data    *old_rdp                    = SC_RPCDATA( old_scp ) ;
  867. X    unsigned                registered_versions    = 0 ;
  868. X    char                    *func                        = "readjust_rpc_service" ;
  869. X
  870. X#ifndef NO_RPC
  871. X    SC_PORT( new_scp ) = SC_PORT( old_scp ) ;
  872. X
  873. X    if ( RD_MINVERS( old_rdp ) == RD_MINVERS( new_rdp ) &&
  874. X                RD_MAXVERS( old_rdp ) == RD_MAXVERS( new_rdp ) )
  875. X        return( OK ) ;
  876. X
  877. X    for ( vers = RD_MINVERS( old_rdp ) ; vers <= RD_MAXVERS( old_rdp ) ; vers++ )
  878. X         (void) pmap_unset( RD_PROGNUM( old_rdp ), vers ) ;
  879. X
  880. X    for ( vers = RD_MINVERS( new_rdp ) ; vers <= RD_MAXVERS( new_rdp ) ; vers++ )
  881. X        if ( pmap_set( RD_PROGNUM( new_rdp ),
  882. X                                        vers, SC_PROTOVAL( new_scp ), port ) )
  883. X            registered_versions++ ;
  884. X        else
  885. X            msg( LOG_ERR, func, 
  886. X                "pmap_set failed. service=%s, program=%ld, version = %ld",
  887. X                    SC_ID( new_scp ), RD_PROGNUM( new_rdp ), vers ) ;
  888. X
  889. X    if ( registered_versions == 0 )
  890. X    {
  891. X        msg( LOG_ERR, func,
  892. X                "No versions registered for RPC service %s", SC_ID( new_scp ) ) ;
  893. X        /*
  894. X         * Avoid the pmap_unset
  895. X         */
  896. X        RD_MINVERS( new_rdp ) = RD_MAXVERS( new_rdp ) + 1 ;
  897. X        return( FAILED ) ;
  898. X    }
  899. X#endif    /* ! NO_RPC */
  900. X    return( OK ) ;
  901. X}
  902. X
  903. X
  904. X/*
  905. X * Readjust service attributes. 
  906. X *
  907. X * We assume that the following attributes are the same:
  908. X *            wait
  909. X *            socket_type
  910. X *            type
  911. X *            protocol
  912. X *
  913. X * Readjustment happens in 3 steps:
  914. X *        1) We swap the svc_conf fields
  915. X *                This has the side-effect of free'ing the memory associated
  916. X *                with the old service configuration when the new configuration
  917. X *                is destroyed.
  918. X *        2) We readjust the fields that require some action to be taken:
  919. X *                RPC mapping
  920. X *                log file open
  921. X *        3) We update the address control fields.
  922. X */
  923. XPRIVATE status_e readjust( sp, new_conf_ptr, type )
  924. X    register struct service                *sp ;
  925. X    register struct service_config    **new_conf_ptr ;
  926. X    reconfig_e                                type ;
  927. X{
  928. X    struct service_config    *temp_conf ;
  929. X    struct service_config    *old_conf    = SVC_CONF( sp ) ;
  930. X    struct service_config    *new_conf    = *new_conf_ptr ;
  931. X    char                            *sid            = SVC_ID( sp ) ;
  932. X    char                            *func            = "readjust" ;
  933. X
  934. X    msg( LOG_NOTICE, func, "readjusting service %s", sid ) ;
  935. X
  936. X    SWAP( SVC_CONF( sp ), *new_conf_ptr, temp_conf ) ;
  937. X
  938. X    if ( SC_IS_RPC( old_conf ) &&
  939. X                        readjust_rpc_service( old_conf, new_conf ) == FAILED )
  940. X        return( FAILED ) ;
  941. X    
  942. X    /*
  943. X     * This is what happens if the INTERCEPT flag is toggled and an
  944. X     * interceptor is running:
  945. X     *
  946. X     * Case 1: clear->set
  947. X     *        Wait until the server dies (soft reconfig) or
  948. X     *        terminate the server (hard reconfig)
  949. X     *
  950. X     * Case 2: set->clear
  951. X    *    Send a signal to the interceptor to tell it to stop intercepting
  952. X     */
  953. X    if ( SC_IS_INTERCEPTED( old_conf ) != SC_IS_INTERCEPTED( new_conf ) )
  954. X    {
  955. X        if ( SC_IS_INTERCEPTED( new_conf ) )            /* case 1 */
  956. X        {
  957. X            if ( type == RECONFIG_HARD )
  958. X                terminate_servers( sp ) ;
  959. X        }
  960. X        else                                                    /* case 2 */
  961. X        {
  962. X            stop_interception( sp ) ;
  963. X            msg( LOG_NOTICE, func, "Stopping interception for %s", sid ) ;
  964. X        }
  965. X    }
  966. X    svc_setup_address_control( sp ) ;
  967. X    return( restart_log( sp, old_conf ) ) ;
  968. X}
  969. X
  970. END_OF_FILE
  971. if test 12082 -ne `wc -c <'xinetd/reconfig.c'`; then
  972.     echo shar: \"'xinetd/reconfig.c'\" unpacked with wrong size!
  973. fi
  974. # end of 'xinetd/reconfig.c'
  975. fi
  976. echo shar: End of archive 21 \(of 31\).
  977. cp /dev/null ark21isdone
  978. MISSING=""
  979. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 ; do
  980.     if test ! -f ark${I}isdone ; then
  981.     MISSING="${MISSING} ${I}"
  982.     fi
  983. done
  984. if test "${MISSING}" = "" ; then
  985.     echo You have unpacked all 31 archives.
  986.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  987. else
  988.     echo You still need to unpack the following archives:
  989.     echo "        " ${MISSING}
  990. fi
  991. ##  End of shell archive.
  992. exit 0
  993.