1 /* lock_flock.c -- Lock files using flock()
2  *
3  * Copyright (c) 1994-2008 Carnegie Mellon University.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in
14  *    the documentation and/or other materials provided with the
15  *    distribution.
16  *
17  * 3. The name "Carnegie Mellon University" must not be used to
18  *    endorse or promote products derived from this software without
19  *    prior written permission. For permission or any legal
20  *    details, please contact
21  *      Carnegie Mellon University
22  *      Center for Technology Transfer and Enterprise Creation
23  *      4615 Forbes Avenue
24  *      Suite 302
25  *      Pittsburgh, PA  15213
26  *      (412) 268-7393, fax: (412) 268-7395
27  *      innovation@andrew.cmu.edu
28  *
29  * 4. Redistributions of any form whatsoever must retain the following
30  *    acknowledgment:
31  *    "This product includes software developed by Computing Services
32  *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
33  *
34  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
35  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
36  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
37  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
38  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
39  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
40  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
41  */
42 
43 #include <config.h>
44 #include <sys/file.h>
45 #include <sys/stat.h>
46 #include <fcntl.h>
47 #include <errno.h>
48 #ifdef HAVE_UNISTD_H
49 #include <unistd.h>
50 #endif
51 
52 #include "cyr_lock.h"
53 
54 EXPORTED const char *lock_method_desc = "flock";
55 
56 /*
57  * Block until we obtain an exclusive lock on the file descriptor 'fd',
58  * opened for reading and writing on the file named 'filename'.  If
59  * 'filename' is replaced, will re-open it as 'fd' and acquire a lock
60  * on the new file.
61  *
62  * On success, returns 0.  If a pointer to a struct stat is given as
63  * 'sbuf', it is filled in.
64  *
65  * On failure, returns -1 with an error code in errno.  If
66  * 'failaction' is provided, it is filled in with a pointer to a fixed
67  * string naming the action that failed.
68  *
69  */
lock_reopen_ex(int fd,const char * filename,struct stat * sbuf,const char ** failaction,int * changed)70 EXPORTED int lock_reopen_ex(int fd, const char *filename,
71                             struct stat *sbuf, const char **failaction,
72                             int *changed)
73 {
74     int r;
75     struct stat sbuffile, sbufspare;
76     int newfd;
77 
78     if (!sbuf) sbuf = &sbufspare;
79 
80     for (;;) {
81         r = flock(fd, LOCK_EX);
82         if (r == -1) {
83             if (errno == EINTR) continue;
84             if (failaction) *failaction = "locking";
85             return -1;
86         }
87 
88         r = fstat(fd, sbuf);
89         if (!r) r = stat(filename, &sbuffile);
90         if (r == -1) {
91             if (failaction) *failaction = "stating";
92             lock_unlock(fd, filename);
93             return -1;
94         }
95 
96         if (sbuf->st_ino == sbuffile.st_ino) return 0;
97 
98         if (changed) *changed = 1;
99 
100         newfd = open(filename, O_RDWR);
101         if (newfd == -1) {
102             if (failaction) *failaction = "opening";
103             lock_unlock(fd, filename);
104             return -1;
105         }
106         dup2(newfd, fd);
107         close(newfd);
108     }
109 }
110 
111 /*
112  * Obtain a lock on 'fd'.  The lock is exclusive if 'exclusive'
113  * is true, otherwise shared.  Normally blocks until a lock is
114  * obtained, but if 'nonblock' is true does not block and instead
115  * fails with errno=EWOUDBLOCK if the lock cannot be obtained.
116  *
117  * Returns 0 for success, -1 for failure, with errno set to an
118  * appropriate error code.
119  */
lock_setlock(int fd,int exclusive,int nonblock,const char * filename)120 EXPORTED int lock_setlock(int fd, int exclusive, int nonblock,
121                           const char *filename __attribute__((unused)))
122 {
123     int r;
124     int op = (exclusive ? LOCK_EX : LOCK_SH);
125     if (nonblock) op |= LOCK_NB;
126 
127     for (;;) {
128         r = flock(fd, op);
129         if (r != -1) return 0;
130         if (errno == EINTR) continue;
131         return -1;
132     }
133 }
134 
135 /*
136  * Release any lock on 'fd'.  Always returns success.
137  */
lock_unlock(int fd,const char * filename)138 EXPORTED int lock_unlock(int fd, const char *filename __attribute__((unused)))
139 {
140     int r;
141 
142     for (;;) {
143         r = flock(fd, LOCK_UN);
144         if (r != -1) return 0;
145         if (errno == EINTR) continue;
146         /* xxx help! */
147         return -1;
148     }
149 }
150 
151