isar-bootstrap.inc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. # Minimal debian root file system
  2. #
  3. # This software is a part of ISAR.
  4. # Copyright (c) Siemens AG, 2018
  5. #
  6. # SPDX-License-Identifier: MIT
  7. LICENSE = "gpl-2.0"
  8. LIC_FILES_CHKSUM = "file://${LAYERDIR_core}/licenses/COPYING.GPLv2;md5=751419260aa954499f7abaabaa882bbe"
  9. FILESPATH_prepend := "${THISDIR}/files:"
  10. SRC_URI = " \
  11. file://isar-apt.conf \
  12. file://isar-apt-fallback.conf \
  13. file://locale \
  14. file://chroot-setup.sh"
  15. PV = "1.0"
  16. DEBOOTSTRAP ?= "qemu-debootstrap"
  17. ROOTFSDIR = "${WORKDIR}/rootfs"
  18. APTPREFS = "${WORKDIR}/apt-preferences"
  19. APTSRCS = "${WORKDIR}/apt-sources"
  20. APTSRCS_INIT = "${WORKDIR}/apt-sources-init"
  21. DISTRO_BOOTSTRAP_KEYFILES = ""
  22. THIRD_PARTY_APT_KEYFILES = ""
  23. DEPLOY_ISAR_BOOTSTRAP ?= ""
  24. DISTRO_BOOTSTRAP_BASE_PACKAGES = "locales"
  25. DISTRO_BOOTSTRAP_BASE_PACKAGES_append_gnupg = ",gnupg"
  26. DISTRO_BOOTSTRAP_BASE_PACKAGES_append_https-support = "${@https_support(d)}"
  27. inherit deb-dl-dir
  28. python () {
  29. distro_bootstrap_keys = (d.getVar("DISTRO_BOOTSTRAP_KEYS") or "").split()
  30. third_party_apt_keys = (d.getVar("THIRD_PARTY_APT_KEYS") or "").split()
  31. # The cached repo key can be both for bootstrapping and apt package
  32. # installation afterwards. However, debootstrap will include the key into
  33. # the rootfs automatically thus the right place is distro_bootstrap_keys.
  34. if bb.utils.to_boolean(d.getVar('ISAR_USE_CACHED_BASE_REPO')):
  35. own_pub_key = d.getVar("BASE_REPO_KEY")
  36. if own_pub_key:
  37. distro_bootstrap_keys += own_pub_key.split()
  38. for key in distro_bootstrap_keys:
  39. d.appendVar("SRC_URI", " %s" % key)
  40. fetcher = bb.fetch2.Fetch([key], d)
  41. filename = fetcher.localpath(key)
  42. d.appendVar("DISTRO_BOOTSTRAP_KEYFILES", " %s" % filename)
  43. for key in third_party_apt_keys:
  44. d.appendVar("SRC_URI", " %s" % key)
  45. fetcher = bb.fetch2.Fetch([key], d)
  46. filename = fetcher.localpath(key)
  47. d.appendVar("THIRD_PARTY_APT_KEYFILES", " %s" % filename)
  48. }
  49. def aggregate_files(d, file_list, file_out):
  50. import shutil
  51. with open(file_out, "wb") as out_fd:
  52. for entry in file_list:
  53. entry_real = bb.parse.resolve_file(entry, d)
  54. with open(entry_real, "rb") as in_fd:
  55. shutil.copyfileobj(in_fd, out_fd, 1024*1024*10)
  56. out_fd.write("\n".encode())
  57. def parse_aptsources_list_line(source_list_line):
  58. import re
  59. s = source_list_line.strip()
  60. if not s or s.startswith("#"):
  61. return None
  62. type, s = re.split("\s+", s, maxsplit=1)
  63. if type not in ["deb", "deb-src"]:
  64. return None
  65. options = ""
  66. options_match = re.match("\[\s*(\S+=\S+(?=\s))*\s*(\S+=\S+)\s*\]\s+", s)
  67. if options_match:
  68. options = options_match.group(0).strip()
  69. s = s[options_match.end():]
  70. source, s = re.split("\s+", s, maxsplit=1)
  71. if s.startswith("/"):
  72. suite = ""
  73. else:
  74. suite, s = re.split("\s+", s, maxsplit=1)
  75. components = " ".join(s.split())
  76. return [type, options, source, suite, components]
  77. def get_apt_source_mirror(d, aptsources_entry_list):
  78. import re
  79. if bb.utils.to_boolean(d.getVar('ISAR_USE_CACHED_BASE_REPO')):
  80. premirrors = "\S* file://${REPO_BASE_DIR}/${BASE_DISTRO}\n"
  81. else:
  82. premirrors = d.getVar('DISTRO_APT_PREMIRRORS', True) or ""
  83. mirror_list = [entry.split()
  84. for entry in premirrors.split('\\n')
  85. if any(entry)]
  86. for regex, replace in mirror_list:
  87. match = re.search(regex, aptsources_entry_list[2])
  88. if match:
  89. new_aptsources_entry_list = aptsources_entry_list.copy()
  90. new_aptsources_entry_list[2] = re.sub(regex, replace,
  91. aptsources_entry_list[2],
  92. count = 1)
  93. return new_aptsources_entry_list
  94. return aptsources_entry_list
  95. def aggregate_aptsources_list(d, file_list, file_out):
  96. import shutil
  97. with open(file_out, "wb") as out_fd:
  98. for entry in file_list:
  99. entry_real = bb.parse.resolve_file(entry, d)
  100. with open(entry_real, "r") as in_fd:
  101. for line in in_fd:
  102. parsed = parse_aptsources_list_line(line)
  103. if parsed:
  104. parsed = get_apt_source_mirror(d, parsed)
  105. out_fd.write(" ".join(parsed).encode())
  106. else:
  107. out_fd.write(line.encode())
  108. out_fd.write("\n".encode())
  109. out_fd.write("\n".encode())
  110. def get_aptsources_list(d, is_host=False):
  111. if is_host:
  112. apt_sources_list = (d.getVar("HOST_DISTRO_APT_SOURCES", True) or "").split()
  113. else:
  114. apt_sources_list = (d.getVar("DISTRO_APT_SOURCES", True) or "").split()
  115. return apt_sources_list
  116. def generate_distro_sources(d, is_host=False):
  117. apt_sources_list = get_aptsources_list(d, is_host)
  118. for entry in apt_sources_list:
  119. entry_real = bb.parse.resolve_file(entry, d)
  120. with open(entry_real, "r") as in_fd:
  121. for line in in_fd:
  122. parsed = parse_aptsources_list_line(line)
  123. if parsed:
  124. parsed = get_apt_source_mirror(d, parsed)
  125. yield parsed
  126. def get_distro_primary_source_entry(d, is_host=False):
  127. apt_sources_list = get_aptsources_list(d, is_host)
  128. for source in generate_distro_sources(d, is_host):
  129. if source[0] == "deb":
  130. return source[2:]
  131. return ["", "", ""]
  132. def get_distro_have_https_source(d, is_host=False):
  133. return any(source[2].startswith("https://") for source in generate_distro_sources(d, is_host))
  134. def https_support(d, is_host=False):
  135. if get_distro_suite(d, is_host) == "stretch":
  136. return ",apt-transport-https,ca-certificates"
  137. else:
  138. return ",ca-certificates"
  139. def get_distro_needs_https_support(d, is_host=False):
  140. if get_distro_have_https_source(d, is_host):
  141. return "https-support"
  142. else:
  143. return ""
  144. def get_distro_needs_gpg_support(d):
  145. apt_keys = d.getVar("DISTRO_BOOTSTRAP_KEYS") or ""
  146. apt_keys += " " + (d.getVar("THIRD_PARTY_APT_KEYS") or "")
  147. apt_keys += " " + (d.getVar("BASE_REPO_KEY") or "")
  148. if apt_keys != " ":
  149. return "gnupg"
  150. return ""
  151. OVERRIDES_append = ":${@get_distro_needs_gpg_support(d)}"
  152. def get_distro_source(d, is_host):
  153. return get_distro_primary_source_entry(d, is_host)[0]
  154. def get_distro_suite(d, is_host):
  155. return get_distro_primary_source_entry(d, is_host)[1]
  156. def get_distro_components_argument(d, is_host):
  157. components = get_distro_primary_source_entry(d, is_host)[2]
  158. if components and components.strip():
  159. return "--components=" + ",".join(components.split())
  160. else:
  161. return ""
  162. APT_KEYS_DIR = "${WORKDIR}/aptkeys"
  163. DISTRO_BOOTSTRAP_KEYRING = "${WORKDIR}/distro-keyring.gpg"
  164. do_generate_keyrings[cleandirs] = "${APT_KEYS_DIR}"
  165. do_generate_keyrings[dirs] = "${DL_DIR}"
  166. do_generate_keyrings[vardeps] += "DISTRO_BOOTSTRAP_KEYS THIRD_PARTY_APT_KEYS"
  167. do_generate_keyrings() {
  168. if [ -n "${@d.getVar("THIRD_PARTY_APT_KEYFILES", True) or ""}" ]; then
  169. chmod 777 "${APT_KEYS_DIR}"
  170. for keyfile in ${@d.getVar("THIRD_PARTY_APT_KEYFILES", True)}; do
  171. cp "$keyfile" "${APT_KEYS_DIR}"/"$(basename "$keyfile")"
  172. done
  173. fi
  174. if [ -n "${@d.getVar("DISTRO_BOOTSTRAP_KEYFILES", True) or ""}" ]; then
  175. for keyfile in ${@d.getVar("DISTRO_BOOTSTRAP_KEYFILES", True)}; do
  176. sudo apt-key --keyring "${DISTRO_BOOTSTRAP_KEYRING}" add $keyfile
  177. cp "$keyfile" "${APT_KEYS_DIR}"/"$(basename "$keyfile")"
  178. done
  179. fi
  180. }
  181. addtask generate_keyrings before do_build after do_unpack
  182. def get_host_release():
  183. import platform
  184. rel = platform.release()
  185. return rel
  186. do_bootstrap[vardeps] += "DISTRO_APT_PREMIRRORS ISAR_ENABLE_COMPAT_ARCH"
  187. do_bootstrap[dirs] = "${DEPLOY_DIR_BOOTSTRAP}"
  188. do_bootstrap[depends] = "base-apt:do_cache isar-apt:do_cache_config"
  189. isar_bootstrap() {
  190. IS_HOST=""
  191. while true; do
  192. case "$1" in
  193. --host) IS_HOST=1 ;;
  194. -*) bbfatal "$0: invalid option specified: $1" ;;
  195. *) break ;;
  196. esac
  197. shift
  198. done
  199. if [ "${ISAR_ENABLE_COMPAT_ARCH}" = "1" ]; then
  200. if [ -z "${COMPAT_DISTRO_ARCH}" ]; then
  201. bbfatal "${DISTRO_ARCH} does not have a compat arch"
  202. fi
  203. if [ "${@get_distro_suite(d, True)}-${COMPAT_DISTRO_ARCH}" = "stretch-i386" ]; then
  204. bbfatal "compat arch build for stretch-i386 not supported"
  205. fi
  206. fi
  207. debootstrap_args="--verbose --variant=minbase --include=${DISTRO_BOOTSTRAP_BASE_PACKAGES}"
  208. if [ -f "${DISTRO_BOOTSTRAP_KEYRING}" ]; then
  209. debootstrap_args="$debootstrap_args --keyring=${DISTRO_BOOTSTRAP_KEYRING}"
  210. fi
  211. if [ "${ISAR_USE_CACHED_BASE_REPO}" = "1" -a -z "${BASE_REPO_KEY}" ]; then
  212. debootstrap_args="$debootstrap_args --no-check-gpg"
  213. fi
  214. E="${@ isar_export_proxies(d)}"
  215. export IS_HOST debootstrap_args E
  216. sudo rm -rf --one-file-system "${ROOTFSDIR}"
  217. if [ "${IS_HOST}" ];then
  218. deb_dl_dir_import "${ROOTFSDIR}" "${HOST_DISTRO}"
  219. else
  220. deb_dl_dir_import "${ROOTFSDIR}" "${DISTRO}"
  221. fi
  222. sudo -E -s <<'EOSUDO'
  223. set -e
  224. if [ ${IS_HOST} ]; then
  225. ${DEBOOTSTRAP} $debootstrap_args \
  226. ${@get_distro_components_argument(d, True)} \
  227. "${@get_distro_suite(d, True)}" \
  228. "${ROOTFSDIR}" \
  229. "${@get_distro_source(d, True)}" \
  230. ${DISTRO_DEBOOTSTRAP_SCRIPT}
  231. else
  232. ${DEBOOTSTRAP} $debootstrap_args \
  233. --arch="${DISTRO_ARCH}" \
  234. ${@get_distro_components_argument(d, False)} \
  235. "${@get_distro_suite(d, False)}" \
  236. "${ROOTFSDIR}" \
  237. "${@get_distro_source(d, False)}" \
  238. ${DISTRO_DEBOOTSTRAP_SCRIPT}
  239. fi
  240. # Install apt config
  241. mkdir -p "${ROOTFSDIR}/etc/apt/preferences.d"
  242. install -v -m644 "${APTPREFS}" \
  243. "${ROOTFSDIR}/etc/apt/preferences.d/bootstrap"
  244. mkdir -p "${ROOTFSDIR}/etc/apt/sources.list.d"
  245. if [ "${ISAR_USE_CACHED_BASE_REPO}" = "1" ]; then
  246. line="file:///base-apt/${BASE_DISTRO} ${BASE_DISTRO_CODENAME} main"
  247. if [ -z "${BASE_REPO_KEY}" ]; then
  248. line="[trusted=yes] ${line}"
  249. fi
  250. echo "deb ${line}" > "${ROOTFSDIR}/etc/apt/sources.list.d/base-apt.list"
  251. echo "deb-src ${line}" >> "${ROOTFSDIR}/etc/apt/sources.list.d/base-apt.list"
  252. mkdir -p ${ROOTFSDIR}/base-apt
  253. mount --bind ${REPO_BASE_DIR} ${ROOTFSDIR}/base-apt
  254. else
  255. install -v -m644 "${APTSRCS}" \
  256. "${ROOTFSDIR}/etc/apt/sources.list.d/bootstrap.list"
  257. fi
  258. install -v -m644 "${APTSRCS_INIT}" "${ROOTFSDIR}/etc/apt/sources-list"
  259. rm -f "${ROOTFSDIR}/etc/apt/sources.list"
  260. rm -rf "${ROOTFSDIR}/var/lib/apt/lists/"*
  261. mkdir -p "${ROOTFSDIR}/etc/apt/apt.conf.d"
  262. install -v -m644 "${WORKDIR}/isar-apt.conf" \
  263. "${ROOTFSDIR}/etc/apt/apt.conf.d/50isar.conf"
  264. if [ "${@get_distro_needs_gpg_support(d)}" = "gnupg" ]; then
  265. MY_GPGHOME="$(chroot "${ROOTFSDIR}" mktemp -d /tmp/gpghomeXXXXXXXXXX)"
  266. echo "Created temporary directory ${MY_GPGHOME} for gpg-agent"
  267. export GNUPGHOME="${MY_GPGHOME}"
  268. chroot "${ROOTFSDIR}" gpg-agent --daemon
  269. APT_KEY_APPEND="--homedir ${MY_GPGHOME}"
  270. fi
  271. find ${APT_KEYS_DIR}/ -type f | while read keyfile
  272. do
  273. kfn="$(basename $keyfile)"
  274. cp $keyfile "${ROOTFSDIR}/tmp/$kfn"
  275. chroot "${ROOTFSDIR}" /usr/bin/apt-key \
  276. --keyring ${THIRD_PARTY_APT_KEYRING} ${APT_KEY_APPEND} add "/tmp/$kfn"
  277. rm "${ROOTFSDIR}/tmp/$kfn"
  278. done
  279. if [ -d "${MY_GPGHOME}" ]; then
  280. echo "Killing gpg-agent for ${MY_GPGHOME}"
  281. chroot "${ROOTFSDIR}" gpgconf --kill gpg-agent && /bin/rm -rf "${MY_GPGHOME}"
  282. fi
  283. if [ "${@get_distro_suite(d, True)}" = "stretch" ] && [ "${@get_host_release().split('.')[0]}" -lt "4" ]; then
  284. install -v -m644 "${WORKDIR}/isar-apt-fallback.conf" \
  285. "${ROOTFSDIR}/etc/apt/apt.conf.d/55isar-fallback.conf"
  286. fi
  287. # Set locale
  288. install -v -m644 "${WORKDIR}/locale" "${ROOTFSDIR}/etc/locale"
  289. sed -i '/en_US.UTF-8 UTF-8/s/^#//g' "${ROOTFSDIR}/etc/locale.gen"
  290. chroot "${ROOTFSDIR}" /usr/sbin/locale-gen
  291. # setup chroot
  292. install -v -m755 "${WORKDIR}/chroot-setup.sh" "${ROOTFSDIR}/chroot-setup.sh"
  293. "${ROOTFSDIR}/chroot-setup.sh" "setup" "${ROOTFSDIR}"
  294. # update APT
  295. mount --rbind /dev ${ROOTFSDIR}/dev
  296. mount --make-rslave ${ROOTFSDIR}/dev
  297. mount -t proc none ${ROOTFSDIR}/proc
  298. mount --rbind /sys ${ROOTFSDIR}/sys
  299. mount --make-rslave ${ROOTFSDIR}/sys
  300. export DEBIAN_FRONTEND=noninteractive
  301. if [ ${IS_HOST} ]; then
  302. chroot "${ROOTFSDIR}" /usr/bin/dpkg --add-architecture ${DISTRO_ARCH}
  303. fi
  304. if [ "${ISAR_ENABLE_COMPAT_ARCH}" = "1" ]; then
  305. chroot "${ROOTFSDIR}" /usr/bin/dpkg --add-architecture ${COMPAT_DISTRO_ARCH}
  306. fi
  307. chroot "${ROOTFSDIR}" /usr/bin/apt-get update -y
  308. chroot "${ROOTFSDIR}" /usr/bin/apt-get install -y -f
  309. chroot "${ROOTFSDIR}" /usr/bin/apt-get dist-upgrade -y \
  310. -o Debug::pkgProblemResolver=yes
  311. umount -l "${ROOTFSDIR}/dev"
  312. umount -l "${ROOTFSDIR}/proc"
  313. umount -l "${ROOTFSDIR}/sys"
  314. umount -l "${ROOTFSDIR}/base-apt" || true
  315. # Finalize debootstrap by setting the link in deploy
  316. ln -Tfsr "${ROOTFSDIR}" "${DEPLOY_ISAR_BOOTSTRAP}"
  317. EOSUDO
  318. if [ "${IS_HOST}" ];then
  319. deb_dl_dir_export "${ROOTFSDIR}" "${HOST_DISTRO}"
  320. else
  321. deb_dl_dir_export "${ROOTFSDIR}" "${DISTRO}"
  322. fi
  323. }
  324. CLEANFUNCS = "clean_deploy"
  325. clean_deploy() {
  326. rm -f "${DEPLOY_ISAR_BOOTSTRAP}"
  327. }