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.
This commit is contained in:
committed by
Zbigniew Jędrzejewski-Szmek
parent
7e7cddb224
commit
cd2eb9e942
@@ -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 \
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 }
|
||||
@@ -22,6 +22,7 @@
|
||||
***/
|
||||
|
||||
#include "time-util.h"
|
||||
#include "lockfile-util.h"
|
||||
#include "hashmap.h"
|
||||
|
||||
typedef enum ImageType {
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user