import subprocess, os, sys, datetime, getpass, shutil from pathlib import Path if __name__ != '__main__': from . import * class OS: def __init__(self): self.root_dir = f"{ROOT_DIR}/root" self.actions = [ [ "chroot", self.chroot ], [ "sync", self.sync_repo ], [ "update", self.update_all ], [ "reinstall", self.rebuild_all ], [ "pack", self.pack ], [ "sqh", self.sqh ] ] def actions_list(self): lst = [] for act in self.actions: lst.append(act[0]) return lst def set_board(self, board): self.board = board self.arch = board.parse_variables("%{ARCH}%") def __sudo(self, args, cwd=None, env=None): args.insert(0, "sudo") p = subprocess.Popen(args, cwd=cwd, env=env) if (p.wait() != 0): Logger.error(f"Command '{args[1]}' finished with error code!") def __prepare(self): qemu_f = Path(f"/proc/sys/fs/binfmt_misc/qemu-{self.arch}") if (not qemu_f.is_file()): self.__sudo(["python", os.path.abspath(__file__), self.arch]) self.__sudo(["cp", f"{ROOT_DIR}/files/qemu/qemu-{self.arch}", f"{self.root_dir}/bin/"]) def __chroot(self, command, dir=""): self.__prepare() if (dir == ""): dir = self.root_dir Logger.os(f"Start chroot'ed command '{command}' into '{dir}'") self.__sudo(["bash", f"{ROOT_DIR}/scripts/chroot.sh", dir, ROOT_DIR, command]) def umount_safe(self): self.__sudo(["umount", "--all-targets", "--recursive", self.root_dir]) def bind(self, dir, path): self.__sudo(["mkdir", "-p", f"{self.root_dir}/{path}"]) self.__sudo(["mount", "--bind", dir, f"{self.root_dir}/{path}"]) def unbind(self, path): self.__sudo(["umount", f"{self.root_dir}/{path}"]) def chroot(self): self.__chroot("") def chroot_ext(self, command, dir): self.__chroot(command, dir) def sync_repo(self): self.__chroot("eix-sync -v") def update_all(self): self.__chroot("emerge -avuDN1b world -j2 && emerge -ac") self.__chroot("ldconfig") def rebuild_all(self): self.__chroot("emerge -av1be world -j2") self.__chroot("ldconfig") def custom(self, command): self.__chroot(command) def __do_archive(self, excl_list, name, dir): Logger.os(f"Create '{name}' archive...") my_env = os.environ.copy() my_env["XZ_OPT"] = "-9 --extreme --threads=0" date = datetime.datetime.today().strftime('%Y_%m_%d') arch_path = self.board.parse_variables("%{out_sh}%/back_" + name + "_" + date + ".tar.xz") self.__sudo(["tar", "-cJpf", arch_path, f"--exclude-from={ROOT_DIR}/files/backups/{excl_list}.lst", "."], cwd=dir, env=my_env) return arch_path def pack(self): return self.__do_archive("excl_min", "FULL", self.root_dir) def __fix_xorg(self): Logger.os("Fix Xorg permissions") self.__sudo(["chmod", "u+s", f"{self.root_dir}/usr/bin/Xorg"]) def __tmp_clean(self, path): Logger.os("Clean temporary directory...") t_dir = Path(path) if (t_dir.is_dir()): self.__sudo(["rm", "-rf", path]) def __extract_tar(self, arch_fn, to_path): Logger.os("Extract to temporary directory...") os.makedirs(to_path, exist_ok=True) my_env = os.environ.copy() my_env["XZ_OPT"] = "-9 --extreme --threads=0" self.__sudo(["tar", "xf", arch_fn], cwd=to_path, env=my_env) def __make_sqh(self, root_path, to_file): Logger.os("Create squashed archive...") t_file = Path(to_file) if (t_file.is_file()): shutil.move(to_file, f"{to_file}.bak") self.__sudo(["mksquashfs", root_path, to_file, "-comp", "xz", "-xattrs-exclude", "^system.nfs"]) user = getpass.getuser() self.__sudo(["chown", user + ":" + user, to_file]) def __remove_bdeps(self, temp_dir): # remove unneccessarry packages list_to_rm = " virtual/perl-JSON-PP virtual/perl-podlators" list_to_rm += " virtual/perl-Getopt-Long virtual/perl-Parse-CPAN-Meta" list_to_rm += " virtual/perl-ExtUtils-CBuilder virtual/perl-ExtUtils-ParseXS" list_to_rm += " virtual/perl-Unicode-Collate virtual/perl-Text-ParseWords" list_to_rm += " virtual/perl-ExtUtils-MakeMaker virtual/perl-Module-Metadata" list_to_rm += " virtual/perl-version virtual/perl-CPAN-Meta" list_to_rm += " virtual/perl-File-Spec perl-core/Getopt-Long" list_to_rm += " dev-perl/Module-Build" list_to_rm += " x11-base/xcb-proto x11-libs/xtrans" list_to_rm += " app-alternatives/ninja app-eselect/eselect-rust" list_to_rm += " dev-libs/vala-common dev-util/glib-utils" list_to_rm += " dev-util/gdbus-codegen media-fonts/font-util" list_to_rm += " dev-libs/libxslt" list_to_rm += " dev-build/gtk-doc-am sys-apps/help2man" list_to_rm += " app-text/docbook-xml-dtd:4.1.2" list_to_rm += " app-text/docbook-xml-dtd:4.2 app-text/docbook-xml-dtd:4.3" list_to_rm += " app-text/docbook-xml-dtd:4.4 app-text/docbook-xml-dtd:4.5" list_to_rm += " app-text/docbook-xsl-ns-stylesheets app-text/docbook-xsl-stylesheets" list_to_rm += " app-text/build-docbook-catalog app-text/xmlto" list_to_rm += " app-text/asciidoc app-text/sgml-common" list_to_rm += " dev-lang/rust-common dev-lang/rust" list_to_rm += " llvm-core/llvm llvm-core/llvm-toolchain-symlinks" list_to_rm += " llvm-core/llvmgold dev-libs/oniguruma" list_to_rm += " llvm-core/llvm-common sys-libs/binutils-libs" list_to_rm += " dev-build/ninja dev-build/meson dev-build/meson-format-array" list_to_rm += " dev-cpp/eigen" list_to_rm += " " self.__chroot(f"emerge -aC {list_to_rm} && ldconfig", temp_dir) self.__do_archive("excl_min", "FULL_min_bdeps", temp_dir) def __finalize(self, dir): Logger.os(f"Finalize system installation...") # enable network services services = "systemctl enable NetworkManager ntpdate sshd" self.__chroot(services, dir) # minimize systemd journal files journal_min = "sed -i -E 's/^#(\\S+MaxUse)=$/\\1=10M/' /etc/systemd/journald.conf &&" journal_min += "sed -i -E 's/^#(\\S+MaxFileSize)=$/\\1=10M/' /etc/systemd/journald.conf" self.__chroot(journal_min, dir) self.__sudo(["cp", "-r", f"{ROOT_DIR}/files/firmware/usr", f"{dir}/"]) soft = Software(self) soft.finalize(dir) def sqh(self): self.__fix_xorg() date = datetime.datetime.today().strftime('%Y_%m_%d') temp_dir = f"{ROOT_DIR}/build/tmp" # pack full system via tar arch_full_path = self.pack() self.__tmp_clean(temp_dir) self.__extract_tar(arch_full_path, temp_dir) # remove unnecessary packages self.__remove_bdeps(temp_dir) # prepare system self.__finalize(temp_dir) # pack a minimal archive arch_path = self.__do_archive("excl", "OS", temp_dir) # remove temp directory self.__tmp_clean(temp_dir) self.__extract_tar(arch_path, temp_dir) sqh_fn = f"{ROOT_DIR}/out/root_{date}.sqh" self.__make_sqh(temp_dir, sqh_fn) #os.symlink(sqh_fn, f"{ROOT_DIR}/out/root.sqh") self.__tmp_clean(temp_dir) def action(self, action): for act in self.actions: if (act[0] == action): act[1]() break if __name__ == '__main__': f = open("/proc/sys/fs/binfmt_misc/register","wb") if (len(sys.argv) < 2) or (sys.argv[1] == "aarch64"): name = "aarch64" interp = f"/usr/bin/qemu-{name}" magic = b"\\x7fELF\\x02\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00\\xb7\\x00" mask = b"\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\x00\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xfe\\xff\\xff\\xff" else: print("Invalid arguments!") exit(1) _REGISTER_FORMAT = b":qemu-%(name)s:M::%(magic)s:%(mask)s:%(interp)s:%(flags)s" s = _REGISTER_FORMAT % { b"name": name.encode("utf-8"), b"magic": magic, b"mask": mask, b"interp": interp.encode("utf-8"), b"flags": b"", } f.write(s)