25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

435 lines
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:-bullseye} # Don't forget to update stage0/prerun.sh
  205. export WPA_ESSID
  206. export WPA_PASSWORD
  207. export WPA_COUNTRY
  208. export ENABLE_SSH="${ENABLE_SSH:-0}"
  209. export PUBKEY_ONLY_SSH="${PUBKEY_ONLY_SSH:-0}"
  210. export LOCALE_DEFAULT="${LOCALE_DEFAULT:-en_GB.UTF-8}"
  211. export KEYBOARD_KEYMAP="${KEYBOARD_KEYMAP:-gb}"
  212. export KEYBOARD_LAYOUT="${KEYBOARD_LAYOUT:-English (UK)}"
  213. export TIMEZONE_DEFAULT="${TIMEZONE_DEFAULT:-Europe/London}"
  214. export GIT_HASH=${GIT_HASH:-"$(git rev-parse HEAD)"}
  215. export PUBKEY_SSH_FIRST_USER
  216. export CLEAN
  217. export IMG_NAME
  218. export APT_PROXY
  219. export STAGE
  220. export STAGE_DIR
  221. export STAGE_WORK_DIR
  222. export PREV_STAGE
  223. export PREV_STAGE_DIR
  224. export ROOTFS_DIR
  225. export PREV_ROOTFS_DIR
  226. export IMG_SUFFIX
  227. export NOOBS_NAME
  228. export NOOBS_DESCRIPTION
  229. export EXPORT_DIR
  230. export EXPORT_ROOTFS_DIR
  231. export QUILT_PATCHES
  232. export QUILT_NO_DIFF_INDEX=1
  233. export QUILT_NO_DIFF_TIMESTAMPS=1
  234. export QUILT_REFRESH_ARGS="-p ab"
  235. # shellcheck source=scripts/common
  236. source "${SCRIPT_DIR}/common"
  237. # shellcheck source=scripts/dependencies_check
  238. source "${SCRIPT_DIR}/dependencies_check"
  239. export NO_PRERUN_QCOW2="${NO_PRERUN_QCOW2:-1}"
  240. export USE_QCOW2="${USE_QCOW2:-0}"
  241. export BASE_QCOW2_SIZE=${BASE_QCOW2_SIZE:-12G}
  242. source "${SCRIPT_DIR}/qcow2_handling"
  243. if [ "${USE_QCOW2}" = "1" ]; then
  244. NO_PRERUN_QCOW2=1
  245. else
  246. NO_PRERUN_QCOW2=0
  247. fi
  248. export NO_PRERUN_QCOW2="${NO_PRERUN_QCOW2:-1}"
  249. if [ "$SETFCAP" != "1" ]; then
  250. export CAPSH_ARG="--drop=cap_setfcap"
  251. fi
  252. dependencies_check "${BASE_DIR}/depends"
  253. #check username is valid
  254. if [[ ! "$FIRST_USER_NAME" =~ ^[a-z][-a-z0-9_]*$ ]]; then
  255. echo "Invalid FIRST_USER_NAME: $FIRST_USER_NAME"
  256. exit 1
  257. fi
  258. if [[ "$DISABLE_FIRST_BOOT_USER_RENAME" == "1" ]] && [ -z "${FIRST_USER_PASS}" ]; then
  259. echo "To disable user rename on first boot, FIRST_USER_PASS needs to be set"
  260. echo "Not setting FIRST_USER_PASS makes your system vulnerable and open to cyberattacks"
  261. exit 1
  262. fi
  263. if [[ "$DISABLE_FIRST_BOOT_USER_RENAME" == "1" ]]; then
  264. echo "User rename on the first boot is disabled"
  265. echo "Be advised of the security risks linked to shipping a device with default username/password set."
  266. fi
  267. if [[ -n "${APT_PROXY}" ]] && ! curl --silent "${APT_PROXY}" >/dev/null ; then
  268. echo "Could not reach APT_PROXY server: ${APT_PROXY}"
  269. exit 1
  270. fi
  271. if [[ -n "${WPA_PASSWORD}" && ${#WPA_PASSWORD} -lt 8 || ${#WPA_PASSWORD} -gt 63 ]] ; then
  272. echo "WPA_PASSWORD" must be between 8 and 63 characters
  273. exit 1
  274. fi
  275. if [[ "${PUBKEY_ONLY_SSH}" = "1" && -z "${PUBKEY_SSH_FIRST_USER}" ]]; then
  276. echo "Must set 'PUBKEY_SSH_FIRST_USER' to a valid SSH public key if using PUBKEY_ONLY_SSH"
  277. exit 1
  278. fi
  279. mkdir -p "${WORK_DIR}"
  280. log "Begin ${BASE_DIR}"
  281. STAGE_LIST=${STAGE_LIST:-${BASE_DIR}/stage*}
  282. for STAGE_DIR in $STAGE_LIST; do
  283. STAGE_DIR=$(realpath "${STAGE_DIR}")
  284. run_stage
  285. done
  286. CLEAN=1
  287. for EXPORT_DIR in ${EXPORT_DIRS}; do
  288. STAGE_DIR=${BASE_DIR}/export-image
  289. # shellcheck source=/dev/null
  290. source "${EXPORT_DIR}/EXPORT_IMAGE"
  291. EXPORT_ROOTFS_DIR=${WORK_DIR}/$(basename "${EXPORT_DIR}")/rootfs
  292. if [ "${USE_QCOW2}" = "1" ]; then
  293. USE_QCOW2=0
  294. EXPORT_NAME="${IMG_FILENAME}${IMG_SUFFIX}"
  295. echo "------------------------------------------------------------------------"
  296. echo "Running export stage for ${EXPORT_NAME}"
  297. rm -f "${WORK_DIR}/export-image/${EXPORT_NAME}.img" || true
  298. rm -f "${WORK_DIR}/export-image/${EXPORT_NAME}.qcow2" || true
  299. rm -f "${WORK_DIR}/${EXPORT_NAME}.img" || true
  300. rm -f "${WORK_DIR}/${EXPORT_NAME}.qcow2" || true
  301. EXPORT_STAGE=$(basename "${EXPORT_DIR}")
  302. for s in $STAGE_LIST; do
  303. TMP_LIST=${TMP_LIST:+$TMP_LIST }$(basename "${s}")
  304. done
  305. FIRST_STAGE=${TMP_LIST%% *}
  306. FIRST_IMAGE="image-${FIRST_STAGE}.qcow2"
  307. pushd "${WORK_DIR}" > /dev/null
  308. echo "Creating new base "${EXPORT_NAME}.qcow2" from ${FIRST_IMAGE}"
  309. cp "./${FIRST_IMAGE}" "${EXPORT_NAME}.qcow2"
  310. ARR=($TMP_LIST)
  311. # rebase stage images to new export base
  312. for CURR_STAGE in "${ARR[@]}"; do
  313. if [ "${CURR_STAGE}" = "${FIRST_STAGE}" ]; then
  314. PREV_IMG="${EXPORT_NAME}"
  315. continue
  316. fi
  317. echo "Rebasing image-${CURR_STAGE}.qcow2 onto ${PREV_IMG}.qcow2"
  318. qemu-img rebase -f qcow2 -u -b ${PREV_IMG}.qcow2 image-${CURR_STAGE}.qcow2
  319. if [ "${CURR_STAGE}" = "${EXPORT_STAGE}" ]; then
  320. break
  321. fi
  322. PREV_IMG="image-${CURR_STAGE}"
  323. done
  324. # commit current export stage into base export image
  325. echo "Committing image-${EXPORT_STAGE}.qcow2 to ${EXPORT_NAME}.qcow2"
  326. qemu-img commit -f qcow2 -p -b "${EXPORT_NAME}.qcow2" image-${EXPORT_STAGE}.qcow2
  327. # rebase stage images back to original first stage for easy re-run
  328. for CURR_STAGE in "${ARR[@]}"; do
  329. if [ "${CURR_STAGE}" = "${FIRST_STAGE}" ]; then
  330. PREV_IMG="image-${CURR_STAGE}"
  331. continue
  332. fi
  333. echo "Rebasing back image-${CURR_STAGE}.qcow2 onto ${PREV_IMG}.qcow2"
  334. qemu-img rebase -f qcow2 -u -b ${PREV_IMG}.qcow2 image-${CURR_STAGE}.qcow2
  335. if [ "${CURR_STAGE}" = "${EXPORT_STAGE}" ]; then
  336. break
  337. fi
  338. PREV_IMG="image-${CURR_STAGE}"
  339. done
  340. popd > /dev/null
  341. mkdir -p "${WORK_DIR}/export-image/rootfs"
  342. mv "${WORK_DIR}/${EXPORT_NAME}.qcow2" "${WORK_DIR}/export-image/"
  343. echo "Mounting image ${WORK_DIR}/export-image/${EXPORT_NAME}.qcow2 to rootfs ${WORK_DIR}/export-image/rootfs"
  344. mount_qimage "${WORK_DIR}/export-image/${EXPORT_NAME}.qcow2" "${WORK_DIR}/export-image/rootfs"
  345. CLEAN=0
  346. run_stage
  347. CLEAN=1
  348. USE_QCOW2=1
  349. else
  350. run_stage
  351. fi
  352. if [ "${USE_QEMU}" != "1" ]; then
  353. if [ -e "${EXPORT_DIR}/EXPORT_NOOBS" ]; then
  354. # shellcheck source=/dev/null
  355. source "${EXPORT_DIR}/EXPORT_NOOBS"
  356. STAGE_DIR="${BASE_DIR}/export-noobs"
  357. if [ "${USE_QCOW2}" = "1" ]; then
  358. USE_QCOW2=0
  359. run_stage
  360. USE_QCOW2=1
  361. else
  362. run_stage
  363. fi
  364. fi
  365. fi
  366. done
  367. if [ -x postrun.sh ]; then
  368. log "Begin postrun.sh"
  369. cd "${BASE_DIR}"
  370. ./postrun.sh
  371. log "End postrun.sh"
  372. fi
  373. if [ "${USE_QCOW2}" = "1" ]; then
  374. unload_qimage
  375. fi
  376. log "End ${BASE_DIR}"