home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #26 / NN_1992_26.iso / spool / comp / mail / sendmail / 2742 < prev    next >
Encoding:
Text File  |  1992-11-12  |  3.5 KB  |  108 lines

  1. Newsgroups: comp.mail.sendmail
  2. Path: sparky!uunet!cs.utexas.edu!uwm.edu!ux1.cso.uiuc.edu!news.cso.uiuc.edu!uxc.cso.uiuc.edu!paul
  3. From: paul@uxc.cso.uiuc.edu (Paul Pomes - UofIllinois CSO)
  4. Subject: Re: file locking after forks in sendmail 5.65
  5. References: <1666@seqp4.sequoia.com>
  6. Message-ID: <BxKw9D.MqJ@news.cso.uiuc.edu>
  7. Sender: usenet@news.cso.uiuc.edu (Net Noise owner)
  8. Reply-To: Paul-Pomes@uiuc.edu
  9. Organization: University of Illinois at Urbana
  10. Date: Thu, 12 Nov 1992 01:03:11 GMT
  11. Keywords: locking files in 5.65
  12. Lines: 94
  13.  
  14. ajm@seqp4.sequoia.com (A.J.Madison) writes:
  15.  
  16. >I ran into a problem of recipients complaining of receiving 2 copies of the
  17. >same mail.  Careful examination of the headers and the syslogs led me to
  18. >conclude that if a user had the misfortune of sending mail at the very
  19. >instant the system's sendmail daemon woke up to check the queue, the mail
  20. >would end up getting delivered twice.
  21. >
  22. >After reproducing the problem on a test machine, I realized that locking on
  23. >queue files in the spool directory was not working on our system.  We're
  24. >SVR3.2 on the outside and fault tolerant & proprietary on the inside (which
  25. >leaves the possibility the OS folks blew it).
  26.  
  27. You've nailed the problem square on the head.  In adapting the original IDA
  28. sendmail to the plethora of platforms around the University, I've seen every
  29. variant of the locking problem.  First there's the shock of discovering that
  30. BSD flock() has differing semantics depending in the vendor.  If the OS is
  31. derived from BSD, locks are inherited across fork().  If the OS comes from
  32. the other side of the fence, they're not.
  33.  
  34. Non-inheritable flock()s are generally implemented as wrappers around fcntl().
  35. fcntl() locks also require that a file be opened for writing to obtain an
  36. exclusive lock.
  37.  
  38. For non-inheritable locks my fix has been to release the lock just before
  39. the fork() and to re-lock immediately in the child.  If the lock fails
  40. the child assumes a daemon process got the file during the window of
  41. vulnerability and exits.
  42.  
  43. I use a replacement flock() routine written by Mark Davies and Andy Linton
  44. (hi!) of the Victoria University of Wellington for those systems that lack
  45. a BSD flock().  It uses either fcntl() or lockf().
  46.  
  47. From sendall() in deliver.c:
  48.  
  49.  
  50.       case SM_FORK:
  51.         if (e->e_xfp != NULL)
  52.             (void) fflush(e->e_xfp);
  53.  
  54. #if defined(FCNTL_FLOCK) || defined(LOCKF_FLOCK)
  55.         /*
  56.         ** lockf()/fcntl() emulation of flock() breaks down here as
  57.         ** locks are not inherited across fork().  release lock so
  58.         ** child can re-lock.
  59.         **/
  60.         if (lockfp != NULL)
  61.             (void) flock(fileno(lockfp), LOCK_UN);
  62. #endif /* (FCNTL_FLOCK) || (LOCKF_FLOCK) */
  63.         pid = fork();
  64.         if (pid > 0 && tTd(4, 2))
  65.             printf("sendall: forking (pid = %d)\n", pid);
  66.         if (pid < 0)
  67.         {
  68.             mode = SM_DELIVER;
  69.             break;
  70.         }
  71.         else if (pid > 0)
  72.         {
  73.             /* be sure we leave the temp files to our child */
  74.             e->e_id = e->e_df = NULL;
  75.             if (lockfp != NULL)
  76.                 (void) fclose(lockfp);
  77.             return;
  78.         }
  79.  
  80.         /* double fork to avoid zombies */
  81.         if (fork() > 0)
  82.             exit(EX_OK);
  83.  
  84. #if defined(FCNTL_FLOCK) || defined(LOCKF_FLOCK) 
  85.         /*
  86.         ** re-lock tf file in child (again for flock() as lockf())
  87.         */
  88.         if (lockfp != NULL && flock(fileno(lockfp), LOCK_EX|LOCK_NB) <0)
  89.         {
  90.             /* someone else got in before us */
  91.             e->e_id = NULL;
  92.             (void) fclose(lockfp);
  93.             finis();
  94.         }
  95. #endif /* (FCNTL_FLOCK) || (LOCKF_FLOCK) */
  96.  
  97.         /* be sure we are immune from the terminal */
  98.         disconnect(FALSE);
  99.  
  100.         break;
  101.     }
  102.  
  103. /pbp
  104. -- 
  105. "A well-schooled electorate, being necessary to the security of a free State,
  106. the right of the People to keep and read Books shall not be infringed."
  107.     -- J. Neil Schulman
  108.