summaryrefslogtreecommitdiff
path: root/src/test/test-fd-util.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2018-02-28 10:00:26 +0100
committerSven Eden <yamakuzure@gmx.net>2018-05-30 07:59:13 +0200
commit2c0aa1402b7bbccc25331c1f82103b3490d88026 (patch)
tree96a94235738e8c29289dd61f0c618e8406aeddc0 /src/test/test-fd-util.c
parent684be08b883424bd6e352e588c15345c78d592a7 (diff)
fd-util: add new call rearrange_stdio()
Quite often we need to set up a number of fds as stdin/stdout/stderr of a process we are about to start. Add a generic implementation for a routine doing that that takes care to do so properly: 1. Can handle the case where stdin/stdout/stderr where previously closed, and the fds to set as stdin/stdout/stderr hence likely in the 0..2 range. handling this properly is nasty, since we need to first move the fds out of this range in order to later move them back in, to make things fully robust. 2. Can optionally open /dev/null in case for one or more of the fds, in a smart way, sharing the open file if possible between multiple of the fds. 3. Guarantees that O_CLOEXEC is not set on the three fds, even if the fds already were in the 0..2 range and hence possibly weren't moved.
Diffstat (limited to 'src/test/test-fd-util.c')
-rw-r--r--src/test/test-fd-util.c69
1 files changed, 69 insertions, 0 deletions
diff --git a/src/test/test-fd-util.c b/src/test/test-fd-util.c
index 76b36053b..186fca733 100644
--- a/src/test/test-fd-util.c
+++ b/src/test/test-fd-util.c
@@ -25,6 +25,8 @@
#include "fd-util.h"
#include "fileio.h"
#include "macro.h"
+//#include "path-util.h"
+//#include "process-util.h"
#include "random-util.h"
#include "string-util.h"
#include "util.h"
@@ -175,6 +177,72 @@ static void test_fd_move_above_stdio(void) {
assert_se(close_nointr(new_fd) != EBADF);
}
+static void test_rearrange_stdio(void) {
+ pid_t pid;
+ int r;
+
+ r = safe_fork("rearrange", FORK_WAIT|FORK_LOG, &pid);
+ assert_se(r >= 0);
+
+ if (r == 0) {
+ _cleanup_free_ char *path = NULL;
+ char buffer[10];
+
+ /* Child */
+
+ safe_close(STDERR_FILENO); /* Let's close an fd < 2, to make it more interesting */
+
+ assert_se(rearrange_stdio(-1, -1, -1) >= 0);
+
+ assert_se(fd_get_path(STDIN_FILENO, &path) >= 0);
+ assert_se(path_equal(path, "/dev/null"));
+ path = mfree(path);
+
+ assert_se(fd_get_path(STDOUT_FILENO, &path) >= 0);
+ assert_se(path_equal(path, "/dev/null"));
+ path = mfree(path);
+
+ assert_se(fd_get_path(STDOUT_FILENO, &path) >= 0);
+ assert_se(path_equal(path, "/dev/null"));
+ path = mfree(path);
+
+ safe_close(STDIN_FILENO);
+ safe_close(STDOUT_FILENO);
+ safe_close(STDERR_FILENO);
+
+ {
+ int pair[2];
+ assert_se(pipe(pair) >= 0);
+ assert_se(pair[0] == 0);
+ assert_se(pair[1] == 1);
+ assert_se(fd_move_above_stdio(0) == 3);
+ }
+ assert_se(open("/dev/full", O_WRONLY|O_CLOEXEC) == 0);
+ assert_se(acquire_data_fd("foobar", 6, 0) == 2);
+
+ assert_se(rearrange_stdio(2, 0, 1) >= 0);
+
+ assert_se(write(1, "x", 1) < 0 && errno == ENOSPC);
+ assert_se(write(2, "z", 1) == 1);
+ assert_se(read(3, buffer, sizeof(buffer)) == 1);
+ assert_se(buffer[0] == 'z');
+ assert_se(read(0, buffer, sizeof(buffer)) == 6);
+ assert_se(memcmp(buffer, "foobar", 6) == 0);
+
+ assert_se(rearrange_stdio(-1, 1, 2) >= 0);
+ assert_se(write(1, "a", 1) < 0 && errno == ENOSPC);
+ assert_se(write(2, "y", 1) == 1);
+ assert_se(read(3, buffer, sizeof(buffer)) == 1);
+ assert_se(buffer[0] == 'y');
+
+ assert_se(fd_get_path(0, &path) >= 0);
+ assert_se(path_equal(path, "/dev/null"));
+ path = mfree(path);
+
+ _exit(EXIT_SUCCESS);
+ }
+}
+
int main(int argc, char *argv[]) {
test_close_many();
test_close_nointr();
@@ -184,6 +252,7 @@ int main(int argc, char *argv[]) {
test_open_serialization_fd();
test_acquire_data_fd();
test_fd_move_above_stdio();
+ test_rearrange_stdio();
return 0;
}