Compare commits

..

11 Commits

8 changed files with 290 additions and 154 deletions

View File

@ -4,7 +4,8 @@
[![Codacy](https://img.shields.io/codacy/grade/dc679a17751448628fe6d8ac35e26eed?logo=Codacy&label=Codacy&style=flat-square)](https://app.codacy.com/gh/bin456789/reinstall/dashboard)
[![CodeFactor](https://img.shields.io/codefactor/grade/github/bin456789/reinstall?logo=CodeFactor&logoColor=white&label=CodeFactor&style=flat-square)](https://www.codefactor.io/repository/github/bin456789/reinstall)
[![Lines of Code](https://tokei.rs/b1/github/bin456789/reinstall?category=code&label=Lines%20of%20Code&style=flat-square)](https://github.com/XAMPPRocky/tokei_rs)
[![Lines of Code](https://aschey.tech/tokei/github/bin456789/reinstall?category=code&label=Lines%20of%20Code&style=flat-square)](https://github.com/aschey/vercel-tokei)
<!-- [![Lines of Code](https://tokei.rs/b1/github/bin456789/reinstall?category=code&label=Lines%20of%20Code&style=flat-square)](https://github.com/XAMPPRocky/tokei_rs) -->
One-Click system reinstallation script for VPS [中文](README.md)
@ -34,7 +35,7 @@ If this helped you, you can buy me a milk tea.
- [Download](#download-current-system-is--linux)
- [Feature 1. One-click reinstallation to Linux](#feature-1-install--linux)
- [Feature 2. One-click DD Raw image to hard disk](#feature-2-dd-raw-image-to-hard-disk)
- [Feature 3. One-click reboot to Alpine Live OS in-memory system](#feature-3-reboot-to--alpine-live-os-ram-os)
- [Feature 3. One-click reboot to Alpine Live OS](#feature-3-reboot-to--alpine-live-os)
- [Feature 4. One-click reboot to netboot.xyz](#feature-4-reboot-to--netbootxyz)
- [Feature 5. One-click reinstallation to Windows](#feature-5-install--windows-iso)
@ -149,7 +150,7 @@ certutil -urlcache -f -split https://cnb.cool/bin456789/reinstall/-/git/raw/main
- When installing the latest version, the version number does not need to be specified.
- Maximizes disk space usage: no boot partition (except for Fedora) and no swap partition.
- Automatically selects different optimized kernels based on machine type, such as `Cloud` or `HWE` kernels.
- When installing Red Hat, you must provide the `qcow2` image link obtained from <https://access.redhat.com/downloads/content/rhel>. You can also install other RHEL-based OS, such as `Alibaba Cloud Linux` and `TencentOS Server`.
- When installing Red Hat, you must provide the `qcow2` image link obtained from <https://access.redhat.com/downloads/content/rhel>. You can also install `qcow2` of other RHEL-based OS, such as `Alibaba Cloud Linux` and `TencentOS Server`.
- After reinstallation, if you need to change the SSH port or switch to key-based login, make sure to also modify the files inside `/etc/ssh/sshd_config.d/`.
```bash
@ -258,7 +259,7 @@ bash reinstall.sh dd --img "https://example.com/xxx.xz"
>
> Or Run `/trans.sh alpine` to automatically recover to Alpine Linux.
### Feature 3: Reboot to <img width="16" height="16" src="https://www.alpinelinux.org/alpine-logo.ico" /> Alpine Live OS (RAM OS)
### Feature 3: Reboot to <img width="16" height="16" src="https://www.alpinelinux.org/alpine-logo.ico" /> Alpine Live OS
- You can use SSH to backup/restore disk, manually perform DD operations, partition modifications, manual Alpine installation, and other operations.
- Username `root`. The script prompts for a password. If left blank, a random one is generated.
@ -266,7 +267,7 @@ bash reinstall.sh dd --img "https://example.com/xxx.xz"
> [!TIP]
>
> Although the script being run is `reinstall`, this feature **does not** delete any data or perform an automatic reinstallation; manual user operation is required.
>
> If the user does not damage the original system during manual operation, rebooting will return to the original system.
```bash
@ -287,7 +288,7 @@ bash reinstall.sh alpine --hold 1
> [!TIP]
>
> Although the script being run is `reinstall`, this feature **does not** delete any data or perform an automatic reinstallation; manual user operation is required.
>
> If the user does not damage the original system during manual operation, rebooting will return to the original system.
```bash

View File

@ -4,7 +4,8 @@
[![Codacy](https://img.shields.io/codacy/grade/dc679a17751448628fe6d8ac35e26eed?logo=Codacy&label=Codacy&style=flat-square)](https://app.codacy.com/gh/bin456789/reinstall/dashboard)
[![CodeFactor](https://img.shields.io/codefactor/grade/github/bin456789/reinstall?logo=CodeFactor&logoColor=white&label=CodeFactor&style=flat-square)](https://www.codefactor.io/repository/github/bin456789/reinstall)
[![Lines of Code](https://tokei.rs/b1/github/bin456789/reinstall?category=code&label=Lines%20of%20Code&style=flat-square)](https://github.com/XAMPPRocky/tokei_rs)
[![Lines of Code](https://aschey.tech/tokei/github/bin456789/reinstall?category=code&label=Lines%20of%20Code&style=flat-square)](https://github.com/aschey/vercel-tokei)
<!-- [![Lines of Code](https://tokei.rs/b1/github/bin456789/reinstall?category=code&label=Lines%20of%20Code&style=flat-square)](https://github.com/XAMPPRocky/tokei_rs) -->
一键 VPS 系统重装脚本 [English](README.en.md)
@ -149,7 +150,7 @@ certutil -urlcache -f -split https://cnb.cool/bin456789/reinstall/-/git/raw/main
- 安装最新版可不输入版本号
- 最大化利用磁盘空间:不含 boot 分区Fedora 例外),不含 swap 分区
- 自动根据机器类型选择不同的优化内核,例如 `Cloud``HWE` 内核
- 安装 Red Hat 时需填写 <https://access.redhat.com/downloads/content/rhel> 得到的 `qcow2` 镜像链接,也可以安装其它类 RHEL 系统,例如 `Alibaba Cloud Linux``TencentOS Server`
- 安装 Red Hat 时需填写 <https://access.redhat.com/downloads/content/rhel> 得到的 `qcow2` 镜像链接,也可以安装其它类 RHEL 系统`qcow2`,例如 `Alibaba Cloud Linux``TencentOS Server`
- 重装后如需修改 SSH 端口或者改成密钥登录,注意还要修改 `/etc/ssh/sshd_config.d/` 里面的文件
```bash

View File

@ -48,20 +48,39 @@ retry() {
# 用 systemd-analyze plot >a.svg 发现 sys-subsystem-net-devices-enp3s0.device 也是出现在 NetworkManager 之后
# 因此需要等待网卡出现
get_ethx_by_mac() {
mac=$(echo "$1" | to_lower)
retry 10 _get_ethx_by_mac "$mac"
retry 10 _get_ethx_by_mac "$@"
}
_get_ethx_by_mac() {
mac=$(echo "$1" | to_lower)
flag=$2
if [ -z "$flag" ]; then
flag=master
fi
if true; then
# 过滤 azure vf (带 master ethx)
ip -o link | grep -i "$mac" | grep -v master | awk '{print $2}' | cut -d: -f1 | grep .
return
if [ "$flag" = master ]; then
# master
# 过滤 azure vf (带 master ethx)
ip -o link | grep -i "$mac" | grep -v master | awk '{print $2}' | cut -d: -f1 | grep .
else
# slave
# 带 master ethx
ip -o link | grep -i "$mac" | grep -w master | awk '{print $2}' | cut -d: -f1 | grep .
fi
else
for i in $(cd /sys/class/net && echo *); do
if [ "$(cat "/sys/class/net/$i/address")" = "$mac" ]; then
echo "$i"
return
if [ $(($(cat "/sys/class/net/$i/flags") & 0x800)) -ne 0 ]; then
fact_flag=slave
else
fact_flag=master
fi
if [ "$flag" = "$fact_flag" ]; then
echo "$i"
return
fi
fi
done
return 1
@ -138,6 +157,23 @@ fix_network_manager() {
# 更改文件名
mv "$file" "$proper_file"
# NM 不会自动忽略 Azure 的 slave 网卡,需手动设置
# azure 文档中的方法不够通用,只适合 azure
# https://learn.microsoft.com/zh-cn/azure/virtual-network/accelerated-networking-overview
# 我们采用红帽的方法
# https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/8/html/configuring_and_managing_networking/configuring-networkmanager-to-ignore-certain-devices_configuring-and-managing-networking
if slave_ethx=$(get_ethx_by_mac "$mac" slave); then
cat >"/etc/NetworkManager/conf.d/99-$slave_ethx-unmanaged.conf" <<EOF
[device-$slave_ethx-unmanaged]
match-device=interface-name:$slave_ethx
managed=0
EOF
fi
# 也可以设置 unmanaged-devices, 但是官方文档不推荐
# https://networkmanager.pages.freedesktop.org/NetworkManager/NetworkManager/NetworkManager.conf.html#:~:text=may%20be%20a-,better%20choice,-.
done
}

View File

@ -60,6 +60,7 @@ get_frpc_url() {
mirror=$(
# nju 没有 win7 用的旧版
# github 不支持 ipv6
# daocloud 加速不支持 ipv6
# jsdelivr 不支持 github releases 文件
if is_ipv6_only; then
if is_need_old_version; then
@ -71,7 +72,7 @@ get_frpc_url() {
else
if is_in_china; then
if is_need_old_version; then
echo https://github.com/fatedier/frp/releases/download
echo https://files.m.daocloud.io/github.com/fatedier/frp/releases/download
else
echo https://mirrors.nju.edu.cn/github-release/fatedier/frp
fi

View File

@ -345,14 +345,14 @@ EOF
db_progress INFO netcfg/link_detect_progress
else
# alpine
# h3c 移动云电脑使用 udhcpc 会重复提示 sending select无法获得 ipv6
# h3c 移动云电脑使用 udhcpc 会重复提示 sending select因此添加 timeout 强制结束进程
# dhcpcd 会配置租约时间,过期会移除 IP但我们的没有在后台运行 dhcpcd ,因此用 udhcpc
method=udhcpc
case "$method" in
udhcpc)
udhcpc -i "$ethx" -f -q -n || true
udhcpc6 -i "$ethx" -f -q -n || true
timeout $DHCP_TIMEOUT udhcpc -i "$ethx" -f -q -n || true
timeout $DHCP_TIMEOUT udhcpc6 -i "$ethx" -f -q -n || true
sleep $DNS_FILE_TIMEOUT # 好像不用等待写入 dns但是以防万一
;;
dhcpcd)

View File

@ -131,6 +131,13 @@ call :check_cygwin_installed || (
set dir=/sourceware/cygwin
)
rem daocloud 加速有 90 天缓存,且不支持 IPv6
rem https://github.com/DaoCloud/public-binary-files-mirror
rem 无法用查询字符串强制刷新缓存
rem https://files.m.daocloud.io/www.cloudflare.com/cdn-cgi/trace?a=1
rem https://files.m.daocloud.io/www.cloudflare.com/cdn-cgi/trace?b=2
rem 也就无法用 https://www.cygwin.com/setup-x86_64.exe?xxx=20250101 强制每天刷新缓存
rem 下载 Cygwin
if not exist setup-!CygwinArch!.exe (
call :download http://www.cygwin.com/setup-!CygwinArch!.exe %~dp0setup-!CygwinArch!.exe || goto :download_failed
@ -195,7 +202,7 @@ rem bitsadmin /transfer "%~3" /priority foreground %~1 %~2
:download
rem certutil 会被 windows Defender 报毒
rem windows server 2019 要用第二条 certutil 命令
echo Download: %~1 %~2
echo Downloading: %~1 %~2
del /q "%~2" 2>nul
if exist "%~2" (echo Cannot delete %~2 & exit /b 1)

View File

@ -1086,7 +1086,10 @@ get_windows_iso_link() {
if [ -n "$label_msdl" ]; then
iso=$(curl -L "$page_url" | grep -ioP 'https://[^ ]+?#[0-9]+' | head -1 | grep .)
else
curl -L "$page_url" | grep -ioP 'https://[^ ]+?.(iso|img)' >$tmp/win.list
curl -L "$page_url" |
tr -d '\n' | sed -e 's,<a ,\n<a ,g' -e 's,</a>,</a>\n,g' | # 使每个 <a></a> 占一行
grep -Ei '\.(iso|img)</a>$' | # 找出是 iso 或 img 的行
sed -E 's,<a href="?([^" ]+)"?.+>(.+)</a>,\2 \1,' >$tmp/win.list # 提取文件名和链接
# 如果不是 ltsc ,应该先去除 ltsc 链接,否则最终链接有 ltsc 的
# 例如查找 windows 10 iot enterprise会得到
@ -1104,10 +1107,14 @@ get_windows_iso_link() {
}
get_shortest_line() {
# awk '{print length($0), $0}' | sort -n | head -1 | awk '{print $2}'
awk '(NR == 1 || length($0) < length(shortest)) { shortest = $0 } END { print shortest }'
}
get_shortest_line_by_field() {
local field=$1
awk "(NR == 1 || length(\$$field) < length(field)) { line = \$0; field = \$$field } END { print line }"
}
get_windows_iso_link_inner() {
regexs=()
@ -1139,7 +1146,9 @@ get_windows_iso_link_inner() {
regex=${regex// /_}
echo "looking for: $regex" >&2
if iso=$(grep -Ei "/$regex" "$tmp/win.list" | get_shortest_line | grep .); then
if line=$(grep -Ei "^$regex " "$tmp/win.list" | get_shortest_line_by_field 1 | grep .) &&
iso=$(awk '{print $2}' <<<"$line" | grep .); then
echo "Selected: $line" >&2
return
fi
done
@ -1512,7 +1521,9 @@ Continue?
}
setos_windows() {
auto_find_iso=false
if [ -z "$iso" ]; then
auto_find_iso=true
# 查找时将 windows longhorn serverdatacenter 改成 windows server 2008 serverdatacenter
image_name=${image_name/windows longhorn server/windows server 2008 server}
echo "iso url is not set. Attempting to find it automatically."
@ -1527,27 +1538,32 @@ Continue?
if [[ "$iso" = magnet:* ]]; then
: # 不测试磁力链接
else
# 需要用户输入 massgrave.dev 直链
if grep -Eiq '\.massgrave\.dev/.*\.(iso|img)$' <<<"$iso" ||
grep -Eiq '\.gravesoft\.dev/#[0-9]+$' <<<"$iso"; then
info "Set Direct link"
# MobaXterm 不支持
# printf '\e]8;;http://example.com\e\\This is a link\e]8;;\e\\\n'
iso_is_tested=false
if $auto_find_iso; then
if test_url_grace "$iso" iso 2>/dev/null; then
iso_is_tested=true
else
# 需要用户输入 massgrave.dev 直链
info "Set Direct link"
# MobaXterm 不支持
# printf '\e]8;;http://example.com\e\\This is a link\e]8;;\e\\\n'
# MobaXterm 不显示为超链接
# info false "请在浏览器中打开 $iso 获取直链并粘贴到这里。"
# info false "Please open $iso in browser to get the direct link and paste it here."
# MobaXterm 不显示为超链接
# info false "请在浏览器中打开 $iso 获取直链并粘贴到这里。"
# info false "Please open $iso in browser to get the direct link and paste it here."
echo "请在浏览器中打开 $iso 获取直链并粘贴到这里。"
echo "Please open $iso in browser to get the direct link and paste it here."
IFS= read -r -p "Direct Link: " iso
if [ -z "$iso" ]; then
error_and_exit "ISO Link is empty."
echo "请在浏览器中打开 $iso 获取直链并粘贴到这里。"
echo "Please open $iso in browser to get the direct link and paste it here."
IFS= read -r -p "Direct Link: " iso
if [ -z "$iso" ]; then
error_and_exit "ISO Link is empty."
fi
fi
fi
# 测试是否是 iso
test_url "$iso" iso
if ! $iso_is_tested; then
test_url "$iso" iso
fi
# 判断 iso 架构是否兼容
# https://gitlab.com/libosinfo/osinfo-db/-/tree/main/data/os/microsoft.com?ref_type=heads
@ -1622,15 +1638,13 @@ Continue with DD?
}
setos_fnos() {
if [ "$basearch" = aarch64 ]; then
error_and_exit "FNOS not supports ARM."
fi
# 系统盘大小
min=8
default=8
echo "请输入系统分区大小,最小 $min GB但可能无法更新系统。"
echo "Please input System Partition Size. Minimal is $min GB but may not be able to do system updates."
while true; do
IFS= read -r -p "Type System Partition Size in GB. Minimal $min GB. [$default]: " input
IFS= read -r -p "Size in GB [$default]: " input
input=${input:-$default}
if ! { is_digit "$input" && [ "$input" -ge "$min" ]; }; then
error "Invalid Size. Please Try again."
@ -1640,16 +1654,25 @@ Continue with DD?
fi
done
iso=$(curl -L https://fnnas.com/ | grep -o 'https://[^"]*\.iso' | head -1 | grep .)
if [ "$basearch" = aarch64 ]; then
if [ -z "$iso" ]; then
IFS= read -r -p "ISO Link: " iso
if [ -z "$iso" ]; then
error_and_exit "ISO Link is empty."
fi
fi
else
iso=$(curl -L https://fnnas.com/ | grep -o -m1 'https://[^"]*\.iso')
# curl 7.82.0+
# curl -L --json '{"url":"'$iso'"}' https://www.fnnas.com/api/download-sign
# curl 7.82.0+
# curl -L --json '{"url":"'$iso'"}' https://www.fnnas.com/api/download-sign
iso=$(curl -L \
-d '{"url":"'$iso'"}' \
-H 'Content-Type: application/json' \
https://www.fnnas.com/api/download-sign |
grep -o 'https://[^"]*')
iso=$(curl -L \
-d '{"url":"'$iso'"}' \
-H 'Content-Type: application/json' \
https://www.fnnas.com/api/download-sign |
grep -o 'https://[^"]*')
fi
test_url "$iso" iso
eval "${step}_iso='$iso'"

271
trans.sh
View File

@ -414,22 +414,30 @@ extract_env_from_cmdline() {
}
ensure_service_started() {
service=$1
local service=$1
if ! rc-service -q $service status; then
if ! retry 5 rc-service -q $service start; then
error_and_exit "Failed to start $service."
fi
if ! rc-service -q "$service" start; then
for i in $(seq 10); do
if [ "$service" = modloop ]; then
# 避免有时 modloop 下载不完整导致报错
# * Failed to verify signature of !
# mount: mounting /dev/loop0 on /.modloop failed: Invalid argument
rm -f /lib/modloop-lts /lib/modloop-virt
fi
if rc-service -q "$service" start; then
return
fi
sleep 5
done
error_and_exit "Failed to start $service."
fi
}
ensure_service_stopped() {
service=$1
local service=$1
if rc-service -q $service status; then
if ! retry 5 rc-service -q $service stop; then
error_and_exit "Failed to stop $service."
fi
if ! retry 10 5 rc-service -q "$service" stop; then
error_and_exit "Failed to stop $service."
fi
}
@ -2431,7 +2439,7 @@ get_disk_logic_sector_size() {
}
is_4kn() {
[ "$(blockdev --getss "$1")" = 4096 ]
[ "$(blockdev --getss "/dev/$xda")" = 4096 ]
}
is_xda_gt_2t() {
@ -2523,15 +2531,18 @@ create_part() {
sector_size=$(get_disk_logic_sector_size /dev/$xda)
total_sector_count=$(get_disk_sector_count /dev/$xda)
# 截止最后一个分区的总扇区数(也就是总硬盘扇区数 - 备份分区表扇区数)
if is_efi; then
total_sector_count_except_backup_gpt=$((total_sector_count - 33))
else
# 截止最后一个分区的总扇区数(也就是总硬盘扇区数 - 备份分区表扇区数 - 备份 GPT Header
if ! is_efi && ! is_xda_gt_2t; then
# mbr
total_sector_count_except_backup_gpt=$total_sector_count
elif is_4kn; then
total_sector_count_except_backup_gpt=$((total_sector_count - 4 - 1))
else
total_sector_count_except_backup_gpt=$((total_sector_count - 32 - 1))
fi
# 向下取整 MiB
# gpt 最后 33 个扇区是备份分区表,不可用
# gpt 最后 33 (512n/512e) 或 5 (4Kn) 个扇区是备份分区表,不可用
# parted 结束位置填 100% 时也会忽略最后不足 1MiB 的部分,我们模仿它
max_can_use_m=$((total_sector_count_except_backup_gpt * sector_size / 1024 / 1024))
@ -2560,9 +2571,20 @@ create_part() {
mkfs.fat /dev/$xda*1 #1 efi
mkfs.ext4 -F $ext4_opts /dev/$xda*2 #2 os + installer
elif is_xda_gt_2t; then
# bios > 2t
# 官方安装器是 mkpart BOOT 1M 100M无论 esp 或者 bios_grub 都用这个分区和大小
parted /dev/$xda -s -- \
mklabel gpt \
mkpart BOOT ext4 1MiB 101MiB \
mkpart SYSTEM ext4 101MiB $os_part_end \
set 1 bios_grub on
update_part
echo #1 bios_boot
mkfs.ext4 -F $ext4_opts /dev/$xda*2 #2 os + installer
else
# bios
# 官方安装器不支持 bios + >2t
parted /dev/$xda -s -- \
mklabel msdos \
mkpart primary 1MiB 101MiB \
@ -3226,52 +3248,60 @@ chroot_systemctl_disable() {
done
}
remove_cloud_init() {
remove_or_disable_cloud_init() {
os_dir=$1
if ! is_have_cmd_on_disk $os_dir cloud-init; then
return
fi
info "Remove Cloud-Init"
info "Remove or Disable Cloud-Init"
# 两种方法都可以
if false && [ -d $os_dir/etc/cloud ]; then
# ubuntu-server-minimal ubuntu-cloud-minimal 都包含 cloud-init
# 用 iso 安装的 ubuntu 也有 cloud-init
# 因此不删除 ubuntu 的 cloud-init而是禁用它
# iso 安装首次启动是通过 /etc/cloud/cloud.cfg.d/99-installer.cfg 初始化系统,包括:
# 1. 创建普通用户和密码,添加 ssh 登录公钥
# 2. 创建 /etc/cloud/cloud-init.disabled
if grep -iq ubuntu $os_dir/etc/os-release; then
# 模仿 iso 安装的 ubuntu只创建 cloud-init.disabled不禁用服务
touch $os_dir/etc/cloud/cloud-init.disabled
else
# systemctl is-enabled cloud-init-hotplugd.service 状态是 static
# disable 会出现一堆提示信息,也无法 disable
for unit in $(
chroot $os_dir systemctl list-unit-files |
grep -E '^(cloud-init|cloud-init-.*|cloud-config|cloud-final)\.(service|socket)' | grep enabled | awk '{print $1}'
); do
# 服务不存在时会报错
if chroot $os_dir systemctl -q is-enabled "$unit"; then
chroot $os_dir systemctl disable "$unit"
fi
done
for pkg_mgr in dnf yum zypper apt-get; do
if is_have_cmd_on_disk $os_dir $pkg_mgr; then
case $pkg_mgr in
dnf | yum)
chroot $os_dir $pkg_mgr remove -y cloud-init
rm -f $os_dir/etc/cloud/cloud.cfg.rpmsave
;;
zypper)
# 加上 -u 才会删除依赖
chroot $os_dir zypper remove -y -u cloud-init cloud-init-config-suse
;;
apt-get)
# ubuntu 25.04 开始有 cloud-init-base
chroot_apt_remove $os_dir cloud-init cloud-init-base
chroot_apt_autoremove $os_dir
;;
esac
break
fi
done
fi
# systemctl is-enabled cloud-init-hotplugd.service 状态是 static
# disable 会出现一堆提示信息,也无法 disable
for unit in $(
chroot $os_dir systemctl list-unit-files |
grep -E '^(cloud-init|cloud-init-.*|cloud-config|cloud-final)\.(service|socket)' | grep enabled | awk '{print $1}'
); do
# 服务不存在时会报错
if chroot $os_dir systemctl -q is-enabled "$unit"; then
chroot $os_dir systemctl disable "$unit"
fi
done
for pkg_mgr in dnf yum zypper apt-get; do
if is_have_cmd_on_disk $os_dir $pkg_mgr; then
case $pkg_mgr in
dnf | yum)
chroot $os_dir $pkg_mgr remove -y cloud-init
rm -f $os_dir/etc/cloud/cloud.cfg.rpmsave
;;
zypper)
# 加上 -u 才会删除依赖
chroot $os_dir zypper remove -y -u cloud-init cloud-init-config-suse
;;
apt-get)
# ubuntu 25.04 开始有 cloud-init-base
chroot_apt_remove $os_dir cloud-init cloud-init-base
chroot_apt_autoremove $os_dir
;;
esac
break
fi
done
}
disable_jeos_firstboot() {
@ -3387,7 +3417,7 @@ EOF
if [ "$distro" = fedora ] && [ "$releasever" = 43 ]; then
chroot $os_dir dnf mark user netcat -y
fi
remove_cloud_init $os_dir
remove_or_disable_cloud_init $os_dir
disable_selinux $os_dir
disable_kdump $os_dir
@ -3414,7 +3444,7 @@ EOF
find_and_mount /boot
find_and_mount /boot/efi
remove_cloud_init $os_dir
remove_or_disable_cloud_init $os_dir
# 获取当前开启的 Components, 后面要用
if [ -f $os_dir/etc/apt/sources.list.d/debian.sources ]; then
@ -3466,10 +3496,8 @@ EOF
! sh /can_use_cloud_kernel.sh "$xda" $(get_eths); then
kernel_package=$(echo "$kernel_package" | sed 's/-cloud//')
fi
# 如果镜像自带内核跟最佳内核是同一种且有更新
# 则 apt install 只会进行更新,不会将包设置成 manual
# 需要再运行 apt install 才会将包设置成 manual
chroot_apt_install $os_dir "$kernel_package"
# 该方法包含了 apt-mark manual
chroot_apt_install $os_dir "$kernel_package"
# 使用 autoremove 删除非最佳内核
@ -3689,7 +3717,7 @@ EOF
# 最后才删除 cloud-init
# 因为生成 sysconfig 网络配置要用目标系统的 cloud-init
remove_cloud_init $os_dir
remove_or_disable_cloud_init $os_dir
restore_resolv_conf $os_dir
fi
@ -4170,7 +4198,7 @@ chroot_dnf() {
}
chroot_apt_update() {
os_dir=$1
local os_dir=$1
current_hash=$(cat $os_dir/etc/apt/sources.list $os_dir/etc/apt/sources.list.d/*.sources 2>/dev/null | md5sum)
if ! [ "$saved_hash" = "$current_hash" ]; then
@ -4180,15 +4208,30 @@ chroot_apt_update() {
}
chroot_apt_install() {
os_dir=$1
local os_dir=$1
shift
chroot_apt_update $os_dir
DEBIAN_FRONTEND=noninteractive chroot $os_dir apt-get install -y "$@"
# 只安装未安装的软件包
# 避免更新浪费时间
local pkg='' pkgs=''
for pkg in "$@"; do
if chroot $os_dir dpkg -s "$pkg" >/dev/null 2>&1; then
# 如果已安装则标记为 manual防止被 autoremove 删除
chroot $os_dir apt-mark manual "$pkg"
else
pkgs="$pkgs $pkg"
fi
done
# 一次性安装,避免多次 update-initramfs
if [ -n "$pkgs" ]; then
chroot_apt_update $os_dir
DEBIAN_FRONTEND=noninteractive chroot $os_dir apt-get install -y $pkgs
fi
}
chroot_apt_remove() {
os_dir=$1
local os_dir=$1
shift
# minimal 镜像 删除 grub-pc 时会安装 grub-efi-amd64
@ -4211,7 +4254,7 @@ chroot_apt_remove() {
}
chroot_apt_autoremove() {
os_dir=$1
local os_dir=$1
change_confs() {
action=$1
@ -4302,7 +4345,14 @@ install_fnos() {
mkdir -p $initrd_dir
(
cd $initrd_dir
zcat /iso/install.amd/initrd.gz | cpio -idm
suffix=$(
case $(uname -m) in
x86_64) echo amd ;;
aarch64) echo a64 ;;
*) ;;
esac
)
zcat /iso/install.$suffix/initrd.gz | cpio -idm
)
apk del cpio
@ -4338,9 +4388,6 @@ install_fnos() {
# 挂载 proc sys dev
mount_pseudo_fs /os
# 更新 initrd
# chroot $os_dir update-initramfs -u
# 更改密码
if is_need_set_ssh_keys; then
set_ssh_keys_and_del_password $os_dir
@ -4354,6 +4401,31 @@ install_fnos() {
chroot $os_dir systemctl enable ssh
fi
# fstab
{
# /
uuid=$(lsblk /dev/$xda*2 -no UUID)
echo "$fstab_line_os" | sed "s/%s/$uuid/"
# swapfile
# 官方安装器即使 swapfile 设为 0 也会有这行
echo "$fstab_line_swapfile"
# /boot/efi
if is_efi; then
uuid=$(lsblk /dev/$xda*1 -no UUID)
echo "$fstab_line_efi" | sed "s/%s/$uuid/"
fi
} >$os_dir/etc/fstab
# 更新 initrd官方安装器也有这一步
# 理论上 /var/tmp 要设置 1777 权限,但飞牛官方安装器安装后不是
# 需要先创建 /etc/fstab ,否则会有以下警告
# W: Couldn't identify type of root file system for fsck hook
mkdir -p $os_dir/var/tmp
chmod 1777 $os_dir/var/tmp
chroot $os_dir update-initramfs -u
# grub
if is_efi; then
chroot $os_dir grub-install --efi-directory=/boot/efi
@ -4362,28 +4434,16 @@ install_fnos() {
chroot $os_dir grub-install /dev/$xda
fi
# grub 配置
# 取自 strings trim-install | grep GRUB_DISTRIBUTOR
sed -i 's/^GRUB_DISTRIBUTOR=.*/GRUB_DISTRIBUTOR="FNOS"/' $os_dir/etc/default/grub
# grub tty
ttys_cmdline=$(get_ttys console=)
echo GRUB_CMDLINE_LINUX=\"\$GRUB_CMDLINE_LINUX $ttys_cmdline\" \
>>$os_dir/etc/default/grub.d/tty.cfg
echo GRUB_CMDLINE_LINUX=\"\$GRUB_CMDLINE_LINUX $ttys_cmdline\" >$os_dir/etc/default/grub.d/tty.cfg
chroot $os_dir update-grub
# fstab
{
# /
uuid=$(lsblk /dev/$xda*2 -no UUID)
echo "$fstab_line_os" | sed "s/%s/$uuid/"
# 官方安装器即使 swapfile 设为 0 也会有这行
echo "$fstab_line_swapfile" | sed "s/%s/$uuid/"
# /boot/efi
if is_efi; then
uuid=$(lsblk /dev/$xda*1 -no UUID)
echo "$fstab_line_efi" | sed "s/%s/$uuid/"
fi
} >$os_dir/etc/fstab
# 网卡配置
create_cloud_init_network_config /net.cfg
create_network_manager_config /net.cfg $os_dir
@ -4743,10 +4803,13 @@ EOF
# 安装最佳内核
flavor=$(get_ubuntu_kernel_flavor)
echo "Use kernel flavor: $flavor"
# 如果镜像自带内核跟最佳内核是同一种且有更新
# 则 apt install 只会进行更新,不会将包设置成 manual
# 需要再运行 apt install 才会将包设置成 manual
chroot_apt_install $os_dir "linux-image-$flavor"
# 题外话
# 如果某个包是 auto 状态且有更新
# 则 apt install PKG 只会进行更新,不会将包设置成 manual
# 需要再次运行 apt install PKG 才会将包设置成 manual
# 该方法包含了 apt-mark manual
chroot_apt_install $os_dir "linux-image-$flavor"
# 使用 autoremove 删除多余内核
@ -5082,7 +5145,7 @@ EOF
# 最后才删除 cloud-init
# 因为生成 netplan/sysconfig 网络配置要用目标系统的 cloud-init
remove_cloud_init /os
remove_or_disable_cloud_init /os
# 删除 swapfile
swapoff -a
@ -5548,12 +5611,6 @@ is_list_has() {
echo "$list" | grep -qFx "$item"
}
# hivexget 是 shell 脚本,开头是 #!/bin/bash
# 但 alpine 没安装 bash直接运行 hivexget 会报错
hivexget() {
ash "$(which hivexget)" "$@"
}
get_windows_type_from_windows_drive() {
local os_dir=$1
@ -6007,8 +6064,18 @@ install_windows() {
echo https://downloadmirror.intel.com/849483/Wired_driver_30.0.1_${arch_intel}.zip
;;
x64)
id=$(
case "$product_ver" in
10) echo 18293 ;;
11) echo 727998 ;;
2016) echo 18737 ;;
2019) echo 19372 ;;
2022) echo 706171 ;;
2025) echo 838943 ;;
esac
)
# intel 禁止了 wget 下载网页
wget -U curl/7.54.1 https://www.intel.com/content/www/us/en/download/727998.html -O- |
wget -U curl/7.54.1 https://www.intel.com/content/www/us/en/download/$id.html -O- |
grep -Eio -m1 "\"https://.+/(Wired_driver|prowin).*${arch_intel}(legacy)?\.(zip|exe)\"" | tr -d '"' | grep .
;;
esac ;;
@ -6794,7 +6861,7 @@ EOF
# 4kn EFI 分区最少要 260M
# https://learn.microsoft.com/windows-hardware/manufacture/desktop/hard-drives-and-partitions
if is_4kn /dev/$xda; then
if is_4kn; then
sed -i 's/is4kn=0/is4kn=1/i' $startnet_cmd
fi