384 lines
14 KiB
Bash
Executable file
384 lines
14 KiB
Bash
Executable file
#!/bin/sh
|
|
|
|
# Copyright 2015, Timothy Redaelli <tredaelli@archlinux.info>
|
|
|
|
# This program is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License at <http://www.gnu.org/licenses/> for
|
|
# more details.
|
|
|
|
set -e
|
|
|
|
# Gathering informations about actual environment.
|
|
if command -v wget >/dev/null 2>&1; then
|
|
_download() { wget -U vps2parch -O- "$@" ; }
|
|
elif command -v curl >/dev/null 2>&1; then
|
|
_download() { curl -A vps2parch -fL "$@" ; }
|
|
else
|
|
echo "This script needs curl or wget" >&2
|
|
exit 2
|
|
fi
|
|
|
|
get_country() {
|
|
_download "https://api.ip.sb/geoip" | grep -oP '(?<=country_code":")\w+'
|
|
}
|
|
|
|
get_mirrors() {
|
|
country=$1
|
|
|
|
[ -z $country ] && country=$(get_country || echo -n "all")
|
|
_download "https://archlinux.org/mirrorlist/?country=$country&protocol=http&protocol=https&ip_version=4&use_mirror_status=on" | grep -oP '(?<=#Server = ).*(?=\$repo/)' || get_mirrors all
|
|
}
|
|
|
|
cpu_type=$(uname -m)
|
|
|
|
is_openvz() { [ -d /proc/vz -a ! -d /proc/bc ]; }
|
|
is_lxc() { grep -aqw container=lxc /proc/1/environ ; }
|
|
|
|
download() {
|
|
local path="$1" x=
|
|
shift
|
|
for x in $mirrors; do
|
|
_download "$x$path" && return 0
|
|
done
|
|
return 1
|
|
}
|
|
|
|
download2() { aria2c -c -s 16 -x 16 -k 1M -j 1 "$@" ; }
|
|
|
|
download_and_extract_bootstrap() {
|
|
local sha256 filename
|
|
download iso/latest/sha256sums.txt | egrep "[[:digit:]]-$cpu_type.tar.zst" > "sha256sums.txt"
|
|
read -r sha256 filename < "sha256sums.txt"
|
|
download "iso/latest/$filename" > "$filename"
|
|
sha256sum -c sha256sums.txt || exit 1
|
|
tar -xpf "$filename"
|
|
rm -f "$filename"
|
|
|
|
if grep -E '^nameserver\s+127\.' /etc/resolv.conf > /dev/null; then
|
|
echo "nameserver 8.8.8.8" > "/root.$cpu_type/etc/resolv.conf"
|
|
else
|
|
cp -L /etc/resolv.conf "/root.$cpu_type/etc"
|
|
fi
|
|
|
|
# Mount options taked from arch-chroot script
|
|
mount -t proc proc -o nosuid,noexec,nodev "/root.$cpu_type/proc"
|
|
mount -t sysfs sys -o nosuid,noexec,nodev,ro "/root.$cpu_type/sys"
|
|
mount -t devtmpfs -o mode=0755,nosuid udev "/root.$cpu_type/dev"
|
|
mkdir -p "/root.$cpu_type/dev/pts" "/root.$cpu_type/dev/shm"
|
|
mount -t devpts -o mode=0620,gid=5,nosuid,noexec devpts "/root.$cpu_type/dev/pts"
|
|
mount -t tmpfs -o mode=1777,nosuid,nodev shm "/root.$cpu_type/dev/shm"
|
|
mount -t tmpfs -o nosuid,nodev,mode=0755 run "/root.$cpu_type/run"
|
|
mount -t tmpfs -o mode=1777,strictatime,nodev,nosuid tmp "/root.$cpu_type/tmp"
|
|
# FIXME support multiple partitions
|
|
mount --bind / "/root.$cpu_type/mnt"
|
|
findmnt /boot >/dev/null && mount --bind /boot "/root.$cpu_type/mnt/boot"
|
|
findmnt /boot/efi >/dev/null && mount --bind /boot/efi "/root.$cpu_type/mnt/boot/efi"
|
|
# Workaround for Debian
|
|
mkdir -p "/root.$cpu_type/run/shm"
|
|
# Workaround for OpenVZ
|
|
rm -f "/root.$cpu_type/etc/mtab"
|
|
cp -L /etc/mtab "/root.$cpu_type/etc/mtab"
|
|
}
|
|
|
|
chroot_exec() {
|
|
chroot "/root.$cpu_type" /bin/bash -c "$*"
|
|
}
|
|
|
|
configure_chroot() {
|
|
local m
|
|
for m in $mirrors; do
|
|
echo 'Server = '"$m"'/$repo/os/$arch'
|
|
done >> "/root.$cpu_type/etc/pacman.d/mirrorlist"
|
|
# Install and initialize haveged if needed
|
|
if ! is_openvz && ! pidof haveged >/dev/null; then
|
|
# Disable signature check, install and launch haveged and re-enable signature checks.
|
|
sed -i.bak "s/^[[:space:]]*SigLevel[[:space:]]*=.*$/SigLevel = Never/" "/root.$cpu_type/etc/pacman.conf"
|
|
chroot_exec 'pacman --needed --noconfirm -Sy haveged && haveged'
|
|
mv "/root.$cpu_type/etc/pacman.conf.bak" "/root.$cpu_type/etc/pacman.conf"
|
|
echo -e "\n\n[ppr]\nSigLevel = Optional TrustAll\nServer = https://mirror.parchlinux.com/repos/\$repo/\$arch\n\n[pcp]\nSigLevel = Optional TrustAll\nServer = https://mirror.parchlinux.com/repos/\$repo/\$arch" >> "/root.$cpu_type/etc/pacman.conf"
|
|
fi
|
|
chroot_exec 'pacman-key --init && pacman-key --populate archlinux'
|
|
chroot_exec 'pacman --needed --noconfirm -Sy archlinux-keyring'
|
|
# Generate fstab
|
|
chroot_exec 'genfstab /mnt >> /etc/fstab'
|
|
|
|
if is_openvz && [ "$kernelver" '<' '2.6.32-042stab111.1' ]; then
|
|
# Use my repository for OpenVZ-patched systemd
|
|
sed -i 's;^#\[testing\]$;[tredaelli-systemd]\nServer = http://pkgbuild.com/~tredaelli/repo/systemd/$arch\n\n&;' "/root.$cpu_type/etc/pacman.conf"
|
|
fi
|
|
}
|
|
|
|
save_root_pass() {
|
|
grep '^root:' /etc/shadow > "/root.$cpu_type/root.passwd"
|
|
chmod 0600 "/root.$cpu_type/root.passwd"
|
|
}
|
|
|
|
backup_old_files() {
|
|
cp -fL /etc/hostname /etc/localtime "/root.$cpu_type/etc/" || true
|
|
}
|
|
|
|
delete_all() {
|
|
# Remove immutable flag from any files / directories
|
|
if command -v chattr >/dev/null 2>&1; then
|
|
find / -type f \( ! -path '/dev/*' -and ! -path '/proc/*' -and ! -path '/sys/*' -and ! -path '/selinux/*' -and ! -path "/root.$cpu_type/*" \) \
|
|
-exec chattr -i {} + 2>/dev/null || true
|
|
fi
|
|
# Delete *all* files from /
|
|
find / \( ! -path '/dev/*' -and ! -path '/proc/*' -and ! -path '/sys/*' -and ! -path '/selinux/*' -and ! -path "/root.$cpu_type/*" \) -delete 2>/dev/null || true
|
|
}
|
|
|
|
install_packages() {
|
|
local packages="amd-ucode b43-fwcutter base base-devel bind brltty btrfs-progs clonezilla cloud-init cryptsetup darkhttpd ddrescue dhclient dhcpcd diffutils dmidecode dmraid dnsmasq dosfstools e2fsprogs edk2-shell efibootmgr espeakup ethtool exfatprogs f2fs-tools fatresize fsarchiver git gnu-netcat gpart gpm gptfdisk grml-zsh-config grub hdparm hyperv intel-ucode irssi iw iwd jfsutils kitty-terminfo less lftp libfido2 libusb-compat linux linux-headers linux-atm linux-firmware linux-firmware-marvell livecd-sounds lsscsi lvm2 lynx man-db man-pages mc mdadm memtest86+ mkinitcpio mkinitcpio-archiso mkinitcpio-nfs-utils modemmanager mtools nano nbd ndisc6 nfs-utils nilfs-utils nmap ntfs-3g nvme-cli open-iscsi open-vm-tools openconnect openssh openvpn partclone parted partimage pcsclite ppp pptpclient pv python python-psutil python-systemd reiserfsprogs rp-pppoe rsync rxvt-unicode-terminfo screen sdparm sg3_utils smartmontools sof-firmware squashfs-tools sudo syslinux systemd-resolvconf tcpdump terminus-font testdisk tmux tpm2-tss udftools usb_modeswitch usbmuxd usbutils vim virtualbox-guest-utils-nox vpnc which wireless-regdb wireless_tools wpa_supplicant wget wvdial xfsprogs xl2tpd zsh archlinux-keyring openssl-1.1 openssl bash-completion networkmanager btop neofetch-git unzip unrar os-prober paru parch-branding parch-pacman reflector"
|
|
[ "$bootloader" != "none" ] && packages="$packages $bootloader"
|
|
# XXX Install gptdisk for syslinux. To be removed then FS#45029 will be closed
|
|
[ "$bootloader" = "syslinux" ] && packages="$packages gptfdisk"
|
|
[ -f /sys/firmware/efi/fw_platform_size ] && packages="$packages efibootmgr"
|
|
[ "$network" = "netctl" ] && packages="$packages netctl"
|
|
while read -r _ mountpoint filesystem _; do
|
|
[ "$mountpoint" = "/" -a "$filesystem" = "xfs" ] && packages="$packages xfsprogs"
|
|
done < /proc/mounts
|
|
# Black magic!
|
|
"/root.$cpu_type/usr/lib"/ld-*.so.2 --library-path "/root.$cpu_type/usr/lib" \
|
|
"/root.$cpu_type/usr/bin/chroot" "/root.$cpu_type" /usr/bin/pacstrap -M /mnt $packages
|
|
cp -L "/root.$cpu_type/etc/resolv.conf" /etc
|
|
}
|
|
|
|
restore_root_pass() {
|
|
# If the root password is not set, use vps2parch
|
|
if egrep -q '^root:[^$]' "/root.$cpu_type/root.passwd"; then
|
|
echo "root:vps2parch" | chpasswd
|
|
else
|
|
sed -i '/^root:/d' /etc/shadow
|
|
cat "/root.$cpu_type/root.passwd" >> /etc/shadow
|
|
fi
|
|
}
|
|
|
|
cleanup() {
|
|
mv "/root.$cpu_type/etc/fstab" "/etc/fstab"
|
|
awk "/\/root.$cpu_type/ {print \$2}" /proc/mounts | sort -r | xargs umount -nl || true
|
|
rm -rf "/root.$cpu_type/"
|
|
}
|
|
|
|
configure_bootloader() {
|
|
local root_dev=$(findmnt -no SOURCE /) root_devs= tmp= needs_lvm2=0 uefi=0
|
|
case $root_dev in
|
|
/dev/mapper/*) needs_lvm2=1 ;;
|
|
esac
|
|
if [ -f /sys/firmware/efi/fw_platform_size ]; then
|
|
uefi=$(cat /sys/firmware/efi/fw_platform_size)
|
|
fi
|
|
|
|
if [ $needs_lvm2 -eq 1 ]; then
|
|
# Some distro doesn't use lvmetad by default
|
|
sed -i.bak 's/use_lvmetad = 1/use_lvmetad = 0/g' /etc/lvm/lvm.conf
|
|
fi
|
|
|
|
if [ "$bootloader" = "grub" ]; then
|
|
# If you are still using eth* as interface name, disable "strange" ifnames
|
|
grep -q '^[[:space:]]*eth' /proc/net/dev && \
|
|
sed -i.bak 's/GRUB_CMDLINE_LINUX_DEFAULT="/&net.ifnames=0 /' /etc/default/grub
|
|
|
|
# Disable "graphic" terminal output
|
|
sed -i.bak 's/^#GRUB_TERMINAL_OUTPUT=console/GRUB_TERMINAL_OUTPUT=console/' /etc/default/grub
|
|
|
|
if [ $needs_lvm2 -eq 1 ]; then
|
|
local vg
|
|
vg=$(lvs --noheadings $root_dev | awk '{print $2}')
|
|
root_dev=$(pvs --noheadings | awk -v vg="$vg" '($2 == vg) { print $1 }')
|
|
fi
|
|
for root_dev in $root_dev; do
|
|
tmp=$(lsblk -npsro TYPE,NAME "$root_dev" | awk '($1 == "disk") { print $2}')
|
|
case " $root_devs " in
|
|
*" $tmp "*) ;;
|
|
*) root_devs="${root_devs:+$root_devs }$tmp" ;;
|
|
esac
|
|
done
|
|
case $uefi in
|
|
0)
|
|
for root_dev in $root_devs; do
|
|
grub-install --target=i386-pc --recheck --force "$root_dev"
|
|
done
|
|
;;
|
|
64)
|
|
grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=GRUB
|
|
;;
|
|
esac
|
|
grub-mkconfig > /boot/grub/grub.cfg
|
|
elif [ "$bootloader" = "syslinux" ]; then
|
|
# If you are still using eth* as interface name, disable "strange" ifnames
|
|
grep -q '^[[:space:]]*eth' /proc/net/dev && tmp="net.ifnames=0"
|
|
syslinux-install_update -ami
|
|
sed -i "s;\(^[[:space:]]*APPEND.*\)root=[^[:space:]]*;\1root=$root_dev${tmp:+ $tmp};" /boot/syslinux/syslinux.cfg
|
|
fi
|
|
|
|
if [ $needs_lvm2 -eq 1 ]; then
|
|
mv /etc/lvm/lvm.conf.bak /etc/lvm/lvm.conf
|
|
sed -i '/HOOKS/s/block/& lvm2/' /etc/mkinitcpio.conf
|
|
mkinitcpio -p linux
|
|
fi
|
|
}
|
|
|
|
configure_network() {
|
|
local gateway dev ip
|
|
|
|
dev=$(ls /sys/class/net | grep -v lo)
|
|
if [ -n "$(ip -4 route show default | awk '{ print $3 }')" ]; then
|
|
gateway=$(ip -4 route show default | awk '{ print $3 }')
|
|
set -- $(ip addr show dev "$dev" | awk '($1 == "inet") { print $2 }')
|
|
else
|
|
gateway=$(ip -6 route show default | awk '{ print $3 }')
|
|
set -- $(ip addr show dev "$dev" | awk '($1 == "inet6" && $2 !~ /^fe80/) { print $2 }')
|
|
fi
|
|
ip=$@
|
|
|
|
# FIXME Not supported for "P2P" interfaces, such as venet, yet
|
|
if [ "$network" = "systemd-networkd" ]; then
|
|
cat > /etc/systemd/network/default.network <<-EOF
|
|
[Match]
|
|
Name=$dev
|
|
|
|
[Network]
|
|
Gateway=$gateway
|
|
EOF
|
|
for ip in $ip; do
|
|
echo "Address=$ip"
|
|
done >> /etc/systemd/network/default.network
|
|
systemctl enable systemd-networkd
|
|
elif [ "$network" = "netctl" ]; then
|
|
cat > /etc/netctl/default <<-EOF
|
|
Interface=$dev
|
|
Connection=ethernet
|
|
IP=static
|
|
Address=($ip)
|
|
EOF
|
|
if [ "$gateway" = "0.0.0.0" ]; then
|
|
echo 'Routes=(0.0.0.0/0)'
|
|
else
|
|
echo "Gateway=$gateway"
|
|
fi >> /etc/netctl/default
|
|
netctl enable default
|
|
fi
|
|
dhclient
|
|
systemctl enable sshd
|
|
}
|
|
|
|
finalize() {
|
|
# OpenVZ hacks
|
|
if is_openvz; then
|
|
local kernelver
|
|
read -r _ _ kernelver _ < /proc/version
|
|
if [ "$kernelver" '>' '3.10' ]; then
|
|
# Virtuozzo 7 works with systemd, but it needs /etc/resolvconf/resolv.conf.d directory
|
|
mkdir -p /etc/resolvconf/resolv.conf.d
|
|
elif [ "$kernelver" '<' '2.6.32-042stab111.1' ]; then
|
|
# Use my repository for OpenVZ-patched systemd
|
|
sed -i 's;^#\[testing\]$;[tredaelli-systemd]\nServer = http://pkgbuild.com/~tredaelli/repo/systemd/$arch\n\n&;' /etc/pacman.conf
|
|
fi
|
|
fi
|
|
|
|
# Enable SSH login for user root (#3)
|
|
sed -i '/^#PermitRootLogin\s/s/.*/&\nPermitRootLogin yes/' /etc/ssh/sshd_config
|
|
|
|
# Run reflector to get updated mirrors
|
|
|
|
cat <<-EOF
|
|
|
|
Reflector: Rating the 35 most recently synced HTTPS servers, sorting them by download speed
|
|
|
|
EOF
|
|
|
|
reflector -l 35 -p https --sort rate --save /etc/pacman.d/mirrorlist
|
|
|
|
cat <<-EOF
|
|
Hi,
|
|
your VM has successfully been reimaged with ParchLinux.
|
|
|
|
This script configured $bootloader as bootloader and $network for networking.
|
|
|
|
When you are finished with your post-installation, you'll need to reboot the VM the rough way:
|
|
# sync ; reboot -f
|
|
|
|
Then you'll be able to connect to your VM using SSH and to login using your old root password (or "vps2parch" if you didn't have a root password).
|
|
EOF
|
|
}
|
|
|
|
bootloader=grub
|
|
network=systemd-networkd
|
|
mirrors=
|
|
|
|
while getopts ":b:m:n:h" opt; do
|
|
case $opt in
|
|
b)
|
|
if ! [ "$OPTARG" = "grub" -o "$OPTARG" = "syslinux" -o "$OPTARG" = "none" ]; then
|
|
echo "Invalid bootloader specified" >&2
|
|
exit 1
|
|
fi
|
|
bootloader="$OPTARG"
|
|
;;
|
|
m)
|
|
mirrors="${mirrors:+$mirrors }$OPTARG"
|
|
;;
|
|
n)
|
|
if ! [ "$OPTARG" = "systemd-networkd" -o "$OPTARG" = "netctl" -o "$OPTARG" = "none" ]; then
|
|
echo "Invalid networking configuration system specified" >&2
|
|
exit 1
|
|
fi
|
|
network="$OPTARG"
|
|
;;
|
|
h)
|
|
cat <<-EOF
|
|
usage: ${0##*/} [options]
|
|
|
|
Options:
|
|
-b (grub|syslinux) Use the specified bootloader. When this option is omitted, it defaults to grub.
|
|
-n (systemd-networkd|netctl) Use the specified networking configuration system. When this option is omitted, it defaults to systemd-networkd.
|
|
-m mirror Use the provided mirror (you can specify this option more than once).
|
|
|
|
-h Print this help message
|
|
|
|
Warning:
|
|
On OpenVZ containers the bootloader will be not installed and the networking configuration system will be enforced to netctl.
|
|
EOF
|
|
exit 0
|
|
;;
|
|
:)
|
|
printf "%s: option requires an argument -- '%s'\n" "${0##*/}" "$OPTARG" >&2
|
|
exit 1
|
|
;;
|
|
?)
|
|
printf "%s: invalid option -- '%s'\n" "${0##*/}" "$OPTARG" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
shift $((OPTIND - 1))
|
|
|
|
[ -z "$mirrors" ] && mirrors=$(get_mirrors)
|
|
|
|
|
|
if is_openvz; then
|
|
bootloader=none
|
|
network=netctl
|
|
elif is_lxc; then
|
|
bootloader=none
|
|
fi
|
|
|
|
cd /
|
|
download_and_extract_bootstrap
|
|
configure_chroot
|
|
save_root_pass
|
|
backup_old_files
|
|
delete_all
|
|
install_packages
|
|
restore_root_pass
|
|
cleanup
|
|
configure_bootloader
|
|
configure_network
|
|
finalize
|