mirror of
https://github.com/systemd/systemd.git
synced 2024-12-25 01:34:28 +03:00
Merge pull request #20471 from poettering/format-str-proc-fd
add FORMAT_PROC_FD_PATH() macro for generating /proc/self/fd/ paths on-the-fly
This commit is contained in:
commit
61a6aa21a5
@ -433,11 +433,9 @@ bool fdname_is_valid(const char *s) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int fd_get_path(int fd, char **ret) {
|
int fd_get_path(int fd, char **ret) {
|
||||||
char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
xsprintf(procfs_path, "/proc/self/fd/%i", fd);
|
r = readlink_malloc(FORMAT_PROC_FD_PATH(fd), ret);
|
||||||
r = readlink_malloc(procfs_path, ret);
|
|
||||||
if (r == -ENOENT) {
|
if (r == -ENOENT) {
|
||||||
/* ENOENT can mean two things: that the fd does not exist or that /proc is not mounted. Let's make
|
/* ENOENT can mean two things: that the fd does not exist or that /proc is not mounted. Let's make
|
||||||
* things debuggable and distinguish the two. */
|
* things debuggable and distinguish the two. */
|
||||||
@ -647,7 +645,6 @@ finish:
|
|||||||
}
|
}
|
||||||
|
|
||||||
int fd_reopen(int fd, int flags) {
|
int fd_reopen(int fd, int flags) {
|
||||||
char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
|
|
||||||
int new_fd;
|
int new_fd;
|
||||||
|
|
||||||
/* Reopens the specified fd with new flags. This is useful for convert an O_PATH fd into a regular one, or to
|
/* Reopens the specified fd with new flags. This is useful for convert an O_PATH fd into a regular one, or to
|
||||||
@ -657,8 +654,7 @@ int fd_reopen(int fd, int flags) {
|
|||||||
*
|
*
|
||||||
* This implicitly resets the file read index to 0. */
|
* This implicitly resets the file read index to 0. */
|
||||||
|
|
||||||
xsprintf(procfs_path, "/proc/self/fd/%i", fd);
|
new_fd = open(FORMAT_PROC_FD_PATH(fd), flags);
|
||||||
new_fd = open(procfs_path, flags);
|
|
||||||
if (new_fd < 0) {
|
if (new_fd < 0) {
|
||||||
if (errno != ENOENT)
|
if (errno != ENOENT)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
|
#include "stdio-util.h"
|
||||||
|
|
||||||
/* maximum length of fdname */
|
/* maximum length of fdname */
|
||||||
#define FDNAME_MAX 255
|
#define FDNAME_MAX 255
|
||||||
@ -104,7 +105,20 @@ static inline int make_null_stdio(void) {
|
|||||||
0; \
|
0; \
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
int fd_reopen(int fd, int flags);
|
int fd_reopen(int fd, int flags);
|
||||||
int read_nr_open(void);
|
int read_nr_open(void);
|
||||||
int btrfs_defrag_fd(int fd);
|
int btrfs_defrag_fd(int fd);
|
||||||
|
|
||||||
|
/* The maximum length a buffer for a /proc/self/fd/<fd> path needs */
|
||||||
|
#define PROC_FD_PATH_MAX \
|
||||||
|
(STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int))
|
||||||
|
|
||||||
|
static inline char *format_proc_fd_path(char buf[static PROC_FD_PATH_MAX], int fd) {
|
||||||
|
assert(buf);
|
||||||
|
assert(fd >= 0);
|
||||||
|
assert_se(snprintf_ok(buf, PROC_FD_PATH_MAX, "/proc/self/fd/%i", fd));
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define FORMAT_PROC_FD_PATH(fd) \
|
||||||
|
format_proc_fd_path((char[PROC_FD_PATH_MAX]) {}, (fd))
|
||||||
|
@ -721,8 +721,6 @@ int read_full_file_full(
|
|||||||
if (dir_fd == AT_FDCWD)
|
if (dir_fd == AT_FDCWD)
|
||||||
r = sockaddr_un_set_path(&sa.un, filename);
|
r = sockaddr_un_set_path(&sa.un, filename);
|
||||||
else {
|
else {
|
||||||
char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
|
|
||||||
|
|
||||||
/* If we shall operate relative to some directory, then let's use O_PATH first to
|
/* If we shall operate relative to some directory, then let's use O_PATH first to
|
||||||
* open the socket inode, and then connect to it via /proc/self/fd/. We have to do
|
* open the socket inode, and then connect to it via /proc/self/fd/. We have to do
|
||||||
* this since there's not connectat() that takes a directory fd as first arg. */
|
* this since there's not connectat() that takes a directory fd as first arg. */
|
||||||
@ -731,8 +729,7 @@ int read_full_file_full(
|
|||||||
if (dfd < 0)
|
if (dfd < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
xsprintf(procfs_path, "/proc/self/fd/%i", dfd);
|
r = sockaddr_un_set_path(&sa.un, FORMAT_PROC_FD_PATH(dfd));
|
||||||
r = sockaddr_un_set_path(&sa.un, procfs_path);
|
|
||||||
}
|
}
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
@ -308,14 +308,11 @@ int fchmod_umask(int fd, mode_t m) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int fchmod_opath(int fd, mode_t m) {
|
int fchmod_opath(int fd, mode_t m) {
|
||||||
char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
|
|
||||||
|
|
||||||
/* This function operates also on fd that might have been opened with
|
/* This function operates also on fd that might have been opened with
|
||||||
* O_PATH. Indeed fchmodat() doesn't have the AT_EMPTY_PATH flag like
|
* O_PATH. Indeed fchmodat() doesn't have the AT_EMPTY_PATH flag like
|
||||||
* fchownat() does. */
|
* fchownat() does. */
|
||||||
|
|
||||||
xsprintf(procfs_path, "/proc/self/fd/%i", fd);
|
if (chmod(FORMAT_PROC_FD_PATH(fd), m) < 0) {
|
||||||
if (chmod(procfs_path, m) < 0) {
|
|
||||||
if (errno != ENOENT)
|
if (errno != ENOENT)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
@ -329,12 +326,9 @@ int fchmod_opath(int fd, mode_t m) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int futimens_opath(int fd, const struct timespec ts[2]) {
|
int futimens_opath(int fd, const struct timespec ts[2]) {
|
||||||
char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
|
|
||||||
|
|
||||||
/* Similar to fchmod_path() but for futimens() */
|
/* Similar to fchmod_path() but for futimens() */
|
||||||
|
|
||||||
xsprintf(procfs_path, "/proc/self/fd/%i", fd);
|
if (utimensat(AT_FDCWD, FORMAT_PROC_FD_PATH(fd), ts, 0) < 0) {
|
||||||
if (utimensat(AT_FDCWD, procfs_path, ts, 0) < 0) {
|
|
||||||
if (errno != ENOENT)
|
if (errno != ENOENT)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
@ -380,7 +374,6 @@ int fd_warn_permissions(const char *path, int fd) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode) {
|
int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode) {
|
||||||
char fdpath[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
|
|
||||||
_cleanup_close_ int fd = -1;
|
_cleanup_close_ int fd = -1;
|
||||||
int r, ret = 0;
|
int r, ret = 0;
|
||||||
|
|
||||||
@ -412,8 +405,6 @@ int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gi
|
|||||||
/* Let's make a path from the fd, and operate on that. With this logic, we can adjust the access mode,
|
/* Let's make a path from the fd, and operate on that. With this logic, we can adjust the access mode,
|
||||||
* ownership and time of the file node in all cases, even if the fd refers to an O_PATH object — which is
|
* ownership and time of the file node in all cases, even if the fd refers to an O_PATH object — which is
|
||||||
* something fchown(), fchmod(), futimensat() don't allow. */
|
* something fchown(), fchmod(), futimensat() don't allow. */
|
||||||
xsprintf(fdpath, "/proc/self/fd/%i", fd);
|
|
||||||
|
|
||||||
ret = fchmod_and_chown(fd, mode, uid, gid);
|
ret = fchmod_and_chown(fd, mode, uid, gid);
|
||||||
|
|
||||||
if (stamp != USEC_INFINITY) {
|
if (stamp != USEC_INFINITY) {
|
||||||
@ -421,9 +412,9 @@ int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gi
|
|||||||
|
|
||||||
timespec_store(&ts[0], stamp);
|
timespec_store(&ts[0], stamp);
|
||||||
ts[1] = ts[0];
|
ts[1] = ts[0];
|
||||||
r = utimensat(AT_FDCWD, fdpath, ts, 0);
|
r = utimensat(AT_FDCWD, FORMAT_PROC_FD_PATH(fd), ts, 0);
|
||||||
} else
|
} else
|
||||||
r = utimensat(AT_FDCWD, fdpath, NULL, 0);
|
r = utimensat(AT_FDCWD, FORMAT_PROC_FD_PATH(fd), NULL, 0);
|
||||||
if (r < 0 && ret >= 0)
|
if (r < 0 && ret >= 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
@ -703,13 +694,10 @@ int unlink_or_warn(const char *filename) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int inotify_add_watch_fd(int fd, int what, uint32_t mask) {
|
int inotify_add_watch_fd(int fd, int what, uint32_t mask) {
|
||||||
char path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
|
|
||||||
int wd;
|
int wd;
|
||||||
|
|
||||||
/* This is like inotify_add_watch(), except that the file to watch is not referenced by a path, but by an fd */
|
/* This is like inotify_add_watch(), except that the file to watch is not referenced by a path, but by an fd */
|
||||||
xsprintf(path, "/proc/self/fd/%i", what);
|
wd = inotify_add_watch(fd, FORMAT_PROC_FD_PATH(what), mask);
|
||||||
|
|
||||||
wd = inotify_add_watch(fd, path, mask);
|
|
||||||
if (wd < 0)
|
if (wd < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
@ -1156,7 +1144,6 @@ int chase_symlinks_and_opendir(
|
|||||||
char **ret_path,
|
char **ret_path,
|
||||||
DIR **ret_dir) {
|
DIR **ret_dir) {
|
||||||
|
|
||||||
char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
|
|
||||||
_cleanup_close_ int path_fd = -1;
|
_cleanup_close_ int path_fd = -1;
|
||||||
_cleanup_free_ char *p = NULL;
|
_cleanup_free_ char *p = NULL;
|
||||||
DIR *d;
|
DIR *d;
|
||||||
@ -1182,8 +1169,7 @@ int chase_symlinks_and_opendir(
|
|||||||
return r;
|
return r;
|
||||||
assert(path_fd >= 0);
|
assert(path_fd >= 0);
|
||||||
|
|
||||||
xsprintf(procfs_path, "/proc/self/fd/%i", path_fd);
|
d = opendir(FORMAT_PROC_FD_PATH(path_fd));
|
||||||
d = opendir(procfs_path);
|
|
||||||
if (!d)
|
if (!d)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
@ -1237,12 +1223,9 @@ int chase_symlinks_and_stat(
|
|||||||
}
|
}
|
||||||
|
|
||||||
int access_fd(int fd, int mode) {
|
int access_fd(int fd, int mode) {
|
||||||
char p[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(fd) + 1];
|
|
||||||
|
|
||||||
/* Like access() but operates on an already open fd */
|
/* Like access() but operates on an already open fd */
|
||||||
|
|
||||||
xsprintf(p, "/proc/self/fd/%i", fd);
|
if (access(FORMAT_PROC_FD_PATH(fd), mode) < 0) {
|
||||||
if (access(p, mode) < 0) {
|
|
||||||
if (errno != ENOENT)
|
if (errno != ENOENT)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
|
@ -89,9 +89,7 @@ int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int
|
|||||||
/* Can't setns to your own userns, since then you could escalate from non-root to root in
|
/* Can't setns to your own userns, since then you could escalate from non-root to root in
|
||||||
* your own namespace, so check if namespaces are equal before attempting to enter. */
|
* your own namespace, so check if namespaces are equal before attempting to enter. */
|
||||||
|
|
||||||
char userns_fd_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
|
r = files_same(FORMAT_PROC_FD_PATH(userns_fd), "/proc/self/ns/user", 0);
|
||||||
xsprintf(userns_fd_path, "/proc/self/fd/%d", userns_fd);
|
|
||||||
r = files_same(userns_fd_path, "/proc/self/ns/user", 0);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
if (r)
|
if (r)
|
||||||
|
@ -10,7 +10,12 @@
|
|||||||
#include "memory-util.h"
|
#include "memory-util.h"
|
||||||
|
|
||||||
#define snprintf_ok(buf, len, fmt, ...) \
|
#define snprintf_ok(buf, len, fmt, ...) \
|
||||||
((size_t) snprintf(buf, len, fmt, __VA_ARGS__) < (len))
|
({ \
|
||||||
|
char *_buf = (buf); \
|
||||||
|
size_t _len = (len); \
|
||||||
|
int _snpf = snprintf(_buf, _len, (fmt), __VA_ARGS__); \
|
||||||
|
_snpf >= 0 && (size_t) _snpf < _len ? _buf : NULL; \
|
||||||
|
})
|
||||||
|
|
||||||
#define xsprintf(buf, fmt, ...) \
|
#define xsprintf(buf, fmt, ...) \
|
||||||
assert_message_se(snprintf_ok(buf, ELEMENTSOF(buf), fmt, __VA_ARGS__), "xsprintf: " #buf "[] must be big enough")
|
assert_message_se(snprintf_ok(buf, ELEMENTSOF(buf), fmt, __VA_ARGS__), "xsprintf: " #buf "[] must be big enough")
|
||||||
|
@ -300,11 +300,7 @@ int link_tmpfile(int fd, const char *path, const char *target) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
} else {
|
} else {
|
||||||
char proc_fd_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(fd) + 1];
|
if (linkat(AT_FDCWD, FORMAT_PROC_FD_PATH(fd), AT_FDCWD, target, AT_SYMLINK_FOLLOW) < 0)
|
||||||
|
|
||||||
xsprintf(proc_fd_path, "/proc/self/fd/%i", fd);
|
|
||||||
|
|
||||||
if (linkat(AT_FDCWD, proc_fd_path, AT_FDCWD, target, AT_SYMLINK_FOLLOW) < 0)
|
|
||||||
return -errno;
|
return -errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,11 +108,10 @@ static int getxattrat_fake_prepare(
|
|||||||
int dirfd,
|
int dirfd,
|
||||||
const char *filename,
|
const char *filename,
|
||||||
int flags,
|
int flags,
|
||||||
char ret_fn[static STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1],
|
char ret_fn[static PROC_FD_PATH_MAX],
|
||||||
int *ret_fd) {
|
int *ret_fd) {
|
||||||
|
|
||||||
_cleanup_close_ int fd = -1;
|
_cleanup_close_ int fd = -1;
|
||||||
|
|
||||||
assert(ret_fn);
|
assert(ret_fn);
|
||||||
assert(ret_fd);
|
assert(ret_fd);
|
||||||
|
|
||||||
@ -125,13 +124,15 @@ static int getxattrat_fake_prepare(
|
|||||||
if (!(flags & AT_EMPTY_PATH))
|
if (!(flags & AT_EMPTY_PATH))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
snprintf(ret_fn, STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1, "/proc/self/fd/%i", dirfd);
|
assert(dirfd >= 0);
|
||||||
|
|
||||||
|
format_proc_fd_path(ret_fn, dirfd);
|
||||||
} else {
|
} else {
|
||||||
fd = openat(dirfd, filename, O_CLOEXEC|O_PATH|(flags & AT_SYMLINK_NOFOLLOW ? O_NOFOLLOW : 0));
|
fd = openat(dirfd, filename, O_CLOEXEC|O_PATH|(flags & AT_SYMLINK_NOFOLLOW ? O_NOFOLLOW : 0));
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
snprintf(ret_fn, STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1, "/proc/self/fd/%i", fd);
|
format_proc_fd_path(ret_fn, fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Pass the FD to the caller, since in case we do openat() the filename depends on it. */
|
/* Pass the FD to the caller, since in case we do openat() the filename depends on it. */
|
||||||
@ -148,8 +149,8 @@ int fgetxattrat_fake(
|
|||||||
int flags,
|
int flags,
|
||||||
size_t *ret_size) {
|
size_t *ret_size) {
|
||||||
|
|
||||||
char fn[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
|
|
||||||
_cleanup_close_ int fd = -1;
|
_cleanup_close_ int fd = -1;
|
||||||
|
char fn[PROC_FD_PATH_MAX];
|
||||||
ssize_t l;
|
ssize_t l;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -172,8 +173,8 @@ int fgetxattrat_fake_malloc(
|
|||||||
int flags,
|
int flags,
|
||||||
char **value) {
|
char **value) {
|
||||||
|
|
||||||
char fn[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
|
|
||||||
_cleanup_close_ int fd = -1;
|
_cleanup_close_ int fd = -1;
|
||||||
|
char fn[PROC_FD_PATH_MAX];
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
r = getxattrat_fake_prepare(dirfd, filename, flags, fn, &fd);
|
r = getxattrat_fake_prepare(dirfd, filename, flags, fn, &fd);
|
||||||
|
@ -916,7 +916,6 @@ static int service_is_suitable_main_pid(Service *s, pid_t pid, int prio) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int service_load_pid_file(Service *s, bool may_warn) {
|
static int service_load_pid_file(Service *s, bool may_warn) {
|
||||||
char procfs[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
|
|
||||||
bool questionable_pid_file = false;
|
bool questionable_pid_file = false;
|
||||||
_cleanup_free_ char *k = NULL;
|
_cleanup_free_ char *k = NULL;
|
||||||
_cleanup_close_ int fd = -1;
|
_cleanup_close_ int fd = -1;
|
||||||
@ -945,8 +944,7 @@ static int service_load_pid_file(Service *s, bool may_warn) {
|
|||||||
|
|
||||||
/* Let's read the PID file now that we chased it down. But we need to convert the O_PATH fd
|
/* Let's read the PID file now that we chased it down. But we need to convert the O_PATH fd
|
||||||
* chase_symlinks() returned us into a proper fd first. */
|
* chase_symlinks() returned us into a proper fd first. */
|
||||||
xsprintf(procfs, "/proc/self/fd/%i", fd);
|
r = read_one_line_file(FORMAT_PROC_FD_PATH(fd), &k);
|
||||||
r = read_one_line_file(procfs, &k);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_unit_error_errno(UNIT(s), r,
|
return log_unit_error_errno(UNIT(s), r,
|
||||||
"Can't convert PID files %s O_PATH file descriptor to proper file descriptor: %m",
|
"Can't convert PID files %s O_PATH file descriptor to proper file descriptor: %m",
|
||||||
|
@ -22,7 +22,6 @@
|
|||||||
#if HAVE_ACL
|
#if HAVE_ACL
|
||||||
|
|
||||||
static int get_acl(int fd, const char *name, acl_type_t type, acl_t *ret) {
|
static int get_acl(int fd, const char *name, acl_type_t type, acl_t *ret) {
|
||||||
char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
|
|
||||||
acl_t acl;
|
acl_t acl;
|
||||||
|
|
||||||
assert(fd >= 0);
|
assert(fd >= 0);
|
||||||
@ -35,14 +34,11 @@ static int get_acl(int fd, const char *name, acl_type_t type, acl_t *ret) {
|
|||||||
if (child_fd < 0)
|
if (child_fd < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
xsprintf(procfs_path, "/proc/self/fd/%i", child_fd);
|
acl = acl_get_file(FORMAT_PROC_FD_PATH(child_fd), type);
|
||||||
acl = acl_get_file(procfs_path, type);
|
|
||||||
} else if (type == ACL_TYPE_ACCESS)
|
} else if (type == ACL_TYPE_ACCESS)
|
||||||
acl = acl_get_fd(fd);
|
acl = acl_get_fd(fd);
|
||||||
else {
|
else
|
||||||
xsprintf(procfs_path, "/proc/self/fd/%i", fd);
|
acl = acl_get_file(FORMAT_PROC_FD_PATH(fd), type);
|
||||||
acl = acl_get_file(procfs_path, type);
|
|
||||||
}
|
|
||||||
if (!acl)
|
if (!acl)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
@ -51,7 +47,6 @@ static int get_acl(int fd, const char *name, acl_type_t type, acl_t *ret) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int set_acl(int fd, const char *name, acl_type_t type, acl_t acl) {
|
static int set_acl(int fd, const char *name, acl_type_t type, acl_t acl) {
|
||||||
char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(fd >= 0);
|
assert(fd >= 0);
|
||||||
@ -64,14 +59,11 @@ static int set_acl(int fd, const char *name, acl_type_t type, acl_t acl) {
|
|||||||
if (child_fd < 0)
|
if (child_fd < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
xsprintf(procfs_path, "/proc/self/fd/%i", child_fd);
|
r = acl_set_file(FORMAT_PROC_FD_PATH(child_fd), type, acl);
|
||||||
r = acl_set_file(procfs_path, type, acl);
|
|
||||||
} else if (type == ACL_TYPE_ACCESS)
|
} else if (type == ACL_TYPE_ACCESS)
|
||||||
r = acl_set_fd(fd, acl);
|
r = acl_set_fd(fd, acl);
|
||||||
else {
|
else
|
||||||
xsprintf(procfs_path, "/proc/self/fd/%i", fd);
|
r = acl_set_file(FORMAT_PROC_FD_PATH(fd), type, acl);
|
||||||
r = acl_set_file(procfs_path, type, acl);
|
|
||||||
}
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
|
@ -1581,12 +1581,8 @@ static int context_load_partition_table(
|
|||||||
* /proc/self/fd/ magic path if we have an existing fd. Open the original file otherwise. */
|
* /proc/self/fd/ magic path if we have an existing fd. Open the original file otherwise. */
|
||||||
if (*backing_fd < 0)
|
if (*backing_fd < 0)
|
||||||
r = fdisk_assign_device(c, node, arg_dry_run);
|
r = fdisk_assign_device(c, node, arg_dry_run);
|
||||||
else {
|
else
|
||||||
char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
|
r = fdisk_assign_device(c, FORMAT_PROC_FD_PATH(*backing_fd), arg_dry_run);
|
||||||
xsprintf(procfs_path, "/proc/self/fd/%i", *backing_fd);
|
|
||||||
|
|
||||||
r = fdisk_assign_device(c, procfs_path, arg_dry_run);
|
|
||||||
}
|
|
||||||
if (r == -EINVAL && arg_size_auto) {
|
if (r == -EINVAL && arg_size_auto) {
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
@ -4593,7 +4589,6 @@ static int find_root(char **ret, int *ret_fd) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int resize_pt(int fd) {
|
static int resize_pt(int fd) {
|
||||||
char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
|
|
||||||
_cleanup_(fdisk_unref_contextp) struct fdisk_context *c = NULL;
|
_cleanup_(fdisk_unref_contextp) struct fdisk_context *c = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -4605,14 +4600,13 @@ static int resize_pt(int fd) {
|
|||||||
if (!c)
|
if (!c)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
xsprintf(procfs_path, "/proc/self/fd/%i", fd);
|
r = fdisk_assign_device(c, FORMAT_PROC_FD_PATH(fd), 0);
|
||||||
r = fdisk_assign_device(c, procfs_path, 0);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to open device '%s': %m", procfs_path);
|
return log_error_errno(r, "Failed to open device '%s': %m", FORMAT_PROC_FD_PATH(fd));
|
||||||
|
|
||||||
r = fdisk_has_label(c);
|
r = fdisk_has_label(c);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to determine whether disk '%s' has a disk label: %m", procfs_path);
|
return log_error_errno(r, "Failed to determine whether disk '%s' has a disk label: %m", FORMAT_PROC_FD_PATH(fd));
|
||||||
if (r == 0) {
|
if (r == 0) {
|
||||||
log_debug("Not resizing partition table, as there currently is none.");
|
log_debug("Not resizing partition table, as there currently is none.");
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -21,7 +21,6 @@ static int chown_one(
|
|||||||
gid_t gid,
|
gid_t gid,
|
||||||
mode_t mask) {
|
mode_t mask) {
|
||||||
|
|
||||||
char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
|
|
||||||
const char *n;
|
const char *n;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -30,11 +29,10 @@ static int chown_one(
|
|||||||
|
|
||||||
/* We change ACLs through the /proc/self/fd/%i path, so that we have a stable reference that works
|
/* We change ACLs through the /proc/self/fd/%i path, so that we have a stable reference that works
|
||||||
* with O_PATH. */
|
* with O_PATH. */
|
||||||
xsprintf(procfs_path, "/proc/self/fd/%i", fd);
|
|
||||||
|
|
||||||
/* Drop any ACL if there is one */
|
/* Drop any ACL if there is one */
|
||||||
FOREACH_STRING(n, "system.posix_acl_access", "system.posix_acl_default")
|
FOREACH_STRING(n, "system.posix_acl_access", "system.posix_acl_default")
|
||||||
if (removexattr(procfs_path, n) < 0)
|
if (removexattr(FORMAT_PROC_FD_PATH(fd), n) < 0)
|
||||||
if (!IN_SET(errno, ENODATA, EOPNOTSUPP, ENOSYS, ENOTTY))
|
if (!IN_SET(errno, ENODATA, EOPNOTSUPP, ENOSYS, ENOTTY))
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
|
@ -305,7 +305,7 @@ static int image_make(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Get directory creation time (not available everywhere, but that's OK */
|
/* Get directory creation time (not available everywhere, but that's OK */
|
||||||
(void) fd_getcrtime(dfd, &crtime);
|
(void) fd_getcrtime(fd, &crtime);
|
||||||
|
|
||||||
/* If the IMMUTABLE bit is set, we consider the directory read-only. Since the ioctl is not
|
/* If the IMMUTABLE bit is set, we consider the directory read-only. Since the ioctl is not
|
||||||
* supported everywhere we ignore failures. */
|
* supported everywhere we ignore failures. */
|
||||||
|
@ -42,10 +42,7 @@ int mount_fd(const char *source,
|
|||||||
unsigned long mountflags,
|
unsigned long mountflags,
|
||||||
const void *data) {
|
const void *data) {
|
||||||
|
|
||||||
char path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
|
if (mount(source, FORMAT_PROC_FD_PATH(target_fd), filesystemtype, mountflags, data) < 0) {
|
||||||
|
|
||||||
xsprintf(path, "/proc/self/fd/%i", target_fd);
|
|
||||||
if (mount(source, path, filesystemtype, mountflags, data) < 0) {
|
|
||||||
if (errno != ENOENT)
|
if (errno != ENOENT)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
@ -733,8 +730,7 @@ static int mount_in_namespace(
|
|||||||
|
|
||||||
_cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
|
_cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
|
||||||
_cleanup_close_ int self_mntns_fd = -1, mntns_fd = -1, root_fd = -1, pidns_fd = -1, chased_src_fd = -1;
|
_cleanup_close_ int self_mntns_fd = -1, mntns_fd = -1, root_fd = -1, pidns_fd = -1, chased_src_fd = -1;
|
||||||
char mount_slave[] = "/tmp/propagate.XXXXXX", *mount_tmp, *mount_outside, *p,
|
char mount_slave[] = "/tmp/propagate.XXXXXX", *mount_tmp, *mount_outside, *p;
|
||||||
chased_src[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
|
|
||||||
bool mount_slave_created = false, mount_slave_mounted = false,
|
bool mount_slave_created = false, mount_slave_mounted = false,
|
||||||
mount_tmp_created = false, mount_tmp_mounted = false,
|
mount_tmp_created = false, mount_tmp_mounted = false,
|
||||||
mount_outside_created = false, mount_outside_mounted = false;
|
mount_outside_created = false, mount_outside_mounted = false;
|
||||||
@ -767,9 +763,8 @@ static int mount_in_namespace(
|
|||||||
if (st.st_ino == self_mntns_st.st_ino && st.st_dev == self_mntns_st.st_dev)
|
if (st.st_ino == self_mntns_st.st_ino && st.st_dev == self_mntns_st.st_dev)
|
||||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to activate bind mount in target, not running in a mount namespace");
|
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to activate bind mount in target, not running in a mount namespace");
|
||||||
|
|
||||||
/* One day, when bind mounting /proc/self/fd/n works across
|
/* One day, when bind mounting /proc/self/fd/n works across namespace boundaries we should rework
|
||||||
* namespace boundaries we should rework this logic to make
|
* this logic to make use of it... */
|
||||||
* use of it... */
|
|
||||||
|
|
||||||
p = strjoina(propagate_path, "/");
|
p = strjoina(propagate_path, "/");
|
||||||
r = laccess(p, F_OK);
|
r = laccess(p, F_OK);
|
||||||
@ -779,7 +774,6 @@ static int mount_in_namespace(
|
|||||||
r = chase_symlinks(src, NULL, CHASE_TRAIL_SLASH, NULL, &chased_src_fd);
|
r = chase_symlinks(src, NULL, CHASE_TRAIL_SLASH, NULL, &chased_src_fd);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_debug_errno(r, "Failed to resolve source path of %s: %m", src);
|
return log_debug_errno(r, "Failed to resolve source path of %s: %m", src);
|
||||||
xsprintf(chased_src, "/proc/self/fd/%i", chased_src_fd);
|
|
||||||
|
|
||||||
if (fstat(chased_src_fd, &st) < 0)
|
if (fstat(chased_src_fd, &st) < 0)
|
||||||
return log_debug_errno(errno, "Failed to stat() resolved source path %s: %m", src);
|
return log_debug_errno(errno, "Failed to stat() resolved source path %s: %m", src);
|
||||||
@ -824,9 +818,9 @@ static int mount_in_namespace(
|
|||||||
mount_tmp_created = true;
|
mount_tmp_created = true;
|
||||||
|
|
||||||
if (is_image)
|
if (is_image)
|
||||||
r = verity_dissect_and_mount(chased_src, mount_tmp, options, NULL, NULL, NULL);
|
r = verity_dissect_and_mount(FORMAT_PROC_FD_PATH(chased_src_fd), mount_tmp, options, NULL, NULL, NULL);
|
||||||
else
|
else
|
||||||
r = mount_follow_verbose(LOG_DEBUG, chased_src, mount_tmp, NULL, MS_BIND, NULL);
|
r = mount_follow_verbose(LOG_DEBUG, FORMAT_PROC_FD_PATH(chased_src_fd), mount_tmp, NULL, MS_BIND, NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto finish;
|
goto finish;
|
||||||
|
|
||||||
|
@ -266,7 +266,6 @@ int mac_selinux_fix_container_fd(int fd, const char *path, const char *inside_pa
|
|||||||
assert(inside_path);
|
assert(inside_path);
|
||||||
|
|
||||||
#if HAVE_SELINUX
|
#if HAVE_SELINUX
|
||||||
char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
|
|
||||||
_cleanup_freecon_ char* fcon = NULL;
|
_cleanup_freecon_ char* fcon = NULL;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
int r;
|
int r;
|
||||||
@ -292,8 +291,7 @@ int mac_selinux_fix_container_fd(int fd, const char *path, const char *inside_pa
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
xsprintf(procfs_path, "/proc/self/fd/%i", fd);
|
if (setfilecon_raw(FORMAT_PROC_FD_PATH(fd), fcon) < 0) {
|
||||||
if (setfilecon_raw(procfs_path, fcon) < 0) {
|
|
||||||
_cleanup_freecon_ char *oldcon = NULL;
|
_cleanup_freecon_ char *oldcon = NULL;
|
||||||
|
|
||||||
/* If the FS doesn't support labels, then exit without warning */
|
/* If the FS doesn't support labels, then exit without warning */
|
||||||
@ -307,7 +305,7 @@ int mac_selinux_fix_container_fd(int fd, const char *path, const char *inside_pa
|
|||||||
r = -errno;
|
r = -errno;
|
||||||
|
|
||||||
/* If the old label is identical to the new one, suppress any kind of error */
|
/* If the old label is identical to the new one, suppress any kind of error */
|
||||||
if (getfilecon_raw(procfs_path, &oldcon) >= 0 && streq(fcon, oldcon))
|
if (getfilecon_raw(FORMAT_PROC_FD_PATH(fd), &oldcon) >= 0 && streq(fcon, oldcon))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -122,7 +122,6 @@ int mac_smack_apply_pid(pid_t pid, const char *label) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int smack_fix_fd(int fd, const char *abspath, LabelFixFlags flags) {
|
static int smack_fix_fd(int fd, const char *abspath, LabelFixFlags flags) {
|
||||||
char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
|
|
||||||
const char *label;
|
const char *label;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
int r;
|
int r;
|
||||||
@ -153,8 +152,7 @@ static int smack_fix_fd(int fd , const char *abspath, LabelFixFlags flags) {
|
|||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
xsprintf(procfs_path, "/proc/self/fd/%i", fd);
|
if (setxattr(FORMAT_PROC_FD_PATH(fd), "security.SMACK64", label, strlen(label), 0) < 0) {
|
||||||
if (setxattr(procfs_path, "security.SMACK64", label, strlen(label), 0) < 0) {
|
|
||||||
_cleanup_free_ char *old_label = NULL;
|
_cleanup_free_ char *old_label = NULL;
|
||||||
|
|
||||||
r = -errno;
|
r = -errno;
|
||||||
@ -168,7 +166,7 @@ static int smack_fix_fd(int fd , const char *abspath, LabelFixFlags flags) {
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* If the old label is identical to the new one, suppress any kind of error */
|
/* If the old label is identical to the new one, suppress any kind of error */
|
||||||
if (getxattr_malloc(procfs_path, "security.SMACK64", &old_label, false) >= 0 &&
|
if (getxattr_malloc(FORMAT_PROC_FD_PATH(fd), "security.SMACK64", &old_label, false) >= 0 &&
|
||||||
streq(old_label, label))
|
streq(old_label, label))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -50,12 +50,8 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
|||||||
else
|
else
|
||||||
log_info(r == 0 ? "Done!" : "Action!");
|
log_info(r == 0 ? "Done!" : "Action!");
|
||||||
|
|
||||||
if (orig_stdout_fd >= 0) {
|
if (orig_stdout_fd >= 0)
|
||||||
char path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
|
assert_se(freopen(FORMAT_PROC_FD_PATH(orig_stdout_fd), "w", stdout));
|
||||||
|
|
||||||
xsprintf(path, "/proc/self/fd/%d", orig_stdout_fd);
|
|
||||||
assert_se(freopen(path, "w", stdout));
|
|
||||||
}
|
|
||||||
|
|
||||||
release_busses(); /* We open the bus for communication with logind.
|
release_busses(); /* We open the bus for communication with logind.
|
||||||
* It needs to be closed to avoid apparent leaks. */
|
* It needs to be closed to avoid apparent leaks. */
|
||||||
|
@ -278,6 +278,14 @@ static void test_close_all_fds(void) {
|
|||||||
log_open();
|
log_open();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_format_proc_fd_path(void) {
|
||||||
|
assert_se(streq_ptr(FORMAT_PROC_FD_PATH(0), "/proc/self/fd/0"));
|
||||||
|
assert_se(streq_ptr(FORMAT_PROC_FD_PATH(1), "/proc/self/fd/1"));
|
||||||
|
assert_se(streq_ptr(FORMAT_PROC_FD_PATH(2), "/proc/self/fd/2"));
|
||||||
|
assert_se(streq_ptr(FORMAT_PROC_FD_PATH(3), "/proc/self/fd/3"));
|
||||||
|
assert_se(streq_ptr(FORMAT_PROC_FD_PATH(2147483647), "/proc/self/fd/2147483647"));
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
test_setup_logging(LOG_DEBUG);
|
test_setup_logging(LOG_DEBUG);
|
||||||
@ -290,6 +298,7 @@ int main(int argc, char *argv[]) {
|
|||||||
test_rearrange_stdio();
|
test_rearrange_stdio();
|
||||||
test_read_nr_open();
|
test_read_nr_open();
|
||||||
test_close_all_fds();
|
test_close_all_fds();
|
||||||
|
test_format_proc_fd_path();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1058,18 +1058,15 @@ static int parse_xattrs_from_arg(Item *i) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int fd_set_xattrs(Item *i, int fd, const char *path, const struct stat *st) {
|
static int fd_set_xattrs(Item *i, int fd, const char *path, const struct stat *st) {
|
||||||
char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
|
|
||||||
char **name, **value;
|
char **name, **value;
|
||||||
|
|
||||||
assert(i);
|
assert(i);
|
||||||
assert(fd >= 0);
|
assert(fd >= 0);
|
||||||
assert(path);
|
assert(path);
|
||||||
|
|
||||||
xsprintf(procfs_path, "/proc/self/fd/%i", fd);
|
|
||||||
|
|
||||||
STRV_FOREACH_PAIR(name, value, i->xattrs) {
|
STRV_FOREACH_PAIR(name, value, i->xattrs) {
|
||||||
log_debug("Setting extended attribute '%s=%s' on %s.", *name, *value, path);
|
log_debug("Setting extended attribute '%s=%s' on %s.", *name, *value, path);
|
||||||
if (setxattr(procfs_path, *name, *value, strlen(*value), 0) < 0)
|
if (setxattr(FORMAT_PROC_FD_PATH(fd), *name, *value, strlen(*value), 0) < 0)
|
||||||
return log_error_errno(errno, "Setting extended attribute %s=%s on %s failed: %m",
|
return log_error_errno(errno, "Setting extended attribute %s=%s on %s failed: %m",
|
||||||
*name, *value, path);
|
*name, *value, path);
|
||||||
}
|
}
|
||||||
@ -1161,7 +1158,6 @@ static int path_set_acl(const char *path, const char *pretty, acl_type_t type, a
|
|||||||
static int fd_set_acls(Item *item, int fd, const char *path, const struct stat *st) {
|
static int fd_set_acls(Item *item, int fd, const char *path, const struct stat *st) {
|
||||||
int r = 0;
|
int r = 0;
|
||||||
#if HAVE_ACL
|
#if HAVE_ACL
|
||||||
char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
|
|
||||||
struct stat stbuf;
|
struct stat stbuf;
|
||||||
|
|
||||||
assert(item);
|
assert(item);
|
||||||
@ -1184,14 +1180,12 @@ static int fd_set_acls(Item *item, int fd, const char *path, const struct stat *
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
xsprintf(procfs_path, "/proc/self/fd/%i", fd);
|
|
||||||
|
|
||||||
if (item->acl_access)
|
if (item->acl_access)
|
||||||
r = path_set_acl(procfs_path, path, ACL_TYPE_ACCESS, item->acl_access, item->append_or_force);
|
r = path_set_acl(FORMAT_PROC_FD_PATH(fd), path, ACL_TYPE_ACCESS, item->acl_access, item->append_or_force);
|
||||||
|
|
||||||
/* set only default acls to folders */
|
/* set only default acls to folders */
|
||||||
if (r == 0 && item->acl_default && S_ISDIR(st->st_mode))
|
if (r == 0 && item->acl_default && S_ISDIR(st->st_mode))
|
||||||
r = path_set_acl(procfs_path, path, ACL_TYPE_DEFAULT, item->acl_default, item->append_or_force);
|
r = path_set_acl(FORMAT_PROC_FD_PATH(fd), path, ACL_TYPE_DEFAULT, item->acl_default, item->append_or_force);
|
||||||
|
|
||||||
if (ERRNO_IS_NOT_SUPPORTED(r)) {
|
if (ERRNO_IS_NOT_SUPPORTED(r)) {
|
||||||
log_debug_errno(r, "ACLs not supported by file system at %s", path);
|
log_debug_errno(r, "ACLs not supported by file system at %s", path);
|
||||||
@ -1938,17 +1932,14 @@ static int item_do(Item *i, int fd, const char *path, fdaction_t action) {
|
|||||||
r = action(i, fd, path, &st);
|
r = action(i, fd, path, &st);
|
||||||
|
|
||||||
if (S_ISDIR(st.st_mode)) {
|
if (S_ISDIR(st.st_mode)) {
|
||||||
char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
|
|
||||||
_cleanup_closedir_ DIR *d = NULL;
|
_cleanup_closedir_ DIR *d = NULL;
|
||||||
struct dirent *de;
|
struct dirent *de;
|
||||||
|
|
||||||
/* The passed 'fd' was opened with O_PATH. We need to convert
|
/* The passed 'fd' was opened with O_PATH. We need to convert it into a 'regular' fd before
|
||||||
* it into a 'regular' fd before reading the directory content. */
|
* reading the directory content. */
|
||||||
xsprintf(procfs_path, "/proc/self/fd/%i", fd);
|
d = opendir(FORMAT_PROC_FD_PATH(fd));
|
||||||
|
|
||||||
d = opendir(procfs_path);
|
|
||||||
if (!d) {
|
if (!d) {
|
||||||
log_error_errno(errno, "Failed to opendir() '%s': %m", procfs_path);
|
log_error_errno(errno, "Failed to opendir() '%s': %m", FORMAT_PROC_FD_PATH(fd));
|
||||||
if (r == 0)
|
if (r == 0)
|
||||||
r = -errno;
|
r = -errno;
|
||||||
goto finish;
|
goto finish;
|
||||||
|
Loading…
Reference in New Issue
Block a user