b1dca6
commit 4f79b3e2fb3eba003240ec38a0e68702b9a60b86
b1dca6
Author: DJ Delorie <dj@redhat.com>
b1dca6
Date:   Mon Feb 3 14:49:25 2020 -0500
b1dca6
b1dca6
    test-container: add exec, cwd
b1dca6
    
b1dca6
    exec <path_to_test_binary> [optional_argv_0]
b1dca6
    
b1dca6
      copies test binary to specified location and runs it from
b1dca6
      there.  If the second argument is provided, that will
b1dca6
      be used for argv[0]
b1dca6
    
b1dca6
    cwd <directory>
b1dca6
    
b1dca6
      attempts to chdir(directory) before running test
b1dca6
    
b1dca6
    Note: "cwd" not "cd" as it takes effect just before the
b1dca6
    test binary runs, not when it's encountered in the script,
b1dca6
    so it can't be used as a path shortcut like "cd" would imply.
b1dca6
    
b1dca6
    cleanup: use xstrdup() instead of strdup()
b1dca6
    
b1dca6
    Reviewed-by: Carlos O'Donell <carlos@redhat.com>
b1dca6
b1dca6
diff --git a/support/test-container.c b/support/test-container.c
b1dca6
index 6503cea90309b9b0..9488ec7b4a824380 100644
b1dca6
--- a/support/test-container.c
b1dca6
+++ b/support/test-container.c
b1dca6
@@ -95,6 +95,8 @@ int verbose = 0;
b1dca6
          mv FILE FILE
b1dca6
 	 cp FILE FILE
b1dca6
 	 rm FILE
b1dca6
+	 cwd PATH
b1dca6
+	 exec 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
@@ -104,6 +106,8 @@ int verbose = 0;
b1dca6
          - 'mv': A minimal move files command.
b1dca6
          - 'cp': A minimal copy files command.
b1dca6
          - 'rm': A minimal remove files command.
b1dca6
+	 - 'cwd': set test working directory
b1dca6
+	 - 'exec': change test binary location (may end in /)
b1dca6
    * mytest.root/postclean.req causes fresh rsync (with delete) after
b1dca6
      test if present
b1dca6
 
b1dca6
@@ -147,7 +151,7 @@ maybe_xmkdir (const char *path, mode_t mode)
b1dca6
 }
b1dca6
 
b1dca6
 /* Temporarily concatenate multiple strings into one.  Allows up to 10
b1dca6
-   temporary results; use strdup () if you need them to be
b1dca6
+   temporary results; use xstrdup () if you need them to be
b1dca6
    permanent.  */
b1dca6
 static char *
b1dca6
 concat (const char *str, ...)
b1dca6
@@ -670,11 +674,13 @@ main (int argc, char **argv)
b1dca6
   char *new_objdir_path;
b1dca6
   char *new_srcdir_path;
b1dca6
   char **new_child_proc;
b1dca6
+  char *new_child_exec;
b1dca6
   char *command_root;
b1dca6
   char *command_base;
b1dca6
   char *command_basename;
b1dca6
   char *so_base;
b1dca6
   int do_postclean = 0;
b1dca6
+  char *change_cwd = NULL;
b1dca6
 
b1dca6
   int pipes[2];
b1dca6
   char pid_buf[20];
b1dca6
@@ -701,7 +707,7 @@ main (int argc, char **argv)
b1dca6
 
b1dca6
   if (argc < 2)
b1dca6
     {
b1dca6
-      fprintf (stderr, "Usage: containerize <program to run> <args...>\n");
b1dca6
+      fprintf (stderr, "Usage: test-container <program to run> <args...>\n");
b1dca6
       exit (1);
b1dca6
     }
b1dca6
 
b1dca6
@@ -746,12 +752,13 @@ main (int argc, char **argv)
b1dca6
 	}
b1dca6
     }
b1dca6
 
b1dca6
-  pristine_root_path = strdup (concat (support_objdir_root,
b1dca6
+  pristine_root_path = xstrdup (concat (support_objdir_root,
b1dca6
 				       "/testroot.pristine", NULL));
b1dca6
-  new_root_path = strdup (concat (support_objdir_root,
b1dca6
+  new_root_path = xstrdup (concat (support_objdir_root,
b1dca6
 				  "/testroot.root", NULL));
b1dca6
   new_cwd_path = get_current_dir_name ();
b1dca6
   new_child_proc = argv + 1;
b1dca6
+  new_child_exec = argv[1];
b1dca6
 
b1dca6
   lock_fd = open (concat (pristine_root_path, "/lock.fd", NULL),
b1dca6
 		 O_CREAT | O_TRUNC | O_RDWR, 0666);
b1dca6
@@ -778,10 +785,10 @@ main (int argc, char **argv)
b1dca6
     command_root = concat (support_srcdir_root,
b1dca6
 			   argv[1] + strlen (support_objdir_root),
b1dca6
 			   ".root", NULL);
b1dca6
-  command_root = strdup (command_root);
b1dca6
+  command_root = xstrdup (command_root);
b1dca6
 
b1dca6
   /* This cuts off the ".root" we appended above.  */
b1dca6
-  command_base = strdup (command_root);
b1dca6
+  command_base = xstrdup (command_root);
b1dca6
   command_base[strlen (command_base) - 5] = 0;
b1dca6
 
b1dca6
   /* This is the basename of the test we're running.  */
b1dca6
@@ -792,7 +799,7 @@ main (int argc, char **argv)
b1dca6
     ++command_basename;
b1dca6
 
b1dca6
   /* Shared object base directory.  */
b1dca6
-  so_base = strdup (argv[1]);
b1dca6
+  so_base = xstrdup (argv[1]);
b1dca6
   if (strrchr (so_base, '/') != NULL)
b1dca6
     strrchr (so_base, '/')[1] = 0;
b1dca6
 
b1dca6
@@ -806,9 +813,9 @@ main (int argc, char **argv)
b1dca6
       && S_ISDIR (st.st_mode))
b1dca6
     rsync (command_root, new_root_path, 0);
b1dca6
 
b1dca6
-  new_objdir_path = strdup (concat (new_root_path,
b1dca6
+  new_objdir_path = xstrdup (concat (new_root_path,
b1dca6
 				    support_objdir_root, NULL));
b1dca6
-  new_srcdir_path = strdup (concat (new_root_path,
b1dca6
+  new_srcdir_path = xstrdup (concat (new_root_path,
b1dca6
 				    support_srcdir_root, NULL));
b1dca6
 
b1dca6
   /* new_cwd_path starts with '/' so no "/" needed between the two.  */
b1dca6
@@ -868,7 +875,10 @@ main (int argc, char **argv)
b1dca6
 		  the_words[i] = concat (new_root_path,
b1dca6
 					 support_libdir_prefix,
b1dca6
 					 the_words[i] + 2, NULL);
b1dca6
-		else if (the_words[i][0] == '/')
b1dca6
+		/* "exec" and "cwd" use inside-root paths.  */
b1dca6
+		else if (strcmp (the_words[0], "exec") != 0
b1dca6
+			 && strcmp (the_words[0], "cwd") != 0
b1dca6
+			 && the_words[i][0] == '/')
b1dca6
 		  the_words[i] = concat (new_root_path,
b1dca6
 					 the_words[i], NULL);
b1dca6
 	      }
b1dca6
@@ -912,13 +922,49 @@ main (int argc, char **argv)
b1dca6
 	      {
b1dca6
 		maybe_xunlink (the_words[1]);
b1dca6
 	      }
b1dca6
+	    else if (nt >= 2 && strcmp (the_words[0], "exec") == 0)
b1dca6
+	      {
b1dca6
+		/* The first argument is the desired location and name
b1dca6
+		   of the test binary as we wish to exec it; we will
b1dca6
+		   copy the binary there.  The second (optional)
b1dca6
+		   argument is the value to pass as argv[0], it
b1dca6
+		   defaults to the same as the first argument.  */
b1dca6
+		char *new_exec_path = the_words[1];
b1dca6
+
b1dca6
+		/* If the new exec path ends with a slash, that's the
b1dca6
+		 * directory, and use the old test base name.  */
b1dca6
+		if (new_exec_path [strlen(new_exec_path) - 1] == '/')
b1dca6
+		    new_exec_path = concat (new_exec_path,
b1dca6
+					    basename (new_child_proc[0]),
b1dca6
+					    NULL);
b1dca6
+
b1dca6
+
b1dca6
+		/* new_child_proc is in the build tree, so has the
b1dca6
+		   same path inside the chroot as outside.  The new
b1dca6
+		   exec path is, by definition, relative to the
b1dca6
+		   chroot.  */
b1dca6
+		copy_one_file (new_child_proc[0],  concat (new_root_path,
b1dca6
+							   new_exec_path,
b1dca6
+							   NULL));
b1dca6
+
b1dca6
+		new_child_exec =  xstrdup (new_exec_path);
b1dca6
+		if (the_words[2])
b1dca6
+		  new_child_proc[0] = xstrdup (the_words[2]);
b1dca6
+		else
b1dca6
+		  new_child_proc[0] = new_child_exec;
b1dca6
+	      }
b1dca6
+	    else if (nt == 2 && strcmp (the_words[0], "cwd") == 0)
b1dca6
+	      {
b1dca6
+		change_cwd = xstrdup (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
+		fprintf (stderr, "\033[31minvalid [%s]\033[0m\n", the_words[0]);
b1dca6
+		exit (1);
b1dca6
 	      }
b1dca6
 	  }
b1dca6
 	fclose (f);
b1dca6
@@ -1089,11 +1135,17 @@ main (int argc, char **argv)
b1dca6
   write (GMAP, tmp, strlen (tmp));
b1dca6
   xclose (GMAP);
b1dca6
 
b1dca6
+  if (change_cwd)
b1dca6
+    {
b1dca6
+      if (chdir (change_cwd) < 0)
b1dca6
+	FAIL_EXIT1 ("Can't cd to %s inside container - ", change_cwd);
b1dca6
+    }
b1dca6
+
b1dca6
   /* Now run the child.  */
b1dca6
-  execvp (new_child_proc[0], new_child_proc);
b1dca6
+  execvp (new_child_exec, new_child_proc);
b1dca6
 
b1dca6
   /* Or don't run the child?  */
b1dca6
-  FAIL_EXIT1 ("Unable to exec %s\n", new_child_proc[0]);
b1dca6
+  FAIL_EXIT1 ("Unable to exec %s\n", new_child_exec);
b1dca6
 
b1dca6
   /* Because gcc won't know error () never returns...  */
b1dca6
   exit (EXIT_UNSUPPORTED);