initscript.sh 6.72 KB
Newer Older
Martin Roukala's avatar
Martin Roukala committed
1
2
#!/bin/busybox sh

3
4
set -eux

Martin Roukala's avatar
Martin Roukala committed
5
6
7
8
MODULES_PATH=/usr_mods
CONTAINER_MOUNTPOINT=/container
CONTAINER_ROOTFS="$CONTAINER_MOUNTPOINT/rootfs"
CONTAINER_CACHE="$CONTAINER_MOUNTPOINT/cache"
9
CACHE_PARTITION_LABEL="B2C_CACHE"
Martin Roukala's avatar
Martin Roukala committed
10
11

function log {
12
    { set +x; } 2>/dev/null
Martin Roukala's avatar
Martin Roukala committed
13
    echo -e "[$(busybox cut -d ' ' -f1 /proc/uptime)]: $*\n"
14
    set -x
Martin Roukala's avatar
Martin Roukala committed
15
16
17
18
}

function setup_busybox {
    for cmd in `busybox --list`; do
19
        [ -f "/bin/$cmd" ] || busybox ln -s /bin/busybox /bin/$cmd
Martin Roukala's avatar
Martin Roukala committed
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
    done
    log "Busybox setup: DONE"
}

function setup_mounts {
    mount -t proc none /proc
    mount -t sysfs none /sys
    mount -t devtmpfs none /dev
    mkdir -p /dev/pts
    mount -t devpts devpts /dev/pts

    # Mount cgroups
    mount -t cgroup2 none /sys/fs/cgroup
    cd /sys/fs/cgroup/
    for sys in $(awk '!/^#/ { if ($4 == 1) print $1 }' /proc/cgroups); do
        mkdir -p $sys
        if ! mount -n -t cgroup -o $sys cgroup $sys; then
            rmdir $sys || true
        fi
    done

    log "Mounts setup: DONE"
}

function setup_env {
    export HOME=/root
}

function parse_cmdline {
    cmdline=$(busybox cat /proc/cmdline)

    # TODO: add a parameter to download a volume with firmwares and modules
    for param in $(echo "$cmdline" | busybox tr ' ' '\n'); do
        value="${param#*=}"
        case $param in
            b2c.insmods=*)
                ARG_MODULES=$value
                ;;
58
59
60
            b2c.cache_device=*)
                ARG_CACHE_DEVICE=$value
                ;;
Martin Roukala's avatar
Martin Roukala committed
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
            b2c.container=*)
                ARG_CONTAINER=$value
                ;;
        esac
    done
}

function load_modules {
    for mod_name in `echo "$1" | busybox tr ',' '\n'`; do
        path="$MODULES_PATH/$mod_name"
        echo "Load the module: $path"
        insmod "$path"
    done

    log "Loading requested modules: DONE"
}

function connect {
    ip link set eth0 up
    udhcpc -i eth0 -s /etc/uhdcp-default.sh -T 1

    log "Getting IP: DONE"
}

function find_container_partition {
86
    dev_name=`blkid | grep "LABEL=\"$CACHE_PARTITION_LABEL\"" | head -n 1 | cut -d ':' -f 1`
Martin Roukala's avatar
Martin Roukala committed
87
88
89
90
91
92
93
94
    if [ -n "$dev_name" ]; then
        echo $dev_name
        return 0
    else
        return 1
    fi
}

95
96
97
98
function format_disk {
    if [ -n "$1" ]; then
        parted --script $1 mklabel gpt
        parted --script $1 mkpart primary ext4 2048s 100%
Martin Roukala's avatar
Martin Roukala committed
99

100
        container_partition=`lsblk -no PATH $1 | tail -n -1`
101
        mkfs.ext4 -F -L "$CACHE_PARTITION_LABEL" "$container_partition"
Martin Roukala's avatar
Martin Roukala committed
102

103
        return $?
Martin Roukala's avatar
Martin Roukala committed
104
105
106
107
108
    fi

    return 1
}

109
function find_or_create_cache_partition {
Martin Roukala's avatar
Martin Roukala committed
110
111
112
    # See if we have an existing block device that would work
    container_partition=`find_container_partition` && return 0

113
114
115
116
    # Find a suitable disk
    sr_disks_majors=`grep ' sr' /proc/devices | sed "s/^[ \t]*//" | cut -d ' ' -f 1 | tr '\n' ',' | sed 's/,$//'`
    disk=`lsblk -ndlfp -e "$sr_disks_majors" | head -n 1`

117
118
    log "No existing cache partition found on this machine, create one from the disk $disk"

Martin Roukala's avatar
Martin Roukala committed
119
    # Find a disk, partition it, then format it as ext4
120
    format_disk $disk || return 1
Martin Roukala's avatar
Martin Roukala committed
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
    return 0
}

function try_to_use_cache_device {
    # Check if the parameter is a path to a file
    if [ -f "$ARG_CACHE_DEVICE" ]; then
        log "The caching parameter '$ARG_CACHE_DEVICE' is neither 'none', 'auto', or a path to a block device. Defaulting to 'none'"
        return 0
    fi

    # $ARG_CACHE_DEVICE has to be a path to a drive
    # NOTE: Pay attention to the space after $ARG_CACHE_DEVICE, as it
    # makes sure that we don't accidentally match /dev/sda1 when asking
    # for /dev/sda.
    blk_dev=`lsblk -rpno PATH,TYPE,LABEL | grep "$ARG_CACHE_DEVICE "`
    if [ -z "$blk_dev" ]; then
        log "Error: The device '$ARG_CACHE_DEVICE' is neither a block device, nor a partition. Defaulting to no caching."
        return 1
    fi

    path=$(echo "$blk_dev" | cut -d ' ' -f 1)
    type=$(echo "$blk_dev" | cut -d ' ' -f 2)
    label=$(echo "$blk_dev" | cut -d ' ' -f 3)
    case $type in
        part)
            container_partition="$path"
            if [ -z "$label" ]; then
                log "Formating the partition $container_partition"
                mkfs.ext4 -F -L "$CACHE_PARTITION_LABEL" "$container_partition"
                return $?
            fi
            ;;

        disk)
            # Look for the first partition from the drive $1, that has the right cache
            container_partition=`lsblk -no PATH,LABEL $path | grep "$CACHE_PARTITION_LABEL" | cut -d ' ' -f 1 | head -n 1`
            if [ -n "$container_partition" ]; then
                return 0
            else
                log "No existing cache partition on the drive $path, recreate the partition table and format a partition"
                format_disk $path
                return $?
            fi
            ;;
    esac

    return 0
Martin Roukala's avatar
Martin Roukala committed
169
170
}

171
function mount_cache_partition {
Martin Roukala's avatar
Martin Roukala committed
172
173
    mkdir "$CONTAINER_MOUNTPOINT"

174
    # Find a suitable cache partition
Martin Roukala's avatar
Martin Roukala committed
175
    container_partition=""
176
177
178
179
180
181
    case $ARG_CACHE_DEVICE in
        none)
            log "Do not use a partition cache"
            return 0
            ;;
        auto)
182
            find_or_create_cache_partition || return 0
183
184
            ;;
        *)
185
            try_to_use_cache_device "$ARG_CACHE_DEVICE" || return 0
186
187
188
189
190
            ;;
    esac

    log "Selected the partition $container_partition as a cache"

191
192
193
    status="DONE"
    mount "$container_partition" "$CONTAINER_MOUNTPOINT" || status="FAILED"
    log "Mounting the partition $container_partition to $CONTAINER_MOUNTPOINT: $status"
Martin Roukala's avatar
Martin Roukala committed
194

195
    return 0
Martin Roukala's avatar
Martin Roukala committed
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
}

function setup_container_runtime {
    # HACK: I could not find a way to change the right parameter in podman's
    # config, so make a symlink for now
    [ -d "$CONTAINER_CACHE" ] || mkdir "$CONTAINER_CACHE"
    ln -s "$CONTAINER_CACHE" /var/tmp

    # Set some configuration files
    touch /etc/hosts
    echo "root:x:0:0:root:/root:/bin/sh" > /etc/passwd
    echo "containers:165536:65537" > /etc/subuid
    echo "containers:165536:65537" > /etc/subgid

    log "Container runtime setup: DONE"
}

function start_container {
214
    podman run --rm --privileged --network=host --runtime /bin/crun-no-pivot $@
Martin Roukala's avatar
Martin Roukala committed
215
216
}

217
218
219
# Do not print all the early commands
set +x

Martin Roukala's avatar
Martin Roukala committed
220
221
222
223
224
# Initial setup
setup_busybox
#setup_mounts  # To be continued to so we could boot without any go commands
setup_env

225
# Parse the kernel command line, in search of the b2c parameters
Martin Roukala's avatar
Martin Roukala committed
226
227
ARG_MODULES=""
ARG_CONTAINER=""
228
ARG_CACHE_DEVICE="none"
Martin Roukala's avatar
Martin Roukala committed
229
230
parse_cmdline

231
232
233
# Now that the early boot is over, let's log every command executed
set -x

234
# Load the user-requested modules
Martin Roukala's avatar
Martin Roukala committed
235
load_modules $ARG_MODULES
236
237

# Connect to the network, now that the modules are loaded
Martin Roukala's avatar
Martin Roukala committed
238
connect
239
240
241
242
243
244

# Mount the cache partition
mount_cache_partition

# Start the container
setup_container_runtime
Martin Roukala's avatar
Martin Roukala committed
245
246
247
start_container $ARG_CONTAINER

# Emergency shell
248
log "Done executing the container, dropping to an emergency shell"
Martin Roukala's avatar
Martin Roukala committed
249
exec /bin/busybox sh