diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 1996-06-11 12:54:26 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 1996-06-11 12:54:26 +0000 |
commit | 1c5940ab5503bf389f03195f3d01a93353919abb (patch) | |
tree | a1e9691c11b7f36906f0943dc7d8464a56b98adc /usr.bin/mail/dotlock.c | |
parent | 5f733ec731243d90e1e65f27ce29e683e7a253a6 (diff) |
from christos;
- Fix PR/105: Implement dot locking protocol and check return value of flock.
- Fix PR/2247: Don't call unknown users "ubluit". Issue an error message.
- Fix/add prototypes.
- Fix warnings.
- Use POSIX signal mask calls.
Diffstat (limited to 'usr.bin/mail/dotlock.c')
-rw-r--r-- | usr.bin/mail/dotlock.c | 198 |
1 files changed, 198 insertions, 0 deletions
diff --git a/usr.bin/mail/dotlock.c b/usr.bin/mail/dotlock.c new file mode 100644 index 00000000000..a16bf531ed1 --- /dev/null +++ b/usr.bin/mail/dotlock.c @@ -0,0 +1,198 @@ +/* $OpenBSD: dotlock.c,v 1.1 1996/06/11 12:53:37 deraadt Exp $ */ +/* $NetBSD: dotlock.c,v 1.1 1996/06/08 19:48:19 christos Exp $ */ + +/* + * Copyright (c) 1996 Christos Zoulas. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Christos Zoulas. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef lint +static char rcsid[] = "$OpenBSD: dotlock.c,v 1.1 1996/06/11 12:53:37 deraadt Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/stat.h> +#include <sys/time.h> + +#include <stdio.h> +#include <string.h> +#include <fcntl.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <signal.h> + +#include "extern.h" + +#ifndef O_SYNC +#define O_SYNC 0 +#endif + +static int create_exclusive __P((const char *)); +/* + * Create a unique file. O_EXCL does not really work over NFS so we follow + * the following trick: [Inspired by S.R. van den Berg] + * + * - make a mostly unique filename and try to create it. + * - link the unique filename to our target + * - get the link count of the target + * - unlink the mostly unique filename + * - if the link count was 2, then we are ok; else we've failed. + */ +static int +create_exclusive(fname) + const char *fname; +{ + char path[MAXPATHLEN], hostname[MAXHOSTNAMELEN]; + const char *ptr; + struct timeval tv; + pid_t pid; + size_t ntries, cookie; + int fd, serrno; + struct stat st; + + (void) gettimeofday(&tv, NULL); + (void) gethostname(hostname, MAXHOSTNAMELEN); + pid = getpid(); + + cookie = pid ^ tv.tv_usec; + + /* + * We generate a semi-unique filename, from hostname.(pid ^ usec) + */ + if ((ptr = strrchr(fname, '/')) == NULL) + ptr = fname; + else + ptr++; + + (void) snprintf(path, sizeof(path), "%.*s.%s.%x", + ptr - fname, fname, hostname, cookie); + + /* + * We try to create the unique filename. + */ + for (ntries = 0; ntries < 5; ntries++) { + fd = open(path, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL|O_SYNC, 0); + if (fd != -1) { + (void) close(fd); + break; + } + else if (errno == EEXIST) + continue; + else + return -1; + } + + /* + * We link the path to the name + */ + if (link(path, fname) == -1) + goto bad; + + /* + * Note that we stat our own exclusively created name, not the + * destination, since the destination can be affected by others. + */ + if (stat(path, &st) == -1) + goto bad; + + (void) unlink(path); + + /* + * If the number of links was two (one for the unique file and one + * for the lock), we've won the race + */ + if (st.st_nlink != 2) { + errno = EEXIST; + return -1; + } + return 0; + +bad: + serrno = errno; + (void) unlink(path); + errno = serrno; + return -1; +} + +int +dot_lock(fname, pollinterval, fp, msg) + const char *fname; /* Pathname to lock */ + int pollinterval; /* Interval to check for lock, -1 return */ + FILE *fp; /* File to print message */ + const char *msg; /* Message to print */ +{ + char path[MAXPATHLEN]; + sigset_t nset, oset; + + sigemptyset(&nset); + sigaddset(&nset, SIGHUP); + sigaddset(&nset, SIGINT); + sigaddset(&nset, SIGQUIT); + sigaddset(&nset, SIGTERM); + sigaddset(&nset, SIGTTIN); + sigaddset(&nset, SIGTTOU); + sigaddset(&nset, SIGTSTP); + sigaddset(&nset, SIGCHLD); + + (void) snprintf(path, sizeof(path), "%s.lock", fname); + + for (;;) { + (void) sigprocmask(SIG_BLOCK, &nset, &oset); + if (create_exclusive(path) != -1) { + (void) sigprocmask(SIG_SETMASK, &oset, NULL); + return 0; + } + else + (void) sigprocmask(SIG_SETMASK, &oset, NULL); + + if (errno != EEXIST) + return -1; + + if (fp && msg) + (void) fputs(msg, fp); + + if (pollinterval) { + if (pollinterval == -1) { + errno = EEXIST; + return -1; + } + sleep(pollinterval); + } + } +} + +void +dot_unlock(fname) + const char *fname; +{ + char path[MAXPATHLEN]; + + (void) snprintf(path, sizeof(path), "%s.lock", fname); + (void) unlink(path); +} |