from . import BonnibelError class Manifest: from collections import namedtuple Entry = namedtuple("Entry", ("module", "target", "output", "flags")) formats = { "none": 0x00, "zstd": 0x01, } flags = { "graphical": 0x01, "symbols": 0x80, } boot_flags = { "debug": 0x01, "test": 0x02, } def __init__(self, path, modules): from . import load_config config = load_config(path) self.location = config.get("location", "jsix") self.kernel = self.__build_entry(modules, config.get("kernel", dict()), name="kernel", target="kernel") self.init = self.__build_entry(modules, config.get("init", None)) self.panics = [self.__build_entry(modules, i, target="kernel") for i in config.get("panic", tuple())] self.services = [self.__build_entry(modules, i) for i in config.get("services", tuple())] self.drivers = [self.__build_entry(modules, i) for i in config.get("drivers", tuple())] self.flags = config.get("flags", tuple()) initrd = config.get("initrd", dict()) self.initrd = initrd.get("name", "initrd.dat") self.initrd_format = initrd.get("format", "none") if not self.initrd_format in Manifest.formats: raise BonnibelError(f"Manifest specifies unknown initrd format '{self.initrd_format}'") self.data = [] for d in config.get("data", tuple()): self.add_data(**d) def __build_entry(self, modules, config, target="user", name=None): flags = tuple() if isinstance(config, str): name = config elif isinstance(config, dict): name = config.get("name", name) target = config.get("target", target) flags = config.get("flags", tuple()) if isinstance(flags, str): flags = flags.split() mod = modules.get(name) if not mod: raise BonnibelError(f"Manifest specifies unknown module '{name}'") for f in flags: if not f in Manifest.flags: raise BonnibelError(f"Manifest specifies unknown flag '{f}'") return Manifest.Entry(name, target, mod.output, flags) def add_data(self, output, desc, flags=tuple()): e = Manifest.Entry(None, None, output, flags) self.data.append(e) return e def write_boot_config(self, path): from os.path import join import struct with open(path, 'wb') as outfile: magic = "jsixboot".encode("utf-8") # magic string version = 1 reserved = 0 initrd_format = Manifest.formats.get(self.initrd_format, 0) bootflags = sum([Manifest.boot_flags.get(s, 0) for s in self.flags]) outfile.write(struct.pack("<8s BBH HH", magic, version, reserved, len(self.panics), initrd_format, bootflags)) def write_str(s): data = s.encode("utf-16le") outfile.write(struct.pack("