Include the FS filesystem as squashfs as second partition.
[rrq/rescue-boot.git] / minbase-strap.sh
1 #!/bin/bash
2 #
3 # Utility script to debootstrap a minbase filesystem, with additions
4 # of kernel, busybox and an init script. Then make an initrd.gz from
5 # that and prepare a boot image file with syslinux from that.
6 #
7 if [ $(id -u) -ne 0 ] ; then
8     exec sudo env http_proxy=$http_proxy $0 $*
9     echo "** Abort: must be root" >&2
10     exit 1
11 fi
12 set -e -x
13
14 ARCH="${1-$(dpkg-architecture -q DEB_HOST_ARCH)}"
15 DIST=${2-ceres}
16 IMG=${3-boot-$DIST-$ARCH.img}
17 FS=${4-FS}
18
19 # Prepare or keep FS
20 DEBSTRAP=true
21 USRMERGE=true
22 if [ -d "$FS" ] ; then
23     select x in "keep existing $FS and skip debootstrap" \
24                     "remove existing $FS and debootstrap anew" \
25                     "abort" ; do
26         [ "$x" = abort ] && exit 1
27         [ -z "$x" ] || break
28     done
29     echo "selection: $REPLY"
30     [ "$REPLY" = 1 ] && DEBSTRAP=false
31 fi
32
33 stupid_links() {
34     mkdir -p $1/usr
35     for d in bin sbin lib ; do mkdir $1/usr/$d ; ln -s usr/$d $1/$d ; done
36 }
37
38 if $DEBSTRAP ; then
39     ## Optionally add the stupid-links
40     read -n 1 -p "prime $FS with stupid-links? [Yn]" x
41     [ "$x" = "n" ] && USRMERGE=false
42
43     rm -rf "$FS" # remove if existin
44
45     $USRMERGE && stupid_links "$FS"
46
47     ## bootstrap a filesystem, with exclusions
48     echo "http_proxy=$http_proxy debootstrap ..."
49     debootstrap --exclude=logrotate,cron,cron-daemon-common \
50                 --arch=$ARCH $DIST "$FS" http://deb.devuan.org/merged
51     chroot "$FS" apt-get install -y logrotate cron
52
53     ## Select and add a kernel
54     KERNELS=( $(chroot "$FS" apt-cache search linux-image-\* | \
55                     sed 's/\s.*//' | sort -h ) )
56     echo "** Please select kernel **"
57     select KERNEL in "${KERNELS[@]}" ; do [ -n "$KERNEL" ] && break ; done
58     chroot "$FS" apt-get install -y $KERNEL
59     chroot "$FS" depmod -a ${KERNEL#linux-image-}
60
61     chroot "$FS" apt-get install -y busybox-static debootstrap
62     touch "$FS"/usr/bin{linuxrc,init} # block these
63     chroot "$FS" /usr/bin/busybox --install -s /usr/bin
64
65 fi # End of $DEBSTRAP actions
66
67 ## Pick boot kernel, if there are many
68 LINUXES=( $(cd "$FS"/boot ; ls vmlinuz* 2>/dev/null) )
69 if [ ${#LINUXES[@]} -gt 1 ] ; then
70     echo "** Please select boot kernel"
71     select LINUX in $LINUXES ; do [ -n "$LINUX" ] && break ; done
72 elif [ -n "$LINUXES" ] ; then
73     LINUX="$FS"/boot/${LINUXES[0]}
74 else
75     echo "** Oh No! There is no $FS/boot/vmlinux-* ... bailing out!" >&2
76     exit 1
77 fi
78
79 #============================================================
80 # Prepare a temporary directory tree with a boot kernel and $FS packed
81 # up into an initrd.gz
82 TMP=$(mktemp -d XXXX)
83 trap "rm -r $TMP" 0 2 15
84
85 mkdir -p $TMP/prep/{proc,dev,tmp,sys,mnt,usr}
86 stupid_links $TMP/prep
87
88 # copy FS tree(s) in full into the TMP/prep tree
89 copyFStree() {
90     local D
91     for D in $* ; do
92         tar cf - -C "$FS" $D \
93             | tar -xf - --skip-old-files --keep-directory-symlink -C $TMP/prep
94     done
95 }
96
97 # Copy FS binary(s) with all its libraries into the TMP/prep tree
98 copyFSbin() {
99     local B BIN
100     for B in $* ; do
101         BIN="$(chroot "$FS" which "$B")"
102         tar cf - --dereference -C "$FS" ${BIN#/} \
103             $(chroot "$FS" ldd "$BIN" | grep -oE '/[^ ]*'|sed 's|/||')\
104             | tar -xf - --keep-directory-symlink -C $TMP/prep
105     done
106 }
107
108 INITRD="$FS"/boot/initrd.img${LINUX#*/vmlinuz}
109 if [ -r "$INITRD" ] ; then
110     #select X in my FS ; do [ -n "$X" ] && break ; done
111     X=FS
112 else
113     X=my
114 fi
115 case "$X" in
116     FS)
117         copyFStree lib/modules
118         zstdcat $INITRD | ( cd $TMP/prep && cpio -i )
119         ;;
120     my)
121         copyFStree lib/modules lib/udev
122         copyFSbin busybox sh cttyhack setsid mount mkdir
123         copyFSbin udevd udevadm modprobe modinfo kmod blkid
124         ;;
125 esac
126
127 ## (re)install /init
128 echo "** Please select /init template"
129 select INIT in none $(echo init*.template) ; do [ -n "$INIT" ] && break ; done
130 if [ "$INIT" != none ] ; then
131     mv $TMP/prep/init{,.FS}
132     cp $INIT $TMP/prep/init
133     chmod a+x $TMP/prep/init
134     cp message.txt $TMP/prep/message.txt
135 fi
136
137 ( cd "$TMP/prep" && find -printf '%P\n' | cpio -o -H newc ) | \
138     gzip > $TMP/initrd.gz
139 cp $LINUX $TMP/vmlinuz
140 rm -rf $TMP/prep
141
142 #============================================================
143 # Add syslinux boot equipment for bios boot under $TMP/syslinux
144 # (also includes the syslinux image mastering further below)
145 echo "Please select boot console options"
146
147 CONOPTS=( none ttyS0,115200 )
148 select CON in "${CONOPTS[@]}" ; do [ -n "$CON" ] && break ; done
149 case "$CON" in none) CON= ;; *) CON="console=$CON" ;; esac
150
151 mkdir -p $TMP/syslinux
152 cp -t $TMP/syslinux /usr/lib/syslinux/modules/bios/*
153 cat <<EOF > $TMP/syslinux/syslinux.cfg
154 default menu.c32
155 label linux
156     kernel /vmlinuz
157     append initrd=/initrd.gz init=/init console=ttyS0,115200 
158 label rescue
159     kernel /vmlinuz
160     append initrd=/initrd.gz init=/init console=ttyS0,115200 rescue
161 EOF
162
163 #============================================================
164 [ -e "$IMG" ] && read -p "** Will overwrite $IMG (or ^C here and now)" x
165 rm -f "$IMG"
166
167 # First partition sectors (round up to a Mb number
168 DUM1=$(( ( $(du -sB1 $TMP | sed 's/\s.*//') / 1048576 + 2 ) ))
169 DUM2=$(( $(stat -c %s FS.sqfs) / 1048576 + 2 ))
170
171 # Estimate the required disk image size in Mib
172 DUM=$(( DUM1 + DUM2 + 1 ))
173
174 # Create the image, with the partition marked as EFI parition and
175 # bootable; acutal format is FAT{12,16,32}
176 dd if=/dev/zero of="$IMG" bs=${DUM}M count=0 seek=1 status=none
177 cat <<EOF | tee -a /proc/self/fd/2 | sfdisk -q "$IMG"
178 label: dos
179
180 2048 $(( DUM1 * 2048 )) 0xef *
181 - - 0x83
182 EOF
183 PART=( $(fdisk -l -ostart,sectors $IMG | tail -n 2) )
184 echo "${PART[*]}"
185
186 # First sector is 2048 by default, which is byte address 1048576
187 TMPIMG=$(mktemp XXXX)
188 fusefile $TMPIMG $IMG/0+$(( ( ${PART[0]} + ${PART[1]} ) * 512 ))
189 mkfs.fat --offset ${PART[0]} "$TMPIMG"  >/dev/null
190 umount $TMPIMG
191 rm $TMPIMG
192 mcopy -i "$IMG@@1048576" -s $TMP/* ::/
193 [ -z "$SUDO_USER" ] || chown $SUDO_USER: "$IMG"
194 dd if=FS.sqfs of=$IMG seek=${PART[3]} conv=notrunc status=none
195
196 #============================================================
197 # Final syslinux bios boot image mastering
198 dd if=/usr/lib/SYSLINUX/mbr.bin of="$IMG" bs=440 conv=notrunc status=none
199 syslinux -i -d syslinux -t 1048576 "$IMG"