windvn/mods/live-installer/data/opt/wdvn/installer/main

347 lines
10 KiB
Python
Executable File

#!/usr/bin/python3
import os
import subprocess
import getpass
import time
import shutil
import random
def nerr(func,*args,**kwargs):
try:
return func(*args,**kwargs)
except:
return
def choiceYn(question,defaultPick = None):
qstring = "\n" + question + " y/n"
if defaultPick != None: qstring = qstring + " [" +defaultPick+ "]"
qstring = qstring + ": "
while True:
chinput = input(qstring)
if chinput == "" and defaultPick != None:
chinput = defaultPick
chinput = chinput.lower()
if chinput == "y": return True
if chinput == "n": return False
def choice(question,options,defaultPick = None,direction = 1):
qstring = "\n"
for option in options:
qstring = qstring + "- " + option + "\n"
qstring = qstring + question
if defaultPick != None: qstring = qstring + " [" +defaultPick+ "]"
qstring = qstring + ": "
while True:
chinput = input(qstring)
if chinput == "" and defaultPick != None:
chinput = defaultPick
if chinput in options: return chinput
def choiceInput(question,defaultPick = None):
qstring = "\n" + question
if defaultPick != None: qstring = qstring + " [" +defaultPick+ "]"
qstring = qstring + ": "
while True:
chinput = input(qstring)
if chinput == "":
if defaultPick == None: continue
return defaultPick
return chinput
def choicePass(question):
while True:
print("")
passw = getpass.getpass(question+ ": ")
passwConfirm = getpass.getpass(question+ " (repeat): ")
if passw == passwConfirm: return passw
print("Passwords don't match, try again.")
def checkProc(proc):
rtn = proc.wait()
if rtn != 0: raise Exception("Process returned error: " +str(rtn))
def call(*args,**kwargs):
proc = subprocess.Popen(*args,**kwargs)
checkProc(proc)
return
def callString(*args,**kwargs):
proc = subprocess.Popen(*args,**kwargs,stdout=subprocess.PIPE)
output = proc.stdout.read().decode("utf-8").strip("\n")
checkProc(proc)
return output
def callList(*args,**kwargs):
proc = subprocess.Popen(*args,**kwargs,stdout=subprocess.PIPE)
output = proc.stdout.read().decode("utf-8").strip("\n").split("\n")
checkProc(proc)
return output
def getDisks():
return callList(["lsblk","-ndo","PATH"])
def getPartitions():
disks = getDisks()
partitions = callList(["lsblk","-no","PATH"])
index = 0
length = len(partitions)
while index < length:
if partitions[index] in disks:
del partitions[index]
length -= 1
continue
index += 1
return partitions
def getDiskType(disk):
return callString(["blkid","-o","value","-s","PTTYPE",disk])
def getPartitionType(partition):
return callString(["blkid","-o","value","-s","TYPE",partition])
def getPartitionUUID(partition):
return callString(["blkid","-o","value","-s","UUID",partition])
def setKbLayout(kb):
call(["loadkeys",kb])
def resetKbLayout():
call(["service","console-setup.sh","restart"])
call(["udevadm","trigger","--subsystem-match=input","--action=change"])
call(["service","keyboard-setup.sh","restart"])
def ipth(path = ""):
return "/media/install/" +path
def mkdirp(path):
if not os.path.isdir(path): os.makedirs(path)
def chroot(path,cmd,*args,**kwargs):
dirs = ["dev","dev/pts","sys","proc"]
try:
for dir in dirs:
call(["mount","-o","bind","/" +dir,path + "/" +dir])
call(["chroot",path] + cmd,*args,**kwargs)
for dir in reversed(dirs):
call(["umount","-l",path + "/" +dir])
except Exception as e:
for dir in reversed(dirs):
try:
call(["umount","-l",path + "/" +dir])
except:
pass
raise e
def randhex(length):
chars = "0123456789ABCDEF"
output = ""
cLength = 0
while cLength < length:
output = output + chars[random.randrange(0,15)]
cLength += 1
return output
def main():
while choiceYn("Partition disk?"):
try:
disk = choice("Disk",getDisks())
call(["fdisk",disk])
except KeyboardInterrupt:
pass
installPartition = choice("OS Partition",getPartitions())
formatPartition = choiceYn("Format partition?","y")
if formatPartition:
fileSystems = []
for path in os.environ["PATH"].split(":"):
if not os.path.isdir(path): continue
for root,dirs,files in os.walk(path):
for file in files:
ffile = os.path.join(root,file)
lfile = ffile.replace(path + os.path.sep,"",1)
if lfile.startswith("mkfs."): fileSystems.append(lfile.replace("mkfs.","",1))
fileSystems.sort()
defaultChoice = None
if "ext4" in fileSystems: defaultChoice = "ext4"
formatPartition = choice("File system",fileSystems,defaultChoice)
else:
formatPartition = None
if formatPartition != None:
encrypt = choiceYn("Encrypt data?")
if encrypt:
encryptionPasswords = []
setKbLayout("us")
try:
encryptionPasswords.append(choicePass("Encryption password"))
except KeyboardInterrupt:
encrypt = False
resetKbLayout()
if encrypt:
while choiceYn("Add another password?"):
setKbLayout("us")
try:
encryptionPasswords.append(choicePass("Encryption password"))
except KeyboardInterrupt:
resetKbLayout()
break
resetKbLayout()
installGRUB = choiceYn("Install GRUB?","y")
if installGRUB:
try:
grubDisk = choice("GRUB disk",getDisks())
except KeyboardInterrupt:
installGRUB = False
print("")
print("The rest of this setup will continue without your input ...")
time.sleep(5)
print("")
print("> Wiping partition signature ...")
call(["wipefs","-a",installPartition])
if encrypt:
print("> Encrypting partition ...")
call(["apt","-y","install","cryptsetup"],stdout=subprocess.DEVNULL)
cryptPartition = installPartition
mainPass = encryptionPasswords.pop(0)
proc = subprocess.Popen(["cryptsetup","luksFormat","--type","luks1",cryptPartition],stdin=subprocess.PIPE)
proc.stdin.write((mainPass + "\n").encode("utf-8"))
proc.stdin.flush()
checkProc(proc)
for passw in encryptionPasswords:
print("Adding another password ...")
proc = subprocess.Popen(["cryptsetup","luksAddKey",cryptPartition],stdin=subprocess.PIPE)
proc.stdin.write((mainPass + "\n" + passw + "\n").encode("utf-8"))
proc.stdin.flush()
checkProc(proc)
print("Creating block device ...")
proc = subprocess.Popen(["cryptsetup","luksOpen",cryptPartition,"system"],stdin=subprocess.PIPE)
proc.stdin.write((mainPass + "\n").encode("utf-8"))
proc.stdin.flush()
checkProc(proc)
installPartition = "/dev/mapper/system"
if formatPartition != None:
print("> Formatting partition ...")
call(["mkfs." +formatPartition,installPartition])
print("> Grabbing partition UUIDs ...")
installPartitionUUID = getPartitionUUID(installPartition)
if encrypt: cryptPartitionUUID = getPartitionUUID(cryptPartition)
print("> Mounting main partition ...")
mkdirp(ipth())
call(["mount",installPartition,ipth()])
print("> Creating swap ...")
call(["dd","if=/dev/zero","of=" +ipth("swap"),"bs=1M","count=512","status=progress"])
call(["chmod","600",ipth("swap")])
call(["mkswap",ipth("swap")])
call(["swapon",ipth("swap")])
print("> Adding files ...")
call(["unsquashfs","-f","-d",ipth(),"/lib/live/mount/medium/live/filesystem.squashfs"])
print("Setting hostname ...")
hostname = randhex(8)
fh = open(ipth("etc/hostname"),"w")
fh.write(hostname + "\n")
fh.close()
if encrypt:
print("Writing crypto grub config ...")
fh = open(ipth("etc/default/grub.d/cryptodisk.cfg"),"w")
fh.write("GRUB_ENABLE_CRYPTODISK=y\n")
fh.write('GRUB_CMDLINE_LINUX="$GRUB_CMDLINE_LINUX cryptdevice=UUID=' +cryptPartitionUUID+ ' root=UUID=' +installPartitionUUID+ '"\n')
fh.close()
print("Writing crypttab ...")
fh = open(ipth("etc/crypttab"),"w")
fh.write('system UUID=' +cryptPartitionUUID+ ' none luks\n')
fh.close()
print("Writing fstab ...")
fh = open(ipth("etc/fstab"),"w")
fh.write('UUID=' +installPartitionUUID+ ' / ' +getPartitionType(installPartition)+ ' defaults 0 1\n')
fh.write('/swap none swap sw 0 0\n')
fh.close()
print("Copying keyboard settings ...")
shutil.copyfile("/etc/default/keyboard",ipth("etc/default/keyboard"))
print("> Removing live-specific packages ...")
chroot(ipth(),["apt","-y","remove","live-boot","live-boot-initramfs-tools"])
chroot(ipth(),["apt","-y","autoremove"])
os.remove(ipth("bin/login"))
os.rename(ipth("bin/login.oobe"),ipth("bin/login"))
if encrypt:
print("> Installing encryption-specific packages ...")
chroot(ipth(),["apt","-y","install","cryptsetup-initramfs"])
else:
print("> Updating initramfs ...")
chroot(ipth(),["update-initramfs","-u"])
if installGRUB:
print("> Installing GRUB")
mbrInstall = True
diskType = getDiskType(grubDisk)
if diskType == "gpt":
print("Scanning GPT disk ...")
partitions = callList(["lsblk",grubDisk,"-no","PATH"])
del partitions[0]
try:
del partitions[partitions.index(installPartition)]
except Exception:
pass
if crypto:
try:
del partitions[partitions.index(cryptoPartition)]
except Exception:
pass
if len(partitions) > 0:
partType = getPartitionType(partitions[0])
if partType == "fat" or partType == "vfat":
print("Mounting ESP ...")
mkdirp(ipth("boot/efi"))
call(["mount",partitions[0],ipth("boot/efi")])
print("Installing GRUB ...")
mbrInstall = False
chroot(ipth(),["grub-install","--target=i386-efi","--uefi-secure-boot","--efi-directory=/boot/efi","--boot-directory=/boot",grubDisk])
chroot(ipth(),["grub-install","--target=x86_64-efi","--uefi-secure-boot","--efi-directory=/boot/efi","--boot-directory=/boot",grubDisk])
chroot(ipth(),["grub-install","--target=i386-pc","--boot-directory=/boot",grubDisk])
chroot(ipth(),["update-grub"])
print("Unmounting ESP ...")
call(["umount","-l",ipth("boot/efi")])
os.rmdir(ipth("boot/efi"))
if mbrInstall:
if diskType == "gpt":
print("WARNING: GPT disk unsuitable for EFI, installing BIOS payload only.")
print("Installing GRUB ...")
chroot(ipth(),["grub-install","--target=i386-pc","--boot-directory=/boot",grubDisk])
chroot(ipth(),["update-grub"])
print("> Unmounting ...")
call(["swapoff",ipth("swap")])
call(["umount",ipth()])
os.rmdir(ipth())
if encrypt: call(["cryptsetup","luksClose","system"])
print("Success. Press ENTER to quit setup.")
input()
main()