math: Remove slow paths in tan [BZ #15267]
[glibc.git] / support / test-container.c
blob28cc44d9f1e28c10e3086f6f5e786ff5340230e9
1 /* Run a test case in an isolated namespace.
2 Copyright (C) 2018-2021 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
19 #define _FILE_OFFSET_BITS 64
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sched.h>
25 #include <sys/syscall.h>
26 #include <unistd.h>
27 #include <sys/types.h>
28 #include <dirent.h>
29 #include <string.h>
30 #include <sys/stat.h>
31 #include <sys/fcntl.h>
32 #include <sys/file.h>
33 #include <sys/wait.h>
34 #include <stdarg.h>
35 #include <sys/sysmacros.h>
36 #include <ctype.h>
37 #include <utime.h>
38 #include <errno.h>
39 #include <error.h>
40 #include <libc-pointer-arith.h>
42 #ifdef __linux__
43 #include <sys/mount.h>
44 #endif
46 #include <support/support.h>
47 #include <support/xunistd.h>
48 #include <support/capture_subprocess.h>
49 #include "check.h"
50 #include "test-driver.h"
52 #ifndef __linux__
53 #define mount(s,t,fs,f,d) no_mount()
54 int no_mount (void)
56 FAIL_UNSUPPORTED("mount not supported; port needed");
58 #endif
60 int verbose = 0;
62 /* Running a test in a container is tricky. There are two main
63 categories of things to do:
65 1. "Once" actions, like setting up the container and doing an
66 install into it.
68 2. "Per-test" actions, like copying in support files and
69 configuring the container.
72 "Once" actions:
74 * mkdir $buildroot/testroot.pristine/
75 * install into it
76 * default glibc install
77 * create /bin for /bin/sh
78 * create $(complocaledir) so localedef tests work with default paths.
79 * install /bin/sh, /bin/echo, and /bin/true.
80 * rsync to $buildroot/testroot.root/
82 "Per-test" actions:
83 * maybe rsync to $buildroot/testroot.root/
84 * copy support files and test binary
85 * chroot/unshare
86 * set up any mounts (like /proc)
87 * run ldconfig
89 Magic files:
91 For test $srcdir/foo/mytest.c we look for $srcdir/foo/mytest.root
92 and, if found...
94 * mytest.root/ is rsync'd into container
95 * mytest.root/preclean.req causes fresh rsync (with delete) before
96 test if present
97 * mytest.root/mytest.script has a list of "commands" to run:
98 syntax:
99 # comment
101 mv FILE FILE
102 cp FILE FILE
103 rm FILE
104 cwd PATH
105 exec FILE
106 mkdirp MODE DIR
108 variables:
109 $B/ build dir, equivalent to $(common-objpfx)
110 $S/ source dir, equivalent to $(srcdir)
111 $I/ install dir, equivalent to $(prefix)
112 $L/ library dir (in container), equivalent to $(libdir)
113 $complocaledir/ compiled locale dir, equivalent to $(complocaledir)
114 / container's root
116 If FILE begins with any of these variables then they will be
117 substituted for the described value.
119 The goal is to expose as many of the runtime's configured paths
120 via variables so they can be used to setup the container environment
121 before execution reaches the test.
123 details:
124 - '#': A comment.
125 - 'su': Enables running test as root in the container.
126 - 'mv': A minimal move files command.
127 - 'cp': A minimal copy files command.
128 - 'rm': A minimal remove files command.
129 - 'cwd': set test working directory
130 - 'exec': change test binary location (may end in /)
131 - 'mkdirp': A minimal "mkdir -p FILE" command.
133 * mytest.root/postclean.req causes fresh rsync (with delete) after
134 test if present
136 * mytest.root/ldconfig.run causes ldconfig to be issued prior
137 test execution (to setup the initial ld.so.cache).
139 Note that $srcdir/foo/mytest.script may be used instead of a
140 $srcdir/foo/mytest.root/mytest.script in the sysroot template, if
141 there is no other reason for a sysroot.
143 Design goals:
145 * independent of other packages which may not be installed (like
146 rsync or Docker, or even "cp")
148 * Simple, easy to review code (i.e. prefer simple naive code over
149 complex efficient code)
151 * The current implementation ist parallel-make-safe, but only in
152 that it uses a lock to prevent parallel access to the testroot. */
155 /* Utility Functions */
157 /* Like xunlink, but it's OK if the file already doesn't exist. */
158 void
159 maybe_xunlink (const char *path)
161 int rv = unlink (path);
162 if (rv < 0 && errno != ENOENT)
163 FAIL_EXIT1 ("unlink (\"%s\"): %m", path);
166 /* Like xmkdir, but it's OK if the directory already exists. */
167 void
168 maybe_xmkdir (const char *path, mode_t mode)
170 struct stat st;
172 if (stat (path, &st) == 0
173 && S_ISDIR (st.st_mode))
174 return;
175 xmkdir (path, mode);
178 /* Temporarily concatenate multiple strings into one. Allows up to 10
179 temporary results; use xstrdup () if you need them to be
180 permanent. */
181 static char *
182 concat (const char *str, ...)
184 /* Assume initialized to NULL/zero. */
185 static char *bufs[10];
186 static size_t buflens[10];
187 static int bufn = 0;
188 int n;
189 size_t len;
190 va_list ap, ap2;
191 char *cp;
192 char *next;
194 va_start (ap, str);
195 va_copy (ap2, ap);
197 n = bufn;
198 bufn = (bufn + 1) % 10;
199 len = strlen (str);
201 while ((next = va_arg (ap, char *)) != NULL)
202 len = len + strlen (next);
204 va_end (ap);
206 if (bufs[n] == NULL)
208 bufs[n] = xmalloc (len + 1); /* NUL */
209 buflens[n] = len + 1;
211 else if (buflens[n] < len + 1)
213 bufs[n] = xrealloc (bufs[n], len + 1); /* NUL */
214 buflens[n] = len + 1;
217 strcpy (bufs[n], str);
218 cp = strchr (bufs[n], '\0');
219 while ((next = va_arg (ap2, char *)) != NULL)
221 strcpy (cp, next);
222 cp = strchr (cp, '\0');
224 *cp = 0;
225 va_end (ap2);
227 return bufs[n];
230 /* Try to mount SRC onto DEST. */
231 static void
232 trymount (const char *src, const char *dest)
234 if (mount (src, dest, "", MS_BIND, NULL) < 0)
235 FAIL_EXIT1 ("can't mount %s onto %s\n", src, dest);
238 /* Special case of above for devices like /dev/zero where we have to
239 mount a device over a device, not a directory over a directory. */
240 static void
241 devmount (const char *new_root_path, const char *which)
243 int fd;
244 fd = open (concat (new_root_path, "/dev/", which, NULL),
245 O_CREAT | O_TRUNC | O_RDWR, 0777);
246 xclose (fd);
248 trymount (concat ("/dev/", which, NULL),
249 concat (new_root_path, "/dev/", which, NULL));
252 /* Returns true if the string "looks like" an environement variable
253 being set. */
254 static int
255 is_env_setting (const char *a)
257 int count_name = 0;
259 while (*a)
261 if (isalnum (*a) || *a == '_')
262 ++count_name;
263 else if (*a == '=' && count_name > 0)
264 return 1;
265 else
266 return 0;
267 ++a;
269 return 0;
272 /* Break the_line into words and store in the_words. Max nwords,
273 returns actual count. */
274 static int
275 tokenize (char *the_line, char **the_words, int nwords)
277 int rv = 0;
279 while (nwords > 0)
281 /* Skip leading whitespace, if any. */
282 while (*the_line && isspace (*the_line))
283 ++the_line;
285 /* End of line? */
286 if (*the_line == 0)
287 return rv;
289 /* THE_LINE points to a non-whitespace character, so we have a
290 word. */
291 *the_words = the_line;
292 ++the_words;
293 nwords--;
294 ++rv;
296 /* Skip leading whitespace, if any. */
297 while (*the_line && ! isspace (*the_line))
298 ++the_line;
300 /* We now point at the trailing NUL *or* some whitespace. */
301 if (*the_line == 0)
302 return rv;
304 /* It was whitespace, skip and keep tokenizing. */
305 *the_line++ = 0;
308 /* We get here if we filled the words buffer. */
309 return rv;
313 /* Mini-RSYNC implementation. Optimize later. */
315 /* A few routines for an "rsync buffer" which stores the paths we're
316 working on. We continuously grow and shrink the paths in each
317 buffer so there's lot of re-use. */
319 /* We rely on "initialized to zero" to set these up. */
320 typedef struct
322 char *buf;
323 size_t len;
324 size_t size;
325 } path_buf;
327 static path_buf spath, dpath;
329 static void
330 r_setup (char *path, path_buf * pb)
332 size_t len = strlen (path);
333 if (pb->buf == NULL || pb->size < len + 1)
335 /* Round up. This is an arbitrary number, just to keep from
336 reallocing too often. */
337 size_t sz = ALIGN_UP (len + 1, 512);
338 if (pb->buf == NULL)
339 pb->buf = (char *) xmalloc (sz);
340 else
341 pb->buf = (char *) xrealloc (pb->buf, sz);
342 if (pb->buf == NULL)
343 FAIL_EXIT1 ("Out of memory while rsyncing\n");
345 pb->size = sz;
347 strcpy (pb->buf, path);
348 pb->len = len;
351 static void
352 r_append (const char *path, path_buf * pb)
354 size_t len = strlen (path) + pb->len;
355 if (pb->size < len + 1)
357 /* Round up */
358 size_t sz = ALIGN_UP (len + 1, 512);
359 pb->buf = (char *) xrealloc (pb->buf, sz);
360 if (pb->buf == NULL)
361 FAIL_EXIT1 ("Out of memory while rsyncing\n");
363 pb->size = sz;
365 strcpy (pb->buf + pb->len, path);
366 pb->len = len;
369 static int
370 file_exists (char *path)
372 struct stat st;
373 if (lstat (path, &st) == 0)
374 return 1;
375 return 0;
378 static void
379 recursive_remove (char *path)
381 pid_t child;
382 int status;
384 child = fork ();
386 switch (child) {
387 case -1:
388 perror("fork");
389 FAIL_EXIT1 ("Unable to fork");
390 case 0:
391 /* Child. */
392 execlp ("rm", "rm", "-rf", path, NULL);
393 FAIL_EXIT1 ("exec rm: %m");
394 default:
395 /* Parent. */
396 waitpid (child, &status, 0);
397 /* "rm" would have already printed a suitable error message. */
398 if (! WIFEXITED (status)
399 || WEXITSTATUS (status) != 0)
400 FAIL_EXIT1 ("exec child returned status: %d", status);
402 break;
406 /* Used for both rsync and the mytest.script "cp" command. */
407 static void
408 copy_one_file (const char *sname, const char *dname)
410 int sfd, dfd;
411 struct stat st;
412 struct utimbuf times;
414 sfd = open (sname, O_RDONLY);
415 if (sfd < 0)
416 FAIL_EXIT1 ("unable to open %s for reading\n", sname);
418 if (fstat (sfd, &st) < 0)
419 FAIL_EXIT1 ("unable to fstat %s\n", sname);
421 dfd = open (dname, O_WRONLY | O_TRUNC | O_CREAT, 0600);
422 if (dfd < 0)
423 FAIL_EXIT1 ("unable to open %s for writing\n", dname);
425 xcopy_file_range (sfd, 0, dfd, 0, st.st_size, 0);
427 xclose (sfd);
428 xclose (dfd);
430 if (chmod (dname, st.st_mode & 0777) < 0)
431 FAIL_EXIT1 ("chmod %s: %s\n", dname, strerror (errno));
433 times.actime = st.st_atime;
434 times.modtime = st.st_mtime;
435 if (utime (dname, &times) < 0)
436 FAIL_EXIT1 ("utime %s: %s\n", dname, strerror (errno));
439 /* We don't check *everything* about the two files to see if a copy is
440 needed, just the minimum to make sure we get the latest copy. */
441 static int
442 need_sync (char *ap, char *bp, struct stat *a, struct stat *b)
444 if ((a->st_mode & S_IFMT) != (b->st_mode & S_IFMT))
445 return 1;
447 if (S_ISLNK (a->st_mode))
449 int rv;
450 char *al, *bl;
452 if (a->st_size != b->st_size)
453 return 1;
455 al = xreadlink (ap);
456 bl = xreadlink (bp);
457 rv = strcmp (al, bl);
458 free (al);
459 free (bl);
460 if (rv == 0)
461 return 0; /* links are same */
462 return 1; /* links differ */
465 if (verbose)
467 if (a->st_size != b->st_size)
468 printf ("SIZE\n");
469 if ((a->st_mode & 0777) != (b->st_mode & 0777))
470 printf ("MODE\n");
471 if (a->st_mtime != b->st_mtime)
472 printf ("TIME\n");
475 if (a->st_size == b->st_size
476 && ((a->st_mode & 0777) == (b->st_mode & 0777))
477 && a->st_mtime == b->st_mtime)
478 return 0;
480 return 1;
483 static void
484 rsync_1 (path_buf * src, path_buf * dest, int and_delete)
486 DIR *dir;
487 struct dirent *de;
488 struct stat s, d;
490 r_append ("/", src);
491 r_append ("/", dest);
493 if (verbose)
494 printf ("sync %s to %s %s\n", src->buf, dest->buf,
495 and_delete ? "and delete" : "");
497 size_t staillen = src->len;
499 size_t dtaillen = dest->len;
501 dir = opendir (src->buf);
503 while ((de = readdir (dir)) != NULL)
505 if (strcmp (de->d_name, ".") == 0
506 || strcmp (de->d_name, "..") == 0)
507 continue;
509 src->len = staillen;
510 r_append (de->d_name, src);
511 dest->len = dtaillen;
512 r_append (de->d_name, dest);
514 s.st_mode = ~0;
515 d.st_mode = ~0;
517 if (lstat (src->buf, &s) != 0)
518 FAIL_EXIT1 ("%s obtained by readdir, but stat failed.\n", src->buf);
520 /* It's OK if this one fails, since we know the file might be
521 missing. */
522 lstat (dest->buf, &d);
524 if (! need_sync (src->buf, dest->buf, &s, &d))
526 if (S_ISDIR (s.st_mode))
527 rsync_1 (src, dest, and_delete);
528 continue;
531 if (d.st_mode != ~0)
532 switch (d.st_mode & S_IFMT)
534 case S_IFDIR:
535 if (!S_ISDIR (s.st_mode))
537 if (verbose)
538 printf ("-D %s\n", dest->buf);
539 recursive_remove (dest->buf);
541 break;
543 default:
544 if (verbose)
545 printf ("-F %s\n", dest->buf);
546 maybe_xunlink (dest->buf);
547 break;
550 switch (s.st_mode & S_IFMT)
552 case S_IFREG:
553 if (verbose)
554 printf ("+F %s\n", dest->buf);
555 copy_one_file (src->buf, dest->buf);
556 break;
558 case S_IFDIR:
559 if (verbose)
560 printf ("+D %s\n", dest->buf);
561 maybe_xmkdir (dest->buf, (s.st_mode & 0777) | 0700);
562 rsync_1 (src, dest, and_delete);
563 break;
565 case S_IFLNK:
567 char *lp;
568 if (verbose)
569 printf ("+L %s\n", dest->buf);
570 lp = xreadlink (src->buf);
571 xsymlink (lp, dest->buf);
572 free (lp);
573 break;
576 default:
577 break;
581 closedir (dir);
582 src->len = staillen;
583 src->buf[staillen] = 0;
584 dest->len = dtaillen;
585 dest->buf[dtaillen] = 0;
587 if (!and_delete)
588 return;
590 /* The rest of this function removes any files/directories in DEST
591 that do not exist in SRC. This is triggered as part of a
592 preclean or postsclean step. */
594 dir = opendir (dest->buf);
596 while ((de = readdir (dir)) != NULL)
598 if (strcmp (de->d_name, ".") == 0
599 || strcmp (de->d_name, "..") == 0)
600 continue;
602 src->len = staillen;
603 r_append (de->d_name, src);
604 dest->len = dtaillen;
605 r_append (de->d_name, dest);
607 s.st_mode = ~0;
608 d.st_mode = ~0;
610 lstat (src->buf, &s);
612 if (lstat (dest->buf, &d) != 0)
613 FAIL_EXIT1 ("%s obtained by readdir, but stat failed.\n", dest->buf);
615 if (s.st_mode == ~0)
617 /* dest exists and src doesn't, clean it. */
618 switch (d.st_mode & S_IFMT)
620 case S_IFDIR:
621 if (!S_ISDIR (s.st_mode))
623 if (verbose)
624 printf ("-D %s\n", dest->buf);
625 recursive_remove (dest->buf);
627 break;
629 default:
630 if (verbose)
631 printf ("-F %s\n", dest->buf);
632 maybe_xunlink (dest->buf);
633 break;
638 closedir (dir);
641 static void
642 rsync (char *src, char *dest, int and_delete)
644 r_setup (src, &spath);
645 r_setup (dest, &dpath);
647 rsync_1 (&spath, &dpath, and_delete);
652 /* See if we can detect what the user needs to do to get unshare
653 support working for us. */
654 void
655 check_for_unshare_hints (void)
657 FILE *f;
658 int i;
660 /* Default Debian Linux disables user namespaces, but allows a way
661 to enable them. */
662 f = fopen ("/proc/sys/kernel/unprivileged_userns_clone", "r");
663 if (f != NULL)
665 i = 99; /* Sentinel. */
666 fscanf (f, "%d", &i);
667 if (i == 0)
669 printf ("To enable test-container, please run this as root:\n");
670 printf (" echo 1 > /proc/sys/kernel/unprivileged_userns_clone\n");
672 fclose (f);
673 return;
676 /* ALT Linux has an alternate way of doing the same. */
677 f = fopen ("/proc/sys/kernel/userns_restrict", "r");
678 if (f != NULL)
680 i = 99; /* Sentinel. */
681 fscanf (f, "%d", &i);
682 if (i == 1)
684 printf ("To enable test-container, please run this as root:\n");
685 printf (" echo 0 > /proc/sys/kernel/userns_restrict\n");
687 fclose (f);
688 return;
692 static void
693 run_ldconfig (void *x __attribute__((unused)))
695 char *prog = xasprintf ("%s/ldconfig", support_install_rootsbindir);
696 char *args[] = { prog, NULL };
698 execv (args[0], args);
699 FAIL_EXIT1 ("execv: %m");
703 main (int argc, char **argv)
705 pid_t child;
706 char *pristine_root_path;
707 char *new_root_path;
708 char *new_cwd_path;
709 char *new_objdir_path;
710 char *new_srcdir_path;
711 char **new_child_proc;
712 char *new_child_exec;
713 char *command_root;
714 char *command_base;
715 char *command_basename;
716 char *so_base;
717 int do_postclean = 0;
718 bool do_ldconfig = false;
719 char *change_cwd = NULL;
721 int pipes[2];
722 char pid_buf[20];
724 uid_t original_uid;
725 gid_t original_gid;
726 /* If set, the test runs as root instead of the user running the testsuite. */
727 int be_su = 0;
728 int UMAP;
729 int GMAP;
730 /* Used for "%lld %lld 1" so need not be large. */
731 char tmp[100];
732 struct stat st;
733 int lock_fd;
735 setbuf (stdout, NULL);
737 /* The command line we're expecting looks like this:
738 env <set some vars> ld.so <library path> test-binary
740 We need to peel off any "env" or "ld.so" portion of the command
741 line, and keep track of which env vars we should preserve and
742 which we drop. */
744 if (argc < 2)
746 fprintf (stderr, "Usage: test-container <program to run> <args...>\n");
747 exit (1);
750 if (strcmp (argv[1], "-v") == 0)
752 verbose = 1;
753 ++argv;
754 --argc;
757 if (strcmp (argv[1], "env") == 0)
759 ++argv;
760 --argc;
761 while (is_env_setting (argv[1]))
763 /* If there are variables we do NOT want to propogate, this
764 is where the test for them goes. */
766 /* Need to keep these. Note that putenv stores a
767 pointer to our argv. */
768 putenv (argv[1]);
770 ++argv;
771 --argc;
775 if (strcmp (argv[1], support_objdir_elf_ldso) == 0)
777 ++argv;
778 --argc;
779 while (argv[1][0] == '-')
781 if (strcmp (argv[1], "--library-path") == 0)
783 ++argv;
784 --argc;
786 ++argv;
787 --argc;
791 pristine_root_path = xstrdup (concat (support_objdir_root,
792 "/testroot.pristine", NULL));
793 new_root_path = xstrdup (concat (support_objdir_root,
794 "/testroot.root", NULL));
795 new_cwd_path = get_current_dir_name ();
796 new_child_proc = argv + 1;
797 new_child_exec = argv[1];
799 lock_fd = open (concat (pristine_root_path, "/lock.fd", NULL),
800 O_CREAT | O_TRUNC | O_RDWR, 0666);
801 if (lock_fd < 0)
802 FAIL_EXIT1 ("Cannot create testroot lock.\n");
804 while (flock (lock_fd, LOCK_EX) != 0)
806 if (errno != EINTR)
807 FAIL_EXIT1 ("Cannot lock testroot.\n");
810 xmkdirp (new_root_path, 0755);
812 /* We look for extra setup info in a subdir in the same spot as the
813 test, with the same name but a ".root" extension. This is that
814 directory. We try to look in the source tree if the path we're
815 given refers to the build tree, but we rely on the path to be
816 absolute. This is what the glibc makefiles do. */
817 command_root = concat (argv[1], ".root", NULL);
818 if (strncmp (command_root, support_objdir_root,
819 strlen (support_objdir_root)) == 0
820 && command_root[strlen (support_objdir_root)] == '/')
821 command_root = concat (support_srcdir_root,
822 argv[1] + strlen (support_objdir_root),
823 ".root", NULL);
824 command_root = xstrdup (command_root);
826 /* This cuts off the ".root" we appended above. */
827 command_base = xstrdup (command_root);
828 command_base[strlen (command_base) - 5] = 0;
830 /* This is the basename of the test we're running. */
831 command_basename = strrchr (command_base, '/');
832 if (command_basename == NULL)
833 command_basename = command_base;
834 else
835 ++command_basename;
837 /* Shared object base directory. */
838 so_base = xstrdup (argv[1]);
839 if (strrchr (so_base, '/') != NULL)
840 strrchr (so_base, '/')[1] = 0;
842 if (file_exists (concat (command_root, "/postclean.req", NULL)))
843 do_postclean = 1;
845 if (file_exists (concat (command_root, "/ldconfig.run", NULL)))
846 do_ldconfig = true;
848 rsync (pristine_root_path, new_root_path,
849 file_exists (concat (command_root, "/preclean.req", NULL)));
851 if (stat (command_root, &st) >= 0
852 && S_ISDIR (st.st_mode))
853 rsync (command_root, new_root_path, 0);
855 new_objdir_path = xstrdup (concat (new_root_path,
856 support_objdir_root, NULL));
857 new_srcdir_path = xstrdup (concat (new_root_path,
858 support_srcdir_root, NULL));
860 /* new_cwd_path starts with '/' so no "/" needed between the two. */
861 xmkdirp (concat (new_root_path, new_cwd_path, NULL), 0755);
862 xmkdirp (new_srcdir_path, 0755);
863 xmkdirp (new_objdir_path, 0755);
865 original_uid = getuid ();
866 original_gid = getgid ();
868 /* Handle the cp/mv/rm "script" here. */
870 char *the_line = NULL;
871 size_t line_len = 0;
872 char *fname = concat (command_root, "/",
873 command_basename, ".script", NULL);
874 char *the_words[3];
875 FILE *f = fopen (fname, "r");
877 if (verbose && f)
878 fprintf (stderr, "running %s\n", fname);
880 if (f == NULL)
882 /* Try foo.script instead of foo.root/foo.script, as a shortcut. */
883 fname = concat (command_base, ".script", NULL);
884 f = fopen (fname, "r");
885 if (verbose && f)
886 fprintf (stderr, "running %s\n", fname);
889 /* Note that we do NOT look for a Makefile-generated foo.script in
890 the build directory. If that is ever needed, this is the place
891 to add it. */
893 /* This is where we "interpret" the mini-script which is <test>.script. */
894 if (f != NULL)
896 while (getline (&the_line, &line_len, f) > 0)
898 int nt = tokenize (the_line, the_words, 3);
899 int i;
901 /* Expand variables. */
902 for (i = 1; i < nt; ++i)
904 if (memcmp (the_words[i], "$B/", 3) == 0)
905 the_words[i] = concat (support_objdir_root,
906 the_words[i] + 2, NULL);
907 else if (memcmp (the_words[i], "$S/", 3) == 0)
908 the_words[i] = concat (support_srcdir_root,
909 the_words[i] + 2, NULL);
910 else if (memcmp (the_words[i], "$I/", 3) == 0)
911 the_words[i] = concat (new_root_path,
912 support_install_prefix,
913 the_words[i] + 2, NULL);
914 else if (memcmp (the_words[i], "$L/", 3) == 0)
915 the_words[i] = concat (new_root_path,
916 support_libdir_prefix,
917 the_words[i] + 2, NULL);
918 else if (memcmp (the_words[i], "$complocaledir/", 15) == 0)
919 the_words[i] = concat (new_root_path,
920 support_complocaledir_prefix,
921 the_words[i] + 14, NULL);
922 /* "exec" and "cwd" use inside-root paths. */
923 else if (strcmp (the_words[0], "exec") != 0
924 && strcmp (the_words[0], "cwd") != 0
925 && the_words[i][0] == '/')
926 the_words[i] = concat (new_root_path,
927 the_words[i], NULL);
930 if (nt == 3 && the_words[2][strlen (the_words[2]) - 1] == '/')
932 char *r = strrchr (the_words[1], '/');
933 if (r)
934 the_words[2] = concat (the_words[2], r + 1, NULL);
935 else
936 the_words[2] = concat (the_words[2], the_words[1], NULL);
939 /* Run the following commands in the_words[0] with NT number of
940 arguments (including the command). */
942 if (nt == 2 && strcmp (the_words[0], "so") == 0)
944 the_words[2] = concat (new_root_path, support_libdir_prefix,
945 "/", the_words[1], NULL);
946 the_words[1] = concat (so_base, the_words[1], NULL);
947 copy_one_file (the_words[1], the_words[2]);
949 else if (nt == 3 && strcmp (the_words[0], "cp") == 0)
951 copy_one_file (the_words[1], the_words[2]);
953 else if (nt == 3 && strcmp (the_words[0], "mv") == 0)
955 if (rename (the_words[1], the_words[2]) < 0)
956 FAIL_EXIT1 ("rename %s -> %s: %s", the_words[1],
957 the_words[2], strerror (errno));
959 else if (nt == 3 && strcmp (the_words[0], "chmod") == 0)
961 long int m;
962 errno = 0;
963 m = strtol (the_words[1], NULL, 0);
964 TEST_COMPARE (errno, 0);
965 if (chmod (the_words[2], m) < 0)
966 FAIL_EXIT1 ("chmod %s: %s\n",
967 the_words[2], strerror (errno));
970 else if (nt == 2 && strcmp (the_words[0], "rm") == 0)
972 maybe_xunlink (the_words[1]);
974 else if (nt >= 2 && strcmp (the_words[0], "exec") == 0)
976 /* The first argument is the desired location and name
977 of the test binary as we wish to exec it; we will
978 copy the binary there. The second (optional)
979 argument is the value to pass as argv[0], it
980 defaults to the same as the first argument. */
981 char *new_exec_path = the_words[1];
983 /* If the new exec path ends with a slash, that's the
984 * directory, and use the old test base name. */
985 if (new_exec_path [strlen(new_exec_path) - 1] == '/')
986 new_exec_path = concat (new_exec_path,
987 basename (new_child_proc[0]),
988 NULL);
991 /* new_child_proc is in the build tree, so has the
992 same path inside the chroot as outside. The new
993 exec path is, by definition, relative to the
994 chroot. */
995 copy_one_file (new_child_proc[0], concat (new_root_path,
996 new_exec_path,
997 NULL));
999 new_child_exec = xstrdup (new_exec_path);
1000 if (the_words[2])
1001 new_child_proc[0] = xstrdup (the_words[2]);
1002 else
1003 new_child_proc[0] = new_child_exec;
1005 else if (nt == 2 && strcmp (the_words[0], "cwd") == 0)
1007 change_cwd = xstrdup (the_words[1]);
1009 else if (nt == 1 && strcmp (the_words[0], "su") == 0)
1011 be_su = 1;
1013 else if (nt == 3 && strcmp (the_words[0], "mkdirp") == 0)
1015 long int m;
1016 errno = 0;
1017 m = strtol (the_words[1], NULL, 0);
1018 TEST_COMPARE (errno, 0);
1019 xmkdirp (the_words[2], m);
1021 else if (nt > 0 && the_words[0][0] != '#')
1023 fprintf (stderr, "\033[31minvalid [%s]\033[0m\n", the_words[0]);
1024 exit (1);
1027 fclose (f);
1031 if (do_postclean)
1033 pid_t pc_pid = fork ();
1035 if (pc_pid < 0)
1037 FAIL_EXIT1 ("Can't fork for post-clean");
1039 else if (pc_pid > 0)
1041 /* Parent. */
1042 int status;
1043 waitpid (pc_pid, &status, 0);
1045 /* Child has exited, we can post-clean the test root. */
1046 printf("running post-clean rsync\n");
1047 rsync (pristine_root_path, new_root_path, 1);
1049 if (WIFEXITED (status))
1050 exit (WEXITSTATUS (status));
1052 if (WIFSIGNALED (status))
1054 printf ("%%SIGNALLED%%\n");
1055 exit (77);
1058 printf ("%%EXITERROR%%\n");
1059 exit (78);
1062 /* Child continues. */
1065 /* This is the last point in the program where we're still in the
1066 "normal" namespace. */
1068 #ifdef CLONE_NEWNS
1069 /* The unshare here gives us our own spaces and capabilities. */
1070 if (unshare (CLONE_NEWUSER | CLONE_NEWPID | CLONE_NEWNS) < 0)
1072 /* Older kernels may not support all the options, or security
1073 policy may block this call. */
1074 if (errno == EINVAL || errno == EPERM)
1076 int saved_errno = errno;
1077 if (errno == EPERM)
1078 check_for_unshare_hints ();
1079 FAIL_UNSUPPORTED ("unable to unshare user/fs: %s", strerror (saved_errno));
1081 else
1082 FAIL_EXIT1 ("unable to unshare user/fs: %s", strerror (errno));
1084 #else
1085 /* Some targets may not support unshare at all. */
1086 FAIL_UNSUPPORTED ("unshare support missing");
1087 #endif
1089 /* Some systems, by default, all mounts leak out of the namespace. */
1090 if (mount ("none", "/", NULL, MS_REC | MS_PRIVATE, NULL) != 0)
1091 FAIL_EXIT1 ("could not create a private mount namespace\n");
1093 trymount (support_srcdir_root, new_srcdir_path);
1094 trymount (support_objdir_root, new_objdir_path);
1096 xmkdirp (concat (new_root_path, "/dev", NULL), 0755);
1097 devmount (new_root_path, "null");
1098 devmount (new_root_path, "zero");
1099 devmount (new_root_path, "urandom");
1101 /* We're done with the "old" root, switch to the new one. */
1102 if (chroot (new_root_path) < 0)
1103 FAIL_EXIT1 ("Can't chroot to %s - ", new_root_path);
1105 if (chdir (new_cwd_path) < 0)
1106 FAIL_EXIT1 ("Can't cd to new %s - ", new_cwd_path);
1108 /* This is to pass the "outside" PID to the child, which will be PID
1109 1. */
1110 if (pipe2 (pipes, O_CLOEXEC) < 0)
1111 FAIL_EXIT1 ("Can't create pid pipe");
1113 /* To complete the containerization, we need to fork () at least
1114 once. We can't exec, nor can we somehow link the new child to
1115 our parent. So we run the child and propogate it's exit status
1116 up. */
1117 child = fork ();
1118 if (child < 0)
1119 FAIL_EXIT1 ("Unable to fork");
1120 else if (child > 0)
1122 /* Parent. */
1123 int status;
1125 /* Send the child's "outside" pid to it. */
1126 write (pipes[1], &child, sizeof(child));
1127 close (pipes[0]);
1128 close (pipes[1]);
1130 waitpid (child, &status, 0);
1132 if (WIFEXITED (status))
1133 exit (WEXITSTATUS (status));
1135 if (WIFSIGNALED (status))
1137 printf ("%%SIGNALLED%%\n");
1138 exit (77);
1141 printf ("%%EXITERROR%%\n");
1142 exit (78);
1145 /* The rest is the child process, which is now PID 1 and "in" the
1146 new root. */
1148 if (do_ldconfig)
1150 struct support_capture_subprocess result =
1151 support_capture_subprocess (run_ldconfig, NULL);
1152 support_capture_subprocess_check (&result, "execv", 0, sc_allow_none);
1155 /* Get our "outside" pid from our parent. We use this to help with
1156 debugging from outside the container. */
1157 read (pipes[0], &child, sizeof(child));
1158 close (pipes[0]);
1159 close (pipes[1]);
1160 sprintf (pid_buf, "%lu", (long unsigned)child);
1161 setenv ("PID_OUTSIDE_CONTAINER", pid_buf, 0);
1163 maybe_xmkdir ("/tmp", 0755);
1165 /* Now that we're pid 1 (effectively "root") we can mount /proc */
1166 maybe_xmkdir ("/proc", 0777);
1167 if (mount ("proc", "/proc", "proc", 0, NULL) < 0)
1168 FAIL_EXIT1 ("Unable to mount /proc: ");
1170 /* We map our original UID to the same UID in the container so we
1171 can own our own files normally. */
1172 UMAP = open ("/proc/self/uid_map", O_WRONLY);
1173 if (UMAP < 0)
1174 FAIL_EXIT1 ("can't write to /proc/self/uid_map\n");
1176 sprintf (tmp, "%lld %lld 1\n",
1177 (long long) (be_su ? 0 : original_uid), (long long) original_uid);
1178 write (UMAP, tmp, strlen (tmp));
1179 xclose (UMAP);
1181 /* We must disable setgroups () before we can map our groups, else we
1182 get EPERM. */
1183 GMAP = open ("/proc/self/setgroups", O_WRONLY);
1184 if (GMAP >= 0)
1186 /* We support kernels old enough to not have this. */
1187 write (GMAP, "deny\n", 5);
1188 xclose (GMAP);
1191 /* We map our original GID to the same GID in the container so we
1192 can own our own files normally. */
1193 GMAP = open ("/proc/self/gid_map", O_WRONLY);
1194 if (GMAP < 0)
1195 FAIL_EXIT1 ("can't write to /proc/self/gid_map\n");
1197 sprintf (tmp, "%lld %lld 1\n",
1198 (long long) (be_su ? 0 : original_gid), (long long) original_gid);
1199 write (GMAP, tmp, strlen (tmp));
1200 xclose (GMAP);
1202 if (change_cwd)
1204 if (chdir (change_cwd) < 0)
1205 FAIL_EXIT1 ("Can't cd to %s inside container - ", change_cwd);
1208 /* Now run the child. */
1209 execvp (new_child_exec, new_child_proc);
1211 /* Or don't run the child? */
1212 FAIL_EXIT1 ("Unable to exec %s: %s\n", new_child_exec, strerror (errno));
1214 /* Because gcc won't know error () never returns... */
1215 exit (EXIT_UNSUPPORTED);