Add test case for O_TMPFILE handling in open, openat

Message ID ecfc153b-5ea4-644a-b89a-1bf53f50b2e9@redhat.com
State Superseded
Headers

Commit Message

Florian Weimer Sept. 20, 2016, 6:51 p.m. UTC
  I noticed that we do not seem to have a test case for O_TMPFILE handling.

I have tested the attached patch with recent kernels and Red Hat's 3.10 
kernels (where it prints UNSUPPORTED).  I verified that probe_path works 
as intended with a vfat file system (which does not support O_TMPFILE 
even on a supported kernel).

Thanks,
Florian
  

Comments

Carlos O'Donell Sept. 20, 2016, 7:26 p.m. UTC | #1
On 09/20/2016 02:51 PM, Florian Weimer wrote:
> I noticed that we do not seem to have a test case for O_TMPFILE
> handling.
> 
> I have tested the attached patch with recent kernels and Red Hat's
> 3.10 kernels (where it prints UNSUPPORTED).  I verified that
> probe_path works as intended with a vfat file system (which does not
> support O_TMPFILE even on a supported kernel).

The actual details of the patch look good to me, so OK conditional
on more comments about:
* What is being tested.
* Is it sufficient?
  * If not, where might we improve in the future?
* Under what conditions do we mark as UNSUPPORTED?

The test cases should have lots of comments explaining the what and
why of the various tests we conduct. Sorry for sounding like a broken
record about documenting tests, but future reviewers of the test will
thank you for it.
  
Florian Weimer Sept. 21, 2016, 11:53 a.m. UTC | #2
On 09/20/2016 09:26 PM, Carlos O'Donell wrote:
> On 09/20/2016 02:51 PM, Florian Weimer wrote:
>> I noticed that we do not seem to have a test case for O_TMPFILE
>> handling.
>>
>> I have tested the attached patch with recent kernels and Red Hat's
>> 3.10 kernels (where it prints UNSUPPORTED).  I verified that
>> probe_path works as intended with a vfat file system (which does not
>> support O_TMPFILE even on a supported kernel).
>
> The actual details of the patch look good to me, so OK conditional
> on more comments about:
> * What is being tested.
> * Is it sufficient?
>   * If not, where might we improve in the future?
> * Under what conditions do we mark as UNSUPPORTED?

I tried to add a test for linkat, but it appears to be broken at the 
kernel level:

   <http://marc.info/?l=linux-man&m=147445864822403&w=2>

I'll probably commit the glibc test without the linkat bits.

Florian
  

Patch

Add test case for O_TMPFILE handling in open, openat

2016-09-20  Florian Weimer  <fweimer@redhat.com>

	* io/tst-open-tmpfile.c: New test.
	* io/Makefile (tests): Add it.

diff --git a/io/Makefile b/io/Makefile
index deb6100..f5977af 100644
--- a/io/Makefile
+++ b/io/Makefile
@@ -71,7 +71,8 @@  tests		:= test-utime test-stat test-stat2 test-lfs tst-getcwd \
 		   tst-renameat tst-fchownat tst-fchmodat tst-faccessat \
 		   tst-symlinkat tst-linkat tst-readlinkat tst-mkdirat \
 		   tst-mknodat tst-mkfifoat tst-ttyname_r bug-ftw5 \
-		   tst-posix_fallocate tst-fts tst-fts-lfs
+		   tst-posix_fallocate tst-fts tst-fts-lfs \
+		   tst-open-tmpfile
 
 ifeq ($(run-built-tests),yes)
 tests-special += $(objpfx)ftwtest.out
diff --git a/io/tst-open-tmpfile.c b/io/tst-open-tmpfile.c
new file mode 100644
index 0000000..33ec4ab
--- /dev/null
+++ b/io/tst-open-tmpfile.c
@@ -0,0 +1,151 @@ 
+/* Test open and openat with O_TMPFILE.
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#ifdef O_TMPFILE
+static int
+wrap_open (const char *path, int flags, mode_t mode)
+{
+  int ret = open (path, flags, mode);
+  if (ret < 0)
+    {
+      printf ("error: open (\"%s\", 0x%x, 0%03o): %m\n", path, flags, mode);
+      exit (1);
+    }
+  return ret;
+}
+
+static int
+wrap_openat (const char *path, int flags, mode_t mode)
+{
+  int ret = openat (AT_FDCWD, path, flags, mode);
+  if (ret < 0)
+    {
+      printf ("error: openat (\"%s\", 0x%x, 0%03o): %m\n", path, flags, mode);
+      exit (1);
+    }
+  return ret;
+}
+
+typedef int (*wrapper_func) (const char *, int, mode_t);
+
+static void
+check_wrapper_flags_mode (const char *op, wrapper_func wrapper,
+                          const char *path, int flags, mode_t mode)
+{
+  int fd = wrapper (path, flags | O_TMPFILE, mode);
+  struct stat64 st;
+  if (fstat64 (fd, &st) != 0)
+    {
+      printf ("error: fstat64: %m\n");
+      exit (1);
+    }
+  int actual_mode = st.st_mode & 0777;
+  if (actual_mode != mode)
+    {
+      printf ("error: unexpected mode; expected 0%03o, actual 0%03o\n",
+              mode, actual_mode);
+      exit (1);
+    }
+  close (fd);
+}
+
+    static void
+check_wrapper_mode (const char *op, wrapper_func wrapper,
+                    const char *path, mode_t mode)
+{
+  check_wrapper_flags_mode (op, wrapper, path, O_RDWR, mode);
+  check_wrapper_flags_mode (op, wrapper, path, O_RDWR | O_EXCL, mode);
+}
+
+static void
+check_wrapper (const char *op, wrapper_func wrapper,
+                    const char *path)
+{
+  check_wrapper_mode (op, wrapper, path, 0);
+  check_wrapper_mode (op, wrapper, path, 0640);
+  check_wrapper_mode (op, wrapper, path, 0600);
+  check_wrapper_mode (op, wrapper, path, 0755);
+  check_wrapper_mode (op, wrapper, path, 0750);
+}
+
+static bool
+probe_path (const char *path)
+{
+  int fd = openat (AT_FDCWD, path, O_TMPFILE | O_RDWR, 0);
+  if (fd < 0)
+    {
+      if (errno == EISDIR)
+        /* The system does not support O_TMPFILE.  */
+        {
+          printf ("info: kernel does not support O_TMPFILE\n");
+          exit (77);
+        }
+      if (errno == EOPNOTSUPP)
+        {
+          printf ("info: path does not support O_TMPFILE: %s\n", path);
+          return false;
+        }
+      printf ("error: openat (\"%s\", O_TMPFILE | O_RDWR): %m\n", path);
+      exit (1);
+    }
+  close (fd);
+  return true;
+}
+
+static int
+do_test (void)
+{
+  umask (0);
+  const char *paths[] = { ".", "/dev/shm", "/tmp",
+                          getenv ("TEST_TMPFILE_PATH"),
+                          NULL };
+  bool supported = false;
+  for (int i = 0; paths[i] != NULL; ++i)
+    if (probe_path (paths[i]))
+      {
+        supported = true;
+        check_wrapper ("open", wrap_open, paths[i]);
+        check_wrapper ("openat", wrap_openat, paths[i]);
+      }
+
+  if (!supported)
+    return 77;
+
+  return 0;
+}
+
+#else  /* !O_TMPFILE */
+
+static int
+do_test (void)
+{
+  return 77;
+}
+
+#endif  /* O_TMPFILE */
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"