pack: Wrapper honors 'GUIX_EXECUTION_ENGINE' environment variable.

* gnu/packages/aux-files/run-in-namespace.c (struct engine): New type.
(exec_default): New function.
(engines): New variable.
(execution_engine): New function.
(main): Use it instead of calling 'exec_in_user_namespace' and
'exec_with_proot' directly.
* tests/guix-pack-relocatable.sh: Add test with 'GUIX_EXECUTION_ENGINE'.
* doc/guix.texi (Invoking guix pack): Document 'GUIX_EXECUTION_ENGINE'.
This commit is contained in:
Ludovic Courtès 2020-05-11 16:32:24 +02:00
parent 80963744a2
commit fde2aec3f4
No known key found for this signature in database
GPG Key ID: 090B11993D9AEBB5
3 changed files with 110 additions and 15 deletions

View File

@ -5187,9 +5187,9 @@ When this option is passed once, the resulting binaries require support for
@dfn{user namespaces} in the kernel Linux; when passed
@emph{twice}@footnote{Here's a trick to memorize it: @code{-RR}, which adds
PRoot support, can be thought of as the abbreviation of ``Really
Relocatable''. Neat, isn't it?}, relocatable binaries fall to back to PRoot
if user namespaces are unavailable, and essentially work anywhere---see below
for the implications.
Relocatable''. Neat, isn't it?}, relocatable binaries fall to back to
other techniques if user namespaces are unavailable, and essentially
work anywhere---see below for the implications.
For example, if you create a pack containing Bash with:
@ -5221,14 +5221,32 @@ turn it off.
To produce relocatable binaries that work even in the absence of user
namespaces, pass @option{--relocatable} or @option{-R} @emph{twice}. In that
case, binaries will try user namespace support and fall back to PRoot if user
namespaces are not supported.
case, binaries will try user namespace support and fall back to another
@dfn{execution engine} if user namespaces are not supported. The
following execution engines are supported:
The @uref{https://proot-me.github.io/, PRoot} program provides the necessary
@table @code
@item default
Try user namespaces and fall back to PRoot if user namespaces are not
supported (see below).
@item userns
Run the program through user namespaces and abort if they are not
supported.
@item proot
Run through PRoot. The @uref{https://proot-me.github.io/, PRoot} program
provides the necessary
support for file system virtualization. It achieves that by using the
@code{ptrace} system call on the running program. This approach has the
advantage to work without requiring special kernel support, but it incurs
run-time overhead every time a system call is made.
@end table
@vindex GUIX_EXECUTION_ENGINE
When running a wrapped program, you can explicitly request one of the
execution engines listed above by setting the
@code{GUIX_EXECUTION_ENGINE} environment variable accordingly.
@end quotation
@cindex entry point, for Docker images

View File

@ -336,6 +336,71 @@ exec_with_proot (const char *store, int argc, char *argv[])
#endif
/* Execution engines. */
struct engine
{
const char *name;
void (* exec) (const char *, int, char **);
};
static void
buffer_stderr (void)
{
static char stderr_buffer[4096];
setvbuf (stderr, stderr_buffer, _IOFBF, sizeof stderr_buffer);
}
/* The default engine. */
static void
exec_default (const char *store, int argc, char *argv[])
{
/* Buffer stderr so that nothing's displayed if 'exec_in_user_namespace'
fails but 'exec_with_proot' works. */
buffer_stderr ();
exec_in_user_namespace (store, argc, argv);
#ifdef PROOT_PROGRAM
exec_with_proot (store, argc, argv);
#endif
}
/* List of supported engines. */
static const struct engine engines[] =
{
{ "default", exec_default },
{ "userns", exec_in_user_namespace },
#ifdef PROOT_PROGRAM
{ "proot", exec_with_proot },
#endif
{ NULL, NULL }
};
/* Return the "execution engine" to use. */
static const struct engine *
execution_engine (void)
{
const char *str = getenv ("GUIX_EXECUTION_ENGINE");
if (str == NULL)
str = "default";
try:
for (const struct engine *engine = engines;
engine->name != NULL;
engine++)
{
if (strcmp (engine->name, str) == 0)
return engine;
}
fprintf (stderr, "%s: unsupported Guix execution engine; ignoring\n",
str);
str = "default";
goto try;
}
int
main (int argc, char *argv[])
@ -362,22 +427,17 @@ main (int argc, char *argv[])
if (strcmp (store, "@STORE_DIRECTORY@") != 0
&& lstat ("@WRAPPED_PROGRAM@", &statbuf) != 0)
{
/* Buffer stderr so that nothing's displayed if 'exec_in_user_namespace'
fails but 'exec_with_proot' works. */
static char stderr_buffer[4096];
setvbuf (stderr, stderr_buffer, _IOFBF, sizeof stderr_buffer);
const struct engine *engine = execution_engine ();
engine->exec (store, argc, argv);
exec_in_user_namespace (store, argc, argv);
#ifdef PROOT_PROGRAM
exec_with_proot (store, argc, argv);
#else
/* If we reach this point, that's because ENGINE failed to do the
job. */
fprintf (stderr, "\
This may be because \"user namespaces\" are not supported on this system.\n\
Consequently, we cannot run '@WRAPPED_PROGRAM@',\n\
unless you move it to the '@STORE_DIRECTORY@' directory.\n\
\n\
Please refer to the 'guix pack' documentation for more information.\n");
#endif
return EXIT_FAILURE;
}

View File

@ -84,6 +84,23 @@ fi
grep 'GNU sed' "$test_directory/output"
chmod -Rf +w "$test_directory"; rm -rf "$test_directory"/*
case "`uname -m`" in
x86_64|i?86)
# Try '-RR' and PRoot.
tarball="`guix pack -RR -S /Bin=bin sed`"
tar tvf "$tarball" | grep /bin/proot
(cd "$test_directory"; tar xvf "$tarball")
GUIX_EXECUTION_ENGINE="proot"
export GUIX_EXECUTION_ENGINE
"$test_directory/Bin/sed" --version > "$test_directory/output"
grep 'GNU sed' "$test_directory/output"
chmod -Rf +w "$test_directory"; rm -rf "$test_directory"/*
;;
*)
echo "skipping PRoot test" >&2
;;
esac
# Ensure '-R' works with outputs other than "out".
tarball="`guix pack -R -S /share=share groff:doc`"
(cd "$test_directory"; tar xvf "$tarball")