logo

bootstrap-initrd

Linux initrd to bootstrap from a small binary seed git clone https://anongit.hacktivis.me/git/bootstrap-initrd.git/

make-root.sh (7801B)


  1. #!/bin/sh
  2. # bootstrap-initrd: Linux initrd to bootstrap from a small binary seed
  3. # SPDX-FileCopyrightText: 2017 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me>
  4. # SPDX-License-Identifier: MPL-2.0
  5. tarballs="
  6. oksh-oksh-7.6.tar.gz
  7. yacc-oyacc-6.6.tar.gz
  8. utils-std-0.0.1.tar.gz
  9. pdpmake-2.0.3.tgz
  10. nawk-20250116.tar.gz
  11. bzip2-bzip2-1.0.8.tar.gz
  12. zlib-1.3.1.tar.gz
  13. pigz-2.8.tar.gz
  14. heirloom-070715.tar.bz2
  15. heirloom-devtools-070527.tar.bz2
  16. sbase-b30fb568.tar.gz
  17. "
  18. local_files="
  19. init.sh
  20. src/ls-stub.c
  21. src/grep-stub.c
  22. src/cp-stub.c
  23. src/getty-stub.c
  24. src/mount-stub.c
  25. src/reboot-stub.c
  26. "
  27. distfiles="
  28. make-4.4.1.tar.gz
  29. lua-5.4.6.tar.gz
  30. pkgconf-pkgconf-2.3.0.tar.gz
  31. iproute2-6.12.0.tar.gz
  32. bearssl-0.6.tar.gz
  33. tiny-curl-8.4.0.tar.gz
  34. cacert-2024-11-26.pem
  35. git-2.48.1.tar.gz
  36. e2fsprogs-1.47.1.tar.gz
  37. muon-v0.4.0.tar.gz
  38. muxzcat-v2b.tar.gz
  39. "
  40. local_distfiles="
  41. extras-build-all.sh
  42. extras/bearssl.sh
  43. extras/e2fsprogs.sh
  44. extras/git.sh
  45. extras/iproute2.sh
  46. extras/lua.sh
  47. extras/make.sh
  48. extras/muon-stage1.sh
  49. extras/muon-stage2.sh
  50. extras/muxzcat.sh
  51. extras/pkgconf-lite.sh
  52. extras/pkgconf.sh
  53. extras/tiny-curl.sh
  54. "
  55. WORKDIR="$(dirname "$0")"
  56. WORKDIR="$(realpath "$WORKDIR")"
  57. . "$WORKDIR/common.sh"
  58. : ${ALPINE_ARCH:=x86_64}
  59. name_base="bootstrap-initrd"
  60. out_base="${WORKDIR}/${name_base}/${ALPINE_ARCH}"
  61. test -z "${EXCLUDE_EXTRAS}" && out_base="${out_base}+extras"
  62. gen_oksh_tcc_h() {
  63. set -e
  64. cd oksh-*/
  65. cp "${WORKDIR}/src/oksh-7.6_pconfig.h" ./pconfig.h
  66. echo 'char *oksh_tcc_cmd[] = {'
  67. # -DSMALL to not need ncurses
  68. printf '\t"%s",\n' /usr/bin/tcc -o /bin/oksh \
  69. -D_GNU_SOURCE -DEMACS -DVI -DSMALL \
  70. *.c
  71. printf '\t0\n'
  72. echo '};'
  73. cd - >/dev/null
  74. }
  75. set -e
  76. sha512sum -c distfiles.SHA512SUM
  77. if test -e "$out_base"; then
  78. rm -fr "$out_base"
  79. fi
  80. mkdir -p "$out_base" || die "Failed: mkdir $out_base"
  81. cd "$out_base" || die "Failed: cd $out_base"
  82. mkdir -p src
  83. cd "${out_base}/src"
  84. for i in $tarballs; do
  85. tar xof "${WORKDIR}/distfiles/$i" || die "Failed extracting $i"
  86. done
  87. cd -
  88. for i in $local_files; do
  89. cp "${WORKDIR}/$i" ./"$i" || die "Failed copying $i"
  90. done
  91. if ! test "${EXCLUDE_EXTRAS:+y}" = "y"; then
  92. mkdir -p ./extras
  93. for i in $local_distfiles; do
  94. cp "${WORKDIR}/$i" ./"$i" || die "Failed copying $i"
  95. done
  96. mkdir -p ./distfiles
  97. for i in $distfiles
  98. do
  99. cp "${WORKDIR}/distfiles/$i" ./distfiles/ || die "Failed copying $i"
  100. done
  101. fi
  102. deblob
  103. mkdir -p dev proc sys etc usr/bin var/empty || die "Failed creating base directories"
  104. ln -s /proc/mounts etc/mtab || die "Failed symlink for /etc/mtab"
  105. ln -s bin sbin
  106. ln -s usr/lib lib
  107. ln -s usr/bin bin
  108. ln -s usr/bin sbin
  109. mkdir -m 777 tmp
  110. cat >etc/passwd <<EOF
  111. root:x:0:0:root:/root:/bin/sh
  112. nobody:x:65534:65534:nobody:/var/empty:/bin/false
  113. EOF
  114. cat >etc/group <<EOF
  115. root:x:0:root
  116. nobody:x:65534:
  117. nogroup:x:65533:
  118. EOF
  119. cat >etc/setdate.sh <<EOF
  120. #!/bin/sh
  121. exec date -f %Y-%m-%dT%TZ $(date +%Y-%m-%dT%TZ)
  122. EOF
  123. chmod +x etc/setdate.sh
  124. for i in fd stderr stdin stdout; do
  125. ln -fs proc/self/$i dev/$i
  126. done
  127. cp "${WORKDIR}/init.c" ./init || die "copying init"
  128. sed -i '1i#!/usr/bin/tcc -run' ./init || die "failed adding tcc shebang to init"
  129. chmod 755 init || die "init chmod"
  130. cp -p "${WORKDIR}/ar-stub.sh" ./bin/ar
  131. for apk in $APKS_main $APKS_testing
  132. do
  133. tar xof "${WORKDIR}/distfiles/$apk.${ALPINE_ARCH}" --exclude '.*'
  134. done
  135. # Allows to shave off ~9.1M from the binary seed
  136. rm usr/lib/libc.a
  137. # tcc-0.9.27_git20250106-r0 doesn't supports alloca(3) on riscv yet
  138. # removing the musl-provided header allows to compile git
  139. # (still breaks GNU make though)
  140. if [ "${ALPINE_ARCH}" = riscv64 ]; then
  141. rm usr/include/alloca.h
  142. sed -i '/alloca\.h/d' usr/include/stdlib.h
  143. fi
  144. cd "${out_base}/src"
  145. ln -s oksh "${out_base}/bin/sh"
  146. gen_oksh_tcc_h > oksh_tcc.h
  147. cd "${out_base}/src"
  148. oyacc=$(echo ./yacc-oyacc-*/)
  149. cat >"${oyacc}/config.h" <<EOF
  150. // __dead and __dead2 are absent in musl
  151. #define __dead __attribute__((__no_return__))
  152. // HAVE_PROGNAME: Absent in musl
  153. #define HAVE_ASPRINTF
  154. // HAVE_PLEDGE: Absent in musl
  155. #define HAVE_REALLOCARRAY
  156. #define HAVE_STRLCPY
  157. EOF
  158. sed -i -e '/CFLAGS/s; -g;;' bzip2-*/Makefile bzip2-*/Makefile-libbz2_so || die "Failed patching out `-g` in /bzip2-*/Makefile*"
  159. sed -i -e 's;bzip2-shared;bzip2;' bzip2-*/Makefile-libbz2_so || die "Failed patching /bzip2-*/Makefile-libbz2_so"
  160. sed -i -e 's;all: libbz2.a;all: libbz2.so;' -e 's;bzip2: libbz2.a;bzip2: libbz2.so;' bzip2-*/Makefile || die "Failed patching /bzip2-*/Makefile"
  161. rm bzip2-*/sample* || die "Failed removing sample bzip2 files"
  162. patch -p0 <"${WORKDIR}/zlib-1.3.1_no_staticlib.patch"
  163. patch -p0 <"${WORKDIR}/zlib-1.3.1-use-LDFLAGS-in-configure.patch"
  164. patch -p0 <"${WORKDIR}/zlib-1.3.1-use-LDFLAGS-in-configure_no_gcc.patch"
  165. rm zlib-*/doc/crc-doc.1.0.pdf || die "Failed removing zlib crc-doc.1.0.pdf"
  166. rm zlib-*/crc32.h || die "Failed removing autogenerated zlib-*/crc32.h"
  167. rm -r zlib-*/examples/ || die "Failed removing zlib-*/examples/"
  168. rm -r zlib-*/contrib/ || die "Failed removing zlib-*/contrib/"
  169. sed -i 's;^clean: minizip-clean;clean:;' zlib-*/Makefile.in || die "Failed disabling minizip cleanup"
  170. sed -i \
  171. -e 's;INSTALL=.*;INSTALL=install;' \
  172. -e 's;PREFIX=.*;PREFIX=/usr;;' \
  173. -e 's;STRIP=.*;STRIP=true;' \
  174. -e 's;#?AR=.*;AR ?= ar;' \
  175. -e 's;RANLIB=.*;RANLIB ?= ranlib;' \
  176. -e 's;YACC=.*;YACC ?= yacc;' \
  177. heirloom-devtools-*/mk.config \
  178. || die "Failed configuring heirloom-devtools"
  179. # pdpmake-1.4.3+ consider them invalid "macros"
  180. sed -i \
  181. -e '/^\.c\.o:/s/;/\n\t/' \
  182. heirloom-devtools-*/lex/Makefile.mk heirloom-devtools-*/m4/Makefile.mk \
  183. || die "Failed patching .c.o: inferred targets in heirloom-devtools"
  184. # Only pick what we need from heirloom
  185. mkdir -p heirloom
  186. cd heirloom-0*/
  187. patch -p1 <"${WORKDIR}/heirloom-no_alloca.patch"
  188. mv \
  189. makefile Makefile.mk build \
  190. libcommon diff tar sort comm find stty \
  191. ../heirloom/ || die "Failed copying heirloom files"
  192. cd -
  193. rm -r heirloom-0*/ || die "Failed removing old heirloom unpacked directory"
  194. # - maninst Fails to create parent dir, just noop it, we don't have man anyway
  195. # -e 's;MANINST =.*;MANINST = $(SHELL) ../build/maninst.sh;' \
  196. # - Turns out tcc comes with an ar(1)
  197. # -e 's;LCOMMON =.*;LCOMMON = ../libcommon/*.c;' \
  198. sed -i \
  199. -e 's;DEFBIN =.*;DEFBIN = /bin;' \
  200. -e 's;DEFSBIN =.*;DEFSBIN = /bin;' \
  201. -e 's;STRIP =.*;STRIP = true;' \
  202. -e 's;SPELLHIST =.*;SPELLHIST = /dev/null;' \
  203. -e 's;UCBINST =.*;UCBINST = install;' \
  204. -e 's;MANINST =.*;MANINST = true;' \
  205. heirloom/build/mk.config \
  206. || die "Failed configuring heirloom (toolchest)"
  207. sed -i \
  208. -e 's;__GLIBC__;__linux__;' \
  209. -e '/#define getdents/s;^;//;' \
  210. heirloom/libcommon/getdir.c || die "Failed fixing heirloom libcommon for musl"
  211. sed -i \
  212. -e 's;#ifdef _AIX;#if defined(_AIX) || defined(__linux__);' \
  213. -e '/static int utf8/avoid writerr(struct oblok *op, int count, int written) {}' \
  214. heirloom/tar/tar.c || die "Failed fixing heirloom tar for musl"
  215. sed -i \
  216. -e 's;#ifdef _AIX;#if defined(_AIX) || defined(__linux__);' \
  217. heirloom/find/find.c || die "Failed fixing heirloom find for musl"
  218. sed -i -e 's;getdir.o regexpr.o gmatch.o;getdir.o gmatch.o;' heirloom/libcommon/Makefile.mk || die
  219. rm -r pigz-*/zopfli || die
  220. rm -r heirloom-devtools-*/make heirloom-devtools-*/sccs || die
  221. rm -r awk-*/testdir || die
  222. cd "${out_base}/"
  223. deblob -n -j "${WORKDIR}"/make-root-deblob.json || die
  224. if command -v jq >/dev/null; then
  225. jq --raw-output0 '.[].path' "${WORKDIR}"/make-root-deblob.json \
  226. | xargs -0 du -bach \
  227. | sort -h
  228. elif command -v qjs >/dev/null; then
  229. <"${WORKDIR}"/make-root-deblob.json \
  230. qjs --std \
  231. -e 'let deblob_raw = std.in.readAsString(); let deblob = JSON.parse(deblob_raw); deblob.forEach((e) => {std.printf("%s\0", e.path);})' \
  232. | xargs -0 du -bach \
  233. | sort -h
  234. else
  235. echo "make-root: Command 'jq' and 'qjs' not found. Not going to list sizes of blobs" 1>&2
  236. fi
  237. cd "${WORKDIR}"