Skip to content

Commit

Permalink
[antlir] fallback to copy if binary resource in XAR is not executable
Browse files Browse the repository at this point in the history
Summary: Something must have changed about how XAR is packaged: S371398

Test Plan:
Using new cm entrypoint from stacked diff
```
❯ buck2 run 'fbcode//windtunnel/cogwheel/examples/example_multiplier:tw.cogwheel.examplemultiplier=publish'
```

Was printed a bunch of times
```
W 20231012 07:38:13.311 3800156 fs_utils.py:380 antlir.btrfsutil-bin is not executable
```

Reviewed By: sergeyfd

Differential Revision: D50224934

fbshipit-source-id: 48a35cefa78eac8057c46333afa323eccbf60320
  • Loading branch information
vmagro authored and facebook-github-bot committed Oct 12, 2023
1 parent bf6f178 commit f1892df
Showing 1 changed file with 32 additions and 31 deletions.
63 changes: 32 additions & 31 deletions antlir/fs_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -371,37 +371,38 @@ def resource(cls, package, name: str, *, exe: bool) -> Iterator["Path"]:
# Future: once the bug with the XAR `access` implementation
# is fixed (https://fburl.com/42s41c0g), this can just check
# for boolean equality.
if exe and not os.access(rsrc_in.name, os.X_OK):
raise RuntimeError(
f"{package}.{name} is not executable"
) # pragma: no cover
yield Path(rsrc_in.name).abspath()
else: # pragma: no cover
# The resource has no path, so we have to materialize it.
#
# This code path is not reached by our coverage harness,
# since resources in '@mode/dev will always have a real
# filesystem path. However, we get all the needed signal
# from running `test-fs-utils-path-resource-*' in
# `@mode/dev` and `@mode/opt'.
#
# Wrap in a temporary directory so we can `chmod 755` below.
with temp_dir() as td:
with open(td / name, "wb") as rsrc_out:
# We can't use `os.sendfile` because `rsrc_in` may
# not be backed by a real FD.
while True:
# Read 512KiB chunks to mask the syscall cost
chunk = rsrc_in.read(2**19)
if not chunk:
break
rsrc_out.write(chunk)
if exe:
# The temporary directory protects us from undesired
# access. The goal is to let both the current user
# and `root` execute this path, but nobody else.
os.chmod(td / name, 0o755)
yield td / name
if exe and os.access(rsrc_in.name, os.X_OK):
yield Path(rsrc_in.name).abspath()
return
else:
# why does this happen? who knows but we can make a copy of
# the binary that _is_ executable
log.warning(f"{package}.{name} is not executable")
# The resource has no path, so we have to materialize it.
#
# This code path is not reached by our coverage harness,
# since resources in '@mode/dev will always have a real
# filesystem path. However, we get all the needed signal
# from running `test-fs-utils-path-resource-*' in
# `@mode/dev` and `@mode/opt'.
#
# Wrap in a temporary directory so we can `chmod 755` below.
with temp_dir() as td:
with open(td / name, "wb") as rsrc_out:
# We can't use `os.sendfile` because `rsrc_in` may
# not be backed by a real FD.
while True:
# Read 512KiB chunks to mask the syscall cost
chunk = rsrc_in.read(2**19)
if not chunk:
break
rsrc_out.write(chunk)
if exe:
# The temporary directory protects us from undesired
# access. The goal is to let both the current user
# and `root` execute this path, but nobody else.
os.chmod(td / name, 0o755)
yield td / name

# Future: Consider if we actually want something like
# `relative_outside_base`, which is `.normpath().has_leading_dot_dot()`.
Expand Down

0 comments on commit f1892df

Please sign in to comment.