Update NEWS.
[glibc.git] / support / test-container.c
blob25e7f1421935a31f36f6ac7bd6a3fbd03760156f
1 /* Run a test case in an isolated namespace.
2 Copyright (C) 2018-2022 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, int force_copies)
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%s\n", src->buf, dest->buf,
495 and_delete ? " and delete" : "",
496 force_copies ? " (forced)" : "");
498 size_t staillen = src->len;
500 size_t dtaillen = dest->len;
502 dir = opendir (src->buf);
504 while ((de = readdir (dir)) != NULL)
506 if (strcmp (de->d_name, ".") == 0
507 || strcmp (de->d_name, "..") == 0)
508 continue;
510 src->len = staillen;
511 r_append (de->d_name, src);
512 dest->len = dtaillen;
513 r_append (de->d_name, dest);
515 s.st_mode = ~0;
516 d.st_mode = ~0;
518 if (lstat (src->buf, &s) != 0)
519 FAIL_EXIT1 ("%s obtained by readdir, but stat failed.\n", src->buf);
521 /* It's OK if this one fails, since we know the file might be
522 missing. */
523 lstat (dest->buf, &d);
525 if (! force_copies && ! need_sync (src->buf, dest->buf, &s, &d))
527 if (S_ISDIR (s.st_mode))
528 rsync_1 (src, dest, and_delete, force_copies);
529 continue;
532 if (d.st_mode != ~0)
533 switch (d.st_mode & S_IFMT)
535 case S_IFDIR:
536 if (!S_ISDIR (s.st_mode))
538 if (verbose)
539 printf ("-D %s\n", dest->buf);
540 recursive_remove (dest->buf);
542 break;
544 default:
545 if (verbose)
546 printf ("-F %s\n", dest->buf);
547 maybe_xunlink (dest->buf);
548 break;
551 switch (s.st_mode & S_IFMT)
553 case S_IFREG:
554 if (verbose)
555 printf ("+F %s\n", dest->buf);
556 copy_one_file (src->buf, dest->buf);
557 break;
559 case S_IFDIR:
560 if (verbose)
561 printf ("+D %s\n", dest->buf);
562 maybe_xmkdir (dest->buf, (s.st_mode & 0777) | 0700);
563 rsync_1 (src, dest, and_delete, force_copies);
564 break;
566 case S_IFLNK:
568 char *lp;
569 if (verbose)
570 printf ("+L %s\n", dest->buf);
571 lp = xreadlink (src->buf);
572 xsymlink (lp, dest->buf);
573 free (lp);
574 break;
577 default:
578 break;
582 closedir (dir);
583 src->len = staillen;
584 src->buf[staillen] = 0;
585 dest->len = dtaillen;
586 dest->buf[dtaillen] = 0;
588 if (!and_delete)
589 return;
591 /* The rest of this function removes any files/directories in DEST
592 that do not exist in SRC. This is triggered as part of a
593 preclean or postsclean step. */
595 dir = opendir (dest->buf);
597 while ((de = readdir (dir)) != NULL)
599 if (strcmp (de->d_name, ".") == 0
600 || strcmp (de->d_name, "..") == 0)
601 continue;
603 src->len = staillen;
604 r_append (de->d_name, src);
605 dest->len = dtaillen;
606 r_append (de->d_name, dest);
608 s.st_mode = ~0;
609 d.st_mode = ~0;
611 lstat (src->buf, &s);
613 if (lstat (dest->buf, &d) != 0)
614 FAIL_EXIT1 ("%s obtained by readdir, but stat failed.\n", dest->buf);
616 if (s.st_mode == ~0)
618 /* dest exists and src doesn't, clean it. */
619 switch (d.st_mode & S_IFMT)
621 case S_IFDIR:
622 if (!S_ISDIR (s.st_mode))
624 if (verbose)
625 printf ("-D %s\n", dest->buf);
626 recursive_remove (dest->buf);
628 break;
630 default:
631 if (verbose)
632 printf ("-F %s\n", dest->buf);
633 maybe_xunlink (dest->buf);
634 break;
639 closedir (dir);
642 static void
643 rsync (char *src, char *dest, int and_delete, int force_copies)
645 r_setup (src, &spath);
646 r_setup (dest, &dpath);
648 rsync_1 (&spath, &dpath, and_delete, force_copies);
653 /* See if we can detect what the user needs to do to get unshare
654 support working for us. */
655 void
656 check_for_unshare_hints (void)
658 FILE *f;
659 int i;
661 /* Default Debian Linux disables user namespaces, but allows a way
662 to enable them. */
663 f = fopen ("/proc/sys/kernel/unprivileged_userns_clone", "r");
664 if (f != NULL)
666 i = 99; /* Sentinel. */
667 fscanf (f, "%d", &i);
668 if (i == 0)
670 printf ("To enable test-container, please run this as root:\n");
671 printf (" echo 1 > /proc/sys/kernel/unprivileged_userns_clone\n");
673 fclose (f);
674 return;
677 /* ALT Linux has an alternate way of doing the same. */
678 f = fopen ("/proc/sys/kernel/userns_restrict", "r");
679 if (f != NULL)
681 i = 99; /* Sentinel. */
682 fscanf (f, "%d", &i);
683 if (i == 1)
685 printf ("To enable test-container, please run this as root:\n");
686 printf (" echo 0 > /proc/sys/kernel/userns_restrict\n");
688 fclose (f);
689 return;
693 static void
694 run_ldconfig (void *x __attribute__((unused)))
696 char *prog = xasprintf ("%s/ldconfig", support_install_rootsbindir);
697 char *args[] = { prog, NULL };
699 execv (args[0], args);
700 FAIL_EXIT1 ("execv: %m");
704 main (int argc, char **argv)
706 pid_t child;
707 char *pristine_root_path;
708 char *new_root_path;
709 char *new_cwd_path;
710 char *new_objdir_path;
711 char *new_srcdir_path;
712 char **new_child_proc;
713 char *new_child_exec;
714 char *command_root;
715 char *command_base;
716 char *command_basename;
717 char *so_base;
718 int do_postclean = 0;
719 bool do_ldconfig = false;
720 char *change_cwd = NULL;
722 int pipes[2];
723 char pid_buf[20];
725 uid_t original_uid;
726 gid_t original_gid;
727 /* If set, the test runs as root instead of the user running the testsuite. */
728 int be_su = 0;
729 int UMAP;
730 int GMAP;
731 /* Used for "%lld %lld 1" so need not be large. */
732 char tmp[100];
733 struct stat st;
734 int lock_fd;
736 setbuf (stdout, NULL);
738 /* The command line we're expecting looks like this:
739 env <set some vars> ld.so <library path> test-binary
741 We need to peel off any "env" or "ld.so" portion of the command
742 line, and keep track of which env vars we should preserve and
743 which we drop. */
745 if (argc < 2)
747 fprintf (stderr, "Usage: test-container <program to run> <args...>\n");
748 exit (1);
751 if (strcmp (argv[1], "-v") == 0)
753 verbose = 1;
754 ++argv;
755 --argc;
758 if (strcmp (argv[1], "env") == 0)
760 ++argv;
761 --argc;
762 while (is_env_setting (argv[1]))
764 /* If there are variables we do NOT want to propogate, this
765 is where the test for them goes. */
767 /* Need to keep these. Note that putenv stores a
768 pointer to our argv. */
769 putenv (argv[1]);
771 ++argv;
772 --argc;
776 if (strcmp (argv[1], support_objdir_elf_ldso) == 0)
778 ++argv;
779 --argc;
780 while (argv[1][0] == '-')
782 if (strcmp (argv[1], "--library-path") == 0)
784 ++argv;
785 --argc;
787 ++argv;
788 --argc;
792 pristine_root_path = xstrdup (concat (support_objdir_root,
793 "/testroot.pristine", NULL));
794 new_root_path = xstrdup (concat (support_objdir_root,
795 "/testroot.root", NULL));
796 new_cwd_path = get_current_dir_name ();
797 new_child_proc = argv + 1;
798 new_child_exec = argv[1];
800 lock_fd = open (concat (pristine_root_path, "/lock.fd", NULL),
801 O_CREAT | O_TRUNC | O_RDWR, 0666);
802 if (lock_fd < 0)
803 FAIL_EXIT1 ("Cannot create testroot lock.\n");
805 while (flock (lock_fd, LOCK_EX) != 0)
807 if (errno != EINTR)
808 FAIL_EXIT1 ("Cannot lock testroot.\n");
811 xmkdirp (new_root_path, 0755);
813 /* We look for extra setup info in a subdir in the same spot as the
814 test, with the same name but a ".root" extension. This is that
815 directory. We try to look in the source tree if the path we're
816 given refers to the build tree, but we rely on the path to be
817 absolute. This is what the glibc makefiles do. */
818 command_root = concat (argv[1], ".root", NULL);
819 if (strncmp (command_root, support_objdir_root,
820 strlen (support_objdir_root)) == 0
821 && command_root[strlen (support_objdir_root)] == '/')
822 command_root = concat (support_srcdir_root,
823 argv[1] + strlen (support_objdir_root),
824 ".root", NULL);
825 command_root = xstrdup (command_root);
827 /* This cuts off the ".root" we appended above. */
828 command_base = xstrdup (command_root);
829 command_base[strlen (command_base) - 5] = 0;
831 /* This is the basename of the test we're running. */
832 command_basename = strrchr (command_base, '/');
833 if (command_basename == NULL)
834 command_basename = command_base;
835 else
836 ++command_basename;
838 /* Shared object base directory. */
839 so_base = xstrdup (argv[1]);
840 if (strrchr (so_base, '/') != NULL)
841 strrchr (so_base, '/')[1] = 0;
843 if (file_exists (concat (command_root, "/postclean.req", NULL)))
844 do_postclean = 1;
846 if (file_exists (concat (command_root, "/ldconfig.run", NULL)))
847 do_ldconfig = true;
849 rsync (pristine_root_path, new_root_path,
850 file_exists (concat (command_root, "/preclean.req", NULL)), 0);
852 if (stat (command_root, &st) >= 0
853 && S_ISDIR (st.st_mode))
854 rsync (command_root, new_root_path, 0, 1);
856 new_objdir_path = xstrdup (concat (new_root_path,
857 support_objdir_root, NULL));
858 new_srcdir_path = xstrdup (concat (new_root_path,
859 support_srcdir_root, NULL));
861 /* new_cwd_path starts with '/' so no "/" needed between the two. */
862 xmkdirp (concat (new_root_path, new_cwd_path, NULL), 0755);
863 xmkdirp (new_srcdir_path, 0755);
864 xmkdirp (new_objdir_path, 0755);
866 original_uid = getuid ();
867 original_gid = getgid ();
869 /* Handle the cp/mv/rm "script" here. */
871 char *the_line = NULL;
872 size_t line_len = 0;
873 char *fname = concat (command_root, "/",
874 command_basename, ".script", NULL);
875 char *the_words[3];
876 FILE *f = fopen (fname, "r");
878 if (verbose && f)
879 fprintf (stderr, "running %s\n", fname);
881 if (f == NULL)
883 /* Try foo.script instead of foo.root/foo.script, as a shortcut. */
884 fname = concat (command_base, ".script", NULL);
885 f = fopen (fname, "r");
886 if (verbose && f)
887 fprintf (stderr, "running %s\n", fname);
890 /* Note that we do NOT look for a Makefile-generated foo.script in
891 the build directory. If that is ever needed, this is the place
892 to add it. */
894 /* This is where we "interpret" the mini-script which is <test>.script. */
895 if (f != NULL)
897 while (getline (&the_line, &line_len, f) > 0)
899 int nt = tokenize (the_line, the_words, 3);
900 int i;
902 /* Expand variables. */
903 for (i = 1; i < nt; ++i)
905 if (memcmp (the_words[i], "$B/", 3) == 0)
906 the_words[i] = concat (support_objdir_root,
907 the_words[i] + 2, NULL);
908 else if (memcmp (the_words[i], "$S/", 3) == 0)
909 the_words[i] = concat (support_srcdir_root,
910 the_words[i] + 2, NULL);
911 else if (memcmp (the_words[i], "$I/", 3) == 0)
912 the_words[i] = concat (new_root_path,
913 support_install_prefix,
914 the_words[i] + 2, NULL);
915 else if (memcmp (the_words[i], "$L/", 3) == 0)
916 the_words[i] = concat (new_root_path,
917 support_libdir_prefix,
918 the_words[i] + 2, NULL);
919 else if (memcmp (the_words[i], "$complocaledir/", 15) == 0)
920 the_words[i] = concat (new_root_path,
921 support_complocaledir_prefix,
922 the_words[i] + 14, NULL);
923 /* "exec" and "cwd" use inside-root paths. */
924 else if (strcmp (the_words[0], "exec") != 0
925 && strcmp (the_words[0], "cwd") != 0
926 && the_words[i][0] == '/')
927 the_words[i] = concat (new_root_path,
928 the_words[i], NULL);
931 if (nt == 3 && the_words[2][strlen (the_words[2]) - 1] == '/')
933 char *r = strrchr (the_words[1], '/');
934 if (r)
935 the_words[2] = concat (the_words[2], r + 1, NULL);
936 else
937 the_words[2] = concat (the_words[2], the_words[1], NULL);
940 /* Run the following commands in the_words[0] with NT number of
941 arguments (including the command). */
943 if (nt == 2 && strcmp (the_words[0], "so") == 0)
945 the_words[2] = concat (new_root_path, support_libdir_prefix,
946 "/", the_words[1], NULL);
947 the_words[1] = concat (so_base, the_words[1], NULL);
948 copy_one_file (the_words[1], the_words[2]);
950 else if (nt == 3 && strcmp (the_words[0], "cp") == 0)
952 copy_one_file (the_words[1], the_words[2]);
954 else if (nt == 3 && strcmp (the_words[0], "mv") == 0)
956 if (rename (the_words[1], the_words[2]) < 0)
957 FAIL_EXIT1 ("rename %s -> %s: %s", the_words[1],
958 the_words[2], strerror (errno));
960 else if (nt == 3 && strcmp (the_words[0], "chmod") == 0)
962 long int m;
963 errno = 0;
964 m = strtol (the_words[1], NULL, 0);
965 TEST_COMPARE (errno, 0);
966 if (chmod (the_words[2], m) < 0)
967 FAIL_EXIT1 ("chmod %s: %s\n",
968 the_words[2], strerror (errno));
971 else if (nt == 2 && strcmp (the_words[0], "rm") == 0)
973 maybe_xunlink (the_words[1]);
975 else if (nt >= 2 && strcmp (the_words[0], "exec") == 0)
977 /* The first argument is the desired location and name
978 of the test binary as we wish to exec it; we will
979 copy the binary there. The second (optional)
980 argument is the value to pass as argv[0], it
981 defaults to the same as the first argument. */
982 char *new_exec_path = the_words[1];
984 /* If the new exec path ends with a slash, that's the
985 * directory, and use the old test base name. */
986 if (new_exec_path [strlen(new_exec_path) - 1] == '/')
987 new_exec_path = concat (new_exec_path,
988 basename (new_child_proc[0]),
989 NULL);
992 /* new_child_proc is in the build tree, so has the
993 same path inside the chroot as outside. The new
994 exec path is, by definition, relative to the
995 chroot. */
996 copy_one_file (new_child_proc[0], concat (new_root_path,
997 new_exec_path,
998 NULL));
1000 new_child_exec = xstrdup (new_exec_path);
1001 if (the_words[2])
1002 new_child_proc[0] = xstrdup (the_words[2]);
1003 else
1004 new_child_proc[0] = new_child_exec;
1006 else if (nt == 2 && strcmp (the_words[0], "cwd") == 0)
1008 change_cwd = xstrdup (the_words[1]);
1010 else if (nt == 1 && strcmp (the_words[0], "su") == 0)
1012 be_su = 1;
1014 else if (nt == 3 && strcmp (the_words[0], "mkdirp") == 0)
1016 long int m;
1017 errno = 0;
1018 m = strtol (the_words[1], NULL, 0);
1019 TEST_COMPARE (errno, 0);
1020 xmkdirp (the_words[2], m);
1022 else if (nt > 0 && the_words[0][0] != '#')
1024 fprintf (stderr, "\033[31minvalid [%s]\033[0m\n", the_words[0]);
1025 exit (1);
1028 fclose (f);
1032 if (do_postclean)
1034 pid_t pc_pid = fork ();
1036 if (pc_pid < 0)
1038 FAIL_EXIT1 ("Can't fork for post-clean");
1040 else if (pc_pid > 0)
1042 /* Parent. */
1043 int status;
1044 waitpid (pc_pid, &status, 0);
1046 /* Child has exited, we can post-clean the test root. */
1047 printf("running post-clean rsync\n");
1048 rsync (pristine_root_path, new_root_path, 1, 0);
1050 if (WIFEXITED (status))
1051 exit (WEXITSTATUS (status));
1053 if (WIFSIGNALED (status))
1055 printf ("%%SIGNALLED%%\n");
1056 exit (77);
1059 printf ("%%EXITERROR%%\n");
1060 exit (78);
1063 /* Child continues. */
1066 /* This is the last point in the program where we're still in the
1067 "normal" namespace. */
1069 #ifdef CLONE_NEWNS
1070 /* The unshare here gives us our own spaces and capabilities. */
1071 if (unshare (CLONE_NEWUSER | CLONE_NEWPID | CLONE_NEWNS) < 0)
1073 /* Older kernels may not support all the options, or security
1074 policy may block this call. */
1075 if (errno == EINVAL || errno == EPERM)
1077 int saved_errno = errno;
1078 if (errno == EPERM)
1079 check_for_unshare_hints ();
1080 FAIL_UNSUPPORTED ("unable to unshare user/fs: %s", strerror (saved_errno));
1082 else
1083 FAIL_EXIT1 ("unable to unshare user/fs: %s", strerror (errno));
1085 #else
1086 /* Some targets may not support unshare at all. */
1087 FAIL_UNSUPPORTED ("unshare support missing");
1088 #endif
1090 /* Some systems, by default, all mounts leak out of the namespace. */
1091 if (mount ("none", "/", NULL, MS_REC | MS_PRIVATE, NULL) != 0)
1092 FAIL_EXIT1 ("could not create a private mount namespace\n");
1094 trymount (support_srcdir_root, new_srcdir_path);
1095 trymount (support_objdir_root, new_objdir_path);
1097 xmkdirp (concat (new_root_path, "/dev", NULL), 0755);
1098 devmount (new_root_path, "null");
1099 devmount (new_root_path, "zero");
1100 devmount (new_root_path, "urandom");
1102 /* We're done with the "old" root, switch to the new one. */
1103 if (chroot (new_root_path) < 0)
1104 FAIL_EXIT1 ("Can't chroot to %s - ", new_root_path);
1106 if (chdir (new_cwd_path) < 0)
1107 FAIL_EXIT1 ("Can't cd to new %s - ", new_cwd_path);
1109 /* This is to pass the "outside" PID to the child, which will be PID
1110 1. */
1111 if (pipe2 (pipes, O_CLOEXEC) < 0)
1112 FAIL_EXIT1 ("Can't create pid pipe");
1114 /* To complete the containerization, we need to fork () at least
1115 once. We can't exec, nor can we somehow link the new child to
1116 our parent. So we run the child and propogate it's exit status
1117 up. */
1118 child = fork ();
1119 if (child < 0)
1120 FAIL_EXIT1 ("Unable to fork");
1121 else if (child > 0)
1123 /* Parent. */
1124 int status;
1126 /* Send the child's "outside" pid to it. */
1127 write (pipes[1], &child, sizeof(child));
1128 close (pipes[0]);
1129 close (pipes[1]);
1131 waitpid (child, &status, 0);
1133 if (WIFEXITED (status))
1134 exit (WEXITSTATUS (status));
1136 if (WIFSIGNALED (status))
1138 printf ("%%SIGNALLED%%\n");
1139 exit (77);
1142 printf ("%%EXITERROR%%\n");
1143 exit (78);
1146 /* The rest is the child process, which is now PID 1 and "in" the
1147 new root. */
1149 if (do_ldconfig)
1151 struct support_capture_subprocess result =
1152 support_capture_subprocess (run_ldconfig, NULL);
1153 support_capture_subprocess_check (&result, "execv", 0, sc_allow_none);
1156 /* Get our "outside" pid from our parent. We use this to help with
1157 debugging from outside the container. */
1158 read (pipes[0], &child, sizeof(child));
1159 close (pipes[0]);
1160 close (pipes[1]);
1161 sprintf (pid_buf, "%lu", (long unsigned)child);
1162 setenv ("PID_OUTSIDE_CONTAINER", pid_buf, 0);
1164 maybe_xmkdir ("/tmp", 0755);
1166 /* Now that we're pid 1 (effectively "root") we can mount /proc */
1167 maybe_xmkdir ("/proc", 0777);
1168 if (mount ("proc", "/proc", "proc", 0, NULL) < 0)
1169 FAIL_EXIT1 ("Unable to mount /proc: ");
1171 /* We map our original UID to the same UID in the container so we
1172 can own our own files normally. */
1173 UMAP = open ("/proc/self/uid_map", O_WRONLY);
1174 if (UMAP < 0)
1175 FAIL_EXIT1 ("can't write to /proc/self/uid_map\n");
1177 sprintf (tmp, "%lld %lld 1\n",
1178 (long long) (be_su ? 0 : original_uid), (long long) original_uid);
1179 write (UMAP, tmp, strlen (tmp));
1180 xclose (UMAP);
1182 /* We must disable setgroups () before we can map our groups, else we
1183 get EPERM. */
1184 GMAP = open ("/proc/self/setgroups", O_WRONLY);
1185 if (GMAP >= 0)
1187 /* We support kernels old enough to not have this. */
1188 write (GMAP, "deny\n", 5);
1189 xclose (GMAP);
1192 /* We map our original GID to the same GID in the container so we
1193 can own our own files normally. */
1194 GMAP = open ("/proc/self/gid_map", O_WRONLY);
1195 if (GMAP < 0)
1196 FAIL_EXIT1 ("can't write to /proc/self/gid_map\n");
1198 sprintf (tmp, "%lld %lld 1\n",
1199 (long long) (be_su ? 0 : original_gid), (long long) original_gid);
1200 write (GMAP, tmp, strlen (tmp));
1201 xclose (GMAP);
1203 if (change_cwd)
1205 if (chdir (change_cwd) < 0)
1206 FAIL_EXIT1 ("Can't cd to %s inside container - ", change_cwd);
1209 /* Now run the child. */
1210 execvp (new_child_exec, new_child_proc);
1212 /* Or don't run the child? */
1213 FAIL_EXIT1 ("Unable to exec %s: %s\n", new_child_exec, strerror (errno));
1215 /* Because gcc won't know error () never returns... */
1216 exit (EXIT_UNSUPPORTED);