name(), [ new HookEntry('default', Dictionary::translateFileModule('minilinux', 'module', 'default_boot_entry'), MiniLinux::updateCurrentBootSetting()) ]); $branches = Database::queryAll('SELECT sourceid, branchid, title FROM minilinux_branch ORDER BY title'); $versions = MiniLinux::queryAllVersionsByBranch(); // Group by branch for detailed listing foreach ($branches as $branch) { if (isset($versions[$branch['branchid']])) { $group = [ new HookEntry($branch['branchid'], $branch['branchid'] . ' ' . Dictionary::translateFileModule('minilinux', 'module', 'latest_of_branch'), true), ]; foreach ($versions[$branch['branchid']] as $version) { $valid = $version['installed'] != MiniLinux::INSTALL_MISSING; $title = $version['versionid'] . ' ' . $version['title']; if (!$valid) { $title .= ' ' . Dictionary::translateFileModule('minilinux', 'module', 'not_installed_hint'); } $group[] = new HookEntry($version['versionid'], $title, $valid); } $array[] = new HookEntryGroup($branch['title'] ?: $branch['branchid'], $group); } } return $array; } /** * @return ?BootEntry the actual boot entry instance for given entry, false if invalid id */ public function getBootEntryInternal(array $localData): ?BootEntry { $id = $localData['id']; if ($id === 'default') { // Special case $effectiveId = Property::get(MiniLinux::PROPERTY_DEFAULT_BOOT_EFFECTIVE); } else { $effectiveId = $id; } $res = Database::queryFirst('SELECT versionid, installed, data FROM minilinux_version WHERE versionid = :id', ['id' => $effectiveId]); if ($res === false) { // Maybe this is a branchid, which means latest from according branch (installed only) $res = Database::queryFirst('SELECT versionid, installed, data FROM minilinux_version WHERE branchid = :id AND installed = :ok ORDER BY dateline DESC LIMIT 1', ['id' => $effectiveId, 'ok' => MiniLinux::INSTALL_OK]); } if ($res === false) { return BootEntry::newCustomBootEntry(['script' => 'prompt Selected version not currently installed on server: ' . $effectiveId]); } $effectiveId = $res['versionid']; // In case we selected from a branchid, so above message doesn't show versionid $remoteData = json_decode($res['data'], true); $bios = $efi = false; if (!@is_array($remoteData['agnostic']) && !@is_array($remoteData['efi']) && !@is_array($remoteData['bios'])) { $remoteData['agnostic'] = []; // We got nothing at all so fake this entry, resulting in a generic default entry } if (@is_array($remoteData['agnostic'])) { $bios = $this->generateExecData($effectiveId, $remoteData['agnostic'], $localData); $arch = BootEntry::AGNOSTIC; } else { if (@is_array($remoteData['efi'])) { $efi = $this->generateExecData($effectiveId, $remoteData['efi'], $localData); } if (@is_array($remoteData['bios'])) { $bios = $this->generateExecData($effectiveId, $remoteData['bios'], $localData); } if ($bios && $efi) { $arch = BootEntry::BOTH; } elseif ($bios) { $arch = BootEntry::BIOS; } else { $arch = BootEntry::EFI; } } return BootEntry::newStandardBootEntry($bios, $efi, $arch, 'ml-' . $id); } private function generateExecData($effectiveId, $remoteData, $localData): ExecData { $exec = new ExecData(); // Defaults $root = '/boot/' . $effectiveId . '/'; $exec->executable = 'kernel'; $exec->initRd = ['initramfs-stage31']; $exec->imageFree = true; $exec->commandLine = 'slxbase=boot/%ID% slxsrv=${serverip} quiet splash ${ipappend1} ${ipappend2}' . ' ipv4.ip=${ip} ipv4.router=${gateway} ipv4.dns=${dns} ipv4.hostname=${hostname} ipv4.domain=${domain} ipv4.search=${dnssl}' . ' ipv4.if=${mac} ipv4.ntpsrv=${ntpsrv} ipv4.subnet=${netmask}'; // Overrides foreach (['executable', 'commandLine', 'initRd', 'imageFree'] as $key) { if (isset($remoteData[$key])) { $exec->{$key} = $remoteData[$key]; } } // KCL hacks if (!empty($localData['debug'])) { // Debug boot enabled $exec->commandLine = IPxe::modifyCommandLine($exec->commandLine, $remoteData['debugCommandLineModifier'] ?? '-vga -quiet -splash -loglevel loglevel=7' ); } // disable all CPU sidechannel attack mitigations etc. if (!empty($localData['insecure-cpu'])) { $exec->commandLine = IPxe::modifyCommandLine($exec->commandLine, 'noibrs noibpb nopti nospectre_v2 nospectre_v1 l1tf=off nospec_store_bypass_disable no_stf_barrier mds=off mitigations=off i915.mitigations=off'); } // force that we if (!empty($localData['force-init-dhcp'])) { $exec->commandLine = IPxe::modifyCommandLine($exec->commandLine, '-ipv4.router -ipv4.dns -ipv4.subnet'); } // GVT, PCI Pass-thru etc. if (Module::isAvailable('statistics')) { $hwextra = HardwareInfo::getKclModifications(); if (!empty($hwextra)) { $exec->commandLine = IPxe::modifyCommandLine($exec->commandLine, $hwextra); } } // User-supplied modifications if (!empty($localData['kcl-extra'])) { $exec->commandLine = IPxe::modifyCommandLine($exec->commandLine, $localData['kcl-extra']); } $exec->commandLine = str_replace('%ID%', $effectiveId, $exec->commandLine); $exec->executable = $root . $exec->executable; foreach ($exec->initRd as &$rd) { if ($rd[0] !== '/') { $rd = $root . $rd; } } unset($rd); return $exec; } public function isValidId(string $id): bool { if ($id === 'default') return true; // Meta-version that links to whatever the default is set to $res = Database::queryFirst('SELECT installed FROM minilinux_version WHERE versionid = :id', ['id' => $id]); if ($res !== false && $res['installed'] != MiniLinux::INSTALL_MISSING) return true; $res = Database::queryFirst('SELECT branchid FROM minilinux_branch WHERE branchid = :id', ['id' => $id]); return $res !== false; } }