fd-util: add new helper move_fd() and make use of it

We are using the same pattern at various places: call dup2() on an fd,
and close the old fd, usually in combination with some O_CLOEXEC
fiddling. Let's add a little helper for this, and port a few obvious
cases over.
This commit is contained in:
Lennart Poettering 2017-10-26 18:45:54 +02:00
parent 05d69e0294
commit 046a82c1b2
5 changed files with 71 additions and 61 deletions

View File

@ -377,3 +377,47 @@ int fd_get_path(int fd, char **ret) {
return r;
}
int move_fd(int from, int to, int cloexec) {
int r;
/* Move fd 'from' to 'to', make sure FD_CLOEXEC remains equal if requested, and release the old fd. If
* 'cloexec' is passed as -1, the original FD_CLOEXEC is inherited for the new fd. If it is 0, it is turned
* off, if it is > 0 it is turned on. */
if (from < 0)
return -EBADF;
if (to < 0)
return -EBADF;
if (from == to) {
if (cloexec >= 0) {
r = fd_cloexec(to, cloexec);
if (r < 0)
return r;
}
return to;
}
if (cloexec < 0) {
int fl;
fl = fcntl(from, F_GETFD, 0);
if (fl < 0)
return -errno;
cloexec = !!(fl & FD_CLOEXEC);
}
r = dup3(from, to, cloexec ? O_CLOEXEC : 0);
if (r < 0)
return -errno;
assert(r == to);
safe_close(from);
return to;
}

View File

@ -75,6 +75,8 @@ bool fdname_is_valid(const char *s);
int fd_get_path(int fd, char **ret);
int move_fd(int from, int to, int cloexec);
/* Hint: ENETUNREACH happens if we try to connect to "non-existing" special IP addresses, such as ::5 */
#define ERRNO_IS_DISCONNECT(r) \
IN_SET(r, ENOTCONN, ECONNRESET, ECONNREFUSED, ECONNABORTED, EPIPE, ENETUNREACH)

View File

@ -275,7 +275,7 @@ static bool exec_context_needs_term(const ExecContext *c) {
}
static int open_null_as(int flags, int nfd) {
int fd, r;
int fd;
assert(nfd >= 0);
@ -283,13 +283,7 @@ static int open_null_as(int flags, int nfd) {
if (fd < 0)
return -errno;
if (fd != nfd) {
r = dup2(fd, nfd) < 0 ? -errno : nfd;
safe_close(fd);
} else
r = nfd;
return r;
return move_fd(fd, nfd, false);
}
static int connect_journal_socket(int fd, uid_t uid, gid_t gid) {
@ -381,16 +375,10 @@ static int connect_logger_as(
is_kmsg_output(output),
is_terminal_output(output));
if (fd == nfd)
return nfd;
r = dup2(fd, nfd) < 0 ? -errno : nfd;
safe_close(fd);
return r;
return move_fd(fd, nfd, false);
}
static int open_terminal_as(const char *path, mode_t mode, int nfd) {
int fd, r;
int fd;
assert(path);
assert(nfd >= 0);
@ -399,13 +387,7 @@ static int open_terminal_as(const char *path, mode_t mode, int nfd) {
if (fd < 0)
return fd;
if (fd != nfd) {
r = dup2(fd, nfd) < 0 ? -errno : nfd;
safe_close(fd);
} else
r = nfd;
return r;
return move_fd(fd, nfd, false);
}
static int fixup_input(ExecInput std_input, int socket_fd, bool apply_tty_stdin) {
@ -459,7 +441,7 @@ static int setup_input(
case EXEC_INPUT_TTY:
case EXEC_INPUT_TTY_FORCE:
case EXEC_INPUT_TTY_FAIL: {
int fd, r;
int fd;
fd = acquire_terminal(exec_context_tty_path(context),
i == EXEC_INPUT_TTY_FAIL,
@ -469,13 +451,7 @@ static int setup_input(
if (fd < 0)
return fd;
if (fd != STDIN_FILENO) {
r = dup2(fd, STDIN_FILENO) < 0 ? -errno : STDIN_FILENO;
safe_close(fd);
} else
r = STDIN_FILENO;
return r;
return move_fd(fd, STDIN_FILENO, false);
}
case EXEC_INPUT_SOCKET:

View File

@ -103,28 +103,24 @@ int import_fork_tar_x(const char *path, pid_t *ret) {
pipefd[1] = safe_close(pipefd[1]);
if (dup2(pipefd[0], STDIN_FILENO) != STDIN_FILENO) {
log_error_errno(errno, "Failed to dup2() fd: %m");
r = move_fd(pipefd[0], STDIN_FILENO, false);
if (r < 0) {
log_error_errno(r, "Failed to move fd: %m");
_exit(EXIT_FAILURE);
}
if (pipefd[0] != STDIN_FILENO)
pipefd[0] = safe_close(pipefd[0]);
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);
}
if (dup2(null_fd, STDOUT_FILENO) != STDOUT_FILENO) {
log_error_errno(errno, "Failed to dup2() fd: %m");
r = move_fd(null_fd, STDOUT_FILENO, false);
if (r < 0) {
log_error_errno(r, "Failed to move fd: %m");
_exit(EXIT_FAILURE);
}
if (null_fd != STDOUT_FILENO)
null_fd = safe_close(null_fd);
stdio_unset_cloexec();
if (unshare(CLONE_NEWNET) < 0)
@ -175,28 +171,24 @@ int import_fork_tar_c(const char *path, pid_t *ret) {
pipefd[0] = safe_close(pipefd[0]);
if (dup2(pipefd[1], STDOUT_FILENO) != STDOUT_FILENO) {
log_error_errno(errno, "Failed to dup2() fd: %m");
r = move_fd(pipefd[1], STDOUT_FILENO, false);
if (r < 0) {
log_error_errno(r, "Failed to move fd: %m");
_exit(EXIT_FAILURE);
}
if (pipefd[1] != STDOUT_FILENO)
pipefd[1] = safe_close(pipefd[1]);
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");
r = move_fd(null_fd, STDIN_FILENO, false);
if (r < 0) {
log_error_errno(errno, "Failed to move fd: %m");
_exit(EXIT_FAILURE);
}
if (null_fd != STDIN_FILENO)
null_fd = safe_close(null_fd);
stdio_unset_cloexec();
if (unshare(CLONE_NEWNET) < 0)

View File

@ -492,28 +492,24 @@ int pull_verify(PullJob *main_job,
gpg_pipe[1] = safe_close(gpg_pipe[1]);
if (dup2(gpg_pipe[0], STDIN_FILENO) != STDIN_FILENO) {
log_error_errno(errno, "Failed to dup2() fd: %m");
r = move_fd(gpg_pipe[0], STDIN_FILENO, false);
if (r < 0) {
log_error_errno(errno, "Failed to move fd: %m");
_exit(EXIT_FAILURE);
}
if (gpg_pipe[0] != STDIN_FILENO)
gpg_pipe[0] = safe_close(gpg_pipe[0]);
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);
}
if (dup2(null_fd, STDOUT_FILENO) != STDOUT_FILENO) {
log_error_errno(errno, "Failed to dup2() fd: %m");
r = move_fd(null_fd, STDOUT_FILENO, false);
if (r < 0) {
log_error_errno(errno, "Failed to move fd: %m");
_exit(EXIT_FAILURE);
}
if (null_fd != STDOUT_FILENO)
null_fd = safe_close(null_fd);
cmd[k++] = strjoina("--homedir=", gpg_home);
/* We add the user keyring only to the command line