https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=922719ba36e097f6d0d7ff454d95ca5f9e8104f7

commit 922719ba36e097f6d0d7ff454d95ca5f9e8104f7
Author: Jeremy Drake <cyg...@jdrake.com>
Date:   Tue Jun 24 11:18:42 2025 -0700

    Cygwin: testsuite: test posix_file_actions_add(f)chdir
    
    Also test their interaction with addopen, as opens added subsequent to a
    chdir need to be relative to that new cwd.
    
    In order for the tests to compile on Linux, define O_SEARCH to O_PATH if
    O_SEARCH is not defined, and use the *chdir_np names instead of the
    now-standardized *chdir.
    
    Signed-off-by: Jeremy Drake <cyg...@jdrake.com>

Diff:
---
 winsup/testsuite/Makefile.am                    |   1 +
 winsup/testsuite/winsup.api/posix_spawn/chdir.c | 146 ++++++++++++++++++++++++
 winsup/testsuite/winsup.api/posix_spawn/fds.c   |   2 +-
 winsup/testsuite/winsup.api/posix_spawn/test.h  |   5 +
 4 files changed, 153 insertions(+), 1 deletion(-)

diff --git a/winsup/testsuite/Makefile.am b/winsup/testsuite/Makefile.am
index 4b056bd5b..957554a82 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/chdir \
        winsup.api/posix_spawn/errors \
        winsup.api/posix_spawn/fds \
        winsup.api/posix_spawn/signals \
diff --git a/winsup/testsuite/winsup.api/posix_spawn/chdir.c 
b/winsup/testsuite/winsup.api/posix_spawn/chdir.c
new file mode 100644
index 000000000..c6ccc45fb
--- /dev/null
+++ b/winsup/testsuite/winsup.api/posix_spawn/chdir.c
@@ -0,0 +1,146 @@
+#include "test.h"
+#include <fcntl.h>
+#include <limits.h>
+#include <spawn.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/* Linux is behind the times a bit (also needs the *chdir_np functions) */
+#ifndef O_SEARCH
+#  define O_SEARCH O_PATH
+#endif
+
+int handle_child (char *expected)
+{
+  char buf[PATH_MAX + 1];
+
+  nullError (getcwd (buf, sizeof (buf)));
+  testAssertMsg (!strcmp (buf, expected), "cwd '%s' != expected '%s'",
+                buf, expected);
+
+  return 0;
+}
+
+int handle_childfds (char *expectedcwd, char *expectedfd0, char *expectedfd1)
+{
+  char buf[PATH_MAX + 1];
+  ssize_t ret;
+
+  testAssert (handle_child (expectedcwd) == 0);
+
+  negError (ret = readlink ("/dev/fd/0", buf, PATH_MAX));
+  testAssertMsg (ret < PATH_MAX, "Path too long for PATH_MAX buffer");
+  buf[ret] = '\0';
+  testAssertMsg (!strcmp (buf, expectedfd0), "fd 0 '%s' != expected '%s'",
+                buf, expectedfd0);
+
+  negError (ret = readlink ("/dev/fd/1", buf, PATH_MAX));
+  testAssertMsg (ret < PATH_MAX, "Path too long for PATH_MAX buffer");
+  buf[ret] = '\0';
+  testAssertMsg (!strcmp (buf, expectedfd1), "fd 1 '%s' != expected '%s'",
+                buf, expectedfd1);
+
+  return 0;
+}
+
+static char tmpcwd[] = "tmpcwd.XXXXXX";
+static char tmppath[] = "tmpfile.XXXXXX";
+static char tmppath2[sizeof (tmpcwd) + 9] = {0};
+
+static void cleanup_tmpfiles (void)
+{
+  if (tmppath2[0])
+    unlink (tmppath2);
+  rmdir (tmpcwd);
+  unlink (tmppath);
+}
+
+int main (int argc, char **argv)
+{
+  posix_spawn_file_actions_t fa;
+  pid_t pid;
+  int status;
+  int fd;
+  char buf[PATH_MAX + 1];
+  char buffd0[PATH_MAX + 1];
+  char buffd1[PATH_MAX + 1];
+  char *childargv[] = {"chdir", "--child", buf, NULL, NULL, NULL};
+
+  /* unbuffer stdout */
+  setvbuf(stdout, NULL, _IONBF, 0);
+
+  if (argc == 3 && !strcmp (argv[1], "--child"))
+    return handle_child (argv[2]);
+  else if (argc == 5 && !strcmp (argv[1], "--child"))
+    return handle_childfds (argv[2], argv[3], argv[4]);
+
+  /* make a directory and a couple of files for testing */
+  nullError (mkdtemp (tmpcwd));
+  atexit (cleanup_tmpfiles);
+
+  negError (fd = mkstemp (tmppath));
+  negError (close (fd));
+
+  stpcpy (stpcpy (stpcpy (tmppath2, tmpcwd), "/"), "tmpfile2");
+  negError (fd = open (tmppath2, O_RDWR|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR));
+  negError (close (fd));
+
+
+  /* ensure cwd is inherited by default */
+  nullError (getcwd (buf, sizeof (buf)));
+  stpcpy (stpcpy (stpcpy (buffd0, buf), "/"), tmppath);
+  errCode (posix_spawn (&pid, MYSELF, NULL, NULL, childargv, environ));
+  negError (waitpid (pid, &status, 0));
+  exitStatus (status, 0);
+
+  /* test posix_spawn_file_actions_addchdir */
+  errCode (posix_spawn_file_actions_init (&fa));
+  errCode (posix_spawn_file_actions_addchdir_np (&fa, tmpcwd));
+
+  strcat (buf, "/");
+  strcat (buf, tmpcwd);
+  stpcpy (stpcpy (stpcpy (buffd1, buf), "/"), "tmpfile2");
+
+  errCode (posix_spawn (&pid, MYSELF, &fa, NULL, childargv, environ));
+  negError (waitpid (pid, &status, 0));
+  exitStatus (status, 0);
+  errCode (posix_spawn_file_actions_destroy (&fa));
+
+  /* test posix_spawn_file_actions_addfchdir */
+  negError (fd = open (tmpcwd, O_SEARCH|O_DIRECTORY|O_CLOEXEC, 0755));
+  errCode (posix_spawn_file_actions_init (&fa));
+  errCode (posix_spawn_file_actions_addfchdir_np (&fa, fd));
+  errCode (posix_spawn (&pid, MYSELF, &fa, NULL, childargv, environ));
+  negError (waitpid (pid, &status, 0));
+  exitStatus (status, 0);
+  errCode (posix_spawn_file_actions_destroy (&fa));
+  negError (close (fd));
+
+  /* test posix_spawn_file_actions_addchdir + addopen */
+  errCode (posix_spawn_file_actions_init (&fa));
+  errCode (posix_spawn_file_actions_addopen (&fa, 0, tmppath, O_RDONLY, 0644));
+  errCode (posix_spawn_file_actions_addchdir_np (&fa, tmpcwd));
+  errCode (posix_spawn_file_actions_addopen (&fa, 1, "tmpfile2", O_WRONLY, 
0644));
+  childargv[3] = buffd0;
+  childargv[4] = buffd1;
+  errCode (posix_spawn (&pid, MYSELF, &fa, NULL, childargv, environ));
+  negError (waitpid (pid, &status, 0));
+  exitStatus (status, 0);
+  errCode (posix_spawn_file_actions_destroy (&fa));
+
+  /* test posix_spawn_file_actions_addfchdir + addopen */
+  negError (fd = open (tmpcwd, O_SEARCH|O_DIRECTORY|O_CLOEXEC, 0755));
+  errCode (posix_spawn_file_actions_init (&fa));
+  errCode (posix_spawn_file_actions_addopen (&fa, 0, tmppath, O_RDONLY, 0644));
+  errCode (posix_spawn_file_actions_addfchdir_np (&fa, fd));
+  errCode (posix_spawn_file_actions_addopen (&fa, 1, "tmpfile2", O_WRONLY, 
0644));
+  errCode (posix_spawn (&pid, MYSELF, &fa, NULL, childargv, environ));
+  negError (waitpid (pid, &status, 0));
+  exitStatus (status, 0);
+  errCode (posix_spawn_file_actions_destroy (&fa));
+  negError (close (fd));
+
+  return 0;
+}
diff --git a/winsup/testsuite/winsup.api/posix_spawn/fds.c 
b/winsup/testsuite/winsup.api/posix_spawn/fds.c
index 6e6e8c635..98ce36ff3 100644
--- a/winsup/testsuite/winsup.api/posix_spawn/fds.c
+++ b/winsup/testsuite/winsup.api/posix_spawn/fds.c
@@ -115,7 +115,7 @@ int main (int argc, char **argv)
   errCode (posix_spawn_file_actions_destroy (&fa));
 
   /* TODO: test new fds (open or dup2) not 0 through 2 */
-  /* TODO: test posix_spawn_file_actions_add(f)chdir */
+  /* TODO: test error cases */
 
   negError (close (fd));
   negError (close (fdcloexec));
diff --git a/winsup/testsuite/winsup.api/posix_spawn/test.h 
b/winsup/testsuite/winsup.api/posix_spawn/test.h
index 531d11c4d..5c56ed10f 100644
--- a/winsup/testsuite/winsup.api/posix_spawn/test.h
+++ b/winsup/testsuite/winsup.api/posix_spawn/test.h
@@ -12,6 +12,11 @@
     error_at_line(1, errno, __FILE__, __LINE__, "%s", #x); \
 } while (0)
 
+#define nullError(x) do { \
+  if (!(x)) \
+    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); \

Reply via email to