Currently just a couple of tests of error conditions, but I have more tests to add.
Signed-off-by: Jeremy Drake <[email protected]> --- 1) is testsuite subject to the same review requirements or can I push more tests as I refactor them from my more monolithic test program? 2) This may have revealed a bug (or, non-compliance with POSIX docs). The posix_spawn docs say posix_spawn returns the errors from exec ("If posix_spawn() or posix_spawnp() fail for any of the reasons that would cause fork() or one of the exec family of functions to fail, including when the corresponding exec function would attempt a fallback to sh instead of failing with [ENOEXEC], an error value shall be returned as described by fork() and exec, respectively; or, if the error occurs after the calling process successfully returns, the child process shall exit with exit status 127."). The exec docs say that it should return ENOTDIR if "A component of the new process image file's path prefix names an existing file that is neither a directory nor a symbolic link to a directory, or the new process image file's pathname contains at least one non-<slash> character and ends with one or more trailing <slash> characters and the last pathname component names an existing file that is neither a directory nor a symbolic link to a directory." For the test of /path/to/file/ls where file is a regular file, Linux does indeed return ENOTDIR but Cygwin returns ENOENT. Is this a known limitation of Cygwin, or just an error code that just wasn't hooked up somewhere? winsup/testsuite/Makefile.am | 1 + .../testsuite/winsup.api/posix_spawn/errors.c | 46 +++++++++++++++++++ .../testsuite/winsup.api/posix_spawn/test.h | 36 +++++++++++++++ 3 files changed, 83 insertions(+) create mode 100644 winsup/testsuite/winsup.api/posix_spawn/errors.c create mode 100644 winsup/testsuite/winsup.api/posix_spawn/test.h diff --git a/winsup/testsuite/Makefile.am b/winsup/testsuite/Makefile.am index 8f2967a6dc..0b265261cd 100644 --- a/winsup/testsuite/Makefile.am +++ b/winsup/testsuite/Makefile.am @@ -311,6 +311,7 @@ check_PROGRAMS = \ winsup.api/pthread/self2 \ winsup.api/pthread/threadidafterfork \ winsup.api/pthread/tsd1 \ + winsup.api/posix_spawn/errors \ winsup.api/samples/sample-fail \ winsup.api/samples/sample-pass # winsup.api/ltp/ulimit01 is omitted as we don't have <ulimit.h> diff --git a/winsup/testsuite/winsup.api/posix_spawn/errors.c b/winsup/testsuite/winsup.api/posix_spawn/errors.c new file mode 100644 index 0000000000..6f8d102b8f --- /dev/null +++ b/winsup/testsuite/winsup.api/posix_spawn/errors.c @@ -0,0 +1,46 @@ +#include "test.h" +#include <spawn.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +char tmppath[] = "empty.XXXXXX"; + +void cleanup_tmpfile (void) +{ + unlink (tmppath); +} + +int main (void) +{ + pid_t pid; + int fd; + char *childargv[] = {"ls", NULL}; + char tmpsub[sizeof (tmppath) + 3]; + char *p; + + /* unbuffer stdout */ + setvbuf(stdout, NULL, _IONBF, 0); + + negError (fd = mkstemp (tmppath)); + negError (close (fd)); + atexit (cleanup_tmpfile); + + /* expected ENOENT: posix_spawn without full path */ + errCodeExpected (ENOENT, posix_spawn (&pid, childargv[0], NULL, NULL, childargv, environ)); + + /* expected EACCES: posix_spawn with path to non-executable file */ + errCodeExpected (EACCES, posix_spawn (&pid, tmppath, NULL, NULL, childargv, environ)); + + p = stpcpy (tmpsub, tmppath); + p = stpcpy (p, "/ls"); + +#ifndef __CYGWIN__ + /* Cygwin returns ENOENT rather than ENOTDIR here */ + /* expected ENOTDIR: posix_spawn with file as non-leaf entry in path */ + errCodeExpected (ENOTDIR, posix_spawn (&pid, tmpsub, NULL, NULL, childargv, environ)); +#endif + + return 0; +} diff --git a/winsup/testsuite/winsup.api/posix_spawn/test.h b/winsup/testsuite/winsup.api/posix_spawn/test.h new file mode 100644 index 0000000000..9cdcc9079d --- /dev/null +++ b/winsup/testsuite/winsup.api/posix_spawn/test.h @@ -0,0 +1,36 @@ +#ifndef _POSIX_SPAWN_TEST_H_ +#define _POSIX_SPAWN_TEST_H_ + +#define _GNU_SOURCE +#include <errno.h> +#include <error.h> +#include <signal.h> +#include <sys/wait.h> + +#define negError(x) do { \ + if ((x) < 0) \ + error_at_line(1, errno, __FILE__, __LINE__, "%s", #x); \ +} while (0) + +#define sigError(x) do { \ + if ((x) == SIG_ERR) \ + error_at_line(1, errno, __FILE__, __LINE__, "%s", #x); \ +} while (0) + +#define errCodeExpected(expected, x) do { \ + int _errcode = (x); \ + if (_errcode != (expected)) \ + error_at_line(1, _errcode, __FILE__, __LINE__, "%s", #x); \ +} while (0) + +#define errCode(x) errCodeExpected(0, x) + +#define exitStatus(status, expectedExitCode) do { \ + if (WIFSIGNALED ((status))) \ + error_at_line (128 + WTERMSIG ((status)), 0, __FILE__, __LINE__ - 2, "child terminated with signal %d", WTERMSIG ((status))); \ + else if (WIFEXITED ((status)) && WEXITSTATUS ((status)) != (expectedExitCode)) \ + error_at_line (WEXITSTATUS ((status)), 0, __FILE__, __LINE__ - 2, "child exited with code %d", WEXITSTATUS ((status))); \ +} while (0) + +#endif /* _POSIX_SPAWN_TEST_H_ */ + -- 2.49.0.windows.1
