-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 2151cc6
Showing
8 changed files
with
1,557 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
name: Build and Publish to Docker | ||
|
||
on: | ||
schedule: | ||
- cron: "0 0 * * 0" | ||
push: | ||
branches: | ||
- "main" | ||
pull_request: | ||
branches: | ||
- "main" | ||
|
||
jobs: | ||
docker: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@v3 | ||
- name: Set up QEMU | ||
uses: docker/setup-qemu-action@v2 | ||
- name: Set up Docker Buildx | ||
uses: docker/setup-buildx-action@v2 | ||
- name: Login to Docker Hub | ||
uses: docker/login-action@v2 | ||
with: | ||
username: ${{ secrets.DOCKERHUB_USERNAME }} | ||
password: ${{ secrets.DOCKERHUB_TOKEN }} | ||
- name: Build and Push to Docker | ||
uses: docker/build-push-action@v3 | ||
with: | ||
context: . | ||
platforms: linux/amd64,linux/arm64 | ||
push: true | ||
tags: ${{ github.repository }}:latest | ||
- name: Update README on Docker | ||
uses: peter-evans/dockerhub-description@v3 | ||
with: | ||
username: ${{ secrets.DOCKERHUB_USERNAME }} | ||
password: ${{ secrets.DOCKERHUB_TOKEN }} | ||
repository: ${{ github.repository }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
FROM debian:stable-slim | ||
RUN apt-get update && apt-get install -y \ | ||
net-tools \ | ||
python3 \ | ||
python3-dask \ | ||
parted \ | ||
dosfstools \ | ||
rsync \ | ||
udev \ | ||
xz-utils \ | ||
&& apt-get clean \ | ||
&& rm -rf /var/lib/apt/lists/* | ||
RUN mkdir /tools | ||
COPY *.py /tools/ | ||
RUN chmod +x /tools/*.py |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
# pi-builder-toolbox | ||
|
||
The Toolbox image for [pi-builder](https://github.com/jmcombs/pi-builder) | ||
|
||
![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/jmcombs/pi-builder-toolbox/docker-publish.yml?logo=github) | ||
[![Docker Pulls](https://img.shields.io/docker/pulls/jmcombs/pi-builder-toolbox)](https://hub.docker.com/r/jmcombs/pi-builder-toolbox "Click to view the image on Docker Hub") | ||
[![Docker Stars](https://img.shields.io/docker/stars/jmcombs/pi-builder-toolbox)](https://hub.docker.com/r/jmcombs/pi-builder-toolbox "Click to view the image on Docker Hub") | ||
[![Github Issues](https://img.shields.io/github/issues/jmcombs/pi-builder-toolbox)](https://github.com/jmcombs/pi-builder-toolbox/issues "Click to view or open issues") | ||
|
||
## About | ||
|
||
This container is based on [Debian](https://hub.docker.com/_/debian), is multi-arch (`AMD64` & `ARM64`), and contains all relevant Python modules and tools needed to support [pi-builder](https://github.com/jmcombs/pi-builder) for building Raspberry Pi images. | ||
|
||
> Note: This project started out as a fork of the [PiKVM](https://github.com/pikvm) [pi-builder](https://github.com/pikvm/pi-builder) project. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,192 @@ | ||
#!/usr/bin/env python3 | ||
# ========================================================================== # | ||
# # | ||
# install-binfmt - mount binfmt_misc and register extra handlers. # | ||
# # | ||
# Copyright (C) 2019-2023 Maxim Devaev <mdevaev@gmail.com> # | ||
# # | ||
# This program is free software: you can redistribute it and/or modify # | ||
# it under the terms of the GNU General Public License as published by # | ||
# the Free Software Foundation, either version 3 of the License, or # | ||
# (at your option) any later version. # | ||
# # | ||
# This program is distributed in the hope that it will be useful, # | ||
# but WITHOUT ANY WARRANTY; without even the implied warranty of # | ||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # | ||
# GNU General Public License for more details. # | ||
# # | ||
# You should have received a copy of the GNU General Public License # | ||
# along with this program. If not, see <https://www.gnu.org/licenses/>. # | ||
# # | ||
# ========================================================================== # | ||
|
||
import os | ||
import subprocess | ||
import dataclasses | ||
import argparse | ||
import logging | ||
import shutil | ||
|
||
@dataclasses.dataclass(frozen=True) | ||
class _Binfmt: | ||
""" | ||
Represents a binary format (binfmt) configuration. | ||
Attributes: | ||
name (str): The name of the binfmt. | ||
arch (str): The architecture of the binfmt. | ||
magic (str): The magic number pattern of the binfmt. | ||
mask (str): The mask pattern of the binfmt. | ||
""" | ||
name: str | ||
arch: str | ||
magic: str | ||
mask: str | ||
|
||
_BINFMT_DB = { | ||
binfmt.arch: binfmt | ||
for binfmt in [ | ||
_Binfmt( | ||
name="ARM", | ||
arch="arm", | ||
magic=r"\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00", | ||
mask=r"\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff", | ||
), | ||
_Binfmt( | ||
name="AArch64", | ||
arch="aarch64", | ||
magic=r"\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7\x00", | ||
mask=r"\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff", | ||
), | ||
] | ||
} | ||
|
||
_logger = logging.getLogger("install-binfmt") | ||
|
||
def _mount_binfmt(mount_path: str) -> None: | ||
""" | ||
Mounts binfmt_misc to the specified mount path. | ||
Args: | ||
mount_path (str): The path where binfmt_misc should be mounted. | ||
Raises: | ||
subprocess.CalledProcessError: If the mount command fails. | ||
""" | ||
_logger.info(":: Mounting binfmt_misc to %r ...", mount_path) | ||
subprocess.check_output(["mount", "binfmt_misc", "-t", "binfmt_misc", mount_path]) | ||
|
||
def _check_binfmt(mount_path: str, binfmt: _Binfmt, interpreter_path: str) -> bool: | ||
""" | ||
Checks if the specified binfmt configuration exists and matches the expected values. | ||
Args: | ||
mount_path (str): The path where binfmt_misc is mounted. | ||
binfmt (_Binfmt): The binfmt configuration to check. | ||
interpreter_path (str): The path to the interpreter associated with the binfmt. | ||
Returns: | ||
bool: True if the binfmt configuration exists and matches the expected values, False otherwise. | ||
Raises: | ||
RuntimeError: If an unknown binfmt configuration is found. | ||
""" | ||
_logger.info(":: Checking %s binfmt configuration ...", binfmt.name) | ||
|
||
binfmt_path = os.path.join(mount_path, binfmt.arch) | ||
if os.path.exists(binfmt_path): | ||
_logger.info(":: Found existent %s binfmt handler", binfmt.name) | ||
|
||
with open(binfmt_path) as binfmt_file: | ||
current_params: dict[str, str] = dict( | ||
(row.split(" ", 1) + [""])[:2] | ||
for row in filter(None, binfmt_file.read().split("\n")) | ||
) | ||
_logger.debug(":: Current configuration: %s", current_params) | ||
|
||
mismatch = "\n".join( | ||
f" - Current {name} {current!r} != expected {expected!r}" | ||
for (name, current, expected) in [ | ||
("magic", current_params.get("magic", "").replace("454c46", "ELF"), binfmt.magic.replace(r"\x", "")), | ||
("mask", current_params.get("mask", ""), binfmt.mask.replace(r"\x", "")), | ||
("interpreter", current_params.get("interpreter"), interpreter_path), | ||
] | ||
if current != expected | ||
) | ||
if mismatch: | ||
raise RuntimeError( | ||
f"Found unknown {binfmt.name} binfmt configuration:\n" | ||
f"{mismatch}\n" | ||
f" - Run 'echo -1 > {binfmt_path}' to disable this binfmt globally" | ||
) | ||
|
||
return True | ||
return False | ||
|
||
def _execute_command(command: str, *args: str) -> None: | ||
""" | ||
Executes the specified command with the given arguments. | ||
Args: | ||
command (str): The command to execute. | ||
args (str): The arguments to pass to the command. | ||
Raises: | ||
FileNotFoundError: If the executable for the command is not found. | ||
subprocess.CalledProcessError: If the command execution fails. | ||
""" | ||
executable_path = shutil.which(command) | ||
if executable_path is None: | ||
raise FileNotFoundError(f"Executable '{command}' not found.") | ||
subprocess.check_call([executable_path, *args]) | ||
|
||
def _install_binfmt(mount_path: str, binfmt: _Binfmt, interpreter_path: str) -> None: | ||
""" | ||
Installs the specified binfmt configuration. | ||
Args: | ||
mount_path (str): The path where binfmt_misc is mounted. | ||
binfmt (_Binfmt): The binfmt configuration to install. | ||
interpreter_path (str): The path to the interpreter associated with the binfmt. | ||
Raises: | ||
subprocess.CalledProcessError: If the register command fails. | ||
""" | ||
_logger.info(":: Installing %s binfmt as %r ...", binfmt.name, interpreter_path) | ||
with open(os.path.join(mount_path, "register"), "w") as register_file: | ||
register_file.write(f":{binfmt.arch}:M::{binfmt.magic}:{binfmt.mask}:{interpreter_path}:") | ||
|
||
def main() -> None: | ||
""" | ||
The main entry point of the program. | ||
Parses command line arguments, mounts binfmt_misc if specified, checks and installs binfmt configurations. | ||
Raises: | ||
RuntimeError: If the user is not running the program as root. | ||
""" | ||
parser = argparse.ArgumentParser() | ||
parser.add_argument("--mount", action="store_true", help="Mount binfmt_misc") | ||
parser.add_argument("--binfmt-misc", default="/proc/sys/fs/binfmt_misc", help="Path to binfmt_misc") | ||
parser.add_argument("arch", choices=sorted(_BINFMT_DB)) | ||
parser.add_argument("interpreter") | ||
parser.add_argument("-d", "--debug", action="store_const", const=logging.DEBUG, dest="log_level") | ||
parser.set_defaults(log_level=logging.INFO) | ||
|
||
options = parser.parse_args() | ||
logging.basicConfig(level=options.log_level, format="%(message)s") | ||
|
||
if os.getuid() != 0: | ||
raise RuntimeError("You must be a root") | ||
|
||
if options.mount: | ||
_mount_binfmt(options.binfmt_misc) | ||
|
||
binfmt = _BINFMT_DB[options.arch] | ||
if not _check_binfmt(options.binfmt_misc, binfmt, options.interpreter): | ||
_install_binfmt(options.binfmt_misc, binfmt, options.interpreter) | ||
|
||
_logger.info(":: %s binfmt handler %r is ready", binfmt.name, options.interpreter) | ||
|
||
if __name__ == "__main__": | ||
main() |
Oops, something went wrong.