You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

433 regels
11 KiB

  1. #!/bin/bash -e
  2. # shellcheck disable=SC2119
  3. run_sub_stage()
  4. {
  5. log "Begin ${SUB_STAGE_DIR}"
  6. pushd "${SUB_STAGE_DIR}" > /dev/null
  7. for i in {00..99}; do
  8. if [ -f "${i}-debconf" ]; then
  9. log "Begin ${SUB_STAGE_DIR}/${i}-debconf"
  10. on_chroot << EOF
  11. debconf-set-selections <<SELEOF
  12. $(cat "${i}-debconf")
  13. SELEOF
  14. EOF
  15. log "End ${SUB_STAGE_DIR}/${i}-debconf"
  16. fi
  17. if [ -f "${i}-packages-nr" ]; then
  18. log "Begin ${SUB_STAGE_DIR}/${i}-packages-nr"
  19. PACKAGES="$(sed -f "${SCRIPT_DIR}/remove-comments.sed" < "${i}-packages-nr")"
  20. if [ -n "$PACKAGES" ]; then
  21. on_chroot << EOF
  22. apt-get -o Acquire::Retries=3 install --no-install-recommends -y $PACKAGES
  23. EOF
  24. if [ "${USE_QCOW2}" = "1" ]; then
  25. on_chroot << EOF
  26. apt-get clean
  27. EOF
  28. fi
  29. fi
  30. log "End ${SUB_STAGE_DIR}/${i}-packages-nr"
  31. fi
  32. if [ -f "${i}-packages" ]; then
  33. log "Begin ${SUB_STAGE_DIR}/${i}-packages"
  34. PACKAGES="$(sed -f "${SCRIPT_DIR}/remove-comments.sed" < "${i}-packages")"
  35. if [ -n "$PACKAGES" ]; then
  36. on_chroot << EOF
  37. apt-get -o Acquire::Retries=3 install -y $PACKAGES
  38. EOF
  39. if [ "${USE_QCOW2}" = "1" ]; then
  40. on_chroot << EOF
  41. apt-get clean
  42. EOF
  43. fi
  44. fi
  45. log "End ${SUB_STAGE_DIR}/${i}-packages"
  46. fi
  47. if [ -d "${i}-patches" ]; then
  48. log "Begin ${SUB_STAGE_DIR}/${i}-patches"
  49. pushd "${STAGE_WORK_DIR}" > /dev/null
  50. if [ "${CLEAN}" = "1" ]; then
  51. rm -rf .pc
  52. rm -rf ./*-pc
  53. fi
  54. QUILT_PATCHES="${SUB_STAGE_DIR}/${i}-patches"
  55. SUB_STAGE_QUILT_PATCH_DIR="$(basename "$SUB_STAGE_DIR")-pc"
  56. mkdir -p "$SUB_STAGE_QUILT_PATCH_DIR"
  57. ln -snf "$SUB_STAGE_QUILT_PATCH_DIR" .pc
  58. quilt upgrade
  59. if [ -e "${SUB_STAGE_DIR}/${i}-patches/EDIT" ]; then
  60. echo "Dropping into bash to edit patches..."
  61. bash
  62. fi
  63. RC=0
  64. quilt push -a || RC=$?
  65. case "$RC" in
  66. 0|2)
  67. ;;
  68. *)
  69. false
  70. ;;
  71. esac
  72. popd > /dev/null
  73. log "End ${SUB_STAGE_DIR}/${i}-patches"
  74. fi
  75. if [ -x ${i}-run.sh ]; then
  76. log "Begin ${SUB_STAGE_DIR}/${i}-run.sh"
  77. ./${i}-run.sh
  78. log "End ${SUB_STAGE_DIR}/${i}-run.sh"
  79. fi
  80. if [ -f ${i}-run-chroot.sh ]; then
  81. log "Begin ${SUB_STAGE_DIR}/${i}-run-chroot.sh"
  82. on_chroot < ${i}-run-chroot.sh
  83. log "End ${SUB_STAGE_DIR}/${i}-run-chroot.sh"
  84. fi
  85. done
  86. popd > /dev/null
  87. log "End ${SUB_STAGE_DIR}"
  88. }
  89. run_stage(){
  90. log "Begin ${STAGE_DIR}"
  91. STAGE="$(basename "${STAGE_DIR}")"
  92. pushd "${STAGE_DIR}" > /dev/null
  93. STAGE_WORK_DIR="${WORK_DIR}/${STAGE}"
  94. ROOTFS_DIR="${STAGE_WORK_DIR}"/rootfs
  95. if [ "${USE_QCOW2}" = "1" ]; then
  96. if [ ! -f SKIP ]; then
  97. load_qimage
  98. fi
  99. else
  100. # make sure we are not umounting during export-image stage
  101. if [ "${USE_QCOW2}" = "0" ] && [ "${NO_PRERUN_QCOW2}" = "0" ]; then
  102. unmount "${WORK_DIR}/${STAGE}"
  103. fi
  104. fi
  105. if [ ! -f SKIP_IMAGES ]; then
  106. if [ -f "${STAGE_DIR}/EXPORT_IMAGE" ]; then
  107. EXPORT_DIRS="${EXPORT_DIRS} ${STAGE_DIR}"
  108. fi
  109. fi
  110. if [ ! -f SKIP ]; then
  111. if [ "${CLEAN}" = "1" ] && [ "${USE_QCOW2}" = "0" ] ; then
  112. if [ -d "${ROOTFS_DIR}" ]; then
  113. rm -rf "${ROOTFS_DIR}"
  114. fi
  115. fi
  116. if [ -x prerun.sh ]; then
  117. log "Begin ${STAGE_DIR}/prerun.sh"
  118. ./prerun.sh
  119. log "End ${STAGE_DIR}/prerun.sh"
  120. fi
  121. for SUB_STAGE_DIR in "${STAGE_DIR}"/*; do
  122. if [ -d "${SUB_STAGE_DIR}" ] && [ ! -f "${SUB_STAGE_DIR}/SKIP" ]; then
  123. run_sub_stage
  124. fi
  125. done
  126. fi
  127. if [ "${USE_QCOW2}" = "1" ]; then
  128. unload_qimage
  129. else
  130. # make sure we are not umounting during export-image stage
  131. if [ "${USE_QCOW2}" = "0" ] && [ "${NO_PRERUN_QCOW2}" = "0" ]; then
  132. unmount "${WORK_DIR}/${STAGE}"
  133. fi
  134. fi
  135. PREV_STAGE="${STAGE}"
  136. PREV_STAGE_DIR="${STAGE_DIR}"
  137. PREV_ROOTFS_DIR="${ROOTFS_DIR}"
  138. popd > /dev/null
  139. log "End ${STAGE_DIR}"
  140. }
  141. if [ "$(id -u)" != "0" ]; then
  142. echo "Please run as root" 1>&2
  143. exit 1
  144. fi
  145. BASE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
  146. if [[ $BASE_DIR = *" "* ]]; then
  147. echo "There is a space in the base path of pi-gen"
  148. echo "This is not a valid setup supported by debootstrap."
  149. echo "Please remove the spaces, or move pi-gen directory to a base path without spaces" 1>&2
  150. exit 1
  151. fi
  152. export BASE_DIR
  153. if [ -f config ]; then
  154. # shellcheck disable=SC1091
  155. source config
  156. fi
  157. while getopts "c:" flag
  158. do
  159. case "$flag" in
  160. c)
  161. EXTRA_CONFIG="$OPTARG"
  162. # shellcheck disable=SC1090
  163. source "$EXTRA_CONFIG"
  164. ;;
  165. *)
  166. ;;
  167. esac
  168. done
  169. term() {
  170. if [ "${USE_QCOW2}" = "1" ]; then
  171. log "Unloading image"
  172. unload_qimage
  173. fi
  174. }
  175. trap term EXIT INT TERM
  176. export PI_GEN=${PI_GEN:-pi-gen}
  177. export PI_GEN_REPO=${PI_GEN_REPO:-https://github.com/RPi-Distro/pi-gen}
  178. if [ -z "${IMG_NAME}" ]; then
  179. echo "IMG_NAME not set" 1>&2
  180. exit 1
  181. fi
  182. export USE_QEMU="${USE_QEMU:-0}"
  183. export IMG_DATE="${IMG_DATE:-"$(date +%Y-%m-%d)"}"
  184. export IMG_FILENAME="${IMG_FILENAME:-"${IMG_DATE}-${IMG_NAME}"}"
  185. export ARCHIVE_FILENAME="${ARCHIVE_FILENAME:-"image_${IMG_DATE}-${IMG_NAME}"}"
  186. export SCRIPT_DIR="${BASE_DIR}/scripts"
  187. export WORK_DIR="${WORK_DIR:-"${BASE_DIR}/work/${IMG_NAME}"}"
  188. export DEPLOY_DIR=${DEPLOY_DIR:-"${BASE_DIR}/deploy"}
  189. # DEPLOY_ZIP was deprecated in favor of DEPLOY_COMPRESSION
  190. # This preserve the old behavior with DEPLOY_ZIP=0 where no archive was created
  191. if [ -z "${DEPLOY_COMPRESSION}" ] && [ "${DEPLOY_ZIP:-1}" = "0" ]; then
  192. echo "DEPLOY_ZIP has been deprecated in favor of DEPLOY_COMPRESSION"
  193. echo "Similar behavior to DEPLOY_ZIP=0 can be obtained with DEPLOY_COMPRESSION=none"
  194. echo "Please update your config file"
  195. DEPLOY_COMPRESSION=none
  196. fi
  197. export DEPLOY_COMPRESSION=${DEPLOY_COMPRESSION:-zip}
  198. export COMPRESSION_LEVEL=${COMPRESSION_LEVEL:-6}
  199. export LOG_FILE="${WORK_DIR}/build.log"
  200. export TARGET_HOSTNAME=${TARGET_HOSTNAME:-raspberrypi}
  201. export FIRST_USER_NAME=${FIRST_USER_NAME:-pi}
  202. export FIRST_USER_PASS
  203. export DISABLE_FIRST_BOOT_USER_RENAME=${DISABLE_FIRST_BOOT_USER_RENAME:-0}
  204. export RELEASE=${RELEASE:-bookworm} # Don't forget to update stage0/prerun.sh
  205. export WPA_COUNTRY
  206. export ENABLE_SSH="${ENABLE_SSH:-0}"
  207. export PUBKEY_ONLY_SSH="${PUBKEY_ONLY_SSH:-0}"
  208. export LOCALE_DEFAULT="${LOCALE_DEFAULT:-en_GB.UTF-8}"
  209. export KEYBOARD_KEYMAP="${KEYBOARD_KEYMAP:-gb}"
  210. export KEYBOARD_LAYOUT="${KEYBOARD_LAYOUT:-English (UK)}"
  211. export TIMEZONE_DEFAULT="${TIMEZONE_DEFAULT:-Europe/London}"
  212. export GIT_HASH=${GIT_HASH:-"$(git rev-parse HEAD)"}
  213. export PUBKEY_SSH_FIRST_USER
  214. export CLEAN
  215. export IMG_NAME
  216. export APT_PROXY
  217. export STAGE
  218. export STAGE_DIR
  219. export STAGE_WORK_DIR
  220. export PREV_STAGE
  221. export PREV_STAGE_DIR
  222. export ROOTFS_DIR
  223. export PREV_ROOTFS_DIR
  224. export IMG_SUFFIX
  225. export NOOBS_NAME
  226. export NOOBS_DESCRIPTION
  227. export EXPORT_DIR
  228. export EXPORT_ROOTFS_DIR
  229. export QUILT_PATCHES
  230. export QUILT_NO_DIFF_INDEX=1
  231. export QUILT_NO_DIFF_TIMESTAMPS=1
  232. export QUILT_REFRESH_ARGS="-p ab"
  233. # shellcheck source=scripts/common
  234. source "${SCRIPT_DIR}/common"
  235. # shellcheck source=scripts/dependencies_check
  236. source "${SCRIPT_DIR}/dependencies_check"
  237. export NO_PRERUN_QCOW2="${NO_PRERUN_QCOW2:-1}"
  238. export USE_QCOW2="${USE_QCOW2:-0}"
  239. export BASE_QCOW2_SIZE=${BASE_QCOW2_SIZE:-12G}
  240. source "${SCRIPT_DIR}/qcow2_handling"
  241. if [ "${USE_QCOW2}" = "1" ]; then
  242. NO_PRERUN_QCOW2=1
  243. else
  244. NO_PRERUN_QCOW2=0
  245. fi
  246. export NO_PRERUN_QCOW2="${NO_PRERUN_QCOW2:-1}"
  247. if [ "$SETFCAP" != "1" ]; then
  248. export CAPSH_ARG="--drop=cap_setfcap"
  249. fi
  250. dependencies_check "${BASE_DIR}/depends"
  251. #check username is valid
  252. if [[ ! "$FIRST_USER_NAME" =~ ^[a-z][-a-z0-9_]*$ ]]; then
  253. echo "Invalid FIRST_USER_NAME: $FIRST_USER_NAME"
  254. exit 1
  255. fi
  256. if [[ "$DISABLE_FIRST_BOOT_USER_RENAME" == "1" ]] && [ -z "${FIRST_USER_PASS}" ]; then
  257. echo "To disable user rename on first boot, FIRST_USER_PASS needs to be set"
  258. echo "Not setting FIRST_USER_PASS makes your system vulnerable and open to cyberattacks"
  259. exit 1
  260. fi
  261. if [[ "$DISABLE_FIRST_BOOT_USER_RENAME" == "1" ]]; then
  262. echo "User rename on the first boot is disabled"
  263. echo "Be advised of the security risks linked to shipping a device with default username/password set."
  264. fi
  265. if [[ -n "${APT_PROXY}" ]] && ! curl --silent "${APT_PROXY}" >/dev/null ; then
  266. echo "Could not reach APT_PROXY server: ${APT_PROXY}"
  267. exit 1
  268. fi
  269. if [[ -n "${WPA_PASSWORD}" && ${#WPA_PASSWORD} -lt 8 || ${#WPA_PASSWORD} -gt 63 ]] ; then
  270. echo "WPA_PASSWORD" must be between 8 and 63 characters
  271. exit 1
  272. fi
  273. if [[ "${PUBKEY_ONLY_SSH}" = "1" && -z "${PUBKEY_SSH_FIRST_USER}" ]]; then
  274. echo "Must set 'PUBKEY_SSH_FIRST_USER' to a valid SSH public key if using PUBKEY_ONLY_SSH"
  275. exit 1
  276. fi
  277. mkdir -p "${WORK_DIR}"
  278. log "Begin ${BASE_DIR}"
  279. STAGE_LIST=${STAGE_LIST:-${BASE_DIR}/stage*}
  280. for STAGE_DIR in $STAGE_LIST; do
  281. STAGE_DIR=$(realpath "${STAGE_DIR}")
  282. run_stage
  283. done
  284. CLEAN=1
  285. for EXPORT_DIR in ${EXPORT_DIRS}; do
  286. STAGE_DIR=${BASE_DIR}/export-image
  287. # shellcheck source=/dev/null
  288. source "${EXPORT_DIR}/EXPORT_IMAGE"
  289. EXPORT_ROOTFS_DIR=${WORK_DIR}/$(basename "${EXPORT_DIR}")/rootfs
  290. if [ "${USE_QCOW2}" = "1" ]; then
  291. USE_QCOW2=0
  292. EXPORT_NAME="${IMG_FILENAME}${IMG_SUFFIX}"
  293. echo "------------------------------------------------------------------------"
  294. echo "Running export stage for ${EXPORT_NAME}"
  295. rm -f "${WORK_DIR}/export-image/${EXPORT_NAME}.img" || true
  296. rm -f "${WORK_DIR}/export-image/${EXPORT_NAME}.qcow2" || true
  297. rm -f "${WORK_DIR}/${EXPORT_NAME}.img" || true
  298. rm -f "${WORK_DIR}/${EXPORT_NAME}.qcow2" || true
  299. EXPORT_STAGE=$(basename "${EXPORT_DIR}")
  300. for s in $STAGE_LIST; do
  301. TMP_LIST=${TMP_LIST:+$TMP_LIST }$(basename "${s}")
  302. done
  303. FIRST_STAGE=${TMP_LIST%% *}
  304. FIRST_IMAGE="image-${FIRST_STAGE}.qcow2"
  305. pushd "${WORK_DIR}" > /dev/null
  306. echo "Creating new base "${EXPORT_NAME}.qcow2" from ${FIRST_IMAGE}"
  307. cp "./${FIRST_IMAGE}" "${EXPORT_NAME}.qcow2"
  308. ARR=($TMP_LIST)
  309. # rebase stage images to new export base
  310. for CURR_STAGE in "${ARR[@]}"; do
  311. if [ "${CURR_STAGE}" = "${FIRST_STAGE}" ]; then
  312. PREV_IMG="${EXPORT_NAME}"
  313. continue
  314. fi
  315. echo "Rebasing image-${CURR_STAGE}.qcow2 onto ${PREV_IMG}.qcow2"
  316. qemu-img rebase -f qcow2 -u -b ${PREV_IMG}.qcow2 image-${CURR_STAGE}.qcow2
  317. if [ "${CURR_STAGE}" = "${EXPORT_STAGE}" ]; then
  318. break
  319. fi
  320. PREV_IMG="image-${CURR_STAGE}"
  321. done
  322. # commit current export stage into base export image
  323. echo "Committing image-${EXPORT_STAGE}.qcow2 to ${EXPORT_NAME}.qcow2"
  324. qemu-img commit -f qcow2 -p -b "${EXPORT_NAME}.qcow2" image-${EXPORT_STAGE}.qcow2
  325. # rebase stage images back to original first stage for easy re-run
  326. for CURR_STAGE in "${ARR[@]}"; do
  327. if [ "${CURR_STAGE}" = "${FIRST_STAGE}" ]; then
  328. PREV_IMG="image-${CURR_STAGE}"
  329. continue
  330. fi
  331. echo "Rebasing back image-${CURR_STAGE}.qcow2 onto ${PREV_IMG}.qcow2"
  332. qemu-img rebase -f qcow2 -u -b ${PREV_IMG}.qcow2 image-${CURR_STAGE}.qcow2
  333. if [ "${CURR_STAGE}" = "${EXPORT_STAGE}" ]; then
  334. break
  335. fi
  336. PREV_IMG="image-${CURR_STAGE}"
  337. done
  338. popd > /dev/null
  339. mkdir -p "${WORK_DIR}/export-image/rootfs"
  340. mv "${WORK_DIR}/${EXPORT_NAME}.qcow2" "${WORK_DIR}/export-image/"
  341. echo "Mounting image ${WORK_DIR}/export-image/${EXPORT_NAME}.qcow2 to rootfs ${WORK_DIR}/export-image/rootfs"
  342. mount_qimage "${WORK_DIR}/export-image/${EXPORT_NAME}.qcow2" "${WORK_DIR}/export-image/rootfs"
  343. CLEAN=0
  344. run_stage
  345. CLEAN=1
  346. USE_QCOW2=1
  347. else
  348. run_stage
  349. fi
  350. if [ "${USE_QEMU}" != "1" ]; then
  351. if [ -e "${EXPORT_DIR}/EXPORT_NOOBS" ]; then
  352. # shellcheck source=/dev/null
  353. source "${EXPORT_DIR}/EXPORT_NOOBS"
  354. STAGE_DIR="${BASE_DIR}/export-noobs"
  355. if [ "${USE_QCOW2}" = "1" ]; then
  356. USE_QCOW2=0
  357. run_stage
  358. USE_QCOW2=1
  359. else
  360. run_stage
  361. fi
  362. fi
  363. fi
  364. done
  365. if [ -x postrun.sh ]; then
  366. log "Begin postrun.sh"
  367. cd "${BASE_DIR}"
  368. ./postrun.sh
  369. log "End postrun.sh"
  370. fi
  371. if [ "${USE_QCOW2}" = "1" ]; then
  372. unload_qimage
  373. fi
  374. log "End ${BASE_DIR}"