summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDaan De Meyer <daan.j.demeyer@gmail.com>2023-03-09 12:59:09 +0100
committerDaan De Meyer <daan.j.demeyer@gmail.com>2023-03-21 15:19:33 +0100
commitaea3ca36135aeb74ea38e7538c710d92b37f479d (patch)
treeec315249081da1eda7f0bf2c59dd6cb740c06c72 /src
parentMerge pull request #26893 from yuwata/uki-util-update-log (diff)
downloadsystemd-aea3ca36135aeb74ea38e7538c710d92b37f479d.tar.xz
systemd-aea3ca36135aeb74ea38e7538c710d92b37f479d.zip
lock-util: Add make_lock_file_at()
Diffstat (limited to 'src')
-rw-r--r--src/basic/lock-util.c18
-rw-r--r--src/basic/lock-util.h10
-rw-r--r--src/test/meson.build1
-rw-r--r--src/test/test-lock-util.c37
4 files changed, 60 insertions, 6 deletions
diff --git a/src/basic/lock-util.c b/src/basic/lock-util.c
index 13e4c12237..46391bb5cc 100644
--- a/src/basic/lock-util.c
+++ b/src/basic/lock-util.c
@@ -15,17 +15,25 @@
#include "missing_fcntl.h"
#include "path-util.h"
-int make_lock_file(const char *p, int operation, LockFile *ret) {
- _cleanup_close_ int fd = -EBADF;
+int make_lock_file_at(int dir_fd, const char *p, int operation, LockFile *ret) {
+ _cleanup_close_ int fd = -EBADF, dfd = -EBADF;
_cleanup_free_ char *t = NULL;
int r;
+ assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
assert(p);
assert(IN_SET(operation & ~LOCK_NB, LOCK_EX, LOCK_SH));
assert(ret);
+ if (isempty(p))
+ return -EINVAL;
+
/* We use UNPOSIX locks as they have nice semantics, and are mostly compatible with NFS. */
+ dfd = fd_reopen(dir_fd, O_CLOEXEC|O_PATH|O_DIRECTORY);
+ if (dfd < 0)
+ return dfd;
+
t = strdup(p);
if (!t)
return -ENOMEM;
@@ -33,7 +41,7 @@ int make_lock_file(const char *p, int operation, LockFile *ret) {
for (;;) {
struct stat st;
- fd = open(p, O_CREAT|O_RDWR|O_NOFOLLOW|O_CLOEXEC|O_NOCTTY, 0600);
+ fd = openat(dfd, p, O_CREAT|O_RDWR|O_NOFOLLOW|O_CLOEXEC|O_NOCTTY, 0600);
if (fd < 0)
return -errno;
@@ -54,6 +62,7 @@ int make_lock_file(const char *p, int operation, LockFile *ret) {
}
*ret = (LockFile) {
+ .dir_fd = TAKE_FD(dfd),
.path = TAKE_PTR(t),
.fd = TAKE_FD(fd),
.operation = operation,
@@ -100,11 +109,12 @@ void release_lock_file(LockFile *f) {
f->operation = LOCK_EX|LOCK_NB;
if ((f->operation & ~LOCK_NB) == LOCK_EX)
- (void) unlink(f->path);
+ (void) unlinkat(f->dir_fd, f->path, 0);
f->path = mfree(f->path);
}
+ f->dir_fd = safe_close(f->dir_fd);
f->fd = safe_close(f->fd);
f->operation = 0;
}
diff --git a/src/basic/lock-util.h b/src/basic/lock-util.h
index 6eebd09143..3659f2b3a0 100644
--- a/src/basic/lock-util.h
+++ b/src/basic/lock-util.h
@@ -1,17 +1,23 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
+#include <fcntl.h>
+
typedef struct LockFile {
+ int dir_fd;
char *path;
int fd;
int operation;
} LockFile;
-int make_lock_file(const char *p, int operation, LockFile *ret);
+int make_lock_file_at(int dir_fd, const char *p, int operation, LockFile *ret);
+static inline int make_lock_file(const char *p, int operation, LockFile *ret) {
+ return make_lock_file_at(AT_FDCWD, p, operation, ret);
+}
int make_lock_file_for(const char *p, int operation, LockFile *ret);
void release_lock_file(LockFile *f);
-#define LOCK_FILE_INIT { .fd = -EBADF, .path = NULL }
+#define LOCK_FILE_INIT { .dir_fd = -EBADF, .fd = -EBADF }
/* POSIX locks with the same interface as flock(). */
int posix_lock(int fd, int operation);
diff --git a/src/test/meson.build b/src/test/meson.build
index e709314152..8d815edea5 100644
--- a/src/test/meson.build
+++ b/src/test/meson.build
@@ -106,6 +106,7 @@ simple_tests += files(
'test-list.c',
'test-local-addresses.c',
'test-locale-util.c',
+ 'test-lock-util.c',
'test-log.c',
'test-logarithm.c',
'test-macro.c',
diff --git a/src/test/test-lock-util.c b/src/test/test-lock-util.c
new file mode 100644
index 0000000000..a9a1b438ff
--- /dev/null
+++ b/src/test/test-lock-util.c
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <unistd.h>
+
+#include "fd-util.h"
+#include "lock-util.h"
+#include "rm-rf.h"
+#include "tests.h"
+#include "tmpfile-util.h"
+
+TEST(make_lock_file) {
+ _cleanup_(rm_rf_physical_and_freep) char *t = NULL;
+ _cleanup_close_ int tfd = -EBADF;
+ _cleanup_(release_lock_file) LockFile lock1 = LOCK_FILE_INIT, lock2 = LOCK_FILE_INIT;
+
+ assert_se((tfd = mkdtemp_open(NULL, 0, &t)) >= 0);
+
+ assert_se(make_lock_file_at(tfd, "lock", LOCK_EX, &lock1) >= 0);
+ assert_se(faccessat(tfd, "lock", F_OK, 0) >= 0);
+ assert_se(make_lock_file_at(tfd, "lock", LOCK_EX|LOCK_NB, &lock2) == -EBUSY);
+ release_lock_file(&lock1);
+ assert_se(RET_NERRNO(faccessat(tfd, "lock", F_OK, 0)) == -ENOENT);
+ assert_se(make_lock_file_at(tfd, "lock", LOCK_EX, &lock2) >= 0);
+ release_lock_file(&lock2);
+ assert_se(make_lock_file_at(tfd, "lock", LOCK_SH, &lock1) >= 0);
+ assert_se(faccessat(tfd, "lock", F_OK, 0) >= 0);
+ assert_se(make_lock_file_at(tfd, "lock", LOCK_SH, &lock2) >= 0);
+ release_lock_file(&lock1);
+ assert_se(faccessat(tfd, "lock", F_OK, 0) >= 0);
+ release_lock_file(&lock2);
+
+ assert_se(fchdir(tfd) >= 0);
+ assert_se(make_lock_file_at(tfd, "lock", LOCK_EX, &lock1) >= 0);
+ assert_se(make_lock_file("lock", LOCK_EX|LOCK_NB, &lock2) == -EBUSY);
+}
+
+DEFINE_TEST_MAIN(LOG_INFO);