From 03563b1407e436b2863509ebf09d412e79cbd1dd Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Tue, 18 Jan 2022 11:27:54 -0500 Subject: util: New close() wrappers to check for EBADF and preserve errno --- bar.c | 15 +++++---------- bftw.c | 4 ++-- dir.c | 6 ++---- exec.c | 10 +++------- main.c | 7 +++---- parse.c | 8 ++++---- spawn.c | 21 +++++++++------------ util.c | 28 +++++++++++++++++++--------- util.h | 20 +++++++++++++++++++- 9 files changed, 66 insertions(+), 53 deletions(-) diff --git a/bar.c b/bar.c index 31734ac..b0e595e 100644 --- a/bar.c +++ b/bar.c @@ -1,6 +1,6 @@ /**************************************************************************** * bfs * - * Copyright (C) 2020 Tavian Barnes * + * Copyright (C) 2020-2022 Tavian Barnes * * * * Permission to use, copy, modify, and/or distribute this software for any * * purpose with or without fee is hereby granted. * @@ -155,28 +155,24 @@ static int bfs_bar_printf(struct bfs_bar *bar, const char *format, ...) { } struct bfs_bar *bfs_bar_show(void) { - int error; - if (the_bar.fd >= 0) { - error = EBUSY; + errno = EBUSY; goto fail; } char term[L_ctermid]; ctermid(term); if (strlen(term) == 0) { - error = ENOTTY; + errno = ENOTTY; goto fail; } the_bar.fd = open(term, O_RDWR | O_CLOEXEC); if (the_bar.fd < 0) { - error = errno; goto fail; } if (bfs_bar_getsize(&the_bar) != 0) { - error = errno; goto fail_close; } @@ -207,10 +203,9 @@ struct bfs_bar *bfs_bar_show(void) { return &the_bar; fail_close: - close(the_bar.fd); + close_quietly(the_bar.fd); the_bar.fd = -1; fail: - errno = error; return NULL; } @@ -248,6 +243,6 @@ void bfs_bar_hide(struct bfs_bar *bar) { bfs_bar_reset(bar); - close(bar->fd); + xclose(bar->fd); bar->fd = -1; } diff --git a/bftw.c b/bftw.c index 64b1120..5f5afff 100644 --- a/bftw.c +++ b/bftw.c @@ -1,6 +1,6 @@ /**************************************************************************** * bfs * - * Copyright (C) 2015-2021 Tavian Barnes * + * Copyright (C) 2015-2022 Tavian Barnes * * * * Permission to use, copy, modify, and/or distribute this software for any * * purpose with or without fee is hereby granted. * @@ -244,7 +244,7 @@ static void bftw_file_close(struct bftw_cache *cache, struct bftw_file *file) { bftw_cache_remove(cache, file); - close(file->fd); + xclose(file->fd); file->fd = -1; } diff --git a/dir.c b/dir.c index 90c2e3e..024e767 100644 --- a/dir.c +++ b/dir.c @@ -138,12 +138,10 @@ struct bfs_dir *bfs_opendir(int at_fd, const char *at_path) { #else dir->dir = fdopendir(fd); if (!dir->dir) { - int error = errno; if (at_path) { - close(fd); + close_quietly(fd); } free(dir); - errno = error; return NULL; } @@ -280,7 +278,7 @@ int bfs_readdir(struct bfs_dir *dir, struct bfs_dirent *de) { int bfs_closedir(struct bfs_dir *dir) { #if __linux__ - int ret = close(dir->fd); + int ret = xclose(dir->fd); #else int ret = closedir(dir->dir); #endif diff --git a/exec.c b/exec.c index 45233e1..310756b 100644 --- a/exec.c +++ b/exec.c @@ -1,6 +1,6 @@ /**************************************************************************** * bfs * - * Copyright (C) 2017-2018 Tavian Barnes * + * Copyright (C) 2017-2022 Tavian Barnes * * * * Permission to use, copy, modify, and/or distribute this software for any * * purpose with or without fee is hereby granted. * @@ -308,12 +308,10 @@ static int bfs_exec_openwd(struct bfs_exec *execbuf, const struct BFTW *ftwbuf) } /** Close the working directory. */ -static int bfs_exec_closewd(struct bfs_exec *execbuf, const struct BFTW *ftwbuf) { - int ret = 0; - +static void bfs_exec_closewd(struct bfs_exec *execbuf, const struct BFTW *ftwbuf) { if (execbuf->wd_fd >= 0) { if (!ftwbuf || execbuf->wd_fd != ftwbuf->at_fd) { - ret = close(execbuf->wd_fd); + xclose(execbuf->wd_fd); } execbuf->wd_fd = -1; } @@ -323,8 +321,6 @@ static int bfs_exec_closewd(struct bfs_exec *execbuf, const struct BFTW *ftwbuf) execbuf->wd_path = NULL; execbuf->wd_len = 0; } - - return ret; } /** Actually spawn the process. */ diff --git a/main.c b/main.c index 7ceb0a2..ade5358 100644 --- a/main.c +++ b/main.c @@ -1,6 +1,6 @@ /**************************************************************************** * bfs * - * Copyright (C) 2015-2021 Tavian Barnes * + * Copyright (C) 2015-2022 Tavian Barnes * * * * Permission to use, copy, modify, and/or distribute this software for any * * purpose with or without fee is hereby granted. * @@ -54,6 +54,7 @@ #include "ctx.h" #include "eval.h" #include "parse.h" +#include "util.h" #include #include #include @@ -79,9 +80,7 @@ static int redirect(int fd, const char *path, int flags) { } int ret = dup2(newfd, fd); - int err = errno; - close(newfd); - errno = err; + close_quietly(newfd); return ret; } diff --git a/parse.c b/parse.c index aea7b4f..8ff47c2 100644 --- a/parse.c +++ b/parse.c @@ -1,6 +1,6 @@ /**************************************************************************** * bfs * - * Copyright (C) 2015-2021 Tavian Barnes * + * Copyright (C) 2015-2022 Tavian Barnes * * * * Permission to use, copy, modify, and/or distribute this software for any * * purpose with or without fee is hereby granted. * @@ -2743,7 +2743,7 @@ static CFILE *launch_pager(pid_t *pid, CFILE *cout) { goto fail_ctx; } - close(pipefd[0]); + xclose(pipefd[0]); bfs_spawn_destroy(&ctx); free(exe); return ret; @@ -2758,10 +2758,10 @@ fail_file: } fail_pipe: if (pipefd[1] >= 0) { - close(pipefd[1]); + xclose(pipefd[1]); } if (pipefd[0] >= 0) { - close(pipefd[0]); + xclose(pipefd[0]); } fail_exe: free(exe); diff --git a/spawn.c b/spawn.c index d4ff4fd..31f9897 100644 --- a/spawn.c +++ b/spawn.c @@ -1,6 +1,6 @@ /**************************************************************************** * bfs * - * Copyright (C) 2018-2019 Tavian Barnes * + * Copyright (C) 2018-2022 Tavian Barnes * * * * Permission to use, copy, modify, and/or distribute this software for any * * purpose with or without fee is hereby granted. * @@ -146,7 +146,7 @@ static void bfs_spawn_exec(const char *exe, const struct bfs_spawn *ctx, char ** int error; const struct bfs_spawn_action *actions = ctx ? ctx->actions : NULL; - close(pipefd[0]); + xclose(pipefd[0]); for (const struct bfs_spawn_action *action = actions; action; action = action->next) { // Move the error-reporting pipe out of the way if necessary... @@ -155,7 +155,7 @@ static void bfs_spawn_exec(const char *exe, const struct bfs_spawn *ctx, char ** if (fd < 0) { goto fail; } - close(pipefd[1]); + xclose(pipefd[1]); pipefd[1] = fd; } @@ -198,7 +198,7 @@ fail: // unsuccessfully, but won't know why (void) xwrite(pipefd[1], &error, sizeof(error)); - close(pipefd[1]); + xclose(pipefd[1]); _Exit(127); } @@ -224,15 +224,11 @@ pid_t bfs_spawn(const char *exe, const struct bfs_spawn *ctx, char **argv, char return -1; } - int error; pid_t pid = fork(); - if (pid < 0) { - error = errno; - close(pipefd[1]); - close(pipefd[0]); + close_quietly(pipefd[1]); + close_quietly(pipefd[0]); free(resolved); - errno = error; return -1; } else if (pid == 0) { // Child @@ -240,11 +236,12 @@ pid_t bfs_spawn(const char *exe, const struct bfs_spawn *ctx, char **argv, char } // Parent - close(pipefd[1]); + xclose(pipefd[1]); free(resolved); + int error; ssize_t nbytes = xread(pipefd[0], &error, sizeof(error)); - close(pipefd[0]); + xclose(pipefd[0]); if (nbytes == sizeof(error)) { int wstatus; waitpid(pid, &wstatus, 0); diff --git a/util.c b/util.c index fa7a5b6..71b3c53 100644 --- a/util.c +++ b/util.c @@ -1,6 +1,6 @@ /**************************************************************************** * bfs * - * Copyright (C) 2016-2021 Tavian Barnes * + * Copyright (C) 2016-2022 Tavian Barnes * * * * Permission to use, copy, modify, and/or distribute this software for any * * purpose with or without fee is hereby granted. * @@ -89,7 +89,7 @@ int dup_cloexec(int fd) { } if (fcntl(ret, F_SETFD, FD_CLOEXEC) == -1) { - close(ret); + close_quietly(ret); return -1; } @@ -106,10 +106,8 @@ int pipe_cloexec(int pipefd[2]) { } if (fcntl(pipefd[0], F_SETFD, FD_CLOEXEC) == -1 || fcntl(pipefd[1], F_SETFD, FD_CLOEXEC) == -1) { - int error = errno; - close(pipefd[1]); - close(pipefd[0]); - errno = error; + close_quietly(pipefd[1]); + close_quietly(pipefd[0]); return -1; } @@ -464,11 +462,23 @@ FILE *xfopen(const char *path, int flags) { FILE *ret = fdopen(fd, mode); if (!ret) { - int error = errno; - close(fd); - errno = error; + close_quietly(fd); return NULL; } return ret; } + +int xclose(int fd) { + int ret = close(fd); + if (ret != 0) { + assert(errno != EBADF); + } + return ret; +} + +void close_quietly(int fd) { + int error = errno; + xclose(fd); + errno = error; +} diff --git a/util.h b/util.h index ccac549..37c03fa 100644 --- a/util.h +++ b/util.h @@ -1,6 +1,6 @@ /**************************************************************************** * bfs * - * Copyright (C) 2016-2021 Tavian Barnes * + * Copyright (C) 2016-2022 Tavian Barnes * * * * Permission to use, copy, modify, and/or distribute this software for any * * purpose with or without fee is hereby granted. * @@ -298,4 +298,22 @@ char *xgetdelim(FILE *file, char delim); */ FILE *xfopen(const char *path, int flags); +/** + * close() wrapper that asserts the file descriptor is valid. + * + * @param fd + * The file descriptor to close. + * @return + * 0 on success, or -1 on error. + */ +int xclose(int fd); + +/** + * close() variant that preserves errno. + * + * @param fd + * The file descriptor to close. + */ +void close_quietly(int fd); + #endif // BFS_UTIL_H -- cgit v1.2.3