b1dca6
commit b2e93de0ffedcfe2cfba100d47a4d4f6f85cea0b
b1dca6
Author: DJ Delorie <dj@redhat.com>
b1dca6
Date:   Tue Dec 4 00:03:12 2018 -0500
b1dca6
b1dca6
    test-container: add "su" command to run test as root, add unshare hints
b1dca6
    
b1dca6
    * support/test-container.c (check_for_unshare_hints): New.
b1dca6
    (main): Call it if unshare fails.  Add support for "su" scriptlet
b1dca6
    command.
b1dca6
b1dca6
diff --git a/support/test-container.c b/support/test-container.c
b1dca6
index fe0ebbd07df83da7..1d1aebeaf3412573 100644
b1dca6
--- a/support/test-container.c
b1dca6
+++ b/support/test-container.c
b1dca6
@@ -88,15 +88,22 @@ int verbose = 0;
b1dca6
    * mytest.root/ is rsync'd into container
b1dca6
    * mytest.root/preclean.req causes fresh rsync (with delete) before
b1dca6
      test if present
b1dca6
-   * mytest.root/mytset.script has a list of "commands" to run:
b1dca6
+   * mytest.root/mytest.script has a list of "commands" to run:
b1dca6
        syntax:
b1dca6
          # comment
b1dca6
+         su
b1dca6
          mv FILE FILE
b1dca6
 	 cp FILE FILE
b1dca6
 	 rm FILE
b1dca6
 	 FILE must start with $B/, $S/, $I/, $L/, or /
b1dca6
 	  (expands to build dir, source dir, install dir, library dir
b1dca6
 	   (in container), or container's root)
b1dca6
+       details:
b1dca6
+         - '#': A comment.
b1dca6
+         - 'su': Enables running test as root in the container.
b1dca6
+         - 'mv': A minimal move files command.
b1dca6
+         - 'cp': A minimal copy files command.
b1dca6
+         - 'rm': A minimal remove files command.
b1dca6
    * mytest.root/postclean.req causes fresh rsync (with delete) after
b1dca6
      test if present
b1dca6
 
b1dca6
@@ -349,6 +356,7 @@ recursive_remove (char *path)
b1dca6
 
b1dca6
   switch (child) {
b1dca6
   case -1:
b1dca6
+    perror("fork");
b1dca6
     FAIL_EXIT1 ("Unable to fork");
b1dca6
   case 0:
b1dca6
     /* Child.  */
b1dca6
@@ -610,6 +618,47 @@ rsync (char *src, char *dest, int and_delete)
b1dca6
 }
b1dca6
 
b1dca6
 
b1dca6
+
b1dca6
+/* See if we can detect what the user needs to do to get unshare
b1dca6
+   support working for us.  */
b1dca6
+void
b1dca6
+check_for_unshare_hints (void)
b1dca6
+{
b1dca6
+  FILE *f;
b1dca6
+  int i;
b1dca6
+
b1dca6
+  /* Default Debian Linux disables user namespaces, but allows a way
b1dca6
+     to enable them.  */
b1dca6
+  f = fopen ("/proc/sys/kernel/unprivileged_userns_clone", "r");
b1dca6
+  if (f != NULL)
b1dca6
+    {
b1dca6
+      i = 99; /* Sentinel.  */
b1dca6
+      fscanf (f, "%d", &i);
b1dca6
+      if (i == 0)
b1dca6
+	{
b1dca6
+	  printf ("To enable test-container, please run this as root:\n");
b1dca6
+	  printf ("  echo 1 > /proc/sys/kernel/unprivileged_userns_clone\n");
b1dca6
+	}
b1dca6
+      fclose (f);
b1dca6
+      return;
b1dca6
+    }
b1dca6
+
b1dca6
+  /* ALT Linux has an alternate way of doing the same.  */
b1dca6
+  f = fopen ("/proc/sys/kernel/userns_restrict", "r");
b1dca6
+  if (f != NULL)
b1dca6
+    {
b1dca6
+      i = 99; /* Sentinel.  */
b1dca6
+      fscanf (f, "%d", &i);
b1dca6
+      if (i == 1)
b1dca6
+	{
b1dca6
+	  printf ("To enable test-container, please run this as root:\n");
b1dca6
+	  printf ("  echo 0 > /proc/sys/kernel/userns_restrict\n");
b1dca6
+	}
b1dca6
+      fclose (f);
b1dca6
+      return;
b1dca6
+    }
b1dca6
+}
b1dca6
+
b1dca6
 int
b1dca6
 main (int argc, char **argv)
b1dca6
 {
b1dca6
@@ -628,6 +677,8 @@ main (int argc, char **argv)
b1dca6
 
b1dca6
   uid_t original_uid;
b1dca6
   gid_t original_gid;
b1dca6
+  /* If set, the test runs as root instead of the user running the testsuite.  */
b1dca6
+  int be_su = 0;
b1dca6
   int UMAP;
b1dca6
   int GMAP;
b1dca6
   /* Used for "%lld %lld 1" so need not be large.  */
b1dca6
@@ -857,6 +908,10 @@ main (int argc, char **argv)
b1dca6
 	      {
b1dca6
 		maybe_xunlink (the_words[1]);
b1dca6
 	      }
b1dca6
+	    else if (nt == 1 && strcmp (the_words[0], "su") == 0)
b1dca6
+	      {
b1dca6
+		be_su = 1;
b1dca6
+	      }
b1dca6
 	    else if (nt > 0 && the_words[0][0] != '#')
b1dca6
 	      {
b1dca6
 		printf ("\033[31minvalid [%s]\033[0m\n", the_words[0]);
b1dca6
@@ -910,7 +965,12 @@ main (int argc, char **argv)
b1dca6
       /* Older kernels may not support all the options, or security
b1dca6
 	 policy may block this call.  */
b1dca6
       if (errno == EINVAL || errno == EPERM)
b1dca6
-	FAIL_UNSUPPORTED ("unable to unshare user/fs: %s", strerror (errno));
b1dca6
+	{
b1dca6
+	  int saved_errno = errno;
b1dca6
+	  if (errno == EPERM)
b1dca6
+	    check_for_unshare_hints ();
b1dca6
+	  FAIL_UNSUPPORTED ("unable to unshare user/fs: %s", strerror (saved_errno));
b1dca6
+	}
b1dca6
       else
b1dca6
 	FAIL_EXIT1 ("unable to unshare user/fs: %s", strerror (errno));
b1dca6
     }
b1dca6
@@ -981,7 +1041,7 @@ main (int argc, char **argv)
b1dca6
     FAIL_EXIT1 ("can't write to /proc/self/uid_map\n");
b1dca6
 
b1dca6
   sprintf (tmp, "%lld %lld 1\n",
b1dca6
-	   (long long) original_uid, (long long) original_uid);
b1dca6
+	   (long long) (be_su ? 0 : original_uid), (long long) original_uid);
b1dca6
   write (UMAP, tmp, strlen (tmp));
b1dca6
   xclose (UMAP);
b1dca6
 
b1dca6
@@ -1002,7 +1062,7 @@ main (int argc, char **argv)
b1dca6
     FAIL_EXIT1 ("can't write to /proc/self/gid_map\n");
b1dca6
 
b1dca6
   sprintf (tmp, "%lld %lld 1\n",
b1dca6
-	   (long long) original_gid, (long long) original_gid);
b1dca6
+	   (long long) (be_su ? 0 : original_gid), (long long) original_gid);
b1dca6
   write (GMAP, tmp, strlen (tmp));
b1dca6
   xclose (GMAP);
b1dca6