229 lines
5.3 KiB
Python
229 lines
5.3 KiB
Python
#!/usr/bin/env python3
|
|
import sys
|
|
import os
|
|
import shutil
|
|
diskSize = "1536M"
|
|
swapSize = "256M"
|
|
outputImage = os.path.abspath(sys.argv[1])
|
|
mountPoint = os.path.abspath(sys.argv[2].rstrip("/"))
|
|
|
|
mountPoints = [ # List of mount points to dismount when quitting
|
|
os.path.join(mountPoint,"proc"),
|
|
os.path.join(mountPoint,"sys"),
|
|
os.path.join(mountPoint,"dev","pts"),
|
|
os.path.join(mountPoint,"dev"),
|
|
mountPoint
|
|
]
|
|
|
|
preReqs = [ # List of required commands to check for
|
|
"fallocate",
|
|
"losetup",
|
|
"fdisk",
|
|
"losetup",
|
|
"mkswap",
|
|
"mkfs.ext4",
|
|
"mount",
|
|
"blkid",
|
|
"debootstrap",
|
|
"chmod",
|
|
"chroot",
|
|
"umount"
|
|
]
|
|
|
|
loopName = False
|
|
|
|
class processError(Exception): pass
|
|
|
|
import subprocess
|
|
def procWait(proc):
|
|
rtn = proc.wait()
|
|
if rtn != 0: raise processError
|
|
|
|
def call(*args,**kwargs):
|
|
proc = subprocess.Popen(*args,**kwargs)
|
|
procWait(proc)
|
|
|
|
def callo(*args,**kwargs):
|
|
data = b""
|
|
proc = subprocess.Popen(*args,**kwargs,stdout=subprocess.PIPE)
|
|
while True:
|
|
b = proc.stdout.read()
|
|
if b == b"": break
|
|
data += b
|
|
procWait(proc)
|
|
return data.decode("utf-8")
|
|
|
|
def cleanUp():
|
|
global diskSize
|
|
global swapSize
|
|
global outputImage
|
|
global mountPoint
|
|
global loopName
|
|
|
|
for mp in mountPoints:
|
|
print("Dismounting " +mp+ " ...")
|
|
try:
|
|
call(["umount",mp])
|
|
except: pass
|
|
|
|
try:
|
|
os.rmdir(mountPoint)
|
|
except Exception as e:
|
|
print(e)
|
|
|
|
print("Detaching loop device ...")
|
|
try:
|
|
call(["losetup","-d",loopName])
|
|
except:
|
|
pass
|
|
|
|
def main():
|
|
global diskSize
|
|
global swapSize
|
|
global outputImage
|
|
global mountPoint
|
|
global loopName
|
|
|
|
print("Checking prerequisites ...")
|
|
call(["sh","-c","command"])
|
|
for req in preReqs:
|
|
try:
|
|
call(["sh","-c","command -v " + req],stdout=subprocess.DEVNULL)
|
|
except:
|
|
print("Missing command: " +req)
|
|
raise
|
|
|
|
print("Creating disk image ...")
|
|
if os.path.isfile(outputImage): os.remove(outputImage)
|
|
call(["fallocate","-l",diskSize,outputImage])
|
|
|
|
print("Creating loop device ...")
|
|
call(["losetup","-fP",outputImage])
|
|
|
|
print("Setting up loop device ...")
|
|
table = callo(["losetup","--list"]).replace("\r","").split("\n")
|
|
length = len(table)
|
|
index = 0
|
|
while index < length:
|
|
while " " in table[index]:
|
|
table[index] = table[index].replace(" "," ")
|
|
if table[index] == "":
|
|
del table[index]
|
|
length -= 1
|
|
continue
|
|
table[index] = table[index].split(" ")
|
|
index += 1
|
|
nameIndex = table[0].index("NAME")
|
|
backfileIndex = table[0].index("BACK-FILE")
|
|
|
|
index = 1
|
|
while index < length:
|
|
if table[index][backfileIndex] == outputImage:
|
|
loopName = table[index][nameIndex]
|
|
break
|
|
index += 1
|
|
|
|
if loopName == False:
|
|
print("Loop device not found.")
|
|
raise processError
|
|
|
|
print("Partitioning ...")
|
|
proc = subprocess.Popen(["fdisk",loopName],stdin=subprocess.PIPE)
|
|
proc.communicate(("""\
|
|
n
|
|
e
|
|
|
|
|
|
+""" +swapSize+ """
|
|
t
|
|
swap
|
|
n
|
|
p
|
|
|
|
|
|
|
|
t
|
|
|
|
linux
|
|
w
|
|
|
|
\
|
|
""").encode("utf-8"))
|
|
procWait(proc)
|
|
|
|
print("Making swap ...")
|
|
call(["mkswap",loopName + "p1"])
|
|
|
|
print("Formatting / (ext4) ...")
|
|
call(["mkfs.ext4",loopName+ "p2"])
|
|
|
|
print("Mounting / ...")
|
|
if not os.path.isdir(mountPoint): os.makedirs(mountPoint)
|
|
call(["mount",loopName + "p2",mountPoint])
|
|
|
|
print("Installing Devuan Chimaera ...")
|
|
tries = 0
|
|
while tries < 10:
|
|
try:
|
|
call(["debootstrap","--arch=i386","chimaera",mountPoint,"http://deb.devuan.org/merged"])
|
|
break
|
|
except:
|
|
tries += 1
|
|
continue
|
|
|
|
if tries >= 10:
|
|
raise processError
|
|
|
|
if os.path.isdir("skel"):
|
|
print("Adding skel ...")
|
|
if not os.path.isdir(os.path.join(mountPoint,"etc","skel")):
|
|
os.makedirs(os.path.join(mountPoint,"etc","skel"))
|
|
for root,dirs,files in os.walk("skel"):
|
|
for file in dirs:
|
|
ffile = os.path.join(root,file)
|
|
lfile = ffile.replace("skel" + os.path.sep,"",1)
|
|
ofile = os.path.join(mountPoint,"etc","skel",lfile)
|
|
if not os.path.isdir(ofile): os.makedirs(ofile)
|
|
|
|
for file in files:
|
|
ffile = os.path.join(root,file)
|
|
lfile = ffile.replace("skel" + os.path.sep,"",1)
|
|
ofile = os.path.join(mountPoint,"etc","skel",lfile)
|
|
if os.path.isfile(ofile): os.remove(ofile)
|
|
shutil.copyfile(ffile,ofile)
|
|
|
|
print("Setting up chroot ...")
|
|
call(["mount","-o","bind","/dev",os.path.join(mountPoint,"dev")])
|
|
call(["mount","--bind","/dev/pts",os.path.join(mountPoint,"dev","pts")])
|
|
call(["mount","-o","bind","/sys",os.path.join(mountPoint,"sys")])
|
|
call(["mount","-t","proc","/proc",os.path.join(mountPoint,"proc")])
|
|
with open("setup","r",encoding="utf-8") as fhIn:
|
|
with open(os.path.join(mountPoint,"setup"),"w",encoding="utf-8") as fhOut:
|
|
for line in fhIn:
|
|
fhOut.write(line.replace("$LOOPNAME",loopName))
|
|
call(["chmod","+x",os.path.join(mountPoint,"setup")])
|
|
|
|
print("Adding devices to fstab ...")
|
|
idSwap = callo(["blkid","-o","value","-s","UUID",loopName+ "p1"]).strip(" \t\r\n")
|
|
idRoot = callo(["blkid","-o","value","-s","UUID",loopName+ "p2"]).strip(" \t\r\n")
|
|
with open(os.path.join(mountPoint,"etc","fstab"),"a+",encoding="utf-8") as fh:
|
|
fh.write("\nUUID=" +idSwap+ " none swap sw 0 0")
|
|
fh.write("\nUUID=" +idRoot+ " / ext4 errors=remount-ro 0 1")
|
|
|
|
print("Running setup ...")
|
|
call(["chroot",mountPoint,"/setup"])
|
|
|
|
print("Injecting OOBE ...")
|
|
os.rename(os.path.join(mountPoint,"bin","login"),os.path.join(mountPoint,"bin","login.bak"))
|
|
shutil.copyfile("oobe",os.path.join(mountPoint,"bin","login"))
|
|
call(["chmod","+x",os.path.join(mountPoint,"bin","login")])
|
|
|
|
cleanUp()
|
|
|
|
try:
|
|
main()
|
|
except:
|
|
print("\n --- AN ERROR OCCURED, CLEANING UP ... --- ")
|
|
cleanUp()
|
|
print("")
|
|
raise |