home *** CD-ROM | disk | FTP | other *** search
- Newsgroups: comp.mail.sendmail
- Path: sparky!uunet!cs.utexas.edu!uwm.edu!ux1.cso.uiuc.edu!news.cso.uiuc.edu!uxc.cso.uiuc.edu!paul
- From: paul@uxc.cso.uiuc.edu (Paul Pomes - UofIllinois CSO)
- Subject: Re: file locking after forks in sendmail 5.65
- References: <1666@seqp4.sequoia.com>
- Message-ID: <BxKw9D.MqJ@news.cso.uiuc.edu>
- Sender: usenet@news.cso.uiuc.edu (Net Noise owner)
- Reply-To: Paul-Pomes@uiuc.edu
- Organization: University of Illinois at Urbana
- Date: Thu, 12 Nov 1992 01:03:11 GMT
- Keywords: locking files in 5.65
- Lines: 94
-
- ajm@seqp4.sequoia.com (A.J.Madison) writes:
-
- >I ran into a problem of recipients complaining of receiving 2 copies of the
- >same mail. Careful examination of the headers and the syslogs led me to
- >conclude that if a user had the misfortune of sending mail at the very
- >instant the system's sendmail daemon woke up to check the queue, the mail
- >would end up getting delivered twice.
- >
- >After reproducing the problem on a test machine, I realized that locking on
- >queue files in the spool directory was not working on our system. We're
- >SVR3.2 on the outside and fault tolerant & proprietary on the inside (which
- >leaves the possibility the OS folks blew it).
-
- You've nailed the problem square on the head. In adapting the original IDA
- sendmail to the plethora of platforms around the University, I've seen every
- variant of the locking problem. First there's the shock of discovering that
- BSD flock() has differing semantics depending in the vendor. If the OS is
- derived from BSD, locks are inherited across fork(). If the OS comes from
- the other side of the fence, they're not.
-
- Non-inheritable flock()s are generally implemented as wrappers around fcntl().
- fcntl() locks also require that a file be opened for writing to obtain an
- exclusive lock.
-
- For non-inheritable locks my fix has been to release the lock just before
- the fork() and to re-lock immediately in the child. If the lock fails
- the child assumes a daemon process got the file during the window of
- vulnerability and exits.
-
- I use a replacement flock() routine written by Mark Davies and Andy Linton
- (hi!) of the Victoria University of Wellington for those systems that lack
- a BSD flock(). It uses either fcntl() or lockf().
-
- From sendall() in deliver.c:
-
-
- case SM_FORK:
- if (e->e_xfp != NULL)
- (void) fflush(e->e_xfp);
-
- #if defined(FCNTL_FLOCK) || defined(LOCKF_FLOCK)
- /*
- ** lockf()/fcntl() emulation of flock() breaks down here as
- ** locks are not inherited across fork(). release lock so
- ** child can re-lock.
- **/
- if (lockfp != NULL)
- (void) flock(fileno(lockfp), LOCK_UN);
- #endif /* (FCNTL_FLOCK) || (LOCKF_FLOCK) */
- pid = fork();
- if (pid > 0 && tTd(4, 2))
- printf("sendall: forking (pid = %d)\n", pid);
- if (pid < 0)
- {
- mode = SM_DELIVER;
- break;
- }
- else if (pid > 0)
- {
- /* be sure we leave the temp files to our child */
- e->e_id = e->e_df = NULL;
- if (lockfp != NULL)
- (void) fclose(lockfp);
- return;
- }
-
- /* double fork to avoid zombies */
- if (fork() > 0)
- exit(EX_OK);
-
- #if defined(FCNTL_FLOCK) || defined(LOCKF_FLOCK)
- /*
- ** re-lock tf file in child (again for flock() as lockf())
- */
- if (lockfp != NULL && flock(fileno(lockfp), LOCK_EX|LOCK_NB) <0)
- {
- /* someone else got in before us */
- e->e_id = NULL;
- (void) fclose(lockfp);
- finis();
- }
- #endif /* (FCNTL_FLOCK) || (LOCKF_FLOCK) */
-
- /* be sure we are immune from the terminal */
- disconnect(FALSE);
-
- break;
- }
-
- /pbp
- --
- "A well-schooled electorate, being necessary to the security of a free State,
- the right of the People to keep and read Books shall not be infringed."
- -- J. Neil Schulman
-