|
@@ -0,0 +1,235 @@
|
|
|
|
|
+#!/bin/sh
|
|
|
|
|
+
|
|
|
|
|
+set -xeu
|
|
|
|
|
+
|
|
|
|
|
+chroot_dir="/mnt"
|
|
|
|
|
+
|
|
|
|
|
+arch="$(uname -m)"
|
|
|
|
|
+mirror="https://dl-cdn.alpinelinux.org/alpine"
|
|
|
|
|
+alpine_version="v3.20"
|
|
|
|
|
+apk_version="2.14.4-r1"
|
|
|
|
|
+apk_link="${mirror}/${alpine_version}/main/${arch}/apk-tools-static-${apk_version}.apk"
|
|
|
|
|
+
|
|
|
|
|
+fatal() {
|
|
|
|
|
+ echo "$1" >&2
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+die() {
|
|
|
|
|
+ fatal "$2"
|
|
|
|
|
+ exit "$1"
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+usage() {
|
|
|
|
|
+ cat >&2 <<EOF
|
|
|
|
|
+Usage: $0 <action> [-r <chroot_dir>] [-h]
|
|
|
|
|
+
|
|
|
|
|
+Action:
|
|
|
|
|
+ rootfs deploy alpine rootfs in <chroot_dir>
|
|
|
|
|
+ setup setup rootfs inside chroot environment
|
|
|
|
|
+ full deploy rootfs and run setup inside chroot
|
|
|
|
|
+
|
|
|
|
|
+Options:
|
|
|
|
|
+ -r <chroot_dir> specify chroot directory
|
|
|
|
|
+ [default: $chroot_dir]
|
|
|
|
|
+ -h show this help message
|
|
|
|
|
+EOF
|
|
|
|
|
+ exit "$1"
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+ensure_root() {
|
|
|
|
|
+ if [ "$(id -u)" = 0 ]; then
|
|
|
|
|
+ return 0
|
|
|
|
|
+ fi
|
|
|
|
|
+
|
|
|
|
|
+ die 1 "The script must be run as root"
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+parse_action() {
|
|
|
|
|
+ case "$1" in
|
|
|
|
|
+ rootfs|setup|full) action="$1" ;;
|
|
|
|
|
+ *)
|
|
|
|
|
+ fatal "unknown op: $1"
|
|
|
|
|
+ usage 1
|
|
|
|
|
+ ;;
|
|
|
|
|
+ esac
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+parse_args() {
|
|
|
|
|
+ [ "$#" -lt 1 ] && usage 1
|
|
|
|
|
+ parse_action "$1" && shift
|
|
|
|
|
+
|
|
|
|
|
+ while getopts "r:h" opt; do
|
|
|
|
|
+ case "$opt" in
|
|
|
|
|
+ r) chroot_dir="$(realpath "$OPTARG")" ;;
|
|
|
|
|
+ h) usage 0 ;;
|
|
|
|
|
+ ?) usage 1 ;;
|
|
|
|
|
+ esac
|
|
|
|
|
+ done
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+# download static apk and print the executable filename
|
|
|
|
|
+download_apk() {
|
|
|
|
|
+ local tmpdir
|
|
|
|
|
+ tmpdir="$(mktemp -d)"
|
|
|
|
|
+
|
|
|
|
|
+ curl -L "$apk_link" | tar -C "$tmpdir" -xzf -
|
|
|
|
|
+
|
|
|
|
|
+ echo "$tmpdir/sbin/apk.static"
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+install_rootfs() {
|
|
|
|
|
+ apk_bin="$(download_apk)"
|
|
|
|
|
+
|
|
|
|
|
+ mkdir -p "$chroot_dir/etc/apk"
|
|
|
|
|
+
|
|
|
|
|
+ "$apk_bin" -X "$mirror/$alpine_version/main" -U --allow-untrusted \
|
|
|
|
|
+ -p "$chroot_dir" --initdb add alpine-base e2fsprogs
|
|
|
|
|
+
|
|
|
|
|
+ cat > "$chroot_dir/etc/resolv.conf" <<EOF
|
|
|
|
|
+nameserver 1.1.1.1
|
|
|
|
|
+nameserver 1.0.0.1
|
|
|
|
|
+nameserver 8.8.8.8
|
|
|
|
|
+EOF
|
|
|
|
|
+
|
|
|
|
|
+ cat > "$chroot_dir/etc/apk/repositories" <<EOF
|
|
|
|
|
+$mirror/$alpine_version/main
|
|
|
|
|
+$mirror/$alpine_version/community
|
|
|
|
|
+EOF
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+bind_mount_vfs() {
|
|
|
|
|
+ for fs in proc sys dev; do
|
|
|
|
|
+ mount -o bind "/$fs" "$chroot_dir/$fs"
|
|
|
|
|
+ done
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+install_inside_chroot() {
|
|
|
|
|
+ deploy_name="$(realpath "$0")"
|
|
|
|
|
+ inside_deploy_path="$chroot_dir/deploy.sh"
|
|
|
|
|
+
|
|
|
|
|
+ cp "$deploy_name" "$inside_deploy_path"
|
|
|
|
|
+ chmod +x "$inside_deploy_path"
|
|
|
|
|
+
|
|
|
|
|
+ bind_mount_vfs
|
|
|
|
|
+ chroot "$chroot_dir" /deploy.sh setup
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+extra_setup_vim() {
|
|
|
|
|
+ apk add vim
|
|
|
|
|
+ ln -s "$(which vim)" /usr/local/bin/vi
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+extra_setup_fish() {
|
|
|
|
|
+ apk add fish
|
|
|
|
|
+ # chsh -s "$(which fish)"
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+setup_extra() {
|
|
|
|
|
+ extra_setup_vim
|
|
|
|
|
+ extra_setup_fish
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+install_kernel() {
|
|
|
|
|
+ apk add linux-virt linux-firmware-none
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+install_packages() {
|
|
|
|
|
+ apk add chrony acpi busybox-mdev-openrc
|
|
|
|
|
+ apk add grub grub-bios
|
|
|
|
|
+
|
|
|
|
|
+ apk add openssh blkid
|
|
|
|
|
+
|
|
|
|
|
+ install_kernel
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+part_uuid() {
|
|
|
|
|
+ blkid -o export -s UUID "$1" | sed -n -e 2p
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+mountpoint_dev() {
|
|
|
|
|
+ mount | grep "on $1 " | awk '{ print $1 }'
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+mountpoint_fstype() {
|
|
|
|
|
+ mount | grep "on $1 " | awk '{ print $5 }'
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+mountpoint_options() {
|
|
|
|
|
+ mount | grep "on $1 " | awk '{ print $6 }' | tr -d '()'
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+# $1: mountpoint
|
|
|
|
|
+# $2: check on boot
|
|
|
|
|
+gen_fstab_entry() {
|
|
|
|
|
+ _mnt="$1"
|
|
|
|
|
+ _dev="$(mountpoint_dev "$_mnt")"
|
|
|
|
|
+ _fs="$(mountpoint_fstype "$_mnt")"
|
|
|
|
|
+ _options="$(mountpoint_options "$_mnt")"
|
|
|
|
|
+ _uuid="$(part_uuid "$_dev")"
|
|
|
|
|
+
|
|
|
|
|
+ case "$2" in
|
|
|
|
|
+ y|Y|1) _check=1 ;;
|
|
|
|
|
+ *) _check=0 ;;
|
|
|
|
|
+ esac
|
|
|
|
|
+
|
|
|
|
|
+ echo "$_uuid $_mnt $_fs $_options 0 $_check"
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+gen_fstab() {
|
|
|
|
|
+ gen_fstab_entry / y
|
|
|
|
|
+ echo "tmpfs /tmp tmpfs nosuid,nodev 0 0"
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+populate_fstab() {
|
|
|
|
|
+ gen_fstab | tee /etc/fstab
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+enable_services() {
|
|
|
|
|
+ rc-update add devfs sysinit
|
|
|
|
|
+ rc-update add dmesg sysinit
|
|
|
|
|
+ rc-update add mdev sysinit
|
|
|
|
|
+
|
|
|
|
|
+ rc-update add hwclock boot
|
|
|
|
|
+ rc-update add modules boot
|
|
|
|
|
+ rc-update add sysctl boot
|
|
|
|
|
+ rc-update add hostname boot
|
|
|
|
|
+ rc-update add bootmisc boot
|
|
|
|
|
+ rc-update add syslog boot
|
|
|
|
|
+ rc-update add localmount boot
|
|
|
|
|
+ rc-update add networking boot
|
|
|
|
|
+
|
|
|
|
|
+ rc-update add mount-ro shutdown
|
|
|
|
|
+ rc-update add killprocs shutdown
|
|
|
|
|
+ rc-update add savecache shutdown
|
|
|
|
|
+
|
|
|
|
|
+ rc-update add acpid default
|
|
|
|
|
+ rc-update add crond default
|
|
|
|
|
+ rc-update add chronyd default
|
|
|
|
|
+ rc-update add sshd default
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+setup_rootfs() {
|
|
|
|
|
+ install_packages
|
|
|
|
|
+ enable_services
|
|
|
|
|
+
|
|
|
|
|
+ echo "Set root password:"
|
|
|
|
|
+ passwd
|
|
|
|
|
+
|
|
|
|
|
+ setup_extra
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+full_install() {
|
|
|
|
|
+ install_rootfs
|
|
|
|
|
+ install_inside_chroot
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+parse_args "$@"
|
|
|
|
|
+
|
|
|
|
|
+ensure_root
|
|
|
|
|
+
|
|
|
|
|
+case "$action" in
|
|
|
|
|
+ rootfs) install_rootfs ;;
|
|
|
|
|
+ setup) setup_rootfs ;;
|
|
|
|
|
+ full) full_install ;;
|
|
|
|
|
+ *) usage 1;;
|
|
|
|
|
+esac
|