Firm up the iso boot variant.
[rrq/tiniest.git] / mkit.sh
1 #!/bin/bash
2 #
3 # A script to prepare the tiniest "linux system". It's a kernel and an
4 # initrd within a FAT with a syslinux boot loader. The initrd contains
5 # a fully expanded busybox and uses /bin/sh as its init.
6 #
7 # This script creates and packs that initrd, as well as the whole,
8 # boot image. 
9
10 set -e
11
12 echo '### Step 1. Download original Packages file from the source'
13 REPOS=( deb.devuan.org/{merged_daedalus_main,merged_ceres_main} )
14 ARCH="amd64"
15 MBR=dos # gpt
16
17 for REPO in ${REPOS[@]} ; do
18     W=( ${REPO//_/ } )
19     SUITE=${W[1]}
20     SECTION=${W[2]}
21     
22     PKGFILE=${W[0]/\//_}_${SUITE}_${SECTION}_binary-${ARCH}_Packages
23     if [ ! -r $PKGFILE ] ; then
24         XZSRC="http://${W[0]}/dists/$SUITE/$SECTION/binary-$ARCH/Packages.xz"
25         echo "$XZSRC"
26         wget -qO - $XZSRC | xzcat - > ${PKGFILE}
27     fi
28
29     echo '# Reduce Packages file into two maps for filename and depends'
30     echo "# ..creating mapdepends.txt and mapfile.txt"
31     awk '
32     BEGIN { print "###" >> "mapdepends.txt"; print "###" >> "mapfile.txt"; }
33 $1=="Package:" {P=$2; next}
34 $1=="Pre-Depends:" {print P,$0 >> "mapdepends.txt";next }
35 $1=="Depends:" {print P,$0 >> "mapdepends.txt";next }
36 $1=="Filename:" {print P,$2 >> "mapfile.txt";next }
37 ' ${PKGFILE}
38 done
39
40 # Function to find the filename for a given package in the given mapfile
41 maplookup() {
42     local FN=${3:-tail}
43     echo "maplookup $1 $2" >&2
44     grep "^$1 " $2 >&2
45     grep "^$1 " $2 | $FN -n 1 | sed 's/[^ ]* //'
46 }
47
48 # Function to download a deb file and return its name
49 debfile() {
50     local FN=${2-tail}
51     local F="$(maplookup $1 mapfile.txt $FN)"
52     if [ ! -e "${F##*/}" ] ; then
53         for REPO in ${REPOS[@]} ; do
54             echo "download http://${REPO%%_*}/$F" >&2
55             wget -q "http://${REPO%%_*}/$F" && break
56             ls -l $(basename $F) >&2
57         done || return 1
58     fi
59     echo "${F##*/}"
60 }
61
62 # Function to extract from a deb without executing and pre/post scripts
63 # $1 = rootfs $2 = package
64 debextract() {
65     ar p $2 data.tar.xz | tar xJf - -C $1
66 }
67
68 # Deteremine which kernel to use; this is
69 echo "# Determine kernel"
70 KERNEL="$(maplookup linux-image-amd64 mapdepends.txt head | \
71                     sed 's/.*\(linux-image[^ ]*\).*/\1/')"
72 echo "# ... $KERNEL"
73
74 echo '### Step 2. Create and populate the initrd, and packit up.'
75 # The initrd contains only a few kernel modules for coping with a
76 # later pivoting onto a "full" filesystem.
77
78 echo "# Create initrd filesystem"
79 rm -fr initrd
80
81 echo "# Extract busybox, and fluff it up"
82 mkdir initrd
83 debextract initrd $(debfile busybox-static head)
84 for L in $(initrd/bin/busybox --listfull) ; do
85     mkdir -p $(dirname initrd/$L)
86     case "$L" in
87         bin/busybox) : ;;
88         usr/*) ln -s ../../bin/busybox initrd/$L ;;
89         sbin/*) ln -s ../bin/busybox initrd/$L ;;
90         bin/*)  ln -s busybox initrd/$L ;;
91         linuxrc) ln -s bin/busybox initrd/$L ;;
92     esac
93 done
94
95 echo "# Extract the kernel package ($KERNEL)"
96 echo "# .. and syslinux stuff if needed"
97 if [ ! -d kernel ] ; then
98     mkdir kernel
99     debextract kernel $(debfile $KERNEL head)
100     debextract kernel $(debfile syslinux)
101     debextract kernel $(debfile syslinux-common)
102     debextract kernel $(debfile syslinux-efi)
103     debextract kernel $(debfile syslinux-utils)
104     debextract kernel $(debfile isolinux)
105 fi
106
107 echo "# Include some kernel modules in the initrd"
108 MODULES=(
109     # disk
110     scsi_common scsi_mod libata ata_piix ata_generic cdrom sr_mod
111     crc32-pclmul crct10dif_common crc-t10dif crc64 crc64-rocksoft
112     t10-pi sd_mod sg
113     nls_cp437 nls_ascii fat vfat
114     crc32c_generic jbd2 mbcache crc16 ext4
115     usb-storage usbcore usb-common xhci-pci xhci-hcd
116     isofs exfat loop
117     # input
118     psmouse evdev
119     # network
120     e1000
121 )
122 MOODLES=""
123 B=$(pwd)
124 for m in ${MODULES[@]} ; do
125     km=$(find kernel/lib/modules -name $m.ko)
126     if [ -z "$km" ] ; then
127         echo "Missing module $m"
128         continue
129     fi
130     im=initrd/${km#kernel/}
131     MOODLES+=" $B/$im"
132     mkdir -p $(dirname $im)
133     cp -n $km $im
134 done
135 V=${KERNEL#linux-image-}
136 mkdir -p initrd/boot initrd/lib/modules/$V
137 cp kernel/boot/System.map-$V initrd/
138 cp kernel/lib/modules/$V/modules.order initrd/lib/modules/$V/
139 cp kernel/lib/modules/$V/modules.builtin initrd/lib/modules/$V/
140 depmod -F initrd/System.map-$V -b initrd $V $MOODLES
141
142 echo "# setup a scripted init. The kernel runs this via the #! interpreter"
143 rm -f initrd/sbin/init # just in case
144 cp init/init initrd/init
145 chmod a+x initrd/init
146
147 echo "# Declare password-less root"
148 mkdir -p initrd/etc
149 echo 'root::0:0:root:/root:/bin/bash' > initrd/etc/passwd
150
151 echo "# Now pack up that initrd as initrd.gz"
152 ( cd initrd ; find . | fakeroot cpio -H newc -o | gzip ) >initrd.gz
153
154 echo '### Step 3. create a 32  Mb fat filesystem with bios and UEFI boot'
155 rm -f bootimage.raw
156 dd if=/dev/zero of=bootimage.raw bs=32M count=1
157
158 # Prepare a gpt/dos partition table with a first partition marked as EFI
159 sfdisk bootimage.raw <<EOF
160 label: $MBR
161
162 2048 32767 U *
163 - - L
164 EOF
165
166 # Add a fat filesystem at 2048 61440
167 mkfs.fat -n TINIEST --offset 2048 -F 16 bootimage.raw
168 IMG="-i bootimage.raw@@$((2048*512))"
169
170 # Add an ext2 filesystem at offset 34816*512
171 # Copy initrd.gz and kernel into the fat filesystem root
172 EXT=offset=$((34816*512))
173 mke2fs -t ext4 -E $EXT -F bootimage.raw 15M
174
175 mcopy $IMG initrd.gz ::
176 mcopy $IMG kernel/boot/vm* ::/vmlinuz
177 mcopy $IMG splash.png ::/
178
179 mmd $IMG ::/boot
180 mmd $IMG ::/boot/syslinux
181 mmd $IMG ::/boot/syslinux/bios
182 mcopy $IMG \
183       kernel/usr/lib/syslinux/modules/bios/* ::/boot/syslinux/bios
184 mcopy $IMG syslinux-legacy.cfg ::/syslinux.cfg
185
186 syslinux --install --offset=${IMG#*@@} bootimage.raw
187
188 mmd $IMG ::/EFI
189 mmd $IMG ::/EFI/BOOT
190 mcopy $IMG kernel/usr/lib/SYSLINUX.EFI/efi64/syslinux.efi \
191       ::/EFI/BOOT/bootx64.efi
192 mcopy $IMG \
193       kernel/usr/lib/syslinux/modules/efi64/* ::/EFI/BOOT
194 mcopy $IMG syslinux-uefi.cfg ::/EFI/BOOT/syslinux.cfg
195
196 case "$MBR" in
197     dos) MBRBIN=mbr.bin ;;
198     gpt)
199         MBRBIN=gptmbr.bin
200         sfdisk --relocate gpt-bak-std bootimage.raw
201         sfdisk -f --part-attrs bootimage.raw 1 LegacyBIOSBootable
202         ;;
203     *) exit 1 ;;
204 esac
205 dd conv=notrunc of=bootimage.raw bs=440 count=1 \
206    if=kernel/usr/lib/syslinux/mbr/$MBRBIN
207
208 echo "# populate the extra partition"
209 if [ -d extra ] ; then
210     mkdir -p X
211     fuse2fs -o fakeroot -o$EXT bootimage.raw X
212     rsync -r extra/. X/.
213     umount X
214 fi
215
216 exit