summaryrefslogtreecommitdiffstats
path: root/modules-available/serversetup-bwlp-ipxe/inc/bootentry.inc.php
diff options
context:
space:
mode:
Diffstat (limited to 'modules-available/serversetup-bwlp-ipxe/inc/bootentry.inc.php')
-rw-r--r--modules-available/serversetup-bwlp-ipxe/inc/bootentry.inc.php248
1 files changed, 130 insertions, 118 deletions
diff --git a/modules-available/serversetup-bwlp-ipxe/inc/bootentry.inc.php b/modules-available/serversetup-bwlp-ipxe/inc/bootentry.inc.php
index e89380ce..5812c0cd 100644
--- a/modules-available/serversetup-bwlp-ipxe/inc/bootentry.inc.php
+++ b/modules-available/serversetup-bwlp-ipxe/inc/bootentry.inc.php
@@ -12,13 +12,28 @@ abstract class BootEntry
/** Supports both via distinct entry */
const BOTH = 'PCBIOS-EFI';
- public abstract function supportsMode($mode);
+ /**
+ * @var string Internal ID - set to your liking, e.g. the MiniLinux version identifier
+ */
+ protected $internalId;
+
+ public function __construct(string $internalId)
+ {
+ $this->internalId = $internalId;
+ }
- public abstract function toScript($failLabel, $mode);
+ public abstract function supportsMode(string $mode): bool;
- public abstract function toArray();
+ public abstract function toScript(ScriptBuilderBase $builder): string;
- public abstract function addFormFields(&$array);
+ public abstract function toArray(): array;
+
+ public abstract function addFormFields(array &$array): void;
+
+ public function internalId(): string
+ {
+ return $this->internalId;
+ }
/*
*
@@ -28,15 +43,15 @@ abstract class BootEntry
* Return a BootEntry instance from the serialized data.
*
* @param string $module module this entry belongs to, or special values .script/.exec
- * @param string $jsonString serialized entry data
- * @return BootEntry|null instance representing boot entry, null on error
+ * @param string $data serialized entry data
+ * @return ?BootEntry instance representing boot entry, null on error
*/
- public static function fromJson($module, $data)
+ public static function fromJson(string $module, string $data): ?BootEntry
{
- if ($module{0} !== '.') {
+ if ($module[0] !== '.') {
// Hook from other module
$hook = Hook::loadSingle($module, 'ipxe-bootentry');
- if ($hook === false) {
+ if ($hook === null) {
error_log('Module ' . $module . ' doesnt have an ipxe-bootentry hook');
return null;
}
@@ -45,26 +60,29 @@ abstract class BootEntry
return null;
return $ret->getBootEntry($data);
}
- if (is_string($data)) {
- $data = json_decode($data, true);
- }
+ $data = json_decode($data, true);
+ if (!is_array($data))
+ return null;
if ($module === '.script') {
return new CustomBootEntry($data);
}
if ($module === '.exec') {
return new StandardBootEntry($data);
}
+ if ($module === '.special') {
+ return new SpecialBootEntry($data);
+ }
return null;
}
- public static function forMenu($menuId)
+ public static function forMenu(int $menuId): MenuBootEntry
{
return new MenuBootEntry($menuId);
}
- public static function newStandardBootEntry($initData, $efi = false, $arch = false)
+ public static function newStandardBootEntry($initData, $efi = false, $arch = false, string $internalId = ''): ?StandardBootEntry
{
- $ret = new StandardBootEntry($initData, $efi, $arch);
+ $ret = new StandardBootEntry($initData, $efi, $arch, $internalId);
$list = [];
if ($ret->arch() !== self::EFI) {
$list[] = self::BIOS;
@@ -82,9 +100,9 @@ abstract class BootEntry
return $ret;
}
- public static function newCustomBootEntry($initData)
+ public static function newCustomBootEntry($initData): ?CustomBootEntry
{
- if (empty($initData['script']))
+ if (!is_array($initData) || empty($initData))
return null;
return new CustomBootEntry($initData);
}
@@ -92,15 +110,14 @@ abstract class BootEntry
/**
* Return a BootEntry instance from database with the given id.
*
- * @param string $id
- * @return BootEntry|null|false false == unknown id, null = unknown entry type, BootEntry instance on success
+ * @return ?BootEntry null = unknown entry type, BootEntry instance on success
*/
- public static function fromDatabaseId($id)
+ public static function fromDatabaseId(string $id): ?BootEntry
{
$row = Database::queryFirst("SELECT module, data FROM serversetup_bootentry
WHERE entryid = :id LIMIT 1", ['id' => $id]);
if ($row === false)
- return false;
+ return null;
return self::fromJson($row['module'], $row['data']);
}
@@ -110,11 +127,11 @@ abstract class BootEntry
*
* @return BootEntry[] all existing BootEntries
*/
- public static function getAll()
+ public static function getAll(): array
{
- $res = Database::simpleQuery("SELECT entryid, data FROM serversetup_bootentry");
+ $res = Database::simpleQuery("SELECT entryid, module, data FROM serversetup_bootentry");
$ret = [];
- while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ foreach ($res as $row) {
$tmp = self::fromJson($row['module'], $row['data']);
if ($tmp === null)
continue;
@@ -135,13 +152,16 @@ class StandardBootEntry extends BootEntry
* @var ExecData same for EFI
*/
protected $efi;
-
- protected $arch; // Constants below
+ /**
+ * @var ?string BootEntry Constants above
+ */
+ protected $arch;
const KEYS = ['executable', 'initRd', 'commandLine', 'replace', 'imageFree', 'autoUnload', 'resetConsole', 'dhcpOptions'];
- public function __construct($data, $efi = false, $arch = false)
+ public function __construct($data, $efi = false, ?string $arch = null, string $internalId = '')
{
+ parent::__construct($internalId);
$this->pcbios = new ExecData();
$this->efi = new ExecData();
if ($data instanceof PxeSection) {
@@ -214,10 +234,7 @@ class StandardBootEntry extends BootEntry
}
}
- /**
- * @param PxeSection $data
- */
- private function fromPxeMenu($data)
+ private function fromPxeMenu(PxeSection $data): void
{
$bios = $this->pcbios;
$bios->executable = $data->kernel;
@@ -241,12 +258,12 @@ class StandardBootEntry extends BootEntry
$bios->commandLine = trim(preg_replace('/\s+/', ' ', $bios->commandLine));
}
- public function arch()
+ public function arch(): ?string
{
return $this->arch;
}
- public function supportsMode($mode)
+ public function supportsMode(string $mode): bool
{
if ($mode === $this->arch || $this->arch === BootEntry::AGNOSTIC)
return true;
@@ -257,77 +274,16 @@ class StandardBootEntry extends BootEntry
return false;
}
- public function toScript($failLabel, $mode)
+ public function toScript(ScriptBuilderBase $builder): string
{
- if (!$this->supportsMode($mode)) {
- return "prompt Entry doesn't have an executable for mode $mode\n";
- }
- if ($this->arch === BootEntry::AGNOSTIC || $mode == BootEntry::BIOS) {
- $entry = $this->pcbios;
- } else {
- $entry = $this->efi;
- }
- $entry->sanitize();
-
- $script = '';
- if ($entry->resetConsole) {
- $script .= "console ||\n";
- }
- if ($entry->imageFree) {
- $script .= "imgfree ||\n";
- }
- foreach ($entry->dhcpOptions as $opt) {
- if (empty($opt['value'])) {
- $val = '${}';
- } else {
- if (empty($opt['hex'])) {
- $val = bin2hex($opt['value']);
- } else {
- $val = $opt['value'];
- }
- preg_match_all('/[0-9a-f]{2}/', $val, $out);
- $val = implode(':', $out[0]);
- }
- $script .= 'set net${idx}/' . $opt['opt'] . ':hex ' . $val
- . ' || prompt Cannot override DHCP server option ' . $opt['opt'] . ". Press any key to continue anyways.\n";
- }
- $initrds = [];
- if (!empty($entry->initRd)) {
- foreach (array_values($entry->initRd) as $i => $initrd) {
- if (empty($initrd))
- continue;
- $script .= "initrd --name initrd$i $initrd || goto $failLabel\n";
- $initrds[] = "initrd$i";
- }
- }
- $script .= "boot ";
- if ($entry->autoUnload) {
- $script .= "-a ";
- }
- if ($entry->replace) {
- $script .= "-r ";
- }
- $script .= $entry->executable;
- if (!empty($initrds)) {
- if ($mode === BootEntry::BIOS) {
- $script .= " initrd=" . implode(',', $initrds);
- } else {
- foreach ($initrds as $initrd) {
- $script .= " initrd=$initrd";
- }
- }
- }
- if (!empty($entry->commandLine)) {
- $script .= ' ' . $entry->commandLine;
- }
- $script .= " || goto $failLabel\n";
- if ($entry->resetConsole) {
- $script .= "goto start ||\n";
- }
- return $script;
+ if ($this->arch === BootEntry::AGNOSTIC) // Same as below, could construct fall-through but this is more clear
+ return $builder->execDataToScript($this->pcbios, null, null);
+ return $builder->execDataToScript(null,
+ $this->supportsMode(BootEntry::BIOS) ? $this->pcbios : null,
+ $this->supportsMode(BootEntry::EFI) ? $this->efi : null);
}
- public function addFormFields(&$array)
+ public function addFormFields(array &$array): void
{
$array[$this->arch . '_selected'] = 'selected';
$array['entries'][] = $this->pcbios->toFormFields(BootEntry::BIOS);
@@ -335,7 +291,10 @@ class StandardBootEntry extends BootEntry
$array['exec_checked'] = 'checked';
}
- public function toArray()
+ /**
+ * @return array{PCBIOS: array, EFI: array, arch: string}
+ */
+ public function toArray(): array
{
return [
BootEntry::BIOS => $this->pcbios->toArray(),
@@ -347,65 +306,118 @@ class StandardBootEntry extends BootEntry
class CustomBootEntry extends BootEntry
{
- protected $script;
+ /**
+ * @var string iPXE
+ */
+ protected $ipxe = '';
+
+ protected $bash;
+
+ protected $grub;
public function __construct($data)
{
- if (is_array($data) && isset($data['script'])) {
- $this->script = $data['script'];
+ parent::__construct('custom');
+ if (is_array($data)) {
+ $this->ipxe = $data['script'] ?? ''; // LEGACY
+ foreach (['bash', 'grub'] as $key) {
+ $this->{$key} = $data[$key] ?? '';
+ }
}
}
- public function supportsMode($mode)
+ public function supportsMode(string $mode): bool
{
return true;
}
- public function toScript($failLabel, $mode)
+ public function toScript(ScriptBuilderBase $builder): string
{
- return str_replace('%fail%', $failLabel, $this->script) . "\n";
+ // TODO: A (very) simple translator for oneliners like "poweroff || goto fail" maybe?
+ if ($builder instanceof ScriptBuilderIpxe)
+ return $this->ipxe;
+ if ($builder instanceof ScriptBuilderBash)
+ return $this->bash;
+ if ($builder instanceof ScriptBuilderGrub)
+ return $this->grub;
+ return '';
}
- public function addFormFields(&$array)
+ public function addFormFields(array &$array): void
{
$array['entry'] = [
- 'script' => $this->script,
+ 'script' => $this->ipxe,
];
$array['script_checked'] = 'checked';
}
- public function toArray()
+ /**
+ * @return array{script: string}
+ */
+ public function toArray(): array
{
- return ['script' => $this->script];
+ return ['script' => $this->ipxe];
}
}
class MenuBootEntry extends BootEntry
{
+ /** @var int */
protected $menuId;
- public function __construct($menuId)
+ public function __construct(int $menuId)
{
+ parent::__construct('menu-' . $menuId);
$this->menuId = $menuId;
}
- public function supportsMode($mode)
+ public function supportsMode(string $mode): bool
{
return true;
}
- public function toScript($failLabel, $mode)
+ public function toScript(ScriptBuilderBase $builder): string
{
- return 'chain -ar ${self}&menuid=' . $this->menuId . ' || goto ' . $failLabel . "\n";
+ $menu = IPxeMenu::get($this->menuId, true);
+ return $builder->menuToScript($menu);
}
- public function toArray()
+ public function toArray(): array
{
return [];
}
- public function addFormFields(&$array)
+ public function addFormFields(array &$array): void
{
}
}
+class SpecialBootEntry extends BootEntry
+{
+
+ private $type;
+
+ public function __construct($type)
+ {
+ $this->type = $type['type'] ?? $type;
+ parent::__construct('special-' . $this->type);
+ }
+
+ public function supportsMode(string $mode): bool
+ {
+ return true;
+ }
+
+ public function toScript(ScriptBuilderBase $builder): string
+ {
+ return $builder->getSpecial($this->type);
+ }
+
+ public function toArray(): array
+ {
+ return [];
+ }
+
+ public function addFormFields(array &$array): void { }
+
+}