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'.master
parent
80963744a2
commit
fde2aec3f4
|
@ -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
|
@dfn{user namespaces} in the kernel Linux; when passed
|
||||||
@emph{twice}@footnote{Here's a trick to memorize it: @code{-RR}, which adds
|
@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
|
PRoot support, can be thought of as the abbreviation of ``Really
|
||||||
Relocatable''. Neat, isn't it?}, relocatable binaries fall to back to PRoot
|
Relocatable''. Neat, isn't it?}, relocatable binaries fall to back to
|
||||||
if user namespaces are unavailable, and essentially work anywhere---see below
|
other techniques if user namespaces are unavailable, and essentially
|
||||||
for the implications.
|
work anywhere---see below for the implications.
|
||||||
|
|
||||||
For example, if you create a pack containing Bash with:
|
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
|
To produce relocatable binaries that work even in the absence of user
|
||||||
namespaces, pass @option{--relocatable} or @option{-R} @emph{twice}. In that
|
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
|
case, binaries will try user namespace support and fall back to another
|
||||||
namespaces are not supported.
|
@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
|
support for file system virtualization. It achieves that by using the
|
||||||
@code{ptrace} system call on the running program. This approach has the
|
@code{ptrace} system call on the running program. This approach has the
|
||||||
advantage to work without requiring special kernel support, but it incurs
|
advantage to work without requiring special kernel support, but it incurs
|
||||||
run-time overhead every time a system call is made.
|
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
|
@end quotation
|
||||||
|
|
||||||
@cindex entry point, for Docker images
|
@cindex entry point, for Docker images
|
||||||
|
|
|
@ -336,6 +336,71 @@ exec_with_proot (const char *store, int argc, char *argv[])
|
||||||
|
|
||||||
#endif
|
#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
|
int
|
||||||
main (int argc, char *argv[])
|
main (int argc, char *argv[])
|
||||||
|
@ -362,22 +427,17 @@ main (int argc, char *argv[])
|
||||||
if (strcmp (store, "@STORE_DIRECTORY@") != 0
|
if (strcmp (store, "@STORE_DIRECTORY@") != 0
|
||||||
&& lstat ("@WRAPPED_PROGRAM@", &statbuf) != 0)
|
&& lstat ("@WRAPPED_PROGRAM@", &statbuf) != 0)
|
||||||
{
|
{
|
||||||
/* Buffer stderr so that nothing's displayed if 'exec_in_user_namespace'
|
const struct engine *engine = execution_engine ();
|
||||||
fails but 'exec_with_proot' works. */
|
engine->exec (store, argc, argv);
|
||||||
static char stderr_buffer[4096];
|
|
||||||
setvbuf (stderr, stderr_buffer, _IOFBF, sizeof stderr_buffer);
|
|
||||||
|
|
||||||
exec_in_user_namespace (store, argc, argv);
|
/* If we reach this point, that's because ENGINE failed to do the
|
||||||
#ifdef PROOT_PROGRAM
|
job. */
|
||||||
exec_with_proot (store, argc, argv);
|
|
||||||
#else
|
|
||||||
fprintf (stderr, "\
|
fprintf (stderr, "\
|
||||||
This may be because \"user namespaces\" are not supported on this system.\n\
|
This may be because \"user namespaces\" are not supported on this system.\n\
|
||||||
Consequently, we cannot run '@WRAPPED_PROGRAM@',\n\
|
Consequently, we cannot run '@WRAPPED_PROGRAM@',\n\
|
||||||
unless you move it to the '@STORE_DIRECTORY@' directory.\n\
|
unless you move it to the '@STORE_DIRECTORY@' directory.\n\
|
||||||
\n\
|
\n\
|
||||||
Please refer to the 'guix pack' documentation for more information.\n");
|
Please refer to the 'guix pack' documentation for more information.\n");
|
||||||
#endif
|
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -84,6 +84,23 @@ fi
|
||||||
grep 'GNU sed' "$test_directory/output"
|
grep 'GNU sed' "$test_directory/output"
|
||||||
chmod -Rf +w "$test_directory"; rm -rf "$test_directory"/*
|
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".
|
# Ensure '-R' works with outputs other than "out".
|
||||||
tarball="`guix pack -R -S /share=share groff:doc`"
|
tarball="`guix pack -R -S /share=share groff:doc`"
|
||||||
(cd "$test_directory"; tar xvf "$tarball")
|
(cd "$test_directory"; tar xvf "$tarball")
|
||||||
|
|
Reference in New Issue