Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 04 Nov 1996 16:44:10 -0800
From:      Julian Elischer <julian@whistle.com>
To:        hackers@freebsd.org
Subject:   [Fwd: usr.sbin.inetd]
Message-ID:  <327E8DDA.59E2B600@whistle.com>

next in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format.

--------------FF6D5DF3F54BC7E1CFBAE39
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Here is a compatible but useful addition to inetd.
I've wanted this for a long time..

one change...
in the man page it describes tha option as [something I forget]
but we decided that it should be better
described as:

{wait|nowait}[/maxclients]

does anyone see a reason this is bad?

does anyone else thonk it's useful?

the reason to do it:
it allows one to limit the effect on a small memory machine of
multiple simultanious connection requests. 
The example would be if you suddenly get 20 mail messages
incoming, accepting them all would be suicide, as the machine would
thrash itself to death. with this option you can limit the effect.
 processing them 3 at a time will get them done quicker than
thrashing on 20 at once which might take 100 times as long..

for our embedded FreeBSD box this has turned out to be the 
SINGLE BIGGEST improvement to user perceptions of unreliablility
and performance.

I'd like ot see it a standard optin so that we don't have to
keep a separate inetd in out tree, because we can't do without it..

comments please..
(BTW it includes a cleanup to make it compile in -wall)

julian

--------------FF6D5DF3F54BC7E1CFBAE39
Content-Type: message/rfc822
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

Return-Path: <archie@whistle.com>
Received: from whistle.com (whistle.whistle.com [207.76.205.131]) by alpo.whistle.com (8.8.2/8.8.2) with ESMTP id NAA10448 for <julian@alpo.whistle.com>; Mon, 4 Nov 1996 13:51:42 -0800 (PST)
Received: (from smap@localhost) by whistle.com (8.7.5/8.6.12) id NAA29848 for <julian@whistle.com>; Mon, 4 Nov 1996 13:51:40 -0800 (PST)
Received: from bubba.whistle.com(207.76.205.7) by whistle.com via smap (V1.3)
	id sma029844; Mon Nov  4 13:51:26 1996
Received: (from archie@localhost) by bubba.whistle.com (8.7.5/8.6.12) id NAA02353 for julian@whistle.com; Mon, 4 Nov 1996 13:51:25 -0800 (PST)
From: Archie Cobbs <archie@whistle.com>
Message-Id: <199611042151.NAA02353@bubba.whistle.com>
Subject: usr.sbin.inetd
To: julian@whistle.com (Julian Elischer)
Date: Mon, 4 Nov 1996 13:51:25 -0800 (PST)
X-Mailer: ELM [version 2.4ME+ PL25 (25)]
MIME-Version: 1.0
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit

Index: Makefile
===================================================================
RCS file: /cvs/freebsd/src/usr.sbin/inetd/Makefile,v
retrieving revision 1.3
diff -c -r1.3 Makefile
*** 1.3	1996/01/01 08:42:22
--- Makefile	1996/11/04 21:50:26
***************
*** 4,9 ****
--- 4,12 ----
  MAN8=	inetd.8
  MLINKS=	inetd.8 inetd.conf.5
  
+ COPTS+=	-Wall
+ #COPTS+=	-DSANITY_CHECK
+ 
  DPADD+=	${LIBUTIL}
  LDADD+=	-lutil
  
Index: inetd.8
===================================================================
RCS file: /cvs/freebsd/src/usr.sbin/inetd/inetd.8,v
retrieving revision 1.9
diff -c -r1.9 inetd.8
*** 1.9	1996/08/09 22:20:23
--- inetd.8	1996/11/04 21:50:26
***************
*** 101,107 ****
  service name
  socket type
  protocol
! wait/nowait
  user
  server program
  server program arguments
--- 101,107 ----
  service name
  socket type
  protocol
! wait/nowait[/max-child]
  user
  server program
  server program arguments
***************
*** 260,265 ****
--- 260,274 ----
  requests until a timeout.
  TCPMUX services must use 
  .Dq nowait .
+ .Pp
+ The maximum number of outstanding child processes (or ``threads'')
+ for a ``nowait'' service may be explicitly specified by appending a
+ ``/'' followed by the number to the ``nowait'' keyword. Normally
+ (or if a value of zero is specified) there is no maximum. Otherwise,
+ once the maximum is reached, further connection attempts will be
+ queued up until an existing child process finishes. This also works
+ in the case of ``wait'' mode, although a value other than one (the
+ default) might not make sense in some cases.
  .Pp
  The
  .Em user
Index: inetd.c
===================================================================
RCS file: /cvs/freebsd/src/usr.sbin/inetd/inetd.c,v
retrieving revision 1.15
diff -c -r1.15 inetd.c
*** 1.15	1996/11/01 01:42:08
--- inetd.c	1996/11/04 21:50:26
***************
*** 32,45 ****
   */
  
  #ifndef lint
! static char copyright[] =
  "@(#) Copyright (c) 1983, 1991, 1993, 1994\n\
  	The Regents of the University of California.  All rights reserved.\n";
  #endif /* not lint */
  
  #ifndef lint
  /* from: @(#)inetd.c	8.4 (Berkeley) 4/13/94"; */
! static char inetd_c_rcsid[] =
  	"$Id: inetd.c,v 1.15 1996/11/01 01:42:08 alex Exp $";
  #endif /* not lint */
  
--- 32,45 ----
   */
  
  #ifndef lint
! static char copyright[] __attribute__ ((unused)) =
  "@(#) Copyright (c) 1983, 1991, 1993, 1994\n\
  	The Regents of the University of California.  All rights reserved.\n";
  #endif /* not lint */
  
  #ifndef lint
  /* from: @(#)inetd.c	8.4 (Berkeley) 4/13/94"; */
! static char inetd_c_rcsid[] __attribute__ ((unused)) =
  	"$Id: inetd.c,v 1.15 1996/11/01 01:42:08 alex Exp $";
  #endif /* not lint */
  
***************
*** 112,117 ****
--- 112,118 ----
  #include <netinet/in.h>
  #include <arpa/inet.h>
  #include <rpc/rpc.h>
+ #include <rpc/pmap_clnt.h>
  
  #include <errno.h>
  #include <fcntl.h>
***************
*** 124,139 ****
  #include <syslog.h>
  #include <unistd.h>
  #include <libutil.h>
  
  #include "pathnames.h"
  
  #define	TOOMANY		256		/* don't start more than TOOMANY */
  #define	CNT_INTVL	60		/* servers in CNT_INTVL sec. */
  #define	RETRYTIME	(60*10)		/* retry after bind or server fail */
  
  #define	SIGBLOCK	(sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM))
  
- 
  int	debug = 0;
  int	log = 0;
  int	nsock, maxsock;
--- 125,141 ----
  #include <syslog.h>
  #include <unistd.h>
  #include <libutil.h>
+ #include <sysexits.h>
  
  #include "pathnames.h"
  
  #define	TOOMANY		256		/* don't start more than TOOMANY */
  #define	CNT_INTVL	60		/* servers in CNT_INTVL sec. */
  #define	RETRYTIME	(60*10)		/* retry after bind or server fail */
+ #define MAX_MAXCHLD	32767		/* max allowable max children */
  
  #define	SIGBLOCK	(sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM))
  
  int	debug = 0;
  int	log = 0;
  int	nsock, maxsock;
***************
*** 149,155 ****
  	char	*se_service;		/* name of service */
  	int	se_socktype;		/* type of socket to use */
  	char	*se_proto;		/* protocol used */
! 	short	se_wait;		/* single threaded server */
  	short	se_checked;		/* looked at during merge */
  	char	*se_user;		/* user name to run as */
  	struct	biltin *se_bi;		/* if built-in, description */
--- 151,159 ----
  	char	*se_service;		/* name of service */
  	int	se_socktype;		/* type of socket to use */
  	char	*se_proto;		/* protocol used */
! 	short	se_maxchild;		/* max number of children */
! 	short	se_numchild;		/* current number of children */
! 	short	*se_pids;		/* array of child pids */
  	short	se_checked;		/* looked at during merge */
  	char	*se_user;		/* user name to run as */
  	struct	biltin *se_bi;		/* if built-in, description */
***************
*** 159,165 ****
  	int	se_fd;			/* open descriptor */
  	int	se_type;		/* type */
  	struct	sockaddr_in se_ctrladdr;/* bound address */
! 	int	se_rpc;			/* ==1 if RPC service */
  	int	se_rpc_prog;		/* RPC program number */
  	u_int	se_rpc_lowvers;		/* RPC low version */
  	u_int	se_rpc_highvers;	/* RPC high version */
--- 163,170 ----
  	int	se_fd;			/* open descriptor */
  	int	se_type;		/* type */
  	struct	sockaddr_in se_ctrladdr;/* bound address */
! 	u_char	se_accept;		/* i.e., wait/nowait mode */
! 	u_char	se_rpc;			/* ==1 if RPC service */
  	int	se_rpc_prog;		/* RPC program number */
  	u_int	se_rpc_lowvers;		/* RPC low version */
  	u_int	se_rpc_highvers;	/* RPC high version */
***************
*** 195,201 ****
--- 200,209 ----
  char	       *newstr __P((char *));
  char	       *nextline __P((FILE *));
  void		print_service __P((char *, struct servtab *));
+ void		addchild __P((struct servtab *, int));
  void		reapchild __P((int));
+ void		enable __P((struct servtab *));
+ void		disable __P((struct servtab *));
  void		retry __P((int));
  int		setconfig __P((void));
  void		setup __P((struct servtab *));
***************
*** 209,215 ****
  	char	*bi_service;		/* internally provided service name */
  	int	bi_socktype;		/* type of socket supported */
  	short	bi_fork;		/* 1 if should fork before call */
! 	short	bi_wait;		/* 1 if should wait for child */
  	void	(*bi_fn)();		/* function which performs it */
  } biltins[] = {
  	/* Echo received data */
--- 217,223 ----
  	char	*bi_service;		/* internally provided service name */
  	int	bi_socktype;		/* type of socket supported */
  	short	bi_fork;		/* 1 if should fork before call */
! 	short	bi_maxchild;		/* max number of children (default) */
  	void	(*bi_fn)();		/* function which performs it */
  } biltins[] = {
  	/* Echo received data */
***************
*** 298,304 ****
  			if (!inet_aton(optarg, &bind_address)) {
  				syslog(LOG_ERR,
  			         "-a %s: invalid IP address", optarg);
! 				 exit(1);
  			}
  			break;
  		case 'p':
--- 306,312 ----
  			if (!inet_aton(optarg, &bind_address)) {
  				syslog(LOG_ERR,
  			         "-a %s: invalid IP address", optarg);
! 				exit(EX_USAGE);
  			}
  			break;
  		case 'p':
***************
*** 309,315 ****
  			syslog(LOG_ERR,
  				"usage: inetd [-dl] [-a address] [-R rate]"
  				" [-p pidfile] [conf-file]");
! 			exit(1);
  		}
  	argc -= optind;
  	argv += optind;
--- 317,323 ----
  			syslog(LOG_ERR,
  				"usage: inetd [-dl] [-a address] [-R rate]"
  				" [-p pidfile] [conf-file]");
! 			exit(EX_USAGE);
  		}
  	argc -= optind;
  	argv += optind;
***************
*** 383,389 ****
  		    if (debug)
  			    fprintf(stderr, "someone wants %s\n",
  				sep->se_service);
! 		    if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) {
  			    ctrl = accept(sep->se_fd, (struct sockaddr *)0,
  				(int *)0);
  			    if (debug)
--- 391,397 ----
  		    if (debug)
  			    fprintf(stderr, "someone wants %s\n",
  				sep->se_service);
! 		    if (sep->se_accept && sep->se_socktype == SOCK_STREAM) {
  			    ctrl = accept(sep->se_fd, (struct sockaddr *)0,
  				(int *)0);
  			    if (debug)
***************
*** 395,401 ****
  						sep->se_service);
  				    continue;
  			    }
! 			    if(log) {
  				i = sizeof peer;
  				if(getpeername(ctrl, (struct sockaddr *)
  						&peer, &i)) {
--- 403,409 ----
  						sep->se_service);
  				    continue;
  			    }
! 			    if (log) {
  				i = sizeof peer;
  				if(getpeername(ctrl, (struct sockaddr *)
  						&peer, &i)) {
***************
*** 456,475 ****
  		    }
  		    if (pid < 0) {
  			    syslog(LOG_ERR, "fork: %m");
! 			    if (!sep->se_wait &&
  				sep->se_socktype == SOCK_STREAM)
  				    close(ctrl);
  			    sigsetmask(0L);
  			    sleep(1);
  			    continue;
  		    }
! 		    if (pid && sep->se_wait) {
! 			    sep->se_wait = pid;
! 			    if (sep->se_fd >= 0) {
! 				FD_CLR(sep->se_fd, &allsock);
! 			        nsock--;
! 			    }
! 		    }
  		    sigsetmask(0L);
  		    if (pid == 0) {
  			    if (dofork) {
--- 464,478 ----
  		    }
  		    if (pid < 0) {
  			    syslog(LOG_ERR, "fork: %m");
! 			    if (sep->se_accept &&
  				sep->se_socktype == SOCK_STREAM)
  				    close(ctrl);
  			    sigsetmask(0L);
  			    sleep(1);
  			    continue;
  		    }
! 		    if (pid)
! 			addchild(sep, pid);
  		    sigsetmask(0L);
  		    if (pid == 0) {
  			    if (dofork) {
***************
*** 478,488 ****
  						maxsock);
  				for (tmpint = maxsock; tmpint > 2; tmpint--)
  					if (tmpint != ctrl)
! 						close(tmpint);
  			    }
! 			    if (sep->se_bi)
  				(*sep->se_bi->bi_fn)(ctrl, sep);
! 			    else {
  				if (debug)
  					fprintf(stderr, "%d execl %s\n",
  					    getpid(), sep->se_server);
--- 481,492 ----
  						maxsock);
  				for (tmpint = maxsock; tmpint > 2; tmpint--)
  					if (tmpint != ctrl)
! 						(void) close(tmpint);
  			    }
! 			    if (sep->se_bi) {
  				(*sep->se_bi->bi_fn)(ctrl, sep);
! 				/* NOTREACHED */
! 			    } else {
  				if (debug)
  					fprintf(stderr, "%d execl %s\n",
  					    getpid(), sep->se_server);
***************
*** 497,522 ****
  						sep->se_user);
  					if (sep->se_socktype != SOCK_STREAM)
  						recv(0, buf, sizeof (buf), 0);
! 					_exit(1);
  				}
  				if (setsid() < 0) {
  					syslog(LOG_ERR,
  						"%s: can't setsid(): %m",
  						 sep->se_service);
! 					/* _exit(1); not fatal yet */
  				}
  				if (pwd->pw_uid) {
  					if (setlogin(sep->se_user) < 0) {
  						syslog(LOG_ERR,
  						 "%s: can't setlogin(%s): %m",
  						 sep->se_service, sep->se_user);
! 						/* _exit(1); not fatal yet */
  					}
  					if (setgid(pwd->pw_gid) < 0) {
  						syslog(LOG_ERR,
  						  "%s: can't set gid %d: %m",
  						  sep->se_service, pwd->pw_gid);
! 						_exit(1);
  					}
  					(void) initgroups(pwd->pw_name,
  							pwd->pw_gid);
--- 501,526 ----
  						sep->se_user);
  					if (sep->se_socktype != SOCK_STREAM)
  						recv(0, buf, sizeof (buf), 0);
! 					_exit(EX_NOUSER);
  				}
  				if (setsid() < 0) {
  					syslog(LOG_ERR,
  						"%s: can't setsid(): %m",
  						 sep->se_service);
! 					/* _exit(EX_OSERR); not fatal yet */
  				}
  				if (pwd->pw_uid) {
  					if (setlogin(sep->se_user) < 0) {
  						syslog(LOG_ERR,
  						 "%s: can't setlogin(%s): %m",
  						 sep->se_service, sep->se_user);
! 						/* _exit(EX_OSERR); not yet */
  					}
  					if (setgid(pwd->pw_gid) < 0) {
  						syslog(LOG_ERR,
  						  "%s: can't set gid %d: %m",
  						  sep->se_service, pwd->pw_gid);
! 						_exit(EX_OSERR);
  					}
  					(void) initgroups(pwd->pw_name,
  							pwd->pw_gid);
***************
*** 524,530 ****
  						syslog(LOG_ERR,
  						  "%s: can't set uid %d: %m",
  						  sep->se_service, pwd->pw_uid);
! 						_exit(1);
  					}
  				}
  				execv(sep->se_server, sep->se_argv);
--- 528,534 ----
  						syslog(LOG_ERR,
  						  "%s: can't set uid %d: %m",
  						  sep->se_service, pwd->pw_uid);
! 						_exit(EX_OSERR);
  					}
  				}
  				execv(sep->se_server, sep->se_argv);
***************
*** 532,551 ****
  					recv(0, buf, sizeof (buf), 0);
  				syslog(LOG_ERR,
  				    "cannot execute %s: %m", sep->se_server);
! 				_exit(1);
  			    }
  		    }
! 		    if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
  			    close(ctrl);
  		}
  	}
  }
  
  void
  reapchild(signo)
  	int signo;
  {
! 	int status;
  	pid_t pid;
  	struct servtab *sep;
  
--- 536,581 ----
  					recv(0, buf, sizeof (buf), 0);
  				syslog(LOG_ERR,
  				    "cannot execute %s: %m", sep->se_server);
! 				_exit(EX_OSERR);
  			    }
  		    }
! 		    if (sep->se_accept && sep->se_socktype == SOCK_STREAM)
  			    close(ctrl);
  		}
  	}
  }
  
+ /*
+  * Record a new child pid for this service. If we've reached the
+  * limit on children, then stop accepting incoming requests.
+  */
+ 
+ void
+ addchild(struct servtab *sep, pid_t pid)
+ {
+ #ifdef SANITY_CHECK
+ 	if (sep->se_numchild >= sep->se_maxchild) {
+ 		syslog(LOG_ERR, "%s: %d >= %d",
+ 		    __FUNCTION__, sep->se_numchild, sep->se_maxchild);
+ 		exit(EX_SOFTWARE);
+ 	}
+ #endif
+ 	if (sep->se_maxchild == 0)
+ 		return;
+ 	sep->se_pids[sep->se_numchild++] = pid;
+ 	if (sep->se_numchild == sep->se_maxchild)
+ 		disable(sep);
+ }
+ 
+ /*
+  * Some child process has exited. See if it's on somebody's list.
+  */
+ 
  void
  reapchild(signo)
  	int signo;
  {
! 	int k, status;
  	pid_t pid;
  	struct servtab *sep;
  
***************
*** 556,574 ****
  		if (debug)
  			fprintf(stderr, "%d reaped, status %#x\n",
  				pid, status);
! 		for (sep = servtab; sep; sep = sep->se_next)
! 			if (sep->se_wait == pid) {
! 				if (status)
! 					syslog(LOG_WARNING,
! 					    "%s: exit status 0x%x",
! 					    sep->se_server, status);
! 				if (debug)
! 					fprintf(stderr, "restored %s, fd %d\n",
! 					    sep->se_service, sep->se_fd);
! 				FD_SET(sep->se_fd, &allsock);
! 				nsock++;
! 				sep->se_wait = 1;
! 			}
  	}
  }
  
--- 586,612 ----
  		if (debug)
  			fprintf(stderr, "%d reaped, status %#x\n",
  				pid, status);
! 		for (sep = servtab; sep; sep = sep->se_next) {
! 			for (k = 0; k < sep->se_numchild; k++)
! 				if (sep->se_pids[k] == pid)
! 					break;
! 			if (k == sep->se_numchild)
! 				continue;
! 			if (sep->se_numchild == sep->se_maxchild)
! 				enable(sep);
! 			memmove(sep->se_pids + k, sep->se_pids + k + 1,
! 				--sep->se_numchild * sizeof(*sep->se_pids));
! 			if (status)
! 				syslog(LOG_WARNING,
! 				    "%s: exit status 0x%x",
! 				    sep->se_server, status);
! 			if (debug)
! 				fprintf(stderr,
! 				    "restored %s, fd %d\n",
! 				    sep->se_service,
! 				    sep->se_fd);
! 			break;
! 		}
  	}
  }
  
***************
*** 576,582 ****
  config(signo)
  	int signo;
  {
! 	struct servtab *sep, *cp, **sepp;
  	struct passwd *pwd;
  	long omask;
  
--- 614,620 ----
  config(signo)
  	int signo;
  {
! 	struct servtab *sep, *new, **sepp;
  	struct passwd *pwd;
  	long omask;
  
***************
*** 586,628 ****
  	}
  	for (sep = servtab; sep; sep = sep->se_next)
  		sep->se_checked = 0;
! 	while (cp = getconfigent()) {
! 		if ((pwd = getpwnam(cp->se_user)) == NULL) {
  			syslog(LOG_ERR,
  				"%s/%s: No such user '%s', service ignored",
! 				cp->se_service, cp->se_proto, cp->se_user);
  			continue;
  		}
  		for (sep = servtab; sep; sep = sep->se_next)
! 			if (strcmp(sep->se_service, cp->se_service) == 0 &&
! 			    strcmp(sep->se_proto, cp->se_proto) == 0)
  				break;
  		if (sep != 0) {
  			int i;
  
  			omask = sigblock(SIGBLOCK);
! 			/*
! 			 * sep->se_wait may be holding the pid of a daemon
! 			 * that we're waiting for.  If so, don't overwrite
! 			 * it unless the config file explicitly says don't
! 			 * wait.
! 			 */
! 			if (cp->se_bi == 0 &&
! 			    (sep->se_wait == 1 || cp->se_wait == 0))
! 				sep->se_wait = cp->se_wait;
! #define SWAP(a, b) { char *c = a; a = b; b = c; }
! 			if (cp->se_user)
! 				SWAP(sep->se_user, cp->se_user);
! 			if (cp->se_server)
! 				SWAP(sep->se_server, cp->se_server);
  			for (i = 0; i < MAXARGV; i++)
! 				SWAP(sep->se_argv[i], cp->se_argv[i]);
  			sigsetmask(omask);
! 			freeconfig(cp);
  			if (debug)
  				print_service("REDO", sep);
  		} else {
! 			sep = enter(cp);
  			if (debug)
  				print_service("ADD ", sep);
  		}
--- 624,680 ----
  	}
  	for (sep = servtab; sep; sep = sep->se_next)
  		sep->se_checked = 0;
! 	while ((new = getconfigent())) {
! 		if ((pwd = getpwnam(new->se_user)) == NULL) {
  			syslog(LOG_ERR,
  				"%s/%s: No such user '%s', service ignored",
! 				new->se_service, new->se_proto, new->se_user);
  			continue;
  		}
  		for (sep = servtab; sep; sep = sep->se_next)
! 			if (strcmp(sep->se_service, new->se_service) == 0 &&
! 			    strcmp(sep->se_proto, new->se_proto) == 0)
  				break;
  		if (sep != 0) {
  			int i;
  
+ #define SWAP(a, b) { typeof(a) c = a; a = b; b = c; }
  			omask = sigblock(SIGBLOCK);
! 			/* copy over outstanding child pids */
! 			if (sep->se_maxchild && new->se_maxchild) {
! 				new->se_numchild = sep->se_numchild;
! 				if (new->se_numchild > new->se_maxchild)
! 					new->se_numchild = new->se_maxchild;
! 				memcpy(new->se_pids, sep->se_pids,
! 				    new->se_numchild * sizeof(*new->se_pids));
! 			}
! 			SWAP(sep->se_pids, new->se_pids);
! 			sep->se_maxchild = new->se_maxchild;
! 			sep->se_numchild = new->se_numchild;
! 			/* might need to turn on or off service now */
! 			if (sep->se_fd >= 0) {
! 			      if (sep->se_maxchild
! 				  && sep->se_numchild == sep->se_maxchild) {
! 				      if (FD_ISSET(sep->se_fd, &allsock))
! 					  disable(sep);
! 			      } else {
! 				      if (!FD_ISSET(sep->se_fd, &allsock))
! 					  enable(sep);
! 			      }
! 			}
! 			sep->se_accept = new->se_accept;
! 			if (new->se_user)
! 				SWAP(sep->se_user, new->se_user);
! 			if (new->se_server)
! 				SWAP(sep->se_server, new->se_server);
  			for (i = 0; i < MAXARGV; i++)
! 				SWAP(sep->se_argv[i], new->se_argv[i]);
  			sigsetmask(omask);
! 			freeconfig(new);
  			if (debug)
  				print_service("REDO", sep);
  		} else {
! 			sep = enter(new);
  			if (debug)
  				print_service("ADD ", sep);
  		}
***************
*** 673,679 ****
  	 */
  	omask = sigblock(SIGBLOCK);
  	sepp = &servtab;
! 	while (sep = *sepp) {
  		if (sep->se_checked) {
  			sepp = &sep->se_next;
  			continue;
--- 725,731 ----
  	 */
  	omask = sigblock(SIGBLOCK);
  	sepp = &servtab;
! 	while ((sep = *sepp)) {
  		if (sep->se_checked) {
  			sepp = &sep->se_next;
  			continue;
***************
*** 727,733 ****
  
  	timingout = 0;
  	for (sep = servtab; sep; sep = sep->se_next)
! 		if (sep->se_fd == -1)
  			setup(sep);
  }
  
--- 779,785 ----
  
  	timingout = 0;
  	for (sep = servtab; sep; sep = sep->se_next)
! 		if (sep->se_fd == -1 && !ISMUX(sep))
  			setup(sep);
  }
  
***************
*** 796,805 ****
          }
  	if (sep->se_socktype == SOCK_STREAM)
  		listen(sep->se_fd, 64);
! 	FD_SET(sep->se_fd, &allsock);
! 	nsock++;
! 	if (sep->se_fd > maxsock)
! 		maxsock = sep->se_fd;
  	if (debug) {
  		fprintf(stderr, "registered %s on %d\n",
  			sep->se_server, sep->se_fd);
--- 848,854 ----
          }
  	if (sep->se_socktype == SOCK_STREAM)
  		listen(sep->se_fd, 64);
! 	enable(sep);
  	if (debug) {
  		fprintf(stderr, "registered %s on %d\n",
  			sep->se_server, sep->se_fd);
***************
*** 814,831 ****
  	struct servtab *sep;
  {
  	if (sep->se_fd >= 0) {
! 		nsock--;
! 		FD_CLR(sep->se_fd, &allsock);
  		(void) close(sep->se_fd);
  		sep->se_fd = -1;
  	}
  	sep->se_count = 0;
  	/*
! 	 * Don't keep the pid of this running deamon: when reapchild()
  	 * reaps this pid, it would erroneously increment nsock.
  	 */
! 	if (sep->se_wait > 1)
! 		sep->se_wait = 1;
  }
  
  struct servtab *
--- 863,879 ----
  	struct servtab *sep;
  {
  	if (sep->se_fd >= 0) {
! 		if (FD_ISSET(sep->se_fd, &allsock))
! 			disable(sep);
  		(void) close(sep->se_fd);
  		sep->se_fd = -1;
  	}
  	sep->se_count = 0;
  	/*
! 	 * Don't keep any running pids, otherwise when reapchild()
  	 * reaps this pid, it would erroneously increment nsock.
  	 */
! 	sep->se_numchild = 0;
  }
  
  struct servtab *
***************
*** 838,844 ****
  	sep = (struct servtab *)malloc(sizeof (*sep));
  	if (sep == (struct servtab *)0) {
  		syslog(LOG_ERR, "Out of memory.");
! 		exit(-1);
  	}
  	*sep = *cp;
  	sep->se_fd = -1;
--- 886,892 ----
  	sep = (struct servtab *)malloc(sizeof (*sep));
  	if (sep == (struct servtab *)0) {
  		syslog(LOG_ERR, "Out of memory.");
! 		exit(EX_OSERR);
  	}
  	*sep = *cp;
  	sep->se_fd = -1;
***************
*** 849,854 ****
--- 897,962 ----
  	return (sep);
  }
  
+ void
+ enable(struct servtab *sep)
+ {
+ 	if (debug)
+ 		print_service("ENAB", sep);
+ #ifdef SANITY_CHECK
+ 	if (sep->se_fd < 0) {
+ 		syslog(LOG_ERR,
+ 		    "%s: %s: bad fd", __FUNCTION__, sep->se_service);
+ 		exit(EX_SOFTWARE);
+ 	}
+ 	if (ISMUX(sep)) {
+ 		syslog(LOG_ERR,
+ 		    "%s: %s: is mux", __FUNCTION__, sep->se_service);
+ 		exit(EX_SOFTWARE);
+ 	}
+ 	if (FD_ISSET(sep->se_fd, &allsock)) {
+ 		syslog(LOG_ERR,
+ 		    "%s: %s: not off", __FUNCTION__, sep->se_service);
+ 		exit(EX_SOFTWARE);
+ 	}
+ #endif
+ 	FD_SET(sep->se_fd, &allsock);
+ 	nsock++;
+ 	if (sep->se_fd > maxsock)
+ 		maxsock = sep->se_fd;
+ }
+ 
+ void
+ disable(struct servtab *sep)
+ {
+ 	if (debug)
+ 		print_service("DSAB", sep);
+ #ifdef SANITY_CHECK
+ 	if (sep->se_fd < 0) {
+ 		syslog(LOG_ERR,
+ 		    "%s: %s: bad fd", __FUNCTION__, sep->se_service);
+ 		exit(EX_SOFTWARE);
+ 	}
+ 	if (ISMUX(sep)) {
+ 		syslog(LOG_ERR,
+ 		    "%s: %s: is mux", __FUNCTION__, sep->se_service);
+ 		exit(EX_SOFTWARE);
+ 	}
+ 	if (!FD_ISSET(sep->se_fd, &allsock)) {
+ 		syslog(LOG_ERR,
+ 		    "%s: %s: not on", __FUNCTION__, sep->se_service);
+ 		exit(EX_SOFTWARE);
+ 	}
+ 	if (nsock == 0) {
+ 		syslog(LOG_ERR, "%s: nsock=0", __FUNCTION__);
+ 		exit(EX_SOFTWARE);
+ 	}
+ #endif
+ 	FD_CLR(sep->se_fd, &allsock);
+ 	nsock--;
+ 	if (sep->se_fd == maxsock)
+ 		maxsock--;
+ }
+ 
  FILE	*fconfig = NULL;
  struct	servtab serv;
  char	line[LINE_MAX];
***************
*** 879,885 ****
  {
  	struct servtab *sep = &serv;
  	int argc;
! 	char *cp, *arg;
  	char *versp;
  	static char TCPMUX_TOKEN[] = "tcpmux/";
  #define MUX_LEN		(sizeof(TCPMUX_TOKEN)-1)
--- 987,993 ----
  {
  	struct servtab *sep = &serv;
  	int argc;
! 	char *cp, *arg, *s;
  	char *versp;
  	static char TCPMUX_TOKEN[] = "tcpmux/";
  #define MUX_LEN		(sizeof(TCPMUX_TOKEN)-1)
***************
*** 959,972 ****
                  }
          }
  	arg = sskip(&cp);
! 	sep->se_wait = strcmp(arg, "wait") == 0;
  	if (ISMUX(sep)) {
  		/*
! 		 * Silently enforce "nowait" for TCPMUX services since
! 		 * they don't have an assigned port to listen on.
  		 */
! 		sep->se_wait = 0;
! 
  		if (strcmp(sep->se_proto, "tcp")) {
  			syslog(LOG_ERR,
  				"%s: bad protocol for tcpmux service %s",
--- 1067,1102 ----
                  }
          }
  	arg = sskip(&cp);
! 	if (!strncmp(arg, "wait", 4))
! 		sep->se_accept = 0;
! 	else if (!strncmp(arg, "nowait", 6))
! 		sep->se_accept = 1;
! 	else {
! 		syslog(LOG_ERR,
! 			"%s: bad wait/nowait for service %s",
! 			CONFIG, sep->se_service);
! 		goto more;
! 	}
! 	sep->se_maxchild = -1;
! 	if ((s = strchr(arg, '/')) != NULL) {
! 		char *eptr;
! 		u_long val;
! 
! 		val = strtoul(s + 1, &eptr, 10);
! 		if (eptr == s + 1 || *eptr || val > MAX_MAXCHLD) {
! 			syslog(LOG_ERR,
! 				"%s: bad max-child for service %s",
! 				CONFIG, sep->se_service);
! 			goto more;
! 		}
! 		sep->se_maxchild = val;
! 	}
  	if (ISMUX(sep)) {
  		/*
! 		 * Silently enforce "wait" mode for TCPMUX services
! 		 * since they don't have an assigned port to listen on.
  		 */
! 		sep->se_accept = 1;
  		if (strcmp(sep->se_proto, "tcp")) {
  			syslog(LOG_ERR,
  				"%s: bad protocol for tcpmux service %s",
***************
*** 994,1007 ****
  				sep->se_service);
  			goto more;
  		}
  		sep->se_bi = bi;
- 		sep->se_wait = bi->bi_wait;
  	} else
  		sep->se_bi = NULL;
  	argc = 0;
  	for (arg = skip(&cp); cp; arg = skip(&cp))
! 		if (argc < MAXARGV)
  			sep->se_argv[argc++] = newstr(arg);
  	while (argc <= MAXARGV)
  		sep->se_argv[argc++] = NULL;
  	return (sep);
--- 1124,1155 ----
  				sep->se_service);
  			goto more;
  		}
+ 		sep->se_accept = 1;	/* force accept mode for built-ins */
  		sep->se_bi = bi;
  	} else
  		sep->se_bi = NULL;
+ 	if (sep->se_maxchild < 0)	/* apply default max-children */
+ 		if (sep->se_bi)
+ 			sep->se_maxchild = sep->se_bi->bi_maxchild;
+ 		else
+ 			sep->se_maxchild = sep->se_accept ? 0 : 1;
+ 	if (sep->se_maxchild) {
+ 		sep->se_pids = malloc(sep->se_maxchild * sizeof(*sep->se_pids));
+ 		if (sep->se_pids == NULL) {
+ 			syslog(LOG_ERR, "Out of memory.");
+ 			exit(EX_OSERR);
+ 		}
+ 	}
  	argc = 0;
  	for (arg = skip(&cp); cp; arg = skip(&cp))
! 		if (argc < MAXARGV) {
  			sep->se_argv[argc++] = newstr(arg);
+ 		} else {
+ 			syslog(LOG_ERR,
+ 				"%s: too many arguments for service %s",
+ 				CONFIG, sep->se_service);
+ 			goto more;
+ 		}
  	while (argc <= MAXARGV)
  		sep->se_argv[argc++] = NULL;
  	return (sep);
***************
*** 1021,1026 ****
--- 1169,1176 ----
  		free(cp->se_user);
  	if (cp->se_server)
  		free(cp->se_server);
+ 	if (cp->se_pids)
+ 		free(cp->se_pids);
  	for (i = 0; i < MAXARGV; i++)
  		if (cp->se_argv[i])
  			free(cp->se_argv[i]);
***************
*** 1040,1046 ****
  	cp = skip(cpp);
  	if (cp == NULL) {
  		syslog(LOG_ERR, "%s: syntax error", CONFIG);
! 		exit(-1);
  	}
  	return (cp);
  }
--- 1190,1196 ----
  	cp = skip(cpp);
  	if (cp == NULL) {
  		syslog(LOG_ERR, "%s: syntax error", CONFIG);
! 		exit(EX_DATAERR);
  	}
  	return (cp);
  }
***************
*** 1062,1068 ****
  		c = getc(fconfig);
  		(void) ungetc(c, fconfig);
  		if (c == ' ' || c == '\t')
! 			if (cp = nextline(fconfig))
  				goto again;
  		*cpp = (char *)0;
  		return ((char *)0);
--- 1212,1218 ----
  		c = getc(fconfig);
  		(void) ungetc(c, fconfig);
  		if (c == ' ' || c == '\t')
! 			if ((cp = nextline(fconfig)))
  				goto again;
  		*cpp = (char *)0;
  		return ((char *)0);
***************
*** 1100,1109 ****
  newstr(cp)
  	char *cp;
  {
! 	if (cp = strdup(cp ? cp : ""))
  		return (cp);
  	syslog(LOG_ERR, "strdup: %m");
! 	exit(-1);
  }
  
  #ifdef OLD_SETPROCTITLE
--- 1250,1259 ----
  newstr(cp)
  	char *cp;
  {
! 	if ((cp = strdup(cp ? cp : "")))
  		return (cp);
  	syslog(LOG_ERR, "strdup: %m");
! 	exit(EX_OSERR);
  }
  
  #ifdef OLD_SETPROCTITLE
***************
*** 1439,1456 ****
  	char *action;
  	struct servtab *sep;
  {
! 	if(sep->se_rpc)
! 		fprintf(stderr,
! 	    		"%s: %s proto=%s, wait=%d, user=%s builtin=%x server=%s\n",
! 	    		action, sep->se_service, sep->se_proto,
! 	    		sep->se_wait, sep->se_user, (int)sep->se_bi,
! 			sep->se_server);
! 	else
! 		fprintf(stderr,
! 			"%s: %s proto=%s, wait=%d, user=%s builtin=%x server=%s\n",
! 			action, sep->se_service, sep->se_proto,
! 			sep->se_wait, sep->se_user, (int)sep->se_bi,
! 			sep->se_server);
  }
  
  /*
--- 1589,1599 ----
  	char *action;
  	struct servtab *sep;
  {
! 	fprintf(stderr,
! 	    "%s: %s proto=%s accept=%d max=%d user=%s builtin=%x server=%s\n",
! 	    action, sep->se_service, sep->se_proto,
! 	    sep->se_accept, sep->se_maxchild, sep->se_user,
! 	    (int)sep->se_bi, sep->se_server);
  }
  
  /*

--------------FF6D5DF3F54BC7E1CFBAE39--




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?327E8DDA.59E2B600>