test-container: move postclean outside of namespace changes
[glibc.git] / support / test-container.c
blob1d1aebeaf3412573dc37a884c8cf64d50fc8b65f
1 /* Run a test case in an isolated namespace.
2 Copyright (C) 2018 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 <http://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 "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 * rsync to $buildroot/testroot.root/
77 "Per-test" actions:
78 * maybe rsync to $buildroot/testroot.root/
79 * copy support files and test binary
80 * chroot/unshare
81 * set up any mounts (like /proc)
83 Magic files:
85 For test $srcdir/foo/mytest.c we look for $srcdir/foo/mytest.root
86 and, if found...
88 * mytest.root/ is rsync'd into container
89 * mytest.root/preclean.req causes fresh rsync (with delete) before
90 test if present
91 * mytest.root/mytest.script has a list of "commands" to run:
92 syntax:
93 # comment
95 mv FILE FILE
96 cp FILE FILE
97 rm FILE
98 FILE must start with $B/, $S/, $I/, $L/, or /
99 (expands to build dir, source dir, install dir, library dir
100 (in container), or container's root)
101 details:
102 - '#': A comment.
103 - 'su': Enables running test as root in the container.
104 - 'mv': A minimal move files command.
105 - 'cp': A minimal copy files command.
106 - 'rm': A minimal remove files command.
107 * mytest.root/postclean.req causes fresh rsync (with delete) after
108 test if present
110 Note that $srcdir/foo/mytest.script may be used instead of a
111 $srcdir/foo/mytest.root/mytest.script in the sysroot template, if
112 there is no other reason for a sysroot.
114 Design goals:
116 * independent of other packages which may not be installed (like
117 rsync or Docker, or even "cp")
119 * Simple, easy to review code (i.e. prefer simple naive code over
120 complex efficient code)
122 * The current implementation ist parallel-make-safe, but only in
123 that it uses a lock to prevent parallel access to the testroot. */
126 /* Utility Functions */
128 /* Like xunlink, but it's OK if the file already doesn't exist. */
129 void
130 maybe_xunlink (const char *path)
132 int rv = unlink (path);
133 if (rv < 0 && errno != ENOENT)
134 FAIL_EXIT1 ("unlink (\"%s\"): %m", path);
137 /* Like xmkdir, but it's OK if the directory already exists. */
138 void
139 maybe_xmkdir (const char *path, mode_t mode)
141 struct stat st;
143 if (stat (path, &st) == 0
144 && S_ISDIR (st.st_mode))
145 return;
146 xmkdir (path, mode);
149 /* Temporarily concatenate multiple strings into one. Allows up to 10
150 temporary results; use strdup () if you need them to be
151 permanent. */
152 static char *
153 concat (const char *str, ...)
155 /* Assume initialized to NULL/zero. */
156 static char *bufs[10];
157 static size_t buflens[10];
158 static int bufn = 0;
159 int n;
160 size_t len;
161 va_list ap, ap2;
162 char *cp;
163 char *next;
165 va_start (ap, str);
166 va_copy (ap2, ap);
168 n = bufn;
169 bufn = (bufn + 1) % 10;
170 len = strlen (str);
172 while ((next = va_arg (ap, char *)) != NULL)
173 len = len + strlen (next);
175 va_end (ap);
177 if (bufs[n] == NULL)
179 bufs[n] = xmalloc (len + 1); /* NUL */
180 buflens[n] = len + 1;
182 else if (buflens[n] < len + 1)
184 bufs[n] = xrealloc (bufs[n], len + 1); /* NUL */
185 buflens[n] = len + 1;
188 strcpy (bufs[n], str);
189 cp = strchr (bufs[n], '\0');
190 while ((next = va_arg (ap2, char *)) != NULL)
192 strcpy (cp, next);
193 cp = strchr (cp, '\0');
195 *cp = 0;
196 va_end (ap2);
198 return bufs[n];
201 /* Try to mount SRC onto DEST. */
202 static void
203 trymount (const char *src, const char *dest)
205 if (mount (src, dest, "", MS_BIND, NULL) < 0)
206 FAIL_EXIT1 ("can't mount %s onto %s\n", src, dest);
209 /* Special case of above for devices like /dev/zero where we have to
210 mount a device over a device, not a directory over a directory. */
211 static void
212 devmount (const char *new_root_path, const char *which)
214 int fd;
215 fd = open (concat (new_root_path, "/dev/", which, NULL),
216 O_CREAT | O_TRUNC | O_RDWR, 0777);
217 xclose (fd);
219 trymount (concat ("/dev/", which, NULL),
220 concat (new_root_path, "/dev/", which, NULL));
223 /* Returns true if the string "looks like" an environement variable
224 being set. */
225 static int
226 is_env_setting (const char *a)
228 int count_name = 0;
230 while (*a)
232 if (isalnum (*a) || *a == '_')
233 ++count_name;
234 else if (*a == '=' && count_name > 0)
235 return 1;
236 else
237 return 0;
238 ++a;
240 return 0;
243 /* Break the_line into words and store in the_words. Max nwords,
244 returns actual count. */
245 static int
246 tokenize (char *the_line, char **the_words, int nwords)
248 int rv = 0;
250 while (nwords > 0)
252 /* Skip leading whitespace, if any. */
253 while (*the_line && isspace (*the_line))
254 ++the_line;
256 /* End of line? */
257 if (*the_line == 0)
258 return rv;
260 /* THE_LINE points to a non-whitespace character, so we have a
261 word. */
262 *the_words = the_line;
263 ++the_words;
264 nwords--;
265 ++rv;
267 /* Skip leading whitespace, if any. */
268 while (*the_line && ! isspace (*the_line))
269 ++the_line;
271 /* We now point at the trailing NUL *or* some whitespace. */
272 if (*the_line == 0)
273 return rv;
275 /* It was whitespace, skip and keep tokenizing. */
276 *the_line++ = 0;
279 /* We get here if we filled the words buffer. */
280 return rv;
284 /* Mini-RSYNC implementation. Optimize later. */
286 /* A few routines for an "rsync buffer" which stores the paths we're
287 working on. We continuously grow and shrink the paths in each
288 buffer so there's lot of re-use. */
290 /* We rely on "initialized to zero" to set these up. */
291 typedef struct
293 char *buf;
294 size_t len;
295 size_t size;
296 } path_buf;
298 static path_buf spath, dpath;
300 static void
301 r_setup (char *path, path_buf * pb)
303 size_t len = strlen (path);
304 if (pb->buf == NULL || pb->size < len + 1)
306 /* Round up. This is an arbitrary number, just to keep from
307 reallocing too often. */
308 size_t sz = ALIGN_UP (len + 1, 512);
309 if (pb->buf == NULL)
310 pb->buf = (char *) xmalloc (sz);
311 else
312 pb->buf = (char *) xrealloc (pb->buf, sz);
313 if (pb->buf == NULL)
314 FAIL_EXIT1 ("Out of memory while rsyncing\n");
316 pb->size = sz;
318 strcpy (pb->buf, path);
319 pb->len = len;
322 static void
323 r_append (const char *path, path_buf * pb)
325 size_t len = strlen (path) + pb->len;
326 if (pb->size < len + 1)
328 /* Round up */
329 size_t sz = ALIGN_UP (len + 1, 512);
330 pb->buf = (char *) xrealloc (pb->buf, sz);
331 if (pb->buf == NULL)
332 FAIL_EXIT1 ("Out of memory while rsyncing\n");
334 pb->size = sz;
336 strcpy (pb->buf + pb->len, path);
337 pb->len = len;
340 static int
341 file_exists (char *path)
343 struct stat st;
344 if (lstat (path, &st) == 0)
345 return 1;
346 return 0;
349 static void
350 recursive_remove (char *path)
352 pid_t child;
353 int status;
355 child = fork ();
357 switch (child) {
358 case -1:
359 perror("fork");
360 FAIL_EXIT1 ("Unable to fork");
361 case 0:
362 /* Child. */
363 execlp ("rm", "rm", "-rf", path, NULL);
364 default:
365 /* Parent. */
366 waitpid (child, &status, 0);
367 /* "rm" would have already printed a suitable error message. */
368 if (! WIFEXITED (status)
369 || WEXITSTATUS (status) != 0)
370 exit (1);
372 break;
376 /* Used for both rsync and the mytest.script "cp" command. */
377 static void
378 copy_one_file (const char *sname, const char *dname)
380 int sfd, dfd;
381 struct stat st;
382 struct utimbuf times;
384 sfd = open (sname, O_RDONLY);
385 if (sfd < 0)
386 FAIL_EXIT1 ("unable to open %s for reading\n", sname);
388 if (fstat (sfd, &st) < 0)
389 FAIL_EXIT1 ("unable to fstat %s\n", sname);
391 dfd = open (dname, O_WRONLY | O_TRUNC | O_CREAT, 0600);
392 if (dfd < 0)
393 FAIL_EXIT1 ("unable to open %s for writing\n", dname);
395 xcopy_file_range (sfd, 0, dfd, 0, st.st_size, 0);
397 xclose (sfd);
398 xclose (dfd);
400 if (chmod (dname, st.st_mode & 0777) < 0)
401 FAIL_EXIT1 ("chmod %s: %s\n", dname, strerror (errno));
403 times.actime = st.st_atime;
404 times.modtime = st.st_mtime;
405 if (utime (dname, &times) < 0)
406 FAIL_EXIT1 ("utime %s: %s\n", dname, strerror (errno));
409 /* We don't check *everything* about the two files to see if a copy is
410 needed, just the minimum to make sure we get the latest copy. */
411 static int
412 need_sync (char *ap, char *bp, struct stat *a, struct stat *b)
414 if ((a->st_mode & S_IFMT) != (b->st_mode & S_IFMT))
415 return 1;
417 if (S_ISLNK (a->st_mode))
419 int rv;
420 char *al, *bl;
422 if (a->st_size != b->st_size)
423 return 1;
425 al = xreadlink (ap);
426 bl = xreadlink (bp);
427 rv = strcmp (al, bl);
428 free (al);
429 free (bl);
430 if (rv == 0)
431 return 0; /* links are same */
432 return 1; /* links differ */
435 if (verbose)
437 if (a->st_size != b->st_size)
438 printf ("SIZE\n");
439 if ((a->st_mode & 0777) != (b->st_mode & 0777))
440 printf ("MODE\n");
441 if (a->st_mtime != b->st_mtime)
442 printf ("TIME\n");
445 if (a->st_size == b->st_size
446 && ((a->st_mode & 0777) == (b->st_mode & 0777))
447 && a->st_mtime == b->st_mtime)
448 return 0;
450 return 1;
453 static void
454 rsync_1 (path_buf * src, path_buf * dest, int and_delete)
456 DIR *dir;
457 struct dirent *de;
458 struct stat s, d;
460 r_append ("/", src);
461 r_append ("/", dest);
463 if (verbose)
464 printf ("sync %s to %s %s\n", src->buf, dest->buf,
465 and_delete ? "and delete" : "");
467 size_t staillen = src->len;
469 size_t dtaillen = dest->len;
471 dir = opendir (src->buf);
473 while ((de = readdir (dir)) != NULL)
475 if (strcmp (de->d_name, ".") == 0
476 || strcmp (de->d_name, "..") == 0)
477 continue;
479 src->len = staillen;
480 r_append (de->d_name, src);
481 dest->len = dtaillen;
482 r_append (de->d_name, dest);
484 s.st_mode = ~0;
485 d.st_mode = ~0;
487 if (lstat (src->buf, &s) != 0)
488 FAIL_EXIT1 ("%s obtained by readdir, but stat failed.\n", src->buf);
490 /* It's OK if this one fails, since we know the file might be
491 missing. */
492 lstat (dest->buf, &d);
494 if (! need_sync (src->buf, dest->buf, &s, &d))
496 if (S_ISDIR (s.st_mode))
497 rsync_1 (src, dest, and_delete);
498 continue;
501 if (d.st_mode != ~0)
502 switch (d.st_mode & S_IFMT)
504 case S_IFDIR:
505 if (!S_ISDIR (s.st_mode))
507 if (verbose)
508 printf ("-D %s\n", dest->buf);
509 recursive_remove (dest->buf);
511 break;
513 default:
514 if (verbose)
515 printf ("-F %s\n", dest->buf);
516 maybe_xunlink (dest->buf);
517 break;
520 switch (s.st_mode & S_IFMT)
522 case S_IFREG:
523 if (verbose)
524 printf ("+F %s\n", dest->buf);
525 copy_one_file (src->buf, dest->buf);
526 break;
528 case S_IFDIR:
529 if (verbose)
530 printf ("+D %s\n", dest->buf);
531 maybe_xmkdir (dest->buf, (s.st_mode & 0777) | 0700);
532 rsync_1 (src, dest, and_delete);
533 break;
535 case S_IFLNK:
537 char *lp;
538 if (verbose)
539 printf ("+L %s\n", dest->buf);
540 lp = xreadlink (src->buf);
541 xsymlink (lp, dest->buf);
542 free (lp);
543 break;
546 default:
547 break;
551 closedir (dir);
552 src->len = staillen;
553 src->buf[staillen] = 0;
554 dest->len = dtaillen;
555 dest->buf[dtaillen] = 0;
557 if (!and_delete)
558 return;
560 /* The rest of this function removes any files/directories in DEST
561 that do not exist in SRC. This is triggered as part of a
562 preclean or postsclean step. */
564 dir = opendir (dest->buf);
566 while ((de = readdir (dir)) != NULL)
568 if (strcmp (de->d_name, ".") == 0
569 || strcmp (de->d_name, "..") == 0)
570 continue;
572 src->len = staillen;
573 r_append (de->d_name, src);
574 dest->len = dtaillen;
575 r_append (de->d_name, dest);
577 s.st_mode = ~0;
578 d.st_mode = ~0;
580 lstat (src->buf, &s);
582 if (lstat (dest->buf, &d) != 0)
583 FAIL_EXIT1 ("%s obtained by readdir, but stat failed.\n", dest->buf);
585 if (s.st_mode == ~0)
587 /* dest exists and src doesn't, clean it. */
588 switch (d.st_mode & S_IFMT)
590 case S_IFDIR:
591 if (!S_ISDIR (s.st_mode))
593 if (verbose)
594 printf ("-D %s\n", dest->buf);
595 recursive_remove (dest->buf);
597 break;
599 default:
600 if (verbose)
601 printf ("-F %s\n", dest->buf);
602 maybe_xunlink (dest->buf);
603 break;
608 closedir (dir);
611 static void
612 rsync (char *src, char *dest, int and_delete)
614 r_setup (src, &spath);
615 r_setup (dest, &dpath);
617 rsync_1 (&spath, &dpath, and_delete);
622 /* See if we can detect what the user needs to do to get unshare
623 support working for us. */
624 void
625 check_for_unshare_hints (void)
627 FILE *f;
628 int i;
630 /* Default Debian Linux disables user namespaces, but allows a way
631 to enable them. */
632 f = fopen ("/proc/sys/kernel/unprivileged_userns_clone", "r");
633 if (f != NULL)
635 i = 99; /* Sentinel. */
636 fscanf (f, "%d", &i);
637 if (i == 0)
639 printf ("To enable test-container, please run this as root:\n");
640 printf (" echo 1 > /proc/sys/kernel/unprivileged_userns_clone\n");
642 fclose (f);
643 return;
646 /* ALT Linux has an alternate way of doing the same. */
647 f = fopen ("/proc/sys/kernel/userns_restrict", "r");
648 if (f != NULL)
650 i = 99; /* Sentinel. */
651 fscanf (f, "%d", &i);
652 if (i == 1)
654 printf ("To enable test-container, please run this as root:\n");
655 printf (" echo 0 > /proc/sys/kernel/userns_restrict\n");
657 fclose (f);
658 return;
663 main (int argc, char **argv)
665 pid_t child;
666 char *pristine_root_path;
667 char *new_root_path;
668 char *new_cwd_path;
669 char *new_objdir_path;
670 char *new_srcdir_path;
671 char **new_child_proc;
672 char *command_root;
673 char *command_base;
674 char *command_basename;
675 char *so_base;
676 int do_postclean = 0;
678 uid_t original_uid;
679 gid_t original_gid;
680 /* If set, the test runs as root instead of the user running the testsuite. */
681 int be_su = 0;
682 int UMAP;
683 int GMAP;
684 /* Used for "%lld %lld 1" so need not be large. */
685 char tmp[100];
686 struct stat st;
687 int lock_fd;
689 setbuf (stdout, NULL);
691 /* The command line we're expecting looks like this:
692 env <set some vars> ld.so <library path> test-binary
694 We need to peel off any "env" or "ld.so" portion of the command
695 line, and keep track of which env vars we should preserve and
696 which we drop. */
698 if (argc < 2)
700 fprintf (stderr, "Usage: containerize <program to run> <args...>\n");
701 exit (1);
704 if (strcmp (argv[1], "-v") == 0)
706 verbose = 1;
707 ++argv;
708 --argc;
711 if (strcmp (argv[1], "env") == 0)
713 ++argv;
714 --argc;
715 while (is_env_setting (argv[1]))
717 /* If there are variables we do NOT want to propogate, this
718 is where the test for them goes. */
720 /* Need to keep these. Note that putenv stores a
721 pointer to our argv. */
722 putenv (argv[1]);
724 ++argv;
725 --argc;
729 if (strcmp (argv[1], support_objdir_elf_ldso) == 0)
731 ++argv;
732 --argc;
733 while (argv[1][0] == '-')
735 if (strcmp (argv[1], "--library-path") == 0)
737 ++argv;
738 --argc;
740 ++argv;
741 --argc;
745 pristine_root_path = strdup (concat (support_objdir_root,
746 "/testroot.pristine", NULL));
747 new_root_path = strdup (concat (support_objdir_root,
748 "/testroot.root", NULL));
749 new_cwd_path = get_current_dir_name ();
750 new_child_proc = argv + 1;
752 lock_fd = open (concat (pristine_root_path, "/lock.fd", NULL),
753 O_CREAT | O_TRUNC | O_RDWR, 0666);
754 if (lock_fd < 0)
755 FAIL_EXIT1 ("Cannot create testroot lock.\n");
757 while (flock (lock_fd, LOCK_EX) != 0)
759 if (errno != EINTR)
760 FAIL_EXIT1 ("Cannot lock testroot.\n");
763 xmkdirp (new_root_path, 0755);
765 /* We look for extra setup info in a subdir in the same spot as the
766 test, with the same name but a ".root" extension. This is that
767 directory. We try to look in the source tree if the path we're
768 given refers to the build tree, but we rely on the path to be
769 absolute. This is what the glibc makefiles do. */
770 command_root = concat (argv[1], ".root", NULL);
771 if (strncmp (command_root, support_objdir_root,
772 strlen (support_objdir_root)) == 0
773 && command_root[strlen (support_objdir_root)] == '/')
774 command_root = concat (support_srcdir_root,
775 argv[1] + strlen (support_objdir_root),
776 ".root", NULL);
777 command_root = strdup (command_root);
779 /* This cuts off the ".root" we appended above. */
780 command_base = strdup (command_root);
781 command_base[strlen (command_base) - 5] = 0;
783 /* This is the basename of the test we're running. */
784 command_basename = strrchr (command_base, '/');
785 if (command_basename == NULL)
786 command_basename = command_base;
787 else
788 ++command_basename;
790 /* Shared object base directory. */
791 so_base = strdup (argv[1]);
792 if (strrchr (so_base, '/') != NULL)
793 strrchr (so_base, '/')[1] = 0;
795 if (file_exists (concat (command_root, "/postclean.req", NULL)))
796 do_postclean = 1;
798 rsync (pristine_root_path, new_root_path,
799 file_exists (concat (command_root, "/preclean.req", NULL)));
801 if (stat (command_root, &st) >= 0
802 && S_ISDIR (st.st_mode))
803 rsync (command_root, new_root_path, 0);
805 new_objdir_path = strdup (concat (new_root_path,
806 support_objdir_root, NULL));
807 new_srcdir_path = strdup (concat (new_root_path,
808 support_srcdir_root, NULL));
810 /* new_cwd_path starts with '/' so no "/" needed between the two. */
811 xmkdirp (concat (new_root_path, new_cwd_path, NULL), 0755);
812 xmkdirp (new_srcdir_path, 0755);
813 xmkdirp (new_objdir_path, 0755);
815 original_uid = getuid ();
816 original_gid = getgid ();
818 /* Handle the cp/mv/rm "script" here. */
820 char *the_line = NULL;
821 size_t line_len = 0;
822 char *fname = concat (command_root, "/",
823 command_basename, ".script", NULL);
824 char *the_words[3];
825 FILE *f = fopen (fname, "r");
827 if (verbose && f)
828 fprintf (stderr, "running %s\n", fname);
830 if (f == NULL)
832 /* Try foo.script instead of foo.root/foo.script, as a shortcut. */
833 fname = concat (command_base, ".script", NULL);
834 f = fopen (fname, "r");
835 if (verbose && f)
836 fprintf (stderr, "running %s\n", fname);
839 /* Note that we do NOT look for a Makefile-generated foo.script in
840 the build directory. If that is ever needed, this is the place
841 to add it. */
843 /* This is where we "interpret" the mini-script which is <test>.script. */
844 if (f != NULL)
846 while (getline (&the_line, &line_len, f) > 0)
848 int nt = tokenize (the_line, the_words, 3);
849 int i;
851 for (i = 1; i < nt; ++i)
853 if (memcmp (the_words[i], "$B/", 3) == 0)
854 the_words[i] = concat (support_objdir_root,
855 the_words[i] + 2, NULL);
856 else if (memcmp (the_words[i], "$S/", 3) == 0)
857 the_words[i] = concat (support_srcdir_root,
858 the_words[i] + 2, NULL);
859 else if (memcmp (the_words[i], "$I/", 3) == 0)
860 the_words[i] = concat (new_root_path,
861 support_install_prefix,
862 the_words[i] + 2, NULL);
863 else if (memcmp (the_words[i], "$L/", 3) == 0)
864 the_words[i] = concat (new_root_path,
865 support_libdir_prefix,
866 the_words[i] + 2, NULL);
867 else if (the_words[i][0] == '/')
868 the_words[i] = concat (new_root_path,
869 the_words[i], NULL);
872 if (nt == 3 && the_words[2][strlen (the_words[2]) - 1] == '/')
874 char *r = strrchr (the_words[1], '/');
875 if (r)
876 the_words[2] = concat (the_words[2], r + 1, NULL);
877 else
878 the_words[2] = concat (the_words[2], the_words[1], NULL);
881 if (nt == 2 && strcmp (the_words[0], "so") == 0)
883 the_words[2] = concat (new_root_path, support_libdir_prefix,
884 "/", the_words[1], NULL);
885 the_words[1] = concat (so_base, the_words[1], NULL);
886 copy_one_file (the_words[1], the_words[2]);
888 else if (nt == 3 && strcmp (the_words[0], "cp") == 0)
890 copy_one_file (the_words[1], the_words[2]);
892 else if (nt == 3 && strcmp (the_words[0], "mv") == 0)
894 if (rename (the_words[1], the_words[2]) < 0)
895 FAIL_EXIT1 ("rename %s -> %s: %s", the_words[1],
896 the_words[2], strerror (errno));
898 else if (nt == 3 && strcmp (the_words[0], "chmod") == 0)
900 long int m;
901 m = strtol (the_words[1], NULL, 0);
902 if (chmod (the_words[2], m) < 0)
903 FAIL_EXIT1 ("chmod %s: %s\n",
904 the_words[2], strerror (errno));
907 else if (nt == 2 && strcmp (the_words[0], "rm") == 0)
909 maybe_xunlink (the_words[1]);
911 else if (nt == 1 && strcmp (the_words[0], "su") == 0)
913 be_su = 1;
915 else if (nt > 0 && the_words[0][0] != '#')
917 printf ("\033[31minvalid [%s]\033[0m\n", the_words[0]);
920 fclose (f);
924 if (do_postclean)
926 pid_t pc_pid = fork ();
928 if (pc_pid < 0)
930 FAIL_EXIT1 ("Can't fork for post-clean");
932 else if (pc_pid > 0)
934 /* Parent. */
935 int status;
936 waitpid (pc_pid, &status, 0);
938 /* Child has exited, we can post-clean the test root. */
939 printf("running post-clean rsync\n");
940 rsync (pristine_root_path, new_root_path, 1);
942 if (WIFEXITED (status))
943 exit (WEXITSTATUS (status));
945 if (WIFSIGNALED (status))
947 printf ("%%SIGNALLED%%\n");
948 exit (77);
951 printf ("%%EXITERROR%%\n");
952 exit (78);
955 /* Child continues. */
958 /* This is the last point in the program where we're still in the
959 "normal" namespace. */
961 #ifdef CLONE_NEWNS
962 /* The unshare here gives us our own spaces and capabilities. */
963 if (unshare (CLONE_NEWUSER | CLONE_NEWPID | CLONE_NEWNS) < 0)
965 /* Older kernels may not support all the options, or security
966 policy may block this call. */
967 if (errno == EINVAL || errno == EPERM)
969 int saved_errno = errno;
970 if (errno == EPERM)
971 check_for_unshare_hints ();
972 FAIL_UNSUPPORTED ("unable to unshare user/fs: %s", strerror (saved_errno));
974 else
975 FAIL_EXIT1 ("unable to unshare user/fs: %s", strerror (errno));
977 #else
978 /* Some targets may not support unshare at all. */
979 FAIL_UNSUPPORTED ("unshare support missing");
980 #endif
982 /* Some systems, by default, all mounts leak out of the namespace. */
983 if (mount ("none", "/", NULL, MS_REC | MS_PRIVATE, NULL) != 0)
984 FAIL_EXIT1 ("could not create a private mount namespace\n");
986 trymount (support_srcdir_root, new_srcdir_path);
987 trymount (support_objdir_root, new_objdir_path);
989 xmkdirp (concat (new_root_path, "/dev", NULL), 0755);
990 devmount (new_root_path, "null");
991 devmount (new_root_path, "zero");
992 devmount (new_root_path, "urandom");
994 /* We're done with the "old" root, switch to the new one. */
995 if (chroot (new_root_path) < 0)
996 FAIL_EXIT1 ("Can't chroot to %s - ", new_root_path);
998 if (chdir (new_cwd_path) < 0)
999 FAIL_EXIT1 ("Can't cd to new %s - ", new_cwd_path);
1001 /* To complete the containerization, we need to fork () at least
1002 once. We can't exec, nor can we somehow link the new child to
1003 our parent. So we run the child and propogate it's exit status
1004 up. */
1005 child = fork ();
1006 if (child < 0)
1007 FAIL_EXIT1 ("Unable to fork");
1008 else if (child > 0)
1010 /* Parent. */
1011 int status;
1012 waitpid (child, &status, 0);
1014 if (WIFEXITED (status))
1015 exit (WEXITSTATUS (status));
1017 if (WIFSIGNALED (status))
1019 printf ("%%SIGNALLED%%\n");
1020 exit (77);
1023 printf ("%%EXITERROR%%\n");
1024 exit (78);
1027 /* The rest is the child process, which is now PID 1 and "in" the
1028 new root. */
1030 maybe_xmkdir ("/tmp", 0755);
1032 /* Now that we're pid 1 (effectively "root") we can mount /proc */
1033 maybe_xmkdir ("/proc", 0777);
1034 if (mount ("proc", "/proc", "proc", 0, NULL) < 0)
1035 FAIL_EXIT1 ("Unable to mount /proc: ");
1037 /* We map our original UID to the same UID in the container so we
1038 can own our own files normally. */
1039 UMAP = open ("/proc/self/uid_map", O_WRONLY);
1040 if (UMAP < 0)
1041 FAIL_EXIT1 ("can't write to /proc/self/uid_map\n");
1043 sprintf (tmp, "%lld %lld 1\n",
1044 (long long) (be_su ? 0 : original_uid), (long long) original_uid);
1045 write (UMAP, tmp, strlen (tmp));
1046 xclose (UMAP);
1048 /* We must disable setgroups () before we can map our groups, else we
1049 get EPERM. */
1050 GMAP = open ("/proc/self/setgroups", O_WRONLY);
1051 if (GMAP >= 0)
1053 /* We support kernels old enough to not have this. */
1054 write (GMAP, "deny\n", 5);
1055 xclose (GMAP);
1058 /* We map our original GID to the same GID in the container so we
1059 can own our own files normally. */
1060 GMAP = open ("/proc/self/gid_map", O_WRONLY);
1061 if (GMAP < 0)
1062 FAIL_EXIT1 ("can't write to /proc/self/gid_map\n");
1064 sprintf (tmp, "%lld %lld 1\n",
1065 (long long) (be_su ? 0 : original_gid), (long long) original_gid);
1066 write (GMAP, tmp, strlen (tmp));
1067 xclose (GMAP);
1069 /* Now run the child. */
1070 execvp (new_child_proc[0], new_child_proc);
1072 /* Or don't run the child? */
1073 FAIL_EXIT1 ("Unable to exec %s\n", new_child_proc[0]);
1075 /* Because gcc won't know error () never returns... */
1076 exit (EXIT_UNSUPPORTED);