1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
|
#!/bin/sh
# SPDX-FileCopyrightText: Copyright (C) 2025 Bruce Ashfield
#
# SPDX-License-Identifier: GPL-2.0-only
#
# vpdmn-init.sh
# Init script for vpdmn: execute arbitrary podman commands in QEMU
#
# This script runs on a real ext4 filesystem after switch_root from initramfs.
# The preinit script mounted /dev/vda (rootfs.img) and did switch_root to us.
#
# Drive layout (rootfs.img is always /dev/vda, mounted as /):
# /dev/vda = rootfs.img (this script runs from here, mounted as /)
# /dev/vdb = input disk (optional, OCI/tar/dir data)
# /dev/vdc = state disk (optional, persistent Podman storage)
#
# Kernel parameters:
# podman_cmd=<base64> Base64-encoded podman command + args
# podman_input=<type> Input type: none, oci, tar, dir (default: none)
# podman_output=<type> Output type: text, tar, storage (default: text)
# podman_state=<type> State type: none, disk (default: none)
# podman_network=1 Enable networking (configure eth0, DNS)
#
# Version: 1.1.0
#
# Note: Podman is daemonless - no containerd/dockerd required!
# Set runtime-specific parameters before sourcing common code
VCONTAINER_RUNTIME_NAME="vpdmn"
VCONTAINER_RUNTIME_CMD="podman"
VCONTAINER_RUNTIME_PREFIX="podman"
VCONTAINER_STATE_DIR="/var/lib/containers/storage"
VCONTAINER_SHARE_NAME="vpdmn_share"
VCONTAINER_VERSION="1.1.0"
# Source common init functions
# When installed as /init, common file is at /vcontainer-init-common.sh
. /vcontainer-init-common.sh
# ============================================================================
# Podman-Specific Functions
# ============================================================================
setup_podman_environment() {
# Podman needs XDG_RUNTIME_DIR
export XDG_RUNTIME_DIR="/run/user/0"
mkdir -p "$XDG_RUNTIME_DIR"
chmod 700 "$XDG_RUNTIME_DIR"
}
setup_podman_mounts() {
# Podman needs /dev/shm
mkdir -p /dev/shm
mount -t tmpfs tmpfs /dev/shm
# Mount /var/volatile for Yocto's volatile symlinks (/var/tmp -> volatile/tmp, etc.)
mkdir -p /var/volatile
mount -t tmpfs tmpfs /var/volatile
mkdir -p /var/volatile/tmp /var/volatile/log /var/volatile/run /var/volatile/cache
# Also mount /var/cache directly (not a symlink)
mount -t tmpfs tmpfs /var/cache
}
setup_podman_storage() {
mkdir -p /run/lock
# /var/lib/containers exists in rootfs.img (read-only), mount tmpfs over it
mount -t tmpfs tmpfs /var/lib/containers
mkdir -p /var/lib/containers/storage
# Handle Podman storage
if [ -n "$STATE_DISK" ] && [ -b "$STATE_DISK" ]; then
log "Mounting state disk $STATE_DISK as /var/lib/containers/storage..."
if mount -t ext4 "$STATE_DISK" /var/lib/containers/storage 2>&1; then
log "SUCCESS: Mounted $STATE_DISK as Podman storage"
log "Podman storage contents:"
[ "$QUIET_BOOT" = "0" ] && ls -la /var/lib/containers/storage/ 2>/dev/null || log "(empty)"
else
log "WARNING: Failed to mount state disk, using tmpfs fallback"
RUNTIME_STATE="none"
fi
else
log "Using tmpfs for Podman storage (ephemeral)..."
fi
}
verify_podman() {
# Podman is daemonless - just verify it's available
if [ -x "/usr/bin/podman" ]; then
log "Podman available: $(podman --version 2>/dev/null || echo 'version unknown')"
else
echo "===ERROR==="
echo "Podman not found at /usr/bin/podman"
sleep 2
reboot -f
fi
}
# Podman is daemonless - nothing to stop
stop_runtime_daemons() {
:
}
handle_storage_output() {
# Export entire podman storage
# Tar from inside /var/lib/containers/storage so paths are vfs-images/... directly
echo "Packaging Podman storage..."
if ! cd /var/lib/containers/storage; then
echo "===ERROR==="
echo "Failed to cd to /var/lib/containers/storage"
echo "Contents of /var/lib/containers:"
ls -la /var/lib/containers/ 2>&1 || echo "(not found)"
poweroff -f
exit 1
fi
tar -cf /tmp/storage.tar .
STORAGE_SIZE=$(stat -c%s /tmp/storage.tar 2>/dev/null || echo "0")
echo "Storage size: $STORAGE_SIZE bytes"
if [ "$STORAGE_SIZE" -gt 1000 ]; then
dmesg -n 1
echo "===STORAGE_START==="
base64 /tmp/storage.tar
echo "===STORAGE_END==="
echo "===EXIT_CODE=$EXEC_EXIT_CODE==="
else
echo "===ERROR==="
echo "Storage too small"
fi
}
# ============================================================================
# Main
# ============================================================================
# Initialize base environment
setup_base_environment
setup_podman_environment
mount_base_filesystems
# Check for quiet boot mode
check_quiet_boot
log "=== vpdmn Init ==="
log "Version: $VCONTAINER_VERSION"
# Mount tmpfs directories and Podman-specific mounts
mount_tmpfs_dirs
setup_podman_mounts
setup_cgroups
# Parse kernel command line
parse_cmdline
# Detect and configure disks
detect_disks
# Set up Podman storage (Podman-specific)
setup_podman_storage
# Mount input disk
mount_input_disk
# Configure networking
configure_networking
# Verify podman is available (no daemon to start)
verify_podman
# Handle daemon mode or single command execution
if [ "$RUNTIME_DAEMON" = "1" ]; then
run_daemon_mode
else
prepare_input_path
execute_command
fi
# Graceful shutdown
graceful_shutdown
|