Annotation of src/usr.bin/mail/dotlock.c, Revision 1.3
1.3 ! millert 1: /* $OpenBSD: dotlock.c,v 1.2 1997/07/13 21:21:11 millert Exp $ */
1.1 deraadt 2: /* $NetBSD: dotlock.c,v 1.1 1996/06/08 19:48:19 christos Exp $ */
3:
4: /*
5: * Copyright (c) 1996 Christos Zoulas. All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: * 3. All advertising materials mentioning features or use of this software
16: * must display the following acknowledgement:
17: * This product includes software developed by Christos Zoulas.
18: * 4. The name of the author may not be used to endorse or promote products
19: * derived from this software without specific prior written permission.
20: *
21: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31: */
32:
33: #ifndef lint
1.3 ! millert 34: static char rcsid[] = "$OpenBSD: dotlock.c,v 1.2 1997/07/13 21:21:11 millert Exp $";
1.1 deraadt 35: #endif
36:
37: #include <sys/types.h>
38: #include <sys/param.h>
39: #include <sys/stat.h>
40: #include <sys/time.h>
41:
42: #include <stdio.h>
43: #include <string.h>
44: #include <fcntl.h>
45: #include <stdlib.h>
46: #include <unistd.h>
47: #include <errno.h>
48: #include <signal.h>
49:
50: #include "extern.h"
51:
52: #ifndef O_SYNC
53: #define O_SYNC 0
54: #endif
55:
56: static int create_exclusive __P((const char *));
57: /*
58: * Create a unique file. O_EXCL does not really work over NFS so we follow
59: * the following trick: [Inspired by S.R. van den Berg]
60: *
61: * - make a mostly unique filename and try to create it.
62: * - link the unique filename to our target
63: * - get the link count of the target
64: * - unlink the mostly unique filename
65: * - if the link count was 2, then we are ok; else we've failed.
66: */
67: static int
68: create_exclusive(fname)
69: const char *fname;
70: {
71: char path[MAXPATHLEN], hostname[MAXHOSTNAMELEN];
72: const char *ptr;
73: struct timeval tv;
74: pid_t pid;
75: size_t ntries, cookie;
76: int fd, serrno;
77: struct stat st;
78:
1.3 ! millert 79: (void)gettimeofday(&tv, NULL);
! 80: (void)gethostname(hostname, MAXHOSTNAMELEN);
1.1 deraadt 81: pid = getpid();
82:
83: cookie = pid ^ tv.tv_usec;
84:
85: /*
86: * We generate a semi-unique filename, from hostname.(pid ^ usec)
87: */
88: if ((ptr = strrchr(fname, '/')) == NULL)
89: ptr = fname;
90: else
91: ptr++;
92:
1.3 ! millert 93: (void)snprintf(path, sizeof(path), "%.*s.%s.%x",
1.1 deraadt 94: ptr - fname, fname, hostname, cookie);
95:
96: /*
97: * We try to create the unique filename.
98: */
99: for (ntries = 0; ntries < 5; ntries++) {
100: fd = open(path, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL|O_SYNC, 0);
101: if (fd != -1) {
1.2 millert 102: (void)close(fd);
1.1 deraadt 103: break;
104: }
105: else if (errno == EEXIST)
106: continue;
107: else
1.2 millert 108: return(-1);
1.1 deraadt 109: }
110:
111: /*
112: * We link the path to the name
113: */
114: if (link(path, fname) == -1)
115: goto bad;
116:
117: /*
118: * Note that we stat our own exclusively created name, not the
119: * destination, since the destination can be affected by others.
120: */
121: if (stat(path, &st) == -1)
122: goto bad;
123:
1.3 ! millert 124: (void)unlink(path);
1.1 deraadt 125:
126: /*
127: * If the number of links was two (one for the unique file and one
128: * for the lock), we've won the race
129: */
130: if (st.st_nlink != 2) {
131: errno = EEXIST;
1.2 millert 132: return(-1);
1.1 deraadt 133: }
1.2 millert 134: return(0);
1.1 deraadt 135:
136: bad:
137: serrno = errno;
1.3 ! millert 138: (void)unlink(path);
1.1 deraadt 139: errno = serrno;
1.2 millert 140: return(-1);
1.1 deraadt 141: }
142:
143: int
144: dot_lock(fname, pollinterval, fp, msg)
145: const char *fname; /* Pathname to lock */
146: int pollinterval; /* Interval to check for lock, -1 return */
147: FILE *fp; /* File to print message */
148: const char *msg; /* Message to print */
149: {
150: char path[MAXPATHLEN];
151: sigset_t nset, oset;
152:
153: sigemptyset(&nset);
154: sigaddset(&nset, SIGHUP);
155: sigaddset(&nset, SIGINT);
156: sigaddset(&nset, SIGQUIT);
157: sigaddset(&nset, SIGTERM);
158: sigaddset(&nset, SIGTTIN);
159: sigaddset(&nset, SIGTTOU);
160: sigaddset(&nset, SIGTSTP);
161: sigaddset(&nset, SIGCHLD);
162:
1.3 ! millert 163: (void)snprintf(path, sizeof(path), "%s.lock", fname);
1.1 deraadt 164:
165: for (;;) {
1.3 ! millert 166: (void)sigprocmask(SIG_BLOCK, &nset, &oset);
1.1 deraadt 167: if (create_exclusive(path) != -1) {
1.3 ! millert 168: (void)sigprocmask(SIG_SETMASK, &oset, NULL);
1.2 millert 169: return(0);
1.1 deraadt 170: }
171: else
1.3 ! millert 172: (void)sigprocmask(SIG_SETMASK, &oset, NULL);
1.1 deraadt 173:
174: if (errno != EEXIST)
1.2 millert 175: return(-1);
1.1 deraadt 176:
177: if (fp && msg)
1.3 ! millert 178: (void)fputs(msg, fp);
1.1 deraadt 179:
180: if (pollinterval) {
181: if (pollinterval == -1) {
182: errno = EEXIST;
1.2 millert 183: return(-1);
1.1 deraadt 184: }
185: sleep(pollinterval);
186: }
187: }
188: }
189:
190: void
191: dot_unlock(fname)
192: const char *fname;
193: {
194: char path[MAXPATHLEN];
195:
1.3 ! millert 196: (void)snprintf(path, sizeof(path), "%s.lock", fname);
! 197: (void)unlink(path);
1.1 deraadt 198: }