aboutsummaryrefslogtreecommitdiff
path: root/mkrootimg
blob: 22a492fdc5fa23f027e7ebddce2d2eaf73a4c931 (plain) (blame)
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
#!/bin/bash
set -e

print_usage() {
    cat 1>&2 <<EOF
Usage: $0 <rootfs_directory> <image_file>
Package the contents of a debian root filesystem into a binary image file, ready to be burned onto an sd card.
EOF
}

fail() {
    echo "$1" >&2
    exit 1
}

log() {
    echo "mkrootimg: $1" >&2
}

# Directory to package
rootfs="$1"

# Binary image file
image="$2"

# Contains temporary build files
builddir=$(mktemp -d)

([ -n "$rootfs" ] && [ -n "$image" ]) || fail "$(print_usage)"
[ -d "$rootfs" ] || fail "$rootfs does not exist or is not a directory"
[ ! -e "$image" ] || fail "$image already exists"

[ "$EUID" -eq 0 ] || fail "$0 must be run as root"

cleanup() {
    set +e
    umount --lazy "$builddir/mount/boot/firmware" 2> /dev/null
    umount --lazy "$builddir/mount" 2> /dev/null
    sync
    losetup --detach "$bootfs_loop" 2> /dev/null
    losetup --detach "$rootfs_loop" 2> /dev/null
    rm -rf "$builddir"
    trap - 0 1 2 3 6
}
trap cleanup 0 1 2 3 6

# Partition layout
#
# Content  Size
# ---------------------------------------------
# reserved 1024k       (1M, for e.g. a bootloader)
# bootfs   100*1024k   (100M)
# rootfs   as required

# size in bytes
reserved_size=1024*1024
bootfs_size=$((100*1024*1024))
rootfs_size=$(du --block-size=1 -s "$rootfs" | awk '{ print $1 }')

# converted to 512-byte sectors
reserved_sectors=$(( $reserved_size / 512 ))
bootfs_sectors=$(( $bootfs_size / 512 ))
# as overhead for journaling and reserved blocks 25% are added.
rootfs_sectors=$(( ($rootfs_size + $rootfs_size * 25 / 100) / 512 ))
image_sectors=$(( $reserved_sectors + $bootfs_sectors + $rootfs_sectors ))

# create empty image file
log "creating empty image"
dd if=/dev/zero of="$image" bs=512 count="$image_sectors" status=none

# write partition table to image
log "partitioning image"
sfdisk --label dos -q -uS "$image" <<EOF > /dev/null
$reserved_sectors,$bootfs_sectors,c,*
,$rootfs_sectors,L,
EOF

# set up temporary loop devices
log "setting up image loop devices"
bootfs_loop=$(losetup \
		  --offset $(( $reserved_sectors * 512 )) \
		  --sizelimit $(( $bootfs_sectors * 512 )) \
		  --find \
		  --show \
		  "$image")
rootfs_loop=$(losetup \
		  --offset $(( ($reserved_sectors + $bootfs_sectors) * 512 )) \
		  --sizelimit $(( $rootfs_sectors * 512 )) \
		  --find \
		  --show \
		  "$image")

# format partitions
log "formatting partitions"
mkfs.vfat -F 32 "$bootfs_loop" &> /dev/null
mkfs.ext4 -O^64bit "$rootfs_loop" &> /dev/null

# mount partitions
log "mounting partitions"
mkdir -p "$builddir/mount"
mount "$rootfs_loop" "$builddir/mount"
mkdir -p "$builddir/mount/boot/firmware"
mount "$bootfs_loop" "$builddir/mount/boot/firmware"

# copy root filesystem to image
log "copying root filesystem"
rsync -a "$rootfs/" "$builddir/mount/"

log "cleaning up"
cleanup

log "done"