I'm planning to use the code in ostree (via libglnx), here's a few minor 
patches for systemd's lockfile code.
From 9e249575b2b99110a29f32f53aab1c1048b72eb9 Mon Sep 17 00:00:00 2001
From: Colin Walters <[email protected]>
Date: Mon, 4 May 2015 16:12:46 -0400
Subject: [PATCH 1/3] lockfile-util.[ch]: Split out from util.[ch]

Continuing the general trend of splitting up util.[ch].  I specifically
want to reuse this code in https://github.com/GNOME/libglnx and
having it split up will make future copy-pasting easier.
---
 Makefile.am                |   2 +
 src/shared/lockfile-util.c | 154 +++++++++++++++++++++++++++++++++++++++++++++
 src/shared/lockfile-util.h |  39 ++++++++++++
 src/shared/machine-image.h |   1 +
 src/shared/machine-pool.c  |   1 +
 src/shared/util.c          | 122 -----------------------------------
 src/shared/util.h          |  14 -----
 7 files changed, 197 insertions(+), 136 deletions(-)
 create mode 100644 src/shared/lockfile-util.c
 create mode 100644 src/shared/lockfile-util.h

diff --git a/Makefile.am b/Makefile.am
index 164bdfb..1ec1e77 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -775,6 +775,8 @@ libsystemd_shared_la_SOURCES = \
 	src/shared/formats-util.h \
 	src/shared/fstab-util.c \
 	src/shared/fstab-util.h \
+	src/shared/lockfile-util.c \
+	src/shared/lockfile-util.h \
 	src/shared/path-util.c \
 	src/shared/path-util.h \
 	src/shared/time-util.c \
diff --git a/src/shared/lockfile-util.c b/src/shared/lockfile-util.c
new file mode 100644
index 0000000..05e16d1
--- /dev/null
+++ b/src/shared/lockfile-util.c
@@ -0,0 +1,154 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdlib.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <limits.h>
+#include <sys/file.h>
+
+#include "util.h"
+#include "lockfile-util.h"
+#include "fileio.h"
+
+int make_lock_file(const char *p, int operation, LockFile *ret) {
+        _cleanup_close_ int fd = -1;
+        _cleanup_free_ char *t = NULL;
+        int r;
+
+        /*
+         * We use UNPOSIX locks if they are available. They have nice
+         * semantics, and are mostly compatible with NFS. However,
+         * they are only available on new kernels. When we detect we
+         * are running on an older kernel, then we fall back to good
+         * old BSD locks. They also have nice semantics, but are
+         * slightly problematic on NFS, where they are upgraded to
+         * POSIX locks, even though locally they are orthogonal to
+         * POSIX locks.
+         */
+
+        t = strdup(p);
+        if (!t)
+                return -ENOMEM;
+
+        for (;;) {
+                struct flock fl = {
+                        .l_type = (operation & ~LOCK_NB) == LOCK_EX ? F_WRLCK : F_RDLCK,
+                        .l_whence = SEEK_SET,
+                };
+                struct stat st;
+
+                fd = open(p, O_CREAT|O_RDWR|O_NOFOLLOW|O_CLOEXEC|O_NOCTTY, 0600);
+                if (fd < 0)
+                        return -errno;
+
+                r = fcntl(fd, (operation & LOCK_NB) ? F_OFD_SETLK : F_OFD_SETLKW, &fl);
+                if (r < 0) {
+
+                        /* If the kernel is too old, use good old BSD locks */
+                        if (errno == EINVAL)
+                                r = flock(fd, operation);
+
+                        if (r < 0)
+                                return errno == EAGAIN ? -EBUSY : -errno;
+                }
+
+                /* If we acquired the lock, let's check if the file
+                 * still exists in the file system. If not, then the
+                 * previous exclusive owner removed it and then closed
+                 * it. In such a case our acquired lock is worthless,
+                 * hence try again. */
+
+                r = fstat(fd, &st);
+                if (r < 0)
+                        return -errno;
+                if (st.st_nlink > 0)
+                        break;
+
+                fd = safe_close(fd);
+        }
+
+        ret->path = t;
+        ret->fd = fd;
+        ret->operation = operation;
+
+        fd = -1;
+        t = NULL;
+
+        return r;
+}
+
+int make_lock_file_for(const char *p, int operation, LockFile *ret) {
+        const char *fn;
+        char *t;
+
+        assert(p);
+        assert(ret);
+
+        fn = basename(p);
+        if (!filename_is_valid(fn))
+                return -EINVAL;
+
+        t = newa(char, strlen(p) + 2 + 4 + 1);
+        stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), fn), ".lck");
+
+        return make_lock_file(t, operation, ret);
+}
+
+void release_lock_file(LockFile *f) {
+        int r;
+
+        if (!f)
+                return;
+
+        if (f->path) {
+
+                /* If we are the exclusive owner we can safely delete
+                 * the lock file itself. If we are not the exclusive
+                 * owner, we can try becoming it. */
+
+                if (f->fd >= 0 &&
+                    (f->operation & ~LOCK_NB) == LOCK_SH) {
+                        static const struct flock fl = {
+                                .l_type = F_WRLCK,
+                                .l_whence = SEEK_SET,
+                        };
+
+                        r = fcntl(f->fd, F_OFD_SETLK, &fl);
+                        if (r < 0 && errno == EINVAL)
+                                r = flock(f->fd, LOCK_EX|LOCK_NB);
+
+                        if (r >= 0)
+                                f->operation = LOCK_EX|LOCK_NB;
+                }
+
+                if ((f->operation & ~LOCK_NB) == LOCK_EX)
+                        unlink_noerrno(f->path);
+
+                free(f->path);
+                f->path = NULL;
+        }
+
+        f->fd = safe_close(f->fd);
+        f->operation = 0;
+}
diff --git a/src/shared/lockfile-util.h b/src/shared/lockfile-util.h
new file mode 100644
index 0000000..38d4709
--- /dev/null
+++ b/src/shared/lockfile-util.h
@@ -0,0 +1,39 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2011 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "macro.h"
+#include "missing.h"
+
+typedef struct LockFile {
+        char *path;
+        int fd;
+        int operation;
+} LockFile;
+
+int make_lock_file(const char *p, int operation, LockFile *ret);
+int make_lock_file_for(const char *p, int operation, LockFile *ret);
+void release_lock_file(LockFile *f);
+
+#define _cleanup_release_lock_file_ _cleanup_(release_lock_file)
+
+#define LOCK_FILE_INIT { .fd = -1, .path = NULL }
diff --git a/src/shared/machine-image.h b/src/shared/machine-image.h
index bf41b2e..f041600 100644
--- a/src/shared/machine-image.h
+++ b/src/shared/machine-image.h
@@ -22,6 +22,7 @@
 ***/
 
 #include "time-util.h"
+#include "lockfile-util.h"
 #include "hashmap.h"
 
 typedef enum ImageType {
diff --git a/src/shared/machine-pool.c b/src/shared/machine-pool.c
index 41aa1b7..9920d15 100644
--- a/src/shared/machine-pool.c
+++ b/src/shared/machine-pool.c
@@ -26,6 +26,7 @@
 
 #include "util.h"
 #include "process-util.h"
+#include "lockfile-util.h"
 #include "mkdir.h"
 #include "btrfs-util.h"
 #include "path-util.h"
diff --git a/src/shared/util.c b/src/shared/util.c
index 2c7254e..19190df 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -6065,128 +6065,6 @@ int read_attr_path(const char *p, unsigned *ret) {
         return read_attr_fd(fd, ret);
 }
 
-int make_lock_file(const char *p, int operation, LockFile *ret) {
-        _cleanup_close_ int fd = -1;
-        _cleanup_free_ char *t = NULL;
-        int r;
-
-        /*
-         * We use UNPOSIX locks if they are available. They have nice
-         * semantics, and are mostly compatible with NFS. However,
-         * they are only available on new kernels. When we detect we
-         * are running on an older kernel, then we fall back to good
-         * old BSD locks. They also have nice semantics, but are
-         * slightly problematic on NFS, where they are upgraded to
-         * POSIX locks, even though locally they are orthogonal to
-         * POSIX locks.
-         */
-
-        t = strdup(p);
-        if (!t)
-                return -ENOMEM;
-
-        for (;;) {
-                struct flock fl = {
-                        .l_type = (operation & ~LOCK_NB) == LOCK_EX ? F_WRLCK : F_RDLCK,
-                        .l_whence = SEEK_SET,
-                };
-                struct stat st;
-
-                fd = open(p, O_CREAT|O_RDWR|O_NOFOLLOW|O_CLOEXEC|O_NOCTTY, 0600);
-                if (fd < 0)
-                        return -errno;
-
-                r = fcntl(fd, (operation & LOCK_NB) ? F_OFD_SETLK : F_OFD_SETLKW, &fl);
-                if (r < 0) {
-
-                        /* If the kernel is too old, use good old BSD locks */
-                        if (errno == EINVAL)
-                                r = flock(fd, operation);
-
-                        if (r < 0)
-                                return errno == EAGAIN ? -EBUSY : -errno;
-                }
-
-                /* If we acquired the lock, let's check if the file
-                 * still exists in the file system. If not, then the
-                 * previous exclusive owner removed it and then closed
-                 * it. In such a case our acquired lock is worthless,
-                 * hence try again. */
-
-                r = fstat(fd, &st);
-                if (r < 0)
-                        return -errno;
-                if (st.st_nlink > 0)
-                        break;
-
-                fd = safe_close(fd);
-        }
-
-        ret->path = t;
-        ret->fd = fd;
-        ret->operation = operation;
-
-        fd = -1;
-        t = NULL;
-
-        return r;
-}
-
-int make_lock_file_for(const char *p, int operation, LockFile *ret) {
-        const char *fn;
-        char *t;
-
-        assert(p);
-        assert(ret);
-
-        fn = basename(p);
-        if (!filename_is_valid(fn))
-                return -EINVAL;
-
-        t = newa(char, strlen(p) + 2 + 4 + 1);
-        stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), fn), ".lck");
-
-        return make_lock_file(t, operation, ret);
-}
-
-void release_lock_file(LockFile *f) {
-        int r;
-
-        if (!f)
-                return;
-
-        if (f->path) {
-
-                /* If we are the exclusive owner we can safely delete
-                 * the lock file itself. If we are not the exclusive
-                 * owner, we can try becoming it. */
-
-                if (f->fd >= 0 &&
-                    (f->operation & ~LOCK_NB) == LOCK_SH) {
-                        static const struct flock fl = {
-                                .l_type = F_WRLCK,
-                                .l_whence = SEEK_SET,
-                        };
-
-                        r = fcntl(f->fd, F_OFD_SETLK, &fl);
-                        if (r < 0 && errno == EINVAL)
-                                r = flock(f->fd, LOCK_EX|LOCK_NB);
-
-                        if (r >= 0)
-                                f->operation = LOCK_EX|LOCK_NB;
-                }
-
-                if ((f->operation & ~LOCK_NB) == LOCK_EX)
-                        unlink_noerrno(f->path);
-
-                free(f->path);
-                f->path = NULL;
-        }
-
-        f->fd = safe_close(f->fd);
-        f->operation = 0;
-}
-
 static size_t nul_length(const uint8_t *p, size_t sz) {
         size_t n = 0;
 
diff --git a/src/shared/util.h b/src/shared/util.h
index 9409ad9..4a67d5c 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -882,20 +882,6 @@ int chattr_path(const char *p, unsigned value, unsigned mask);
 int read_attr_fd(int fd, unsigned *ret);
 int read_attr_path(const char *p, unsigned *ret);
 
-typedef struct LockFile {
-        char *path;
-        int fd;
-        int operation;
-} LockFile;
-
-int make_lock_file(const char *p, int operation, LockFile *ret);
-int make_lock_file_for(const char *p, int operation, LockFile *ret);
-void release_lock_file(LockFile *f);
-
-#define _cleanup_release_lock_file_ _cleanup_(release_lock_file)
-
-#define LOCK_FILE_INIT { .fd = -1, .path = NULL }
-
 #define RLIMIT_MAKE_CONST(lim) ((struct rlimit) { lim, lim })
 
 ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length);
-- 
1.8.3.1

From 45b44522276cbcf67fff29b607283dc66acbedc7 Mon Sep 17 00:00:00 2001
From: Colin Walters <[email protected]>
Date: Mon, 4 May 2015 16:23:29 -0400
Subject: [PATCH 2/3] util: Add unlinkat_noerrno()

Will be used in a subsequent patch, but it's worth considering the
alternative of a treewide port of all current `unlink_noerrno()`
users.  There's 24 right now.
---
 src/shared/util.c | 6 +++++-
 src/shared/util.h | 2 ++
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/src/shared/util.c b/src/shared/util.c
index 19190df..0972df6 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -299,10 +299,14 @@ void close_many(const int fds[], unsigned n_fd) {
 }
 
 int unlink_noerrno(const char *path) {
+        return unlinkat_noerrno(AT_FDCWD, path, 0);
+}
+
+int unlinkat_noerrno(int dfd, const char *path, int flags) {
         PROTECT_ERRNO;
         int r;
 
-        r = unlink(path);
+        r = unlinkat(dfd, path, flags);
         if (r < 0)
                 return -errno;
 
diff --git a/src/shared/util.h b/src/shared/util.h
index 4a67d5c..f9bba97 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -728,6 +728,8 @@ static inline bool logind_running(void) {
 
 int unlink_noerrno(const char *path);
 
+int unlinkat_noerrno(int dfd, const char *path, int flags);
+
 #define alloca0(n)                                      \
         ({                                              \
                 char *_new_;                            \
-- 
1.8.3.1

From 839641ca295feb583359ce231d43afbd97725fd3 Mon Sep 17 00:00:00 2001
From: Colin Walters <[email protected]>
Date: Mon, 4 May 2015 16:18:49 -0400
Subject: [PATCH 3/3] lockfile: Add fd-relative support

This won't actually be used in systemd yet, but for ostree (which will
copy this lockfile code via libglnx) I'm trying to consistently use
fd-relative APIs, so let's support it here.
---
 src/shared/lockfile-util.c | 17 +++++++++++------
 src/shared/lockfile-util.h |  7 ++++---
 src/shared/machine-image.c |  6 +++---
 src/shared/machine-pool.c  |  2 +-
 4 files changed, 19 insertions(+), 13 deletions(-)

diff --git a/src/shared/lockfile-util.c b/src/shared/lockfile-util.c
index 05e16d1..e76226a 100644
--- a/src/shared/lockfile-util.c
+++ b/src/shared/lockfile-util.c
@@ -31,7 +31,7 @@
 #include "lockfile-util.h"
 #include "fileio.h"
 
-int make_lock_file(const char *p, int operation, LockFile *ret) {
+int make_lock_file(int dfd, const char *p, int operation, LockFile *ret) {
         _cleanup_close_ int fd = -1;
         _cleanup_free_ char *t = NULL;
         int r;
@@ -58,7 +58,7 @@ int make_lock_file(const char *p, int operation, LockFile *ret) {
                 };
                 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;
 
@@ -88,6 +88,10 @@ int make_lock_file(const char *p, int operation, LockFile *ret) {
                 fd = safe_close(fd);
         }
 
+        /* Note that if this is not AT_FDCWD, the caller takes responsibility
+         * for the fd's lifetime being >= that of the lock.
+         */
+        ret->dfd = dfd;
         ret->path = t;
         ret->fd = fd;
         ret->operation = operation;
@@ -98,7 +102,7 @@ int make_lock_file(const char *p, int operation, LockFile *ret) {
         return r;
 }
 
-int make_lock_file_for(const char *p, int operation, LockFile *ret) {
+int make_lock_file_for(int dfd, const char *p, int operation, LockFile *ret) {
         const char *fn;
         char *t;
 
@@ -112,7 +116,7 @@ int make_lock_file_for(const char *p, int operation, LockFile *ret) {
         t = newa(char, strlen(p) + 2 + 4 + 1);
         stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), fn), ".lck");
 
-        return make_lock_file(t, operation, ret);
+        return make_lock_file(dfd, t, operation, ret);
 }
 
 void release_lock_file(LockFile *f) {
@@ -142,8 +146,9 @@ void release_lock_file(LockFile *f) {
                                 f->operation = LOCK_EX|LOCK_NB;
                 }
 
-                if ((f->operation & ~LOCK_NB) == LOCK_EX)
-                        unlink_noerrno(f->path);
+                if ((f->operation & ~LOCK_NB) == LOCK_EX) {
+                        unlinkat_noerrno(f->dfd, f->path, 0);
+                }
 
                 free(f->path);
                 f->path = NULL;
diff --git a/src/shared/lockfile-util.h b/src/shared/lockfile-util.h
index 38d4709..694b177 100644
--- a/src/shared/lockfile-util.h
+++ b/src/shared/lockfile-util.h
@@ -25,15 +25,16 @@
 #include "missing.h"
 
 typedef struct LockFile {
+        int dfd;
         char *path;
         int fd;
         int operation;
 } LockFile;
 
-int make_lock_file(const char *p, int operation, LockFile *ret);
-int make_lock_file_for(const char *p, int operation, LockFile *ret);
+int make_lock_file(int dfd, const char *p, int operation, LockFile *ret);
+int make_lock_file_for(int dfd, const char *p, int operation, LockFile *ret);
 void release_lock_file(LockFile *f);
 
 #define _cleanup_release_lock_file_ _cleanup_(release_lock_file)
 
-#define LOCK_FILE_INIT { .fd = -1, .path = NULL }
+#define LOCK_FILE_INIT { .fd = -1, .dfd = AT_FDCWD, .path = NULL }
diff --git a/src/shared/machine-image.c b/src/shared/machine-image.c
index bc215f0..4fefa0c 100644
--- a/src/shared/machine-image.c
+++ b/src/shared/machine-image.c
@@ -598,14 +598,14 @@ int image_path_lock(const char *path, int operation, LockFile *global, LockFile
                         return -ENOMEM;
         }
 
-        r = make_lock_file_for(path, operation, &t);
+        r = make_lock_file_for(AT_FDCWD, path, operation, &t);
         if (r < 0)
                 return r;
 
         if (p) {
                 mkdir_p("/run/systemd/nspawn/locks", 0600);
 
-                r = make_lock_file(p, operation, global);
+                r = make_lock_file(AT_FDCWD, p, operation, global);
                 if (r < 0) {
                         release_lock_file(&t);
                         return r;
@@ -646,7 +646,7 @@ int image_name_lock(const char *name, int operation, LockFile *ret) {
         mkdir_p("/run/systemd/nspawn/locks", 0600);
         p = strjoina("/run/systemd/nspawn/locks/name-", name);
 
-        return make_lock_file(p, operation, ret);
+        return make_lock_file(AT_FDCWD, p, operation, ret);
 }
 
 bool image_name_is_valid(const char *s) {
diff --git a/src/shared/machine-pool.c b/src/shared/machine-pool.c
index 9920d15..b0f3f54 100644
--- a/src/shared/machine-pool.c
+++ b/src/shared/machine-pool.c
@@ -181,7 +181,7 @@ int setup_machine_directory(uint64_t size, sd_bus_error *error) {
                 size = 16*1024*1024;
 
         /* Make sure we only set the directory up once at a time */
-        r = make_lock_file("/run/systemd/machines.lock", LOCK_EX, &lock_file);
+        r = make_lock_file(AT_FDCWD, "/run/systemd/machines.lock", LOCK_EX, &lock_file);
         if (r < 0)
                 return r;
 
-- 
1.8.3.1

_______________________________________________
systemd-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/systemd-devel

Reply via email to