#!/bin/bash ################################################################################ ### INSTRUCTIONS AT https://github.com/gh2o/digitalocean-debian-to-arch/ ### ################################################################################ run_from_file() { local f t for f in /dev/fd/*; do [ -h ${f} ] || continue [ ${f} -ef "${0}" ] && return done t=$(mktemp) cat >${t} if [ "$(head -n 1 ${t})" = '#!/bin/bash' ]; then chmod +x ${t} exec /bin/bash ${t} "$@" &2 echo "Please try bash instead." >&2 exit 1 fi } # do not modify the two lines below [ -h /dev/fd/0 ] && run_from_file #!/bin/bash ### CONFIGURATION archlinux_mirror="https://mirrors.kernel.org/archlinux/" preserve_home_directories=true if [ -n "${POSIXLY_CORRECT}" ] || [ -z "${BASH_VERSION}" ]; then unset POSIXLY_CORRECT exec /bin/bash "${0}" "$@" exit 1 fi set -eu set -o pipefail shopt -s nullglob shopt -s dotglob export LC_ALL=C export LANG=C unset LANGUAGE declare -A dependencies dependencies[pacman]=x log() { echo "[$(date)]" "$@" >&2 } mask2prefix() { local prefix=0 netmask=${1} for octet in ${netmask//./ }; do for bitmask in 128 64 32 16 8 4 2 1; do (( $bitmask & $octet )) && (( prefix+=1 )) || break 2 done done echo ${prefix} } clean_archroot() { local file local prompted=false local lsfd while read file <&${lsfd}; do if [ "${file}" = "installer" ] || [ "${file}" = "packages" ]; then continue fi if ! $prompted; then log "Your /archroot directory contains a stale installation or other data." log "Remove it?" local response read -p '(yes or [no]) ' response if [ "${response}" = "yes" ]; then prompted=true else break fi fi rm -rf "/archroot/${file}" done {lsfd}< <(ls /archroot) } install_haveged() { if which haveged >/dev/null 2>&1; then return fi log "Creating keys for pacman will be very slow because" log "KVM lacks true sources of ramdomness. Install haveged" log "to speed it up?" local response read -p '([yes] or no) ' response if [ "${response}" = "yes" ] || [ -z "${response}" ]; then apt-get -y install haveged fi } initialize_coredb() { log "Downloading package database ..." wget "${archlinux_mirror}/core/os/x86_64/core.db" log "Unpacking package database ..." mkdir core tar -zxf core.db -C core } remove_version() { echo "${1}" | grep -o '^[A-Za-z0-9_-]*' } get_package_directory() { local dir pkg for dir in core/${1}-*; do if [ "$(get_package_value ${dir}/desc NAME)" = "${1}" ]; then echo "${dir}" return fi done for dir in core/*; do while read pkg; do pkg=$(remove_version "${pkg}") if [ "${pkg}" = "${1}" ]; then echo "${dir}" return fi done < <(get_package_array ${dir}/depends PROVIDES) done log "Package '${1}' not found." } get_package_value() { local infofile=${1} local infokey=${2} get_package_array ${infofile} ${infokey} | ( local value read value echo "${value}" ) } get_package_array() { local infofile=${1} local infokey=${2} local line while read line; do if [ "${line}" = "%${infokey}%" ]; then while read line; do if [ -z "${line}" ]; then return fi echo "${line}" done fi done < ${infofile} } calculate_dependencies() { log "Calculating dependencies ..." local dirty=true local pkg dir dep while $dirty; do dirty=false for pkg in "${!dependencies[@]}"; do dir=$(get_package_directory $pkg) while read line; do dep=$(remove_version "${line}") if [ -z "${dependencies[$dep]:-}" ]; then dependencies[$dep]=x dirty=true fi done < <(get_package_array ${dir}/depends DEPENDS) done done } download_packages() { log "Downloading packages ..." mkdir -p /archroot/packages local pkg dir filename sha256 localfn for pkg in "${!dependencies[@]}"; do dir=$(get_package_directory ${pkg}) filename=$(get_package_value ${dir}/desc FILENAME) sha256=$(get_package_value ${dir}/desc SHA256SUM) localfn=/archroot/packages/${filename} if [ -e "${localfn}" ] && ( echo "${sha256} ${localfn}" | sha256sum -c ); then continue fi wget "${archlinux_mirror}/core/os/x86_64/${filename}" -O "${localfn}" if [ -e "${localfn}" ] && ( echo "${sha256} ${localfn}" | sha256sum -c ); then continue fi log "Couldn't download package '${pkg}'." false done } extract_packages() { log "Extracting packages ..." local dir filename for pkg in "${!dependencies[@]}"; do dir=$(get_package_directory ${pkg}) filename=$(get_package_value ${dir}/desc FILENAME) xz -dc /archroot/packages/${filename} | tar -C /archroot -xf - done } mount_virtuals() { log "Mounting virtual filesystems ..." mount -t proc proc /archroot/proc mount -t sysfs sys /archroot/sys mount --bind /dev /archroot/dev mount -t devpts pts /archroot/dev/pts } prebootstrap_configuration() { log "Doing pre-bootstrap configuration ..." rmdir /archroot/var/cache/pacman/pkg ln -s ../../../packages /archroot/var/cache/pacman/pkg chroot /archroot /usr/bin/update-ca-certificates --fresh } bootstrap_system() { local shouldbootstrap=false isbootstrapped=false while ! $isbootstrapped; do if $shouldbootstrap; then log "Bootstrapping system ..." chroot /archroot pacman-key --init chroot /archroot pacman-key --populate archlinux chroot /archroot pacman -Sy --force --noconfirm base openssh kexec-tools isbootstrapped=true else shouldbootstrap=true fi # config overwritten by pacman rm -f /archroot/etc/resolv.conf.pacorig cp /etc/resolv.conf /archroot/etc/resolv.conf rm -f /archroot/etc/pacman.d/mirrorlist.pacorig echo "Server = ${archlinux_mirror}"'/$repo/os/$arch' \ >> /archroot/etc/pacman.d/mirrorlist done } postbootstrap_configuration() { log "Doing post-bootstrap configuration ..." # set up fstab echo "LABEL=DOROOT / ext4 defaults 0 1" >> /archroot/etc/fstab # set up shadow ( umask 077 { grep '^root:' /etc/shadow grep -v '^root:' /archroot/etc/shadow } > /archroot/etc/shadow.new cat /archroot/etc/shadow.new > /archroot/etc/shadow rm /archroot/etc/shadow.new ) # set up network local grepfd local ipaddr netmask gateway prefixlen local eni=/etc/network/interfaces exec {grepfd}< <( grep -m 1 -o 'address [0-9.]\+' ${eni} grep -m 1 -o 'netmask [0-9.]\+' ${eni} grep -m 1 -o 'gateway [0-9.]\+' ${eni} ) read ignored ipaddr <&${grepfd} read ignored netmask <&${grepfd} read ignored gateway <&${grepfd} exec {grepfd}<&- prefixlen=$(mask2prefix ${netmask}) cat > /archroot/etc/systemd/network/internet.network < ${unitdir}/installer-cleanup.service < ${unitdir}/arch-kernel.service <