]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/lockfile-util.c
Merge pull request #2495 from heftig/master
[thirdparty/systemd.git] / src / basic / lockfile-util.c
CommitLineData
cd2eb9e9
CW
1/***
2 This file is part of systemd.
3
4 Copyright 2010 Lennart Poettering
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18***/
19
cd2eb9e9 20#include <errno.h>
11c3a366 21#include <fcntl.h>
cf0fbc49 22#include <stdio.h>
cf0fbc49 23#include <string.h>
cd2eb9e9 24#include <sys/file.h>
11c3a366 25#include <sys/stat.h>
cd2eb9e9 26
b5efdb8a 27#include "alloc-util.h"
3ffd4af2 28#include "fd-util.h"
f4f15635 29#include "fs-util.h"
3ffd4af2 30#include "lockfile-util.h"
11c3a366 31#include "macro.h"
93cc7779 32#include "path-util.h"
cd2eb9e9
CW
33
34int make_lock_file(const char *p, int operation, LockFile *ret) {
35 _cleanup_close_ int fd = -1;
36 _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 t = strdup(p);
51 if (!t)
52 return -ENOMEM;
53
54 for (;;) {
55 struct flock fl = {
56 .l_type = (operation & ~LOCK_NB) == LOCK_EX ? F_WRLCK : F_RDLCK,
57 .l_whence = SEEK_SET,
58 };
59 struct stat st;
60
61 fd = open(p, O_CREAT|O_RDWR|O_NOFOLLOW|O_CLOEXEC|O_NOCTTY, 0600);
62 if (fd < 0)
63 return -errno;
64
65 r = fcntl(fd, (operation & LOCK_NB) ? F_OFD_SETLK : F_OFD_SETLKW, &fl);
66 if (r < 0) {
67
68 /* If the kernel is too old, use good old BSD locks */
69 if (errno == EINVAL)
70 r = flock(fd, operation);
71
72 if (r < 0)
73 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 r = fstat(fd, &st);
83 if (r < 0)
84 return -errno;
85 if (st.st_nlink > 0)
86 break;
87
88 fd = safe_close(fd);
89 }
90
91 ret->path = t;
92 ret->fd = fd;
93 ret->operation = operation;
94
95 fd = -1;
96 t = NULL;
97
98 return r;
99}
100
101int make_lock_file_for(const char *p, int operation, LockFile *ret) {
102 const char *fn;
103 char *t;
104
105 assert(p);
106 assert(ret);
107
108 fn = basename(p);
109 if (!filename_is_valid(fn))
110 return -EINVAL;
111
112 t = newa(char, strlen(p) + 2 + 4 + 1);
113 stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), fn), ".lck");
114
115 return make_lock_file(t, operation, ret);
116}
117
118void release_lock_file(LockFile *f) {
119 int r;
120
121 if (!f)
122 return;
123
124 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 if (f->fd >= 0 &&
131 (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 r = fcntl(f->fd, F_OFD_SETLK, &fl);
138 if (r < 0 && errno == EINVAL)
139 r = flock(f->fd, LOCK_EX|LOCK_NB);
140
141 if (r >= 0)
142 f->operation = LOCK_EX|LOCK_NB;
143 }
144
145 if ((f->operation & ~LOCK_NB) == LOCK_EX)
146 unlink_noerrno(f->path);
147
a1e58e8e 148 f->path = mfree(f->path);
cd2eb9e9
CW
149 }
150
151 f->fd = safe_close(f->fd);
152 f->operation = 0;
153}