* can detect EOFs. */
#define READ_VIRTUAL_BYTES_MAX (4U*1024U*1024U - 2U)
-int fopen_unlocked_at(int dir_fd, const char *path, const char *options, int flags, FILE **ret) {
- int r;
-
- assert(ret);
-
- r = xfopenat(dir_fd, path, options, flags, ret);
- if (r < 0)
- return r;
-
- (void) __fsetlocking(*ret, FSETLOCKING_BYCALLER);
-
- return 0;
-}
-
int fdopen_unlocked(int fd, const char *options, FILE **ret) {
assert(ret);
size_t *ret_size) {
_cleanup_fclose_ FILE *f = NULL;
+ XfopenFlags xflags = XFOPEN_UNLOCKED;
int r;
assert(filename);
assert(ret_contents);
- r = xfopenat(dir_fd, filename, "re", 0, &f);
- if (r < 0) {
- _cleanup_close_ int sk = -EBADF;
-
- /* ENXIO is what Linux returns if we open a node that is an AF_UNIX socket */
- if (r != -ENXIO)
- return r;
-
- /* If this is enabled, let's try to connect to it */
- if (!FLAGS_SET(flags, READ_FULL_FILE_CONNECT_SOCKET))
- return -ENXIO;
-
- /* Seeking is not supported on AF_UNIX sockets */
- if (offset != UINT64_MAX)
- return -ENXIO;
-
- sk = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
- if (sk < 0)
- return -errno;
-
- if (bind_name) {
- /* If the caller specified a socket name to bind to, do so before connecting. This is
- * useful to communicate some minor, short meta-information token from the client to
- * the server. */
- union sockaddr_union bsa;
-
- r = sockaddr_un_set_path(&bsa.un, bind_name);
- if (r < 0)
- return r;
-
- if (bind(sk, &bsa.sa, r) < 0)
- return -errno;
- }
-
- r = connect_unix_path(sk, dir_fd, filename);
- if (IN_SET(r, -ENOTSOCK, -EINVAL)) /* propagate original error if this is not a socket after all */
- return -ENXIO;
- if (r < 0)
- return r;
-
- if (shutdown(sk, SHUT_WR) < 0)
- return -errno;
-
- f = take_fdopen(&sk, "r");
- if (!f)
- return -errno;
- }
+ if (FLAGS_SET(flags, READ_FULL_FILE_CONNECT_SOCKET) && /* If this is enabled, let's try to connect to it */
+ offset == UINT64_MAX) /* Seeking is not supported on AF_UNIX sockets */
+ xflags |= XFOPEN_SOCKET;
- (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
+ r = xfopenat_full(dir_fd, filename, "re", 0, xflags, bind_name, &f);
+ if (r < 0)
+ return r;
return read_full_stream_full(f, filename, offset, size, flags, ret_contents, ret_size);
}
return flags;
}
-int xfopenat(int dir_fd, const char *path, const char *mode, int flags, FILE **ret) {
+static int xfopenat_regular(int dir_fd, const char *path, const char *mode, int open_flags, FILE **ret) {
FILE *f;
/* A combination of fopen() with openat() */
assert(mode);
assert(ret);
- if (dir_fd == AT_FDCWD && flags == 0)
+ if (dir_fd == AT_FDCWD && open_flags == 0)
f = fopen(path, mode);
else {
_cleanup_close_ int fd = -EBADF;
if (mode_flags < 0)
return mode_flags;
- fd = openat(dir_fd, path, mode_flags | flags);
+ fd = openat(dir_fd, path, mode_flags | open_flags);
if (fd < 0)
return -errno;
return 0;
}
+static int xfopenat_unix_socket(int dir_fd, const char *path, const char *bind_name, FILE **ret) {
+ _cleanup_close_ int sk = -EBADF;
+ FILE *f;
+ int r;
+
+ assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
+ assert(path);
+ assert(ret);
+
+ sk = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
+ if (sk < 0)
+ return -errno;
+
+ if (bind_name) {
+ /* If the caller specified a socket name to bind to, do so before connecting. This is
+ * useful to communicate some minor, short meta-information token from the client to
+ * the server. */
+ union sockaddr_union bsa;
+
+ r = sockaddr_un_set_path(&bsa.un, bind_name);
+ if (r < 0)
+ return r;
+
+ if (bind(sk, &bsa.sa, r) < 0)
+ return -errno;
+ }
+
+ r = connect_unix_path(sk, dir_fd, path);
+ if (r < 0)
+ return r;
+
+ if (shutdown(sk, SHUT_WR) < 0)
+ return -errno;
+
+ f = take_fdopen(&sk, "r");
+ if (!f)
+ return -errno;
+
+ *ret = f;
+ return 0;
+}
+
+int xfopenat_full(
+ int dir_fd,
+ const char *path,
+ const char *mode,
+ int open_flags,
+ XfopenFlags flags,
+ const char *bind_name,
+ FILE **ret) {
+
+ FILE *f = NULL; /* avoid false maybe-uninitialized warning */
+ int r;
+
+ assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
+ assert(path);
+ assert(mode);
+ assert(ret);
+
+ r = xfopenat_regular(dir_fd, path, mode, open_flags, &f);
+ if (r == -ENXIO && FLAGS_SET(flags, XFOPEN_SOCKET)) {
+ /* ENXIO is what Linux returns if we open a node that is an AF_UNIX socket */
+ r = xfopenat_unix_socket(dir_fd, path, bind_name, &f);
+ if (IN_SET(r, -ENOTSOCK, -EINVAL))
+ return -ENXIO; /* propagate original error if this is not a socket after all */
+ }
+ if (r < 0)
+ return r;
+
+ if (FLAGS_SET(flags, XFOPEN_UNLOCKED))
+ (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
+
+ *ret = f;
+ return 0;
+}
+
int fdopen_independent(int fd, const char *mode, FILE **ret) {
_cleanup_close_ int copy_fd = -EBADF;
_cleanup_fclose_ FILE *f = NULL;
READ_FULL_FILE_FAIL_WHEN_LARGER = 1 << 5, /* fail loading if file is larger than specified size */
} ReadFullFileFlags;
-int fopen_unlocked_at(int dir_fd, const char *path, const char *options, int flags, FILE **ret);
-static inline int fopen_unlocked(const char *path, const char *options, FILE **ret) {
- return fopen_unlocked_at(AT_FDCWD, path, options, 0, ret);
-}
int fdopen_unlocked(int fd, const char *options, FILE **ret);
int take_fdopen_unlocked(int *fd, const char *options, FILE **ret);
FILE* take_fdopen(int *fd, const char *options);
int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field);
DIR *xopendirat(int dirfd, const char *name, int flags);
-int xfopenat(int dir_fd, const char *path, const char *mode, int flags, FILE **ret);
+
+typedef enum XfopenFlags {
+ XFOPEN_UNLOCKED = 1 << 0, /* call __fsetlocking(FSETLOCKING_BYCALLER) after opened */
+ XFOPEN_SOCKET = 1 << 1, /* also try to open unix socket */
+} XfopenFlags;
+
+int xfopenat_full(
+ int dir_fd,
+ const char *path,
+ const char *mode,
+ int open_flags,
+ XfopenFlags flags,
+ const char *bind_name,
+ FILE **ret);
+static inline int xfopenat(int dir_fd, const char *path, const char *mode, int open_flags, FILE **ret) {
+ return xfopenat_full(dir_fd, path, mode, open_flags, 0, NULL, ret);
+}
+static inline int fopen_unlocked_at(int dir_fd, const char *path, const char *mode, int open_flags, FILE **ret) {
+ return xfopenat_full(dir_fd, path, mode, open_flags, XFOPEN_UNLOCKED, NULL, ret);
+}
+static inline int fopen_unlocked(const char *path, const char *mode, FILE **ret) {
+ return fopen_unlocked_at(AT_FDCWD, path, mode, 0, ret);
+}
int fdopen_independent(int fd, const char *mode, FILE **ret);