summaryrefslogtreecommitdiffstats
path: root/recipes-containers/vcontainer/files/vcontainer-preinit.sh
blob: 6f1b7e09f00d557ac7773dd9e33be37e49805205 (plain)
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
#!/bin/sh
# SPDX-FileCopyrightText: Copyright (C) 2025 Bruce Ashfield
#
# SPDX-License-Identifier: GPL-2.0-only
#
# vcontainer-preinit.sh
# Minimal init for initramfs - mounts rootfs and does switch_root
#
# This script runs from the initramfs and:
# 1. Mounts essential filesystems
# 2. Finds and mounts the rootfs.img (squashfs, read-only)
# 3. Creates overlayfs with tmpfs for writes
# 4. Executes switch_root to the overlay root filesystem
#
# The real init (/init or /sbin/init on rootfs) then continues boot

# Mount essential filesystems first (needed to check cmdline)
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mount -t devtmpfs devtmpfs /dev

# Check for quiet mode (interactive)
QUIET=0
for param in $(cat /proc/cmdline 2>/dev/null); do
    case "$param" in
        docker_interactive=1) QUIET=1 ;;
    esac
done

log() {
    [ "$QUIET" = "0" ] && echo "$@"
}

log "=== vcontainer preinit (squashfs) ==="

# Wait for block devices to appear
log "Waiting for block devices..."
sleep 2

# Show available block devices
log "Block devices:"
[ "$QUIET" = "0" ] && ls -la /dev/vd* 2>/dev/null || log "No virtio block devices found"

# The rootfs.img is always the first virtio-blk device (/dev/vda)
# Additional devices (input, state) come after
ROOTFS_DEV="/dev/vda"

if [ ! -b "$ROOTFS_DEV" ]; then
    echo "ERROR: Rootfs device $ROOTFS_DEV not found!"
    echo "Available devices:"
    ls -la /dev/
    sleep 10
    reboot -f
fi

# Create mount points for overlay setup
mkdir -p /mnt/lower    # squashfs (read-only)
mkdir -p /mnt/upper    # tmpfs for overlay upper
mkdir -p /mnt/work     # tmpfs for overlay work
mkdir -p /mnt/root     # final overlayfs mount

# Mount squashfs read-only
log "Mounting squashfs rootfs from $ROOTFS_DEV..."

if ! mount -t squashfs -o ro "$ROOTFS_DEV" /mnt/lower; then
    # Fallback to ext4 for backwards compatibility
    log "squashfs mount failed, trying ext4..."
    if ! mount -t ext4 -o ro "$ROOTFS_DEV" /mnt/lower; then
        echo "ERROR: Failed to mount rootfs (tried squashfs and ext4)!"
        sleep 10
        reboot -f
    fi
    # ext4 fallback - just use it directly without overlay
    log "Using ext4 rootfs directly (no overlay)"
    mount --move /mnt/lower /mnt/root
else
    log "Squashfs mounted successfully"

    # Create tmpfs for overlay upper/work directories
    # Size is generous since container operations need temp space
    log "Creating tmpfs overlay..."
    mount -t tmpfs -o size=1G tmpfs /mnt/upper
    mkdir -p /mnt/upper/upper
    mkdir -p /mnt/upper/work

    # Create overlayfs combining squashfs (lower) + tmpfs (upper)
    log "Mounting overlayfs..."
    if ! mount -t overlay overlay -o lowerdir=/mnt/lower,upperdir=/mnt/upper/upper,workdir=/mnt/upper/work /mnt/root; then
        echo "ERROR: Failed to mount overlayfs!"
        sleep 10
        reboot -f
    fi

    log "Overlayfs mounted successfully"
fi

if [ "$QUIET" = "0" ]; then
    echo "Contents:"
    ls -la /mnt/root/
fi

# Verify init exists on rootfs
if [ ! -x /mnt/root/init ] && [ ! -x /mnt/root/sbin/init ]; then
    echo "ERROR: No init found on rootfs!"
    sleep 10
    reboot -f
fi

# Move filesystems to new root before switch_root
# This way they persist across switch_root and the new init doesn't need to remount
mkdir -p /mnt/root/proc /mnt/root/sys /mnt/root/dev
mount --move /proc /mnt/root/proc
mount --move /sys /mnt/root/sys
mount --move /dev /mnt/root/dev

# Switch to real root
# switch_root will:
# 1. Mount the new root
# 2. chroot into it
# 3. Execute the new init
# 4. Delete everything in the old initramfs
log "Switching to real root..."

if [ -x /mnt/root/init ]; then
    exec switch_root /mnt/root /init
elif [ -x /mnt/root/sbin/init ]; then
    exec switch_root /mnt/root /sbin/init
fi

# If we get here, switch_root failed
echo "ERROR: switch_root failed!"
sleep 10
reboot -f