From acd9814a5cd1a04b37a1c1c913c8448c6374db0d Mon Sep 17 00:00:00 2001 From: amy Date: Fri, 22 Oct 2021 19:42:30 +0200 Subject: [PATCH] updated mkarchiso, can now build isos, bootstrap tarballs and netboot images --- chrooted.sh | 2 +- crystal/airootfs/etc/buildstamp | 2 +- crystal/airootfs/etc/packages.x86_64 | 7 +- crystal/airootfs/etc/pacman.d/mirrorlist | 772 ++++++++++++++++++++- crystal/bootstrap_packages.x86_64 | 30 + mkarchiso | 820 ++++++++++++++++------- 6 files changed, 1352 insertions(+), 281 deletions(-) create mode 100644 crystal/bootstrap_packages.x86_64 diff --git a/chrooted.sh b/chrooted.sh index 1d8ee5d..723c962 100644 --- a/chrooted.sh +++ b/chrooted.sh @@ -12,7 +12,7 @@ chmod +x /usr/bin/mirrorsetup useradd -m crystal usermod -p $(echo "crystal" | openssl passwd -6 -stdin) crystal usermod -p $(echo "crystal" | openssl passwd -6 -stdin) root -chsh -s $(which zsh) crystal +chsh -s /usr/bin/zsh crystal cat >> /home/crystal/.zshrc << EOF PROMPT="%n@%m %~ %# " diff --git a/crystal/airootfs/etc/buildstamp b/crystal/airootfs/etc/buildstamp index b9482d3..d4be9d8 100644 --- a/crystal/airootfs/etc/buildstamp +++ b/crystal/airootfs/etc/buildstamp @@ -1 +1 @@ -Built on 09/12/21 @ 18:36:50 EST +Built on 10/22/21 @ 19:15:37 EST diff --git a/crystal/airootfs/etc/packages.x86_64 b/crystal/airootfs/etc/packages.x86_64 index b15ac1b..4803304 100644 --- a/crystal/airootfs/etc/packages.x86_64 +++ b/crystal/airootfs/etc/packages.x86_64 @@ -15,13 +15,16 @@ curl openbsd-netcat memtest86+ edk2-shell +sudo +dosfstools +systemd-sysvcompat +cowsay # Things we're hosting arch-install-scripts ame base filesystem -crystal-cli-boot -crystal-branding citrine neofetch +pfetch diff --git a/crystal/airootfs/etc/pacman.d/mirrorlist b/crystal/airootfs/etc/pacman.d/mirrorlist index 9ecf79e..3bcb069 100644 --- a/crystal/airootfs/etc/pacman.d/mirrorlist +++ b/crystal/airootfs/etc/pacman.d/mirrorlist @@ -1,30 +1,742 @@ -################################################################################ -################# Arch Linux mirrorlist generated by Reflector ################# -################################################################################ - -# With: reflector @/etc/xdg/reflector/reflector.conf -# When: 2021-05-05 03:24:13 UTC -# From: https://www.archlinux.org/mirrors/status/json/ -# Retrieved: 2021-05-05 03:22:27 UTC -# Last Check: 2021-05-05 03:12:27 UTC - -Server = https://america.mirror.pkgbuild.com/$repo/os/$arch -Server = https://arch.mirror.square-r00t.net/$repo/os/$arch -Server = https://mirror.pkgbuild.com/$repo/os/$arch -Server = https://europe.mirror.pkgbuild.com/$repo/os/$arch -Server = https://mirror.chaoticum.net/arch/$repo/os/$arch -Server = https://archlinux.uk.mirror.allworldit.com/archlinux/$repo/os/$arch -Server = https://mirror.f4st.host/archlinux/$repo/os/$arch -Server = https://mirror.easylee.nl/archlinux/$repo/os/$arch -Server = https://mirror.pseudoform.org/$repo/os/$arch -Server = https://archmirror.it/repos/$repo/os/$arch -Server = https://mirror.telepoint.bg/archlinux/$repo/os/$arch -Server = https://asia.mirror.pkgbuild.com/$repo/os/$arch -Server = https://archlinux.thaller.ws/$repo/os/$arch -Server = https://mirror.csclub.uwaterloo.ca/archlinux/$repo/os/$arch -Server = https://mirror.lty.me/archlinux/$repo/os/$arch -Server = https://ftp.sh.cvut.cz/arch/$repo/os/$arch -Server = https://ftp.halifax.rwth-aachen.de/archlinux/$repo/os/$arch -Server = https://mirrors.neusoft.edu.cn/archlinux/$repo/os/$arch -Server = https://arch.mirror.constant.com/$repo/os/$arch -Server = https://arch.jensgutermuth.de/$repo/os/$arch +## +## Arch Linux repository mirrorlist +## Generated on 2021-05-09 +## + +## Worldwide +#Server = http://mirrors.evowise.com/archlinux/$repo/os/$arch +#Server = http://mirror.rackspace.com/archlinux/$repo/os/$arch +#Server = https://mirror.rackspace.com/archlinux/$repo/os/$arch + +## Australia +#Server = https://mirror.aarnet.edu.au/pub/archlinux/$repo/os/$arch +#Server = http://archlinux.mirror.digitalpacific.com.au/$repo/os/$arch +#Server = https://archlinux.mirror.digitalpacific.com.au/$repo/os/$arch +#Server = http://ftp.iinet.net.au/pub/archlinux/$repo/os/$arch +#Server = http://mirror.internode.on.net/pub/archlinux/$repo/os/$arch +#Server = http://mirror.launtel.net.au/repo/arch/$repo/os/$arch +#Server = https://mirror.launtel.net.au/repo/arch/$repo/os/$arch +#Server = http://arch.lucassymons.net/$repo/os/$arch +#Server = https://arch.lucassymons.net/$repo/os/$arch +#Server = http://syd.mirror.rackspace.com/archlinux/$repo/os/$arch +#Server = https://syd.mirror.rackspace.com/archlinux/$repo/os/$arch +#Server = http://ftp.swin.edu.au/archlinux/$repo/os/$arch + +## Austria +#Server = http://mirror.digitalnova.at/archlinux/$repo/os/$arch +#Server = http://mirror.easyname.at/archlinux/$repo/os/$arch +#Server = http://mirror.reisenbauer.ee/archlinux/$repo/os/$arch +#Server = https://mirror.reisenbauer.ee/archlinux/$repo/os/$arch + +## Bangladesh +#Server = http://mirror.xeonbd.com/archlinux/$repo/os/$arch + +## Belarus +#Server = http://ftp.byfly.by/pub/archlinux/$repo/os/$arch +#Server = http://mirror.datacenter.by/pub/archlinux/$repo/os/$arch + +## Belgium +#Server = http://archlinux.cu.be/$repo/os/$arch +#Server = http://archlinux.mirror.kangaroot.net/$repo/os/$arch +#Server = http://mirror.tiguinet.net/arch/$repo/os/$arch + +## Bosnia and Herzegovina +#Server = http://archlinux.mirror.ba/$repo/os/$arch + +## Brazil +#Server = http://br.mirror.archlinux-br.org/$repo/os/$arch +#Server = http://archlinux.c3sl.ufpr.br/$repo/os/$arch +#Server = http://www.caco.ic.unicamp.br/archlinux/$repo/os/$arch +#Server = https://www.caco.ic.unicamp.br/archlinux/$repo/os/$arch +#Server = http://linorg.usp.br/archlinux/$repo/os/$arch +#Server = http://archlinux.pop-es.rnp.br/$repo/os/$arch +#Server = http://mirror.ufam.edu.br/archlinux/$repo/os/$arch +#Server = http://mirror.ufscar.br/archlinux/$repo/os/$arch + +## Bulgaria +#Server = https://mirror.darklinux.uk/archlinux/$repo/os/$arch +#Server = http://mirror.host.ag/archlinux/$repo/os/$arch +#Server = http://mirrors.netix.net/archlinux/$repo/os/$arch +#Server = http://mirror.telepoint.bg/archlinux/$repo/os/$arch +#Server = https://mirror.telepoint.bg/archlinux/$repo/os/$arch +#Server = http://mirrors.uni-plovdiv.net/archlinux/$repo/os/$arch +#Server = https://mirrors.uni-plovdiv.net/archlinux/$repo/os/$arch + +## Canada +#Server = https://mirror.0xem.ma/arch/$repo/os/$arch +#Server = http://mirror.cedille.club/archlinux/$repo/os/$arch +#Server = http://archlinux.mirror.colo-serv.net/$repo/os/$arch +#Server = http://mirror.csclub.uwaterloo.ca/archlinux/$repo/os/$arch +#Server = https://mirror.csclub.uwaterloo.ca/archlinux/$repo/os/$arch +#Server = http://mirror2.evolution-host.com/archlinux/$repo/os/$arch +#Server = https://mirror2.evolution-host.com/archlinux/$repo/os/$arch +#Server = http://mirror.its.dal.ca/archlinux/$repo/os/$arch +#Server = http://muug.ca/mirror/archlinux/$repo/os/$arch +#Server = https://muug.ca/mirror/archlinux/$repo/os/$arch +#Server = http://archlinux.mirror.rafal.ca/$repo/os/$arch +#Server = http://mirror.scd31.com/arch/$repo/os/$arch +#Server = https://mirror.scd31.com/arch/$repo/os/$arch +#Server = http://mirror.sergal.org/archlinux/$repo/os/$arch +#Server = https://mirror.sergal.org/archlinux/$repo/os/$arch + +## Chile +#Server = http://mirror.anquan.cl/archlinux/$repo/os/$arch +#Server = http://mirror.archlinux.cl/$repo/os/$arch +#Server = http://mirror1.cl.netactuate.com/archlinux/$repo/os/$arch +#Server = https://mirror1.cl.netactuate.com/archlinux/$repo/os/$arch +#Server = http://mirror.ufro.cl/archlinux/$repo/os/$arch +#Server = https://mirror.ufro.cl/archlinux/$repo/os/$arch + +## China +#Server = http://mirrors.163.com/archlinux/$repo/os/$arch +#Server = http://mirrors.bfsu.edu.cn/archlinux/$repo/os/$arch +#Server = https://mirrors.bfsu.edu.cn/archlinux/$repo/os/$arch +#Server = http://mirrors.cqu.edu.cn/archlinux/$repo/os/$arch +#Server = https://mirrors.cqu.edu.cn/archlinux/$repo/os/$arch +#Server = http://mirrors.dgut.edu.cn/archlinux/$repo/os/$arch +#Server = https://mirrors.dgut.edu.cn/archlinux/$repo/os/$arch +#Server = http://mirrors.hit.edu.cn/archlinux/$repo/os/$arch +#Server = https://mirrors.hit.edu.cn/archlinux/$repo/os/$arch +#Server = http://mirror.lzu.edu.cn/archlinux/$repo/os/$arch +#Server = http://mirrors.neusoft.edu.cn/archlinux/$repo/os/$arch +#Server = https://mirrors.neusoft.edu.cn/archlinux/$repo/os/$arch +#Server = http://mirrors.nju.edu.cn/archlinux/$repo/os/$arch +#Server = https://mirrors.nju.edu.cn/archlinux/$repo/os/$arch +#Server = http://mirror.redrock.team/archlinux/$repo/os/$arch +#Server = https://mirror.redrock.team/archlinux/$repo/os/$arch +#Server = https://mirrors.sjtug.sjtu.edu.cn/archlinux/$repo/os/$arch +#Server = http://mirrors.tuna.tsinghua.edu.cn/archlinux/$repo/os/$arch +#Server = https://mirrors.tuna.tsinghua.edu.cn/archlinux/$repo/os/$arch +#Server = http://mirrors.ustc.edu.cn/archlinux/$repo/os/$arch +#Server = https://mirrors.ustc.edu.cn/archlinux/$repo/os/$arch +#Server = https://mirrors.xjtu.edu.cn/archlinux/$repo/os/$arch +#Server = http://mirrors.zju.edu.cn/archlinux/$repo/os/$arch + +## Colombia +#Server = http://mirrors.udenar.edu.co/archlinux/$repo/os/$arch + +## Croatia +#Server = http://archlinux.iskon.hr/$repo/os/$arch + +## Czechia +#Server = http://mirror.dkm.cz/archlinux/$repo/os/$arch +#Server = https://mirror.dkm.cz/archlinux/$repo/os/$arch +#Server = https://europe.mirror.pkgbuild.com/$repo/os/$arch +#Server = http://ftp.fi.muni.cz/pub/linux/arch/$repo/os/$arch +#Server = http://ftp.linux.cz/pub/linux/arch/$repo/os/$arch +#Server = http://gluttony.sin.cvut.cz/arch/$repo/os/$arch +#Server = https://gluttony.sin.cvut.cz/arch/$repo/os/$arch +#Server = http://mirrors.nic.cz/archlinux/$repo/os/$arch +#Server = http://ftp.sh.cvut.cz/arch/$repo/os/$arch +#Server = https://ftp.sh.cvut.cz/arch/$repo/os/$arch +#Server = http://mirror.vpsfree.cz/archlinux/$repo/os/$arch + +## Denmark +#Server = http://mirrors.dotsrc.org/archlinux/$repo/os/$arch +#Server = https://mirrors.dotsrc.org/archlinux/$repo/os/$arch +#Server = http://mirror.one.com/archlinux/$repo/os/$arch +#Server = https://mirror.one.com/archlinux/$repo/os/$arch + +## Ecuador +#Server = http://mirror.cedia.org.ec/archlinux/$repo/os/$arch +#Server = http://mirror.espoch.edu.ec/archlinux/$repo/os/$arch +#Server = http://mirror.uta.edu.ec/archlinux/$repo/os/$arch + +## Estonia +#Server = http://mirror.cspacehostings.com/archlinux/$repo/os/$arch +#Server = https://mirror.cspacehostings.com/archlinux/$repo/os/$arch + +## Finland +#Server = https://arch.mcstrugs.org/$repo/os/$arch +#Server = http://arch.mirror.far.fi/$repo/os/$arch +#Server = http://mirror.hosthink.net/archlinux/$repo/os/$arch +#Server = https://mirror.srv.fail/archlinux/$repo/os/$arch +#Server = http://mirror.wuki.li/archlinux/$repo/os/$arch +#Server = https://mirror.wuki.li/archlinux/$repo/os/$arch + +## France +#Server = http://archlinux.de-labrusse.fr/$repo/os/$arch +#Server = http://mirror.archlinux.ikoula.com/archlinux/$repo/os/$arch +#Server = https://archlinux.vi-di.fr/$repo/os/$arch +#Server = http://mirror.arctic.lol/ArchMirror/$repo/os/$arch +#Server = http://archlinux.mirrors.benatherton.com/$repo/os/$arch +#Server = http://mirror.cyberbits.eu/archlinux/$repo/os/$arch +#Server = https://mirror.cyberbits.eu/archlinux/$repo/os/$arch +#Server = http://archlinux.datagr.am/$repo/os/$arch +#Server = https://mirrors.eric.ovh/arch/$repo/os/$arch +#Server = http://mirror.ibcp.fr/pub/archlinux/$repo/os/$arch +#Server = http://mirror.lastmikoi.net/archlinux/$repo/os/$arch +#Server = https://arch-mirror.cloud.louifox.house/$repo/os/$arch +#Server = http://archlinux.mailtunnel.eu/$repo/os/$arch +#Server = https://archlinux.mailtunnel.eu/$repo/os/$arch +#Server = http://mir.archlinux.fr/$repo/os/$arch +#Server = http://mirrors.celianvdb.fr/archlinux/$repo/os/$arch +#Server = https://mirrors.celianvdb.fr/archlinux/$repo/os/$arch +#Server = http://arch.nimukaito.net/$repo/os/$arch +#Server = https://arch.nimukaito.net/$repo/os/$arch +#Server = http://mirror.oldsql.cc/archlinux/$repo/os/$arch +#Server = https://mirror.oldsql.cc/archlinux/$repo/os/$arch +#Server = http://archlinux.mirrors.ovh.net/archlinux/$repo/os/$arch +#Server = http://archlinux.polymorf.fr/$repo/os/$arch +#Server = http://archlinux.rezopole.net/$repo/os/$arch +#Server = https://mirrors.slaanesh.org/archlinux/$repo/os/$arch +#Server = http://mirrors.standaloneinstaller.com/archlinux/$repo/os/$arch +#Server = https://mirror.sysa.tech/archlinux/$repo/os/$arch +#Server = https://mirror.thekinrar.fr/archlinux/$repo/os/$arch +#Server = http://ftp.u-strasbg.fr/linux/distributions/archlinux/$repo/os/$arch +#Server = https://mirror.wormhole.eu/archlinux/$repo/os/$arch +#Server = http://mirroir.wptheme.fr/archlinux/$repo/os/$arch +#Server = https://mirroir.wptheme.fr/archlinux/$repo/os/$arch +#Server = http://arch.yourlabs.org/$repo/os/$arch +#Server = https://arch.yourlabs.org/$repo/os/$arch + +## Georgia +#Server = http://archlinux.grena.ge/$repo/os/$arch +#Server = https://archlinux.grena.ge/$repo/os/$arch + +## Germany +#Server = http://mirror.23media.com/archlinux/$repo/os/$arch +#Server = https://mirror.23media.com/archlinux/$repo/os/$arch +#Server = http://ftp.agdsn.de/pub/mirrors/archlinux/$repo/os/$arch +#Server = https://ftp.agdsn.de/pub/mirrors/archlinux/$repo/os/$arch +#Server = https://appuals.com/archlinux/$repo/os/$arch +#Server = http://artfiles.org/archlinux.org/$repo/os/$arch +#Server = https://mirror.bethselamin.de/$repo/os/$arch +#Server = http://mirror.chaoticum.net/arch/$repo/os/$arch +#Server = https://mirror.chaoticum.net/arch/$repo/os/$arch +#Server = http://mirror.checkdomain.de/archlinux/$repo/os/$arch +#Server = https://mirror.checkdomain.de/archlinux/$repo/os/$arch +#Server = http://mirror.clientvps.com/archlinux/$repo/os/$arch +#Server = https://mirror.clientvps.com/archlinux/$repo/os/$arch +#Server = https://mirror.dogado.de/archlinux/$repo/os/$arch +#Server = http://mirror.f4st.host/archlinux/$repo/os/$arch +#Server = https://mirror.f4st.host/archlinux/$repo/os/$arch +#Server = http://ftp.fau.de/archlinux/$repo/os/$arch +#Server = https://ftp.fau.de/archlinux/$repo/os/$arch +#Server = https://pkg.fef.moe/archlinux/$repo/os/$arch +#Server = https://dist-mirror.fem.tu-ilmenau.de/archlinux/$repo/os/$arch +#Server = http://mirror.fsrv.services/archlinux/$repo/os/$arch +#Server = https://mirror.fsrv.services/archlinux/$repo/os/$arch +#Server = https://mirror.gnomus.de/$repo/os/$arch +#Server = http://www.gutscheindrache.com/mirror/archlinux/$repo/os/$arch +#Server = http://ftp.gwdg.de/pub/linux/archlinux/$repo/os/$arch +#Server = http://archlinux.honkgong.info/$repo/os/$arch +#Server = http://ftp.hosteurope.de/mirror/ftp.archlinux.org/$repo/os/$arch +#Server = http://ftp-stud.hs-esslingen.de/pub/Mirrors/archlinux/$repo/os/$arch +#Server = http://archlinux.mirror.iphh.net/$repo/os/$arch +#Server = http://arch.jensgutermuth.de/$repo/os/$arch +#Server = https://arch.jensgutermuth.de/$repo/os/$arch +#Server = http://mirror.kumi.systems/archlinux/$repo/os/$arch +#Server = https://mirror.kumi.systems/archlinux/$repo/os/$arch +#Server = http://mirror.fra10.de.leaseweb.net/archlinux/$repo/os/$arch +#Server = https://mirror.fra10.de.leaseweb.net/archlinux/$repo/os/$arch +#Server = http://mirror.metalgamer.eu/archlinux/$repo/os/$arch +#Server = https://mirror.metalgamer.eu/archlinux/$repo/os/$arch +#Server = http://mirror.mikrogravitation.org/archlinux/$repo/os/$arch +#Server = https://mirror.mikrogravitation.org/archlinux/$repo/os/$arch +#Server = https://mirror.pkgbuild.com/$repo/os/$arch +#Server = http://mirrors.n-ix.net/archlinux/$repo/os/$arch +#Server = https://mirrors.n-ix.net/archlinux/$repo/os/$arch +#Server = http://mirror.netcologne.de/archlinux/$repo/os/$arch +#Server = https://mirror.netcologne.de/archlinux/$repo/os/$arch +#Server = http://mirrors.niyawe.de/archlinux/$repo/os/$arch +#Server = https://mirrors.niyawe.de/archlinux/$repo/os/$arch +#Server = http://mirror.orbit-os.com/archlinux/$repo/os/$arch +#Server = https://mirror.orbit-os.com/archlinux/$repo/os/$arch +#Server = http://packages.oth-regensburg.de/archlinux/$repo/os/$arch +#Server = https://packages.oth-regensburg.de/archlinux/$repo/os/$arch +#Server = http://phinau.de/arch/$repo/os/$arch +#Server = https://phinau.de/arch/$repo/os/$arch +#Server = https://mirror.pseudoform.org/$repo/os/$arch +#Server = https://www.ratenzahlung.de/mirror/archlinux/$repo/os/$arch +#Server = http://ftp.halifax.rwth-aachen.de/archlinux/$repo/os/$arch +#Server = https://ftp.halifax.rwth-aachen.de/archlinux/$repo/os/$arch +#Server = http://linux.rz.rub.de/archlinux/$repo/os/$arch +#Server = http://mirror.satis-faction.de/archlinux/$repo/os/$arch +#Server = https://mirror.satis-faction.de/archlinux/$repo/os/$arch +#Server = http://mirror.selfnet.de/archlinux/$repo/os/$arch +#Server = https://mirror.selfnet.de/archlinux/$repo/os/$arch +#Server = http://ftp.spline.inf.fu-berlin.de/mirrors/archlinux/$repo/os/$arch +#Server = https://ftp.spline.inf.fu-berlin.de/mirrors/archlinux/$repo/os/$arch +#Server = http://archlinux.thaller.ws/$repo/os/$arch +#Server = https://archlinux.thaller.ws/$repo/os/$arch +#Server = http://ftp.tu-chemnitz.de/pub/linux/archlinux/$repo/os/$arch +#Server = http://mirror.ubrco.de/archlinux/$repo/os/$arch +#Server = https://mirror.ubrco.de/archlinux/$repo/os/$arch +#Server = http://mirror.undisclose.de/archlinux/$repo/os/$arch +#Server = https://mirror.undisclose.de/archlinux/$repo/os/$arch +#Server = http://ftp.uni-bayreuth.de/linux/archlinux/$repo/os/$arch +#Server = http://ftp.uni-hannover.de/archlinux/$repo/os/$arch +#Server = http://ftp.uni-kl.de/pub/linux/archlinux/$repo/os/$arch +#Server = http://mirror.united-gameserver.de/archlinux/$repo/os/$arch +#Server = https://arch.unixpeople.org/$repo/os/$arch +#Server = http://ftp.wrz.de/pub/archlinux/$repo/os/$arch +#Server = https://ftp.wrz.de/pub/archlinux/$repo/os/$arch +#Server = http://mirror.wtnet.de/arch/$repo/os/$arch +#Server = https://mirror.wtnet.de/arch/$repo/os/$arch +#Server = http://mirrors.xtom.de/archlinux/$repo/os/$arch +#Server = https://mirrors.xtom.de/archlinux/$repo/os/$arch +#Server = http://arch.mirror.zachlge.org/$repo/os/$arch +#Server = https://arch.mirror.zachlge.org/$repo/os/$arch + +## Greece +#Server = http://ftp.cc.uoc.gr/mirrors/linux/archlinux/$repo/os/$arch +#Server = https://repo.greeklug.gr/data/pub/linux/archlinux/$repo/os/$arch +#Server = http://mirrors.myaegean.gr/linux/archlinux/$repo/os/$arch +#Server = http://ftp.ntua.gr/pub/linux/archlinux/$repo/os/$arch +#Server = http://ftp.otenet.gr/linux/archlinux/$repo/os/$arch + +## Hong Kong +#Server = https://asia.mirror.pkgbuild.com/$repo/os/$arch +#Server = http://mirror-hk.koddos.net/archlinux/$repo/os/$arch +#Server = https://mirror-hk.koddos.net/archlinux/$repo/os/$arch +#Server = http://hkg.mirror.rackspace.com/archlinux/$repo/os/$arch +#Server = https://hkg.mirror.rackspace.com/archlinux/$repo/os/$arch +#Server = https://arch-mirror.wtako.net/$repo/os/$arch +#Server = http://mirror.xtom.com.hk/archlinux/$repo/os/$arch +#Server = https://mirror.xtom.com.hk/archlinux/$repo/os/$arch + +## Hungary +#Server = http://ftp.energia.mta.hu/pub/mirrors/ftp.archlinux.org/$repo/os/$arch +#Server = http://archmirror.hbit.sztaki.hu/archlinux/$repo/os/$arch +#Server = http://nova.quantum-mirror.hu/mirrors/pub/archlinux/$repo/os/$arch +#Server = http://quantum-mirror.hu/mirrors/pub/archlinux/$repo/os/$arch +#Server = http://super.quantum-mirror.hu/mirrors/pub/archlinux/$repo/os/$arch +#Server = https://nova.quantum-mirror.hu/mirrors/pub/archlinux/$repo/os/$arch +#Server = https://quantum-mirror.hu/mirrors/pub/archlinux/$repo/os/$arch +#Server = https://super.quantum-mirror.hu/mirrors/pub/archlinux/$repo/os/$arch + +## Iceland +#Server = http://mirror.system.is/arch/$repo/os/$arch +#Server = https://mirror.system.is/arch/$repo/os/$arch + +## India +#Server = http://mirror.cse.iitk.ac.in/archlinux/$repo/os/$arch +#Server = http://mirrors.piconets.webwerks.in/archlinux-mirror/$repo/os/$arch +#Server = https://mirrors.piconets.webwerks.in/archlinux-mirror/$repo/os/$arch + +## Indonesia +#Server = http://mirror.cloudweeb.com/archlinux/$repo/os/$arch +#Server = http://mirror.faizuladib.com/archlinux/$repo/os/$arch +#Server = http://mirror.gi.co.id/archlinux/$repo/os/$arch +#Server = https://mirror.gi.co.id/archlinux/$repo/os/$arch +#Server = http://vpsmurah.jagoanhosting.com/archlinux/$repo/os/$arch +#Server = https://vpsmurah.jagoanhosting.com/archlinux/$repo/os/$arch +#Server = http://mirror.labkom.id/archlinux/$repo/os/$arch +#Server = http://mirror.papua.go.id/archlinux/$repo/os/$arch +#Server = https://mirror.papua.go.id/archlinux/$repo/os/$arch +#Server = http://mirror.poliwangi.ac.id/archlinux/$repo/os/$arch +#Server = http://suro.ubaya.ac.id/archlinux/$repo/os/$arch +#Server = http://mirror.telkomuniversity.ac.id/archlinux/$repo/os/$arch +#Server = https://mirror.telkomuniversity.ac.id/archlinux/$repo/os/$arch + +## Iran +#Server = http://repo.iut.ac.ir/repo/archlinux/$repo/os/$arch +#Server = http://mirror.nak-mci.ir/arch/$repo/os/$arch +#Server = http://mirror.rasanegar.com/archlinux/$repo/os/$arch +#Server = https://mirror.rasanegar.com/archlinux/$repo/os/$arch + +## Ireland +#Server = http://ftp.heanet.ie/mirrors/ftp.archlinux.org/$repo/os/$arch +#Server = https://ftp.heanet.ie/mirrors/ftp.archlinux.org/$repo/os/$arch + +## Israel +#Server = http://mirror.isoc.org.il/pub/archlinux/$repo/os/$arch +#Server = https://mirror.isoc.org.il/pub/archlinux/$repo/os/$arch +#Server = https://archlinux.mivzakim.net/$repo/os/$arch + +## Italy +#Server = https://archmirror.it/repos/$repo/os/$arch +#Server = http://archlinux.mirror.garr.it/archlinux/$repo/os/$arch +#Server = http://mirrors.prometeus.net/archlinux/$repo/os/$arch +#Server = http://archlinux.mirror.server24.net/$repo/os/$arch +#Server = https://archlinux.mirror.server24.net/$repo/os/$arch + +## Japan +#Server = http://mirrors.cat.net/archlinux/$repo/os/$arch +#Server = https://mirrors.cat.net/archlinux/$repo/os/$arch +#Server = http://ftp.tsukuba.wide.ad.jp/Linux/archlinux/$repo/os/$arch +#Server = http://ftp.jaist.ac.jp/pub/Linux/ArchLinux/$repo/os/$arch +#Server = https://ftp.jaist.ac.jp/pub/Linux/ArchLinux/$repo/os/$arch + +## Kazakhstan +#Server = http://mirror.hoster.kz/archlinux/$repo/os/$arch +#Server = https://mirror.hoster.kz/archlinux/$repo/os/$arch +#Server = http://mirror.ps.kz/archlinux/$repo/os/$arch +#Server = https://mirror.ps.kz/archlinux/$repo/os/$arch + +## Kenya +#Server = http://archlinux.mirror.liquidtelecom.com/$repo/os/$arch +#Server = https://archlinux.mirror.liquidtelecom.com/$repo/os/$arch + +## Latvia +#Server = http://archlinux.koyanet.lv/archlinux/$repo/os/$arch +#Server = https://archlinux.koyanet.lv/archlinux/$repo/os/$arch + +## Lithuania +#Server = http://mirrors.atviras.lt/archlinux/$repo/os/$arch +#Server = https://mirrors.atviras.lt/archlinux/$repo/os/$arch +#Server = http://mirrors.ims.nksc.lt/archlinux/$repo/os/$arch +#Server = https://mirrors.ims.nksc.lt/archlinux/$repo/os/$arch + +## Luxembourg +#Server = http://archlinux.mirror.root.lu/$repo/os/$arch + +## Mexico +#Server = https://arch.mirror.jsc.mx/$repo/os/$arch + +## Moldova +#Server = http://mirror.ihost.md/archlinux/$repo/os/$arch +#Server = https://mirror.ihost.md/archlinux/$repo/os/$arch + +## Monaco +#Server = http://archlinux.qontinuum.space/$repo/os/$arch +#Server = https://archlinux.qontinuum.space:4443/$repo/os/$arch + +## Netherlands +#Server = https://archlinux.beccacervello.it/archlinux/$repo/os/$arch +#Server = http://mirror.cj2.nl/archlinux/$repo/os/$arch +#Server = https://mirror.cj2.nl/archlinux/$repo/os/$arch +#Server = https://mirrors.daan.vodka/archlinux/$repo/os/$arch +#Server = http://mirror.easylee.nl/archlinux/$repo/os/$arch +#Server = https://mirror.easylee.nl/archlinux/$repo/os/$arch +#Server = http://mirror.i3d.net/pub/archlinux/$repo/os/$arch +#Server = https://mirror.i3d.net/pub/archlinux/$repo/os/$arch +#Server = https://arch.jeweet.net/$repo/os/$arch +#Server = http://mirror.koddos.net/archlinux/$repo/os/$arch +#Server = https://mirror.koddos.net/archlinux/$repo/os/$arch +#Server = http://arch.mirrors.lavatech.top/$repo/os/$arch +#Server = https://arch.mirrors.lavatech.top/$repo/os/$arch +#Server = http://mirror.ams1.nl.leaseweb.net/archlinux/$repo/os/$arch +#Server = https://mirror.ams1.nl.leaseweb.net/archlinux/$repo/os/$arch +#Server = http://archlinux.mirror.liteserver.nl/$repo/os/$arch +#Server = https://archlinux.mirror.liteserver.nl/$repo/os/$arch +#Server = http://mirror.lyrahosting.com/archlinux/$repo/os/$arch +#Server = https://mirror.lyrahosting.com/archlinux/$repo/os/$arch +#Server = http://mirror.mijn.host/archlinux/$repo/os/$arch +#Server = https://mirror.mijn.host/archlinux/$repo/os/$arch +#Server = http://mirror.neostrada.nl/archlinux/$repo/os/$arch +#Server = https://mirror.neostrada.nl/archlinux/$repo/os/$arch +#Server = http://ftp.nluug.nl/os/Linux/distr/archlinux/$repo/os/$arch +#Server = http://archlinux.mirror.pcextreme.nl/$repo/os/$arch +#Server = https://archlinux.mirror.pcextreme.nl/$repo/os/$arch +#Server = http://mirror.serverion.com/archlinux/$repo/os/$arch +#Server = https://mirror.serverion.com/archlinux/$repo/os/$arch +#Server = http://ftp.snt.utwente.nl/pub/os/linux/archlinux/$repo/os/$arch +#Server = http://mirror.tarellia.net/distr/archlinux/$repo/os/$arch +#Server = https://mirror.tarellia.net/distr/archlinux/$repo/os/$arch +#Server = http://archlinux.mirror.wearetriple.com/$repo/os/$arch +#Server = https://archlinux.mirror.wearetriple.com/$repo/os/$arch +#Server = http://mirror-archlinux.webruimtehosting.nl/$repo/os/$arch +#Server = https://mirror-archlinux.webruimtehosting.nl/$repo/os/$arch +#Server = http://mirrors.xtom.nl/archlinux/$repo/os/$arch +#Server = https://mirrors.xtom.nl/archlinux/$repo/os/$arch + +## New Caledonia +#Server = http://mirror.lagoon.nc/pub/archlinux/$repo/os/$arch +#Server = http://archlinux.nautile.nc/archlinux/$repo/os/$arch +#Server = https://archlinux.nautile.nc/archlinux/$repo/os/$arch + +## New Zealand +#Server = http://mirror.fsmg.org.nz/archlinux/$repo/os/$arch +#Server = https://mirror.fsmg.org.nz/archlinux/$repo/os/$arch +#Server = http://mirror.smith.geek.nz/archlinux/$repo/os/$arch +#Server = https://mirror.smith.geek.nz/archlinux/$repo/os/$arch + +## North Macedonia +#Server = http://arch.softver.org.mk/archlinux/$repo/os/$arch +#Server = http://mirror.onevip.mk/archlinux/$repo/os/$arch +#Server = http://mirror.t-home.mk/archlinux/$repo/os/$arch +#Server = https://mirror.t-home.mk/archlinux/$repo/os/$arch + +## Norway +#Server = http://mirror.archlinux.no/$repo/os/$arch +#Server = https://mirror.archlinux.no/$repo/os/$arch +#Server = http://archlinux.uib.no/$repo/os/$arch +#Server = http://mirror.neuf.no/archlinux/$repo/os/$arch +#Server = https://mirror.neuf.no/archlinux/$repo/os/$arch +#Server = http://mirror.terrahost.no/linux/archlinux/$repo/os/$arch + +## Pakistan +#Server = http://repo.inara.pk/archlinux/$repo/os/$arch +#Server = https://repo.inara.pk/archlinux/$repo/os/$arch + +## Paraguay +#Server = http://archlinux.mirror.py/archlinux/$repo/os/$arch + +## Poland +#Server = http://ftp.icm.edu.pl/pub/Linux/dist/archlinux/$repo/os/$arch +#Server = https://ftp.icm.edu.pl/pub/Linux/dist/archlinux/$repo/os/$arch +#Server = http://mirror.juniorjpdj.pl/archlinux/$repo/os/$arch +#Server = https://mirror.juniorjpdj.pl/archlinux/$repo/os/$arch +#Server = http://arch.midov.pl/arch/$repo/os/$arch +#Server = https://arch.midov.pl/arch/$repo/os/$arch +#Server = http://arch.nixlab.pl/$repo/os/$arch +#Server = https://arch.nixlab.pl/$repo/os/$arch +#Server = http://mirror.onet.pl/pub/mirrors/archlinux/$repo/os/$arch +#Server = http://piotrkosoft.net/pub/mirrors/ftp.archlinux.org/$repo/os/$arch +#Server = http://mirror.sfinae.tech/pub/mirrors/archlinux/$repo/os/$arch +#Server = https://mirror.sfinae.tech/pub/mirrors/archlinux/$repo/os/$arch +#Server = http://repo.skni.umcs.pl/archlinux/$repo/os/$arch +#Server = https://repo.skni.umcs.pl/archlinux/$repo/os/$arch +#Server = http://ftp.vectranet.pl/archlinux/$repo/os/$arch + +## Portugal +#Server = http://glua.ua.pt/pub/archlinux/$repo/os/$arch +#Server = https://glua.ua.pt/pub/archlinux/$repo/os/$arch +#Server = http://ftp.rnl.tecnico.ulisboa.pt/pub/archlinux/$repo/os/$arch +#Server = https://ftp.rnl.tecnico.ulisboa.pt/pub/archlinux/$repo/os/$arch + +## Romania +#Server = http://mirrors.chroot.ro/archlinux/$repo/os/$arch +#Server = https://mirrors.chroot.ro/archlinux/$repo/os/$arch +#Server = http://mirror.efect.ro/archlinux/$repo/os/$arch +#Server = https://mirror.efect.ro/archlinux/$repo/os/$arch +#Server = http://mirrors.go.ro/archlinux/$repo/os/$arch +#Server = https://mirrors.go.ro/archlinux/$repo/os/$arch +#Server = http://mirrors.hostico.ro/archlinux/$repo/os/$arch +#Server = https://mirrors.hostico.ro/archlinux/$repo/os/$arch +#Server = http://archlinux.mirrors.linux.ro/$repo/os/$arch +#Server = http://mirrors.m247.ro/archlinux/$repo/os/$arch +#Server = http://mirrors.nav.ro/archlinux/$repo/os/$arch +#Server = http://mirrors.nxthost.com/archlinux/$repo/os/$arch +#Server = https://mirrors.nxthost.com/archlinux/$repo/os/$arch +#Server = http://mirrors.pidginhost.com/arch/$repo/os/$arch +#Server = https://mirrors.pidginhost.com/arch/$repo/os/$arch + +## Russia +#Server = http://mirror.surf/archlinux/$repo/os/$arch +#Server = https://mirror.surf/archlinux/$repo/os/$arch +#Server = http://mirror.nw-sys.ru/archlinux/$repo/os/$arch +#Server = https://mirror.nw-sys.ru/archlinux/$repo/os/$arch +#Server = http://mirrors.powernet.com.ru/archlinux/$repo/os/$arch +#Server = http://mirror.rol.ru/archlinux/$repo/os/$arch +#Server = https://mirror.rol.ru/archlinux/$repo/os/$arch +#Server = http://mirror.truenetwork.ru/archlinux/$repo/os/$arch +#Server = https://mirror.truenetwork.ru/archlinux/$repo/os/$arch +#Server = http://mirror.yandex.ru/archlinux/$repo/os/$arch +#Server = https://mirror.yandex.ru/archlinux/$repo/os/$arch +#Server = http://archlinux.zepto.cloud/$repo/os/$arch + +## Serbia +#Server = http://arch.petarmaric.com/$repo/os/$arch +#Server = http://mirror.pmf.kg.ac.rs/archlinux/$repo/os/$arch + +## Singapore +#Server = http://mirror.0x.sg/archlinux/$repo/os/$arch +#Server = https://mirror.0x.sg/archlinux/$repo/os/$arch +#Server = http://mirror.aktkn.sg/archlinux/$repo/os/$arch +#Server = https://mirror.aktkn.sg/archlinux/$repo/os/$arch +#Server = https://download.nus.edu.sg/mirror/archlinux/$repo/os/$arch +#Server = http://mirror.guillaumea.fr/archlinux/$repo/os/$arch +#Server = https://mirror.guillaumea.fr/archlinux/$repo/os/$arch +#Server = http://mirror.nus.edu.sg/archlinux/$repo/os/$arch + +## Slovakia +#Server = http://mirror.lnx.sk/pub/linux/archlinux/$repo/os/$arch +#Server = https://mirror.lnx.sk/pub/linux/archlinux/$repo/os/$arch +#Server = http://tux.rainside.sk/archlinux/$repo/os/$arch + +## Slovenia +#Server = http://archimonde.ts.si/archlinux/$repo/os/$arch +#Server = https://archimonde.ts.si/archlinux/$repo/os/$arch + +## South Africa +#Server = http://archlinux.za.mirror.allworldit.com/archlinux/$repo/os/$arch +#Server = https://archlinux.za.mirror.allworldit.com/archlinux/$repo/os/$arch +#Server = http://za.mirror.archlinux-br.org/$repo/os/$arch +#Server = http://mirror.is.co.za/mirror/archlinux.org/$repo/os/$arch +#Server = http://arch.opnmirror.co.za/$repo/os/$arch +#Server = https://arch.opnmirror.co.za/$repo/os/$arch +#Server = http://mirrors.urbanwave.co.za/archlinux/$repo/os/$arch +#Server = https://mirrors.urbanwave.co.za/archlinux/$repo/os/$arch + +## South Korea +#Server = http://mirror.anigil.com/archlinux/$repo/os/$arch +#Server = https://mirror.anigil.com/archlinux/$repo/os/$arch +#Server = http://ftp.harukasan.org/archlinux/$repo/os/$arch +#Server = https://ftp.harukasan.org/archlinux/$repo/os/$arch +#Server = http://ftp.lanet.kr/pub/archlinux/$repo/os/$arch +#Server = https://ftp.lanet.kr/pub/archlinux/$repo/os/$arch +#Server = http://mirror.premi.st/archlinux/$repo/os/$arch +#Server = https://mirror.premi.st/archlinux/$repo/os/$arch + +## Spain +#Server = https://mirror.cloroformo.org/archlinux/$repo/os/$arch +#Server = http://mirror.librelabucm.org/archlinux/$repo/os/$arch +#Server = https://mirror.librelabucm.org/archlinux/$repo/os/$arch +#Server = http://ftp.rediris.es/mirror/archlinux/$repo/os/$arch +#Server = http://sharing.thelinuxsect.com/archlinux/$repo/os/$arch + +## Sweden +#Server = http://ftp.acc.umu.se/mirror/archlinux/$repo/os/$arch +#Server = https://ftp.acc.umu.se/mirror/archlinux/$repo/os/$arch +#Server = http://ftpmirror.infania.net/mirror/archlinux/$repo/os/$arch +#Server = http://ftp.lysator.liu.se/pub/archlinux/$repo/os/$arch +#Server = https://ftp.lysator.liu.se/pub/archlinux/$repo/os/$arch +#Server = http://ftp.myrveln.se/pub/linux/archlinux/$repo/os/$arch +#Server = https://ftp.myrveln.se/pub/linux/archlinux/$repo/os/$arch +#Server = https://mirror.osbeck.com/archlinux/$repo/os/$arch +#Server = http://tedwall.se/archlinux/$repo/os/$arch +#Server = https://tedwall.se/archlinux/$repo/os/$arch + +## Switzerland +#Server = http://pkg.adfinis.com/archlinux/$repo/os/$arch +#Server = https://pkg.adfinis.com/archlinux/$repo/os/$arch +#Server = http://mirror.init7.net/archlinux/$repo/os/$arch +#Server = https://mirror.init7.net/archlinux/$repo/os/$arch +#Server = http://mirror.puzzle.ch/archlinux/$repo/os/$arch +#Server = https://mirror.puzzle.ch/archlinux/$repo/os/$arch +#Server = https://theswissbay.ch/archlinux/$repo/os/$arch +#Server = https://mirror.ungleich.ch/mirror/packages/archlinux/$repo/os/$arch + +## Taiwan +#Server = http://archlinux.ccns.ncku.edu.tw/archlinux/$repo/os/$arch +#Server = http://free.nchc.org.tw/arch/$repo/os/$arch +#Server = https://free.nchc.org.tw/arch/$repo/os/$arch +#Server = http://archlinux.cs.nctu.edu.tw/$repo/os/$arch +#Server = http://shadow.ind.ntou.edu.tw/archlinux/$repo/os/$arch +#Server = https://shadow.ind.ntou.edu.tw/archlinux/$repo/os/$arch +#Server = http://ftp.tku.edu.tw/Linux/ArchLinux/$repo/os/$arch +#Server = http://ftp.yzu.edu.tw/Linux/archlinux/$repo/os/$arch +#Server = https://ftp.yzu.edu.tw/Linux/archlinux/$repo/os/$arch + +## Thailand +#Server = http://mirror.kku.ac.th/archlinux/$repo/os/$arch +#Server = https://mirror.kku.ac.th/archlinux/$repo/os/$arch +#Server = http://mirror2.totbb.net/archlinux/$repo/os/$arch + +## Turkey +#Server = http://ftp.linux.org.tr/archlinux/$repo/os/$arch +#Server = http://mirror.veriteknik.net.tr/archlinux/$repo/os/$arch + +## Ukraine +#Server = http://archlinux.ip-connect.vn.ua/$repo/os/$arch +#Server = https://archlinux.ip-connect.vn.ua/$repo/os/$arch +#Server = http://mirror.mirohost.net/archlinux/$repo/os/$arch +#Server = https://mirror.mirohost.net/archlinux/$repo/os/$arch +#Server = http://mirrors.nix.org.ua/linux/archlinux/$repo/os/$arch +#Server = https://mirrors.nix.org.ua/linux/archlinux/$repo/os/$arch + +## United Kingdom +#Server = http://archlinux.uk.mirror.allworldit.com/archlinux/$repo/os/$arch +#Server = https://archlinux.uk.mirror.allworldit.com/archlinux/$repo/os/$arch +#Server = http://mirror.bytemark.co.uk/archlinux/$repo/os/$arch +#Server = https://mirror.bytemark.co.uk/archlinux/$repo/os/$arch +#Server = http://mirrors.gethosted.online/archlinux/$repo/os/$arch +#Server = https://mirrors.gethosted.online/archlinux/$repo/os/$arch +#Server = http://mirrors.manchester.m247.com/arch-linux/$repo/os/$arch +#Server = http://mirrors.melbourne.co.uk/archlinux/$repo/os/$arch +#Server = https://mirrors.melbourne.co.uk/archlinux/$repo/os/$arch +#Server = http://www.mirrorservice.org/sites/ftp.archlinux.org/$repo/os/$arch +#Server = https://www.mirrorservice.org/sites/ftp.archlinux.org/$repo/os/$arch +#Server = http://mirror.netweaver.uk/archlinux/$repo/os/$arch +#Server = https://mirror.netweaver.uk/archlinux/$repo/os/$arch +#Server = http://lon.mirror.rackspace.com/archlinux/$repo/os/$arch +#Server = https://lon.mirror.rackspace.com/archlinux/$repo/os/$arch +#Server = http://arch.serverspace.co.uk/arch/$repo/os/$arch +#Server = http://archlinux.mirrors.uk2.net/$repo/os/$arch +#Server = http://mirrors.ukfast.co.uk/sites/archlinux.org/$repo/os/$arch +#Server = https://mirrors.ukfast.co.uk/sites/archlinux.org/$repo/os/$arch + +## United States +#Server = http://mirrors.acm.wpi.edu/archlinux/$repo/os/$arch +#Server = http://mirrors.advancedhosters.com/archlinux/$repo/os/$arch +#Server = http://mirrors.aggregate.org/archlinux/$repo/os/$arch +#Server = https://america.mirror.pkgbuild.com/$repo/os/$arch +#Server = http://ca.us.mirror.archlinux-br.org/$repo/os/$arch +#Server = http://il.us.mirror.archlinux-br.org/$repo/os/$arch +#Server = http://archlinux.surlyjake.com/archlinux/$repo/os/$arch +#Server = https://archlinux.surlyjake.com/archlinux/$repo/os/$arch +#Server = http://mirror.arizona.edu/archlinux/$repo/os/$arch +#Server = https://mirror.arizona.edu/archlinux/$repo/os/$arch +#Server = http://arlm.tyzoid.com/$repo/os/$arch +#Server = https://arlm.tyzoid.com/$repo/os/$arch +#Server = https://mirror.ava.dev/archlinux/$repo/os/$arch +#Server = http://mirrors.cat.pdx.edu/archlinux/$repo/os/$arch +#Server = http://mirror.cc.columbia.edu/pub/linux/archlinux/$repo/os/$arch +#Server = http://arch.mirror.constant.com/$repo/os/$arch +#Server = https://arch.mirror.constant.com/$repo/os/$arch +#Server = http://mirror.cs.pitt.edu/archlinux/$repo/os/$arch +#Server = http://mirror.cs.vt.edu/pub/ArchLinux/$repo/os/$arch +#Server = http://mirror.cybersecurity.nmt.edu/archlinux/$repo/os/$arch +#Server = https://mirror.cybersecurity.nmt.edu/archlinux/$repo/os/$arch +#Server = http://distro.ibiblio.org/archlinux/$repo/os/$arch +#Server = http://mirror.es.its.nyu.edu/archlinux/$repo/os/$arch +#Server = http://mirror.ette.biz/archlinux/$repo/os/$arch +#Server = https://mirror.ette.biz/archlinux/$repo/os/$arch +#Server = http://mirrors.gigenet.com/archlinux/$repo/os/$arch +#Server = http://www.gtlib.gatech.edu/pub/archlinux/$repo/os/$arch +#Server = http://mirror.hackingand.coffee/arch/$repo/os/$arch +#Server = https://mirror.hackingand.coffee/arch/$repo/os/$arch +#Server = https://mirror.hodgepodge.dev/archlinux/$repo/os/$arch +#Server = http://mirror.hostup.org/archlinux/$repo/os/$arch +#Server = https://mirror.hostup.org/archlinux/$repo/os/$arch +#Server = http://arch.hu.fo/archlinux/$repo/os/$arch +#Server = https://arch.hu.fo/archlinux/$repo/os/$arch +#Server = http://repo.ialab.dsu.edu/archlinux/$repo/os/$arch +#Server = https://repo.ialab.dsu.edu/archlinux/$repo/os/$arch +#Server = http://mirrors.kernel.org/archlinux/$repo/os/$arch +Server = https://mirrors.kernel.org/archlinux/$repo/os/$arch +#Server = http://mirror.dal10.us.leaseweb.net/archlinux/$repo/os/$arch +#Server = http://mirror.mia11.us.leaseweb.net/archlinux/$repo/os/$arch +#Server = http://mirror.sfo12.us.leaseweb.net/archlinux/$repo/os/$arch +#Server = http://mirror.wdc1.us.leaseweb.net/archlinux/$repo/os/$arch +#Server = https://mirror.dal10.us.leaseweb.net/archlinux/$repo/os/$arch +#Server = https://mirror.mia11.us.leaseweb.net/archlinux/$repo/os/$arch +#Server = https://mirror.sfo12.us.leaseweb.net/archlinux/$repo/os/$arch +#Server = https://mirror.wdc1.us.leaseweb.net/archlinux/$repo/os/$arch +#Server = http://mirrors.liquidweb.com/archlinux/$repo/os/$arch +#Server = http://mirror.lty.me/archlinux/$repo/os/$arch +#Server = https://mirror.lty.me/archlinux/$repo/os/$arch +#Server = http://mirrors.lug.mtu.edu/archlinux/$repo/os/$arch +#Server = https://mirrors.lug.mtu.edu/archlinux/$repo/os/$arch +#Server = http://mirror.math.princeton.edu/pub/archlinux/$repo/os/$arch +#Server = http://mirror.metrocast.net/archlinux/$repo/os/$arch +#Server = http://mirror.kaminski.io/archlinux/$repo/os/$arch +#Server = https://mirror.kaminski.io/archlinux/$repo/os/$arch +#Server = http://iad.mirrors.misaka.one/archlinux/$repo/os/$arch +#Server = https://iad.mirrors.misaka.one/archlinux/$repo/os/$arch +#Server = http://repo.miserver.it.umich.edu/archlinux/$repo/os/$arch +#Server = http://mirrors.mit.edu/archlinux/$repo/os/$arch +#Server = https://mirrors.mit.edu/archlinux/$repo/os/$arch +#Server = http://mirrors.ocf.berkeley.edu/archlinux/$repo/os/$arch +#Server = https://mirrors.ocf.berkeley.edu/archlinux/$repo/os/$arch +#Server = http://archmirror1.octyl.net/$repo/os/$arch +#Server = https://archmirror1.octyl.net/$repo/os/$arch +#Server = http://ftp.osuosl.org/pub/archlinux/$repo/os/$arch +#Server = http://arch.mirrors.pair.com/$repo/os/$arch +#Server = http://dfw.mirror.rackspace.com/archlinux/$repo/os/$arch +#Server = http://iad.mirror.rackspace.com/archlinux/$repo/os/$arch +#Server = http://ord.mirror.rackspace.com/archlinux/$repo/os/$arch +#Server = https://dfw.mirror.rackspace.com/archlinux/$repo/os/$arch +#Server = https://iad.mirror.rackspace.com/archlinux/$repo/os/$arch +#Server = https://ord.mirror.rackspace.com/archlinux/$repo/os/$arch +#Server = http://plug-mirror.rcac.purdue.edu/archlinux/$repo/os/$arch +#Server = https://plug-mirror.rcac.purdue.edu/archlinux/$repo/os/$arch +#Server = http://mirrors.rit.edu/archlinux/$repo/os/$arch +#Server = https://mirrors.rit.edu/archlinux/$repo/os/$arch +#Server = https://arch.rrig.gs/$repo/os/$arch +#Server = http://mirrors.rutgers.edu/archlinux/$repo/os/$arch +#Server = https://mirrors.rutgers.edu/archlinux/$repo/os/$arch +#Server = http://mirror.siena.edu/archlinux/$repo/os/$arch +#Server = http://mirrors.sonic.net/archlinux/$repo/os/$arch +#Server = https://mirrors.sonic.net/archlinux/$repo/os/$arch +#Server = http://arch.mirror.square-r00t.net/$repo/os/$arch +#Server = https://arch.mirror.square-r00t.net/$repo/os/$arch +#Server = http://mirror.stephen304.com/archlinux/$repo/os/$arch +#Server = https://mirror.stephen304.com/archlinux/$repo/os/$arch +#Server = http://ftp.sudhip.com/archlinux/$repo/os/$arch +#Server = https://ftp.sudhip.com/archlinux/$repo/os/$arch +#Server = http://mirror.pit.teraswitch.com/archlinux/$repo/os/$arch +#Server = https://mirror.pit.teraswitch.com/archlinux/$repo/os/$arch +#Server = http://mirror.umd.edu/archlinux/$repo/os/$arch +#Server = http://mirror.vtti.vt.edu/archlinux/$repo/os/$arch +#Server = http://mirrors.xmission.com/archlinux/$repo/os/$arch +#Server = http://mirrors.xtom.com/archlinux/$repo/os/$arch +#Server = https://mirrors.xtom.com/archlinux/$repo/os/$arch +#Server = https://zxcvfdsa.com/arch/$repo/os/$arch + +## Vietnam +#Server = http://f.archlinuxvn.org/archlinux/$repo/os/$arch +#Server = http://mirror.bizflycloud.vn/archlinux/$repo/os/$arch diff --git a/crystal/bootstrap_packages.x86_64 b/crystal/bootstrap_packages.x86_64 new file mode 100644 index 0000000..4803304 --- /dev/null +++ b/crystal/bootstrap_packages.x86_64 @@ -0,0 +1,30 @@ +reflector +pacman-contrib +nano +linux-firmware +tree +linux +mkinitcpio +mkinitcpio-archiso +openssh +syslinux +networkmanager +zsh +ckbcomp +curl +openbsd-netcat +memtest86+ +edk2-shell +sudo +dosfstools +systemd-sysvcompat +cowsay + +# Things we're hosting +arch-install-scripts +ame +base +filesystem +citrine +neofetch +pfetch diff --git a/mkarchiso b/mkarchiso index fa3fbb2..bcb51ce 100755 --- a/mkarchiso +++ b/mkarchiso @@ -6,7 +6,7 @@ set -e -u # Control the environment umask 0022 -export LANG="C" +export LC_ALL="C" export SOURCE_DATE_EPOCH="${SOURCE_DATE_EPOCH:-"$(date +%s)"}" # Set application name from the script's file name @@ -14,11 +14,12 @@ app_name="${0##*/}" # Define global variables. All of them will be overwritten later pkg_list=() +bootstrap_pkg_list=() quiet="" work_dir="" out_dir="" -img_name="" gpg_key="" +gpg_sender="" iso_name="" iso_label="" iso_publisher="" @@ -28,11 +29,17 @@ install_dir="" arch="" pacman_conf="" packages="" +bootstrap_packages="crystal/bootstrap_packages.x86_64" +pacstrap_dir="" +buildmodes=() bootmodes=() airootfs_image_type="" airootfs_image_tool_options=() +cert_list=() +sign_netboot_artifacts="" declare -A file_permissions=() - +# adapted from GRUB_EARLY_INITRD_LINUX_STOCK in https://git.savannah.gnu.org/cgit/grub.git/tree/util/grub-mkconfig.in +readonly ucodes=('intel-uc.img' 'intel-ucode.img' 'amd-uc.img' 'amd-ucode.img' 'early_ucode.cpio' 'microcode.cpio') startdir=$(pwd) # Show an INFO message @@ -61,22 +68,6 @@ _msg_error() { fi } -_mount_airootfs() { - trap "_umount_airootfs" EXIT HUP INT TERM - install -d -m 0755 -- "${work_dir}/mnt/airootfs" - _msg_info "Mounting '${airootfs_dir}.img' on '${work_dir}/mnt/airootfs'..." - mount -- "${airootfs_dir}.img" "${work_dir}/mnt/airootfs" - _msg_info "Done!" -} - -_umount_airootfs() { - _msg_info "Unmounting '${work_dir}/mnt/airootfs'..." - umount -d -- "${work_dir}/mnt/airootfs" - _msg_info "Done!" - rmdir -- "${work_dir}/mnt/airootfs" - trap - EXIT HUP INT TERM -} - # Show help usage, with an exit status. # $1: exit status number. _usage() { @@ -94,11 +85,20 @@ usage: ${app_name} [options] Default: '${iso_label}' -P Set the ISO publisher Default: '${iso_publisher}' - -g Set the GPG key to be used for signing the sqashfs image + -c [cert ..] Provide certificates for codesigning of netboot artifacts + Multiple files are provided as quoted, space delimited list. + The first file is considered as the signing certificate, + the second as the key. + -g Set the PGP key ID to be used for signing the rootfs image. + Passed to gpg as the value for --default-key + -G Set the PGP signer (must include an email address) + Passed to gpg as the value for --sender -h This message + -m [mode ..] Build mode(s) to use (valid modes are: 'bootstrap', 'iso' and 'netboot'). + Multiple build modes are provided as quoted, space delimited list. -o Set the output directory Default: '${out_dir}' - -p PACKAGE(S) Package(s) to install. + -p [package ..] Package(s) to install. Multiple packages are provided as quoted, space delimited list. -v Enable verbose output -w Set the working directory @@ -120,43 +120,52 @@ _show_config() { _msg_info " Installation directory: ${install_dir}" _msg_info " Build date: ${build_date}" _msg_info " Output directory: ${out_dir}" + _msg_info " Current build mode: ${buildmode}" + _msg_info " Build modes: ${buildmodes[*]}" _msg_info " GPG key: ${gpg_key:-None}" + _msg_info " GPG signer: ${gpg_sender:-None}" + _msg_info "Code signing certificates: ${cert_list[*]}" _msg_info " Profile: ${profile}" _msg_info "Pacman configuration file: ${pacman_conf}" - _msg_info " Image file name: ${img_name}" + _msg_info " Image file name: ${image_name:-None}" _msg_info " ISO volume label: ${iso_label}" _msg_info " ISO publisher: ${iso_publisher}" _msg_info " ISO application: ${iso_application}" _msg_info " Boot modes: ${bootmodes[*]}" - _msg_info " Packages: ${pkg_list[*]}" + _msg_info " Packages File: ${buildmode_packages}" + _msg_info " Packages: ${buildmode_pkg_list[*]}" } # Cleanup airootfs -_cleanup_airootfs() { - _msg_info "Cleaning up what we can on airootfs..." +_cleanup_pacstrap_dir() { + _msg_info "Cleaning up in pacstrap location..." # Delete all files in /boot - [[ -d "${airootfs_dir}/boot" ]] && find "${airootfs_dir}/boot" -mindepth 1 -delete + [[ -d "${pacstrap_dir}/boot" ]] && find "${pacstrap_dir}/boot" -mindepth 1 -delete # Delete pacman database sync cache files (*.tar.gz) - [[ -d "${airootfs_dir}/var/lib/pacman" ]] && find "${airootfs_dir}/var/lib/pacman" -maxdepth 1 -type f -delete + [[ -d "${pacstrap_dir}/var/lib/pacman" ]] && find "${pacstrap_dir}/var/lib/pacman" -maxdepth 1 -type f -delete # Delete pacman database sync cache - [[ -d "${airootfs_dir}/var/lib/pacman/sync" ]] && find "${airootfs_dir}/var/lib/pacman/sync" -delete + [[ -d "${pacstrap_dir}/var/lib/pacman/sync" ]] && find "${pacstrap_dir}/var/lib/pacman/sync" -delete # Delete pacman package cache - [[ -d "${airootfs_dir}/var/cache/pacman/pkg" ]] && find "${airootfs_dir}/var/cache/pacman/pkg" -type f -delete + [[ -d "${pacstrap_dir}/var/cache/pacman/pkg" ]] && find "${pacstrap_dir}/var/cache/pacman/pkg" -type f -delete # Delete all log files, keeps empty dirs. - [[ -d "${airootfs_dir}/var/log" ]] && find "${airootfs_dir}/var/log" -type f -delete + [[ -d "${pacstrap_dir}/var/log" ]] && find "${pacstrap_dir}/var/log" -type f -delete # Delete all temporary files and dirs - [[ -d "${airootfs_dir}/var/tmp" ]] && find "${airootfs_dir}/var/tmp" -mindepth 1 -delete + [[ -d "${pacstrap_dir}/var/tmp" ]] && find "${pacstrap_dir}/var/tmp" -mindepth 1 -delete # Delete package pacman related files. find "${work_dir}" \( -name '*.pacnew' -o -name '*.pacsave' -o -name '*.pacorig' \) -delete # Create an empty /etc/machine-id - printf '' > "${airootfs_dir}/etc/machine-id" + rm -f -- "${pacstrap_dir}/etc/machine-id" + printf '' > "${pacstrap_dir}/etc/machine-id" _msg_info "Done!" } +# Create a squashfs image and place it in the ISO 9660 file system. +# $@: options to pass to mksquashfs _run_mksquashfs() { local image_path="${isofs_dir}/${install_dir}/${arch}/airootfs.sfs" + rm -f -- "${image_path}" if [[ "${quiet}" == "y" ]]; then mksquashfs "$@" "${image_path}" -noappend "${airootfs_image_tool_options[@]}" -no-progress > /dev/null else @@ -164,58 +173,66 @@ _run_mksquashfs() { fi } -# Makes a ext4 filesystem inside a SquashFS from a source directory. +# Create an ext4 image containing the root file system and pack it inside a squashfs image. +# Save the squashfs image on the ISO 9660 file system. _mkairootfs_ext4+squashfs() { - [[ -e "${airootfs_dir}" ]] || _msg_error "The path '${airootfs_dir}' does not exist" 1 - - _msg_info "Creating ext4 image of 32 GiB..." - if [[ "${quiet}" == "y" ]]; then - mkfs.ext4 -q -O '^has_journal,^resize_inode' -E 'lazy_itable_init=0' -m 0 -F -- "${airootfs_dir}.img" 32G - else - mkfs.ext4 -O '^has_journal,^resize_inode' -E 'lazy_itable_init=0' -m 0 -F -- "${airootfs_dir}.img" 32G - fi - tune2fs -c 0 -i 0 -- "${airootfs_dir}.img" > /dev/null - _msg_info "Done!" - _mount_airootfs - _msg_info "Copying '${airootfs_dir}/' to '${work_dir}/mnt/airootfs/'..." - cp -aT -- "${airootfs_dir}/" "${work_dir}/mnt/airootfs/" - chown -- 0:0 "${work_dir}/mnt/airootfs/" + local ext4_hash_seed mkfs_ext4_options=() + [[ -e "${pacstrap_dir}" ]] || _msg_error "The path '${pacstrap_dir}' does not exist" 1 + + _msg_info "Creating ext4 image of 32 GiB and copying '${pacstrap_dir}/' to it..." + + ext4_hash_seed="$(uuidgen --sha1 --namespace 93a870ff-8565-4cf3-a67b-f47299271a96 \ + --name "${SOURCE_DATE_EPOCH} ext4 hash seed")" + mkfs_ext4_options=( + '-d' "${pacstrap_dir}" + '-O' '^has_journal,^resize_inode' + '-E' "lazy_itable_init=0,root_owner=0:0,hash_seed=${ext4_hash_seed}" + '-m' '0' + '-F' + '-U' 'clear' + ) + [[ ! "${quiet}" == "y" ]] || mkfs_ext4_options+=('-q') + rm -f -- "${pacstrap_dir}.img" + E2FSPROGS_FAKE_TIME="${SOURCE_DATE_EPOCH}" mkfs.ext4 "${mkfs_ext4_options[@]}" -- "${pacstrap_dir}.img" 32G + tune2fs -c 0 -i 0 -- "${pacstrap_dir}.img" > /dev/null _msg_info "Done!" - _umount_airootfs + install -d -m 0755 -- "${isofs_dir}/${install_dir}/${arch}" - _msg_info "Creating SquashFS image, this may take some time... (1)" + _msg_info "Creating SquashFS image, this may take some time..." _msg_info "But before that, we're running inject.sh" - pushd ${startdir} && ./inject.sh ${airootfs_dir} && popd - _run_mksquashfs "${airootfs_dir}.img" + pushd ${startdir} && ./inject.sh ${pacstrap_dir} && popd + _run_mksquashfs "${pacstrap_dir}.img" _msg_info "Done!" - rm -- "${airootfs_dir}.img" + rm -- "${pacstrap_dir}.img" } -# Makes a SquashFS filesystem from a source directory. +# Create a squashfs image containing the root file system and saves it on the ISO 9660 file system. _mkairootfs_squashfs() { - [[ -e "${airootfs_dir}" ]] || _msg_error "The path '${airootfs_dir}' does not exist" 1 + [[ -e "${pacstrap_dir}" ]] || _msg_error "The path '${pacstrap_dir}' does not exist" 1 install -d -m 0755 -- "${isofs_dir}/${install_dir}/${arch}" - _msg_info "Creating SquashFS image, this may take some time... (2)" + _msg_info "Creating SquashFS image, this may take some time..." _msg_info "But before that, we're running inject.sh" - pushd ${startdir} && ./inject.sh ${airootfs_dir} && popd - _run_mksquashfs "${airootfs_dir}" + pushd ${startdir} && ./inject.sh ${pacstrap_dir} && popd + _run_mksquashfs "${pacstrap_dir}" } -# Makes an EROFS file system from a source directory. +# Create an EROFS image containing the root file system and saves it on the ISO 9660 file system. _mkairootfs_erofs() { local fsuuid - [[ -e "${airootfs_dir}" ]] || _msg_error "The path '${airootfs_dir}' does not exist" 1 + [[ -e "${pacstrap_dir}" ]] || _msg_error "The path '${pacstrap_dir}' does not exist" 1 install -d -m 0755 -- "${isofs_dir}/${install_dir}/${arch}" local image_path="${isofs_dir}/${install_dir}/${arch}/airootfs.erofs" + rm -f -- "${image_path}" # Generate reproducible file system UUID from SOURCE_DATE_EPOCH fsuuid="$(uuidgen --sha1 --namespace 93a870ff-8565-4cf3-a67b-f47299271a96 --name "${SOURCE_DATE_EPOCH}")" _msg_info "Creating EROFS image, this may take some time..." - mkfs.erofs -U "${fsuuid}" "${airootfs_image_tool_options[@]}" -- "${image_path}" "${airootfs_dir}" + mkfs.erofs -U "${fsuuid}" "${airootfs_image_tool_options[@]}" -- "${image_path}" "${pacstrap_dir}" _msg_info "Done!" } +# Create checksum file for the rootfs image. _mkchecksum() { _msg_info "Creating checksum file for self-test..." cd -- "${isofs_dir}/${install_dir}/${arch}" @@ -228,33 +245,40 @@ _mkchecksum() { _msg_info "Done!" } +# GPG sign the root file system image. _mksignature() { - _msg_info "Signing SquashFS image..." - cd -- "${isofs_dir}/${install_dir}/${arch}" + local airootfs_image_filename gpg_options=() + _msg_info "Signing rootfs image..." if [[ -e "${isofs_dir}/${install_dir}/${arch}/airootfs.sfs" ]]; then - gpg --detach-sign --default-key "${gpg_key}" airootfs.sfs + airootfs_image_filename="${isofs_dir}/${install_dir}/${arch}/airootfs.sfs" elif [[ -e "${isofs_dir}/${install_dir}/${arch}/airootfs.erofs" ]]; then - gpg --detach-sign --default-key "${gpg_key}" airootfs.erofs + airootfs_image_filename="${isofs_dir}/${install_dir}/${arch}/airootfs.erofs" fi - cd -- "${OLDPWD}" + rm -f -- "${airootfs_image_filename}.sig" + # Add gpg sender option if the value is provided + [[ -z "${gpg_sender}" ]] || gpg_options+=('--sender' "${gpg_sender}") + # always use the .sig file extension, as that is what mkinitcpio-archiso's hooks expect + gpg --batch --no-armor --no-include-key-block --output "${airootfs_image_filename}.sig" --detach-sign \ + --default-key "${gpg_key}" "${gpg_options[@]}" "${airootfs_image_filename}" _msg_info "Done!" } # Helper function to run functions only one time. +# $1: function name _run_once() { - if [[ ! -e "${work_dir}/build.${1}" ]]; then + if [[ ! -e "${work_dir}/${run_once_mode}.${1}" ]]; then "$1" - touch "${work_dir}/build.${1}" + touch "${work_dir}/${run_once_mode}.${1}" fi } -# Set up custom pacman.conf with custom cache and pacman hook directories +# Set up custom pacman.conf with custom cache and pacman hook directories. _make_pacman_conf() { local _cache_dirs _system_cache_dirs _profile_cache_dirs _system_cache_dirs="$(pacman-conf CacheDir| tr '\n' ' ')" _profile_cache_dirs="$(pacman-conf --config "${pacman_conf}" CacheDir| tr '\n' ' ')" - # only use the profile's CacheDir, if it is not the default and not the same as the system cache dir + # Only use the profile's CacheDir, if it is not the default and not the same as the system cache dir. if [[ "${_profile_cache_dirs}" != "/var/cache/pacman/pkg" ]] && \ [[ "${_system_cache_dirs}" != "${_profile_cache_dirs}" ]]; then _cache_dirs="${_profile_cache_dirs}" @@ -270,35 +294,35 @@ _make_pacman_conf() { # see `man 8 pacman` for further info pacman-conf --config "${pacman_conf}" | \ sed "/CacheDir/d;/DBPath/d;/HookDir/d;/LogFile/d;/RootDir/d;/\[options\]/a CacheDir = ${_cache_dirs} - /\[options\]/a HookDir = ${airootfs_dir}/etc/pacman.d/hooks/" > "${work_dir}/pacman.conf" + /\[options\]/a HookDir = ${pacstrap_dir}/etc/pacman.d/hooks/" > "${work_dir}/${buildmode}.pacman.conf" } -# Prepare working directory and copy custom airootfs files (airootfs) +# Prepare working directory and copy custom root file system files. _make_custom_airootfs() { local passwd=() local filename permissions - install -d -m 0755 -o 0 -g 0 -- "${airootfs_dir}" + install -d -m 0755 -o 0 -g 0 -- "${pacstrap_dir}" if [[ -d "${profile}/airootfs" ]]; then _msg_info "Copying custom airootfs files..." - cp -af --no-preserve=ownership,mode -- "${profile}/airootfs/." "${airootfs_dir}" + cp -af --no-preserve=ownership,mode -- "${profile}/airootfs/." "${pacstrap_dir}" # Set ownership and mode for files and directories for filename in "${!file_permissions[@]}"; do IFS=':' read -ra permissions <<< "${file_permissions["${filename}"]}" - # Prevent file path traversal outside of $airootfs_dir - if [[ "$(realpath -q -- "${airootfs_dir}${filename}")" != "${airootfs_dir}"* ]]; then - _msg_error "Failed to set permissions on '${airootfs_dir}${filename}'. Outside of valid path." 1 + # Prevent file path traversal outside of $pacstrap_dir + if [[ "$(realpath -q -- "${pacstrap_dir}${filename}")" != "${pacstrap_dir}"* ]]; then + _msg_error "Failed to set permissions on '${pacstrap_dir}${filename}'. Outside of valid path." 1 # Warn if the file does not exist - elif [[ ! -e "${airootfs_dir}${filename}" ]]; then - _msg_warning "Cannot change permissions of '${airootfs_dir}${filename}'. The file or directory does not exist." + elif [[ ! -e "${pacstrap_dir}${filename}" ]]; then + _msg_warning "Cannot change permissions of '${pacstrap_dir}${filename}'. The file or directory does not exist." else if [[ "${filename: -1}" == "/" ]]; then - chown -fhR -- "${permissions[0]}:${permissions[1]}" "${airootfs_dir}${filename}" - chmod -fR -- "${permissions[2]}" "${airootfs_dir}${filename}" + chown -fhR -- "${permissions[0]}:${permissions[1]}" "${pacstrap_dir}${filename}" + chmod -fR -- "${permissions[2]}" "${pacstrap_dir}${filename}" else - chown -fh -- "${permissions[0]}:${permissions[1]}" "${airootfs_dir}${filename}" - chmod -f -- "${permissions[2]}" "${airootfs_dir}${filename}" + chown -fh -- "${permissions[0]}:${permissions[1]}" "${pacstrap_dir}${filename}" + chmod -f -- "${permissions[2]}" "${pacstrap_dir}${filename}" fi fi done @@ -306,19 +330,20 @@ _make_custom_airootfs() { fi } -# Install desired packages to airootfs +# Install desired packages to the root file system _make_packages() { - _msg_info "Installing packages to '${airootfs_dir}/'..." + _msg_info "Installing packages to '${pacstrap_dir}/'..." if [[ -n "${gpg_key}" ]]; then exec {ARCHISO_GNUPG_FD}<>"${work_dir}/pubkey.gpg" export ARCHISO_GNUPG_FD fi + # Unset TMPDIR to work around https://bugs.archlinux.org/task/70580 if [[ "${quiet}" = "y" ]]; then - yes '' | pacstrap -C "${work_dir}/pacman.conf" -c -G -M -- "${airootfs_dir}" "${pkg_list[@]}" &> /dev/null + env -u TMPDIR pacstrap -C "${work_dir}/${buildmode}.pacman.conf" -c -G -M -- "${pacstrap_dir}" "${buildmode_pkg_list[@]}" &> /dev/null else - yes '' | pacstrap -C "${work_dir}/pacman.conf" -c -G -M -- "${airootfs_dir}" "${pkg_list[@]}" + env -u TMPDIR pacstrap -C "${work_dir}/${buildmode}.pacman.conf" -c -G -M -- "${pacstrap_dir}" "${buildmode_pkg_list[@]}" fi if [[ -n "${gpg_key}" ]]; then @@ -329,7 +354,7 @@ _make_packages() { _msg_info "Done! Packages installed successfully." } -# Customize installation (airootfs) +# Customize installation. _make_customize_airootfs() { local passwd=() @@ -341,27 +366,28 @@ _make_customize_airootfs() { # Skip invalid home directories [[ "${passwd[5]}" == '/' ]] && continue [[ -z "${passwd[5]}" ]] && continue - # Prevent path traversal outside of $airootfs_dir - if [[ "$(realpath -q -- "${airootfs_dir}${passwd[5]}")" == "${airootfs_dir}"* ]]; then - if [[ ! -d "${airootfs_dir}${passwd[5]}" ]]; then - install -d -m 0750 -o "${passwd[2]}" -g "${passwd[3]}" -- "${airootfs_dir}${passwd[5]}" + # Prevent path traversal outside of $pacstrap_dir + if [[ "$(realpath -q -- "${pacstrap_dir}${passwd[5]}")" == "${pacstrap_dir}"* ]]; then + if [[ ! -d "${pacstrap_dir}${passwd[5]}" ]]; then + install -d -m 0750 -o "${passwd[2]}" -g "${passwd[3]}" -- "${pacstrap_dir}${passwd[5]}" fi - cp -dnRT --preserve=mode,timestamps,links -- "${airootfs_dir}/etc/skel/." "${airootfs_dir}${passwd[5]}" - chmod -f 0750 -- "${airootfs_dir}${passwd[5]}" - chown -hR -- "${passwd[2]}:${passwd[3]}" "${airootfs_dir}${passwd[5]}" + cp -dnRT --preserve=mode,timestamps,links -- "${pacstrap_dir}/etc/skel/." "${pacstrap_dir}${passwd[5]}" + chmod -f 0750 -- "${pacstrap_dir}${passwd[5]}" + chown -hR -- "${passwd[2]}:${passwd[3]}" "${pacstrap_dir}${passwd[5]}" else - _msg_error "Failed to set permissions on '${airootfs_dir}${passwd[5]}'. Outside of valid path." 1 + _msg_error "Failed to set permissions on '${pacstrap_dir}${passwd[5]}'. Outside of valid path." 1 fi done < "${profile}/airootfs/etc/passwd" _msg_info "Done!" fi - if [[ -e "${airootfs_dir}/root/customize_airootfs.sh" ]]; then - _msg_info "Running customize_airootfs.sh in '${airootfs_dir}' chroot..." + if [[ -e "${pacstrap_dir}/root/customize_airootfs.sh" ]]; then + _msg_info "Running customize_airootfs.sh in '${pacstrap_dir}' chroot..." _msg_warning "customize_airootfs.sh is deprecated! Support for it will be removed in a future archiso version." - chmod -f -- +x "${airootfs_dir}/root/customize_airootfs.sh" - eval -- arch-chroot "${airootfs_dir}" "/root/customize_airootfs.sh" - rm -- "${airootfs_dir}/root/customize_airootfs.sh" + chmod -f -- +x "${pacstrap_dir}/root/customize_airootfs.sh" + # Unset TMPDIR to work around https://bugs.archlinux.org/task/70580 + eval -- env -u TMPDIR arch-chroot "${pacstrap_dir}" "/root/customize_airootfs.sh" + rm -- "${pacstrap_dir}/root/customize_airootfs.sh" _msg_info "Done! customize_airootfs.sh run successfully." fi } @@ -374,20 +400,20 @@ _make_bootmodes() { done } -# Prepare kernel/initramfs ${install_dir}/boot/ +# Copy kernel and initramfs to ISO 9660 _make_boot_on_iso9660() { local ucode_image _msg_info "Preparing kernel and initramfs for the ISO 9660 file system..." install -d -m 0755 -- "${isofs_dir}/${install_dir}/boot/${arch}" - install -m 0644 -- "${airootfs_dir}/boot/initramfs-"*".img" "${isofs_dir}/${install_dir}/boot/${arch}/" - install -m 0644 -- "${airootfs_dir}/boot/vmlinuz-"* "${isofs_dir}/${install_dir}/boot/${arch}/" + install -m 0644 -- "${pacstrap_dir}/boot/initramfs-"*".img" "${isofs_dir}/${install_dir}/boot/${arch}/" + install -m 0644 -- "${pacstrap_dir}/boot/vmlinuz-"* "${isofs_dir}/${install_dir}/boot/${arch}/" - for ucode_image in {intel-uc.img,intel-ucode.img,amd-uc.img,amd-ucode.img,early_ucode.cpio,microcode.cpio}; do - if [[ -e "${airootfs_dir}/boot/${ucode_image}" ]]; then - install -m 0644 -- "${airootfs_dir}/boot/${ucode_image}" "${isofs_dir}/${install_dir}/boot/" - if [[ -e "${airootfs_dir}/usr/share/licenses/${ucode_image%.*}/" ]]; then + for ucode_image in "${ucodes[@]}"; do + if [[ -e "${pacstrap_dir}/boot/${ucode_image}" ]]; then + install -m 0644 -- "${pacstrap_dir}/boot/${ucode_image}" "${isofs_dir}/${install_dir}/boot/" + if [[ -e "${pacstrap_dir}/usr/share/licenses/${ucode_image%.*}/" ]]; then install -d -m 0755 -- "${isofs_dir}/${install_dir}/boot/licenses/${ucode_image%.*}/" - install -m 0644 -- "${airootfs_dir}/usr/share/licenses/${ucode_image%.*}/"* \ + install -m 0644 -- "${pacstrap_dir}/usr/share/licenses/${ucode_image%.*}/"* \ "${isofs_dir}/${install_dir}/boot/licenses/${ucode_image%.*}/" fi fi @@ -395,7 +421,7 @@ _make_boot_on_iso9660() { _msg_info "Done!" } -# Prepare /syslinux for booting from MBR +# Prepare syslinux for booting from MBR (isohybrid) _make_bootmode_bios.syslinux.mbr() { _msg_info "Setting up SYSLINUX for BIOS booting from a disk..." install -d -m 0755 -- "${isofs_dir}/syslinux" @@ -408,39 +434,39 @@ _make_bootmode_bios.syslinux.mbr() { if [[ -e "${profile}/syslinux/splash.png" ]]; then install -m 0644 -- "${profile}/syslinux/splash.png" "${isofs_dir}/syslinux/" fi - install -m 0644 -- "${airootfs_dir}/usr/lib/syslinux/bios/"*.c32 "${isofs_dir}/syslinux/" - install -m 0644 -- "${airootfs_dir}/usr/lib/syslinux/bios/lpxelinux.0" "${isofs_dir}/syslinux/" - install -m 0644 -- "${airootfs_dir}/usr/lib/syslinux/bios/memdisk" "${isofs_dir}/syslinux/" + install -m 0644 -- "${pacstrap_dir}/usr/lib/syslinux/bios/"*.c32 "${isofs_dir}/syslinux/" + install -m 0644 -- "${pacstrap_dir}/usr/lib/syslinux/bios/lpxelinux.0" "${isofs_dir}/syslinux/" + install -m 0644 -- "${pacstrap_dir}/usr/lib/syslinux/bios/memdisk" "${isofs_dir}/syslinux/" _run_once _make_boot_on_iso9660 if [[ -e "${isofs_dir}/syslinux/hdt.c32" ]]; then install -d -m 0755 -- "${isofs_dir}/syslinux/hdt" - if [[ -e "${airootfs_dir}/usr/share/hwdata/pci.ids" ]]; then - gzip -c -9 "${airootfs_dir}/usr/share/hwdata/pci.ids" > \ + if [[ -e "${pacstrap_dir}/usr/share/hwdata/pci.ids" ]]; then + gzip -cn9 "${pacstrap_dir}/usr/share/hwdata/pci.ids" > \ "${isofs_dir}/syslinux/hdt/pciids.gz" fi - find "${airootfs_dir}/usr/lib/modules" -name 'modules.alias' -print -exec gzip -c -9 '{}' ';' -quit > \ + find "${pacstrap_dir}/usr/lib/modules" -name 'modules.alias' -print -exec gzip -cn9 '{}' ';' -quit > \ "${isofs_dir}/syslinux/hdt/modalias.gz" fi # Add other aditional/extra files to ${install_dir}/boot/ - if [[ -e "${airootfs_dir}/boot/memtest86+/memtest.bin" ]]; then - # rename for PXE: https://wiki.archlinux.org/index.php/Syslinux#Using_memtest - install -m 0644 -- "${airootfs_dir}/boot/memtest86+/memtest.bin" "${isofs_dir}/${install_dir}/boot/memtest" + if [[ -e "${pacstrap_dir}/boot/memtest86+/memtest.bin" ]]; then + # rename for PXE: https://wiki.archlinux.org/title/Syslinux#Using_memtest + install -m 0644 -- "${pacstrap_dir}/boot/memtest86+/memtest.bin" "${isofs_dir}/${install_dir}/boot/memtest" install -d -m 0755 -- "${isofs_dir}/${install_dir}/boot/licenses/memtest86+/" - install -m 0644 -- "${airootfs_dir}/usr/share/licenses/common/GPL2/license.txt" \ + install -m 0644 -- "${pacstrap_dir}/usr/share/licenses/common/GPL2/license.txt" \ "${isofs_dir}/${install_dir}/boot/licenses/memtest86+/" fi _msg_info "Done! SYSLINUX set up for BIOS booting from a disk successfully." } -# Prepare /syslinux for El-Torito booting +# Prepare syslinux for El-Torito booting _make_bootmode_bios.syslinux.eltorito() { _msg_info "Setting up SYSLINUX for BIOS booting from an optical disc..." install -d -m 0755 -- "${isofs_dir}/syslinux" - install -m 0644 -- "${airootfs_dir}/usr/lib/syslinux/bios/isolinux.bin" "${isofs_dir}/syslinux/" - install -m 0644 -- "${airootfs_dir}/usr/lib/syslinux/bios/isohdpfx.bin" "${isofs_dir}/syslinux/" + install -m 0644 -- "${pacstrap_dir}/usr/lib/syslinux/bios/isolinux.bin" "${isofs_dir}/syslinux/" + install -m 0644 -- "${pacstrap_dir}/usr/lib/syslinux/bios/isohdpfx.bin" "${isofs_dir}/syslinux/" # ISOLINUX and SYSLINUX installation is shared _run_once _make_bootmode_bios.syslinux.mbr @@ -448,44 +474,17 @@ _make_bootmode_bios.syslinux.eltorito() { _msg_info "Done! SYSLINUX set up for BIOS booting from an optical disc successfully." } -# Prepare /EFI on ISO-9660 -_make_efi_dir_on_iso9660() { - _msg_info "Preparing an /EFI directory for the ISO 9660 file system..." - install -d -m 0755 -- "${isofs_dir}/EFI/BOOT" - install -m 0644 -- "${airootfs_dir}/usr/lib/systemd/boot/efi/systemd-bootx64.efi" \ - "${isofs_dir}/EFI/BOOT/BOOTx64.EFI" - - install -d -m 0755 -- "${isofs_dir}/loader/entries" - install -m 0644 -- "${profile}/efiboot/loader/loader.conf" "${isofs_dir}/loader/" - - for _conf in "${profile}/efiboot/loader/entries/"*".conf"; do - sed "s|%ARCHISO_LABEL%|${iso_label}|g; - s|%INSTALL_DIR%|${install_dir}|g; - s|%ARCH%|${arch}|g" \ - "${_conf}" > "${isofs_dir}/loader/entries/${_conf##*/}" - done - - # edk2-shell based UEFI shell - # shellx64.efi is picked up automatically when on / - if [[ -e "${airootfs_dir}/usr/share/edk2-shell/x64/Shell_Full.efi" ]]; then - install -m 0644 -- "${airootfs_dir}/usr/share/edk2-shell/x64/Shell_Full.efi" "${isofs_dir}/shellx64.efi" - fi - _msg_info "Done!" -} - -# Prepare kernel/initramfs on efiboot.img +# Copy kernel and initramfs to FAT image _make_boot_on_fat() { local ucode_image all_ucode_images=() _msg_info "Preparing kernel and initramfs for the FAT file system..." mmd -i "${work_dir}/efiboot.img" \ "::/${install_dir}" "::/${install_dir}/boot" "::/${install_dir}/boot/${arch}" - mcopy -i "${work_dir}/efiboot.img" "${airootfs_dir}/boot/vmlinuz-"* \ - "${airootfs_dir}/boot/initramfs-"*".img" "::/${install_dir}/boot/${arch}/" - for ucode_image in \ - "${airootfs_dir}/boot/"{intel-uc.img,intel-ucode.img,amd-uc.img,amd-ucode.img,early_ucode.cpio,microcode.cpio} - do - if [[ -e "${ucode_image}" ]]; then - all_ucode_images+=("${ucode_image}") + mcopy -i "${work_dir}/efiboot.img" "${pacstrap_dir}/boot/vmlinuz-"* \ + "${pacstrap_dir}/boot/initramfs-"*".img" "::/${install_dir}/boot/${arch}/" + for ucode_image in "${ucodes[@]}"; do + if [[ -e "${pacstrap_dir}/boot/${ucode_image}" ]]; then + all_ucode_images+=("${pacstrap_dir}/boot/${ucode_image}") fi done if (( ${#all_ucode_images[@]} )); then @@ -494,34 +493,55 @@ _make_boot_on_fat() { _msg_info "Done!" } -# Prepare efiboot.img::/EFI for EFI boot mode -_make_bootmode_uefi-x64.systemd-boot.esp() { - local efiboot_imgsize="0" - _msg_info "Setting up systemd-boot for UEFI booting..." +# Create a FAT image (efiboot.img) which will serve as the EFI system partition +# $1: image size in bytes +_make_efibootimg() { + local imgsize="0" - # the required image size in KiB (rounded up to the next full MiB with an additional MiB for reserved sectors) - efiboot_imgsize="$(du -bc \ - "${airootfs_dir}/usr/lib/systemd/boot/efi/systemd-bootx64.efi" \ - "${airootfs_dir}/usr/share/edk2-shell/x64/Shell_Full.efi" \ - "${profile}/efiboot/" \ - "${airootfs_dir}/boot/vmlinuz-"* \ - "${airootfs_dir}/boot/initramfs-"*".img" \ - "${airootfs_dir}/boot/"{intel-uc.img,intel-ucode.img,amd-uc.img,amd-ucode.img,early_ucode.cpio,microcode.cpio} \ - 2>/dev/null | awk 'function ceil(x){return int(x)+(x>int(x))} + # Convert from bytes to KiB and round up to the next full MiB with an additional MiB for reserved sectors. + imgsize="$(awk 'function ceil(x){return int(x)+(x>int(x))} function byte_to_kib(x){return x/1024} function mib_to_kib(x){return x*1024} - END {print mib_to_kib(ceil((byte_to_kib($1)+1024)/1024))}' - )" + END {print mib_to_kib(ceil((byte_to_kib($1)+1024)/1024))}' <<< "${1}" + )" # The FAT image must be created with mkfs.fat not mformat, as some systems have issues with mformat made images: # https://lists.gnu.org/archive/html/grub-devel/2019-04/msg00099.html - [[ -e "${work_dir}/efiboot.img" ]] && rm -f -- "${work_dir}/efiboot.img" - _msg_info "Creating FAT image of size: ${efiboot_imgsize} KiB..." - mkfs.fat -C -n ARCHISO_EFI "${work_dir}/efiboot.img" "$efiboot_imgsize" + rm -f -- "${work_dir}/efiboot.img" + _msg_info "Creating FAT image of size: ${imgsize} KiB..." + mkfs.fat -C -n ARCHISO_EFI "${work_dir}/efiboot.img" "${imgsize}" + # Create the default/fallback boot path in which a boot loaders will be placed later. mmd -i "${work_dir}/efiboot.img" ::/EFI ::/EFI/BOOT +} + +# Prepare system-boot for booting when written to a disk (isohybrid) +_make_bootmode_uefi-x64.systemd-boot.esp() { + local _file efiboot_imgsize + local _available_ucodes=() + _msg_info "Setting up systemd-boot for UEFI booting..." + + for _file in "${ucodes[@]}"; do + if [[ -e "${pacstrap_dir}/boot/${_file}" ]]; then + _available_ucodes+=("${pacstrap_dir}/boot/${_file}") + fi + done + # Calculate the required FAT image size in bytes + efiboot_imgsize="$(du -bc \ + "${pacstrap_dir}/usr/lib/systemd/boot/efi/systemd-bootx64.efi" \ + "${pacstrap_dir}/usr/share/edk2-shell/x64/Shell_Full.efi" \ + "${profile}/efiboot/" \ + "${pacstrap_dir}/boot/vmlinuz-"* \ + "${pacstrap_dir}/boot/initramfs-"*".img" \ + "${_available_ucodes[@]}" \ + 2>/dev/null | awk 'END { print $1 }')" + # Create a FAT image for the EFI system partition + _make_efibootimg "$efiboot_imgsize" + + # Copy systemd-boot EFI binary to the default/fallback boot path mcopy -i "${work_dir}/efiboot.img" \ - "${airootfs_dir}/usr/lib/systemd/boot/efi/systemd-bootx64.efi" ::/EFI/BOOT/BOOTx64.EFI + "${pacstrap_dir}/usr/lib/systemd/boot/efi/systemd-bootx64.efi" ::/EFI/BOOT/BOOTx64.EFI + # Copy systemd-boot configuration files mmd -i "${work_dir}/efiboot.img" ::/loader ::/loader/entries mcopy -i "${work_dir}/efiboot.img" "${profile}/efiboot/loader/loader.conf" ::/loader/ for _conf in "${profile}/efiboot/loader/entries/"*".conf"; do @@ -532,22 +552,51 @@ _make_bootmode_uefi-x64.systemd-boot.esp() { done # shellx64.efi is picked up automatically when on / - if [[ -e "${airootfs_dir}/usr/share/edk2-shell/x64/Shell_Full.efi" ]]; then + if [[ -e "${pacstrap_dir}/usr/share/edk2-shell/x64/Shell_Full.efi" ]]; then mcopy -i "${work_dir}/efiboot.img" \ - "${airootfs_dir}/usr/share/edk2-shell/x64/Shell_Full.efi" ::/shellx64.efi + "${pacstrap_dir}/usr/share/edk2-shell/x64/Shell_Full.efi" ::/shellx64.efi fi - # Copy kernel and initramfs + # Copy kernel and initramfs to FAT image. + # systemd-boot can only access files from the EFI system partition it was launched from. _make_boot_on_fat _msg_info "Done! systemd-boot set up for UEFI booting successfully." } -# Prepare efiboot.img::/EFI for "El Torito" EFI boot mode +# Prepare system-boot for El Torito booting _make_bootmode_uefi-x64.systemd-boot.eltorito() { + # El Torito UEFI boot requires an image containing the EFI system partition. + # uefi-x64.systemd-boot.eltorito has the same requirements as uefi-x64.systemd-boot.esp _run_once _make_bootmode_uefi-x64.systemd-boot.esp - # Set up /EFI on ISO-9660 to allow preparing an installation medium by manually copying files - _run_once _make_efi_dir_on_iso9660 + + # Additionally set up system-boot in ISO 9660. This allows creating a medium for the live environment by using + # manual partitioning and simply copying the ISO 9660 file system contents. + # This is not related to El Torito booting and no firmware uses these files. + _msg_info "Preparing an /EFI directory for the ISO 9660 file system..." + install -d -m 0755 -- "${isofs_dir}/EFI/BOOT" + + # Copy systemd-boot EFI binary to the default/fallback boot path + install -m 0644 -- "${pacstrap_dir}/usr/lib/systemd/boot/efi/systemd-bootx64.efi" \ + "${isofs_dir}/EFI/BOOT/BOOTx64.EFI" + + # Copy systemd-boot configuration files + install -d -m 0755 -- "${isofs_dir}/loader/entries" + install -m 0644 -- "${profile}/efiboot/loader/loader.conf" "${isofs_dir}/loader/" + for _conf in "${profile}/efiboot/loader/entries/"*".conf"; do + sed "s|%ARCHISO_LABEL%|${iso_label}|g; + s|%INSTALL_DIR%|${install_dir}|g; + s|%ARCH%|${arch}|g" \ + "${_conf}" > "${isofs_dir}/loader/entries/${_conf##*/}" + done + + # edk2-shell based UEFI shell + # shellx64.efi is picked up automatically when on / + if [[ -e "${pacstrap_dir}/usr/share/edk2-shell/x64/Shell_Full.efi" ]]; then + install -m 0644 -- "${pacstrap_dir}/usr/share/edk2-shell/x64/Shell_Full.efi" "${isofs_dir}/shellx64.efi" + fi + + _msg_info "Done!" } _validate_requirements_bootmode_bios.syslinux.mbr() { @@ -589,6 +638,7 @@ _validate_requirements_bootmode_bios.syslinux.mbr() { } _validate_requirements_bootmode_bios.syslinux.eltorito() { + # bios.syslinux.eltorito has the exact same requirements as bios.syslinux.mbr _validate_requirements_bootmode_bios.syslinux.mbr } @@ -645,6 +695,40 @@ _prepare_airootfs_image() { fi } +# export build artifacts for netboot +_export_netboot_artifacts() { + _msg_info "Exporting netboot artifacts..." + install -d -m 0755 "${out_dir}" + cp -a -- "${isofs_dir}/${install_dir}/" "${out_dir}/" + _msg_info "Done!" + du -h -- "${out_dir}/${install_dir}" +} + +# sign build artifacts for netboot +_sign_netboot_artifacts() { + local _file _dir + local _files_to_sign=() + _msg_info "Signing netboot artifacts..." + _dir="${isofs_dir}/${install_dir}/boot/" + for _file in "${ucodes[@]}"; do + if [[ -e "${_dir}${_file}" ]]; then + _files_to_sign+=("${_dir}${_file}") + fi + done + for _file in "${_files_to_sign[@]}" "${_dir}${arch}/vmlinuz-"* "${_dir}${arch}/initramfs-"*.img; do + openssl cms \ + -sign \ + -binary \ + -noattr \ + -in "${_file}" \ + -signer "${cert_list[0]}" \ + -inkey "${cert_list[1]}" \ + -outform DER \ + -out "${_file}".ipxe.sig + done + _msg_info "Done!" +} + _validate_requirements_airootfs_image_type_squashfs() { if ! command -v mksquashfs &> /dev/null; then (( validation_error=validation_error+1 )) @@ -667,6 +751,130 @@ _validate_requirements_airootfs_image_type_erofs() { fi } +_validate_common_requirements_buildmode_all() { + if ! command -v pacman &> /dev/null; then + (( validation_error=validation_error+1 )) + _msg_error "Validating build mode '${_buildmode}': pacman is not available on this host. Install 'pacman'!" 0 + fi + if ! command -v find &> /dev/null; then + (( validation_error=validation_error+1 )) + _msg_error "Validating build mode '${_buildmode}': find is not available on this host. Install 'findutils'!" 0 + fi + if ! command -v gzip &> /dev/null; then + (( validation_error=validation_error+1 )) + _msg_error "Validating build mode '${_buildmode}': gzip is not available on this host. Install 'gzip'!" 0 + fi +} + +_validate_requirements_buildmode_bootstrap() { + local bootstrap_pkg_list_from_file=() + + # Check if packages for the bootstrap image are specified + if [[ -e "${bootstrap_packages}" ]]; then + mapfile -t bootstrap_pkg_list_from_file < \ + <(sed '/^[[:blank:]]*#.*/d;s/#.*//;/^[[:blank:]]*$/d' "${bootstrap_packages}") + bootstrap_pkg_list+=("${bootstrap_pkg_list_from_file[@]}") + if (( ${#bootstrap_pkg_list_from_file[@]} < 1 )); then + (( validation_error=validation_error+1 )) + _msg_error "No package specified in '${bootstrap_packages}'." 0 + fi + else + (( validation_error=validation_error+1 )) + _msg_error "Bootstrap packages file '${bootstrap_packages}' does not exist." 0 + fi + + _validate_common_requirements_buildmode_all + if ! command -v bsdtar &> /dev/null; then + (( validation_error=validation_error+1 )) + _msg_error "Validating build mode '${_buildmode}': bsdtar is not available on this host. Install 'libarchive'!" 0 + fi +} + +_validate_common_requirements_buildmode_iso_netboot() { + local bootmode + local pkg_list_from_file=() + + # Check if the package list file exists and read packages from it + if [[ -e "${packages}" ]]; then + mapfile -t pkg_list_from_file < <(sed '/^[[:blank:]]*#.*/d;s/#.*//;/^[[:blank:]]*$/d' "${packages}") + pkg_list+=("${pkg_list_from_file[@]}") + if (( ${#pkg_list_from_file[@]} < 1 )); then + (( validation_error=validation_error+1 )) + _msg_error "No package specified in '${packages}'." 0 + fi + else + (( validation_error=validation_error+1 )) + _msg_error "Packages file '${packages}' does not exist." 0 + fi + + # Check if the specified bootmodes are supported + if (( ${#bootmodes[@]} < 1 )); then + (( validation_error=validation_error+1 )) + _msg_error "No boot modes specified in '${profile}/profiledef.sh'." 0 + fi + for bootmode in "${bootmodes[@]}"; do + if typeset -f "_make_bootmode_${bootmode}" &> /dev/null; then + if typeset -f "_validate_requirements_bootmode_${bootmode}" &> /dev/null; then + "_validate_requirements_bootmode_${bootmode}" + else + _msg_warning "Function '_validate_requirements_bootmode_${bootmode}' does not exist. Validating the requirements of '${bootmode}' boot mode will not be possible." + fi + else + (( validation_error=validation_error+1 )) + _msg_error "${bootmode} is not a valid boot mode!" 0 + fi + done + + # Check if the specified airootfs_image_type is supported + if typeset -f "_mkairootfs_${airootfs_image_type}" &> /dev/null; then + if typeset -f "_validate_requirements_airootfs_image_type_${airootfs_image_type}" &> /dev/null; then + "_validate_requirements_airootfs_image_type_${airootfs_image_type}" + else + _msg_warning "Function '_validate_requirements_airootfs_image_type_${airootfs_image_type}' does not exist. Validating the requirements of '${airootfs_image_type}' airootfs image type will not be possible." + fi + else + (( validation_error=validation_error+1 )) + _msg_error "Unsupported image type: '${airootfs_image_type}'" 0 + fi +} + +_validate_requirements_buildmode_iso() { + _validate_common_requirements_buildmode_iso_netboot + _validate_common_requirements_buildmode_all + if ! command -v awk &> /dev/null; then + (( validation_error=validation_error+1 )) + _msg_error "Validating build mode '${_buildmode}': awk is not available on this host. Install 'awk'!" 0 + fi +} + +_validate_requirements_buildmode_netboot() { + local _override_cert_list=() + + if [[ "${sign_netboot_artifacts}" == "y" ]]; then + # Check if the certificate files exist + for _cert in "${cert_list[@]}"; do + if [[ -e "${_cert}" ]]; then + _override_cert_list+=("$(realpath -- "${_cert}")") + else + (( validation_error=validation_error+1 )) + _msg_error "File '${_cert}' does not exist." 0 + fi + done + cert_list=("${_override_cert_list[@]}") + # Check if there are at least two certificate files + if (( ${#cert_list[@]} < 2 )); then + (( validation_error=validation_error+1 )) + _msg_error "Two certificates are required for codesigning, but '${cert_list[*]}' is provided." 0 + fi + fi + _validate_common_requirements_buildmode_iso_netboot + _validate_common_requirements_buildmode_all + if ! command -v openssl &> /dev/null; then + (( validation_error=validation_error+1 )) + _msg_error "Validating build mode '${_buildmode}': openssl is not available on this host. Install 'openssl'!" 0 + fi +} + # SYSLINUX El Torito _add_xorrisofs_options_bios.syslinux.eltorito() { xorrisofs_options+=( @@ -679,22 +887,17 @@ _add_xorrisofs_options_bios.syslinux.eltorito() { ) } -# SYSLINUX MBR +# SYSLINUX MBR (isohybrid) _add_xorrisofs_options_bios.syslinux.mbr() { xorrisofs_options+=( # SYSLINUX MBR bootstrap code; does not work without "-eltorito-boot syslinux/isolinux.bin" '-isohybrid-mbr' "${isofs_dir}/syslinux/isohdpfx.bin" # When GPT is used, create an additional partition in the MBR (besides 0xEE) for sectors 0–1 (MBR # bootstrap code area) and mark it as bootable - # This violates the UEFI specification, but may allow booting on some systems - # https://wiki.archlinux.org/index.php/Partitioning#Tricking_old_BIOS_into_booting_from_GPT + # May allow booting on some systems + # https://wiki.archlinux.org/title/Partitioning#Tricking_old_BIOS_into_booting_from_GPT '--mbr-force-bootable' - # Set the ISO 9660 partition's type to "Linux filesystem data" - # When only MBR is present, the partition type ID will be 0x83 "Linux" as xorriso translates all - # GPT partition type GUIDs except for the ESP GUID to MBR type ID 0x83 - '-iso_mbr_part_type' '0FC63DAF-8483-4772-8E79-3D69D8477DE4' - # Move the first partition away from the start of the ISO to match the expectations of partition - # editors + # Move the first partition away from the start of the ISO to match the expectations of partition editors # May allow booting on some systems # https://dev.lovelyhq.com/libburnia/libisoburn/src/branch/master/doc/partition_offset.wiki '-partition_offset' '16' @@ -707,12 +910,26 @@ _add_xorrisofs_options_uefi-x64.systemd-boot.esp() { # partition will not be mountable # shellcheck disable=SC2076 [[ " ${xorrisofs_options[*]} " =~ ' -partition_offset ' ]] || xorrisofs_options+=('-partition_offset' '16') - xorrisofs_options+=( - # Attach efiboot.img as a second partition and set its partition type to "EFI system partition" - '-append_partition' '2' 'C12A7328-F81F-11D2-BA4B-00A0C93EC93B' "${work_dir}/efiboot.img" - # Ensure GPT is used as some systems do not support UEFI booting without it - '-appended_part_as_gpt' - ) + # Attach efiboot.img as a second partition and set its partition type to "EFI system partition" + xorrisofs_options+=('-append_partition' '2' 'C12A7328-F81F-11D2-BA4B-00A0C93EC93B' "${work_dir}/efiboot.img") + # Ensure GPT is used as some systems do not support UEFI booting without it + # shellcheck disable=SC2076 + if [[ " ${bootmodes[*]} " =~ ' bios.syslinux.mbr ' ]]; then + # A valid GPT prevents BIOS booting on some systems, instead use an invalid GPT (without a protective MBR). + # The attached partition will have the EFI system partition type code in MBR, but in the invalid GPT it will + # have a Microsoft basic partition type code. + if [[ ! " ${bootmodes[*]} " =~ ' uefi-x64.systemd-boot.eltorito ' ]]; then + # If '-isohybrid-gpt-basdat' is specified before '-e', then the appended EFI system partition will have the + # EFI system partition type ID/GUID in both MBR and GPT. If '-isohybrid-gpt-basdat' is specified after '-e', + # the appended EFI system partition will have the Microsoft basic data type GUID in GPT. + if [[ ! " ${xorrisofs_options[*]} " =~ ' -isohybrid-gpt-basdat ' ]]; then + xorrisofs_options+=('-isohybrid-gpt-basdat') + fi + fi + else + # Use valid GPT if BIOS booting support will not be required + xorrisofs_options+=('-appended_part_as_gpt') + fi } # systemd-boot via El Torito @@ -728,6 +945,15 @@ _add_xorrisofs_options_uefi-x64.systemd-boot.eltorito() { # Boot image is not emulating floppy or hard disk; required for all known boot loaders '-no-emul-boot' ) + # A valid GPT prevents BIOS booting on some systems, use an invalid GPT instead. + if [[ " ${bootmodes[*]} " =~ ' bios.syslinux.mbr ' ]]; then + # If '-isohybrid-gpt-basdat' is specified before '-e', then the appended EFI system partition will have the + # EFI system partition type ID/GUID in both MBR and GPT. If '-isohybrid-gpt-basdat' is specified after '-e', + # the appended EFI system partition will have the Microsoft basic data type GUID in GPT. + if [[ ! " ${xorrisofs_options[*]} " =~ ' -isohybrid-gpt-basdat ' ]]; then + xorrisofs_options+=('-isohybrid-gpt-basdat') + fi + fi else # The ISO will not contain a GPT partition table, so to be able to reference efiboot.img, place it as a # file inside the ISO 9660 file system @@ -748,8 +974,24 @@ _add_xorrisofs_options_uefi-x64.systemd-boot.eltorito() { [[ " ${bootmodes[*]} " =~ ' bios.' ]] || xorrisofs_options+=('-eltorito-catalog' 'EFI/boot.cat') } +# Build bootstrap image +_build_bootstrap_image() { + local _bootstrap_parent + _bootstrap_parent="$(dirname -- "${pacstrap_dir}")" + + [[ -d "${out_dir}" ]] || install -d -- "${out_dir}" + + cd -- "${_bootstrap_parent}" + + _msg_info "Creating bootstrap image..." + bsdtar -cf - "root.${arch}" | gzip -cn9 > "${out_dir}/${image_name}" + _msg_info "Done!" + du -h -- "${out_dir}/${image_name}" + cd -- "${OLDPWD}" +} + # Build ISO -_build_iso() { +_build_iso_image() { local xorrisofs_options=() local bootmode @@ -762,6 +1004,7 @@ _build_iso() { typeset -f "_add_xorrisofs_options_${bootmode}" &> /dev/null && "_add_xorrisofs_options_${bootmode}" done + rm -f -- "${out_dir}/${image_name}" _msg_info "Creating ISO image..." xorriso -as mkisofs \ -iso-level 3 \ @@ -774,10 +1017,10 @@ _build_iso() { -publisher "${iso_publisher}" \ -preparer "prepared by ${app_name}" \ "${xorrisofs_options[@]}" \ - -output "${out_dir}/${img_name}" \ + -output "${out_dir}/${image_name}" \ "${isofs_dir}/" _msg_info "Done!" - du -h -- "${out_dir}/${img_name}" + du -h -- "${out_dir}/${image_name}" } # Read profile's values from profiledef.sh @@ -801,58 +1044,43 @@ _read_profile() { packages="$(realpath -- "${packages}")" pacman_conf="$(realpath -- "${pacman_conf}")" + # Resolve paths of files that may reside in the profile's directory + if [[ -z "$bootstrap_packages" ]] && [[ -e "${profile}/bootstrap_packages.${arch}" ]]; then + bootstrap_packages="${profile}/bootstrap_packages.${arch}" + bootstrap_packages="$(realpath -- "${bootstrap_packages}")" + pacman_conf="$(realpath -- "${pacman_conf}")" + fi + cd -- "${OLDPWD}" fi } # Validate set options _validate_options() { - local validation_error=0 bootmode - local pkg_list_from_file=() - _msg_info "Validating options..." - # Check if the package list file exists and read packages from it - if [[ -e "${packages}" ]]; then - mapfile -t pkg_list_from_file < <(sed '/^[[:blank:]]*#.*/d;s/#.*//;/^[[:blank:]]*$/d' "${packages}") - pkg_list+=("${pkg_list_from_file[@]}") - if (( ${#pkg_list_from_file} < 1 )); then - (( validation_error=validation_error+1 )) - _msg_error "No package specified in '${packages}'." 0 - fi - else - (( validation_error=validation_error+1 )) - _msg_error "File '${packages}' does not exist." 0 + local validation_error=0 _buildmode - fi + _msg_info "Validating options..." # Check if pacman configuration file exists if [[ ! -e "${pacman_conf}" ]]; then (( validation_error=validation_error+1 )) _msg_error "File '${pacman_conf}' does not exist." 0 fi - # Check if the specified bootmodes are supported - for bootmode in "${bootmodes[@]}"; do - if typeset -f "_make_bootmode_${bootmode}" &> /dev/null; then - if typeset -f "_validate_requirements_bootmode_${bootmode}" &> /dev/null; then - "_validate_requirements_bootmode_${bootmode}" + + # Check if the specified buildmodes are supported + for _buildmode in "${buildmodes[@]}"; do + if typeset -f "_build_buildmode_${_buildmode}" &> /dev/null; then + if typeset -f "_validate_requirements_buildmode_${_buildmode}" &> /dev/null; then + "_validate_requirements_buildmode_${_buildmode}" else - _msg_warning "Function '_validate_requirements_bootmode_${bootmode}' does not exist. Validating the requirements of '${bootmode}' boot mode will not be possible." + _msg_warning "Function '_validate_requirements_buildmode_${_buildmode}' does not exist. Validating the requirements of '${_buildmode}' build mode will not be possible." fi else (( validation_error=validation_error+1 )) - _msg_error "${bootmode} is not a valid boot mode!" 0 + _msg_error "${_buildmode} is not a valid build mode!" 0 fi done - # Check if the specified airootfs_image_type is supported - if typeset -f "_mkairootfs_${airootfs_image_type}" &> /dev/null; then - if typeset -f "_validate_requirements_airootfs_image_type_${airootfs_image_type}" &> /dev/null; then - "_validate_requirements_airootfs_image_type_${airootfs_image_type}" - else - _msg_warning "Function '_validate_requirements_airootfs_image_type_${airootfs_image_type}' does not exist. Validating the requirements of '${airootfs_image_type}' airootfs image type will not be possible." - fi - else - (( validation_error=validation_error+1 )) - _msg_error "Unsupported image type: '${airootfs_image_type}'" 0 - fi + if (( validation_error )); then _msg_error "${validation_error} errors were encountered while validating the profile. Aborting." 1 fi @@ -862,6 +1090,10 @@ _validate_options() { # Set defaults and, if present, overrides from mkarchiso command line option parameters _set_overrides() { # Set variables that have command line overrides + [[ ! -v override_buildmodes ]] || buildmodes=("${override_buildmodes[@]}") + if (( ${#buildmodes[@]} < 1 )); then + buildmodes+=('iso') + fi if [[ -v override_work_dir ]]; then work_dir="$override_work_dir" elif [[ -z "$work_dir" ]]; then @@ -881,6 +1113,7 @@ _set_overrides() { fi pacman_conf="$(realpath -- "$pacman_conf")" [[ ! -v override_pkg_list ]] || pkg_list+=("${override_pkg_list[@]}") + # TODO: allow overriding bootstrap_pkg_list if [[ -v override_iso_label ]]; then iso_label="$override_iso_label" elif [[ -z "$iso_label" ]]; then @@ -902,6 +1135,11 @@ _set_overrides() { install_dir="${app_name}" fi [[ ! -v override_gpg_key ]] || gpg_key="$override_gpg_key" + [[ ! -v override_gpg_sender ]] || gpg_sender="$override_gpg_sender" + if [[ -v override_cert_list ]]; then + sign_netboot_artifacts="y" + fi + [[ ! -v override_cert_list ]] || cert_list+=("${override_cert_list[@]}") if [[ -v override_quiet ]]; then quiet="$override_quiet" elif [[ -z "$quiet" ]]; then @@ -912,34 +1150,69 @@ _set_overrides() { [[ -n "$arch" ]] || arch="$(uname -m)" [[ -n "$airootfs_image_type" ]] || airootfs_image_type="squashfs" [[ -n "$iso_name" ]] || iso_name="${app_name}" - [[ -n "$img_name" ]] || img_name="${iso_name}-${iso_version}-${arch}.iso" } _export_gpg_publickey() { - gpg --batch --output "${work_dir}/pubkey.gpg" --export "${gpg_key}" + rm -f -- "${work_dir}/pubkey.gpg" + gpg --batch --no-armor --output "${work_dir}/pubkey.gpg" --export "${gpg_key}" } _make_version() { - install -d -m 0755 -- "${isofs_dir}/${install_dir}" - _msg_info "Creating files with iso version..." - printf '%s\n' "${iso_version}" > "${airootfs_dir}/version" - printf '%s\n' "${iso_version}" > "${isofs_dir}/${install_dir}/version" - printf '%.1024s' "$(printf '# GRUB Environment Block\nVERSION=%s\n%s' "${iso_version}" \ - "$(printf '%0.1s' "#"{1..1024})")" > "${isofs_dir}/${install_dir}/grubenv" + local _os_release + + _msg_info "Creating version files..." + # Write version file to system installation dir + rm -f -- "${pacstrap_dir}/version" + printf '%s\n' "${iso_version}" > "${pacstrap_dir}/version" + + if [[ "${buildmode}" == @("iso"|"netboot") ]]; then + install -d -m 0755 -- "${isofs_dir}/${install_dir}" + # Write version file to ISO 9660 + printf '%s\n' "${iso_version}" > "${isofs_dir}/${install_dir}/version" + # Write grubenv with version information to ISO 9660 + printf '%.1024s' "$(printf '# GRUB Environment Block\nNAME=%s\nVERSION=%s\n%s' \ + "${iso_name}" "${iso_version}" "$(printf '%0.1s' "#"{1..1024})")" \ + > "${isofs_dir}/${install_dir}/grubenv" + fi + + # Append IMAGE_ID & IMAGE_VERSION to os-release + _os_release="$(realpath -- "${pacstrap_dir}/etc/os-release")" + if [[ ! -e "${pacstrap_dir}/etc/os-release" && -e "${pacstrap_dir}/usr/lib/os-release" ]]; then + _os_release="$(realpath -- "${pacstrap_dir}/usr/lib/os-release")" + fi + if [[ "${_os_release}" != "${pacstrap_dir}"* ]]; then + _msg_warning "os-release file '${_os_release}' is outside of valid path." + else + [[ ! -e "${_os_release}" ]] || sed -i '/^IMAGE_ID=/d;/^IMAGE_VERSION=/d' "${_os_release}" + printf 'IMAGE_ID=%s\nIMAGE_VERSION=%s\n' "${iso_name}" "${iso_version}" >> "${_os_release}" + fi _msg_info "Done!" } _make_pkglist() { - install -d -m 0755 -- "${isofs_dir}/${install_dir}" _msg_info "Creating a list of installed packages on live-enviroment..." - pacman -Q --sysroot "${airootfs_dir}" > "${isofs_dir}/${install_dir}/pkglist.${arch}.txt" + case "${buildmode}" in + "bootstrap") + pacman -Q --sysroot "${pacstrap_dir}" > "${pacstrap_dir}/pkglist.${arch}.txt" + ;; + "iso"|"netboot") + install -d -m 0755 -- "${isofs_dir}/${install_dir}" + pacman -Q --sysroot "${pacstrap_dir}" > "${isofs_dir}/${install_dir}/pkglist.${arch}.txt" + ;; + esac _msg_info "Done!" } -_build_profile() { +# build the base for an ISO and/or a netboot target +_build_iso_base() { + local run_once_mode="base" + local buildmode_packages="${packages}" + # Set the package list to use + local buildmode_pkg_list=("${pkg_list[@]}") # Set up essential directory paths - airootfs_dir="${work_dir}/${arch}/airootfs" + pacstrap_dir="${work_dir}/${arch}/airootfs" isofs_dir="${work_dir}/iso" + # Create working directory [[ -d "${work_dir}" ]] || install -d -- "${work_dir}" # Write build date to file or if the file exists, read it from there @@ -958,12 +1231,62 @@ _build_profile() { _run_once _make_customize_airootfs _run_once _make_pkglist _make_bootmodes - _run_once _cleanup_airootfs + _run_once _cleanup_pacstrap_dir _run_once _prepare_airootfs_image - _run_once _build_iso } -while getopts 'p:C:L:P:A:D:w:o:g:vh?' arg; do +# Build the bootstrap buildmode +_build_buildmode_bootstrap() { + local image_name="${iso_name}-bootstrap-${iso_version}-${arch}.tar.gz" + local run_once_mode="${buildmode}" + local buildmode_packages="${bootstrap_packages}" + # Set the package list to use + local buildmode_pkg_list=("${bootstrap_pkg_list[@]}") + + # Set up essential directory paths + pacstrap_dir="${work_dir}/${arch}/bootstrap/root.${arch}" + [[ -d "${work_dir}" ]] || install -d -- "${work_dir}" + install -d -m 0755 -o 0 -g 0 -- "${pacstrap_dir}" + + [[ "${quiet}" == "y" ]] || _show_config + _run_once _make_pacman_conf + _run_once _make_packages + _run_once _make_version + _run_once _make_pkglist + _run_once _cleanup_pacstrap_dir + _run_once _build_bootstrap_image +} + +# Build the netboot buildmode +_build_buildmode_netboot() { + local run_once_mode="${buildmode}" + + _build_iso_base + if [[ -v cert_list ]]; then + _run_once _sign_netboot_artifacts + fi + _run_once _export_netboot_artifacts +} + +# Build the ISO buildmode +_build_buildmode_iso() { + local image_name="${iso_name}-${iso_version}-${arch}.iso" + local run_once_mode="${buildmode}" + _build_iso_base + _run_once _build_iso_image +} + +# build all buildmodes +_build() { + local buildmode + local run_once_mode="build" + + for buildmode in "${buildmodes[@]}"; do + _run_once "_build_buildmode_${buildmode}" + done +} + +while getopts 'c:p:C:L:P:A:D:w:m:o:g:G:vh?' arg; do case "${arg}" in p) read -r -a override_pkg_list <<< "${OPTARG}" ;; C) override_pacman_conf="${OPTARG}" ;; @@ -971,9 +1294,12 @@ while getopts 'p:C:L:P:A:D:w:o:g:vh?' arg; do P) override_iso_publisher="${OPTARG}" ;; A) override_iso_application="${OPTARG}" ;; D) override_install_dir="${OPTARG}" ;; + c) read -r -a override_cert_list <<< "${OPTARG}" ;; w) override_work_dir="${OPTARG}" ;; + m) read -r -a override_buildmodes <<< "${OPTARG}" ;; o) override_out_dir="${OPTARG}" ;; g) override_gpg_key="${OPTARG}" ;; + G) override_gpg_sender="${OPTARG}" ;; v) override_quiet="n" ;; h|?) _usage 0 ;; *) @@ -1000,6 +1326,6 @@ profile="$(realpath -- "${1}")" _read_profile _set_overrides _validate_options -_build_profile +_build # vim:ts=4:sw=4:et: