Skip to content
Snippets Groups Projects
Commit bfbe9c46 authored by Simon McVittie's avatar Simon McVittie
Browse files

pv-adverb: Allow setting the architecture of a module in the CLI


This will allow pv-wrap to translate a host `LD_PRELOAD` item like
`/usr/$LIB/libMangoHud.so` into a pair of `--ld-preload` options, each
looking like `--ld-preload=/usr/lib32/libMangoHud.so:abi=i386-linux-gnu`.

The only character that cannot appear in a `LD_PRELOAD` path entry is `:`,
so we're free to use that as our representation for extra options.
Instead of just appending the ABI tuple, use a key/value notation so
we can extend later if we need to.

Signed-off-by: default avatarSimon McVittie <smcv@collabora.com>
parent 198d1fd0
No related branches found
No related tags found
1 merge request!350pv-adverb: Improve LD_AUDIT, LD_PRELOAD handling
Pipeline #16419 passed
...@@ -18,8 +18,8 @@ pressure-vessel-adverb - wrap processes in various ways ...@@ -18,8 +18,8 @@ pressure-vessel-adverb - wrap processes in various ways
[**--[no-]exit-with-parent**] [**--[no-]exit-with-parent**]
[**--fd** *FD*...] [**--fd** *FD*...]
[**--[no-]generate-locales**] [**--[no-]generate-locales**]
[**--ld-audit** *MODULE*...] [**--ld-audit** *MODULE*[**:arch=***TUPLE*]...]
[**--ld-preload** *MODULE*...] [**--ld-preload** *MODULE*[**:**...]...]
[**--pass-fd** *FD*...] [**--pass-fd** *FD*...]
[**--shell** **none**|**after**|**fail**|**instead**] [**--shell** **none**|**after**|**fail**|**instead**]
[**--subreaper**] [**--subreaper**]
...@@ -70,15 +70,27 @@ exit status. ...@@ -70,15 +70,27 @@ exit status.
**LOCPATH** environment variable. **LOCPATH** environment variable.
**--no-generate-locales** disables this behaviour, and is the default. **--no-generate-locales** disables this behaviour, and is the default.
**--ld-audit** *MODULE* **--ld-audit** *MODULE*[**:arch=***TUPLE*]
: Add *MODULE* to **LD_AUDIT** before executing *COMMAND*. : Add *MODULE* to **LD_AUDIT** before executing *COMMAND*.
The optional *TUPLE* is the same as for **--ld-preload**, below.
**--ld-preload** *MODULE* **--ld-preload** *MODULE*[**:arch=***TUPLE*]
: Add *MODULE* to **LD_PRELOAD** before executing *COMMAND*. : Add *MODULE* to **LD_PRELOAD** before executing *COMMAND*.
Some adjustments may be performed to the provided *MODULE*, e.g.
multiple preloads of gameoverlayrenderer.so for different ABIs may be If the optional **:arch=***TUPLE* is given, the *MODULE* is only used for
joined together into a single path by leveraging the dynamic linker the given architecture, and is paired with other modules (if any) that
token expansion feature. share its basename; for example,
`/home/me/.steam/root/ubuntu12_32/gameoverlayrenderer.so:arch=i386-linux-gnu`
and
`/home/me/.steam/root/ubuntu12_64/gameoverlayrenderer.so:arch=x86_64-linux-gnu`
will be combined into a single **LD_PRELOAD** entry of the form
`/tmp/pressure-vessel-libs-123456/${PLATFORM}/gameoverlayrenderer.so`.
For a **LD_PRELOAD** module named `gameoverlayrenderer.so` in a directory
named `ubuntu12_32` or `ubuntu12_64`, the architecture is automatically
set to `i386-linux-gnu` or `x86_64-linux-gnu` respectively, if not
otherwise given. Other special-case behaviour might be added in future
if required.
**--lock-file** *FILENAME* **--lock-file** *FILENAME*
: Lock the file *FILENAME* according to the most recently seen : Lock the file *FILENAME* according to the most recently seen
......
...@@ -259,6 +259,51 @@ opt_ld_something (const char *option, ...@@ -259,6 +259,51 @@ opt_ld_something (const char *option,
GError **error) GError **error)
{ {
AdverbPreloadModule module = { NULL, 0, G_MAXSIZE }; AdverbPreloadModule module = { NULL, 0, G_MAXSIZE };
g_auto(GStrv) parts = NULL;
const char *architecture = NULL;
parts = g_strsplit (value, ":", 0);
if (parts[0] != NULL)
{
gsize i;
for (i = 1; parts[i] != NULL; i++)
{
if (g_str_has_prefix (parts[i], "abi="))
{
gsize abi;
architecture = parts[i] + strlen ("abi=");
for (abi = 0; abi < PV_N_SUPPORTED_ARCHITECTURES; abi++)
{
if (strcmp (architecture, pv_multiarch_details[abi].tuple) == 0)
{
module.abi_index = abi;
break;
}
}
if (module.abi_index == G_MAXSIZE)
{
g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
"Unsupported ABI %s",
architecture);
return FALSE;
}
}
else
{
g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
"Unexpected option in %s=\"%s\": %s",
option, value, parts[i]);
return FALSE;
}
}
value = parts[0];
}
if (opt_preload_modules == NULL) if (opt_preload_modules == NULL)
{ {
......
...@@ -80,6 +80,15 @@ class TestAdverb(BaseTest): ...@@ -80,6 +80,15 @@ class TestAdverb(BaseTest):
'--ld-preload=/nonexistent/libpreload.so', '--ld-preload=/nonexistent/libpreload.so',
'--ld-preload=/nonexistent/ubuntu12_32/gameoverlayrenderer.so', '--ld-preload=/nonexistent/ubuntu12_32/gameoverlayrenderer.so',
'--ld-preload=/nonexistent/ubuntu12_64/gameoverlayrenderer.so', '--ld-preload=/nonexistent/ubuntu12_64/gameoverlayrenderer.so',
('--ld-preload'
'=/nonexistent/lib32/libMangoHud.so'
':abi=i386-linux-gnu'),
('--ld-preload'
'=/nonexistent/lib64/libMangoHud.so'
':abi=x86_64-linux-gnu'),
('--ld-preload'
'=/nonexistent/lib64/64-bit-only.so'
':abi=x86_64-linux-gnu'),
'--', '--',
'sh', '-euc', 'sh', '-euc',
# The hard-coded i686 and xeon_phi here must match up with # The hard-coded i686 and xeon_phi here must match up with
...@@ -104,9 +113,9 @@ class TestAdverb(BaseTest): ...@@ -104,9 +113,9 @@ class TestAdverb(BaseTest):
xeon_phi="$(echo "$item" | xeon_phi="$(echo "$item" |
sed -e 's/[$]{PLATFORM}/xeon_phi/g')" sed -e 's/[$]{PLATFORM}/xeon_phi/g')"
printf "i686: symlink to " printf "i686: symlink to "
readlink "$i686" readlink "$i686" || echo "(nothing)"
printf "xeon_phi: symlink to " printf "xeon_phi: symlink to "
readlink "$xeon_phi" readlink "$xeon_phi" || echo "(nothing)"
;; ;;
(*) (*)
echo "literal $item" echo "literal $item"
...@@ -135,7 +144,11 @@ class TestAdverb(BaseTest): ...@@ -135,7 +144,11 @@ class TestAdverb(BaseTest):
lines[1]), lines[1]),
('LD_PRELOAD=/nonexistent/libpreload.so' ('LD_PRELOAD=/nonexistent/libpreload.so'
':/tmp/pressure-vessel-libs-XXXXXX/' ':/tmp/pressure-vessel-libs-XXXXXX/'
'${PLATFORM}/gameoverlayrenderer.so') '${PLATFORM}/gameoverlayrenderer.so'
':/tmp/pressure-vessel-libs-XXXXXX/'
'${PLATFORM}/libMangoHud.so'
':/tmp/pressure-vessel-libs-XXXXXX/'
'${PLATFORM}/64-bit-only.so')
) )
self.assertEqual(lines[2], 'literal /nonexistent/libpreload.so') self.assertEqual(lines[2], 'literal /nonexistent/libpreload.so')
self.assertEqual( self.assertEqual(
...@@ -147,6 +160,22 @@ class TestAdverb(BaseTest): ...@@ -147,6 +160,22 @@ class TestAdverb(BaseTest):
('xeon_phi: symlink to ' ('xeon_phi: symlink to '
'/nonexistent/ubuntu12_64/gameoverlayrenderer.so'), '/nonexistent/ubuntu12_64/gameoverlayrenderer.so'),
) )
self.assertEqual(
lines[5],
'i686: symlink to /nonexistent/lib32/libMangoHud.so',
)
self.assertEqual(
lines[6],
'xeon_phi: symlink to /nonexistent/lib64/libMangoHud.so',
)
self.assertEqual(
lines[7],
'i686: symlink to (nothing)',
)
self.assertEqual(
lines[8],
'xeon_phi: symlink to /nonexistent/lib64/64-bit-only.so',
)
def test_stdio_passthrough(self) -> None: def test_stdio_passthrough(self) -> None:
proc = subprocess.Popen( proc = subprocess.Popen(
...@@ -217,6 +246,9 @@ class TestAdverb(BaseTest): ...@@ -217,6 +246,9 @@ class TestAdverb(BaseTest):
def test_wrong_options(self) -> None: def test_wrong_options(self) -> None:
for option in ( for option in (
'--an-unknown-option', '--an-unknown-option',
'--ld-preload=/nonexistent/libfoo.so:abi=hal9000-movieos',
'--ld-preload=/nonexistent/libfoo.so:abi=i386-linux-gnu:foo',
'--ld-preload=/nonexistent/libfoo.so:foo=bar',
'--pass-fd=-1', '--pass-fd=-1',
'--shell=wrong', '--shell=wrong',
'--terminal=wrong', '--terminal=wrong',
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment