#!/usr/bin/env bash # we rely on some output which is parsed in english! unset LANG ANSWER="/tmp/.setup" TITLE="Arch Linux Installation" # use the first VT not dedicated to a running console LOG="/dev/tty7" # don't use /mnt because it's intended to mount other things there! DESTDIR="/install" RUNNING_ARCH="$(uname -m)" EDITOR="" _BLKID="blkid -c /dev/null" _LSBLK="lsblk -rpno" # name of kernel package KERNELPKG="linux" # name of the kernel image [[ "${RUNNING_ARCH}" == "x86_64" ]] && VMLINUZ="vmlinuz-${KERNELPKG}" if [[ "${RUNNING_ARCH}" == "aarch64" ]]; then VMLINUZ="Image.gz" VMLINUZ_EFISTUB="Image" fi # name of the initramfs filesystem INITRAMFS="initramfs-${KERNELPKG}" # name of intel ucode initramfs image INTEL_UCODE="intel-ucode.img" # name of amd ucode initramfs image AMD_UCODE="amd-ucode.img" # abstract the common pacman args PACMAN="pacman --root ${DESTDIR} --cachedir=${DESTDIR}/var/cache/pacman/pkg --noconfirm --noprogressbar" # downloader DLPROG="wget" # sources SYNC_URL="" MIRRORLIST="/etc/pacman.d/mirrorlist" unset PACKAGES # partitions PART_ROOT="" ROOTFS="" # install stages S_SRC=0 # choose mirror S_NET=0 # network configuration S_MKFS=0 # formatting S_MKFSAUTO=0 # auto fs part/formatting S_CONFIG=0 # configuration editing # menu item tracker- autoselect the next item NEXTITEM="" # DIALOG() # an el-cheapo dialog wrapper # # parameters: see dialog(1) # returns: whatever dialog did DIALOG() { dialog --backtitle "${TITLE}" --aspect 15 "$@" return $? } # chroot_mount() # prepares target system as a chroot # chroot_mount() { [[ -e "${DESTDIR}/proc" ]] || mkdir -m 555 "${DESTDIR}/proc" [[ -e "${DESTDIR}/sys" ]] || mkdir -m 555 "${DESTDIR}/sys" [[ -e "${DESTDIR}/dev" ]] || mkdir -m 755 "${DESTDIR}/dev" mount proc "${DESTDIR}/proc" -t proc -o nosuid,noexec,nodev mount sys "${DESTDIR}/sys" -t sysfs -o nosuid,noexec,nodev,ro mount udev "${DESTDIR}/dev" -t devtmpfs -o mode=0755,nosuid mount devpts "${DESTDIR}/dev/pts" -t devpts -o mode=0620,gid=5,nosuid,noexec mount shm "${DESTDIR}/dev/shm" -t tmpfs -o mode=1777,nosuid,nodev } # chroot_umount() # tears down chroot in target system # chroot_umount() { umount -R "${DESTDIR}/proc" umount -R "${DESTDIR}/sys" umount -R "${DESTDIR}/dev" } getfstype() { ${_LSBLK} FSTYPE "${1}" } # getfsuuid() # converts /dev devices to FSUUIDs # # parameters: device file # outputs: FSUUID on success # nothing on failure # returns: nothing getfsuuid() { ${_LSBLK} UUID "${1}" } # parameters: device file # outputs: LABEL on success # nothing on failure # returns: nothing getfslabel() { ${_LSBLK} LABEL "${1}" } getpartuuid() { ${_LSBLK} PARTUUID "${1}" } getpartlabel() { ${_LSBLK} PARTLABEL "${1}" } # list all net devices with mac adress net_interfaces() { find /sys/class/net/* -type l -printf '%f ' -exec cat {}/address \; } # activate_dmraid() # activate dmraid devices activate_dmraid() { if [[ -e /usr/bin/dmraid ]]; then DIALOG --infobox "Activating dmraid arrays..." 0 0 dmraid -ay -I -Z >/dev/null 2>&1 fi } # activate_lvm2 # activate lvm2 devices activate_lvm2() { ACTIVATE_LVM2="" if [[ -e /usr/bin/lvm ]]; then OLD_LVM2_GROUPS=${LVM2_GROUPS} OLD_LVM2_VOLUMES=${LVM2_VOLUMES} DIALOG --infobox "Scanning logical volumes..." 0 0 lvm vgscan --ignorelockingfailure >/dev/null 2>&1 DIALOG --infobox "Activating logical volumes..." 0 0 lvm vgchange --ignorelockingfailure --ignoremonitoring -ay >/dev/null 2>&1 LVM2_GROUPS="$(vgs -o vg_name --noheading 2>/dev/null)" LVM2_VOLUMES="$(lvs -o vg_name,lv_name --noheading --separator - 2>/dev/null)" [[ "${OLD_LVM2_GROUPS}" = "${LVM2_GROUPS}" && "${OLD_LVM2_VOLUMES}" = "${LVM2_VOLUMES}" ]] && ACTIVATE_LVM2="no" fi } # activate_raid # activate md devices activate_raid() { ACTIVATE_RAID="" if [[ -e /usr/bin/mdadm ]]; then DIALOG --infobox "Activating RAID arrays..." 0 0 mdadm --assemble --scan >/dev/null 2>&1 || ACTIVATE_RAID="no" fi } # activate_luks # activate luks devices activate_luks() { ACTIVATE_LUKS="" if [[ -e /usr/bin/cryptsetup ]]; then DIALOG --infobox "Scanning for luks encrypted devices..." 0 0 if ${_LSBLK} FSTYPE | grep -q "crypto_LUKS"; then for PART in $(${_LSBLK} NAME,FSTYPE | grep " crypto_LUKS$" | cut -d' ' -f 1); do # skip already encrypted devices, device mapper! if ! ${_LSBLK} TYPE "${PART}" | grep -q "crypt$"; then RUN_LUKS="" DIALOG --yesno "Setup detected luks encrypted device, do you want to activate ${PART} ?" 0 0 && RUN_LUKS="1" [[ "${RUN_LUKS}" = "1" ]] && _enter_luks_name && _enter_luks_passphrase && _opening_luks [[ "${RUN_LUKS}" = "" ]] && ACTIVATE_LUKS="no" else ACTIVATE_LUKS="no" fi done else ACTIVATE_LUKS="no" fi fi } # activate_special_devices() # activate special devices: # activate dmraid, lvm2 and raid devices, if not already activated during bootup! # run it more times if needed, it can be hidden by each other! activate_special_devices() { ACTIVATE_RAID="" ACTIVATE_LUKS="" ACTIVATE_LVM2="" activate_dmraid while ! [[ "${ACTIVATE_LVM2}" = "no" && "${ACTIVATE_RAID}" = "no" && "${ACTIVATE_LUKS}" = "no" ]]; do activate_raid activate_lvm2 activate_luks done } # destdir_mounts() # check if PART_ROOT is set and if something is mounted on ${DESTDIR} destdir_mounts(){ # Don't ask for filesystem and create new filesystems ASK_MOUNTPOINTS="" PART_ROOT="" # check if something is mounted on ${DESTDIR} PART_ROOT="$(mount | grep "${DESTDIR} " | cut -d' ' -f 1)" # Run mountpoints, if nothing is mounted on ${DESTDIR} if [[ "${PART_ROOT}" = "" ]]; then DIALOG --msgbox "Setup couldn't detect mounted partition(s) in ${DESTDIR}, please set mountpoints first." 0 0 detect_uefi_boot mountpoints || return 1 fi } # lists linux blockdevices blockdevices() { # all available block disk devices for dev in $(${_LSBLK} NAME,TYPE | grep "disk$" | cut -d' ' -f1); do # exclude checks: #- dmraid_devices # ${_LSBLK} TYPE ${dev} | grep "dmraid" #- iso9660 devices # (${_LSBLK} FSTYPE ${dev} | grep "iso9660" #- fakeraid isw devices # ${_LSBLK} FSTYPE ${dev} | grep "isw_raid_member" #- fakeraid ddf devices # ${_LSBLK} FSTYPE ${dev} | grep "ddf_raid_member" if ! ${_LSBLK} TYPE "${dev}" 2>/dev/null | grep -q "dmraid" || ${_LSBLK} FSTYPE "${dev}" 2>/dev/null | grep -q "iso9660" || ${_LSBLK} FSTYPE "${dev}" 2>/dev/null | grep -q "isw_raid_member" || ${_LSBLK} FSTYPE "${dev}" 2>/dev/null | grep -q "ddf_raid_member"; then echo "${dev}" [[ "${1}" ]] && echo "${1}" fi done } # lists linux blockdevice partitions blockdevices_partitions() { # all available block devices partitions # printk off needed cause of parted usage printk off for part in $(${_LSBLK} NAME,TYPE | grep -v '^/dev/md' | grep "part$"| cut -d' ' -f1); do # exclude checks: #- part of raid device # ${_LSBLK} FSTYPE ${part} | grep "linux_raid_member" #- part of lvm2 device # ${_LSBLK} FSTYPE /dev/${part} | grep "LVM2_member" #- part of luks device # ${_LSBLK} FSTYPE /dev/${part} | grep "crypto_LUKS" #- extended partition # sfdisk -l 2>/dev/null | grep "${part}" | grep "Extended$" # - extended partition (LBA) # sfdisk -l 2>/dev/null | grep "${part}" | grep "(LBA)$" #- bios_grub partitions # "echo ${part} | grep "[a-z]$(parted -s $(${_LSBLK} PKNAME ${part}) print 2>/dev/null | grep bios_grub | cut -d " " -f 2)$" #- iso9660 devices # "${_LSBLK} FSTYPE -s ${part} | grep "iso9660" if ! (${_LSBLK} FSTYPE "${part}" 2>/dev/null | grep -q "linux_raid_member" || ${_LSBLK} FSTYPE "${part}" 2>/dev/null | grep -q "LVM2_member" || ${_LSBLK} FSTYPE "${part}" 2>/dev/null | grep -q "crypto_LUKS" || sfdisk -l 2>/dev/null | grep "${part}" | grep -q "Extended$" || sfdisk -l 2>/dev/null | grep "${part}" | grep -q "(LBA)$" || echo "${part}" | grep -q "[a-z]$(parted -s "$(${_LSBLK} PKNAME "${part}" 2>/dev/null)" print 2>/dev/null | grep bios_grub | cut -d " " -f 2)$" || ${_LSBLK} FSTYPE -s "${part}" 2>/dev/null | grep -q "iso9660"); then echo "${part}" [[ "${1}" ]] && echo "${1}" fi done printk on } # list none partitionable raid md devices raid_devices() { for dev in $(${_LSBLK} NAME,TYPE | grep " raid.*$" | cut -d' ' -f 1 | sort -u); do # exclude checks: # - part of lvm2 device_found # ${_LSBLK} FSTYPE ${dev} | grep "LVM2_member" # - part of luks device # ${_LSBLK} FSTYPE ${dev} | grep "crypto_LUKS" # - part of isw fakeraid # ${_LSBLK} FSTYPE ${dev} -s | grep "isw_raid_member" # - part of ddf fakeraid # ${_LSBLK} FSTYPE ${dev} -s | grep "ddf_raid_member" if ! (${_LSBLK} FSTYPE "${dev}" 2>/dev/null | grep -q "LVM2_member" || ${_LSBLK} FSTYPE "${dev}" 2>/dev/null | grep -q "crypto_LUKS" || ${_LSBLK} FSTYPE "${dev}" -s 2>/dev/null | grep -q "isw_raid_member" || ${_LSBLK} FSTYPE "${dev}" -s 2>/dev/null | grep -q "ddf_raid_member" || find "$dev"*p* -type f -exec echo {} \; 2>/dev/null ); then echo "${dev}" [[ "${1}" ]] && echo "${1}" fi done } # lists linux partitionable raid devices partitions partitionable_raid_devices_partitions() { for part in $(${_LSBLK} NAME,TYPE | grep "part$" | grep "^/dev/md.*p" 2>/dev/null | cut -d' ' -f 1 | sort -u) ; do # exclude checks: # - part of lvm2 device_found # ${_LSBLK} FSTYPE ${part} | grep "LVM2_member" # - part of luks device # ${_LSBLK} FSTYPE ${part} | grep "crypto_LUKS" # - extended partition # sfdisk -l 2>/dev/null | grep "${part}" | grep "Extended$" # - extended partition (LBA) # sfdisk -l 2>/dev/null | grep "${part}" | grep "(LBA)$" # - part of isw fakeraid # ${_LSBLK} FSTYPE ${dev} -s | grep "isw_raid_member" # - part of ddf fakeraid # ${_LSBLK} FSTYPE ${dev} -s | grep "ddf_raid_member" if ! (${_LSBLK} FSTYPE "${part}" 2>/dev/null | grep -q "LVM2_member" || ${_LSBLK} FSTYPE "${part}" 2>/dev/null | grep -q "crypto_LUKS" || sfdisk -l 2>/dev/null | grep "${part}" | grep -q "Extended$" || sfdisk -l 2>/dev/null | grep "${part}" | grep -q "(LBA)$" || ${_LSBLK} FSTYPE "${dev}" -s 2>/dev/null | grep -q "isw_raid_member" || ${_LSBLK} FSTYPE "${dev}" -s 2>/dev/null | grep -q "ddf_raid_member"); then echo "${part}" [[ "${1}" ]] && echo "${1}" fi done } # lists dmraid devices dmraid_devices() { for dev in $(${_LSBLK} NAME,TYPE | grep "dmraid$" | cut -d' ' -f 1 | grep -v "_.*p.*$" | sort -u); do echo "${dev}" [[ "${1}" ]] && echo "${1}" done # isw_raid_member, managed by mdadm for dev in $(${_LSBLK} NAME,TYPE 2>/dev/null | grep " raid.*$" | cut -d' ' -f 1 | sort -u); do if ${_LSBLK} NAME,FSTYPE -s "${dev}" | grep "isw_raid_member$" | cut -d' ' -f 1; then echo "${dev}" [[ "${1}" ]] && echo "${1}" fi done # ddf_raid_member, managed by mdadm for dev in $(${_LSBLK} NAME,TYPE 2>/dev/null | grep " raid.*$" | cut -d' ' -f 1 | sort -u); do if ${_LSBLK} NAME,FSTYPE -s "${dev}" | grep "ddf_raid_member$" | cut -d' ' -f 1; then echo "${dev}" [[ "${1}" ]] && echo "${1}" fi done } # dmraid_partitions # - show dmraid partitions dmraid_partitions() { for part in $(${_LSBLK} NAME,TYPE | grep "dmraid$" | cut -d' ' -f 1 | grep "_.*p.*$" | sort -u); do # exclude checks: # - part of lvm2 device # ${_LSBLK} FSTYPE ${dev} | grep "LVM2_member" # - part of luks device # ${_LSBLK} FSTYPE ${dev} | grep "crypto_LUKS" # - part of raid device # ${_LSBLK} FSTYPE ${dev} | grep "linux_raid_member$" # - extended partition # $(sfdisk -l 2>/dev/null | grep "${part}" | grep "Extended$" # - extended partition (LBA) # sfdisk -l 2>/dev/null | grep "${part}" | grep "(LBA)$") if ! (${_LSBLK} FSTYPE "${part}" 2>/dev/null | grep -q "crypto_LUKS$" || ${_LSBLK} FSTYPE "${part}" 2>/dev/null | grep -q "LVM2_member$" || ${_LSBLK} FSTYPE "${part}" 2>/dev/null | grep -q "linux_raid_member$" || sfdisk -l 2>/dev/null | grep "${part}" | grep -q "Extended$"|| sfdisk -l 2>/dev/null | grep "${part}" | grep -q "(LBA)$"); then echo "${part}" [[ "${1}" ]] && echo "${1}" fi done # isw_raid_member, managed by mdadm for dev in $(${_LSBLK} NAME,TYPE | grep " md$" | cut -d' ' -f 1 | sort -u); do if ${_LSBLK} NAME,FSTYPE -s "${dev}" 2>/dev/null | grep "isw_raid_member$" | cut -d' ' -f 1; then echo "${dev}" [[ "${1}" ]] && echo "${1}" fi done # ddf_raid_member, managed by mdadm for dev in $(${_LSBLK} NAME,TYPE | grep " md$" | cut -d' ' -f 1 | sort -u); do if ${_LSBLK} NAME,FSTYPE -s "${dev}" 2>/dev/null | grep "ddf_raid_member$" | cut -d' ' -f 1; then echo "${dev}" [[ "${1}" ]] && echo "${1}" fi done } # dm_devices # - show device mapper devices: # lvm2 and cryptdevices dm_devices() { for dev in $(${_LSBLK} NAME,TYPE | grep -e "lvm$" -e "crypt$" | cut -d' ' -f1 | sort -u); do # exclude checks: # - part of lvm2 device # ${_LSBLK} FSTYPE ${dev} | grep "LVM2_member" # - part of luks device # ${_LSBLK} FSTYPE ${dev} | grep "crypto_LUKS" # - part of raid device # ${_LSBLK} FSTYPE ${dev} | grep "linux_raid_member$" # - part of running raid on encrypted device # ${_LSBLK} TYPE ${dev} | grep "raid.*$ if ! (${_LSBLK} FSTYPE "${dev}" | grep -q "crypto_LUKS$" 2>/dev/null || ${_LSBLK} FSTYPE "${dev}" | grep -q "LVM2_member$" 2>/dev/null || ${_LSBLK} FSTYPE "${dev}" 2>/dev/null | grep -q "linux_raid_member$" || ${_LSBLK} TYPE "${dev}" 2>/dev/null | grep -q "raid.*$"); then echo "${dev}" [[ "${1}" ]] && echo "${1}" fi done } finddisks() { blockdevices "${1}" dmraid_devices "${1}" } findpartitions() { blockdevices_partitions "${1}" dm_devices "${1}" dmraid_partitions "${1}" raid_devices "${1}" partitionable_raid_devices_partitions "${1}" } # don't check on raid devices! findbootloaderdisks() { if ! [[ "${USE_DMRAID}" = "1" ]]; then blockdevices "${1}" else dmraid_devices "${1}" fi } # don't list raid devices, lvm2 and devicemapper! findbootloaderpartitions() { if ! [[ "${USE_DMRAID}" = "1" ]]; then blockdevices_partitions "${1}" else dmraid_partitions "${1}" fi } # find any gpt/guid formatted disks find_gpt() { GUID_DETECTED="" for i in $(finddisks); do [[ "$(${_BLKID} -p -i -o value -s PTTYPE "${i}")" == "gpt" ]] && GUID_DETECTED="1" done } # freeze and unfreeze xfs, as hack for grub(2) installing freeze_xfs() { sync if [[ -x /usr/bin/xfs_freeze ]]; then if grep -q "${DESTDIR}/boot " /proc/mounts | grep -q " xfs "; then xfs_freeze -f ${DESTDIR}/boot >/dev/null 2>&1 xfs_freeze -u ${DESTDIR}/boot >/dev/null 2>&1 fi if grep -q "${DESTDIR} " /proc/mounts | grep -q " xfs "; then xfs_freeze -f ${DESTDIR} >/dev/null 2>&1 xfs_freeze -u ${DESTDIR} >/dev/null 2>&1 fi fi } printk() { case ${1} in "on") echo 4 >/proc/sys/kernel/printk ;; "off") echo 0 >/proc/sys/kernel/printk ;; esac } getdest() { [[ "${DESTDIR}" ]] && return 0 DIALOG --inputbox "Enter the destination directory where your target system is mounted" 8 65 "${DESTDIR}" 2>${ANSWER} || return 1 DESTDIR=$(cat ${ANSWER}) } # geteditor() # prompts the user to choose an editor # sets EDITOR global variable # geteditor() { if ! [[ "${EDITOR}" ]]; then DIALOG --menu "Select a Text Editor to Use" 10 35 3 \ "1" "nano (easier)" \ "2" "vi" 2>${ANSWER} || return 1 case $(cat ${ANSWER}) in "1") EDITOR="nano" ;; "2") EDITOR="vi" ;; esac fi } # set device name scheme set_device_name_scheme() { NAME_SCHEME_PARAMETER="" NAME_SCHEME_LEVELS="" MENU_DESC_TEXT="" # check if gpt/guid formatted disks are there find_gpt ## util-linux root=PARTUUID=/root=PARTLABEL= support - https://git.kernel.org/?p=utils/util-linux/util-linux.git;a=commitdiff;h=fc387ee14c6b8672761ae5e67ff639b5cae8f27c;hp=21d1fa53f16560dacba33fffb14ffc05d275c926 ## mkinitcpio's init root=PARTUUID= support - https://projects.archlinux.org/mkinitcpio.git/tree/init_functions#n185 if [[ "${GUID_DETECTED}" == "1" ]]; then NAME_SCHEME_LEVELS="${NAME_SCHEME_LEVELS} PARTUUID PARTUUID= PARTLABEL PARTLABEL=" MENU_DESC_TEXT="\nPARTUUID and PARTLABEL are specific to GPT disks.\nIn GPT disks, PARTUUID is recommended.\nIn MBR/msdos disks," fi NAME_SCHEME_LEVELS="${NAME_SCHEME_LEVELS} FSUUID UUID= FSLABEL LABEL=