diff --git a/subprojects/libglnx/.gitlab-ci.yml b/subprojects/libglnx/.gitlab-ci.yml
index 0d204ba8deea35a9b53ec1a972f3b8481a1d0acc..36638d7400d041e31f998b768518890c4936d395 100644
--- a/subprojects/libglnx/.gitlab-ci.yml
+++ b/subprojects/libglnx/.gitlab-ci.yml
@@ -1,4 +1,4 @@
-image: fedora:rawhide
+image: registry.fedoraproject.org/fedora:30
 
 stages:
   - build
diff --git a/subprojects/libglnx/Makefile-libglnx.am b/subprojects/libglnx/Makefile-libglnx.am
index 158063c7beee4b71100b5f85e4d2cbd43ffab4d7..957eae977e79ad9eb89f8abe9e2da9bd8e3b20cf 100644
--- a/subprojects/libglnx/Makefile-libglnx.am
+++ b/subprojects/libglnx/Makefile-libglnx.am
@@ -56,23 +56,25 @@ libglnx_la_LIBADD = $(libglnx_libs)
 libglnx_tests = test-libglnx-xattrs test-libglnx-fdio test-libglnx-errors test-libglnx-macros test-libglnx-shutil
 TESTS += $(libglnx_tests)
 
+libglnx_testlib_sources = $(libglnx_srcpath)/tests/libglnx-testlib.c
+
 check_PROGRAMS += $(libglnx_tests)
-test_libglnx_xattrs_SOURCES = $(libglnx_srcpath)/tests/test-libglnx-xattrs.c
+test_libglnx_xattrs_SOURCES = $(libglnx_testlib_sources) $(libglnx_srcpath)/tests/test-libglnx-xattrs.c
 test_libglnx_xattrs_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags)
 test_libglnx_xattrs_LDADD = $(libglnx_libs) libglnx.la
 
-test_libglnx_fdio_SOURCES = $(libglnx_srcpath)/tests/test-libglnx-fdio.c
+test_libglnx_fdio_SOURCES = $(libglnx_testlib_sources) $(libglnx_srcpath)/tests/test-libglnx-fdio.c
 test_libglnx_fdio_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags)
 test_libglnx_fdio_LDADD = $(libglnx_libs) libglnx.la
 
-test_libglnx_errors_SOURCES = $(libglnx_srcpath)/tests/test-libglnx-errors.c
+test_libglnx_errors_SOURCES = $(libglnx_testlib_sources) $(libglnx_srcpath)/tests/test-libglnx-errors.c
 test_libglnx_errors_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags)
 test_libglnx_errors_LDADD = $(libglnx_libs) libglnx.la
 
-test_libglnx_macros_SOURCES = $(libglnx_srcpath)/tests/test-libglnx-macros.c
+test_libglnx_macros_SOURCES = $(libglnx_testlib_sources) $(libglnx_srcpath)/tests/test-libglnx-macros.c
 test_libglnx_macros_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags)
 test_libglnx_macros_LDADD = $(libglnx_libs) libglnx.la
 
-test_libglnx_shutil_SOURCES = $(libglnx_srcpath)/tests/test-libglnx-shutil.c
+test_libglnx_shutil_SOURCES = $(libglnx_testlib_sources) $(libglnx_srcpath)/tests/test-libglnx-shutil.c
 test_libglnx_shutil_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags)
 test_libglnx_shutil_LDADD = $(libglnx_libs) libglnx.la
diff --git a/subprojects/libglnx/glnx-fdio.c b/subprojects/libglnx/glnx-fdio.c
index 288cc0235f3164eabaec172a13094883d399deaf..31bb15d246c8691ffb5132481d5dcaeb960c794f 100644
--- a/subprojects/libglnx/glnx-fdio.c
+++ b/subprojects/libglnx/glnx-fdio.c
@@ -278,17 +278,19 @@ glnx_open_tmpfile_linkable_at (int dfd,
   return open_tmpfile_core (dfd, subpath, flags, out_tmpf, error);
 }
 
+
 /* A variant of `glnx_open_tmpfile_linkable_at()` which doesn't support linking.
- * Useful for true temporary storage. The fd will be allocated in /var/tmp to
- * ensure maximum storage space.
+ * Useful for true temporary storage. The fd will be allocated in the specified
+ * directory.
  */
 gboolean
-glnx_open_anonymous_tmpfile (int          flags,
-                             GLnxTmpfile *out_tmpf,
-                             GError     **error)
+glnx_open_anonymous_tmpfile_full (int          flags,
+                                  const char  *dir,
+                                  GLnxTmpfile *out_tmpf,
+                                  GError     **error)
 {
   /* Add in O_EXCL */
-  if (!open_tmpfile_core (AT_FDCWD, "/var/tmp", flags | O_EXCL, out_tmpf, error))
+  if (!open_tmpfile_core (AT_FDCWD, dir, flags | O_EXCL, out_tmpf, error))
     return FALSE;
   if (out_tmpf->path)
     {
@@ -300,6 +302,21 @@ glnx_open_anonymous_tmpfile (int          flags,
   return TRUE;
 }
 
+/* A variant of `glnx_open_tmpfile_linkable_at()` which doesn't support linking.
+ * Useful for true temporary storage. The fd will be allocated in /var/tmp to
+ * ensure maximum storage space.
+ *
+ * If you need the file on a specific filesystem use glnx_open_anonymous_tmpfile_full()
+ * which lets you pass a directory.
+ */
+gboolean
+glnx_open_anonymous_tmpfile (int          flags,
+                             GLnxTmpfile *out_tmpf,
+                             GError     **error)
+{
+  return glnx_open_anonymous_tmpfile_full (flags, "/var/tmp", out_tmpf, error);
+}
+
 /* Use this after calling glnx_open_tmpfile_linkable_at() to give
  * the file its final name (link into place).
  */
@@ -347,8 +364,7 @@ glnx_link_tmpfile_at (GLnxTmpfile *tmpf,
     {
       /* This case we have O_TMPFILE, so our reference to it is via /proc/self/fd */
       char proc_fd_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(tmpf->fd) + 1];
-
-      sprintf (proc_fd_path, "/proc/self/fd/%i", tmpf->fd);
+      snprintf (proc_fd_path, sizeof (proc_fd_path), "/proc/self/fd/%i", tmpf->fd);
 
       if (replace)
         {
@@ -408,6 +424,45 @@ glnx_link_tmpfile_at (GLnxTmpfile *tmpf,
   return TRUE;
 }
 
+/* glnx_tmpfile_reopen_rdonly:
+ * @tmpf: tmpfile
+ * @error: Error
+ *
+ * Give up write access to the file descriptior.  One use
+ * case for this is fs-verity, which requires a read-only fd.
+ * It could also be useful to allocate an anonymous tmpfile
+ * write some sort of caching/indexing data to it, then reopen it
+ * read-only thereafter.
+ **/
+gboolean
+glnx_tmpfile_reopen_rdonly (GLnxTmpfile *tmpf,
+                            GError **error)
+{
+  g_return_val_if_fail (tmpf->fd >= 0, FALSE);
+  g_return_val_if_fail (tmpf->src_dfd == AT_FDCWD || tmpf->src_dfd >= 0, FALSE);
+
+  glnx_fd_close int rdonly_fd = -1;
+
+  if (tmpf->path)
+    {
+      if (!glnx_openat_rdonly (tmpf->src_dfd, tmpf->path, FALSE, &rdonly_fd, error))
+        return FALSE;
+    }
+  else
+    {
+      /* This case we have O_TMPFILE, so our reference to it is via /proc/self/fd */
+      char proc_fd_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(tmpf->fd) + 1];
+      snprintf (proc_fd_path, sizeof (proc_fd_path), "/proc/self/fd/%i", tmpf->fd);
+
+      if (!glnx_openat_rdonly (AT_FDCWD, proc_fd_path, TRUE, &rdonly_fd, error))
+        return FALSE;
+    }
+
+  glnx_close_fd (&tmpf->fd);
+  tmpf->fd = glnx_steal_fd (&rdonly_fd);
+  return TRUE;
+}
+
 /**
  * glnx_openat_rdonly:
  * @dfd: File descriptor for origin directory
diff --git a/subprojects/libglnx/glnx-fdio.h b/subprojects/libglnx/glnx-fdio.h
index c0a7cc1de847e0bc9ca2f1c3306eb413055701d7..9c57dc5ee290070f69313b8b3b8329de8965016d 100644
--- a/subprojects/libglnx/glnx-fdio.h
+++ b/subprojects/libglnx/glnx-fdio.h
@@ -83,6 +83,13 @@ glnx_open_anonymous_tmpfile (int flags,
                              GLnxTmpfile *out_tmpf,
                              GError **error);
 
+gboolean
+glnx_open_anonymous_tmpfile_full (int flags,
+                                  const char *dir,
+                                  GLnxTmpfile *out_tmpf,
+                                  GError **error);
+
+
 gboolean
 glnx_open_tmpfile_linkable_at (int dfd,
                                const char *subpath,
@@ -103,6 +110,10 @@ glnx_link_tmpfile_at (GLnxTmpfile *tmpf,
                       const char *target,
                       GError **error);
 
+gboolean
+glnx_tmpfile_reopen_rdonly (GLnxTmpfile *tmpf,
+                            GError **error);
+
 gboolean
 glnx_openat_rdonly (int             dfd,
                     const char     *path,
diff --git a/subprojects/libglnx/glnx-macros.h b/subprojects/libglnx/glnx-macros.h
index 6d8aca93f8a36b49e378c59bc374e169e0991c71..700fc75ceed0ab1248a95e4fe03abb8b8bc6c6e9 100644
--- a/subprojects/libglnx/glnx-macros.h
+++ b/subprojects/libglnx/glnx-macros.h
@@ -31,6 +31,16 @@ G_BEGIN_DECLS
 /* All of these are for C only. */
 #ifndef __GI_SCANNER__
 
+/* fixes builds against musl, taken from glibc unistd.h */
+#ifndef TEMP_FAILURE_RETRY
+#define TEMP_FAILURE_RETRY(expression) \
+  (__extension__                                                              \
+    ({ long int __result;                                                     \
+       do __result = (long int) (expression);                                 \
+       while (__result == -1L && errno == EINTR);                             \
+       __result; }))
+#endif
+
 /* Taken from https://github.com/systemd/systemd/src/basic/string-util.h
  * at revision v228-666-gcf6c8c4
  */