2023-06-07 21:42:25 +08:00
#!/bin/ash
#
# Alpine Linux use "ash" as the default shell.
exec >/dev/tty0 2>& 1
# Delete the initial script itself to prevent to be executed in the new system.
2023-06-07 21:43:38 +08:00
rm -f /etc/local.d/ubuntuConf.start
2023-06-07 21:42:25 +08:00
rm -f /etc/runlevels/default/local
2023-06-10 02:15:43 +08:00
# Install necessary components.
apk update
2023-09-30 03:55:24 +08:00
apk add coreutils grep sed
2023-06-10 02:15:43 +08:00
2023-06-07 21:42:25 +08:00
# Get Ubuntu Linux configurations.
2023-09-30 05:17:21 +08:00
confFile = '/root/alpine.config'
cloudInitFile = '/mnt/etc/cloud/cloud.cfg.d/99-fake_cloud.cfg'
2023-06-07 21:42:25 +08:00
# Read configs from initial file.
2023-06-10 01:23:12 +08:00
IncDisk = $( grep "IncDisk" $confFile | awk '{print $2}' )
2023-06-10 02:28:16 +08:00
LinuxMirror = $( grep -w "LinuxMirror" $confFile | awk '{print $2}' )
2023-06-10 00:58:51 +08:00
alpineVer = $( grep "alpineVer" $confFile | awk '{print $2}' )
2023-06-14 03:57:43 +08:00
TimeZone1 = $( grep "TimeZone" $confFile | awk '{print $2}' | cut -d'/' -f 1)
TimeZone2 = $( grep "TimeZone" $confFile | awk '{print $2}' | cut -d'/' -f 2)
2023-06-12 15:33:00 +08:00
tmpWORD = $( grep -w "tmpWORD" $confFile | awk '{print $2}' )
2023-06-07 21:42:25 +08:00
sshPORT = $( grep "sshPORT" $confFile | awk '{print $2}' )
2023-08-23 17:24:36 +08:00
networkAdapter = $( grep "networkAdapter" $confFile | awk '{print $2}' )
2023-06-07 21:42:25 +08:00
IPv4 = $( grep "IPv4" $confFile | awk '{print $2}' )
MASK = $( grep "MASK" $confFile | awk '{print $2}' )
2023-06-08 04:48:56 +08:00
ipPrefix = $( grep "ipPrefix" $confFile | awk '{print $2}' )
2023-07-01 22:26:15 +08:00
actualIp4Prefix = $( grep "actualIp4Prefix" $confFile | awk '{print $2}' )
2023-06-08 04:56:03 +08:00
GATE = $( grep "GATE" $confFile | awk '{print $2}' )
2023-06-08 04:30:59 +08:00
ipDNS1 = $( grep "ipDNS1" $confFile | awk '{print $2}' )
ipDNS2 = $( grep "ipDNS2" $confFile | awk '{print $2}' )
2023-09-18 17:14:15 +08:00
iAddrNum = $( grep "iAddrNum" $confFile | awk '{print $2}' )
writeIpsCmd = $( grep "writeIpsCmd" $confFile | awk '{print $2}' )
2023-06-07 21:42:25 +08:00
ip6Addr = $( grep "ip6Addr" $confFile | awk '{print $2}' )
ip6Mask = $( grep "ip6Mask" $confFile | awk '{print $2}' )
2023-07-01 22:26:15 +08:00
actualIp6Prefix = $( grep "actualIp6Prefix" $confFile | awk '{print $2}' )
2023-06-07 21:42:25 +08:00
ip6Gate = $( grep "ip6Gate" $confFile | awk '{print $2}' )
2023-06-08 04:30:59 +08:00
ip6DNS1 = $( grep "ip6DNS1" $confFile | awk '{print $2}' )
ip6DNS2 = $( grep "ip6DNS2" $confFile | awk '{print $2}' )
2023-09-18 17:34:33 +08:00
i6AddrNum = $( grep "i6AddrNum" $confFile | awk '{print $2}' )
writeIp6sCmd = $( grep "writeIp6sCmd" $confFile | awk '{print $2}' )
2023-06-16 07:06:25 +08:00
setIPv6 = $( grep "setIPv6" $confFile | awk '{print $2}' )
2023-06-07 21:42:25 +08:00
HostName = $( grep "HostName" $confFile | awk '{print $2}' )
2023-06-07 23:31:30 +08:00
DDURL = $( grep "DDURL" $confFile | awk '{print $2}' )
2023-09-23 16:04:33 +08:00
DEC_CMD = $( grep "DEC_CMD" $confFile | awk '{print $2}' )
2023-06-08 04:35:18 +08:00
targetLinuxMirror = $( grep "targetLinuxMirror" $confFile | awk '{print $2}' )
2023-10-02 06:38:16 +08:00
targetLinuxSecurityMirror = $( grep "targetLinuxSecurityMirror" $confFile | awk '{print $2}' )
2023-06-08 04:35:18 +08:00
cloudInitUrl = $( grep "cloudInitUrl" $confFile | awk '{print $2}' )
2023-09-17 13:03:07 +08:00
setFail2banStatus = $( grep "setFail2banStatus" $confFile | awk '{print $2}' )
2023-06-07 21:42:25 +08:00
2023-10-01 01:01:31 +08:00
# Reset configurations of repositories.
2023-06-07 21:42:25 +08:00
true >/etc/apk/repositories
2023-06-10 00:58:51 +08:00
setup-apkrepos $LinuxMirror /$alpineVer /main
2023-06-07 21:42:25 +08:00
setup-apkcache /var/cache/apk
2023-10-01 01:01:31 +08:00
# Add community mirror.
2023-06-10 00:58:51 +08:00
sed -i '$a\' $LinuxMirror '/' $alpineVer '/community' /etc/apk/repositories
2023-06-07 21:42:25 +08:00
# Add edge testing to the repositories
2023-10-08 00:46:29 +08:00
# sed -i '$a\'$LinuxMirror'/edge/testing' /etc/apk/repositories
2023-06-07 21:42:25 +08:00
2023-10-01 01:01:31 +08:00
# Synchronize time from hardware.
2023-06-10 02:15:43 +08:00
hwclock -s
2023-06-07 21:42:25 +08:00
# Install necessary components.
apk update
2023-10-08 00:46:29 +08:00
apk add hdparm multipath-tools util-linux wget xz
2023-06-07 21:42:25 +08:00
2023-09-30 05:17:21 +08:00
# Start dd.
2023-10-08 00:46:29 +08:00
wget --no-check-certificate --report-speed= bits --tries= 0 --timeout= 10 --wait= 5 -O- " $DDURL " | $DEC_CMD | dd of = " $IncDisk " status = progress
2023-06-07 21:42:25 +08:00
2023-09-30 05:17:21 +08:00
# Get a valid loop device.
2023-06-07 21:42:25 +08:00
loopDevice = $( echo $( losetup -f) )
loopDeviceNum = $( echo $( losetup -f) | cut -d'/' -f 3)
2023-09-30 05:17:21 +08:00
# Make a soft link between valid loop device and disk.
2023-06-10 01:23:12 +08:00
losetup $loopDevice $IncDisk
2023-06-07 21:42:25 +08:00
2023-09-30 05:17:21 +08:00
# Get mapper partition.
2023-10-07 07:38:45 +08:00
mapperDevice = $( kpartx -av $loopDevice | grep " $loopDeviceNum " | head -n 1 | awk '{print $3}' )
2023-06-07 21:42:25 +08:00
2023-10-01 01:01:31 +08:00
# Mount Ubuntu dd partition to /mnt .
2023-06-07 21:42:25 +08:00
mount /dev/mapper/$mapperDevice /mnt
2023-09-30 05:17:21 +08:00
# Download cloud init file.
2023-10-08 00:46:29 +08:00
wget --no-check-certificate -qO $cloudInitFile '' $cloudInitUrl ''
2023-06-07 21:42:25 +08:00
2023-09-30 05:17:21 +08:00
# User config.
sed -ri 's/HostName/' ${ HostName } '/g' $cloudInitFile
sed -ri 's/tmpWORD/' ${ tmpWORD } '/g' $cloudInitFile
sed -ri 's/TimeZone/' ${ TimeZone1 } '\/' ${ TimeZone2 } '/g' $cloudInitFile
sed -ri 's/targetLinuxMirror/' ${ targetLinuxMirror } '/g' $cloudInitFile
2023-10-02 06:38:16 +08:00
sed -ri 's/targetLinuxSecurityMirror/' ${ targetLinuxSecurityMirror } '/g' $cloudInitFile
2023-09-30 05:17:21 +08:00
sed -ri 's/networkAdapter/' ${ networkAdapter } '/g' $cloudInitFile
2023-09-18 17:14:15 +08:00
if [ [ " $iAddrNum " -ge "2" ] ] ; then
2023-10-12 16:16:45 +08:00
sed -ri 's#IPv4/ipPrefix#' ${ writeIpsCmd } '#g' $cloudInitFile
2023-09-18 17:14:15 +08:00
else
2023-10-12 16:16:45 +08:00
sed -ri 's/IPv4/' ${ IPv4 } '/g' $cloudInitFile
sed -ri 's/ipPrefix/' ${ ipPrefix } '/g' $cloudInitFile
sed -ri " s/ ${ IPv4 } \/ ${ ipPrefix } / ${ IPv4 } \/ ${ actualIp4Prefix } /g " $cloudInitFile
2023-09-18 17:14:15 +08:00
fi
2023-09-30 05:17:21 +08:00
sed -ri 's/GATE/' ${ GATE } '/g' $cloudInitFile
sed -ri 's/ipDNS1/' ${ ipDNS1 } '/g' $cloudInitFile
sed -ri 's/ipDNS2/' ${ ipDNS2 } '/g' $cloudInitFile
2023-09-18 17:34:33 +08:00
if [ [ " $i6AddrNum " -ge "2" ] ] ; then
2023-10-12 16:16:45 +08:00
sed -ri 's#ip6Addr/ip6Mask#' ${ writeIp6sCmd } '#g' $cloudInitFile
2023-09-18 17:34:33 +08:00
else
2023-10-12 16:16:45 +08:00
sed -ri 's/ip6Addr/' ${ ip6Addr } '/g' $cloudInitFile
sed -ri 's/ip6Mask/' ${ ip6Mask } '/g' $cloudInitFile
sed -ri " s/ ${ ip6Addr } \/ ${ ip6Mask } / ${ ip6Addr } \/ ${ actualIp6Prefix } /g " $cloudInitFile
2023-09-18 17:34:33 +08:00
fi
2023-09-30 05:17:21 +08:00
sed -ri 's/ip6Gate/' ${ ip6Gate } '/g' $cloudInitFile
sed -ri 's/ip6DNS1/' ${ ip6DNS1 } '/g' $cloudInitFile
sed -ri 's/ip6DNS2/' ${ ip6DNS2 } '/g' $cloudInitFile
2023-06-08 02:29:47 +08:00
2023-10-01 01:01:31 +08:00
# Disable any datahouse.
2023-07-29 22:34:25 +08:00
# Reference: https://github.com/canonical/cloud-init/issues/3772
2023-10-12 16:16:45 +08:00
echo 'datasource_list: [ NoCloud, None ]' >/mnt/etc/cloud/cloud.cfg.d/90_dpkg.cfg
2023-07-29 22:34:25 +08:00
2023-09-30 05:17:21 +08:00
# Disable IPv6.
2023-06-16 06:02:41 +08:00
[ [ " $setIPv6 " = = "0" ] ] && {
2023-10-12 16:16:45 +08:00
sed -ri 's/GRUB_CMDLINE_LINUX="net.ifnames=0 biosdevname=0"/GRUB_CMDLINE_LINUX="net.ifnames=0 biosdevname=0 ipv6.disable=1"/g' /mnt/etc/default/grub
sed -ri 's/ro net.ifnames=0 biosdevname=0/ro net.ifnames=0 biosdevname=0 ipv6.disable=1/g' /mnt/boot/grub/grub.cfg
2023-06-16 06:02:41 +08:00
}
2023-09-30 22:39:34 +08:00
# Permit root user login by password, change ssh port.
2023-09-30 05:17:21 +08:00
sed -ri 's/^#?PermitRootLogin.*/PermitRootLogin yes/g' /mnt/etc/ssh/sshd_config
sed -ri 's/^#?PasswordAuthentication.*/PasswordAuthentication yes/g' /mnt/etc/ssh/sshd_config
2023-09-30 23:11:59 +08:00
sed -ri 's/^#?Port.*/Port ' ${ sshPORT } '/g' /mnt/etc/ssh/sshd_config
2023-09-30 05:17:21 +08:00
# Disable installing fail2ban.
2023-09-17 13:03:07 +08:00
[ [ " $setFail2banStatus " != "1" ] ] && {
2023-10-12 16:16:45 +08:00
sed -ri 's/dnsutils fail2ban/dnsutils/g' $cloudInitFile
sed -i '/\/etc\/fail2ban/d' $cloudInitFile
sed -i '/fail2ban enable/d' $cloudInitFile
sed -i '/fail2ban restart/d' $cloudInitFile
2023-09-17 13:03:07 +08:00
}
2023-10-03 12:44:33 +08:00
# Hack cloud init, this method is effective for versions from 22.1.9 to 23.2.2 .
2023-09-30 20:30:12 +08:00
#
2023-10-03 12:44:33 +08:00
# Some cloud providers will storage a set of static cloud init configs which are including like "vendor-data", "meta-data", "network-config" and "user-data" in another hard drive with filesystem of iso like "sr0" or "sdb" etc. :
2023-09-30 20:30:12 +08:00
#
# [root@WIKIHOST-230702AJ306Z ~]# lsblk -ipf
# NAME FSTYPE FSVER LABEL UUID FSAVAIL FSUSE% MOUNTPOINTS
# /dev/sr0 iso9660 cidata 2023-09-01-12-11-27-00 0 100% /mnt
#
# or
#
# root@crunchbits-DualStackTest1:~# lsblk -ipf
# NAME FSTYPE FSVER LABEL UUID FSAVAIL FSUSE% MOUNTPOINTS
# /dev/sdb iso9660 Joliet Extension cidata 2023-09-30-05-08-06-00 0 100% /mnt
#
# Here is the list of the mounted files:
#
# [root@WIKIHOST-230702AJ306Z ~]# ls /mnt/
# meta-data network-config user-data vendor-data
#
# The initiate priority of these cloud init config files which were offered by cloud providers was executed in the early stage even laid over our cloud init file
# which had been storaged in directory of "/etc/cloud/cloud.cfg.d/" named like "99-fake_cloud.cfg" and the earliest command of "bootcmd:" in "99-fake_cloud.cfg" was
# executed later than them.
#
# If the consequence of this situation could not be resolved entirely, we are unable to set user timezone, permit root password login, config vim settings etc.
# The "user-data" in one cloud provider like "Crunchbits" even prohibit us to root user login although we changed password by "passwd" or added new ssh keys, that's quite serious.
# Here is the sample of file:
#
# root@crunchbits-DualStackTest1:~# cat /mnt/user-data
# #cloud-config
# timezone: Europe/London
# ssh_pwauth: false
# users:
# -
# name: root
# ssh-authorized-keys:
# - 'ssh-rsa abcde'
# hashed_passwd: ''
# lock_passwd: true
# runcmd:
# - 'DEBIAN_FRONTEND=noninteractive /usr/bin/apt-get ...'
#
# I analyzed the log file of cloud init which can be found in directory of "/var/log/cloud-init.log" in "WikiHost" and got some clues:
#
# 2023-09-29 03:13:20,892 - util.py[DEBUG]: Reading from /var/lib/cloud/seed/nocloud/user-data (quiet=False)
# 2023-09-29 03:13:20,893 - util.py[DEBUG]: Reading from /var/lib/cloud/seed/nocloud/meta-data (quiet=False)
# 2023-09-29 03:13:20,893 - util.py[DEBUG]: Reading from /var/lib/cloud/seed/nocloud/vendor-data (quiet=False)
# 2023-09-29 03:13:20,893 - util.py[DEBUG]: Reading from /var/lib/cloud/seed/nocloud/network-config (quiet=False)
# 2023-09-29 03:13:20,893 - util.py[DEBUG]: Reading from /var/lib/cloud/seed/nocloud-net/user-data (quiet=False)
# 2023-09-29 03:13:20,893 - util.py[DEBUG]: Reading from /var/lib/cloud/seed/nocloud-net/meta-data (quiet=False)
# 2023-09-29 03:13:20,893 - util.py[DEBUG]: Reading from /var/lib/cloud/seed/nocloud-net/vendor-data (quiet=False)
# 2023-09-29 03:13:20,893 - util.py[DEBUG]: Reading from /var/lib/cloud/seed/nocloud-net/network-config (quiet=False)
# 2023-09-29 03:13:20,894 - subp.py[DEBUG]: Running command ['blkid', '-tTYPE=vfat', '-odevice'] with allowed return codes [0, 2] (shell=False, capture=True)
# 2023-09-29 03:13:21,053 - subp.py[DEBUG]: Running command ['blkid', '-tTYPE=iso9660', '-odevice'] with allowed return codes [0, 2] (shell=False, capture=True)
# 2023-09-29 03:13:22,381 - subp.py[DEBUG]: Running command ['blkid', '-tLABEL=CIDATA', '-odevice'] with allowed return codes [0, 2] (shell=False, capture=True)
# 2023-09-29 03:13:22,486 - subp.py[DEBUG]: Running command ['blkid', '-tLABEL=cidata', '-odevice'] with allowed return codes [0, 2] (shell=False, capture=True)
# 2023-09-29 03:13:22,584 - subp.py[DEBUG]: Running command ['blkid', '-tLABEL_FATBOOT=cidata', '-odevice'] with allowed return codes [0, 2] (shell=False, capture=True)
# 2023-09-29 03:13:22,679 - DataSourceNoCloud.py[DEBUG]: Attempting to use data from /dev/sr0
#
# Another log was generated in "Crunchbits":
#
# 2023-09-30 10:39:04,417 - util.py[DEBUG]: Be similar with above and omitted.
# 2023-09-30 10:39:04,417 - subp.py[DEBUG]: Running command ['blkid', '-tTYPE=vfat', '-odevice'] with allowed return codes [0, 2] (shell=False, capture=True)
# 2023-09-30 10:39:04,479 - subp.py[DEBUG]: Running command ['blkid', '-tTYPE=iso9660', '-odevice'] with allowed return codes [0, 2] (shell=False, capture=True)
# 2023-09-30 10:39:04,572 - subp.py[DEBUG]: Running command ['blkid', '-tLABEL=CIDATA', '-odevice'] with allowed return codes [0, 2] (shell=False, capture=True)
# 2023-09-30 10:39:04,663 - subp.py[DEBUG]: Running command ['blkid', '-tLABEL=cidata', '-odevice'] with allowed return codes [0, 2] (shell=False, capture=True)
# 2023-09-30 10:39:04,748 - subp.py[DEBUG]: Running command ['blkid', '-tLABEL_FATBOOT=cidata', '-odevice'] with allowed return codes [0, 2] (shell=False, capture=True)
# 2023-09-30 10:39:04,836 - DataSourceNoCloud.py[DEBUG]: Attempting to use data from /dev/sdb
#
2023-10-03 12:44:33 +08:00
# The log generated in "Racknerd" which is using "SolusVM" panel to manage and initiate virtual machines without using cloud init, so there are no "user-data" in "/dev/vdb" or "/dev/sr1" etc.
2023-09-30 20:30:12 +08:00
# and the initial of cloud init was not affected by items came from upstream cloud providers. Here is the record:
#
# 2023-09-29 21:37:54,936 - util.py[DEBUG]: Be similar with above and omitted.
# 2023-09-29 21:37:54,936 - subp.py[DEBUG]: Running command ['blkid', '-tTYPE=vfat', '-odevice'] with allowed return codes [0, 2] (shell=False, capture=True)
# 2023-09-29 21:37:55,007 - subp.py[DEBUG]: Running command ['blkid', '-tTYPE=iso9660', '-odevice'] with allowed return codes [0, 2] (shell=False, capture=True)
# 2023-09-29 21:37:55,065 - subp.py[DEBUG]: Running command ['blkid', '-tLABEL=CIDATA', '-odevice'] with allowed return codes [0, 2] (shell=False, capture=True)
# 2023-09-29 21:37:55,128 - subp.py[DEBUG]: Running command ['blkid', '-tLABEL=cidata', '-odevice'] with allowed return codes [0, 2] (shell=False, capture=True)
# 2023-09-29 21:37:55,191 - subp.py[DEBUG]: Running command ['blkid', '-tLABEL_FATBOOT=cidata', '-odevice'] with allowed return codes [0, 2] (shell=False, capture=True)
# 2023-09-29 21:37:55,254 - __init__.py[DEBUG]: Datasource DataSourceNoCloud [seed=None][dsmode=net] not updated for events: boot-new-instance
# 2023-09-29 21:37:55,254 - handlers.py[DEBUG]: finish: init-local/search-NoCloud: SUCCESS: no local data found from DataSourceNoCloud
#
2023-10-03 12:44:33 +08:00
# I'm not quite familiar with python, but I discovered that "subp.py" called "blkid" commands of bash and tried to found any valid cloud init configs if they were in any filesystem of iso9660 drive
# and then applied them on a very, very, very early stage. That's why we wrote our own cloud init configs into "99-fake_cloud.cfg" even through but it was not be executed completely.
2023-09-30 20:30:12 +08:00
# We can also use "blkid" to repeat the behavior of cloud init, here are the results of those three machines:
#
# root@crunchbits-DualStackTest1:~# blkid -tTYPE=vfat -odevice
# /dev/sda15
# root@crunchbits-DualStackTest1:~# blkid -tTYPE=iso9660 -odevice
# /dev/sdb
# root@crunchbits-DualStackTest1:~# blkid -tLABEL=cidata -odevice
# /dev/sdb
#
# [root@WIKIHOST-230702AJ306Z ~]# blkid -tTYPE=vfat -odevice
# /dev/vda1
# [root@WIKIHOST-230702AJ306Z ~]# blkid -tTYPE=iso9660 -odevice
# /dev/sr0
# [root@WIKIHOST-230702AJ306Z ~]# blkid -tLABEL=cidata -odevice
# /dev/sr0
#
# root@racknerd-20fb37:~# blkid -tTYPE=vfat -odevice
# /dev/vda15
# root@racknerd-20fb37:~# blkid -tTYPE=iso9660 -odevice
# root@racknerd-20fb37:~# blkid -tLABEL=cidata -odevice
#
2023-10-03 12:44:33 +08:00
# We can make a obvious conclusion that when booting from a newly installed linux system which belongs to cloud image, cloud init will scan any valid iso filesystem hard drives and attempt to
# find any existed valid cloud init configs which were named by "meta-data, user-data etc." and treat them as the most prioritized configs so that this case contributes to bring a fatal for us
2023-09-30 20:30:12 +08:00
# to use our own cloud init config whatever we put any commands in it even in "bootcmd:" because it was executed extremely later than those cloud inits which were storaged in iso drives.
2023-10-03 12:44:33 +08:00
# I'm so confused that why Canonical has a almost maniacal passion and strange persistence with iso image not only on this case but also on deleting compatible with Debian "preseed" unattended installation method.
2023-09-30 20:30:12 +08:00
# They didn't intent to deliver a similar solution but told all individual users to install Ubuntu 22.04+ with downloading a huge iso image finally.
# So fuck you son of bitch, Canonical!
#
2023-10-03 12:53:01 +08:00
# We can replace all key words of "iso9660" and "blkid" in "util.py" which belongs to a component of cloud init and give it a failure of finding other hard drives.
2023-09-30 20:30:12 +08:00
#
# Due to dissimilar versions of python 3 and other factors, in different linux distributions of cloud images,
# the directory which contains main programs of cloud init may not the same, for examples:
#
2023-10-03 12:44:33 +08:00
# Official cloud image of Ubuntu 22.04.3:
# /usr/lib/python3/dist-packages/cloudinit/*
2023-09-30 20:30:12 +08:00
#
# Official cloud image of Rocky Linux 9.2:
2023-10-03 12:44:33 +08:00
# /usr/lib/python3.9/site-packages/cloudinit/*
2023-09-30 20:30:12 +08:00
utilProgram = $( find /mnt/usr/lib/python* -name "util.py" | grep "cloudinit" | head -n 1)
sed -ri 's/iso9660/osi9876/g' $utilProgram
2023-10-01 03:20:44 +08:00
sed -ri 's#"blkid"#"echo"#g' $utilProgram
2023-09-30 20:30:12 +08:00
2023-09-30 05:17:21 +08:00
# Umount mounted directory and loop device.
umount /mnt
kpartx -dv $loopDevice
losetup -d $loopDevice
2023-10-03 13:22:38 +08:00
# Reboot, the temporary intermediary system of AlpineLinux which is executing in memory will be destroyed during the power down and then server will reboot to the newly installed system immediately.
2023-06-14 04:52:41 +08:00
exec reboot