[comp.sources.unix] v23i009: Deliver 2.0 patches, Part09/10

rsalz@bbn.com (Rich Salz) (08/31/90)

Submitted-by: Chip Salzenberg <tct!chip@uunet.uu.net>
Posting-number: Volume 23, Issue 9
Archive-name: deliver2.0pch/part09

Changes in patch #10 to Deliver 2.0:

1.  UUCP delivery now combines destinations into a single "uux" if
    their bang paths share a common first hop.  A few configuration
    items have been added to config.h to support this feature.

2.  Kernel record locking on mailbox files now unlocks files when done
    with them.  Ever since version 1.0 PL0, Deliver was supposed to
    release record locks, but somehow I mistyped the original code and
    the error survived until now.  It never showed up before because
    close() automatically releases record locks.

3.  Date parsing is more robust.  Thanks to G. Paul Ziemba for the
    fixes to unctime.y.

4.  Support for nap() under ABCenix.  Thanks to Goran Larsson for
    information on this most wonderfully obscure OS.  :-)

This patch contains changes to the following files:
	patchlevel.h
	Makefile
	config.h
	lock.c
	log.c
	sysdep.c
	unctime.y
	uucp.c

Index: patchlevel.h
Prereq: 9
***************
*** 1,1 ****
! #define PATCHLEVEL 9
--- 1,1 ----
! #define PATCHLEVEL 10

Index: Makefile
***************
*** 1,3 ****
! # $Header: Makefile,v 2.6 90/03/06 12:15:39 chip Exp $
  #
  # Makefile for deliver
--- 1,3 ----
! # $Header: Makefile,v 2.7 90/05/09 12:26:11 chip Exp $
  #
  # Makefile for deliver
***************
*** 45,48 ****
--- 45,51 ----
  #       with "-lx".  SCO Xenix System V needs it; Altos Xenix doesn't.
  #
+ # LINT
+ #	Your favorite lint program, with flags.
+ #
  # BIN
  #       Target directory for installation; /usr/bin is recommended.
***************
*** 62,65 ****
--- 65,69 ----
  LDFLAGS = -i
  LIBS = -lx
+ LINT = lint -x
  BIN =   /usr/bin
  DELSHAR =  deliver.sh
***************
*** 180,190 ****
  
  deliver.lint: $(HDRS) $(DELSRCC) $(COMSRCS)
! 	lint $(DELSRCC) $(COMSRCS) -lc $(LIBS) >$@
  
  header.lint: $(HDRSRCS) $(COMSRCS)
! 	lint $(HDRSRCS) $(COMSRCS) -lc $(LIBS) >$@
  
  uid.lint: config.h $(UIDSRCS) $(COMSRCS)
! 	lint $(UIDSRCS) $(COMSRCS) -lc $(LIBS) >$@
  
  clean::
--- 184,194 ----
  
  deliver.lint: $(HDRS) $(DELSRCC) $(COMSRCS)
! 	$(LINT) $(DELSRCC) $(COMSRCS) $(LIBS) >$@
  
  header.lint: $(HDRSRCS) $(COMSRCS)
! 	$(LINT) $(HDRSRCS) $(COMSRCS) $(LIBS) >$@
  
  uid.lint: config.h $(UIDSRCS) $(COMSRCS)
! 	$(LINT) $(UIDSRCS) $(COMSRCS) $(LIBS) >$@
  
  clean::

Index: config.h
***************
*** 1,3 ****
! /* $Header: config.h,v 2.9 90/03/06 12:21:08 chip Exp $
   *
   * Deliver configuration.
--- 1,3 ----
! /* $Header: config.h,v 2.10 90/05/03 10:28:48 chip Exp $
   *
   * Deliver configuration.
***************
*** 4,7 ****
--- 4,10 ----
   *
   * $Log:	config.h,v $
+  * Revision 2.10  90/05/03  10:28:48  chip
+  * Add UUCP configuration.
+  * 
   * Revision 2.9  90/03/06  12:21:08  chip
   * Move logging into log.c and address parsing into addr.c.
***************
*** 209,212 ****
--- 212,229 ----
  #define HAS_GETOPT
  #endif
+ 
+ /*----------------------------------------------------------------------
+  * UUCP configuration.
+  *
+  * UUCP_NAMESIZE        Maximum size of a UUCP system name.
+  * UUX_OPTS             Options for uux; "-r" means queue but don't call.
+  * UUX_ARGCOUNT         Maximum count of arguments for uux.
+  * UUX_ARGSIZE          Maximum total size of arguments for uux.
+  */
+ 
+ #define UUCP_NAMESIZE 16
+ #define UUX_OPTS      "-r"
+ #define UUX_ARGCOUNT  16
+ #define UUX_ARGSIZE   512
  
  /*----------------------------------------------------------------------

Index: lock.c
***************
*** 1,3 ****
! /* $Header: lock.c,v 2.1 89/06/09 12:25:30 network Exp $
   *
   * Mailbox locking.
--- 1,3 ----
! /* $Header: lock.c,v 2.2 90/05/03 10:13:56 chip Exp $
   *
   * Mailbox locking.
***************
*** 5,8 ****
--- 5,11 ----
   *
   * $Log:	lock.c,v $
+  * Revision 2.2  90/05/03  10:13:56  chip
+  * Really unlock file descriptors in fd_unlock().  (!)
+  * 
   * Revision 2.1  89/06/09  12:25:30  network
   * Update RCS revisions.
***************
*** 42,46 ****
  #define SIMPLE_LOCK "locking"
  #define LOCKFD(fd, size)    locking(fd, LK_LOCK, size)
! #define UNLOCKFD(fd, size)  locking(fd, LK_UNLOCK, size)
  #endif
  
--- 45,49 ----
  #define SIMPLE_LOCK "locking"
  #define LOCKFD(fd, size)    locking(fd, LK_LOCK, size)
! #define UNLOCKFD(fd, size)  locking(fd, LK_UNLCK, size)
  #endif
  
***************
*** 214,218 ****
  		return -1;
  	}
! 	if (LOCKFD(fd, 0L) == -1)
  	{
  		syserr("can't unlock with %s()", SIMPLE_LOCK);
--- 217,221 ----
  		return -1;
  	}
! 	if (UNLOCKFD(fd, 0L) == -1)
  	{
  		syserr("can't unlock with %s()", SIMPLE_LOCK);

Index: log.c
***************
*** 1,3 ****
! /* $Header: log.c,v 2.2 90/03/05 17:54:53 chip Exp $
   *
   * Deliver logging.
--- 1,3 ----
! /* $Header: log.c,v 2.3 90/05/03 10:13:31 chip Exp $
   *
   * Deliver logging.
***************
*** 4,7 ****
--- 4,10 ----
   *
   * $Log:	log.c,v $
+  * Revision 2.3  90/05/03  10:13:31  chip
+  * Print correct filename when log can't be opened.
+  * 
   * Revision 2.2  90/03/05  17:54:53  chip
   * Create log.c from various routines throughout the code.
***************
*** 200,204 ****
  #endif
  	if (realfd == -1)
! 		syserr("can't open %s for writing", logfile);
  	else
  	{
--- 203,207 ----
  #endif
  	if (realfd == -1)
! 		syserr("can't open %s for writing", realfile);
  	else
  	{

Index: sysdep.c
***************
*** 1,3 ****
! /* $Header: sysdep.c,v 2.8 90/03/06 12:21:16 chip Exp $
   *
   * Routines which are (or might well be) system-dependant.
--- 1,3 ----
! /* $Header: sysdep.c,v 2.9 90/05/03 10:13:06 chip Exp $
   *
   * Routines which are (or might well be) system-dependant.
***************
*** 6,9 ****
--- 6,12 ----
   *
   * $Log:	sysdep.c,v $
+  * Revision 2.9  90/05/03  10:13:06  chip
+  * Support nap() call in ABCenix.  (Huh?)
+  * 
   * Revision 2.8  90/03/06  12:21:16  chip
   * Move logging into log.c and address parsing into addr.c.
***************
*** 71,75 ****
   */
  
! #ifdef M_XENIX
  extern  long    nap();
  #else
--- 74,82 ----
   */
  
! #if defined(M_XENIX) || defined(ABCenix)
! #define CALL_NAP
! #endif
! 
! #ifdef CALL_NAP
  extern  long    nap();
  #else
***************
*** 197,201 ****
  int     n;
  {
! #ifdef M_XENIX
  	(void) nap(n * 1000L);
  #else
--- 204,208 ----
  int     n;
  {
! #ifdef CALL_NAP
  	(void) nap(n * 1000L);
  #else

Index: unctime.y
***************
*** 1,4 ****
  /*
!  * $Header: unctime.y,v 2.4 89/12/19 16:29:49 network Exp $
   *
   * Conversion of ctime-style date string back to a time_t.
--- 1,4 ----
  /*
!  * $Header: unctime.y,v 2.5 90/05/09 12:25:10 chip Exp $
   *
   * Conversion of ctime-style date string back to a time_t.
***************
*** 7,10 ****
--- 7,14 ----
   *
   * $Log:	unctime.y,v $
+  * Revision 2.5  90/05/09  12:25:10  chip
+  * Use isxxx() and toxxx() portably.  Test for exact match on timezone
+  * names.  Terminate token strings properly.  [From G. Paul Ziemba]
+  * 
   * Revision 2.4  89/12/19  16:29:49  network
   * Make timezone handling portable to System V.
***************
*** 117,129 ****
  %%
  
! /* Return true if s is a prefix of t; e.g. prefix("mar", "march") = true.
     Note that comparison is case-insensitive. */
  static
! prefix(s,t)
       char *s, *t;
  {
!   while (*s && *t && tolower(*s) == tolower(*t))
!     s++, t++;
!   return *s == 0;
  }
  
--- 121,149 ----
  %%
  
! /* Return 0 if s is the same word as t.
!    Return 1 if s is a prefix of t; e.g. prefix("mar", "march") returns 1.
!    Return -1 if s is not a prefix of t.
     Note that comparison is case-insensitive. */
  static
! wordeq(s,t)
       char *s, *t;
  {
!   while (*s && *t)
!     {
!       int i, j;
! 
!       i = *s++;
!       j = *t++;
!       if (isascii(i) && isupper(i))
! 	i = tolower(i);
!       if (isascii(j) && isupper(j))
! 	j = tolower(j);
!       if (i != j)
! 	return -1;
!     }
! 
!   if (*s)
!     return -1;
!   return (*t == 0);
  }
  
***************
*** 217,231 ****
    for (;;)
      {
!       while (isspace(*lexptr))
  	lexptr++;
        if (*lexptr == 0)
  	return 0;
!       else if (isalpha(*lexptr))
  	{
  	  i = 0;
! 	  while (isalpha(*lexptr))
! 	    token[i++] = *lexptr++;	/* Null termination is automatic. */
  	  for (i = 0; months[i]; i++)
! 	    if (prefix(months[i],token))
  	      {
  		yylval = i + 1;
--- 237,252 ----
    for (;;)
      {
!       while (isascii(*lexptr) && isspace(*lexptr))
  	lexptr++;
        if (*lexptr == 0)
  	return 0;
!       else if (isascii(*lexptr) && isalpha(*lexptr))
  	{
  	  i = 0;
! 	  while (isascii(*lexptr) && isalpha(*lexptr))
! 	    token[i++] = *lexptr++;
! 	  token[i] = '\0';
  	  for (i = 0; months[i]; i++)
! 	    if (wordeq(months[i],token) >= 0)
  	      {
  		yylval = i + 1;
***************
*** 233,237 ****
  	      }
  	  for (i = 0; zones[i].name; i++)
! 	    if (prefix(zones[i].name,token))
  	      {
  		int oper, next;
--- 254,258 ----
  	      }
  	  for (i = 0; zones[i].name; i++)
! 	    if (wordeq(zones[i].name,token) == 0)
  	      {
  		int oper, next;
***************
*** 258,271 ****
  		  return oper;
  	      }
! 	  if (prefix("pm",token) || prefix("p.m.", token))
  	    return PM;
! 	  if (prefix("am",token) || prefix("a.m.", token))
  	    return AM;
  	  continue;
  	}
!       else if (isdigit(*lexptr))
  	{
  	  i = 0;
! 	  while (isdigit(*lexptr))
  	    token[i++] = *lexptr++;
  	  token[i] = '\0';
--- 279,292 ----
  		  return oper;
  	      }
! 	  if (wordeq("pm",token) == 0 || wordeq("p.m.", token) == 0)
  	    return PM;
! 	  if (wordeq("am",token) == 0 || wordeq("a.m.", token) == 0)
  	    return AM;
  	  continue;
  	}
!       else if (isascii(*lexptr) && isdigit(*lexptr))
  	{
  	  i = 0;
! 	  while (isascii(*lexptr) && isdigit(*lexptr))
  	    token[i++] = *lexptr++;
  	  token[i] = '\0';
***************
*** 496,500 ****
  
    /* If garbage beyond valid date, that's an error. */
!   while (*lexptr && isspace(*lexptr))
      ++lexptr;
    if (*lexptr)
--- 517,521 ----
  
    /* If garbage beyond valid date, that's an error. */
!   while (isascii(*lexptr) && isspace(*lexptr))
      ++lexptr;
    if (*lexptr)

Index: uucp.c
***************
*** 1,3 ****
! /* $Header: uucp.c,v 2.4 90/02/23 14:16:54 chip Exp $
   *
   * Handle mail destined for other hosts via UUCP.
--- 1,3 ----
! /* $Header: uucp.c,v 2.6 90/05/03 10:35:51 chip Exp $
   *
   * Handle mail destined for other hosts via UUCP.
***************
*** 6,9 ****
--- 6,15 ----
   *
   * $Log:	uucp.c,v $
+  * Revision 2.6  90/05/03  10:35:51  chip
+  * Quiet lint.
+  * 
+  * Revision 2.5  90/05/03  10:26:21  chip
+  * Combine destinations with a common first hop.
+  * 
   * Revision 2.4  90/02/23  14:16:54  chip
   * Support "#!" in delivery files.
***************
*** 33,36 ****
--- 39,43 ----
   */
  
+ static	char	*find_uux();
  static  int     uucp_copy();
  
***************
*** 38,42 ****
   * Send mail to UUCP addresses (if any).
   * Return count of UUCP addresses for which delivery was attempted.
-  * This is a simple implementation: invoke uux once per address.
   */
  
--- 45,48 ----
***************
*** 45,71 ****
  {
  	DEST    *d;
  	char    *uux;
  	int	uucpcount;
- 	static char uux1[] = "/bin/uux";
- 	static char uux2[] = "/usr/bin/uux";
  
! 	if (exists(uux1))
! 		uux = uux1;
! 	else if (exists(uux2))
! 		uux = uux2;
! 	else
! 	{
! 		error("can't find uux!?\n");
  		return -1;
! 	}
  
  	uucpcount = 0;
  	for (d = first_dest(); d; d = next_dest(d))
  	{
  		FILE    *uux_fp;
! 		char    *bang;
! 		char    *av[5];
! 		char    rmail[40];
! 		char    who[BUFSIZ];
  
  		if (d->d_class != CL_UUCP || d->d_state != ST_WORKING)
--- 51,91 ----
  {
  	DEST    *d;
+ 	char    *uav[UUX_ARGCOUNT + 8];     /* arguments for execv() */
+ 	char	**av;			    /* remote addresses in uav[] */
+ 	DEST	*dv[UUX_ARGCOUNT];	    /* destinations in av[] */
+ 	char    rmail[UUCP_NAMESIZE + 8];   /* "sysname!rmail" */
  	char    *uux;
  	int	uucpcount;
  
! 	if ((uux = find_uux()) == NULL)
  		return -1;
! 
! 	av = uav;
! 	*av++ = "uux";
! #ifdef UUX_OPTS
! 	*av++ = UUX_OPTS;
! #endif
! 	*av++ = "-";
! 	*av++ = rmail;
! 
! 	/*
! 	 * Look for a UUCP address that is "working".  If we find one,
! 	 * then we scan the rest of the list for other UUCP addresses
! 	 * that begin with the same first hop.  If we find any, then
! 	 * we handle them too.  Note that as we continue scanning,
! 	 * we'll find those same addresses again; that's okay, though,
! 	 * because their status fields will report that they're
! 	 * already done.  Cool, eh?
! 	 */
  
  	uucpcount = 0;
+ 
  	for (d = first_dest(); d; d = next_dest(d))
  	{
  		FILE    *uux_fp;
! 		DEST	*ud;
! 		DERROR	e;
! 		char	*bang;
! 		int	namesize, argcount, argsize, problem, a;
  
  		if (d->d_class != CL_UUCP || d->d_state != ST_WORKING)
***************
*** 83,113 ****
  		}
  
! 		bang = strchr(d->d_name, '!');
! 		*bang = 0;
! 		(void) sprintf(rmail, "%s!rmail", d->d_name);
! 		*bang++ = '!';
! 		(void) sprintf(who, "(%s)", bang);
! 
! 		av[0] = "uux";
! 		av[1] = "-";
! 		av[2] = rmail;
! 		av[3] = who;
! 		av[4] = NULL;
! 		if ((uux_fp = ct_fopenv(real_ct, uux, av, "w")) == NULL)
  			continue;
  
! 		if (uucp_copy(uux_fp) < 0)
! 			dest_err(d, E_PIPE);
  
! 		if (ct_fclose(uux_fp))
  		{
! 			/* "No such host" overrides piping problems. */
! 			dest_err(d, E_NSHOST);
  		}
  		else
! 			d->d_state = ST_DONE;
  	}
  
  	return uucpcount;
  }
  
--- 103,238 ----
  		}
  
! 		/*
! 		 * This is the first destination with the given system
! 		 * as the first hop.  Generate the rmail command.
! 		 */
! 
! 		if ((bang = strchr(d->d_name, '!')) == NULL
! 		 || (namesize = bang - d->d_name) > UUCP_NAMESIZE)
! 		{
! 			dest_err(d, E_NSHOST);
  			continue;
+ 		}
  
! 		(void) strncpy(rmail, d->d_name, namesize);
! 		(void) strcpy(rmail + namesize, "!rmail");
  
! 		/*
! 		 * Now keep looking for addresses until a limit is reached,
! 		 * either max arguments or max argument size.
! 		 * We'll find them again, but their statuses will prevent us
! 		 * from trying to mail to them twice.
! 		 */
! 
! 		argcount = 0;
! 		argsize = 0;
! 		for (ud = d; ud; ud = next_dest(ud))
  		{
! 			char *rest, *arg;
! 
! 			if (ud->d_class != CL_UUCP
! 			 || ud->d_state != ST_WORKING)
! 				continue;
! 
! 			if (strncmp(ud->d_name, d->d_name, namesize + 1) != 0)
! 				continue;
! 
! 			/*
! 			 * We have a match!  (Or, it could be the first one.)
! 			 * Be sure we don't exceed our configured maxima,
! 			 * except for the first address, which always goes.
! 			 */
! 
! 			rest = ud->d_name + namesize + 1;
! 
! 			if (argcount > 0)
! 			{
! 				if (argcount + 1 > UUX_ARGCOUNT
! 				 || argsize + strlen(rest) + 2 > UUX_ARGSIZE)
! 					break;
! 			}
! 
! 			/*
! 			 * Generate a uux argument and save the destination.
! 			 */
! 
! 			arg = zalloc((unsigned) 3 + strlen(rest));
! 			(void) sprintf(arg, "(%s)", rest);
! 
! 			av[argcount] = arg;
! 			dv[argcount] = ud;
! 
! 			/*
! 			 * Keep track of arg count and total size.
! 			 */
! 
! 			++argcount;
! 			argsize += strlen(arg);
  		}
+ 
+ 		av[argcount] = NULL;
+ 
+ 		/*
+ 		 * Do the dirty deed.
+ 		 * We have to remember the error code as a variable,
+ 		 * since it may apply to multiple destinations.
+ 		 */
+ 
+ 		problem = 0;
+ 		e = E_PIPE;	/* default error */
+ 
+ 		if ((uux_fp = ct_fopenv(real_ct, uux, uav, "w")) == NULL)
+ 			problem = 1;
  		else
! 		{
! 			if (uucp_copy(uux_fp) < 0)
! 				problem = 1;
! 
! 			if (ct_fclose(uux_fp))
! 			{
! 				/* "No such host" overrides piping problems. */
! 				e = E_NSHOST;
! 				problem = 1;
! 			}
! 		}
! 
! 		/*
! 		 * We're done.  Update each destination's status.
! 		 */
! 
! 		for (a = 0; a < argcount; ++a)
! 		{
! 			free(av[a]);
! 
! 			if (problem)
! 				dest_err(dv[a], e);
! 			else
! 				dv[a]->d_state = ST_DONE;
! 		}
! 
! 		/* Track the correct count of UUCP addresses found. */
! 
! 		uucpcount += argcount - 1;
  	}
  
  	return uucpcount;
+ }
+ 
+ /*----------------------------------------------------------------------
+  * Where is uux?
+  */
+ 
+ static char *
+ find_uux()
+ {
+ 	static char uux1[] = "/bin/uux";
+ 	static char uux2[] = "/usr/bin/uux";
+ 
+ 	if (exists(uux1))
+ 		return uux1;
+ 	if (exists(uux2))
+ 		return uux2;
+ 	error("can't find uux!?\n");
+ 	return NULL;
  }
  
-- 
Chip Salzenberg at ComDev/TCT     <chip@tct.uucp>, <uunet!ateng!tct!chip>


exit 0 # Just in case...
-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.