fileio: add support for read_full_file() on AF_UNIX stream sockets

Optionally, teach read_full_file() the ability to connect to an AF_UNIX
socket if the specified path points to one.
This commit is contained in:
Lennart Poettering
2020-07-21 10:23:44 +02:00
parent f294470262
commit b93d3f6b81
3 changed files with 104 additions and 9 deletions
+53 -9
View File
@@ -22,6 +22,7 @@
#include "mkdir.h"
#include "parse-util.h"
#include "path-util.h"
#include "socket-util.h"
#include "stdio-util.h"
#include "string-util.h"
#include "tmpfile-util.h"
@@ -535,21 +536,18 @@ int read_full_stream_full(
errno = 0;
k = fread(buf + l, 1, n - l, f);
if (k > 0)
l += k;
assert(k <= n - l);
l += k;
if (ferror(f)) {
r = errno_or_else(EIO);
goto finalize;
}
if (feof(f))
break;
/* We aren't expecting fread() to return a short read outside
* of (error && eof), assert buffer is full and enlarge buffer.
*/
assert(l == n);
assert(k > 0); /* we can't have read zero bytes because that would have been EOF */
/* Safety check */
if (n >= READ_FULL_BYTES_MAX) {
@@ -603,8 +601,54 @@ int read_full_file_full(int dir_fd, const char *filename, ReadFullFileFlags flag
assert(contents);
r = xfopenat(dir_fd, filename, "re", 0, &f);
if (r < 0)
return r;
if (r < 0) {
_cleanup_close_ int dfd = -1, sk = -1;
union sockaddr_union sa;
/* 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;
if (dir_fd == AT_FDCWD)
r = sockaddr_un_set_path(&sa.un, filename);
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
* 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. */
dfd = openat(dir_fd, filename, O_PATH|O_CLOEXEC);
if (dfd < 0)
return -errno;
xsprintf(procfs_path, "/proc/self/fd/%i", dfd);
r = sockaddr_un_set_path(&sa.un, procfs_path);
}
if (r < 0)
return r;
sk = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
if (sk < 0)
return -errno;
if (connect(sk, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0)
return errno == ENOTSOCK ? -ENXIO : -errno; /* propagate original error if this is
* not a socket after all */
if (shutdown(sk, SHUT_WR) < 0)
return -errno;
f = fdopen(sk, "r");
if (!f)
return -errno;
TAKE_FD(sk);
}
(void) __fsetlocking(f, FSETLOCKING_BYCALLER);
+1
View File
@@ -36,6 +36,7 @@ typedef enum {
READ_FULL_FILE_UNBASE64 = 1 << 1,
READ_FULL_FILE_UNHEX = 1 << 2,
READ_FULL_FILE_WARN_WORLD_READABLE = 1 << 3,
READ_FULL_FILE_CONNECT_SOCKET = 1 << 4,
} ReadFullFileFlags;
int fopen_unlocked(const char *path, const char *options, FILE **ret);