mirror of
https://github.com/systemd/systemd.git
synced 2024-10-30 23:21:22 +03:00
Merge pull request #8314 from poettering/rearrange-stdio
refactor how we rearrange fds for stdin/stdout/stderr
This commit is contained in:
commit
6cc7e918ff
3
TODO
3
TODO
@ -24,6 +24,9 @@ Janitorial Clean-ups:
|
||||
|
||||
Features:
|
||||
|
||||
* add proper dbus APIs for the various sd_notify() commands, such as MAINPID=1
|
||||
and so on, which would mean we could report errors and such.
|
||||
|
||||
* block setrlimit(RLIMIT_NOPROC) (and other per-user limits) in nspawn when userns is not on
|
||||
|
||||
* nss-systemd: implement enumeration, that shows all dynamic users plus the
|
||||
|
@ -199,15 +199,10 @@ static int exec_process(const char* name, char **argv, char **env, int start_fd,
|
||||
if (arg_inetd) {
|
||||
assert(n_fds == 1);
|
||||
|
||||
r = dup2(start_fd, STDIN_FILENO);
|
||||
r = rearrange_stdio(start_fd, start_fd, STDERR_FILENO); /* invalidates start_fd on success + error */
|
||||
if (r < 0)
|
||||
return log_error_errno(errno, "Failed to dup connection to stdin: %m");
|
||||
return log_error_errno(errno, "Failed to move fd to stdin+stdout: %m");
|
||||
|
||||
r = dup2(start_fd, STDOUT_FILENO);
|
||||
if (r < 0)
|
||||
return log_error_errno(errno, "Failed to dup connection to stdout: %m");
|
||||
|
||||
start_fd = safe_close(start_fd);
|
||||
} else {
|
||||
if (start_fd != SD_LISTEN_FDS_START) {
|
||||
assert(n_fds == 1);
|
||||
|
@ -62,12 +62,9 @@ static int do_spawn(const char *path, char *argv[], int stdout_fd, pid_t *pid) {
|
||||
char *_argv[2];
|
||||
|
||||
if (stdout_fd >= 0) {
|
||||
/* If the fd happens to be in the right place, go along with that */
|
||||
if (stdout_fd != STDOUT_FILENO &&
|
||||
dup2(stdout_fd, STDOUT_FILENO) < 0)
|
||||
r = rearrange_stdio(STDIN_FILENO, stdout_fd, STDERR_FILENO);
|
||||
if (r < 0)
|
||||
_exit(EXIT_FAILURE);
|
||||
|
||||
(void) fd_cloexec(STDOUT_FILENO, false);
|
||||
}
|
||||
|
||||
if (!argv) {
|
||||
|
@ -191,12 +191,6 @@ int fd_cloexec(int fd, bool cloexec) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void stdio_unset_cloexec(void) {
|
||||
(void) fd_cloexec(STDIN_FILENO, false);
|
||||
(void) fd_cloexec(STDOUT_FILENO, false);
|
||||
(void) fd_cloexec(STDERR_FILENO, false);
|
||||
}
|
||||
|
||||
_pure_ static bool fd_in_set(int fd, const int fdset[], unsigned n_fdset) {
|
||||
unsigned i;
|
||||
|
||||
@ -615,3 +609,118 @@ int fd_move_above_stdio(int fd) {
|
||||
(void) close(fd);
|
||||
return copy;
|
||||
}
|
||||
|
||||
int rearrange_stdio(int original_input_fd, int original_output_fd, int original_error_fd) {
|
||||
|
||||
int fd[3] = { /* Put together an array of fds we work on */
|
||||
original_input_fd,
|
||||
original_output_fd,
|
||||
original_error_fd
|
||||
};
|
||||
|
||||
int r, i,
|
||||
null_fd = -1, /* if we open /dev/null, we store the fd to it here */
|
||||
copy_fd[3] = { -1, -1, -1 }; /* This contains all fds we duplicate here temporarily, and hence need to close at the end */
|
||||
bool null_readable, null_writable;
|
||||
|
||||
/* Sets up stdin, stdout, stderr with the three file descriptors passed in. If any of the descriptors is
|
||||
* specified as -1 it will be connected with /dev/null instead. If any of the file descriptors is passed as
|
||||
* itself (e.g. stdin as STDIN_FILENO) it is left unmodified, but the O_CLOEXEC bit is turned off should it be
|
||||
* on.
|
||||
*
|
||||
* Note that if any of the passed file descriptors are > 2 they will be closed — both on success and on
|
||||
* failure! Thus, callers should assume that when this function returns the input fds are invalidated.
|
||||
*
|
||||
* Note that when this function fails stdin/stdout/stderr might remain half set up!
|
||||
*
|
||||
* O_CLOEXEC is turned off for all three file descriptors (which is how it should be for
|
||||
* stdin/stdout/stderr). */
|
||||
|
||||
null_readable = original_input_fd < 0;
|
||||
null_writable = original_output_fd < 0 || original_error_fd < 0;
|
||||
|
||||
/* First step, open /dev/null once, if we need it */
|
||||
if (null_readable || null_writable) {
|
||||
|
||||
/* Let's open this with O_CLOEXEC first, and convert it to non-O_CLOEXEC when we move the fd to the final position. */
|
||||
null_fd = open("/dev/null", (null_readable && null_writable ? O_RDWR :
|
||||
null_readable ? O_RDONLY : O_WRONLY) | O_CLOEXEC);
|
||||
if (null_fd < 0) {
|
||||
r = -errno;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
/* If this fd is in the 0…2 range, let's move it out of it */
|
||||
if (null_fd < 3) {
|
||||
int copy;
|
||||
|
||||
copy = fcntl(null_fd, F_DUPFD_CLOEXEC, 3); /* Duplicate this with O_CLOEXEC set */
|
||||
if (copy < 0) {
|
||||
r = -errno;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
safe_close(null_fd);
|
||||
null_fd = copy;
|
||||
}
|
||||
}
|
||||
|
||||
/* Let's assemble fd[] with the fds to install in place of stdin/stdout/stderr */
|
||||
for (i = 0; i < 3; i++) {
|
||||
|
||||
if (fd[i] < 0)
|
||||
fd[i] = null_fd; /* A negative parameter means: connect this one to /dev/null */
|
||||
else if (fd[i] != i && fd[i] < 3) {
|
||||
/* This fd is in the 0…2 territory, but not at its intended place, move it out of there, so that we can work there. */
|
||||
copy_fd[i] = fcntl(fd[i], F_DUPFD_CLOEXEC, 3); /* Duplicate this with O_CLOEXEC set */
|
||||
if (copy_fd[i] < 0) {
|
||||
r = -errno;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
fd[i] = copy_fd[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* At this point we now have the fds to use in fd[], and they are all above the stdio range, so that we
|
||||
* have freedom to move them around. If the fds already were at the right places then the specific fds are
|
||||
* -1. Let's now move them to the right places. This is the point of no return. */
|
||||
for (i = 0; i < 3; i++) {
|
||||
|
||||
if (fd[i] == i) {
|
||||
|
||||
/* fd is already in place, but let's make sure O_CLOEXEC is off */
|
||||
r = fd_cloexec(i, false);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
} else {
|
||||
assert(fd[i] > 2);
|
||||
|
||||
if (dup2(fd[i], i) < 0) { /* Turns off O_CLOEXEC on the new fd. */
|
||||
r = -errno;
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
r = 0;
|
||||
|
||||
finish:
|
||||
/* Close the original fds, but only if they were outside of the stdio range. Also, properly check for the same
|
||||
* fd passed in multiple times. */
|
||||
safe_close_above_stdio(original_input_fd);
|
||||
if (original_output_fd != original_input_fd)
|
||||
safe_close_above_stdio(original_output_fd);
|
||||
if (original_error_fd != original_input_fd && original_error_fd != original_output_fd)
|
||||
safe_close_above_stdio(original_error_fd);
|
||||
|
||||
/* Close the copies we moved > 2 */
|
||||
for (i = 0; i < 3; i++)
|
||||
safe_close(copy_fd[i]);
|
||||
|
||||
/* Close our null fd, if it's > 2 */
|
||||
safe_close_above_stdio(null_fd);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
@ -71,7 +71,6 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(DIR*, closedir);
|
||||
|
||||
int fd_nonblock(int fd, bool nonblock);
|
||||
int fd_cloexec(int fd, bool cloexec);
|
||||
void stdio_unset_cloexec(void);
|
||||
|
||||
int close_all_fds(const int except[], unsigned n_except);
|
||||
|
||||
@ -100,3 +99,9 @@ int acquire_data_fd(const void *data, size_t size, unsigned flags);
|
||||
IN_SET(r, ENOTCONN, ECONNRESET, ECONNREFUSED, ECONNABORTED, EPIPE, ENETUNREACH)
|
||||
|
||||
int fd_move_above_stdio(int fd);
|
||||
|
||||
int rearrange_stdio(int original_input_fd, int original_output_fd, int original_error_fd);
|
||||
|
||||
static inline int make_null_stdio(void) {
|
||||
return rearrange_stdio(-1, -1, -1);
|
||||
}
|
||||
|
@ -628,9 +628,9 @@ int make_console_stdio(void) {
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to reset terminal, ignoring: %m");
|
||||
|
||||
r = make_stdio(fd);
|
||||
r = rearrange_stdio(fd, fd, fd); /* This invalidates 'fd' both on success and on failure. */
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to duplicate terminal fd: %m");
|
||||
return log_error_errno(r, "Failed to make terminal stdin/stdout/stderr: %m");
|
||||
|
||||
reset_terminal_feature_caches();
|
||||
|
||||
@ -905,40 +905,6 @@ bool on_tty(void) {
|
||||
return cached_on_tty;
|
||||
}
|
||||
|
||||
int make_stdio(int fd) {
|
||||
int r = 0;
|
||||
|
||||
assert(fd >= 0);
|
||||
|
||||
if (dup2(fd, STDIN_FILENO) < 0)
|
||||
r = -errno;
|
||||
if (dup2(fd, STDOUT_FILENO) < 0 && r >= 0)
|
||||
r = -errno;
|
||||
if (dup2(fd, STDERR_FILENO) < 0 && r >= 0)
|
||||
r = -errno;
|
||||
|
||||
safe_close_above_stdio(fd);
|
||||
|
||||
/* Explicitly unset O_CLOEXEC, since if fd was < 3, then dup2() was a NOP and the bit hence possibly set. */
|
||||
stdio_unset_cloexec();
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int make_null_stdio(void) {
|
||||
int null_fd, r;
|
||||
|
||||
null_fd = open("/dev/null", O_RDWR|O_NOCTTY|O_CLOEXEC);
|
||||
if (null_fd < 0)
|
||||
return -errno;
|
||||
|
||||
r = make_stdio(null_fd);
|
||||
|
||||
reset_terminal_feature_caches();
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int getttyname_malloc(int fd, char **ret) {
|
||||
size_t l = 100;
|
||||
int r;
|
||||
|
@ -114,8 +114,6 @@ bool tty_is_console(const char *tty) _pure_;
|
||||
int vtnr_from_tty(const char *tty);
|
||||
const char *default_term_for_tty(const char *tty);
|
||||
|
||||
int make_stdio(int fd);
|
||||
int make_null_stdio(void);
|
||||
int make_console_stdio(void);
|
||||
|
||||
int fd_columns(int fd);
|
||||
|
@ -765,15 +765,10 @@ static int setup_confirm_stdio(const char *vc, int *_saved_stdin, int *_saved_st
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (dup2(fd, STDIN_FILENO) < 0)
|
||||
return -errno;
|
||||
|
||||
if (dup2(fd, STDOUT_FILENO) < 0)
|
||||
return -errno;
|
||||
|
||||
if (fd >= 2)
|
||||
safe_close(fd);
|
||||
r = rearrange_stdio(fd, fd, STDERR_FILENO);
|
||||
fd = -1;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*_saved_stdin = saved_stdin;
|
||||
*_saved_stdout = saved_stdout;
|
||||
|
@ -87,7 +87,6 @@ int import_fork_tar_x(const char *path, pid_t *ret) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0) {
|
||||
int null_fd;
|
||||
uint64_t retain =
|
||||
(1ULL << CAP_CHOWN) |
|
||||
(1ULL << CAP_FOWNER) |
|
||||
@ -100,26 +99,12 @@ int import_fork_tar_x(const char *path, pid_t *ret) {
|
||||
|
||||
pipefd[1] = safe_close(pipefd[1]);
|
||||
|
||||
r = move_fd(pipefd[0], STDIN_FILENO, false);
|
||||
r = rearrange_stdio(pipefd[0], -1, STDERR_FILENO);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to move fd: %m");
|
||||
log_error_errno(r, "Failed to rearrange stdin/stdout: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
null_fd = open("/dev/null", O_WRONLY|O_NOCTTY);
|
||||
if (null_fd < 0) {
|
||||
log_error_errno(errno, "Failed to open /dev/null: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
r = move_fd(null_fd, STDOUT_FILENO, false);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to move fd: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
stdio_unset_cloexec();
|
||||
|
||||
if (unshare(CLONE_NEWNET) < 0)
|
||||
log_error_errno(errno, "Failed to lock tar into network namespace, ignoring: %m");
|
||||
|
||||
@ -156,33 +141,18 @@ int import_fork_tar_c(const char *path, pid_t *ret) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0) {
|
||||
int null_fd;
|
||||
uint64_t retain = (1ULL << CAP_DAC_OVERRIDE);
|
||||
|
||||
/* Child */
|
||||
|
||||
pipefd[0] = safe_close(pipefd[0]);
|
||||
|
||||
r = move_fd(pipefd[1], STDOUT_FILENO, false);
|
||||
r = rearrange_stdio(-1, pipefd[1], STDERR_FILENO);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to move fd: %m");
|
||||
log_error_errno(r, "Failed to rearrange stdin/stdout: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
null_fd = open("/dev/null", O_RDONLY|O_NOCTTY);
|
||||
if (null_fd < 0) {
|
||||
log_error_errno(errno, "Failed to open /dev/null: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
r = move_fd(null_fd, STDIN_FILENO, false);
|
||||
if (r < 0) {
|
||||
log_error_errno(errno, "Failed to move fd: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
stdio_unset_cloexec();
|
||||
|
||||
if (unshare(CLONE_NEWNET) < 0)
|
||||
log_error_errno(errno, "Failed to lock tar into network namespace, ignoring: %m");
|
||||
|
||||
|
@ -395,57 +395,14 @@ static int transfer_start(Transfer *t) {
|
||||
|
||||
pipefd[0] = safe_close(pipefd[0]);
|
||||
|
||||
if (dup2(pipefd[1], STDERR_FILENO) != STDERR_FILENO) {
|
||||
log_error_errno(errno, "Failed to dup2() fd: %m");
|
||||
r = rearrange_stdio(t->stdin_fd,
|
||||
t->stdout_fd < 0 ? pipefd[1] : t->stdout_fd,
|
||||
pipefd[1]);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to set stdin/stdout/stderr: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (t->stdout_fd >= 0) {
|
||||
if (dup2(t->stdout_fd, STDOUT_FILENO) != STDOUT_FILENO) {
|
||||
log_error_errno(errno, "Failed to dup2() fd: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (t->stdout_fd != STDOUT_FILENO)
|
||||
safe_close(t->stdout_fd);
|
||||
} else {
|
||||
if (dup2(pipefd[1], STDOUT_FILENO) != STDOUT_FILENO) {
|
||||
log_error_errno(errno, "Failed to dup2() fd: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (!IN_SET(pipefd[1], STDOUT_FILENO, STDERR_FILENO))
|
||||
pipefd[1] = safe_close(pipefd[1]);
|
||||
|
||||
if (t->stdin_fd >= 0) {
|
||||
if (dup2(t->stdin_fd, STDIN_FILENO) != STDIN_FILENO) {
|
||||
log_error_errno(errno, "Failed to dup2() fd: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (t->stdin_fd != STDIN_FILENO)
|
||||
safe_close(t->stdin_fd);
|
||||
} else {
|
||||
int null_fd;
|
||||
|
||||
null_fd = open("/dev/null", O_RDONLY|O_NOCTTY);
|
||||
if (null_fd < 0) {
|
||||
log_error_errno(errno, "Failed to open /dev/null: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (dup2(null_fd, STDIN_FILENO) != STDIN_FILENO) {
|
||||
log_error_errno(errno, "Failed to dup2() fd: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (null_fd != STDIN_FILENO)
|
||||
safe_close(null_fd);
|
||||
}
|
||||
|
||||
stdio_unset_cloexec();
|
||||
|
||||
if (setenv("SYSTEMD_LOG_TARGET", "console-prefixed", 1) < 0 ||
|
||||
setenv("NOTIFY_SOCKET", "/run/systemd/import/notify", 1) < 0) {
|
||||
log_error_errno(errno, "setenv() failed: %m");
|
||||
|
@ -483,27 +483,14 @@ int pull_verify(PullJob *main_job,
|
||||
NULL /* trailing NULL */
|
||||
};
|
||||
unsigned k = ELEMENTSOF(cmd) - 6;
|
||||
int null_fd;
|
||||
|
||||
/* Child */
|
||||
|
||||
gpg_pipe[1] = safe_close(gpg_pipe[1]);
|
||||
|
||||
r = move_fd(gpg_pipe[0], STDIN_FILENO, false);
|
||||
r = rearrange_stdio(gpg_pipe[0], -1, STDERR_FILENO);
|
||||
if (r < 0) {
|
||||
log_error_errno(errno, "Failed to move fd: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
null_fd = open("/dev/null", O_WRONLY|O_NOCTTY);
|
||||
if (null_fd < 0) {
|
||||
log_error_errno(errno, "Failed to open /dev/null: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
r = move_fd(null_fd, STDOUT_FILENO, false);
|
||||
if (r < 0) {
|
||||
log_error_errno(errno, "Failed to move fd: %m");
|
||||
log_error_errno(r, "Failed to rearrange stdin/stdout: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
@ -524,8 +511,6 @@ int pull_verify(PullJob *main_job,
|
||||
cmd[k++] = NULL;
|
||||
}
|
||||
|
||||
stdio_unset_cloexec();
|
||||
|
||||
execvp("gpg2", (char * const *) cmd);
|
||||
execvp("gpg", (char * const *) cmd);
|
||||
log_error_errno(errno, "Failed to execute gpg: %m");
|
||||
|
@ -96,23 +96,20 @@ static int spawn_child(const char* child, char** argv) {
|
||||
|
||||
/* In the child */
|
||||
if (r == 0) {
|
||||
safe_close(fd[0]);
|
||||
|
||||
r = dup2(fd[1], STDOUT_FILENO);
|
||||
r = rearrange_stdio(STDIN_FILENO, fd[1], STDERR_FILENO);
|
||||
if (r < 0) {
|
||||
log_error_errno(errno, "Failed to dup pipe to stdout: %m");
|
||||
log_error_errno(r, "Failed to dup pipe to stdout: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
safe_close_pair(fd);
|
||||
|
||||
execvp(child, argv);
|
||||
log_error_errno(errno, "Failed to exec child %s: %m", child);
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
r = close(fd[1]);
|
||||
if (r < 0)
|
||||
log_warning_errno(errno, "Failed to close write end of pipe: %m");
|
||||
safe_close(fd[1]);
|
||||
|
||||
r = fd_nonblock(fd[0], true);
|
||||
if (r < 0)
|
||||
|
@ -135,14 +135,13 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
saved_stderr = fcntl(STDERR_FILENO, F_DUPFD_CLOEXEC, 3);
|
||||
|
||||
if (dup3(fd, STDOUT_FILENO, 0) < 0 ||
|
||||
dup3(fd, STDERR_FILENO, 0) < 0) {
|
||||
r = log_error_errno(errno, "Failed to duplicate fd: %m");
|
||||
r = rearrange_stdio(STDIN_FILENO, fd, fd); /* Invalidates fd on succcess + error! */
|
||||
fd = -1;
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to rearrange stdout/stderr: %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
fd = safe_close_above_stdio(fd);
|
||||
|
||||
if (argc <= optind)
|
||||
(void) execl("/bin/cat", "/bin/cat", NULL);
|
||||
else
|
||||
|
@ -2646,7 +2646,7 @@ _public_ int sd_bus_message_append_array_memfd(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
copy_fd = dup(memfd);
|
||||
copy_fd = fcntl(memfd, F_DUPFD_CLOEXEC, 3);
|
||||
if (copy_fd < 0)
|
||||
return copy_fd;
|
||||
|
||||
@ -2721,7 +2721,7 @@ _public_ int sd_bus_message_append_string_memfd(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
copy_fd = dup(memfd);
|
||||
copy_fd = fcntl(memfd, FD_CLOEXEC, 3);
|
||||
if (copy_fd < 0)
|
||||
return copy_fd;
|
||||
|
||||
|
@ -960,14 +960,11 @@ int bus_socket_exec(sd_bus *b) {
|
||||
if (r == 0) {
|
||||
/* Child */
|
||||
|
||||
assert_se(dup3(s[1], STDIN_FILENO, 0) == STDIN_FILENO);
|
||||
assert_se(dup3(s[1], STDOUT_FILENO, 0) == STDOUT_FILENO);
|
||||
safe_close(s[0]);
|
||||
|
||||
if (!IN_SET(s[1], STDIN_FILENO, STDOUT_FILENO))
|
||||
safe_close(s[1]);
|
||||
if (rearrange_stdio(s[1], s[1], STDERR_FILENO) < 0)
|
||||
_exit(EXIT_FAILURE);
|
||||
|
||||
(void) fd_cloexec(STDIN_FILENO, false);
|
||||
(void) fd_cloexec(STDOUT_FILENO, false);
|
||||
(void) fd_nonblock(STDIN_FILENO, false);
|
||||
(void) fd_nonblock(STDOUT_FILENO, false);
|
||||
|
||||
|
@ -54,26 +54,12 @@ static int spawn_getent(const char *database, const char *key, pid_t *rpid) {
|
||||
}
|
||||
if (r == 0) {
|
||||
char *empty_env = NULL;
|
||||
int nullfd;
|
||||
|
||||
if (dup3(pipe_fds[1], STDOUT_FILENO, 0) < 0)
|
||||
safe_close(pipe_fds[0]);
|
||||
|
||||
if (rearrange_stdio(-1, pipe_fds[1], -1) < 0)
|
||||
_exit(EXIT_FAILURE);
|
||||
|
||||
safe_close_above_stdio(pipe_fds[0]);
|
||||
safe_close_above_stdio(pipe_fds[1]);
|
||||
|
||||
nullfd = open("/dev/null", O_RDWR);
|
||||
if (nullfd < 0)
|
||||
_exit(EXIT_FAILURE);
|
||||
|
||||
if (dup3(nullfd, STDIN_FILENO, 0) < 0)
|
||||
_exit(EXIT_FAILURE);
|
||||
|
||||
if (dup3(nullfd, STDERR_FILENO, 0) < 0)
|
||||
_exit(EXIT_FAILURE);
|
||||
|
||||
safe_close_above_stdio(nullfd);
|
||||
|
||||
close_all_fds(NULL, 0);
|
||||
|
||||
execle("/usr/bin/getent", "getent", database, key, NULL, &empty_env);
|
||||
|
@ -2582,23 +2582,15 @@ static int outer_child(
|
||||
return log_error_errno(errno, "PR_SET_PDEATHSIG failed: %m");
|
||||
|
||||
if (interactive) {
|
||||
close_nointr(STDIN_FILENO);
|
||||
close_nointr(STDOUT_FILENO);
|
||||
close_nointr(STDERR_FILENO);
|
||||
int terminal;
|
||||
|
||||
r = open_terminal(console, O_RDWR);
|
||||
if (r != STDIN_FILENO) {
|
||||
if (r >= 0) {
|
||||
safe_close(r);
|
||||
r = -EINVAL;
|
||||
}
|
||||
terminal = open_terminal(console, O_RDWR);
|
||||
if (terminal < 0)
|
||||
return log_error_errno(terminal, "Failed to open console: %m");
|
||||
|
||||
return log_error_errno(r, "Failed to open console: %m");
|
||||
}
|
||||
|
||||
if (dup2(STDIN_FILENO, STDOUT_FILENO) != STDOUT_FILENO ||
|
||||
dup2(STDIN_FILENO, STDERR_FILENO) != STDERR_FILENO)
|
||||
return log_error_errno(errno, "Failed to duplicate console: %m");
|
||||
r = rearrange_stdio(terminal, terminal, terminal); /* invalidates 'terminal' on success and failure */
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to move console to stdin/stdout/stderr: %m");
|
||||
}
|
||||
|
||||
r = reset_audit_loginuid();
|
||||
|
@ -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"
|
||||
@ -173,6 +175,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();
|
||||
@ -180,6 +248,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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user