{"id":15538742,"url":"https://github.com/nature40/pimod","last_synced_at":"2025-08-20T18:34:13.409Z","repository":{"id":34213778,"uuid":"167050136","full_name":"Nature40/pimod","owner":"Nature40","description":"Reconfigure Raspberry Pi images with an easy, Docker-like configuration file","archived":false,"fork":false,"pushed_at":"2023-09-15T08:30:25.000Z","size":136,"stargazers_count":112,"open_issues_count":6,"forks_count":19,"subscribers_count":9,"default_branch":"master","last_synced_at":"2024-04-26T16:31:50.503Z","etag":null,"topics":["automation","distribution","pi-image","pifile","raspberry-pi"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Nature40.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2019-01-22T19:01:36.000Z","updated_at":"2024-07-10T05:46:58.613Z","dependencies_parsed_at":"2024-01-05T20:47:11.693Z","dependency_job_id":"5a1a4fea-9864-4be1-825f-b1144ee94f4f","html_url":"https://github.com/Nature40/pimod","commit_stats":null,"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nature40%2Fpimod","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nature40%2Fpimod/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nature40%2Fpimod/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nature40%2Fpimod/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Nature40","download_url":"https://codeload.github.com/Nature40/pimod/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":230445927,"owners_count":18227060,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["automation","distribution","pi-image","pifile","raspberry-pi"],"created_at":"2024-10-02T12:05:48.519Z","updated_at":"2025-08-20T18:34:13.384Z","avatar_url":"https://github.com/Nature40.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# pimod\n[![CI: Tests](https://github.com/Nature40/pimod/actions/workflows/tests.yml/badge.svg)](https://github.com/Nature40/pimod/actions/workflows/tests.yml)\n[![CI: Shellcheck](https://github.com/Nature40/pimod/actions/workflows/shellcheck.yml/badge.svg)](https://github.com/Nature40/pimod/actions/workflows/shellcheck.yml)\n[![CI: Build and upload DockerHub image](https://github.com/Nature40/pimod/actions/workflows/dockerhub.yml/badge.svg)](https://github.com/Nature40/pimod/actions/workflows/dockerhub.yml)\n[![Docker Hub: Version](https://img.shields.io/docker/v/nature40/pimod?color=blue\u0026label=Docker%20Hub\u0026logo=docker\u0026logoColor=lightgrey\u0026sort=semver)](https://hub.docker.com/r/nature40/pimod/tags)\n\nReconfigure Raspberry Pi images with an easy, Docker-like configuration file.\n\n## About\npimod overtakes a given Raspberry Pi image file by mounting a copy and modifying it within a QEMU chroot.\nThis allows the execution of a Pi's ARM code on whatever target, e.g., a x86\\_64 host.\n\nTo ease the usability, a Docker-inspired recipe, called the Pifile, is used to instrument pimod.\n\n```\n# Example Pifile to create a customized version of the Raspberry Pi OS Lite\n\n# Based on a remote image, which will be cached locally, create the altered raspi_example.img file\nFROM https://downloads.raspberrypi.org/raspios_lite_arm64/images/raspios_lite_arm64-2023-02-22/2023-02-21-raspios-bullseye-arm64-lite.img.xz\nTO rapsi_example.img\n\n# Increase the image by 100 MB\nPUMP 100M\n\n# Install an ssh key from local sources\nRUN mkdir -p /home/pi/.ssh\nINSTALL id_rsa.pub /home/pi/.ssh/authorized_keys\n\n# Enable the serial console and SSH\nRUN raspi-config nonint do_serial 0\nRUN raspi-config nonint do_ssh 0\n\n# Install the important cowsay util\nRUN apt-get update\nRUN apt-get install -y cowsay\n```\n\n## Installation, Usage\n```\nUsage: pimod.sh [Options] Pifile\n\nOptions:\n  -c --cache DEST   Define cache location.\n  -d --debug        Debug on failure; run an interactive shell before tear down.\n  -h --help         Print this help message.\n  -r --resolv TYPE  Specify which /etc/resolv.conf file to use for networking.\n                    By default, TYPE \"auto\" is used, which prefers an already\n                    existing resolv.conf, only to be replaced by the host's if\n                    missing.\n                    TYPE \"guest\" never mounts the host's file within the guest,\n                    even when such a file is absent within the image.\n                    TYPE \"host\" always uses the host's file within the guest.\n                    Be aware that when run within Docker, the host's file might\n                    be Docker's resolv.conf file.\n  -t --trace        Trace each executed command for debugging.\n```\n\n### Docker\n#### Getting or Building the Docker Image\nThere are pre-built images available on [Docker Hub](https://hub.docker.com/r/nature40/pimod):\n\n```sh\ndocker pull nature40/pimod\n```\n\nAlternatively, you can simply build the image yourself locally.\nThis is essential for development, among other things:\n\n```sh\ngit clone https://github.com/Nature40/pimod.git\ncd pimod\ndocker build -t nature40/pimod .\n```\n\n#### Using the Docker Image\nAfterwards, the Docker image can either be used by `docker` or `docker compose`:\n\n```sh\n# Using Docker:\ndocker run --rm --privileged -v $PWD:/pimod nature40/pimod pimod.sh examples/RPi-OpenWRT.Pifile\n\n# Using Docker Compose:\ndocker compose run nature40/pimod pimod.sh examples/RPi-OpenWRT.Pifile\n```\n\n### Debian\nOf course, Docker isn't really necessary and pimod can also be used on, e.g., a Debian directly:\n\n```sh\nsudo apt-get install \\\n  binfmt-support \\\n  fdisk \\\n  file \\\n  kpartx \\\n  lsof \\\n  p7zip-full \\\n  qemu-user-static \\\n  unzip \\\n  wget \\\n  xz-utils \\\n  units\n\nsudo ./pimod.sh Pifile\n```\n\n### GitHub Actions\nPimod can also be used as a GitHub Action and is available on the [marketplace](https://github.com/marketplace/actions/run-pimod).\n\n```yml\nname: tests\non: push\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v3\n        with:\n          submodules: recursive\n      - name: Run pimod OpenWRT example\n        uses: Natur40/pimod@master\n        with:\n          pifile: examples/RPi-OpenWRT.Pifile\n```\n\n## Pifile\nThe Pifile contains commands to modify the image.\n\nThose commands are grouped in stages which pimod executes in their corresponding order.\n\n- First, all _setup stage_ commands are being executed to download the base image and configure the output.\n- The _prepare stage_ follows which pre-flight commands, e.g., resizing the output image.\n- The action happens in the _chroot stage_ where the QEMU chroot is built, commands are executed within, files are copied and so on.\n- Finally, the _postprocess stage_ might clean up some things.\n\nHowever, as the Pifile being just a Bash script by itself and the commands are functions, which are loaded in different stages, Bash scripting is possible within the Pifile to some extend.\n\nMore internals are documented in our [our scientific paper](https://jonashoechst.de/assets/papers/hoechst2020pimod.pdf).\nIf you stumble upon details there that you think belong in this README, feel free to create an issue or pull request.\n\n### Example\n```\n$ cat Upgrade.Pifile\nFROM 2018-11-13-raspbian-stretch-lite.img\n\nPUMP 100M\n\nRUN raspi-config nonint do_serial 0\n\nRUN apt-get update\nRUN bash -c 'DEBIAN_FRONTEND=noninteractive apt-get -y dist-upgrade'\nRUN apt-get install -y sl\n\n# The Upgrade.Pifile will create, called by the following command, a new\n# Upgrade.img image based on the given Raspbian image. This image's size is\n# increased about 100MB, has an enabled UART/serial output, the latest software\n# and sl installed.\n$ sudo ./pimod.sh Upgrade.Pifile\n\n# Write the new image to a SD card present at /dev/sdc.\n$ dd if=Upgrade.img of=/dev/sdc bs=4M status=progress\n```\n\nFurther and more expressive examples are available in this repository's `./example` directory.\nPlease take a look and feel free to submit your own examples if they are covering a current blind spot.\n\n### Commands\n#### Stage independent\n##### `INCLUDE PATH_TO_PIFILE`\n`INCLUDE` includes the provided Pifile in the current one for modularity and re-use.\nThe included file _has_ to have a `.Pifile` extension which need not be specified.\n\n#### 1. Setup Stage\n##### `FROM PATH_TO_IMAGE [PARTITION_NO]`, `FROM URL [PARTITION_NO]`\n`FROM` sets the `SOURCE_IMG` variable to a target.\nThis might be a local file or a remote URL, which will be downloaded.\nThis file will become the base for the new image.\n\nBy default, the Raspberry Pi's default partition number 2 will be used, but can be altered for other targets.\n\n##### `TO PATH_TO_IMAGE`\n`TO` sets the `DEST_IMG` variable to the given file.\nThis file will contain the new image.\nExisting files will be overridden.\n\nInstead of calling `TO`, the Pifile's filename can also indicate the output file, if the Pifile ends with *\".Pifile\"*.\nThe part before this suffix will be the new `DEST_IMG`.\n\nIf neither `TO` is called nor the Pifile indicates the output, `DEST_IMG` will default to *rpi.img* in the source file's directory.\n\n##### `INPLACE FROM_ARGS...`\n`INPLACE` does not create a copy of the image, but performs all further operations on the given image.\nThis is an alternative to `FROM` and `TO`.\n\n#### 2. Prepare Stage\n##### `PUMP SIZE`\n`PUMP` increases the image's size about the given amount (suffixes K, M, G are allowed).\n\n##### `ADDPART SIZE PTYPE FS`\n`PUMP` appends a partition of the size (suffixes K, M, G are allowed) using a partion type and file system (ext4, exfat, ...).\n\n#### 3. Chroot Stage\n##### `INSTALL \u003cMODE\u003e SOURCE DEST`\n`INSTALL` installs a given file or directory into the destination in the image.\nThe optionally permission mode (*chmod*) can be set as the first parameter.\n\n##### `EXTRACT SOURCE DEST`\n`EXTRACT` copies a given file or directory from the image to the destination.\n\n##### `PATH /my/guest/path`\n`PATH` adds the given path to an overlaying PATH variable, used within the `RUN` command.\n\n##### `WORKDIR /my/guest/path`\n`WORKDIR` sets the working directory within the image.\n\n##### `ENV KEY [VALUE]`\n`ENV` either sets or unsets an environment variable to be used within the image.\nIf two parameters are given, the first is the key and the second the value.\nIf one parameter is given, the environment variable will be removed.\n\nAn environment variable can be either used via `$VAR` within another sub-shell (`sh -c 'echo $VAR'`) or substituted beforehand via `@@VAR@@`.\n\n```\nENV FOO BAR\n\nRUN sh -c 'echo FOO = $FOO'   # FOO = BAR - substituted within a sh in the image\nRUN echo FOO = @@FOO@@        # FOO = BAR - substituted beforehand via pimod\n\nENV FOO\n```\n\n##### `RUN CMD [PARAMS...]`\n`RUN` executes a command in the chrooted image based on QEMU user emulation.\n\nCaveat: because the Pifile is just a Bash script, pipes do not work as one might suspect.\nA possible workaround could be the usage of `bash -c`:\n\n```\nRUN bash -c 'hexdump /dev/urandom | head'\n```\n\n##### `HOST CMD [PARAMS...]`\n`HOST` executed a command on the local host and can be used to prepare files, cross-compile software, etc.\n\n### Pifile Extensions\nBecause the *Pifile* is just a Bash script, some ~~dirty~~ brilliant hacks and extensions are possible.\n\n#### Bulk execution\nSub shells can be used with the `RUN` command.\n\n```sh\nRUN sh -c '\napt-get update\nDEBIAN_FRONTEND=noninteractive apt-get -y dist-upgrade\napt-get install -y sl\n'\n```\n\n#### Inplace Files\nHere documents can also be used to create files inside of the guest system, e.g., by using `tee` or `dd`.\n\n```bash\nRUN tee /bin/example.sh \u003c\u003cEOF\n#!/bin/sh\n\necho \"Example output.\"\nEOF\n```\n\n## Scientific Usage \u0026 Citation\nIf you happen to use pimod in a scientific project, we would very much appreciate if you cited [our scientific paper](https://jonashoechst.de/assets/papers/hoechst2020pimod.pdf):\n\n```bibtex\n@inproceedings{hoechst2020pimod,\n  author = {{Höchst}, Jonas and Penning, Alvar and Lampe, Patrick and Freisleben, Bernd},\n  title = {{PIMOD: A Tool for Configuring Single-Board Computer Operating System Images}},\n  booktitle = {{2020 IEEE Global Humanitarian Technology Conference (GHTC 2020)}},\n  address = {Seattle, USA},\n  days = {29},\n  month = oct,\n  year = {2020},\n  keywords = {Single-Board Computer; Operating System Image; System Provisioning},\n}\n```\n\n## Notable Mentions\n- [Debian Wiki, qemu-user-static](https://wiki.debian.org/RaspberryPi/qemu-user-static)\n- [raspberry-pi-chroot-armv7-qemu.md](https://gist.github.com/jkullick/9b02c2061fbdf4a6c4e8a78f1312a689)\n- [chroot-to-pi.sh](https://gist.github.com/htruong/7df502fb60268eeee5bca21ef3e436eb)\n- [PiShrink](https://github.com/Drewsif/PiShrink)\n- [pi-bootstrap](https://github.com/aniongithub/pi-bootstrap)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnature40%2Fpimod","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnature40%2Fpimod","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnature40%2Fpimod/lists"}