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
25 #include <sys/syscall.h>
27 #include <sys/types.h>
31 #include <sys/fcntl.h>
35 #include <sys/sysmacros.h>
40 #include <libc-pointer-arith.h>
43 #include <sys/mount.h>
46 #include <support/support.h>
47 #include <support/xunistd.h>
48 #include <support/capture_subprocess.h>
50 #include "test-driver.h"
53 #define mount(s,t,fs,f,d) no_mount()
56 FAIL_UNSUPPORTED("mount not supported; port needed");
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
68 2. "Per-test" actions, like copying in support files and
69 configuring the container.
74 * mkdir $buildroot/testroot.pristine/
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/
83 * maybe rsync to $buildroot/testroot.root/
84 * copy support files and test binary
86 * set up any mounts (like /proc)
91 For test $srcdir/foo/mytest.c we look for $srcdir/foo/mytest.root
94 * mytest.root/ is rsync'd into container
95 * mytest.root/preclean.req causes fresh rsync (with delete) before
97 * mytest.root/mytest.script has a list of "commands" to run:
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)
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.
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
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.
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. */
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. */
168 maybe_xmkdir (const char *path
, mode_t mode
)
172 if (stat (path
, &st
) == 0
173 && S_ISDIR (st
.st_mode
))
178 /* Temporarily concatenate multiple strings into one. Allows up to 10
179 temporary results; use xstrdup () if you need them to be
182 concat (const char *str
, ...)
184 /* Assume initialized to NULL/zero. */
185 static char *bufs
[10];
186 static size_t buflens
[10];
198 bufn
= (bufn
+ 1) % 10;
201 while ((next
= va_arg (ap
, char *)) != NULL
)
202 len
= len
+ strlen (next
);
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
)
222 cp
= strchr (cp
, '\0');
230 /* Try to mount SRC onto DEST. */
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. */
241 devmount (const char *new_root_path
, const char *which
)
244 fd
= open (concat (new_root_path
, "/dev/", which
, NULL
),
245 O_CREAT
| O_TRUNC
| O_RDWR
, 0777);
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
255 is_env_setting (const char *a
)
261 if (isalnum (*a
) || *a
== '_')
263 else if (*a
== '=' && count_name
> 0)
272 /* Break the_line into words and store in the_words. Max nwords,
273 returns actual count. */
275 tokenize (char *the_line
, char **the_words
, int nwords
)
281 /* Skip leading whitespace, if any. */
282 while (*the_line
&& isspace (*the_line
))
289 /* THE_LINE points to a non-whitespace character, so we have a
291 *the_words
= the_line
;
296 /* Skip leading whitespace, if any. */
297 while (*the_line
&& ! isspace (*the_line
))
300 /* We now point at the trailing NUL *or* some whitespace. */
304 /* It was whitespace, skip and keep tokenizing. */
308 /* We get here if we filled the words buffer. */
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. */
327 static path_buf spath
, dpath
;
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);
339 pb
->buf
= (char *) xmalloc (sz
);
341 pb
->buf
= (char *) xrealloc (pb
->buf
, sz
);
343 FAIL_EXIT1 ("Out of memory while rsyncing\n");
347 strcpy (pb
->buf
, path
);
352 r_append (const char *path
, path_buf
* pb
)
354 size_t len
= strlen (path
) + pb
->len
;
355 if (pb
->size
< len
+ 1)
358 size_t sz
= ALIGN_UP (len
+ 1, 512);
359 pb
->buf
= (char *) xrealloc (pb
->buf
, sz
);
361 FAIL_EXIT1 ("Out of memory while rsyncing\n");
365 strcpy (pb
->buf
+ pb
->len
, path
);
370 file_exists (char *path
)
373 if (lstat (path
, &st
) == 0)
379 recursive_remove (char *path
)
389 FAIL_EXIT1 ("Unable to fork");
392 execlp ("rm", "rm", "-rf", path
, NULL
);
393 FAIL_EXIT1 ("exec rm: %m");
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
);
406 /* Used for both rsync and the mytest.script "cp" command. */
408 copy_one_file (const char *sname
, const char *dname
)
412 struct utimbuf times
;
414 sfd
= open (sname
, O_RDONLY
);
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);
423 FAIL_EXIT1 ("unable to open %s for writing\n", dname
);
425 xcopy_file_range (sfd
, 0, dfd
, 0, st
.st_size
, 0);
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
, ×
) < 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. */
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
))
447 if (S_ISLNK (a
->st_mode
))
452 if (a
->st_size
!= b
->st_size
)
457 rv
= strcmp (al
, bl
);
461 return 0; /* links are same */
462 return 1; /* links differ */
467 if (a
->st_size
!= b
->st_size
)
469 if ((a
->st_mode
& 0777) != (b
->st_mode
& 0777))
471 if (a
->st_mtime
!= b
->st_mtime
)
475 if (a
->st_size
== b
->st_size
476 && ((a
->st_mode
& 0777) == (b
->st_mode
& 0777))
477 && a
->st_mtime
== b
->st_mtime
)
484 rsync_1 (path_buf
* src
, path_buf
* dest
, int and_delete
, int force_copies
)
491 r_append ("/", dest
);
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)
511 r_append (de
->d_name
, src
);
512 dest
->len
= dtaillen
;
513 r_append (de
->d_name
, dest
);
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
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
);
533 switch (d
.st_mode
& S_IFMT
)
536 if (!S_ISDIR (s
.st_mode
))
539 printf ("-D %s\n", dest
->buf
);
540 recursive_remove (dest
->buf
);
546 printf ("-F %s\n", dest
->buf
);
547 maybe_xunlink (dest
->buf
);
551 switch (s
.st_mode
& S_IFMT
)
555 printf ("+F %s\n", dest
->buf
);
556 copy_one_file (src
->buf
, dest
->buf
);
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
);
570 printf ("+L %s\n", dest
->buf
);
571 lp
= xreadlink (src
->buf
);
572 xsymlink (lp
, dest
->buf
);
584 src
->buf
[staillen
] = 0;
585 dest
->len
= dtaillen
;
586 dest
->buf
[dtaillen
] = 0;
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)
604 r_append (de
->d_name
, src
);
605 dest
->len
= dtaillen
;
606 r_append (de
->d_name
, dest
);
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
);
618 /* dest exists and src doesn't, clean it. */
619 switch (d
.st_mode
& S_IFMT
)
622 if (!S_ISDIR (s
.st_mode
))
625 printf ("-D %s\n", dest
->buf
);
626 recursive_remove (dest
->buf
);
632 printf ("-F %s\n", dest
->buf
);
633 maybe_xunlink (dest
->buf
);
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. */
656 check_for_unshare_hints (void)
661 /* Default Debian Linux disables user namespaces, but allows a way
663 f
= fopen ("/proc/sys/kernel/unprivileged_userns_clone", "r");
666 i
= 99; /* Sentinel. */
667 fscanf (f
, "%d", &i
);
670 printf ("To enable test-container, please run this as root:\n");
671 printf (" echo 1 > /proc/sys/kernel/unprivileged_userns_clone\n");
677 /* ALT Linux has an alternate way of doing the same. */
678 f
= fopen ("/proc/sys/kernel/userns_restrict", "r");
681 i
= 99; /* Sentinel. */
682 fscanf (f
, "%d", &i
);
685 printf ("To enable test-container, please run this as root:\n");
686 printf (" echo 0 > /proc/sys/kernel/userns_restrict\n");
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
)
707 char *pristine_root_path
;
710 char *new_objdir_path
;
711 char *new_srcdir_path
;
712 char **new_child_proc
;
713 char *new_child_exec
;
716 char *command_basename
;
718 int do_postclean
= 0;
719 bool do_ldconfig
= false;
720 char *change_cwd
= NULL
;
727 /* If set, the test runs as root instead of the user running the testsuite. */
731 /* Used for "%lld %lld 1" so need not be large. */
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
747 fprintf (stderr
, "Usage: test-container <program to run> <args...>\n");
751 if (strcmp (argv
[1], "-v") == 0)
758 if (strcmp (argv
[1], "env") == 0)
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. */
776 if (strcmp (argv
[1], support_objdir_elf_ldso
) == 0)
780 while (argv
[1][0] == '-')
782 if (strcmp (argv
[1], "--library-path") == 0)
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);
803 FAIL_EXIT1 ("Cannot create testroot lock.\n");
805 while (flock (lock_fd
, LOCK_EX
) != 0)
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
),
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
;
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
)))
846 if (file_exists (concat (command_root
, "/ldconfig.run", NULL
)))
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
;
873 char *fname
= concat (command_root
, "/",
874 command_basename
, ".script", NULL
);
876 FILE *f
= fopen (fname
, "r");
879 fprintf (stderr
, "running %s\n", fname
);
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");
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
894 /* This is where we "interpret" the mini-script which is <test>.script. */
897 while (getline (&the_line
, &line_len
, f
) > 0)
899 int nt
= tokenize (the_line
, the_words
, 3);
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
,
931 if (nt
== 3 && the_words
[2][strlen (the_words
[2]) - 1] == '/')
933 char *r
= strrchr (the_words
[1], '/');
935 the_words
[2] = concat (the_words
[2], r
+ 1, NULL
);
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)
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]),
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
996 copy_one_file (new_child_proc
[0], concat (new_root_path
,
1000 new_child_exec
= xstrdup (new_exec_path
);
1002 new_child_proc
[0] = xstrdup (the_words
[2]);
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)
1014 else if (nt
== 3 && strcmp (the_words
[0], "mkdirp") == 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]);
1034 pid_t pc_pid
= fork ();
1038 FAIL_EXIT1 ("Can't fork for post-clean");
1040 else if (pc_pid
> 0)
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");
1059 printf ("%%EXITERROR%%\n");
1063 /* Child continues. */
1066 /* This is the last point in the program where we're still in the
1067 "normal" namespace. */
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
;
1079 check_for_unshare_hints ();
1080 FAIL_UNSUPPORTED ("unable to unshare user/fs: %s", strerror (saved_errno
));
1083 FAIL_EXIT1 ("unable to unshare user/fs: %s", strerror (errno
));
1086 /* Some targets may not support unshare at all. */
1087 FAIL_UNSUPPORTED ("unshare support missing");
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
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
1120 FAIL_EXIT1 ("Unable to fork");
1126 /* Send the child's "outside" pid to it. */
1127 write (pipes
[1], &child
, sizeof(child
));
1131 waitpid (child
, &status
, 0);
1133 if (WIFEXITED (status
))
1134 exit (WEXITSTATUS (status
));
1136 if (WIFSIGNALED (status
))
1138 printf ("%%SIGNALLED%%\n");
1142 printf ("%%EXITERROR%%\n");
1146 /* The rest is the child process, which is now PID 1 and "in" the
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
));
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
);
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
));
1182 /* We must disable setgroups () before we can map our groups, else we
1184 GMAP
= open ("/proc/self/setgroups", O_WRONLY
);
1187 /* We support kernels old enough to not have this. */
1188 write (GMAP
, "deny\n", 5);
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
);
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
));
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
);