stages: Add org.osbuild.write-device stage

This stage writes a file to a device using dd. This is a
rewrite/backport of one of the stages in osbuild-auto.

The osbuild-auto stage is used in automotive-image-builder to write
the aboot image to the "boot_a" partition, to allow android boot
systems to boot. We will want similar functionallity in
bootc-image-builder, so it is important to upstream this.

Signed-off-by: Alexander Larsson <alexl@redhat.com>
This commit is contained in:
Alexander Larsson 2025-06-17 11:45:21 +02:00 committed by Michael Vogt
parent aac3c8b359
commit 30ca57de2c
2 changed files with 88 additions and 0 deletions

49
stages/org.osbuild.write-device Executable file
View file

@ -0,0 +1,49 @@
#!/usr/bin/python3
"""
Write to device
"""
import fcntl
import os
import struct
import subprocess
import sys
import osbuild.api
from osbuild.util import parsing
def blksize(device_path):
req = 0x80081272 # BLKGETSIZE64, result is bytes as unsigned 64-bit integer (uint64)
buf = b' ' * 8
fmt = 'L'
with open(device_path, "rb") as dev:
buf = fcntl.ioctl(dev.fileno(), req, buf)
return struct.unpack(fmt, buf)[0]
def main(args, devices, options):
src = parsing.parse_location(options.get("from"), args)
device = devices["device"]["path"]
src_size = os.path.getsize(src)
print(f"src: '{src}' src_size: {src_size}")
device_size = blksize(device)
print(f"device: '{device}' device_size: {device_size}")
if src_size > device_size:
raise ValueError(
f"File too large ({src_size / (1024 * 1024):.1f} mb) for device ({device_size / (1024 * 1024):.1f} mb)")
cmd = ["dd", f"if={src}", f"of={device}", "status=progress", "conv=fsync"]
print("Running {cmd}")
subprocess.run(cmd, check=True)
return 0
if __name__ == '__main__':
_args = osbuild.api.arguments()
r = main(_args, _args["devices"], _args["options"])
sys.exit(r)

View file

@ -0,0 +1,39 @@
{
"summary": "Write a file to a device",
"description": [
"This allows writing a file to a raw device. This is useful for example",
"to write bootloader or firmware files to custom partitions."
],
"schema_2": {
"devices": {
"type": "object",
"additionalProperties": true,
"required": [
"device"
],
"properties": {
"device": {
"type": "object",
"additionalProperties": true
}
}
},
"inputs": {
"type": "object",
"additionalProperties": true
},
"options": {
"additionalProperties": false,
"required": [
"from"
],
"properties": {
"from": {
"type": "string",
"description": "The source",
"pattern": "^input:\\/\\/[^\\/]+\\/"
}
}
}
}
}