#! /bin/bash # Set globals # ***************************** VERSION="1.5.3" # ***************************** TMPDIR=/var/tmp/manjaro-arm-installer ARCH='aarch64' CARCH=$(uname -m) NSPAWN='systemd-nspawn -q --resolv-conf=copy-host --timezone=off -D' srv_list=/var/tmp/manjaro-arm-installer/services_list # set colorscheme if [[ -f "./dialogrc_gui" ]]; then export DIALOGRC="./dialogrc_gui" else export DIALOGRC="/etc/manjaro-arm-installer/dialogrc_gui" fi BRANCH="arm-stable" if [[ -n $1 ]]; then BRANCH=$1 fi # clearing variables DEVICE="" EDITION="" USER="" USERGROUPS="" FULLNAME="" PASSWORD="" CONFIRMPASSWORD="" CONFIRMROOTPASSWORD="" ROOTPASSWORD="" SDCARD="" SDTYP="" SDDEV="" DEV_NAME="" FSTYPE="" TIMEZONE="" LOCALE="" HOSTNAME="" CRYPT="" # check if root if [ "$EUID" -ne 0 ]; then echo "*******************************************************************************************" echo "* *" echo "* This script requires root permissions to run. Please run as root or with sudo! *" echo "* *" echo "*******************************************************************************************" exit fi # Sanity checks for dependencies declare -a DEPENDENCIES=("git" "parted" "systemd-nspawn" "wget" "dialog" "bsdtar" "openssl" "awk" "btrfs" "mkfs.vfat" "mkfs.btrfs" "mkfs.f2fs" "cryptsetup") for i in "${DEPENDENCIES[@]}"; do if ! [[ -f "/bin/$i" || -f "/sbin/$i" || -f "/usr/bin/$i" || -f "/usr/sbin/$i" ]] ; then echo "$i command is missing! Please install the relevant package." exit 1 fi done if [[ "$CARCH" != "aarch64" ]]; then if [ ! -f "/usr/lib/binfmt.d/qemu-aarch64-static.conf" ]; then echo "qemu-aarch64-static.conf file is missing. Please install the relevant package." exit 1 fi fi # Functions msg() { ALL_OFF="\e[1;0m" BOLD="\e[1;1m" GREEN="${BOLD}\e[1;32m" local mesg=$1; shift printf "${GREEN}==>${ALL_OFF}${BOLD} ${mesg}${ALL_OFF}\n" "$@" >&2 } info() { ALL_OFF="\e[1;0m" BOLD="\e[1;1m" BLUE="${BOLD}\e[1;34m" local mesg=$1; shift printf "${BLUE} ->${ALL_OFF}${BOLD} ${mesg}${ALL_OFF}\n" "$@" >&2 } usage_build_installer() { echo "Usage: ${0##*/} [options]" echo ' -h This help' echo '' echo '' exit $1 } get_timer(){ echo $(date +%s) } # $1: start timer elapsed_time(){ echo $(echo $1 $(get_timer) | awk '{ printf "%0.2f",($2-$1)/60 }') } show_elapsed_time(){ msg "Time %s: %s minutes..." "$1" "$(elapsed_time $2)" } installer_getarmprofiles () { info "Getting package lists ready for $DEVICE $EDITION edition..." rm -rf $TMPDIR/arm-profiles mkdir -p $TMPDIR chmod 777 $TMPDIR git clone https://gitlab.manjaro.org/manjaro-arm/applications/arm-profiles.git $TMPDIR/arm-profiles/ 1> /dev/null 2>&1 } create_install() { msg "Creating install for $DEVICE..." info "Used device is ${SDCARD}" # fetch and extract rootfs info "Downloading latest $ARCH rootfs..." cd $TMPDIR if [ -f Manjaro-ARM-$ARCH-latest.tar.gz* ]; then rm Manjaro-ARM_$ARCH-latest.tar.gz* fi wget -q --show-progress --progress=bar:force:noscroll https://github.com/manjaro-arm/rootfs/releases/latest/download/Manjaro-ARM-$ARCH-latest.tar.gz info "Extracting $ARCH rootfs..." bsdtar -xpf $TMPDIR/Manjaro-ARM-$ARCH-latest.tar.gz -C $TMPDIR/root # Create a "marker" that tells the packages that they're installed as part of building # an image, which is currently used by the "generic-post-install" package only touch $TMPDIR/root/MANJARO-ARM-IMAGE-BUILD # Make this symlink available, it's created by systemd on a running system mkdir -p $TMPDIR/root/etc ln -sf ../usr/lib/os-release $TMPDIR/root/etc/os-release info "Setting up keyrings..." $NSPAWN $TMPDIR/root pacman-key --init 1> /dev/null 2>&1 $NSPAWN $TMPDIR/root pacman-key --populate archlinuxarm manjaro manjaro-arm 1> /dev/null 2>&1 info "Setting target branch ${BRANCH}..." sed -i 's|^Branch.*|Branch = '${BRANCH}'|' $TMPDIR/root/etc/pacman-mirrors.conf info "Generating mirrorlist..." $NSPAWN $TMPDIR/root pacman-mirrors -f10 1> /dev/null 2>&1 info "Installing packages for $EDITION on $DEVICE..." # Setup cache mount mkdir -p $TMPDIR/pkg-cache mount -o bind $TMPDIR/pkg-cache $TMPDIR/root/var/cache/pacman/pkg # Install device and editions specific packages $NSPAWN $TMPDIR/root pacman -Syyu base manjaro-system manjaro-release systemd systemd-libs $PKG_SHARED $PKG_EDITION $PKG_DEVICE --noconfirm info "Enabling services..." # Enable services $NSPAWN $TMPDIR/root systemctl enable getty.target haveged.service 1>/dev/null while read service; do if [ -e $TMPDIR/root/usr/lib/systemd/system/$service ]; then echo "Enabling $service ..." $NSPAWN $TMPDIR/root systemctl enable $service 1>/dev/null else echo "$service not found in rootfs. Skipping." fi done < $srv_list if [ -f $TMPDIR/root/usr/bin/xdg-user-dirs-update ]; then $NSPAWN $TMPDIR/root systemctl --global enable xdg-user-dirs-update.service 1> /dev/null 2>&1 fi info "Applying overlay for $EDITION..." cp -ap $TMPDIR/arm-profiles/overlays/$EDITION/* $TMPDIR/root/ info "Setting up users..." #setup users echo "$USER" > $TMPDIR/user echo "$PASSWORD" > $TMPDIR/password echo "$ROOTPASSWORD" > $TMPDIR/rootpassword info "Setting password for root ..." $NSPAWN $TMPDIR/root awk -i inplace -F: "BEGIN {OFS=FS;} \$1 == \"root\" {\$2=\"$(openssl passwd -6 $(cat $TMPDIR/rootpassword))\"} 1" /etc/shadow 1> /dev/null 2>&1 if [[ "$EDITION" = "plasma-mobile" ]]; then $NSPAWN $TMPDIR/root userdel -f -r kde elif [[ "$EDITION" = "phosh" ]]; then $NSPAWN $TMPDIR/root userdel -f -r manjaro fi info "Adding user..." $NSPAWN $TMPDIR/root useradd -m -G wheel,sys,audio,input,video,storage,lp,network,users,power -p $(openssl passwd -6 $(cat $TMPDIR/password)) -s /bin/bash $(cat $TMPDIR/user) 1> /dev/null 2>&1 $NSPAWN $TMPDIR/root usermod -aG $USERGROUPS $(cat $TMPDIR/user) 1> /dev/null 2>&1 $NSPAWN $TMPDIR/root chfn -f "$FULLNAME" $(cat $TMPDIR/user) 1> /dev/null 2>&1 info "Enabling user services..." if [[ "$EDITION" = "minimal" ]] || [[ "$EDITION" = "server" ]]; then echo "No user services for $EDITION edition" else $NSPAWN $TMPDIR/root --user $(cat $TMPDIR/user) systemctl --user enable pulseaudio.service 1> /dev/null 2>&1 fi info "Setting up system settings..." #system setup $NSPAWN $TMPDIR/root chmod u+s /usr/bin/ping 1> /dev/null 2>&1 rm -f $TMPDIR/root/etc/ssl/certs/ca-certificates.crt rm -f $TMPDIR/root/etc/ca-certificates/extracted/tls-ca-bundle.pem cp -a /etc/ssl/certs/ca-certificates.crt $TMPDIR/root/etc/ssl/certs/ cp -a /etc/ca-certificates/extracted/tls-ca-bundle.pem $TMPDIR/root/etc/ca-certificates/extracted/ $NSPAWN $TMPDIR/root ln -sf /usr/share/zoneinfo/"$TIMEZONE" /etc/localtime 1> /dev/null 2>&1 $NSPAWN $TMPDIR/root timedatectl set-ntp true /dev/null 2>&1 $NSPAWN $TMPDIR/root sed -i s/"#$LOCALE"/"$LOCALE"/g /etc/locale.gen 1> /dev/null 2>&1 echo "LANG=$LOCALE" | tee --append $TMPDIR/root/etc/locale.conf 1> /dev/null 2>&1 $NSPAWN $TMPDIR/root locale-gen echo "KEYMAP=$CLIKEYMAP" | tee --append $TMPDIR/root/etc/vconsole.conf 1> /dev/null 2>&1 if [[ "$EDITION" != "minimal" ]] && [[ "$EDITION" != "server" ]] && [[ "$EDITION" != "sway" ]]; then echo 'Section "InputClass"' > $TMPDIR/root/etc/X11/xorg.conf.d/00-keyboard.conf echo 'Identifier "system-keyboard"' >> $TMPDIR/root/etc/X11/xorg.conf.d/00-keyboard.conf echo 'Option "XkbLayout" "us"' >> $TMPDIR/root/etc/X11/xorg.conf.d/00-keyboard.conf echo 'EndSection' >> $TMPDIR/root/etc/X11/xorg.conf.d/00-keyboard.conf sed -i s/"us"/"$X11KEYMAP"/ $TMPDIR/root/etc/X11/xorg.conf.d/00-keyboard.conf fi if [[ "$EDITION" = "sway" ]]; then sed -i s/"us"/"$X11KEYMAP"/ $TMPDIR/root/etc/sway/inputs/default-keyboard 1> /dev/null 2>&1 fi echo "$HOSTNAME" | tee --append $TMPDIR/root/etc/hostname 1> /dev/null 2>&1 sed -i s/"enable systemd-resolved.service"/"#enable systemd-resolved.service"/ $TMPDIR/root/usr/lib/systemd/system-preset/90-systemd.preset if [[ "$EDITION" = "plasma-mobile" ]]; then sed -i "s/User=kde/User=$USER/g" $TMPDIR/root/etc/sddm.conf.d/00-default.conf fi echo "Correcting permissions from overlay..." chown -R root:root $TMPDIR/root/etc chown -R root:root $TMPDIR/root/usr/{local,share} if [[ -d $TMPDIR/root/etc/polkit-1/rules.d ]]; then chown root:polkitd $TMPDIR/root/etc/polkit-1/rules.d fi if [[ -d $TMPDIR/root/usr/share/polkit-1/rules.d ]]; then chown root:polkitd $TMPDIR/root/usr/share/polkit-1/rules.d fi if [[ "$EDITION" = "cubocore" ]]; then cp $TMPDIR/root/usr/share/applications/corestuff.desktop $TMPDIR/root/etc/xdg/autostart/ fi case "$FSTYPE" in btrfs) info "Adding btrfs support to system..." if [ -f $TMPDIR/root/boot/extlinux/extlinux.conf ]; then sed -i 's/APPEND/& rootflags=subvol=@/' $TMPDIR/root/boot/extlinux/extlinux.conf elif [ -f $TMPDIR/root/boot/boot.ini ]; then sed -i 's/setenv bootargs /&rootflags=subvol=@ /' $TMPDIR/root/boot/boot.ini elif [ -f $TMPDIR/root/boot/uEnv.ini ]; then sed -i 's/setenv bootargs /&rootflags=subvol=@ /' $TMPDIR/root/boot/uEnv.ini #elif [ -f $TMPDIR/root/boot/cmdline.txt ]; then # sed -i 's/^/rootflags=subvol=@ rootfstype=btrfs /' $TMPDIR/root/boot/cmdline.txt elif [ -f $TMPDIR/root/boot/boot.txt ]; then sed -i 's/setenv bootargs/& rootflags=subvol=@/' $TMPDIR/root/boot/boot.txt $NSPAWN $TMPDIR/root mkimage -A arm -O linux -T script -C none -n "U-Boot boot script" -d /boot/boot.txt /boot/boot.scr fi echo "LABEL=ROOT_MNJRO / btrfs subvol=@,compress=zstd,defaults,noatime 0 0" >> $TMPDIR/root/etc/fstab echo "LABEL=ROOT_MNJRO /home btrfs subvol=@home,compress=zstd,defaults,noatime 0 0" >> $TMPDIR/root/etc/fstab sed -i '/^MODULES/{s/)/ btrfs)/}' $TMPDIR/root/etc/mkinitcpio.conf $NSPAWN $TMPDIR/root mkinitcpio -P 1> /dev/null 2>&1 ;; f2fs) info "Adding f2fs support to system..." $NSPAWN $TMPDIR/root pacman -S f2fs-tools --noconfirm 1> /dev/null 2>&1 echo "LABEL=ROOT_MNJRO / f2fs defaults,noatime,compress_algorithm=zstd 0 0" >> $TMPDIR/root/etc/fstab sed -i '/^MODULES/{s/)/ f2fs)/}' $TMPDIR/root/etc/mkinitcpio.conf $NSPAWN $TMPDIR/root mkinitcpio -P 1> /dev/null 2>&1 ;; *) info "Adding ext4 support to system..." ;; esac if [[ "$CRYPT" = "yes" ]]; then tweakinitrd_crypt fi info "Cleaning install for unwanted files..." umount $TMPDIR/root/var/cache/pacman/pkg rm -f $TMPDIR/root/usr/bin/qemu-aarch64-static rm -f $ROOTFS_IMG/rootfs_$ARCH/MANJARO-ARM-IMAGE-BUILD rm -f $TMPDIR/root/var/cache/pacman/pkg/* rm -f $TMPDIR/root/var/log/* rm -rf $ROOTFS_IMG/rootfs_$ARCH/var/log/journal/* rm -f $TMPDIR/root/etc/*.pacnew rm -f $TMPDIR/root/usr/lib/systemd/system/systemd-firstboot.service rm -f $TMPDIR/root/etc/machine-id # Remove temp files on host rm -f $TMPDIR/user $TMPDIR/password $TMPDIR/rootpassword rm -f $TMPDIR/Manjaro-ARM-$ARCH-latest.tar.gz* msg "$DEVICE $EDITION install complete" if [[ "$DEVICE" = "generic-efi" ]]; then msg "Please run 'sudo update-grub' after boot to correctly configure Grub!" fi } prepare_card () { msg "Getting $SDCARD ready with $FSTYPE for $DEVICE..." # umount SD card umount ${SDCARD}${SDDEV}1 1> /dev/null 2>&1 umount ${SDCARD}${SDDEV}2 1> /dev/null 2>&1 # Create partitions #remove previous partitions for v_partition in $(parted -s $SDCARD print|awk '/^ / {print $1}') do parted -s $SDCARD rm ${v_partition} 1> /dev/null 2>&1 done #Clear first 32mb dd if=/dev/zero of=${SDCARD} bs=1M count=32 1> /dev/null 2>&1 #partition with boot and root case "$DEVICE" in edgev|gsking-x|gtking-pro|oc2|on2|on2-plus|oc4|ohc4|pinephone|radxa-zero|rpi4|vim1|vim2|vim3) parted -s $SDCARD mklabel msdos 1> /dev/null 2>&1 ;; *) parted -s $SDCARD mklabel gpt 1> /dev/null 2>&1 ;; esac if [[ "$DEVICE" = "generic-efi" ]]; then parted -s $SDCARD mkpart primary fat32 0% 512M > /dev/null 2>&1 else parted -s $SDCARD mkpart primary fat32 32M 512M 1> /dev/null 2>&1 fi sleep 5 START=`cat /sys/block/$DEV_NAME/${DEV_NAME}${SDDEV}1/start` SIZE=`cat /sys/block/$DEV_NAME/${DEV_NAME}${SDDEV}1/size` END_SECTOR=$(expr $START + $SIZE) case "$FSTYPE" in btrfs) case "$DEVICE" in generic-efi) parted -s $SDCARD mkpart primary btrfs "${END_SECTOR}s" 100% > /dev/null 2>&1 parted -s $SDCARD set 1 esp on partprobe $SDCARD > /dev/null 2>&1 mkfs.vfat "${SDCARD}${SDDEV}1" -n BOOT_MNJRO > /dev/null 2>&1 mkfs.btrfs -m single -L ROOT_MNJRO "${SDCARD}${SDDEV}p2" > /dev/null 2>&1 # Create and mount the subvolumes info "Creating btrfs subvolumes..." mkdir -p $TMPDIR/root mkdir -p $TMPDIR/boot/efi mount ${SDCARD}${SDDEV}1 $TMPDIR/boot/efi mount -o compress=zstd "${SDCARD}${SDDEV}2" $TMPDIR/root btrfs su cr $TMPDIR/root/@ > /dev/null 2>&1 btrfs su cr $TMPDIR/root/@home > /dev/null 2>&1 umount $TMPDIR/root mount -o compress=zstd,subvol=@ "${SDCARD}${SDDEV}2" $TMPDIR/root mkdir -p $TMPDIR/root/home mount -o compress=zstd,subvol=@home "${SDCARD}${SDDEV}2" $TMPDIR/root/home ;; *) parted -s $SDCARD mkpart primary btrfs "${END_SECTOR}s" 100% 1> /dev/null 2>&1 partprobe $SDCARD 1> /dev/null 2>&1 mkfs.vfat "${SDCARD}${SDDEV}1" -n BOOT_MNJRO 1> /dev/null 2>&1 mkfs.btrfs -m single -L ROOT_MNJRO -f "${SDCARD}${SDDEV}2" 1> /dev/null 2>&1 mkdir -p $TMPDIR/root mkdir -p $TMPDIR/boot # Do subvolumes mount -o compress=zstd "${SDCARD}${SDDEV}2" $TMPDIR/root btrfs su cr $TMPDIR/root/@ 1> /dev/null 2>&1 btrfs su cr $TMPDIR/root/@home 1> /dev/null 2>&1 umount $TMPDIR/root mount -o compress=zstd,subvol=@ "${SDCARD}${SDDEV}2" $TMPDIR/root mkdir -p $TMPDIR/root/home mount -o compress=zstd,subvol=@home "${SDCARD}${SDDEV}2" $TMPDIR/root/home mount ${SDCARD}${SDDEV}1 $TMPDIR/boot ;; esac ;; f2fs) case "$DEVICE" in generic-efi) parted -s $SDCARD mkpart primary f2fs "${END_SECTOR}s" 100% > /dev/null 2>&1 parted -s $SDCARD set 1 esp on partprobe $SDCARD > /dev/null 2>&1 mkfs.vfat "${SDCARD}${SDDEV}1" -n BOOT_MNJRO > /dev/null 2>&1 mkfs.f2fs -f -l ROOT_MNJRO -O extra_attr,inode_checksum,sb_checksum,compression "${SDCARD}${SDDEV}2" 1> /dev/null 2>&1 mkdir -p $TMPDIR/root mkdir -p $TMPDIR/boot/efi mount ${SDCARD}${SDDEV}1 $TMPDIR/boot/efi mount -t f2fs ${SDCARD}${SDDEV}2 $TMPDIR/root ;; *) parted -s $SDCARD mkpart primary f2fs "${END_SECTOR}s" 100% 1> /dev/null 2>&1 partprobe $SDCARD 1> /dev/null 2>&1 mkfs.vfat "${SDCARD}${SDDEV}1" -n BOOT_MNJRO 1> /dev/null 2>&1 mkfs.f2fs -f -l ROOT_MNJRO -O extra_attr,inode_checksum,sb_checksum,compression "${SDCARD}${SDDEV}2" 1> /dev/null 2>&1 mkdir -p $TMPDIR/root mkdir -p $TMPDIR/boot mount ${SDCARD}${SDDEV}1 $TMPDIR/boot mount -t f2fs ${SDCARD}${SDDEV}2 $TMPDIR/root ;; esac ;; ext4) case "$DEVICE" in generic-efi) parted -s $SDCARD mkpart primary ext4 "${END_SECTOR}s" 100% > /dev/null 2>&1 parted -s $SDCARD set 1 esp on partprobe $SDCARD > /dev/null 2>&1 mkfs.vfat "${SDCARD}${SDDEV}1" -n BOOT_MNJRO > /dev/null 2>&1 mkfs.ext4 -O ^metadata_csum,^64bit "${SDCARD}${SDDEV}2" -L ROOT_MNJRO > /dev/null 2>&1 mkdir -p $TMPDIR/root mkdir -p $TMPDIR/boot/efi mount ${SDCARD}${SDDEV}1 $TMPDIR/boot/efi mount ${SDCARD}${SDDEV}2 $TMPDIR/root ;; *) parted -s $SDCARD mkpart primary ext4 "${END_SECTOR}s" 100% 1> /dev/null 2>&1 partprobe $SDCARD 1> /dev/null 2>&1 mkfs.vfat "${SDCARD}${SDDEV}1" -n BOOT_MNJRO 1> /dev/null 2>&1 if [[ "$CRYPT" != "yes" ]]; then mkfs.ext4 -O ^metadata_csum,^64bit "${SDCARD}${SDDEV}2" -L ROOT_MNJRO 1> /dev/null 2>&1 else info "Create encryption password:" cryptsetup luksFormat -q "${SDCARD}${SDDEV}2" info "Confirm encryption password:" cryptsetup open "${SDCARD}${SDDEV}2" ROOT_MNJRO mkfs.ext4 -O ^metadata_csum,^64bit /dev/mapper/ROOT_MNJRO 1> /dev/null 2>&1 fi mkdir -p $TMPDIR/root mkdir -p $TMPDIR/boot mount ${SDCARD}${SDDEV}1 $TMPDIR/boot if [[ "$CRYPT" != "yes" ]]; then mount ${SDCARD}${SDDEV}2 $TMPDIR/root else [ ! -e /dev/mapper/ROOT_MNJRO ] && cryptsetup open "${SDCARD}${SDDEV}2" ROOT_MNJRO mount /dev/mapper/ROOT_MNJRO $TMPDIR/root fi ;; esac ;; esac } cleanup () { if [[ "$DEVICE" != "generic-efi" ]]; then msg "Writing bootloader and cleaning up after install..." # Move boot files mv $TMPDIR/root/boot/* $TMPDIR/boot fi # Flash bootloader case "$DEVICE" in oc2) dd if=$TMPDIR/boot/bl1.bin.hardkernel of=${SDCARD} conv=fsync bs=1 count=442 1> /dev/null 2>&1 dd if=$TMPDIR/boot/bl1.bin.hardkernel of=${SDCARD} conv=fsync bs=512 skip=1 seek=1 1> /dev/null 2>&1 dd if=$TMPDIR/boot/u-boot.gxbb of=${SDCARD} conv=fsync bs=512 seek=97 1> /dev/null 2>&1 ;; oc4|ohc4|on2|on2-plus) dd if=$TMPDIR/boot/u-boot.bin of=${SDCARD} conv=fsync,notrunc bs=512 seek=1 1> /dev/null 2>&1 ;; radxa-zero|vim1|vim2|vim3) dd if=$TMPDIR/boot/u-boot.bin of=${SDCARD} conv=fsync bs=1 count=442 1> /dev/null 2>&1 dd if=$TMPDIR/boot/u-boot.bin of=${SDCARD} conv=fsync bs=512 skip=1 seek=1 1> /dev/null 2>&1 ;; pine64-lts|pine64|pinebook|pinetab|pine-h64) dd if=$TMPDIR/boot/u-boot-sunxi-with-spl-$DEVICE.bin of=${SDCARD} conv=fsync bs=128k seek=1 1> /dev/null 2>&1 ;; pinephone) dd if=$TMPDIR/boot/u-boot-sunxi-with-spl-$DEVICE-552.bin of=${SDCARD} conv=fsync bs=8k seek=1 1> /dev/null 2>&1 ;; clockworkpi-a06|nanopc-t4|om1|opi4-lts|pbpro|pinephonepro|quartz64-a|quartz64-b|rock3a|rock64|roc-cc|rockpi4b|rockpi4c|rockpro64) dd if=$TMPDIR/boot/idbloader.img of=${SDCARD} seek=64 conv=notrunc,fsync 1> /dev/null 2>&1 dd if=$TMPDIR/boot/u-boot.itb of=${SDCARD} seek=16384 conv=notrunc,fsync 1> /dev/null 2>&1 ;; esac if [[ "$CRYPT" = "yes" ]]; then post_crypt fi # edit boot files and fstab # set UUID for boot partition in fstab BOOT_PARTUUID=$(lsblk -p -o NAME,PARTUUID | grep ${DEV_NAME}${SDDEV}1 | awk '{print $2}') sed -i "s/LABEL=BOOT_MNJRO/PARTUUID=$BOOT_PARTUUID/g" $TMPDIR/root/etc/fstab info "Set boot partition to $BOOT_PARTUUID in /etc/fstab..." # Change boot script and fstab to root partition UUID ROOT_PARTUUID=$(lsblk -p -o NAME,PARTUUID | grep ${DEV_NAME}${SDDEV}2 | awk '{print $2}') ROOT_UUID=$(blkid | grep ${DEV_NAME}${SDDEV}2 | awk '{print $3}' | grep -oP "[^/]=\K.*" | sed 's/\"//g') info "Set root partition to $ROOT_PARTUUID in the relevant boot script and /etc/fstab..." if [[ "$DEVICE" = "generic-efi" ]]; then info "Set root partition to $ROOT_UUID in /boot/grub/grub.cfg..." fi if [ -f $TMPDIR/boot/extlinux/extlinux.conf ]; then sed -i "s/LABEL=ROOT_MNJRO/PARTUUID=$ROOT_PARTUUID/g" $TMPDIR/boot/extlinux/extlinux.conf elif [ -f $TMPDIR/boot/efi/extlinux/extlinux.conf ]; then sed -i "s/LABEL=ROOT_MNJRO/PARTUUID=$ROOT_PARTUUID/g" $TMPDIR/boot/efi/extlinux/extlinux.conf elif [ -f $TMPDIR/boot/boot.ini ]; then sed -i "s/LABEL=ROOT_MNJRO/PARTUUID=$ROOT_PARTUUID/g" $TMPDIR/boot/boot.ini elif [ -f $TMPDIR/boot/uEnv.ini ]; then sed -i "s/LABEL=ROOT_MNJRO/PARTUUID=$ROOT_PARTUUID/g" $TMPDIR/boot/uEnv.ini #elif [ -f $TMPDIR/boot/boot.txt ]; then # sed -i "s/PARTUUID=/PARTUUID=$ROOT_PARTUUID/g" $TMPDIR/boot/boot.txt # $NSPAWN $TMPDIR/root mkimage -A arm -O linux -T script -C none -n "U-Boot boot script" -d $TMPDIR/boot/boot.txt $TMPDIR/boot/boot.scr fi sync if [[ "$DEVICE" = "rpi4" ]] && [[ "$FSTYPE" = "btrfs" ]]; then echo "===> Installing default btrfs RPi cmdline.txt /boot..." echo "rootflags=subvol=@ root=PARTUUID=$ROOT_PARTUUID rw rootwait console=serial0,115200 console=tty3 selinux=0 quiet splash plymouth.ignore-serial-consoles smsc95xx.turbo_mode=N dwc_otg.lpm_enable=0 kgdboc=serial0,115200 usbhid.mousepoll=8 audit=0" > $TMPDIR/boot/cmdline.txt elif [[ "$DEVICE" = "rpi4" ]]; then echo "===> Installing default ext4 RPi cmdline.txt /boot..." echo "root=PARTUUID=$ROOT_PARTUUID rw rootwait console=serial0,115200 console=tty3 selinux=0 quiet splash plymouth.ignore-serial-consoles smsc95xx.turbo_mode=N dwc_otg.lpm_enable=0 kgdboc=serial0,115200 usbhid.mousepoll=8 audit=0" > $TMPDIR/boot/cmdline.txt fi if [[ "$DEVICE" = "rpi4" ]]; then echo "===> Installing default /boot/config.txt file..." echo "# See /boot/overlays/README for all available options # Uncomment some or all of these to enable optional Hardware interfaces #dtparam=i2c_arm=on #dtparam=i2s=on #dtparam=spi=on # Run in 64bit mode arm_64bit=1 # Auto load correct initramfs files if found auto_initramfs=1 # Run as fast as the firmware/board allows arm_boost=1 # Disable compensation for displays with overscan disable_overscan=1 # Enable sound dtparam=audio=on # Uncomment if no sound thru hdmi #hdmi_drive=2 # Auto load overlays for detected cameras camera_auto_detect=1 # Auto load overlays for detected DSI displays display_auto_detect=1 # Enable DRM VC4 V3D driver dtoverlay=vc4-kms-v3d # For pi4's and above boards uncomment next line & Comment out above line #dtoverlay=vc4-kms-v3d,cma-512 max_framebuffers=2 # Don't have the firmware create an initial video= setting in cmdline.txt # Use the kernel default instead #disable_fw_kms_setup=1 # Disable rainbow screen at boot disable_splash=1 # RPi 5B/4B/400 ONLY # For 4k content @ 60 Hz refresh rate, uncomment hdmi_enable_4kp60=1 #hdmi_enable_4kp60=1 # If video breaks with hdmi_enable_4kp60=1 uncomment #force_turbo=1 [cm4] # Enable host mode on the 2711 built-in XHCI USB controller # This line should be remoed if the legacy DWC2 controller is required otg_mode=1 [cm5] dtoverlay=dwc2,dr_mode=host [all]" > $TMPDIR/boot/config.txt fi case "$FSTYPE" in btrfs|f2fs) sed -i "s/LABEL=ROOT_MNJRO/PARTUUID=$ROOT_PARTUUID/g" $TMPDIR/root/etc/fstab ;; *) echo "PARTUUID=$ROOT_PARTUUID / $FSTYPE defaults 0 1" >> $TMPDIR/root/etc/fstab ;; esac if [[ "$DEVICE" = "generic-efi" ]]; then sed -i "s|/boot|/boot/efi|g" $TMPDIR/root/etc/fstab msg "Setup GRUB for EFI..." grub-install --target=arm64-efi --efi-directory=$TMPDIR/boot/efi --removable --boot-directory=$TMPDIR/root/boot --bootloader-id=grub ${SDCARD} mkdir -p $TMPDIR/root/boot/grub if [ -f $TMPDIR/root/boot/Image ]; then KERNEL="/boot/Image" INITRAMFS="/boot/initramfs-linux.img" else KERNEL="/boot/$(ls $TMPDIR/root/boot/ | grep vmlinuz)" INITRAMFS="/boot/$(ls $TMPDIR/root/boot/ | grep initramfs | grep -v fallback)" fi echo "Kernel image is $KERNEL..." echo "Initramfs image is $INITRAMFS..." echo "Creating minimal grub configuration..." echo '### BEGIN /etc/grub.d/00_header ### insmod part_gpt insmod part_msdos if [ -s $prefix/grubenv ]; then load_env fi if [ "${next_entry}" ] ; then set default="${next_entry}" set next_entry= save_env next_entry set boot_once=true else set default="${saved_entry}" fi if [ x"${feature_menuentry_id}" = xy ]; then menuentry_id_option="--id" else menuentry_id_option="" fi export menuentry_id_option if [ "${prev_saved_entry}" ]; then set saved_entry="${prev_saved_entry}" save_env saved_entry set prev_saved_entry= save_env prev_saved_entry set boot_once=true fi function savedefault { if [ -z "${boot_once}" ]; then saved_entry="${chosen}" save_env saved_entry fi } function load_video { if [ x$feature_all_video_module = xy ]; then insmod all_video else insmod efi_gop insmod efi_uga insmod ieee1275_fb insmod vbe insmod vga insmod video_bochs insmod video_cirrus fi } set menu_color_normal=white/black set menu_color_highlight=green/black if [ x$feature_default_font_path = xy ] ; then font=unicode else insmod part_gpt insmod ext2 search --no-floppy --fs-uuid --set=root $ROOT_UUID font="/usr/share/grub/unicode.pf2" fi if loadfont $font ; then set gfxmode=auto load_video insmod gfxterm fi terminal_input console terminal_output gfxterm if [ x$feature_timeout_style = xy ] ; then set timeout_style=menu set timeout=5 # Fallback normal timeout code in case the timeout_style feature is # unavailable. else set timeout=5 fi ### END /etc/grub.d/00_header ###' > $TMPDIR/root/boot/grub/grub.cfg echo "### BEGIN /etc/grub.d/10_linux ### menuentry 'Manjaro ARM' --class manjaro --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-simple-$ROOT_UUID' { savedefault load_video set gfxpayload=keep insmod gzio insmod part_gpt insmod ext2 search --no-floppy --fs-uuid --set=root $ROOT_UUID linux $(if [[ "$FILESYSTEM" = "btrfs" ]]; then echo "/@"; fi)$KERNEL root=UUID=$ROOT_UUID rw quiet splash plymouth.ignore-serial-consoles $(if [[ "$FSTYPE" = "btrfs" ]]; then echo "rootflags=subvol=@ rootfstype=btrfs"; fi) initrd $(if [[ "$FILESYSTEM" = "btrfs" ]]; then echo "/@"; fi)$INITRAMFS }" >> $TMPDIR/root/boot/grub/grub.cfg fi #clean up if [[ "$FSTYPE" = "btrfs" ]]; then umount $TMPDIR/root/home umount $TMPDIR/root if [[ "$DEVICE" = "generic-efi" ]]; then umount $TMPDIR/boot/efi else umount $TMPDIR/boot fi else umount $TMPDIR/root if [[ "$DEVICE" = "generic-efi" ]]; then umount $TMPDIR/boot/efi else umount $TMPDIR/boot fi if [[ "$CRYPT" = "yes" ]]; then cryptsetup close /dev/mapper/ROOT_MNJRO fi fi partprobe $SDCARD 1> /dev/null 2>&1 info "If you get an error stating 'failed to preserve ownership ... Operation not permitted', it's expected, since the boot partition is FAT32 and does not support ownership permissions..." } tweakinitrd_crypt () { case "$DEVICE" in pbpro|rockpi4b|rockpi4c|rockpro64) # Use the proper mkinitcpio. cat << EOF > ${TMPDIR}/root/etc/mkinitcpio.conf MODULES=(panfrost rockchipdrm drm_kms_helper hantro_vpu analogix_dp rockchip_rga panel_edp arc_uart cw2015_battery i2c-hid iscsi_boot_sysfs jsm pwm_bl uhid) BINARIES=() FILES=() HOOKS=(base udev keyboard autodetect keymap modconf block encrypt lvm2 filesystems fsck) COMPRESSION="cat" EOF # Install lvm2, this will trigger the cpio rebuild $NSPAWN $TMPDIR/root pacman -Syyu lvm2 --noconfirm ;; esac } post_crypt () { # Get the UUID UUID=$(blkid -s UUID -o value "${SDCARD}${SDDEV}2") # Modify the /boot/extlinux/extlinux.conf to match our needs case "$DEVICE" in clockworkpi-a06|pbpro|rockpi4b|rockpi4c|rockpro64) # NOTE: I've tried to only modify the cryptdevice and root parameters but bootsplash and console=ttyS2 prevents to show the password prompt # TODO: Need to add plymouth support sed -i -e "s!APPEND.*!APPEND initrd=/initramfs-linux.img console=tty1 cryptdevice=UUID=${UUID}:ROOT_MNJRO root=/dev/mapper/ROOT_MNJRO rw rootwait!g" ${TMPDIR}/boot/extlinux/extlinux.conf ;; esac # Generate the /etc/crypttab file echo "ROOT_MNJRO UUID=${UUID} none luks,discard" > ${TMPDIR}/root/etc/crypttab } # Using Dialog to ask for user input for variables DEVICE=$(dialog --clear --title "Manjaro ARM Installer v${VERSION}" \ --menu "Choose a device:" 20 75 10 \ "clockworkpi-a06" "ClockworkPi DevTerm" \ "generic" "Generic" \ "generic-efi" "Generic EFI" \ "gt1-ultimate" "Beelink GT1 Ultimate" \ "oc4" "Odroid C4" \ "oc2" "Odroid C2" \ "ohc4" "Odroid HC4" \ "om1" "Odroid M1" \ "on2" "Odroid N2" \ "on2-plus" "Odroid N2+" \ "opi4-lts" "Orange Pi 4 LTS" \ "pine64-lts" "Pine64-LTS / Sopine" \ "pine64" "Pine64+" \ "pinebook" "Pinebook" \ "pine-h64" "Pine H64" \ "pinephone" "PinePhone" \ "pinephonepro" "PinePhone Pro (Experimental)" \ "pbpro" "Pinebook Pro" \ "pinetab" "PineTab" \ "radxa-zero" "Radxa Zero" \ "rpi4" "Raspberry Pi 5/4's/3's/zero2w" \ "rock3a" "Rock 3A" \ "rock64" "Rock64" \ "rockpi4b" "Rock Pi 4B" \ "rockpi4c" "Rock Pi 4C" \ "rockpro64" "RockPro64" \ "roc-cc" "LibreComputer Renegade" \ "nanopc-t4" "NanoPC T4" \ "quartz64-a" "Quartz64 Model A" \ "quartz64-b" "Quartz64 Model B" \ "vim1" "Khadas Vim 1" \ "vim2" "Khadas Vim 2" \ "vim3" "Khadas Vim 3" \ 3>&1 1>&2 2>&3 3>&-) #The if statement makes sure that the user has put in something in the previous prompt. If not (left blank or pressed cancel) the script will end if [ ! -z "$DEVICE" ]; then if [[ "$DEVICE" = "pinetab" ]] || [[ "$DEVICE" = "pinephone" ]] || [[ "$DEVICE" = "pinephonepro" ]]; then EDITION=$(dialog --clear --title "Manjaro ARM Installer v${VERSION}" \ --menu "Choose an edition:" 20 75 10 \ "plasma-mobile" "Plasma Mobile (QT based mobile UI)" \ "phosh" "Phosh (GTK based mobile UI)" \ 3>&1 1>&2 2>&3 3>&-) else EDITION=$(dialog --clear --title "Manjaro ARM Installer v${VERSION}" \ --menu "Choose an edition:" 20 75 10 \ "minimal" "Minimal Edition (only CLI)" \ "kde-plasma" "Full KDE/Plasma Desktop (full featured)" \ "xfce" "Full XFCE desktop and apps (full featured)" \ "mate" "Full MATE desktop and apps (lightweight)" \ "gnome" "Full Gnome desktop and apps (full featured)" \ "sway" "Minimal Sway WM with apps (very light)" \ "lxqt" "Full LXQT Desktop and apps (lightweight)" \ "i3" "Mininal i3 WM with apps (very light)" \ "server" "Minimal with LAMP and Docker (only cli)" \ "budgie" "Full Budgie desktop (EXPERIMENTAL))" \ 3>&1 1>&2 2>&3 3>&-) fi else clear exit 1 fi if [[ "$EDITION" = "phosh" ]]; then #Set Phosh specific variables USER="manjaro" PASSWORD="123456" CONFIRMPASSWORD="123456" ROOTPASSWORD="root" CONFIRMROOTPASSWORD="root" fi if [ ! -z "$EDITION" ]; then if [[ "$EDITION" != "phosh" ]]; then USER=$(dialog --clear --title "Manjaro ARM Installer v${VERSION}" \ --inputbox "Enter the username you want: (usernames must be all lowercase and first character may not be a number)" 10 90 \ 3>&1 1>&2 2>&3 3>&-) fi if [[ "$USER" =~ [A-Z] ]] || [[ "$USER" =~ ^[0-9] ]] || [[ "$USER" == *['!'@#\$%^\&*()_+]* ]]; then clear msg "Configuration aborted! Username contained invalid characters." exit 1 fi else clear exit 1 fi if [ ! -z "$USER" ] then USERGROUPS=$(dialog --clear --title "Manjaro ARM Installer v${VERSION}" \ --inputbox "Enter additional groups for $USER in a comma seperated list: (empty if none) (default: wheel,sys,audio,input,video,storage,lp,network,users,power)" 10 90 \ 3>&1 1>&2 2>&3 3>&- \ ) else clear exit 1 fi if [ ! -z "$USER" ] then FULLNAME=$(dialog --clear --title "Manjaro ARM Installer v${VERSION}" \ --inputbox "Enter desired Full Name for $USER:" 8 50 \ 3>&1 1>&2 2>&3 3>&- \ ) else clear exit 1 fi if [ ! -z "$FULLNAME" ]; then if [[ "$EDITION" != "phosh" ]]; then PASSWORD=$(dialog --clear --title "Manjaro ARM Installer v${VERSION}" \ --insecure --passwordbox "Enter new Password for $USER:" 8 50 \ 3>&1 1>&2 2>&3 3>&- \ ) fi else clear exit 1 fi if [ ! -z "$PASSWORD" ]; then if [[ "$EDITION" != "phosh" ]]; then CONFIRMPASSWORD=$(dialog --clear --title "Manjaro ARM Installer v${VERSION}" \ --insecure --passwordbox "Confirm new Password for $USER:" 8 50 \ 3>&1 1>&2 2>&3 3>&- \ ) fi else clear exit 1 fi if [[ "$PASSWORD" != "$CONFIRMPASSWORD" ]]; then clear msg "User passwords do not match! Please restart the installer and try again." exit 1 fi if [ ! -z "$CONFIRMPASSWORD" ]; then if [[ "$EDITION" != "phosh" ]]; then ROOTPASSWORD=$(dialog --clear --title "Manjaro ARM Installer v${VERSION}" \ --insecure --passwordbox "Enter new Root Password:" 8 50 \ 3>&1 1>&2 2>&3 3>&- \ ) fi else clear exit 1 fi if [ ! -z "$ROOTPASSWORD" ]; then if [[ "$EDITION" != "phosh" ]]; then CONFIRMROOTPASSWORD=$(dialog --clear --title "Manjaro ARM Installer v${VERSION}" \ --insecure --passwordbox "Confirm new Root Password:" 8 50 \ 3>&1 1>&2 2>&3 3>&- \ ) fi else clear exit 1 fi if [[ "$ROOTPASSWORD" != "$CONFIRMROOTPASSWORD" ]]; then clear msg "Root passwords do not match! Please restart the installer and try again." exit 1 fi if [ ! -z "$CONFIRMROOTPASSWORD" ] then # simple command to put the results of lsblk (just the names of the devices) into an array and make that array populate the options let i=0 W=() while read -r line; do let i=$i+1 W+=($line "") done < <( lsblk -dn -o NAME ) SDCARD=$(dialog --title "Manjaro ARM Installer v${VERSION}" \ --menu "Choose your SDCard/eMMC/USB - Be sure the correct drive is selected! WARNING! This WILL destroy the data on it!" 20 50 10 \ "${W[@]}" 3>&2 2>&1 1>&3) # add /dev/ to the selected option above DEV_NAME=$SDCARD SDCARD=/dev/$SDCARD SDTYP=${SDCARD:5:2} else clear exit 1 fi if [[ "$SDTYP" = "sd" ]]; then SDDEV="" elif [[ "$SDTYP" = "mm" || "$SDTYP" = "nv" ]]; then SDDEV="p" else clear echo "Unkown Block Device Type" exit 1 fi if [ ! -z "$SDCARD" ]; then if [[ "$DEVICE" = "generic-efi" ]]; then FSTYPE="ext4" else FSTYPE=$(dialog --clear --title "Manjaro ARM Installer v${VERSION}" \ --menu "Choose a filesystem:" 10 90 10 \ "ext4" "Regular ext4 filesystem for the root partition" \ "btrfs" "Uses btrfs for root partition and makes / and /home subvolumes" \ "f2fs" "Use f2fs for the root partition" \ 3>&1 1>&2 2>&3 3>&-) fi else clear exit 1 fi if [[ "$DEVICE" = "clockworkpi-a06" ]] || [[ "$DEVICE" = "pbpro" ]] || [[ "$DEVICE" = "rockpro64" ]] || [[ "$DEVICE" = "rockpi4b" ]] || [[ "$DEVICE" = "rockpi4c" ]] && [[ "$FSTYPE" != "btrfs" ]] && [[ "$FSTYPE" != "f2fs" ]]; then CRYPT=$(dialog --clear --title "Manjaro ARM Installer v${VERSION}" \ --menu "[Experimental!] Do you want encryption on root partition?" 10 90 10 \ "no" "No, thanks" \ "yes" "Yes, please" \ 3>&1 1>&2 2>&3 3>&-) fi if [[ -d /dev/mapper/ROOT_MNJRO ]] && [[ "$CRYPT" = "yes" ]]; then clear exit 2 fi if [ ! -z "$FSTYPE" ]; then let i=0 W=() while read -r line; do let i=$i+1 W+=($line "") done < <( timedatectl list-timezones ) TIMEZONE=$(dialog --clear --title "Manjaro ARM Installer v${VERSION}" \ --menu "Choose your timezone!" 20 50 15 \ "${W[@]}" 3>&1 1>&2 2>&3 3>&- \ ) else clear exit 1 fi if [ ! -z "$TIMEZONE" ]; then let i=0 W=() while read -r line; do let i=$i+1 W+=($line "") done < <( cat /etc/locale.gen | grep "UTF-8" | tail -n +2 | sed -e 's/^#*//' | awk '{print $1}' ) LOCALE=$(dialog --clear --title "Manjaro ARM Installer v${VERSION}" \ --menu "Choose your locale!" 20 50 15 \ "${W[@]}" 3>&1 1>&2 2>&3 3>&- \ ) else clear exit 1 fi if [ ! -z "$LOCALE" ]; then let i=0 W=() while read -r line; do let i=$i+1 W+=($line "") done < <( localectl list-keymaps ) CLIKEYMAP=$(dialog --clear --title "Manjaro ARM Installer v${VERSION}" \ --menu "Choose your TTY keyboard layout:" 20 50 15 \ "${W[@]}" 3>&1 1>&2 2>&3 3>&- \ ) else clear exit 1 fi if [[ "$EDITION" != "minimal" ]]; then if [ ! -z "$CLIKEYMAP" ]; then let i=0 W=() while read -r line; do let i=$i+1 W+=($line "") done < <( localectl list-x11-keymap-layouts ) X11KEYMAP=$(dialog --clear --title "Manjaro ARM Installer v${VERSION}" \ --menu "Choose your X11 keyboard layout:" 20 50 15 \ "${W[@]}" 3>&1 1>&2 2>&3 3>&- \ ) else clear exit 1 fi fi if [ ! -z "$CLIKEYMAP" ]; then HOSTNAME=$(dialog --clear --title "Manjaro ARM Installer v${VERSION}" \ --inputbox "Enter desired hostname for this system:" 8 50 \ 3>&1 1>&2 2>&3 3>&- \ ) else clear exit 1 fi if [ ! -z "$HOSTNAME" ]; then dialog --clear --title "Manjaro ARM Installer v${VERSION}" \ --yesno "Is the below information correct: Device = $DEVICE Edition = $EDITION Username = $USER Full Username = $FULLNAME Additional usergroups = $USERGROUPS Password for $USER = (password hidden) Password for root = (password hidden) SDCard/eMMC/USB = $SDCARD Filesystem = $FSTYPE Encryption (only on select devices) = $CRYPT Timezone = $TIMEZONE Locale = $LOCALE TTY Keyboard layout = $CLIKEYMAP X11 Keyboard layout = $X11KEYMAP Hostname = $HOSTNAME" 25 70 \ 3>&1 1>&2 2>&3 3>&- else clear exit 1 fi response=$? case $response in 0) clear; msg "Proceeding....";; 1) clear; msg "Installation aborted...."; exit 1;; 2) clear; msg "Installation not possible from an encrypted system..."; exit 1;; 255) clear; msg "Installation aborted..."; exit 1;; esac # get the profiles installer_getarmprofiles #Package lists sed -i 's/pico-wizard-plamo-scripts//g' $TMPDIR/arm-profiles/editions/$EDITION sed -i 's/pico-wizard-git//g' $TMPDIR/arm-profiles/editions/$EDITION PKG_DEVICE=$(grep "^[^#;]" $TMPDIR/arm-profiles/devices/$DEVICE | awk '{print $1}') PKG_SHARED=$(grep "^[^#;]" $TMPDIR/arm-profiles/editions/shared | awk '{sub(/>pinephone/,""); print $1}') case "$DEVICE" in pinephone) PKG_EDITION=$(grep "^[^#;]" $TMPDIR/arm-profiles/editions/$EDITION | awk '{sub(/>pinephone/,""); print $1}') cat $TMPDIR/arm-profiles/services/$EDITION | sed -e '/^#/d' -e 's/>pinephone //g' >$srv_list ;; *) PKG_EDITION=$(grep "^[^#;]" $TMPDIR/arm-profiles/editions/$EDITION | awk '{sub(/>pinephone.*/,""); print $1}') cat $TMPDIR/arm-profiles/services/$EDITION | sed -e '/^#/d' -e '/>pinephone/d' >$srv_list ;; esac # Commands timer_start=$(get_timer) prepare_card create_install cleanup show_elapsed_time "${FUNCNAME}" "${timer_start}" sync