支持从 Windows 重装到 Linux

This commit is contained in:
bin456789 2023-06-18 21:27:22 +08:00
parent 19ba1d4fee
commit 071968e713
No known key found for this signature in database
GPG Key ID: EE301B386DE6C11B
4 changed files with 438 additions and 109 deletions

View File

@ -8,7 +8,10 @@
可能是第一个支持在 1g 内存上安装 红帽 7/8/9 系列的脚本 可能是第一个支持在 1g 内存上安装 红帽 7/8/9 系列的脚本
可能是第一个支持重装到 ubuntu 22.04 的脚本 可能是第一个支持重装到 ubuntu 22.04 的脚本
可能是第一个支持重装到 alpine 的脚本 可能是第一个支持重装到 alpine 的脚本
可能是第一个支持重装到 Windows 的脚本(不算 dd 的话) 可能是第一个支持用官方 iso 重装到 Windows 的脚本
支持从 Windows 重装到 Linux
有高贵的 dd 进度条
有很多注释
``` ```
#### 使用: #### 使用:
``` ```
@ -35,7 +38,7 @@ rocky-8/9
fedora-37/38 fedora-37/38
ubuntu-20.04/22.04 ubuntu-20.04/22.04
alpine-3.16/3.17/3.18 alpine-3.16/3.17/3.18
debian-10/11 debian-10/11/12
windows (见下方注意事项) windows (见下方注意事项)
dd dd
``` ```

77
reinstall.bat Normal file
View File

@ -0,0 +1,77 @@
@echo off
set confhome=https://raw.githubusercontent.com/bin456789/reinstall/main
setlocal EnableDelayedExpansion
:: 进入脚本目录
cd /d %~dp0
:: 检查是否有管理员权限
openfiles 1>nul 2>&1
if not !errorlevel! == 0 (
echo "Please run as administrator!"
exit 1
)
:: pkgs 改动了才重新运行 Cygwin 安装程序
set pkgs="curl,cpio,p7zip"
set tags=%tmp%\cygwin-installed-!pkgs!
if not exist !tags! (
:: 检查是否国内
:: 在括号里面,:: 下一行不能是空行!!!!!
call :download https://geoip.fedoraproject.org/city %tmp%\geoip "Check Location"
findstr CHN %tmp%\geoip >nul
if !errorlevel! == 0 (
set host=https://mirrors.tuna.tsinghua.edu.cn
) else (
set host=https://mirrors.kernel.org
)
:: 检查32/64位
wmic os get osarchitecture | findstr 64 >nul
if !errorlevel! == 0 (
set arch=x86_64
set dir=/sourceware/cygwin
) else (
set arch=x86
set dir=/sourceware/cygwin-archive/20221123
)
:: 下载 Cygwin
call :download https://www.cygwin.com/setup-!arch!.exe %tmp%\setup-cygwin.exe "Download Cygwin"
:: 安装 Cygwin
set site=!host!!dir!
%tmp%\setup-cygwin.exe --allow-unsupported-windows^
--quiet-mode^
--only-site^
--site !site!^
--root %SystemDrive%\cygwin^
--local-package-dir %tmp%\cygwin-local-package-dir^
--packages !pkgs!^
&& echo >!tags!
)
:: 下载 reinstall.sh
if not exist reinstall.sh (
call :download %confhome%/reinstall.sh %~dp0reinstall.sh "Download reinstall.sh"
)
:: 运行 reinstall.sh
:: 方法1:
for /f %%a in ('%SystemDrive%\cygwin\bin\cygpath -ua .') do set thisdir=%%a
%SystemDrive%\cygwin\bin\bash -l -c "%thisdir%reinstall.sh %*"
:: 方法2:
:: set PATH=/usr/local/bin:/usr/bin
:: %SystemDrive%\cygwin\bin\bash reinstall.sh %*
exit /b !errorlevel!
:download
:: coreutil 会被 windows Defender 报毒
:: certutil -urlcache -f -split %~1 %~2
bitsadmin /transfer "%~3" %~1 %~2
exit /b !errorlevel!

View File

@ -1,35 +1,72 @@
#!/bin/bash #!/bin/bash
set -eE
confhome=https://raw.githubusercontent.com/bin456789/reinstall/main confhome=https://raw.githubusercontent.com/bin456789/reinstall/main
localtest_confhome=http://192.168.253.1 localtest_confhome=http://192.168.253.1
trap 'error line $LINENO return $?' ERR
usage_and_exit() { usage_and_exit() {
echo "Usage: reinstall.sh centos-7/8/9 alma-8/9 rocky-8/9 fedora-37/38 ubuntu-20.04/22.04 alpine-3.16/3.17/3.18 debian-10/11 windows dd" echo "Usage: reinstall.sh centos-7/8/9 alma-8/9 rocky-8/9 fedora-37/38 ubuntu-20.04/22.04 alpine-3.16/3.17/3.18 debian-10/11/12 windows dd"
exit 1 exit 1
} }
info() {
color='\e[32m'
plain='\e[0m'
upper=$(echo "$@" | tr '[:lower:]' '[:upper:]')
echo -e "$color***** $upper *****$plain"
}
error() {
color='\e[31m'
plain='\e[0m'
echo -e "${color}Error: $*$plain"
}
error_and_exit() { error_and_exit() {
echo "Error: $1" error "$@"
exit 1 exit 1
} }
curl() {
command curl --connect-timeout 10 --retry 5 --retry-delay 0 "$@"
}
is_in_china() { is_in_china() {
if [ -z $_is_in_china ]; then if [ -z $_is_in_china ]; then
# https://geoip.fedoraproject.org/city
# https://geoip.ubuntu.com/lookup # https://geoip.ubuntu.com/lookup
curl -L https://geoip.fedoraproject.org/city | grep -w CHN curl -L https://geoip.ubuntu.com/lookup | grep -qw CHN
_is_in_china=$? _is_in_china=$?
fi fi
return $_is_in_china return $_is_in_china
} }
is_in_windows() {
[ "$(uname -o)" = Cygwin ] || [ "$(uname -o)" = Msys ]
}
set_github_proxy() {
case "$confhome" in
http*://raw.githubusercontent.com/*)
if is_in_china; then
confhome=https://ghproxy.com/$confhome
fi
;;
esac
}
test_url() { test_url() {
url=$1 url=$1
expect_type=$2 expect_type=$2
var_to_eval=$3 var_to_eval=$3
info test url
echo $url
tmp_file=/tmp/reinstall-img-test tmp_file=/tmp/reinstall-img-test
install_pkg file install_pkg file
http_code=$(curl -Ls -r 0-1048576 -w "%{http_code}" -o $tmp_file $url) http_code=$(curl -Ls -r 0-1048575 -w "%{http_code}" -o $tmp_file $url)
if [ "$http_code" != 200 ] && [ "$http_code" != 206 ]; then if [ "$http_code" != 200 ] && [ "$http_code" != 206 ]; then
error_and_exit "$url not accessible" error_and_exit "$url not accessible"
fi fi
@ -47,29 +84,58 @@ test_url() {
fi fi
} }
add_community_repo_for_alpine() {
alpine_ver=$(cut -d. -f1,2 </etc/alpine-release)
echo http://dl-cdn.alpinelinux.org/alpine/v$alpine_ver/community >>/etc/apk/repositories
}
is_virt() {
if command -v systemd-detect-virt; then
systemd-detect-virt
else
if ! install_pkg virt-what && [ -f /etc/alpine-release ]; then
add_community_repo_for_alpine
install_pkg virt-what
fi
virt-what
fi
}
setos() { setos() {
local step=$1 local step=$1
local distro=$2 local distro=$2
local releasever=$3 local releasever=$3
info set $step $distro $releasever
setos_alpine() { setos_alpine() {
flavour=lts
# 在windows中没有命令判断是否为虚拟机
if ! is_in_windows && is_virt; then
# alpine aarch64 3.18 才有 virt 直连链接
if [ "$basearch" == aarch64 ]; then
(($("$releasever >= 3.18" | bc))) && flavour=virt
else
flavour=virt
fi
fi
if [ "$localtest" = 1 ]; then if [ "$localtest" = 1 ]; then
mirror=$confhome/alpine-netboot-3.18.0-x86_64/boot mirror=$confhome/alpine-netboot-3.18.0-x86_64/boot
eval ${step}_vmlinuz=$mirror/vmlinuz-lts eval ${step}_vmlinuz=$mirror/vmlinuz-$flavour
eval ${step}_initrd=$mirror/initramfs-lts eval ${step}_initrd=$mirror/initramfs-$flavour
eval ${step}_repo=https://mirrors.aliyun.com/alpine/v$releasever/main eval ${step}_repo=http://mirrors.tuna.tsinghua.edu.cn/alpine/v$releasever/main
eval ${step}_modloop=$mirror/modloop-lts eval ${step}_modloop=$mirror/modloop-$flavour
else else
# 不要用https 因为甲骨文云arm initramfs阶段不会从硬件同步时钟导致访问https出错 # 不要用https 因为甲骨文云arm initramfs阶段不会从硬件同步时钟导致访问https出错
if is_in_china; then if is_in_china; then
mirror=http://mirrors.aliyun.com/alpine/v$releasever mirror=http://mirrors.tuna.tsinghua.edu.cn/alpine/v$releasever
else else
mirror=http://dl-cdn.alpinelinux.org/alpine/v$releasever mirror=http://dl-cdn.alpinelinux.org/alpine/v$releasever
fi fi
eval ${step}_vmlinuz=$mirror/releases/$basearch/netboot/vmlinuz-lts eval ${step}_vmlinuz=$mirror/releases/$basearch/netboot/vmlinuz-$flavour
eval ${step}_initrd=$mirror/releases/$basearch/netboot/initramfs-lts eval ${step}_initrd=$mirror/releases/$basearch/netboot/initramfs-$flavour
eval ${step}_repo=$mirror/main eval ${step}_repo=$mirror/main
eval ${step}_modloop=$mirror/releases/$basearch/netboot/modloop-lts eval ${step}_modloop=$mirror/releases/$basearch/netboot/modloop-$flavour
fi fi
} }
@ -102,8 +168,8 @@ setos() {
else else
if is_in_china; then if is_in_china; then
case "$basearch" in case "$basearch" in
"x86_64") mirror=https://mirrors.aliyun.com/ubuntu-releases/$releasever/ ;; "x86_64") mirror=https://mirrors.tuna.tsinghua.edu.cn/ubuntu-releases/$releasever/ ;;
"aarch64") mirror=https://mirrors.aliyun.com/ubuntu-cdimage/releases/$releasever/release/ ;; "aarch64") mirror=https://mirrors.tuna.tsinghua.edu.cn/ubuntu-cdimage/releases/$releasever/release/ ;;
esac esac
else else
case "$basearch" in case "$basearch" in
@ -122,8 +188,7 @@ setos() {
setos_windows() { setos_windows() {
if [ -z "$iso" ] || [ -z "$image_name" ]; then if [ -z "$iso" ] || [ -z "$image_name" ]; then
echo "Install Windows need --iso --image-name" error_and_exit "Install Windows need --iso --image-name"
exit 1
fi fi
test_url $iso iso test_url $iso iso
eval "${step}_iso='$iso'" eval "${step}_iso='$iso'"
@ -133,8 +198,7 @@ setos() {
# shellcheck disable=SC2154 # shellcheck disable=SC2154
setos_dd() { setos_dd() {
if [ -z "$img" ]; then if [ -z "$img" ]; then
echo "dd need --img" error_and_exit "dd need --img"
exit 1
fi fi
test_url $img 'xz|gzip' img_type test_url $img 'xz|gzip' img_type
eval "${step}_img='$img'" eval "${step}_img='$img'"
@ -198,7 +262,7 @@ verify_os_string() {
fi fi
done done
echo "Please specify a proper os." error "Please specify a proper os"
usage_and_exit usage_and_exit
} }
@ -212,7 +276,7 @@ install_pkg() {
for pkg in $pkgs; do for pkg in $pkgs; do
# util-linux 用 lsmem 命令测试 # util-linux 用 lsmem 命令测试
[ "$pkg" = util-linux ] && pkg=lsmem [ "$pkg" = util-linux ] && pkg=lsmem
if ! command -v $pkg; then if ! command -v $pkg >/dev/null; then
{ {
apt_install $pkgs || apt_install $pkgs ||
dnf install -y $pkgs || dnf install -y $pkgs ||
@ -227,13 +291,17 @@ install_pkg() {
} }
check_ram() { check_ram() {
# lsmem最准确但centos7 arm 和alpine不能用 if is_in_windows; then
# arm 24g dmidecode 显示少了128m ram_size=$(wmic memorychip get capacity | tail +2 | awk '{sum+=$1} END {print sum/1024/1024}')
install_pkg util-linux else
ram_size=$(lsmem -b 2>/dev/null | grep 'Total online memory:' | awk '{ print $NF/1024/1024 }') # lsmem最准确但centos7 arm 和alpine不能用
if [ -z $ram_size ]; then # arm 24g dmidecode 显示少了128m
install_pkg dmidecode install_pkg util-linux
ram_size=$(dmidecode -t 17 | grep "Size.*[GM]B" | awk '{if ($3=="GB") s+=$2*1024; else s+=$2} END {print s}') ram_size=$(lsmem -b 2>/dev/null | grep 'Total online memory:' | awk '{ print $NF/1024/1024 }')
if [ -z $ram_size ]; then
install_pkg dmidecode
ram_size=$(dmidecode -t 17 | grep "Size.*[GM]B" | awk '{if ($3=="GB") s+=$2*1024; else s+=$2} END {print s}')
fi
fi fi
case "$distro" in case "$distro" in
@ -242,30 +310,141 @@ check_ram() {
*) ram_requirement=1024 ;; *) ram_requirement=1024 ;;
esac esac
if [ -z $ram_size ] || [ $ram_size -le 0 ]; then
error_and_exit "Could not detect RAM size."
fi
if [ $ram_size -lt $ram_requirement ]; then if [ $ram_size -lt $ram_requirement ]; then
echo "Could not install $distro: RAM < $ram_requirement MB." error_and_exit "Could not install $distro: RAM < $ram_requirement MB."
exit 1 fi
}
is_efi() {
if is_in_windows; then
bcdedit | grep -q '^path.*\.efi'
else
[ -d /sys/firmware/efi ]
fi
}
install_grub_win() {
grub_cfg=$1 # /cygdrive/$c/grub.cfg
# 下载 grub
info download grub
grub_ver=2.06
is_in_china && grub_url=https://mirrors.tuna.tsinghua.edu.cn/gnu/grub/grub-$grub_ver-for-windows.zip ||
grub_url=https://ftp.gnu.org/gnu/grub/grub-$grub_ver-for-windows.zip
echo $grub_url
curl -Lo /tmp/grub.zip $grub_url
# unzip -qo /tmp/grub.zip
7z x /tmp/grub.zip -o/tmp -r -y -xr!i386-efi -xr!locale -xr!themes -bso0
grub_exe_dir=$(readlink -f /tmp/grub-$grub_ver-for-windows)
# 设置 grub 内嵌的模块
grub_modules+=" normal minicmd ls echo test cat reboot halt linux chain search all_video configfile"
grub_modules+=" scsi part_msdos part_gpt fat ntfs ntfscomp ext2 lvm xfs lzopio xzio gzio zstd"
if ! is_efi; then
grub_modules+=" biosdisk"
fi
# 设置 grub prefix 为c盘根目录
# 运行 grub-probe 会改变cmd窗口字体
prefix=$($grub_exe_dir/grub-probe -t drive $c: | sed 's,.*PhysicalDrive,(hd,' | sed 's,\r,,')/
echo $prefix
# 安装 grub
if is_efi; then
# efi
info install grub for efi
# 挂载
if result=$(find /cygdrive/?/EFI/Microsoft/Boot/bootmgfw.efi 2>/dev/null); then
# 已经挂载
x=$(echo $result | cut -d/ -f3)
else
# 找到空盘符并挂载
for x in {a..z}; do
[ ! -e /cygdrive/$x ] && break
done
mountvol $x: /s
fi
# 文件夹命名为reinstall而不是grub因为可能机器已经安装了grubbcdedit名字同理
grub_dir=$x:\\EFI\\reinstall
mkdir -p $grub_dir
# grub-mkimage 可设置prefix也可嵌入配置文件官方不建议嵌入menuentry条目
# -c $grub_cfg_win
$grub_exe_dir/grub-mkimage -p $prefix -O x86_64-efi -o $grub_dir\\grubx64.efi $grub_modules
# 添加引导
# 脚本可能不是首次运行,所以先删除原来的
bcdedit /enum bootmgr | grep --text -B3 Reinstall | awk '{print $2}' | grep '{.*}' |
xargs -I {} cmd /c bcdedit /delete {}
id=$(bcdedit /copy '{bootmgr}' /d Reinstall | grep -o '{.*}')
bcdedit /set $id device partition=$x:
bcdedit /set $id path \\EFI\\reinstall\\grubx64.efi
bcdedit /set '{fwbootmgr}' bootsequence $id
else
# bios
info install grub for bios
# bootmgr 加载 gr2ldr 有64k限制
# 解决方法1 gr2ldr.mbr + gr2ldr
# 解决方法2 生成少于64K的 g2ldr + 动态模块
# gr2ldr.mbr
curl -LO http://ftp.cn.debian.org/debian/tools/win32-loader/stable/win32-loader.exe
7z x win32-loader.exe 'g2ldr.mbr' -o/tmp/win32-loader -r -y -bso0
find /tmp/win32-loader -name 'g2ldr.mbr' -exec cp {} /cygdrive/$c/ \;
# g2ldr
$grub_exe_dir/grub-mkimage -p "$prefix" -O i386-pc -o core.img $grub_modules
cat $grub_exe_dir/i386-pc/lnxboot.img core.img >/cygdrive/$c/g2ldr
# 添加引导
# 脚本可能不是首次运行,所以先删除原来的
id='{1c41f649-1637-52f1-aea8-f96bfebeecc8}'
bcdedit /enum all | grep --text $id && bcdedit /delete $id
bcdedit /create $id /d Reinstall /application bootsector
bcdedit /set $id device partition=$c:
bcdedit /set $id path \\g2ldr.mbr
bcdedit /displayorder $id /addlast
bcdedit /bootsequence $id /addfirst
fi fi
} }
# 脚本入口 # 脚本入口
if [ "$EUID" -ne 0 ]; then # 检查 root
echo "Please run as root." if ! is_in_windows; then
exit 1 if [ "$EUID" -ne 0 ]; then
info "Please run as root."
exit 1
fi
fi fi
if ! opts=$(getopt -a -n $0 --options l --long localtest,iso:,image-name:,img: -- "$@"); then # 整理参数
if ! opts=$(getopt -n $0 -o "" --long localtest,debug,sleep:,iso:,image-name:,img: -- "$@"); then
usage_and_exit usage_and_exit
fi fi
eval set -- "$opts" eval set -- "$opts"
# shellcheck disable=SC2034
while true; do while true; do
case "$1" in case "$1" in
-l | --localtest) --localtest)
localtest=1 localtest=1
confhome=$localtest_confhome confhome=$localtest_confhome
shift shift
;; ;;
--debug)
set -x
shift
;;
--sleep)
sleep=$2
shift 2
;;
--img) --img)
img=$2 img=$2
shift 2 shift 2
@ -289,8 +468,14 @@ while true; do
esac esac
done done
# 验证目标系统字符串
verify_os_string "$@" verify_os_string "$@"
# win系统盘
if is_in_windows; then
c=$(echo $SYSTEMDRIVE | cut -c1)
fi
# 必备组件 # 必备组件
install_pkg curl install_pkg curl
# alpine 自带的 grep 是 busybox 里面的, 要下载完整版grep # alpine 自带的 grep 是 busybox 里面的, 要下载完整版grep
@ -298,13 +483,21 @@ if [ -f /etc/alpine-release ]; then
apk add grep apk add grep
fi fi
# 检查内存
check_ram check_ram
# 检查硬件架构
# x86强制使用x64
basearch=$(uname -m) basearch=$(uname -m)
[ $basearch = i686 ] && basearch=x86_64
case "$basearch" in case "$basearch" in
"x86_64") basearch_alt=amd64 ;; "x86_64") basearch_alt=amd64 ;;
"aarch64") basearch_alt=arm64 ;; "aarch64") basearch_alt=arm64 ;;
esac esac
# 设置 github 国内代理
set_github_proxy
# 以下目标系统需要进入alpine环境安装 # 以下目标系统需要进入alpine环境安装
# ubuntu/alpine # ubuntu/alpine
# el8/9/fedora 任何架构 <2g # el8/9/fedora 任何架构 <2g
@ -326,27 +519,29 @@ fi
# 下载启动内核 # 下载启动内核
# shellcheck disable=SC2154 # shellcheck disable=SC2154
{ {
cd / info download vmlnuz and initrd
echo $nextos_vmlinuz echo $nextos_vmlinuz
curl -Lo reinstall-vmlinuz $nextos_vmlinuz curl -Lo /reinstall-vmlinuz $nextos_vmlinuz
echo $nextos_initrd echo $nextos_initrd
curl -Lo reinstall-initrd $nextos_initrd curl -Lo /reinstall-initrd $nextos_initrd
} }
# 转换 finalos_a=1 为 finalos.a=1 ,排除 finalos_mirrorlist # 转换 finalos_a=1 为 finalos.a=1 ,排除 finalos_mirrorlist
build_finalos_cmdline() { build_finalos_cmdline() {
for key in $(compgen -v finalos_); do if vars=$(compgen -v finalos_); then
value=${!key} for key in $vars; do
key=${key#finalos_} value=${!key}
if [ -n "$value" ] && [ $key != "mirrorlist" ]; then key=${key#finalos_}
finalos_cmdline+=" finalos.$key='$value'" if [ -n "$value" ] && [ $key != "mirrorlist" ]; then
fi finalos_cmdline+=" finalos.$key='$value'"
done fi
done
fi
} }
build_extra_cmdline() { build_extra_cmdline() {
for key in localtest confhome; do for key in localtest confhome sleep; do
value=${!key} value=${!key}
if [ -n "$value" ]; then if [ -n "$value" ]; then
extra_cmdline+=" extra.$key='$value'" extra_cmdline+=" extra.$key='$value'"
@ -361,24 +556,30 @@ build_extra_cmdline() {
fi fi
} }
build_finalos_cmdline # shellcheck disable=SC2154
build_extra_cmdline build_cmdline() {
grub_cfg=$(find /boot -type f -name grub.cfg -exec grep -E -l 'menuentry|blscfg' {} \;) if [ -n "$finalos_cmdline" ]; then
grub_cfg_dir=$(dirname $grub_cfg) # 有 finalos_cmdline 表示需要两步安装
# 两步安装需要修改 alpine initrd
mod_alpine_initrd
# 在x86 efi机器上可能用 linux 或 linuxefi 加载内核 # 可添加 pkgs=xxx,yyy 启动时自动安装
# 通过检测原有的条目有没有 linuxefi 字样就知道当前 grub 用哪一种 # apkovl=http://xxx.com/apkovl.tar.gz 可用arm https未测但应该不行
search_files=$(find /boot -type f -name grub.cfg) # apkovl=sda2:ext4:/apkovl.tar.gz 官方有写但不生效
if [ -d /boot/loader/entries/ ]; then cmdline="alpine_repo=$nextos_repo modloop=$nextos_modloop $extra_cmdline $finalos_cmdline"
search_files="$search_files /boot/loader/entries/" else
fi if [ $distro = debian ]; then
if grep -q -r -E '^[[:blank:]]*linuxefi[[:blank:]]' $search_files; then cmdline="lowmem=+1 lowmem/low=1 auto=true priority=critical url=$nextos_ks"
efi=efi else
fi # redhat
cmdline="root=live:$nextos_squashfs inst.ks=$nextos_ks $extra_cmdline"
fi
fi
}
# 修改 alpine 启动时运行我们的脚本 mod_alpine_initrd() {
# shellcheck disable=SC2154,SC2164 # 修改 alpine 启动时运行我们的脚本
if [ -n "$finalos_cmdline" ]; then info mod alpine initrd
install_pkg gzip cpio install_pkg gzip cpio
# 解压 # 解压
@ -394,13 +595,12 @@ if [ -n "$finalos_cmdline" ]; then
# exec switch_root $switch_root_opts $sysroot $chart_init "$KOPT_init" $KOPT_init_args # 3.18 # exec switch_root $switch_root_opts $sysroot $chart_init "$KOPT_init" $KOPT_init_args # 3.18
line_num=$(grep -E -n '^exec (/bin/busybox )?switch_root' init | cut -d: -f1) line_num=$(grep -E -n '^exec (/bin/busybox )?switch_root' init | cut -d: -f1)
line_num=$((line_num - 1)) line_num=$((line_num - 1))
# alpine arm initramfs 时间问题 要添加 --no-check-certificate
cat <<EOF | sed -i "${line_num}r /dev/stdin" init cat <<EOF | sed -i "${line_num}r /dev/stdin" init
# alpine arm initramfs 时间问题 要添加 --no-check-certificate
wget --no-check-certificate -O \$sysroot/etc/local.d/trans.start $confhome/trans.sh wget --no-check-certificate -O \$sysroot/etc/local.d/trans.start $confhome/trans.sh
chmod a+x \$sysroot/etc/local.d/trans.start chmod a+x \$sysroot/etc/local.d/trans.start
ln -s /etc/init.d/local \$sysroot/etc/runlevels/default/ ln -s /etc/init.d/local \$sysroot/etc/runlevels/default/
EOF EOF
# 重建 # 重建
# 注意要用 cpio -H newc 不要用 cpio -c ,不同版本的 -c 作用不一样,很坑 # 注意要用 cpio -H newc 不要用 cpio -c ,不同版本的 -c 作用不一样,很坑
# -c Use the old portable (ASCII) archive format # -c Use the old portable (ASCII) archive format
@ -408,26 +608,35 @@ EOF
# portable format.If you wish the old portable # portable format.If you wish the old portable
# (ASCII) archive format, use "-H odc" instead. # (ASCII) archive format, use "-H odc" instead.
find . | cpio -o -H newc | gzip -1 >/reinstall-initrd find . | cpio -o -H newc | gzip -1 >/reinstall-initrd
cd -
}
# 删除临时文件 build_finalos_cmdline
cd / build_extra_cmdline
rm -rf $tmp_dir build_cmdline
# 可添加 pkgs=xxx,yyy 启动时自动安装 info 'create grub config'
# apkovl=http://xxx.com/apkovl.tar.gz 可用arm https未测但应该不行 # linux grub
# apkovl=sda2:ext4:/apkovl.tar.gz 官方有写但不生效 if ! is_in_windows; then
cmdline="alpine_repo=$nextos_repo modloop=$nextos_modloop $extra_cmdline $finalos_cmdline" # 找到主配置 grub.cfg
else grub_cfg=$(find /boot -type f -name grub.cfg -exec grep -E -l 'menuentry|blscfg' {} \;)
if [ $distro = debian ]; then
cmdline="lowmem=+1 lowmem/low=1 auto=true priority=critical url=$nextos_ks" # 在x86 efi机器上不同版本的 grub 可能用 linux 或 linuxefi 加载内核
else # 通过检测原有的条目有没有 linuxefi 字样就知道当前 grub 用哪一种
cmdline="root=live:$nextos_squashfs inst.ks=$nextos_ks $extra_cmdline" search_files=$(find /boot -type f -name grub.cfg)
if [ -d /boot/loader/entries/ ]; then
search_files+=" /boot/loader/entries/"
fi
if grep -q -r -E '^[[:blank:]]*linuxefi[[:blank:]]' $search_files; then
efi=efi
fi fi
fi fi
custom_cfg=$grub_cfg_dir/custom.cfg # 生成 custom.cfg (linux) 或者 grub.cfg (win)
is_in_windows && custom_cfg=/cygdrive/$c/grub.cfg || custom_cfg=$(dirname $grub_cfg)/custom.cfg
echo $custom_cfg echo $custom_cfg
cat <<EOF | tee $custom_cfg cat <<EOF | tee $custom_cfg
set timeout=5
menuentry "reinstall" { menuentry "reinstall" {
insmod lvm insmod lvm
insmod xfs insmod xfs
@ -437,5 +646,12 @@ menuentry "reinstall" {
} }
EOF EOF
$(command -v grub-reboot grub2-reboot) reinstall if is_in_windows; then
echo "Please reboot to begin the installation." mv /reinstall-vmlinuz /cygdrive/$c/
mv /reinstall-initrd /cygdrive/$c/
install_grub_win $custom_cfg
else
$(command -v grub-reboot grub2-reboot) reinstall
fi
info 'Please reboot to begin the installation'

View File

@ -1,17 +1,61 @@
#!/bin/ash #!/bin/ash
# shellcheck shell=dash # shellcheck shell=dash
# shellcheck disable=SC3047,SC3036
# alpine 默认使用 busybox ash # alpine 默认使用 busybox ash
# 命令出错退出脚本,进入到登录界面,防止失联
# TODO: neet more test
set -eE
# 显示输出到前台 # 显示输出到前台
# 似乎script更优雅但 alpine 不带 script 命令 # 似乎script更优雅但 alpine 不带 script 命令
# script -f/dev/tty0 # script -f/dev/tty0
exec >/dev/tty0 2>&1 exec >/dev/tty0 2>&1
trap 'error' ERR
catch() {
if [ "$1" != "0" ]; then
error "Error $1 occurred on $2"
fi
}
error() {
color='\e[31m'
plain='\e[0m'
echo -e "${color}Error: $*$plain"
}
add_community_repo() { add_community_repo() {
alpine_ver=$(cut -d. -f1,2 </etc/alpine-release) alpine_ver=$(cut -d. -f1,2 </etc/alpine-release)
echo http://dl-cdn.alpinelinux.org/alpine/v$alpine_ver/community >>/etc/apk/repositories echo http://dl-cdn.alpinelinux.org/alpine/v$alpine_ver/community >>/etc/apk/repositories
} }
download() {
# 显示 url
echo $1
# 阿里云禁止 axel 下载
# axel https://mirrors.aliyun.com/alpine/latest-stable/releases/x86_64/alpine-netboot-3.17.0-x86_64.tar.gz
# Initializing download: https://mirrors.aliyun.com/alpine/latest-stable/releases/x86_64/alpine-netboot-3.17.0-x86_64.tar.gz
# HTTP/1.1 403 Forbidden
# 先用 axel 下载
[ -z $2 ] && save="" || save="-o $2"
if ! axel $1 $save; then
# 出错再用 curl
[ -z $2 ] && save="-O" || save="-o $2"
curl -L $1 $save
fi
}
update_part() {
hdparm -z $1 || true
partprobe $1 || true
partx -u $1 || true
udevadm settle || true
echo 1 >/sys/block/${1#/dev/}/device/rescan || true
} 2>/dev/null
# 提取 finalos/extra 到变量 # 提取 finalos/extra 到变量
for prefix in finalos extra; do for prefix in finalos extra; do
while read -r line; do while read -r line; do
@ -38,6 +82,12 @@ hwclock -s
echo root:123@@@ | chpasswd echo root:123@@@ | chpasswd
printf '\nyes' | setup-sshd printf '\nyes' | setup-sshd
# shellcheck disable=SC2154
if [ "$sleep" = 1 ]; then
cd /
sleep infinity
fi
# shellcheck disable=SC2154 # shellcheck disable=SC2154
if [ "$distro" = "alpine" ]; then if [ "$distro" = "alpine" ]; then
# 还原改动,不然本脚本会被复制到新系统 # 还原改动,不然本脚本会被复制到新系统
@ -51,15 +101,15 @@ if [ "$distro" = "alpine" ]; then
# 设置 # 设置
setup-keymap us us setup-keymap us us
setup-timezone -i Asia/Shanghai setup-timezone -i Asia/Shanghai
setup-ntp chrony setup-ntp chrony || true
# 在 arm netboot initramfs init 中 # 在 arm netboot initramfs init 中
# 如果识别到rtc硬件就往系统添加hwclock服务否则添加swclock # 如果识别到rtc硬件就往系统添加hwclock服务否则添加swclock
# 这个设置也被复制到安装的系统中 # 这个设置也被复制到安装的系统中
# 但是从initramfs chroot到真正的系统后是能识别rtc硬件的 # 但是从initramfs chroot到真正的系统后是能识别rtc硬件的
# 所以我们手动改用hwclock修复这个问题 # 所以我们手动改用hwclock修复这个问题
rc-update del swclock boot rc-update del swclock boot || true
rc-update add hwclock boot rc-update add hwclock boot || true
# 通过 setup-alpine 安装会多启用几个服务 # 通过 setup-alpine 安装会多启用几个服务
# https://github.com/alpinelinux/alpine-conf/blob/c5131e9a038b09881d3d44fb35e86851e406c756/setup-alpine.in#L189 # https://github.com/alpinelinux/alpine-conf/blob/c5131e9a038b09881d3d44fb35e86851e406c756/setup-alpine.in#L189
@ -98,41 +148,23 @@ elif [ "$distro" = "dd" ]; then
if [ -n "$prog" ]; then if [ -n "$prog" ]; then
# alpine busybox 自带 gzip xz但官方版也许性能更好 # alpine busybox 自带 gzip xz但官方版也许性能更好
# wget -O- $img | $prog -dc >/dev/$xda
apk add curl $prog apk add curl $prog
curl -L $img | $prog -dc >/dev/$xda curl -L $img | $prog -dc >/dev/$xda
sync
else else
echo 'Not supported' echo 'Not supported'
sleep 1m sleep 1m
fi fi
if [ "$sleep" = 2 ]; then
cd /
sleep infinity
fi
exec reboot exec reboot
fi fi
download() { # 目标系统非 alpine 和 dd
# 显示 url # 脚本开始
echo $1
# 阿里云禁止 axel 下载
# axel https://mirrors.aliyun.com/alpine/latest-stable/releases/x86_64/alpine-netboot-3.17.0-x86_64.tar.gz
# Initializing download: https://mirrors.aliyun.com/alpine/latest-stable/releases/x86_64/alpine-netboot-3.17.0-x86_64.tar.gz
# HTTP/1.1 403 Forbidden
# 先用 axel 下载
[ -z $2 ] && save="" || save="-o $2"
if ! axel $1 $save; then
# 出错再用 curl
[ -z $2 ] && save="-O" || save="-o $2"
curl -L $1 $save
fi
}
update_part() {
hdparm -z $1
partprobe $1
partx -u $1
udevadm settle
echo 1 >/sys/block/${1#/dev/}/device/rescan
} 2>/dev/null
if ! apk add util-linux axel grub udev hdparm e2fsprogs curl parted; then if ! apk add util-linux axel grub udev hdparm e2fsprogs curl parted; then
echo 'Unable to install package!' echo 'Unable to install package!'
sleep 1m sleep 1m
@ -281,6 +313,7 @@ if [ "$distro" = "windows" ]; then
'windows 8.1'*) sys=w8.1 ;; 'windows 8.1'*) sys=w8.1 ;;
'windows 8'*) sys=w8 ;; 'windows 8'*) sys=w8 ;;
'windows 7'*) sys=w7 ;; 'windows 7'*) sys=w7 ;;
'windows vista'*) sys=2k8 ;; # virtio 没有 vista 专用驱动
esac esac
case "$sys" in case "$sys" in