nptl: Reformat Makefile.
[glibc.git] / support / test-container.c
blobe68f16eecfddc918ccfafea28403f64420c1bc77
1 /* Run a test case in an isolated namespace.
2 Copyright (C) 2018-2023 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 #include <array_length.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <sched.h>
24 #include <sys/syscall.h>
25 #include <unistd.h>
26 #include <sys/types.h>
27 #include <dirent.h>
28 #include <string.h>
29 #include <sys/stat.h>
30 #include <sys/fcntl.h>
31 #include <sys/file.h>
32 #include <sys/wait.h>
33 #include <stdarg.h>
34 #include <sys/sysmacros.h>
35 #include <ctype.h>
36 #include <utime.h>
37 #include <errno.h>
38 #include <error.h>
39 #include <libc-pointer-arith.h>
41 #ifdef __linux__
42 #include <sys/mount.h>
43 #endif
45 #include <support/support.h>
46 #include <support/xunistd.h>
47 #include <support/capture_subprocess.h>
48 #include "check.h"
49 #include "test-driver.h"
51 #ifndef __linux__
52 #define mount(s,t,fs,f,d) no_mount()
53 int no_mount (void)
55 FAIL_UNSUPPORTED("mount not supported; port needed");
57 #endif
59 int verbose = 0;
61 /* Running a test in a container is tricky. There are two main
62 categories of things to do:
64 1. "Once" actions, like setting up the container and doing an
65 install into it.
67 2. "Per-test" actions, like copying in support files and
68 configuring the container.
71 "Once" actions:
73 * mkdir $buildroot/testroot.pristine/
74 * install into it
75 * default glibc install
76 * create /bin for /bin/sh
77 * create $(complocaledir) so localedef tests work with default paths.
78 * install /bin/sh, /bin/echo, and /bin/true.
79 * rsync to $buildroot/testroot.root/
81 "Per-test" actions:
82 * maybe rsync to $buildroot/testroot.root/
83 * copy support files and test binary
84 * chroot/unshare
85 * set up any mounts (like /proc)
86 * run ldconfig
88 Magic files:
90 For test $srcdir/foo/mytest.c we look for $srcdir/foo/mytest.root
91 and, if found...
93 * mytest.root/ is rsync'd into container
94 * mytest.root/preclean.req causes fresh rsync (with delete) before
95 test if present
96 * mytest.root/mytest.script has a list of "commands" to run:
97 syntax:
98 # comment
99 pidns <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 - 'pidns': Require a separate PID namespace, prints comment if it can't
126 (default is a shared pid namespace)
127 - 'su': Enables running test as root in the container.
128 - 'mv': A minimal move files command.
129 - 'cp': A minimal copy files command.
130 - 'rm': A minimal remove files command.
131 - 'cwd': set test working directory
132 - 'exec': change test binary location (may end in /)
133 - 'mkdirp': A minimal "mkdir -p FILE" command.
135 * mytest.root/postclean.req causes fresh rsync (with delete) after
136 test if present
138 * mytest.root/ldconfig.run causes ldconfig to be issued prior
139 test execution (to setup the initial ld.so.cache).
141 Note that $srcdir/foo/mytest.script may be used instead of a
142 $srcdir/foo/mytest.root/mytest.script in the sysroot template, if
143 there is no other reason for a sysroot.
145 Design goals:
147 * independent of other packages which may not be installed (like
148 rsync or Docker, or even "cp")
150 * Simple, easy to review code (i.e. prefer simple naive code over
151 complex efficient code)
153 * The current implementation is parallel-make-safe, but only in
154 that it uses a lock to prevent parallel access to the testroot. */
157 /* Utility Functions */
159 /* Like xunlink, but it's OK if the file already doesn't exist. */
160 void
161 maybe_xunlink (const char *path)
163 int rv = unlink (path);
164 if (rv < 0 && errno != ENOENT)
165 FAIL_EXIT1 ("unlink (\"%s\"): %m", path);
168 /* Like xmkdir, but it's OK if the directory already exists. */
169 void
170 maybe_xmkdir (const char *path, mode_t mode)
172 struct stat st;
174 if (stat (path, &st) == 0
175 && S_ISDIR (st.st_mode))
176 return;
177 xmkdir (path, mode);
180 /* Temporarily concatenate multiple strings into one. Allows up to 10
181 temporary results; use xstrdup () if you need them to be
182 permanent. */
183 static char *
184 concat (const char *str, ...)
186 /* Assume initialized to NULL/zero. */
187 static char *bufs[10];
188 static size_t buflens[10];
189 static int bufn = 0;
190 int n;
191 size_t len;
192 va_list ap, ap2;
193 char *cp;
194 char *next;
196 va_start (ap, str);
197 va_copy (ap2, ap);
199 n = bufn;
200 bufn = (bufn + 1) % 10;
201 len = strlen (str);
203 while ((next = va_arg (ap, char *)) != NULL)
204 len = len + strlen (next);
206 va_end (ap);
208 if (bufs[n] == NULL)
210 bufs[n] = xmalloc (len + 1); /* NUL */
211 buflens[n] = len + 1;
213 else if (buflens[n] < len + 1)
215 bufs[n] = xrealloc (bufs[n], len + 1); /* NUL */
216 buflens[n] = len + 1;
219 strcpy (bufs[n], str);
220 cp = strchr (bufs[n], '\0');
221 while ((next = va_arg (ap2, char *)) != NULL)
223 strcpy (cp, next);
224 cp = strchr (cp, '\0');
226 *cp = 0;
227 va_end (ap2);
229 return bufs[n];
232 #ifdef CLONE_NEWNS
233 /* Like the above, but put spaces between words. Caller frees. */
234 static char *
235 concat_words (char **words, int num_words)
237 int len = 0;
238 int i;
239 char *rv, *p;
241 for (i = 0; i < num_words; i ++)
243 len += strlen (words[i]);
244 len ++;
247 p = rv = (char *) xmalloc (len);
249 for (i = 0; i < num_words; i ++)
251 if (i > 0)
252 p = stpcpy (p, " ");
253 p = stpcpy (p, words[i]);
256 return rv;
258 #endif
260 /* Try to mount SRC onto DEST. */
261 static void
262 trymount (const char *src, const char *dest)
264 if (mount (src, dest, "", MS_BIND | MS_REC, NULL) < 0)
265 FAIL_EXIT1 ("can't mount %s onto %s\n", src, dest);
268 /* Special case of above for devices like /dev/zero where we have to
269 mount a device over a device, not a directory over a directory. */
270 static void
271 devmount (const char *new_root_path, const char *which)
273 int fd;
274 fd = open (concat (new_root_path, "/dev/", which, NULL),
275 O_CREAT | O_TRUNC | O_RDWR, 0777);
276 xclose (fd);
278 trymount (concat ("/dev/", which, NULL),
279 concat (new_root_path, "/dev/", which, NULL));
282 /* Returns true if the string "looks like" an environement variable
283 being set. */
284 static int
285 is_env_setting (const char *a)
287 int count_name = 0;
289 while (*a)
291 if (isalnum (*a) || *a == '_')
292 ++count_name;
293 else if (*a == '=' && count_name > 0)
294 return 1;
295 else
296 return 0;
297 ++a;
299 return 0;
302 /* Break the_line into words and store in the_words. Max nwords,
303 returns actual count. */
304 static int
305 tokenize (char *the_line, char **the_words, int nwords)
307 int rv = 0;
309 while (nwords > 0)
311 /* Skip leading whitespace, if any. */
312 while (*the_line && isspace (*the_line))
313 ++the_line;
315 /* End of line? */
316 if (*the_line == 0)
317 return rv;
319 /* THE_LINE points to a non-whitespace character, so we have a
320 word. */
321 *the_words = the_line;
322 ++the_words;
323 nwords--;
324 ++rv;
326 /* Skip leading whitespace, if any. */
327 while (*the_line && ! isspace (*the_line))
328 ++the_line;
330 /* We now point at the trailing NUL *or* some whitespace. */
331 if (*the_line == 0)
332 return rv;
334 /* It was whitespace, skip and keep tokenizing. */
335 *the_line++ = 0;
338 /* We get here if we filled the words buffer. */
339 return rv;
343 /* Mini-RSYNC implementation. Optimize later. */
345 /* A few routines for an "rsync buffer" which stores the paths we're
346 working on. We continuously grow and shrink the paths in each
347 buffer so there's lot of re-use. */
349 /* We rely on "initialized to zero" to set these up. */
350 typedef struct
352 char *buf;
353 size_t len;
354 size_t size;
355 } path_buf;
357 static path_buf spath, dpath;
359 static void
360 r_setup (char *path, path_buf * pb)
362 size_t len = strlen (path);
363 if (pb->buf == NULL || pb->size < len + 1)
365 /* Round up. This is an arbitrary number, just to keep from
366 reallocing too often. */
367 size_t sz = ALIGN_UP (len + 1, 512);
368 if (pb->buf == NULL)
369 pb->buf = (char *) xmalloc (sz);
370 else
371 pb->buf = (char *) xrealloc (pb->buf, sz);
372 if (pb->buf == NULL)
373 FAIL_EXIT1 ("Out of memory while rsyncing\n");
375 pb->size = sz;
377 strcpy (pb->buf, path);
378 pb->len = len;
381 static void
382 r_append (const char *path, path_buf * pb)
384 size_t len = strlen (path) + pb->len;
385 if (pb->size < len + 1)
387 /* Round up */
388 size_t sz = ALIGN_UP (len + 1, 512);
389 pb->buf = (char *) xrealloc (pb->buf, sz);
390 if (pb->buf == NULL)
391 FAIL_EXIT1 ("Out of memory while rsyncing\n");
393 pb->size = sz;
395 strcpy (pb->buf + pb->len, path);
396 pb->len = len;
399 static int
400 file_exists (char *path)
402 struct stat st;
403 if (lstat (path, &st) == 0)
404 return 1;
405 return 0;
408 static void
409 recursive_remove (char *path)
411 pid_t child;
412 int status;
414 child = fork ();
416 switch (child) {
417 case -1:
418 perror("fork");
419 FAIL_EXIT1 ("Unable to fork");
420 case 0:
421 /* Child. */
422 execlp ("rm", "rm", "-rf", path, NULL);
423 FAIL_EXIT1 ("exec rm: %m");
424 default:
425 /* Parent. */
426 waitpid (child, &status, 0);
427 /* "rm" would have already printed a suitable error message. */
428 if (! WIFEXITED (status)
429 || WEXITSTATUS (status) != 0)
430 FAIL_EXIT1 ("exec child returned status: %d", status);
432 break;
436 /* Used for both rsync and the mytest.script "cp" command. */
437 static void
438 copy_one_file (const char *sname, const char *dname)
440 int sfd, dfd;
441 struct stat st;
442 struct utimbuf times;
444 sfd = open (sname, O_RDONLY);
445 if (sfd < 0)
446 FAIL_EXIT1 ("unable to open %s for reading\n", sname);
448 if (fstat (sfd, &st) < 0)
449 FAIL_EXIT1 ("unable to fstat %s\n", sname);
451 dfd = open (dname, O_WRONLY | O_TRUNC | O_CREAT, 0600);
452 if (dfd < 0)
453 FAIL_EXIT1 ("unable to open %s for writing\n", dname);
455 xcopy_file_range (sfd, 0, dfd, 0, st.st_size, 0);
457 xclose (sfd);
458 xclose (dfd);
460 if (chmod (dname, st.st_mode & 0777) < 0)
461 FAIL_EXIT1 ("chmod %s: %s\n", dname, strerror (errno));
463 times.actime = st.st_atime;
464 times.modtime = st.st_mtime;
465 if (utime (dname, &times) < 0)
466 FAIL_EXIT1 ("utime %s: %s\n", dname, strerror (errno));
469 /* We don't check *everything* about the two files to see if a copy is
470 needed, just the minimum to make sure we get the latest copy. */
471 static int
472 need_sync (char *ap, char *bp, struct stat *a, struct stat *b)
474 if ((a->st_mode & S_IFMT) != (b->st_mode & S_IFMT))
475 return 1;
477 if (S_ISLNK (a->st_mode))
479 int rv;
480 char *al, *bl;
482 if (a->st_size != b->st_size)
483 return 1;
485 al = xreadlink (ap);
486 bl = xreadlink (bp);
487 rv = strcmp (al, bl);
488 free (al);
489 free (bl);
490 if (rv == 0)
491 return 0; /* links are same */
492 return 1; /* links differ */
495 if (verbose)
497 if (a->st_size != b->st_size)
498 printf ("SIZE\n");
499 if ((a->st_mode & 0777) != (b->st_mode & 0777))
500 printf ("MODE\n");
501 if (a->st_mtime != b->st_mtime)
502 printf ("TIME\n");
505 if (a->st_size == b->st_size
506 && ((a->st_mode & 0777) == (b->st_mode & 0777))
507 && a->st_mtime == b->st_mtime)
508 return 0;
510 return 1;
513 static void
514 rsync_1 (path_buf * src, path_buf * dest, int and_delete, int force_copies)
516 DIR *dir;
517 struct dirent *de;
518 struct stat s, d;
520 r_append ("/", src);
521 r_append ("/", dest);
523 if (verbose)
524 printf ("sync %s to %s%s%s\n", src->buf, dest->buf,
525 and_delete ? " and delete" : "",
526 force_copies ? " (forced)" : "");
528 size_t staillen = src->len;
530 size_t dtaillen = dest->len;
532 dir = opendir (src->buf);
534 while ((de = readdir (dir)) != NULL)
536 if (strcmp (de->d_name, ".") == 0
537 || strcmp (de->d_name, "..") == 0)
538 continue;
540 src->len = staillen;
541 r_append (de->d_name, src);
542 dest->len = dtaillen;
543 r_append (de->d_name, dest);
545 s.st_mode = ~0;
546 d.st_mode = ~0;
548 if (lstat (src->buf, &s) != 0)
549 FAIL_EXIT1 ("%s obtained by readdir, but stat failed.\n", src->buf);
551 /* It's OK if this one fails, since we know the file might be
552 missing. */
553 lstat (dest->buf, &d);
555 if (! force_copies && ! need_sync (src->buf, dest->buf, &s, &d))
557 if (S_ISDIR (s.st_mode))
558 rsync_1 (src, dest, and_delete, force_copies);
559 continue;
562 if (d.st_mode != ~0)
563 switch (d.st_mode & S_IFMT)
565 case S_IFDIR:
566 if (!S_ISDIR (s.st_mode))
568 if (verbose)
569 printf ("-D %s\n", dest->buf);
570 recursive_remove (dest->buf);
572 break;
574 default:
575 if (verbose)
576 printf ("-F %s\n", dest->buf);
577 maybe_xunlink (dest->buf);
578 break;
581 switch (s.st_mode & S_IFMT)
583 case S_IFREG:
584 if (verbose)
585 printf ("+F %s\n", dest->buf);
586 copy_one_file (src->buf, dest->buf);
587 break;
589 case S_IFDIR:
590 if (verbose)
591 printf ("+D %s\n", dest->buf);
592 maybe_xmkdir (dest->buf, (s.st_mode & 0777) | 0700);
593 rsync_1 (src, dest, and_delete, force_copies);
594 break;
596 case S_IFLNK:
598 char *lp;
599 if (verbose)
600 printf ("+L %s\n", dest->buf);
601 lp = xreadlink (src->buf);
602 xsymlink (lp, dest->buf);
603 free (lp);
604 break;
607 default:
608 break;
612 closedir (dir);
613 src->len = staillen;
614 src->buf[staillen] = 0;
615 dest->len = dtaillen;
616 dest->buf[dtaillen] = 0;
618 if (!and_delete)
619 return;
621 /* The rest of this function removes any files/directories in DEST
622 that do not exist in SRC. This is triggered as part of a
623 preclean or postsclean step. */
625 dir = opendir (dest->buf);
627 while ((de = readdir (dir)) != NULL)
629 if (strcmp (de->d_name, ".") == 0
630 || strcmp (de->d_name, "..") == 0)
631 continue;
633 src->len = staillen;
634 r_append (de->d_name, src);
635 dest->len = dtaillen;
636 r_append (de->d_name, dest);
638 s.st_mode = ~0;
639 d.st_mode = ~0;
641 lstat (src->buf, &s);
643 if (lstat (dest->buf, &d) != 0)
644 FAIL_EXIT1 ("%s obtained by readdir, but stat failed.\n", dest->buf);
646 if (s.st_mode == ~0)
648 /* dest exists and src doesn't, clean it. */
649 switch (d.st_mode & S_IFMT)
651 case S_IFDIR:
652 if (!S_ISDIR (s.st_mode))
654 if (verbose)
655 printf ("-D %s\n", dest->buf);
656 recursive_remove (dest->buf);
658 break;
660 default:
661 if (verbose)
662 printf ("-F %s\n", dest->buf);
663 maybe_xunlink (dest->buf);
664 break;
669 closedir (dir);
672 static void
673 rsync (char *src, char *dest, int and_delete, int force_copies)
675 r_setup (src, &spath);
676 r_setup (dest, &dpath);
678 rsync_1 (&spath, &dpath, and_delete, force_copies);
683 /* See if we can detect what the user needs to do to get unshare
684 support working for us. */
685 void
686 check_for_unshare_hints (int require_pidns)
688 static struct {
689 const char *path;
690 int bad_value, good_value, for_pidns;
691 } files[] = {
692 /* Default Debian Linux disables user namespaces, but allows a way
693 to enable them. */
694 { "/proc/sys/kernel/unprivileged_userns_clone", 0, 1, 0 },
695 /* ALT Linux has an alternate way of doing the same. */
696 { "/proc/sys/kernel/userns_restrict", 1, 0, 0 },
697 /* Linux kernel >= 4.9 has a configurable limit on the number of
698 each namespace. Some distros set the limit to zero to disable the
699 corresponding namespace as a "security policy". */
700 { "/proc/sys/user/max_user_namespaces", 0, 1024, 0 },
701 { "/proc/sys/user/max_mnt_namespaces", 0, 1024, 0 },
702 { "/proc/sys/user/max_pid_namespaces", 0, 1024, 1 },
704 FILE *f;
705 int i, val;
707 for (i = 0; i < array_length (files); i++)
709 if (!require_pidns && files[i].for_pidns)
710 continue;
712 f = fopen (files[i].path, "r");
713 if (f == NULL)
714 continue;
716 val = -1; /* Sentinel. */
717 fscanf (f, "%d", &val);
718 if (val != files[i].bad_value)
719 continue;
721 printf ("To enable test-container, please run this as root:\n");
722 printf (" echo %d > %s\n", files[i].good_value, files[i].path);
723 return;
727 static void
728 run_ldconfig (void *x __attribute__((unused)))
730 char *prog = xasprintf ("%s/ldconfig", support_install_rootsbindir);
731 char *args[] = { prog, NULL };
733 execv (args[0], args);
734 FAIL_EXIT1 ("execv: %m");
738 main (int argc, char **argv)
740 pid_t child;
741 char *pristine_root_path;
742 char *new_root_path;
743 char *new_cwd_path;
744 char *new_objdir_path;
745 char *new_srcdir_path;
746 char **new_child_proc;
747 char *new_child_exec;
748 char *command_root;
749 char *command_base;
750 char *command_basename;
751 char *so_base;
752 int do_postclean = 0;
753 bool do_ldconfig = false;
754 char *change_cwd = NULL;
756 int pipes[2];
757 char pid_buf[20];
759 uid_t original_uid;
760 gid_t original_gid;
761 /* If set, the test runs as root instead of the user running the testsuite. */
762 int be_su = 0;
763 int require_pidns = 0;
764 #ifdef CLONE_NEWNS
765 const char *pidns_comment = NULL;
766 #endif
767 int do_proc_mounts = 0;
768 int UMAP;
769 int GMAP;
770 /* Used for "%lld %lld 1" so need not be large. */
771 char tmp[100];
772 struct stat st;
773 int lock_fd;
775 setbuf (stdout, NULL);
777 /* The command line we're expecting looks like this:
778 env <set some vars> ld.so <library path> test-binary
780 We need to peel off any "env" or "ld.so" portion of the command
781 line, and keep track of which env vars we should preserve and
782 which we drop. */
784 if (argc < 2)
786 fprintf (stderr, "Usage: test-container <program to run> <args...>\n");
787 exit (1);
790 if (strcmp (argv[1], "-v") == 0)
792 verbose = 1;
793 ++argv;
794 --argc;
797 if (strcmp (argv[1], "env") == 0)
799 ++argv;
800 --argc;
801 while (is_env_setting (argv[1]))
803 /* If there are variables we do NOT want to propogate, this
804 is where the test for them goes. */
806 /* Need to keep these. Note that putenv stores a
807 pointer to our argv. */
808 putenv (argv[1]);
810 ++argv;
811 --argc;
815 if (strcmp (argv[1], support_objdir_elf_ldso) == 0)
817 ++argv;
818 --argc;
819 while (argv[1][0] == '-')
821 if (strcmp (argv[1], "--library-path") == 0)
823 ++argv;
824 --argc;
826 ++argv;
827 --argc;
831 pristine_root_path = xstrdup (concat (support_objdir_root,
832 "/testroot.pristine", NULL));
833 new_root_path = xstrdup (concat (support_objdir_root,
834 "/testroot.root", NULL));
835 new_cwd_path = get_current_dir_name ();
836 new_child_proc = argv + 1;
837 new_child_exec = argv[1];
839 lock_fd = open (concat (pristine_root_path, "/lock.fd", NULL),
840 O_CREAT | O_TRUNC | O_RDWR, 0666);
841 if (lock_fd < 0)
842 FAIL_EXIT1 ("Cannot create testroot lock.\n");
844 while (flock (lock_fd, LOCK_EX) != 0)
846 if (errno != EINTR)
847 FAIL_EXIT1 ("Cannot lock testroot.\n");
850 xmkdirp (new_root_path, 0755);
852 /* We look for extra setup info in a subdir in the same spot as the
853 test, with the same name but a ".root" extension. This is that
854 directory. We try to look in the source tree if the path we're
855 given refers to the build tree, but we rely on the path to be
856 absolute. This is what the glibc makefiles do. */
857 command_root = concat (argv[1], ".root", NULL);
858 if (strncmp (command_root, support_objdir_root,
859 strlen (support_objdir_root)) == 0
860 && command_root[strlen (support_objdir_root)] == '/')
861 command_root = concat (support_srcdir_root,
862 argv[1] + strlen (support_objdir_root),
863 ".root", NULL);
864 command_root = xstrdup (command_root);
866 /* This cuts off the ".root" we appended above. */
867 command_base = xstrdup (command_root);
868 command_base[strlen (command_base) - 5] = 0;
870 /* This is the basename of the test we're running. */
871 command_basename = strrchr (command_base, '/');
872 if (command_basename == NULL)
873 command_basename = command_base;
874 else
875 ++command_basename;
877 /* Shared object base directory. */
878 so_base = xstrdup (argv[1]);
879 if (strrchr (so_base, '/') != NULL)
880 strrchr (so_base, '/')[1] = 0;
882 if (file_exists (concat (command_root, "/postclean.req", NULL)))
883 do_postclean = 1;
885 if (file_exists (concat (command_root, "/ldconfig.run", NULL)))
886 do_ldconfig = true;
888 rsync (pristine_root_path, new_root_path,
889 file_exists (concat (command_root, "/preclean.req", NULL)), 0);
891 if (stat (command_root, &st) >= 0
892 && S_ISDIR (st.st_mode))
893 rsync (command_root, new_root_path, 0, 1);
895 new_objdir_path = xstrdup (concat (new_root_path,
896 support_objdir_root, NULL));
897 new_srcdir_path = xstrdup (concat (new_root_path,
898 support_srcdir_root, NULL));
900 /* new_cwd_path starts with '/' so no "/" needed between the two. */
901 xmkdirp (concat (new_root_path, new_cwd_path, NULL), 0755);
902 xmkdirp (new_srcdir_path, 0755);
903 xmkdirp (new_objdir_path, 0755);
905 original_uid = getuid ();
906 original_gid = getgid ();
908 /* Handle the cp/mv/rm "script" here. */
910 char *the_line = NULL;
911 size_t line_len = 0;
912 char *fname = concat (command_root, "/",
913 command_basename, ".script", NULL);
914 char *the_words[3];
915 FILE *f = fopen (fname, "r");
917 if (verbose && f)
918 fprintf (stderr, "running %s\n", fname);
920 if (f == NULL)
922 /* Try foo.script instead of foo.root/foo.script, as a shortcut. */
923 fname = concat (command_base, ".script", NULL);
924 f = fopen (fname, "r");
925 if (verbose && f)
926 fprintf (stderr, "running %s\n", fname);
929 /* Note that we do NOT look for a Makefile-generated foo.script in
930 the build directory. If that is ever needed, this is the place
931 to add it. */
933 /* This is where we "interpret" the mini-script which is <test>.script. */
934 if (f != NULL)
936 while (getline (&the_line, &line_len, f) > 0)
938 int nt = tokenize (the_line, the_words, 3);
939 int i;
941 /* Expand variables. */
942 for (i = 1; i < nt; ++i)
944 if (memcmp (the_words[i], "$B/", 3) == 0)
945 the_words[i] = concat (support_objdir_root,
946 the_words[i] + 2, NULL);
947 else if (memcmp (the_words[i], "$S/", 3) == 0)
948 the_words[i] = concat (support_srcdir_root,
949 the_words[i] + 2, NULL);
950 else if (memcmp (the_words[i], "$I/", 3) == 0)
951 the_words[i] = concat (new_root_path,
952 support_install_prefix,
953 the_words[i] + 2, NULL);
954 else if (memcmp (the_words[i], "$L/", 3) == 0)
955 the_words[i] = concat (new_root_path,
956 support_libdir_prefix,
957 the_words[i] + 2, NULL);
958 else if (memcmp (the_words[i], "$complocaledir/", 15) == 0)
959 the_words[i] = concat (new_root_path,
960 support_complocaledir_prefix,
961 the_words[i] + 14, NULL);
962 /* "exec" and "cwd" use inside-root paths. */
963 else if (strcmp (the_words[0], "exec") != 0
964 && strcmp (the_words[0], "cwd") != 0
965 && the_words[i][0] == '/')
966 the_words[i] = concat (new_root_path,
967 the_words[i], NULL);
970 if (nt == 3 && the_words[2][strlen (the_words[2]) - 1] == '/')
972 char *r = strrchr (the_words[1], '/');
973 if (r)
974 the_words[2] = concat (the_words[2], r + 1, NULL);
975 else
976 the_words[2] = concat (the_words[2], the_words[1], NULL);
979 /* Run the following commands in the_words[0] with NT number of
980 arguments (including the command). */
982 if (nt == 2 && strcmp (the_words[0], "so") == 0)
984 the_words[2] = concat (new_root_path, support_libdir_prefix,
985 "/", the_words[1], NULL);
986 the_words[1] = concat (so_base, the_words[1], NULL);
987 copy_one_file (the_words[1], the_words[2]);
989 else if (nt == 3 && strcmp (the_words[0], "cp") == 0)
991 copy_one_file (the_words[1], the_words[2]);
993 else if (nt == 3 && strcmp (the_words[0], "mv") == 0)
995 if (rename (the_words[1], the_words[2]) < 0)
996 FAIL_EXIT1 ("rename %s -> %s: %s", the_words[1],
997 the_words[2], strerror (errno));
999 else if (nt == 3 && strcmp (the_words[0], "chmod") == 0)
1001 long int m;
1002 errno = 0;
1003 m = strtol (the_words[1], NULL, 0);
1004 TEST_COMPARE (errno, 0);
1005 if (chmod (the_words[2], m) < 0)
1006 FAIL_EXIT1 ("chmod %s: %s\n",
1007 the_words[2], strerror (errno));
1010 else if (nt == 2 && strcmp (the_words[0], "rm") == 0)
1012 maybe_xunlink (the_words[1]);
1014 else if (nt >= 2 && strcmp (the_words[0], "exec") == 0)
1016 /* The first argument is the desired location and name
1017 of the test binary as we wish to exec it; we will
1018 copy the binary there. The second (optional)
1019 argument is the value to pass as argv[0], it
1020 defaults to the same as the first argument. */
1021 char *new_exec_path = the_words[1];
1023 /* If the new exec path ends with a slash, that's the
1024 * directory, and use the old test base name. */
1025 if (new_exec_path [strlen(new_exec_path) - 1] == '/')
1026 new_exec_path = concat (new_exec_path,
1027 basename (new_child_proc[0]),
1028 NULL);
1031 /* new_child_proc is in the build tree, so has the
1032 same path inside the chroot as outside. The new
1033 exec path is, by definition, relative to the
1034 chroot. */
1035 copy_one_file (new_child_proc[0], concat (new_root_path,
1036 new_exec_path,
1037 NULL));
1039 new_child_exec = xstrdup (new_exec_path);
1040 if (the_words[2])
1041 new_child_proc[0] = xstrdup (the_words[2]);
1042 else
1043 new_child_proc[0] = new_child_exec;
1045 else if (nt == 2 && strcmp (the_words[0], "cwd") == 0)
1047 change_cwd = xstrdup (the_words[1]);
1049 else if (nt == 1 && strcmp (the_words[0], "su") == 0)
1051 be_su = 1;
1053 else if (nt >= 1 && strcmp (the_words[0], "pidns") == 0)
1055 require_pidns = 1;
1056 #ifdef CLONE_NEWNS
1057 if (nt > 1)
1058 pidns_comment = concat_words (the_words + 1, nt - 1);
1059 #endif
1061 else if (nt == 3 && strcmp (the_words[0], "mkdirp") == 0)
1063 long int m;
1064 errno = 0;
1065 m = strtol (the_words[1], NULL, 0);
1066 TEST_COMPARE (errno, 0);
1067 xmkdirp (the_words[2], m);
1069 else if (nt > 0 && the_words[0][0] != '#')
1071 fprintf (stderr, "\033[31minvalid [%s]\033[0m\n", the_words[0]);
1072 exit (1);
1075 fclose (f);
1079 if (do_postclean)
1081 pid_t pc_pid = fork ();
1083 if (pc_pid < 0)
1085 FAIL_EXIT1 ("Can't fork for post-clean");
1087 else if (pc_pid > 0)
1089 /* Parent. */
1090 int status;
1091 waitpid (pc_pid, &status, 0);
1093 /* Child has exited, we can post-clean the test root. */
1094 printf("running post-clean rsync\n");
1095 rsync (pristine_root_path, new_root_path, 1, 0);
1097 if (WIFEXITED (status))
1098 exit (WEXITSTATUS (status));
1100 if (WIFSIGNALED (status))
1102 printf ("%%SIGNALLED%%\n");
1103 exit (77);
1106 printf ("%%EXITERROR%%\n");
1107 exit (78);
1110 /* Child continues. */
1113 /* This is the last point in the program where we're still in the
1114 "normal" namespace. */
1116 #ifdef CLONE_NEWNS
1117 /* The unshare here gives us our own spaces and capabilities. */
1118 if (unshare (CLONE_NEWUSER | CLONE_NEWNS
1119 | (require_pidns ? CLONE_NEWPID : 0)) < 0)
1121 /* Older kernels may not support all the options, or security
1122 policy may block this call. */
1123 if (errno == EINVAL || errno == EPERM || errno == ENOSPC)
1125 int saved_errno = errno;
1126 if (errno == EPERM || errno == ENOSPC)
1127 check_for_unshare_hints (require_pidns);
1128 FAIL_UNSUPPORTED ("unable to unshare user/fs: %s", strerror (saved_errno));
1130 /* We're about to exit anyway, it's "safe" to call unshare again
1131 just to see if the CLONE_NEWPID caused the error. */
1132 else if (require_pidns && unshare (CLONE_NEWUSER | CLONE_NEWNS) >= 0)
1133 FAIL_EXIT1 ("unable to unshare pid ns: %s : %s", strerror (errno),
1134 pidns_comment ? pidns_comment : "required by test");
1135 else
1136 FAIL_EXIT1 ("unable to unshare user/fs: %s", strerror (errno));
1138 #else
1139 /* Some targets may not support unshare at all. */
1140 FAIL_UNSUPPORTED ("unshare support missing");
1141 #endif
1143 /* Some systems, by default, all mounts leak out of the namespace. */
1144 if (mount ("none", "/", NULL, MS_REC | MS_PRIVATE, NULL) != 0)
1145 FAIL_EXIT1 ("could not create a private mount namespace\n");
1147 trymount (support_srcdir_root, new_srcdir_path);
1148 trymount (support_objdir_root, new_objdir_path);
1150 /* It may not be possible to mount /proc directly. */
1151 if (! require_pidns)
1153 char *new_proc = concat (new_root_path, "/proc", NULL);
1154 xmkdirp (new_proc, 0755);
1155 trymount ("/proc", new_proc);
1156 do_proc_mounts = 1;
1159 xmkdirp (concat (new_root_path, "/dev", NULL), 0755);
1160 devmount (new_root_path, "null");
1161 devmount (new_root_path, "zero");
1162 devmount (new_root_path, "urandom");
1164 /* We're done with the "old" root, switch to the new one. */
1165 if (chroot (new_root_path) < 0)
1166 FAIL_EXIT1 ("Can't chroot to %s - ", new_root_path);
1168 if (chdir (new_cwd_path) < 0)
1169 FAIL_EXIT1 ("Can't cd to new %s - ", new_cwd_path);
1171 /* This is to pass the "outside" PID to the child, which will be PID
1172 1. */
1173 if (pipe2 (pipes, O_CLOEXEC) < 0)
1174 FAIL_EXIT1 ("Can't create pid pipe");
1176 /* To complete the containerization, we need to fork () at least
1177 once. We can't exec, nor can we somehow link the new child to
1178 our parent. So we run the child and propogate it's exit status
1179 up. */
1180 child = fork ();
1181 if (child < 0)
1182 FAIL_EXIT1 ("Unable to fork");
1183 else if (child > 0)
1185 /* Parent. */
1186 int status;
1188 /* Send the child's "outside" pid to it. */
1189 write (pipes[1], &child, sizeof(child));
1190 close (pipes[0]);
1191 close (pipes[1]);
1193 waitpid (child, &status, 0);
1195 if (WIFEXITED (status))
1196 exit (WEXITSTATUS (status));
1198 if (WIFSIGNALED (status))
1200 printf ("%%SIGNALLED%%\n");
1201 exit (77);
1204 printf ("%%EXITERROR%%\n");
1205 exit (78);
1208 /* The rest is the child process, which is now PID 1 and "in" the
1209 new root. */
1211 if (do_ldconfig)
1213 struct support_capture_subprocess result =
1214 support_capture_subprocess (run_ldconfig, NULL);
1215 support_capture_subprocess_check (&result, "execv", 0, sc_allow_none);
1218 /* Get our "outside" pid from our parent. We use this to help with
1219 debugging from outside the container. */
1220 read (pipes[0], &child, sizeof(child));
1221 close (pipes[0]);
1222 close (pipes[1]);
1223 sprintf (pid_buf, "%lu", (long unsigned)child);
1224 setenv ("PID_OUTSIDE_CONTAINER", pid_buf, 0);
1226 maybe_xmkdir ("/tmp", 0755);
1228 if (require_pidns)
1230 /* Now that we're pid 1 (effectively "root") we can mount /proc */
1231 maybe_xmkdir ("/proc", 0777);
1232 if (mount ("proc", "/proc", "proc", 0, NULL) != 0)
1234 /* This happens if we're trying to create a nested container,
1235 like if the build is running under podman, and we lack
1236 priviledges.
1238 Ideally we would WARN here, but that would just add noise to
1239 *every* test-container test, and the ones that care should
1240 have their own relevent diagnostics.
1242 FAIL_EXIT1 ("Unable to mount /proc: "); */
1244 else
1245 do_proc_mounts = 1;
1248 if (do_proc_mounts)
1250 /* We map our original UID to the same UID in the container so we
1251 can own our own files normally. */
1252 UMAP = open ("/proc/self/uid_map", O_WRONLY);
1253 if (UMAP < 0)
1254 FAIL_EXIT1 ("can't write to /proc/self/uid_map\n");
1256 sprintf (tmp, "%lld %lld 1\n",
1257 (long long) (be_su ? 0 : original_uid), (long long) original_uid);
1258 write (UMAP, tmp, strlen (tmp));
1259 xclose (UMAP);
1261 /* We must disable setgroups () before we can map our groups, else we
1262 get EPERM. */
1263 GMAP = open ("/proc/self/setgroups", O_WRONLY);
1264 if (GMAP >= 0)
1266 /* We support kernels old enough to not have this. */
1267 write (GMAP, "deny\n", 5);
1268 xclose (GMAP);
1271 /* We map our original GID to the same GID in the container so we
1272 can own our own files normally. */
1273 GMAP = open ("/proc/self/gid_map", O_WRONLY);
1274 if (GMAP < 0)
1275 FAIL_EXIT1 ("can't write to /proc/self/gid_map\n");
1277 sprintf (tmp, "%lld %lld 1\n",
1278 (long long) (be_su ? 0 : original_gid), (long long) original_gid);
1279 write (GMAP, tmp, strlen (tmp));
1280 xclose (GMAP);
1283 if (change_cwd)
1285 if (chdir (change_cwd) < 0)
1286 FAIL_EXIT1 ("Can't cd to %s inside container - ", change_cwd);
1289 /* Now run the child. */
1290 execvp (new_child_exec, new_child_proc);
1292 /* Or don't run the child? */
1293 FAIL_EXIT1 ("Unable to exec %s: %s\n", new_child_exec, strerror (errno));
1295 /* Because gcc won't know error () never returns... */
1296 exit (EXIT_UNSUPPORTED);