From dan@obluda.cz Sat May  8 13:59:56 1999
Return-Path: <dan@obluda.cz>
Received: from dan-h.fio.cz (fio.vol.cz [195.250.146.50])
	by hub.freebsd.org (Postfix) with ESMTP id CB7A5151B2
	for <FreeBSD-gnats-submit@freebsd.org>; Sat,  8 May 1999 13:59:49 -0700 (PDT)
	(envelope-from dan@obluda.cz)
Received: (from dan@localhost)
	by dan-h.fio.cz (8.9.2/8.9.0) id WAA14714;
	Sat, 8 May 1999 22:59:06 +0200 (CEST)
Received: (from dan@localhost)
	by dan-h.fio.cz (8.9.2/8.9.0) id QAA10290;
	Sat, 8 May 1999 16:22:36 +0200 (CEST)
Message-Id: <199905081422.QAA10290@dan-h.fio.cz>
Date: Sat, 8 May 1999 16:22:36 +0200 (CEST)
From: dan@obluda.cz
Reply-To: dan@obluda.cz
To: FreeBSD-gnats-submit@freebsd.org
Subject: INETD hangup problem report
X-Send-Pr-Version: 3.2

>Number:         11594
>Category:       bin
>Synopsis:       hang problem in INETD
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    des
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Sat May  8 14:00:04 PDT 1999
>Closed-Date:    Wed May 12 05:16:17 PDT 1999
>Last-Modified:  Wed May 12 05:16:48 PDT 1999
>Originator:     Dan Lukes
>Release:        FreeBSD 3.1-RELEASE i386
>Organization:
Obludarium
>Environment:

	a system with inetd running

>Description:

	INETD hang if maximum number of child on all configured services 
        is reached
	Childs thats ends after it remain "zombie" forever.

        When the maximum child for a service is running, the service is
disabled (see last command of addchild() ). It remove the service's
socket descriptor from allsock (used in select() ) and do nsock-- (the
number of enabled services).

	After the last service is disabled by this mechanism, the nsock is
zero and allsock contain no descriptor but pipe descriptor for communicating
with signal handler functions.

	Lets inspect the neverending "for(;;)" in main():

           if (nsock == 0) {
                (void) sigblock(SIGBLOCK);
                while (nsock == 0)
                    sigpause(0L);
                (void) sigsetmask(0L);
            }

	Entering the while() is the last action in program's life as no signal
handler never change the nsock variable directly, so while never end. Signal 
handlers writes the "I'm has been invoked!" mark in pipe only. The code
processing those marks on the other end of pipe is never invoked. This is
true for SIGCHLD also, so wait() is never called and childs remain in
"zombie" status until inetd exit.

>How-To-Repeat:

	Create inetd.conf with one "wait" service only.
	Run (restart) inetd.
	Connect to service.

	The inetd is in neverending loop now until terminated.
>Fix:

	I see no reason for existence problematic code in source code. The
allsock variable ever contain at least the read end of pipe descriptor, so the 
list of socket is never empty. 
	Well, it's not so good to wait in select() for output from signal 
handler routines as the select() will terminate with errno=EINTR when signal
arrive, but "continue" immediately wrap execution back to new select(). It
immediately detect the pipe's end is ready for reading (if EINTR has been 
caused by one of "our" signal). I thing the one system call overhead can be 
ignored. 
	The suggested fix:

*** inetd.c.ORIG        Tue Jan  5 12:56:35 1999
--- inetd.c     Sat May  8 13:19:20 1999
***************
*** 447,458 ****
            int n, ctrl;
            fd_set readable;

-           if (nsock == 0) {
-               (void) sigblock(SIGBLOCK);
-               while (nsock == 0)
-                   sigpause(0L);
-               (void) sigsetmask(0L);
-           }
            readable = allsock;
            if ((n = select(maxsock + 1, &readable, (fd_set *)0,
                (fd_set *)0, (struct timeval *)0)) <= 0) {
--- 447,452 ----


	Note, I look to old FreeBSD's sources and it's very old error. 
        IMHO, it may come from original Berkeley sources and may appear
in other systems derived from those sources too.

	This problem report MAY fix the problem report i386/10468




>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-bugs->des 
Responsible-Changed-By: des 
Responsible-Changed-When: Tue May 11 05:18:50 PDT 1999 
Responsible-Changed-Why:  
I'll investigate this. 

From: Dag-Erling Smorgrav <des@flood.ping.uio.no>
To: dan@obluda.cz
Cc: FreeBSD-gnats-submit@FreeBSD.ORG
Subject: Re: bin/11594: INETD hangup problem report
Date: 11 May 1999 14:44:00 +0200

 dan@obluda.cz writes:
 > 	After the last service is disabled by this mechanism, the nsock is
 > zero and allsock contain no descriptor but pipe descriptor for communicating
 > with signal handler functions.
 
 Please try the attached patch.
 
 DES
 -- 
 Dag-Erling Smorgrav - des@flood.ping.uio.no
 
 Index: inetd.c
 ===================================================================
 RCS file: /home/ncvs/src/usr.sbin/inetd/inetd.c,v
 retrieving revision 1.48
 diff -u -r1.48 inetd.c
 --- inetd.c	1999/04/11 09:22:17	1.48
 +++ inetd.c	1999/05/11 12:33:29
 @@ -465,17 +465,17 @@
  		exit(EX_OSERR);
  	}
  	FD_SET(signalpipe[0], &allsock);
 -	if (signalpipe[0]>maxsock) maxsock = signalpipe[0];
 +	nsock++;
 +	if (signalpipe[0] > maxsock)
 +	    maxsock = signalpipe[0];
  
  	for (;;) {
  	    int n, ctrl;
  	    fd_set readable;
  
  	    if (nsock == 0) {
 -		(void) sigblock(SIGBLOCK);
 -		while (nsock == 0)
 -		    sigpause(0L);
 -		(void) sigsetmask(0L);
 +		syslog(LOG_ERR, "%s: nsock=0", __FUNCTION__);
 +		exit(EX_SOFTWARE);
  	    }
  	    readable = allsock;
  	    if ((n = select(maxsock + 1, &readable, (fd_set *)0,
 

From: Dan Lukes <dan@fio.cz>
To: freebsd-gnats-submit@freebsd.org, dan@obluda.cz
Cc:  
Subject: Re: bin/11594: hang problem in INETD
Date: Wed, 12 May 1999 11:45:39 +0200

 	Your patch is functional equivalent of my patch.
 	You consider the "nsock" is number of handlers that is FD_SETed
 into allsock. I trust nsock as the number of sockets FD_SETed into
 allsock.
 
 	You increase nsock, so "if (nsock == 0)" conditioon is false
 everytime. The "if" block I recommend to delete in my patch is still
 present in your patch, but it's body is never reached.
 	Testing of ever-failing condition is defensive-programming
 practice - just "for sure" and create safer program. But, it waste
 a CPU time a lot.
 
 	I have no opinion which is better for this case. 
 	IMHO, you can commit either patch "ad nutum".
 
 
 							Dan
 -- 
 
 Dan Lukes            tel: +420 2 24102204, fax: +420 2 24102301
 root, postmaster (and *master) of FIONet, webmaster of KolejNET
 Administrator   of    www.antispam.cz's    spammer    blacklist
 AKA: dan@obluda.cz, dan@freebsd.cz, dan@kolej.mff.cuni.cz
 
State-Changed-From-To: open->closed 
State-Changed-By: des 
State-Changed-When: Wed May 12 05:16:17 PDT 1999 
State-Changed-Why:  
Fixed in 4.0 and 3.2. 
>Unformatted:
