Line data Source code
1 : /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2 :
3 : /***
4 : This file is part of systemd.
5 :
6 : Copyright 2010 Lennart Poettering
7 :
8 : systemd is free software; you can redistribute it and/or modify it
9 : under the terms of the GNU Lesser General Public License as published by
10 : the Free Software Foundation; either version 2.1 of the License, or
11 : (at your option) any later version.
12 :
13 : systemd is distributed in the hope that it will be useful, but
14 : WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 : Lesser General Public License for more details.
17 :
18 : You should have received a copy of the GNU Lesser General Public License
19 : along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 : ***/
21 :
22 : #include <stdlib.h>
23 : #include <stdbool.h>
24 : #include <errno.h>
25 : #include <string.h>
26 : #include <stdio.h>
27 : #include <limits.h>
28 : #include <sys/file.h>
29 :
30 : #include "util.h"
31 : #include "lockfile-util.h"
32 : #include "fileio.h"
33 :
34 0 : int make_lock_file(const char *p, int operation, LockFile *ret) {
35 0 : _cleanup_close_ int fd = -1;
36 0 : _cleanup_free_ char *t = NULL;
37 : int r;
38 :
39 : /*
40 : * We use UNPOSIX locks if they are available. They have nice
41 : * semantics, and are mostly compatible with NFS. However,
42 : * they are only available on new kernels. When we detect we
43 : * are running on an older kernel, then we fall back to good
44 : * old BSD locks. They also have nice semantics, but are
45 : * slightly problematic on NFS, where they are upgraded to
46 : * POSIX locks, even though locally they are orthogonal to
47 : * POSIX locks.
48 : */
49 :
50 0 : t = strdup(p);
51 0 : if (!t)
52 0 : return -ENOMEM;
53 :
54 : for (;;) {
55 0 : struct flock fl = {
56 0 : .l_type = (operation & ~LOCK_NB) == LOCK_EX ? F_WRLCK : F_RDLCK,
57 : .l_whence = SEEK_SET,
58 : };
59 : struct stat st;
60 :
61 0 : fd = open(p, O_CREAT|O_RDWR|O_NOFOLLOW|O_CLOEXEC|O_NOCTTY, 0600);
62 0 : if (fd < 0)
63 0 : return -errno;
64 :
65 0 : r = fcntl(fd, (operation & LOCK_NB) ? F_OFD_SETLK : F_OFD_SETLKW, &fl);
66 0 : if (r < 0) {
67 :
68 : /* If the kernel is too old, use good old BSD locks */
69 0 : if (errno == EINVAL)
70 0 : r = flock(fd, operation);
71 :
72 0 : if (r < 0)
73 0 : return errno == EAGAIN ? -EBUSY : -errno;
74 : }
75 :
76 : /* If we acquired the lock, let's check if the file
77 : * still exists in the file system. If not, then the
78 : * previous exclusive owner removed it and then closed
79 : * it. In such a case our acquired lock is worthless,
80 : * hence try again. */
81 :
82 0 : r = fstat(fd, &st);
83 0 : if (r < 0)
84 0 : return -errno;
85 0 : if (st.st_nlink > 0)
86 0 : break;
87 :
88 0 : fd = safe_close(fd);
89 0 : }
90 :
91 0 : ret->path = t;
92 0 : ret->fd = fd;
93 0 : ret->operation = operation;
94 :
95 0 : fd = -1;
96 0 : t = NULL;
97 :
98 0 : return r;
99 : }
100 :
101 0 : int make_lock_file_for(const char *p, int operation, LockFile *ret) {
102 : const char *fn;
103 : char *t;
104 :
105 0 : assert(p);
106 0 : assert(ret);
107 :
108 0 : fn = basename(p);
109 0 : if (!filename_is_valid(fn))
110 0 : return -EINVAL;
111 :
112 0 : t = newa(char, strlen(p) + 2 + 4 + 1);
113 0 : stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), fn), ".lck");
114 :
115 0 : return make_lock_file(t, operation, ret);
116 : }
117 :
118 0 : void release_lock_file(LockFile *f) {
119 : int r;
120 :
121 0 : if (!f)
122 0 : return;
123 :
124 0 : if (f->path) {
125 :
126 : /* If we are the exclusive owner we can safely delete
127 : * the lock file itself. If we are not the exclusive
128 : * owner, we can try becoming it. */
129 :
130 0 : if (f->fd >= 0 &&
131 0 : (f->operation & ~LOCK_NB) == LOCK_SH) {
132 : static const struct flock fl = {
133 : .l_type = F_WRLCK,
134 : .l_whence = SEEK_SET,
135 : };
136 :
137 0 : r = fcntl(f->fd, F_OFD_SETLK, &fl);
138 0 : if (r < 0 && errno == EINVAL)
139 0 : r = flock(f->fd, LOCK_EX|LOCK_NB);
140 :
141 0 : if (r >= 0)
142 0 : f->operation = LOCK_EX|LOCK_NB;
143 : }
144 :
145 0 : if ((f->operation & ~LOCK_NB) == LOCK_EX)
146 0 : unlink_noerrno(f->path);
147 :
148 0 : free(f->path);
149 0 : f->path = NULL;
150 : }
151 :
152 0 : f->fd = safe_close(f->fd);
153 0 : f->operation = 0;
154 : }
|