From owner-freebsd-stable Thu Jan 7 23:41:35 1999 Return-Path: Received: (from majordom@localhost) by hub.freebsd.org (8.8.8/8.8.8) id XAA17326 for freebsd-stable-outgoing; Thu, 7 Jan 1999 23:41:35 -0800 (PST) (envelope-from owner-freebsd-stable@FreeBSD.ORG) Received: from picasso.wcape.school.za (picasso.wcape.school.za [196.21.102.12]) by hub.freebsd.org (8.8.8/8.8.8) with ESMTP id XAA17315 for ; Thu, 7 Jan 1999 23:41:29 -0800 (PST) (envelope-from pvh@leftside.wcape.school.za) Received: from uucp by picasso.wcape.school.za with local-rmail (Exim 2.05 #1) id 0zyWXQ-0002PM-00 for freebsd-stable@freebsd.org; Fri, 8 Jan 1999 09:40:56 +0200 Received: from localhost (pvh@localhost) by leftside.wcape.school.za (8.8.8/8.8.4) with SMTP id HAA14544 for ; Fri, 8 Jan 1999 07:42:24 +0200 (SAT) Date: Fri, 8 Jan 1999 07:42:23 +0200 (SAT) From: Peter van Heusden To: freebsd-stable@FreeBSD.ORG Subject: Patch for inetd.c in realloc() problem Message-ID: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII Sender: owner-freebsd-stable@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.ORG I have made a version of Graham Wheeler's inetd patch which fixes signal handling in inetd. This prevents the 'inetd in realloc(): warning: junk pointer, too low to make sense'. The patch is basically a slightly modified version of the same patch applied to -CURRENT. Unfortunately, however, I don't use inetd particularly heavily. I would appreciate it if someone who does use inetd heavily could apply the patch and check that there are no adverse effects. Here's the patch - it must be applied to the latest version of inetd.c (rev 1.15.2.11): Peter --- inetd.c-REALSTABLE Thu Jan 7 08:25:11 1999 +++ inetd.c Thu Jan 7 08:49:23 1999 @@ -42,7 +42,7 @@ static char sccsid[] = "@(#)from: inetd.c 8.4 (Berkeley) 4/13/94"; #endif static const char rcsid[] = - "$Id: inetd.c,v 1.15.2.11 1998/12/16 00:00:12 dillon Exp $"; + "$Id: inetd.c,v 1.15.2.12 1998/12/16 00:00:12 dillon Exp $"; #endif /* not lint */ /* @@ -172,6 +172,7 @@ struct servent *sp; struct rpcent *rpc; struct in_addr bind_address; +int signalpipe[2]; struct servtab { char *se_service; /* name of service */ @@ -217,7 +218,9 @@ void chargen_dg __P((int, struct servtab *)); void chargen_stream __P((int, struct servtab *)); void close_sep __P((struct servtab *)); -void config __P((int)); +void flag_signal __P((char)); +void flag_config __P((int)); +void config __P((void)); void daytime_dg __P((int, struct servtab *)); void daytime_stream __P((int, struct servtab *)); void discard_dg __P((int, struct servtab *)); @@ -234,10 +237,12 @@ char *nextline __P((FILE *)); void print_service __P((char *, struct servtab *)); void addchild __P((struct servtab *, int)); -void reapchild __P((int)); +void flag_reapchild __P((int)); +void reapchild __P((void)); void enable __P((struct servtab *)); void disable __P((struct servtab *)); -void retry __P((int)); +void flag_retry __P((int)); +void retry __P((void)); int setconfig __P((void)); void setup __P((struct servtab *)); char *sskip __P((char **)); @@ -408,12 +413,12 @@ sigaddset(&sa.sa_mask, SIGALRM); sigaddset(&sa.sa_mask, SIGCHLD); sigaddset(&sa.sa_mask, SIGHUP); - sa.sa_handler = retry; + sa.sa_handler = flag_retry; sigaction(SIGALRM, &sa, (struct sigaction *)0); - config(SIGHUP); - sa.sa_handler = config; + config(); + sa.sa_handler = flag_config; sigaction(SIGHUP, &sa, (struct sigaction *)0); - sa.sa_handler = reapchild; + sa.sa_handler = flag_reapchild; sigaction(SIGCHLD, &sa, (struct sigaction *)0); sa.sa_handler = SIG_IGN; sigaction(SIGPIPE, &sa, &sapipe); @@ -428,47 +433,69 @@ (void)setenv("inetd_dummy", dummy, 1); } - (void) sigblock(SIGBLOCK); + if (pipe(signalpipe) != 0) + { + syslog(LOG_ERR, "pipe: %%m"); + exit(EX_OSERR); + } + FD_SET(signalpipe[0], &allsock); + if (signalpipe[0]>maxsock) maxsock = signalpipe[0]; for (;;) { int n, ctrl; fd_set readable; - struct timeval tv = { 5, 0 }; - - /* - * Handle signal masking and select. Signals are unmasked and - * we pause if we have no active descriptors. If we do have - * active descriptors, leave signals unmasked through the select() - * call. The select() call is inclusive of a timeout in order - * to handle the race condition where a signal occurs just prior - * to the select() call and potentially changes the allsock - * fd_set, to prevent select() from potentially blocking forever. - * - * Signals are masked at all other times. - */ if (nsock == 0) { + (void) sigblock(SIGBLOCK); while (nsock == 0) sigpause(0L); + (void) sigsetmask(0L); } - - (void) sigsetmask(0L); - - readable = allsock; - errno = 0; - n = select(maxsock + 1, &readable, NULL, NULL, &tv); - - (void) sigblock(SIGBLOCK); - - if (n <= 0) { - if (n < 0 && errno && errno != EINTR) { + if ((n = select(maxsock + 1, &readable, (fd_set *)0, + (fd_set *)0, (struct timeval *)0)) <= 0) { + if (n < 0 && errno != EINTR) { syslog(LOG_WARNING, "select: %m"); sleep(1); } continue; } + /* handle any queued signal flags */ + if (FD_ISSET(signalpipe[0], &readable)) + { + int n; + if (ioctl(signalpipe[0], FIONREAD, &n) == 0) + { + while (--n >= 0) + { + char c; + if (read(signalpipe[0], &c, 1) == 1) + { + if (debug) warnx("Handling signal flag %c", c); + switch(c) + { + case 'A': /* sigalrm */ + retry(); break; + case 'C': /* sigchld */ + reapchild(); break; + case 'H': /* sighup */ + config(); break; + } + } + else + { + syslog(LOG_ERR, "read: %m"); + exit(EX_OSERR); + } + } + } + else + { + syslog(LOG_ERR, "ioctl: %m"); + exit(EX_OSERR); + } + } for (sep = servtab; n && sep; sep = sep->se_next) if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) { n--; @@ -506,7 +533,7 @@ } } else ctrl = sep->se_fd; - /* (void) sigblock(SIGBLOCK); */ + (void) sigblock(SIGBLOCK); pid = 0; dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork); if (dofork) { @@ -527,7 +554,7 @@ "%s/%s server failing (looping), service terminated", sep->se_service, sep->se_proto); close_sep(sep); - /* sigsetmask(0L); */ + sigsetmask(0L); if (!timingout) { timingout = 1; alarm(RETRYTIME); @@ -542,13 +569,13 @@ if (sep->se_accept && sep->se_socktype == SOCK_STREAM) close(ctrl); - /* sigsetmask(0L); */ + sigsetmask(0L); sleep(1); continue; } if (pid) addchild(sep, pid); - /* sigsetmask(0L); */ + sigsetmask(0L); if (pid == 0) { if (dofork) { if (debug) @@ -654,7 +681,6 @@ #endif sigaction(SIGPIPE, &sapipe, (struct sigaction *)0); - (void) sigsetmask(0L); execv(sep->se_server, sep->se_argv); if (sep->se_socktype != SOCK_STREAM) recv(0, buf, sizeof (buf), 0); @@ -670,6 +696,20 @@ } /* + * Add a signal flag to the signal flag queue for later handling + */ + +void flag_signal(c) + char c; +{ + if (write(signalpipe[1], &c, 1) != 1) + { + syslog(LOG_ERR, "write: %m"); + exit(EX_OSERR); + } +} + +/* * Record a new child pid for this service. If we've reached the * limit on children, then stop accepting incoming requests. */ @@ -696,9 +736,15 @@ */ void -reapchild(signo) +flag_reapchild(signo) int signo; { + flag_signal('C'); +} + +void +reapchild() +{ int k, status; pid_t pid; struct servtab *sep; @@ -728,11 +774,16 @@ } void -config(signo) +flag_config(signo) int signo; { + flag_signal('H'); +} + +void config() +{ struct servtab *sep, *new, **sepp; - /* long omask; */ + long omask; if (!setconfig()) { syslog(LOG_ERR, "%s: %m", CONFIG); @@ -770,7 +821,7 @@ int i; #define SWAP(a, b) { typeof(a) c = a; a = b; b = c; } - /* omask = sigblock(SIGBLOCK); */ + omask = sigblock(SIGBLOCK); /* copy over outstanding child pids */ if (sep->se_maxchild && new->se_maxchild) { new->se_numchild = sep->se_numchild; @@ -803,7 +854,7 @@ SWAP(sep->se_server, new->se_server); for (i = 0; i < MAXARGV; i++) SWAP(sep->se_argv[i], new->se_argv[i]); - /* sigsetmask(omask); */ + sigsetmask(omask); freeconfig(new); if (debug) print_service("REDO", sep); @@ -858,7 +909,7 @@ /* * Purge anything not looked at above. */ - /* omask = sigblock(SIGBLOCK); */ + omask = sigblock(SIGBLOCK); sepp = &servtab; while ((sep = *sepp)) { if (sep->se_checked) { @@ -875,7 +926,7 @@ freeconfig(sep); free((char *)sep); } - /* (void) sigsetmask(omask); */ + (void) sigsetmask(omask); } void @@ -884,9 +935,9 @@ { int i; struct servtab *sepp; - /* long omask; */ + long omask; - /* omask = sigblock(SIGBLOCK); */ + omask = sigblock(SIGBLOCK); for (sepp = servtab; sepp; sepp = sepp->se_next) { if (sepp == sep) continue; @@ -903,13 +954,19 @@ if (sep->se_fd != -1) (void) close(sep->se_fd); sep->se_fd = -1; - /* (void) sigsetmask(omask); */ + (void) sigsetmask(omask); } void -retry(signo) +flag_retry(signo) int signo; { + flag_signal('A'); +} + +void +retry() +{ struct servtab *sep; timingout = 0; @@ -1016,7 +1073,7 @@ struct servtab *cp; { struct servtab *sep; - /* long omask; */ + long omask; sep = (struct servtab *)malloc(sizeof (*sep)); if (sep == (struct servtab *)0) { @@ -1025,10 +1082,10 @@ } *sep = *cp; sep->se_fd = -1; - /* omask = sigblock(SIGBLOCK); */ + omask = sigblock(SIGBLOCK); sep->se_next = servtab; servtab = sep; - /* sigsetmask(omask); */ + sigsetmask(omask); return (sep); } @@ -1775,9 +1832,6 @@ /* * Based on TCPMUX.C by Mark K. Lottor November 1988 * sri-nic::ps:tcpmux.c - * - * signals are masked on call, we have to unmask SIGALRM for the - * duration of the read */ @@ -1788,38 +1842,27 @@ int len; { int count = 0, n; - int not_done = 1; struct sigaction sa; - long omask; sa.sa_flags = 0; sigemptyset(&sa.sa_mask); sa.sa_handler = SIG_DFL; sigaction(SIGALRM, &sa, (struct sigaction *)0); - - omask = sigsetmask(SIGBLOCK & ~sigmask(SIGALRM)); - do { alarm(10); n = read(fd, buf, len-count); alarm(0); if (n == 0) - break; - if (n < 0) { - count = -1; - break; - } + return (count); + if (n < 0) + return (-1); while (--n >= 0) { - if (*buf == '\r' || *buf == '\n' || *buf == '\0') { - not_done = 0; - break; - } + if (*buf == '\r' || *buf == '\n' || *buf == '\0') + return (count); count++; buf++; } - } while (not_done && count < len); - - sigsetmask(omask); + } while (count < len); return (count); } -- Peter van Heusden | Its the 90's, and collective action is STILL cool! pvh@leftside.wcape.school.za | Get active in your union today! To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-stable" in the body of the message