From deef4028ecd70d5b0006b83da07d170c38efb3aa Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 31 Jan 2019 23:39:27 -0500 Subject: tests: Fail if bfs fails For tests that expect bfs to fail, the return value disambiguates whether bfs itself failed or whether the output was unexpected. --- tests.sh | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) (limited to 'tests.sh') diff --git a/tests.sh b/tests.sh index 5905d38..775a254 100755 --- a/tests.sh +++ b/tests.sh @@ -787,6 +787,11 @@ function invoke_bfs() { $BFS "$@" } +# Return value when bfs fails +EX_BFS=10 +# Return value when a difference is detected +EX_DIFF=20 + function bfs_diff() ( bfs_verbose "$@" @@ -802,9 +807,16 @@ function bfs_diff() ( fi $BFS "$@" | bfs_sort >"$ACTUAL" + local STATUS="${PIPESTATUS[0]}" if [ ! "$UPDATE" ]; then - diff -u "$EXPECTED" "$ACTUAL" + diff -u "$EXPECTED" "$ACTUAL" || return $EX_DIFF + fi + + if [ "$STATUS" -eq 0 ]; then + return 0 + else + return $EX_BFS fi ) @@ -890,7 +902,7 @@ function test_depth_error() { chmod +r scratch/foo rm -rf scratch/* - return $ret + [ $ret -eq $EX_BFS ] } function test_name() { @@ -1046,10 +1058,12 @@ function test_L_loops() { function test_L_loops_continue() { bfs_diff -L loops 2>/dev/null + [ $? -eq $EX_BFS ] } function test_X() { bfs_diff -X weirdnames 2>/dev/null + [ $? -eq $EX_BFS ] } function test_follow() { @@ -1708,7 +1722,7 @@ function test_printf_Y_error() { chmod +x scratch/foo rm -rf scratch/* - return $ret + [ $ret -eq $EX_BFS ] } function test_fstype() { -- cgit v1.2.3 From aa5f0f5745e4e7392c078d1fe28825c941f52f7c Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 31 Jan 2019 23:46:56 -0500 Subject: main: Fix closed standard stream handling bfs >&- should complain about a missing file descriptor, rather than silently succeeding. --- main.c | 40 ++++++++++++++++++++++++--------------- tests.sh | 29 ++++++++++++++++++++++++++++ tests/test_closed_stdin.out | 19 +++++++++++++++++++ tests/test_ok_closed_stdin.out | 0 tests/test_okdir_closed_stdin.out | 0 util.c | 10 +++------- 6 files changed, 76 insertions(+), 22 deletions(-) create mode 100644 tests/test_closed_stdin.out create mode 100644 tests/test_ok_closed_stdin.out create mode 100644 tests/test_okdir_closed_stdin.out (limited to 'tests.sh') diff --git a/main.c b/main.c index 2734aaf..3c19092 100644 --- a/main.c +++ b/main.c @@ -1,6 +1,6 @@ /**************************************************************************** * bfs * - * Copyright (C) 2015-2017 Tavian Barnes * + * Copyright (C) 2015-2019 Tavian Barnes * * * * Permission to use, copy, modify, and/or distribute this software for any * * purpose with or without fee is hereby granted. * @@ -24,16 +24,31 @@ #include /** - * Ensure that a file descriptor is open. + * Make sure the standard streams std{in,out,err} are open. If they are not, + * future open() calls may use those file descriptors, and std{in,out,err} will + * use them unintentionally. */ -static int ensure_fd_open(int fd, int flags) { - if (isopen(fd)) { - return 0; - } else if (redirect(fd, "/dev/null", flags) >= 0) { - return 0; - } else { +static int open_std_streams() { +#ifdef O_PATH + const int inflags = O_PATH, outflags = O_PATH; +#else + // These are intentionally backwards so that bfs >&- still fails with EBADF + const int inflags = O_WRONLY, outflags = O_RDONLY; +#endif + + if (!isopen(STDERR_FILENO) && redirect(STDERR_FILENO, "/dev/null", outflags) < 0) { + return -1; + } + if (!isopen(STDOUT_FILENO) && redirect(STDOUT_FILENO, "/dev/null", outflags) < 0) { + perror("redirect()"); + return -1; + } + if (!isopen(STDIN_FILENO) && redirect(STDIN_FILENO, "/dev/null", inflags) < 0) { + perror("redirect()"); return -1; } + + return 0; } /** @@ -42,13 +57,8 @@ static int ensure_fd_open(int fd, int flags) { int main(int argc, char *argv[]) { int ret = EXIT_FAILURE; - if (ensure_fd_open(STDIN_FILENO, O_RDONLY) != 0) { - goto done; - } - if (ensure_fd_open(STDOUT_FILENO, O_WRONLY) != 0) { - goto done; - } - if (ensure_fd_open(STDERR_FILENO, O_WRONLY) != 0) { + // Make sure the standard streams are open + if (open_std_streams() != 0) { goto done; } diff --git a/tests.sh b/tests.sh index 775a254..302a4c2 100755 --- a/tests.sh +++ b/tests.sh @@ -290,6 +290,11 @@ posix_tests=( test_user_name test_user_id + # Closed file descriptors + test_closed_stdin + test_closed_stdout + test_closed_stderr + # PATH_MAX handling test_deep @@ -385,8 +390,10 @@ bsd_tests=( test_nouser test_ok_stdin + test_ok_closed_stdin test_okdir_stdin + test_okdir_closed_stdin test_perm_000_plus test_perm_222_plus @@ -525,8 +532,10 @@ gnu_tests=( test_nouser + test_ok_closed_stdin test_ok_nothing + test_okdir_closed_stdin test_okdir_plus_semicolon test_perm_000_slash @@ -1929,6 +1938,26 @@ function test_fprint_error() { fi } +function test_closed_stdin() { + bfs_diff basic <&- +} + +function test_ok_closed_stdin() { + bfs_diff basic -ok echo \; <&- 2>/dev/null +} + +function test_okdir_closed_stdin() { + bfs_diff basic -okdir echo {} \; <&- 2>/dev/null +} + +function test_closed_stdout() { + ! invoke_bfs basic >&- 2>/dev/null +} + +function test_closed_stderr() { + ! invoke_bfs basic >&- 2>&- +} + if [ -t 1 -a ! "$VERBOSE" ]; then in_place=yes fi diff --git a/tests/test_closed_stdin.out b/tests/test_closed_stdin.out new file mode 100644 index 0000000..bb3cd8d --- /dev/null +++ b/tests/test_closed_stdin.out @@ -0,0 +1,19 @@ +basic +basic/a +basic/b +basic/c +basic/e +basic/g +basic/i +basic/j +basic/k +basic/l +basic/c/d +basic/e/f +basic/g/h +basic/j/foo +basic/k/foo +basic/l/foo +basic/k/foo/bar +basic/l/foo/bar +basic/l/foo/bar/baz diff --git a/tests/test_ok_closed_stdin.out b/tests/test_ok_closed_stdin.out new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_okdir_closed_stdin.out b/tests/test_okdir_closed_stdin.out new file mode 100644 index 0000000..e69de29 diff --git a/util.c b/util.c index b708527..1e5ebdb 100644 --- a/util.c +++ b/util.c @@ -85,8 +85,6 @@ bool isopen(int fd) { } int redirect(int fd, const char *path, int flags, ...) { - close(fd); - mode_t mode = 0; if (flags & O_CREAT) { va_list args; @@ -102,11 +100,9 @@ int redirect(int fd, const char *path, int flags, ...) { int ret = open(path, flags, mode); if (ret >= 0 && ret != fd) { - int other = ret; - ret = dup2(other, fd); - if (close(other) != 0) { - ret = -1; - } + int orig = ret; + ret = dup2(orig, fd); + close(orig); } return ret; -- cgit v1.2.3 From 30012351f6cadc25bf800c86f1431eade4ee0af5 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Fri, 1 Feb 2019 00:00:08 -0500 Subject: tests: New utility for making and testing socket files --- .gitignore | 1 + Makefile | 4 +- tests.sh | 22 +++---- tests/mksock.c | 131 +++++++++++++++++++++++++++++++++++++ tests/test_color.out | 1 + tests/test_color_ext.out | 1 + tests/test_color_ext0.out | 1 + tests/test_color_mh.out | 1 + tests/test_color_mh0.out | 1 + tests/test_color_mi.out | 1 + tests/test_color_missing_colon.out | 1 + tests/test_color_or.out | 1 + tests/test_color_or0_mi.out | 1 + tests/test_color_or_mi.out | 1 + tests/test_color_or_mi0.out | 1 + 15 files changed, 156 insertions(+), 13 deletions(-) create mode 100644 tests/mksock.c (limited to 'tests.sh') diff --git a/.gitignore b/.gitignore index b251086..99776af 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ *.o *.d /bfs +/tests/mksock diff --git a/Makefile b/Makefile index 2349727..c1249fa 100644 --- a/Makefile +++ b/Makefile @@ -94,7 +94,7 @@ tests/mksock: tests/mksock.o %.o: %.c $(CC) $(ALL_CFLAGS) -c $< -o $@ -check: all +check: all tests/mksock ./tests.sh distcheck: @@ -107,7 +107,7 @@ endif +$(MAKE) -Bs check clean: - $(RM) bfs *.o *.d + $(RM) bfs *.[od] tests/mksock tests/*.[od] install: $(MKDIR) $(DESTDIR)$(PREFIX)/bin diff --git a/tests.sh b/tests.sh index 302a4c2..57b19de 100755 --- a/tests.sh +++ b/tests.sh @@ -22,6 +22,16 @@ umask 022 export LC_ALL=C export TZ=UTC +function _realpath() { + ( + cd "${1%/*}" + echo "$PWD/${1##*/}" + ) +} + +BFS="$(_realpath ./bfs)" +TESTS="$(_realpath ./tests)" + # The temporary directory that will hold our test data TMP="$(mktemp -d "${TMPDIR:-/tmp}"/bfs.XXXXXXXXXX)" chown "$(id -u):$(id -g)" "$TMP" @@ -177,7 +187,7 @@ function make_rainbow() { # TODO: block # TODO: chardev ln -s nowhere "$1/broken" - # TODO: socket + "$TESTS/mksock" "$1/socket" touchp "$1"/s{u,g,ug}id chmod u+s "$1"/su{,g}id chmod g+s "$1"/s{u,}gid @@ -195,16 +205,6 @@ function make_scratch() { } make_scratch "$TMP/scratch" -function _realpath() { - ( - cd "${1%/*}" - echo "$PWD/${1##*/}" - ) -} - -BFS="$(_realpath ./bfs)" -TESTS="$(_realpath ./tests)" - posix_tests=( # General parsing test_basic diff --git a/tests/mksock.c b/tests/mksock.c new file mode 100644 index 0000000..a996d58 --- /dev/null +++ b/tests/mksock.c @@ -0,0 +1,131 @@ +/**************************************************************************** + * bfs * + * Copyright (C) 2019 Tavian Barnes * + * * + * Permission to use, copy, modify, and/or distribute this software for any * + * purpose with or without fee is hereby granted. * + * * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * + ****************************************************************************/ + +/** + * There's no standard Unix utility that creates a socket file, so this small + * program does the job. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * Print an error message. + */ +static void errmsg(const char *cmd, const char *path) { + fprintf(stderr, "%s: '%s': %s.\n", cmd, path, strerror(errno)); +} + +/** + * struct sockaddr_un::sun_path is very short, so we chdir() into the target + * directory before creating sockets in case the full path is too long but the + * file name is not. + */ +static int chdir_parent(const char *path) { + char *copy = strdup(path); + if (!copy) { + return -1; + } + const char *dir = dirname(copy); + + int ret = chdir(dir); + + int error = errno; + free(copy); + errno = error; + + return ret; +} + +/** + * Initialize a struct sockaddr_un with the right filename. + */ +static int init_sun(struct sockaddr_un *sock, const char *path) { + size_t len = strlen(path); + if (len == 0 || path[len - 1] == '/') { + errno = ENOENT; + return -1; + } + + char *copy = strdup(path); + if (!copy) { + return -1; + } + const char *base = basename(copy); + + len = strlen(base); + if (len >= sizeof(sock->sun_path)) { + free(copy); + errno = ENAMETOOLONG; + return -1; + } + + sock->sun_family = AF_UNIX; + memcpy(sock->sun_path, base, len + 1); + free(copy); + return 0; +} + +int main(int argc, char *argv[]) { + const char *cmd = argc > 0 ? argv[0] : "mksock"; + + if (argc != 2) { + fprintf(stderr, "Usage: %s NAME\n", cmd); + return EXIT_FAILURE; + } + + const char *path = argv[1]; + + if (chdir_parent(path) != 0) { + errmsg(cmd, path); + return EXIT_FAILURE; + } + + struct sockaddr_un sock; + if (init_sun(&sock, path) != 0) { + errmsg(cmd, path); + return EXIT_FAILURE; + } + + int fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd < 0) { + errmsg(cmd, path); + return EXIT_FAILURE; + } + + int ret = EXIT_SUCCESS; + + if (bind(fd, (struct sockaddr *)&sock, sizeof(sock)) != 0) { + errmsg(cmd, path); + ret = EXIT_FAILURE; + } + + if (close(fd) != 0) { + errmsg(cmd, path); + ret = EXIT_FAILURE; + } + + return ret; +} diff --git a/tests/test_color.out b/tests/test_color.out index e267da8..40e09b4 100644 --- a/tests/test_color.out +++ b/tests/test_color.out @@ -1,5 +1,6 @@ rainbow rainbow/exec.sh +rainbow/socket rainbow/link.txt rainbow/sticky_ow rainbow/sgid diff --git a/tests/test_color_ext.out b/tests/test_color_ext.out index d2e2a70..f8c4d28 100644 --- a/tests/test_color_ext.out +++ b/tests/test_color_ext.out @@ -1,5 +1,6 @@ rainbow rainbow/exec.sh +rainbow/socket rainbow/link.txt rainbow/file.txt rainbow/sticky_ow diff --git a/tests/test_color_ext0.out b/tests/test_color_ext0.out index 3bc8dc1..8710fc8 100644 --- a/tests/test_color_ext0.out +++ b/tests/test_color_ext0.out @@ -1,6 +1,7 @@ rainbow rainbow/file.txt rainbow/exec.sh +rainbow/socket rainbow/link.txt rainbow/sticky_ow rainbow/sgid diff --git a/tests/test_color_mh.out b/tests/test_color_mh.out index 600451e..32e2b95 100644 --- a/tests/test_color_mh.out +++ b/tests/test_color_mh.out @@ -1,5 +1,6 @@ rainbow rainbow/exec.sh +rainbow/socket rainbow/link.txt rainbow/mh1 rainbow/mh2 diff --git a/tests/test_color_mh0.out b/tests/test_color_mh0.out index e267da8..40e09b4 100644 --- a/tests/test_color_mh0.out +++ b/tests/test_color_mh0.out @@ -1,5 +1,6 @@ rainbow rainbow/exec.sh +rainbow/socket rainbow/link.txt rainbow/sticky_ow rainbow/sgid diff --git a/tests/test_color_mi.out b/tests/test_color_mi.out index e267da8..40e09b4 100644 --- a/tests/test_color_mi.out +++ b/tests/test_color_mi.out @@ -1,5 +1,6 @@ rainbow rainbow/exec.sh +rainbow/socket rainbow/link.txt rainbow/sticky_ow rainbow/sgid diff --git a/tests/test_color_missing_colon.out b/tests/test_color_missing_colon.out index d2e2a70..f8c4d28 100644 --- a/tests/test_color_missing_colon.out +++ b/tests/test_color_missing_colon.out @@ -1,5 +1,6 @@ rainbow rainbow/exec.sh +rainbow/socket rainbow/link.txt rainbow/file.txt rainbow/sticky_ow diff --git a/tests/test_color_or.out b/tests/test_color_or.out index 6e94bc6..e132546 100644 --- a/tests/test_color_or.out +++ b/tests/test_color_or.out @@ -1,5 +1,6 @@ rainbow rainbow/exec.sh +rainbow/socket rainbow/link.txt rainbow/broken rainbow/sticky_ow diff --git a/tests/test_color_or0_mi.out b/tests/test_color_or0_mi.out index cafa798..8b92ded 100644 --- a/tests/test_color_or0_mi.out +++ b/tests/test_color_or0_mi.out @@ -1,5 +1,6 @@ rainbow rainbow/exec.sh +rainbow/socket rainbow/broken rainbow/link.txt rainbow/sticky_ow diff --git a/tests/test_color_or_mi.out b/tests/test_color_or_mi.out index 7e57688..8a095a8 100644 --- a/tests/test_color_or_mi.out +++ b/tests/test_color_or_mi.out @@ -1,6 +1,7 @@ rainbow rainbow/broken rainbow/exec.sh +rainbow/socket rainbow/link.txt rainbow/sticky_ow rainbow/sgid diff --git a/tests/test_color_or_mi0.out b/tests/test_color_or_mi0.out index 7e57688..8a095a8 100644 --- a/tests/test_color_or_mi0.out +++ b/tests/test_color_or_mi0.out @@ -1,6 +1,7 @@ rainbow rainbow/broken rainbow/exec.sh +rainbow/socket rainbow/link.txt rainbow/sticky_ow rainbow/sgid -- cgit v1.2.3