summaryrefslogtreecommitdiffstats
path: root/modules-available/serversetup-bwlp-ipxe/inc/ipxe.inc.php
diff options
context:
space:
mode:
Diffstat (limited to 'modules-available/serversetup-bwlp-ipxe/inc/ipxe.inc.php')
-rw-r--r--modules-available/serversetup-bwlp-ipxe/inc/ipxe.inc.php154
1 files changed, 74 insertions, 80 deletions
diff --git a/modules-available/serversetup-bwlp-ipxe/inc/ipxe.inc.php b/modules-available/serversetup-bwlp-ipxe/inc/ipxe.inc.php
index 29885588..5e0531ab 100644
--- a/modules-available/serversetup-bwlp-ipxe/inc/ipxe.inc.php
+++ b/modules-available/serversetup-bwlp-ipxe/inc/ipxe.inc.php
@@ -12,13 +12,13 @@ class IPxe
* Import all IP-Range based pxe menus from the given directory.
*
* @param string $configPath The pxelinux.cfg path where to look for menu files in hexadecimal IP format.
- * @return Number of menus imported
+ * @return int Number of menus imported
*/
- public static function importSubnetPxeMenus($configPath)
+ public static function importSubnetPxeMenus(string $configPath): int
{
$res = Database::simpleQuery('SELECT menuid, entryid FROM serversetup_menuentry ORDER BY sortval ASC');
$menus = [];
- while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ foreach ($res as $row) {
if (!isset($menus[$row['menuid']])) {
$menus[(int)$row['menuid']] = [];
}
@@ -40,7 +40,7 @@ class IPxe
WHERE startaddr >= :start AND endaddr <= :end", compact('start', 'end'));
$locations = [];
// Iterate over result, eliminate those that are dominated by others
- while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ foreach ($res as $row) {
foreach ($locations as &$loc) {
if ($row['startaddr'] <= $loc['startaddr'] && $row['endaddr'] >= $loc['endaddr']) {
$loc = false;
@@ -52,6 +52,10 @@ class IPxe
$locations[] = $row;
}
$menu = PxeLinux::parsePxeLinux($content, true);
+ if ($menu === null) {
+ error_log("Skipping empty pxelinux menu file $file");
+ continue;
+ }
// Insert all entries first, so we can get the list of entry IDs
$entries = [];
self::importPxeMenuEntries($menu, $entries);
@@ -83,10 +87,10 @@ class IPxe
} else {
error_log('Imported menu ' . $menu->title . ' is NEW, using for ' . count($locations) . ' locations.');
// Insert new menu
- $menuId = self::insertMenu($menu, 'Auto Imported', false, 0, [], []);
- if ($menuId === false)
+ $menuId = self::insertMenu($menu, 'Auto Imported', null, 0, [], []);
+ if ($menuId === null)
continue;
- $menus[(int)$menuId] = $entries;
+ $menus[$menuId] = $entries;
$importCount++;
}
foreach ($locations as $loc) {
@@ -103,20 +107,20 @@ class IPxe
return $importCount;
}
- public static function importLegacyMenu($force = false)
+ public static function importLegacyMenu(bool $force = false): bool
{
// See if anything is there
if (!$force && false !== Database::queryFirst("SELECT menuentryid FROM serversetup_menuentry LIMIT 1"))
return false; // Already exists
// Now create the default entry
self::createDefaultEntries();
- $prepend = ['bwlp-default' => false, 'localboot' => false];
+ $prepend = ['bwlp-default' => null, 'localboot' => null];
$defaultLabel = 'bwlp-default';
$menuTitle = 'bwLehrpool Bootauswahl';
$pxeConfig = '';
$timeoutSecs = 60;
- // Try to import any customization
- $oldMenu = Property::getBootMenu();
+ // Try to import any customization of the legacy PXELinux menu (despite the property name hinting at iPXE)
+ $oldMenu = json_decode(Property::get('ipxe-menu'), true);
if (is_array($oldMenu)) {
//
if (isset($oldMenu['timeout'])) {
@@ -136,47 +140,45 @@ class IPxe
}
}
$append = [
- '',
- 'bwlp-default-dbg' => false,
- '',
- 'poweroff' => false,
+ new PxeSection(null),
+ 'bwlp-default-dbg' => null,
+ new PxeSection(null),
+ 'poweroff' => null,
];
- return self::insertMenu(PxeLinux::parsePxeLinux($pxeConfig, false), $menuTitle, $defaultLabel, $timeoutSecs, $prepend, $append);
+ self::insertMenu(PxeLinux::parsePxeLinux($pxeConfig, false), $menuTitle, $defaultLabel, $timeoutSecs, $prepend, $append);
+ return !empty($pxeConfig);
}
/**
- * @param PxeMenu $pxeMenu
- * @param string $menuTitle
- * @param string|false $defaultLabel Fallback for the default label, if PxeMenu doesn't set one
+ * @param ?string $defaultLabel Fallback for the default label, if PxeMenu doesn't set one
* @param int $defaultTimeoutSeconds Default timeout, if PxeMenu doesn't set one
- * @param array $prepend
- * @param array $append
- * @return int|false
+ * @param (?PxeSection)[] $prepend
+ * @param (?PxeSection)[] $append
+ * @return ?int ID of newly created menu, or null on error, e.g. if the menu is empty
*/
- public static function insertMenu($pxeMenu, $menuTitle, $defaultLabel, $defaultTimeoutSeconds, $prepend, $append)
+ public static function insertMenu(?PxeMenu $pxeMenu, string $menuTitle, ?string $defaultLabel, int $defaultTimeoutSeconds,
+ array $prepend, array $append): ?int
{
$timeoutMs = [];
$menuEntries = $prepend;
- settype($menuEntries, 'array');
- if (!empty($pxeMenu)) {
- $pxe =& $pxeMenu;
- if (!empty($pxe->title)) {
- $menuTitle = $pxe->title;
+ if ($pxeMenu !== null) {
+ if (!empty($pxeMenu->title)) {
+ $menuTitle = $pxeMenu->title;
}
- if ($pxe->timeoutLabel !== null && $pxe->hasLabel($pxe->timeoutLabel)) {
- $defaultLabel = $pxe->timeoutLabel;
- } elseif ($pxe->hasLabel($pxe->default)) {
- $defaultLabel = $pxe->default;
+ if ($pxeMenu->timeoutLabel !== null && $pxeMenu->hasLabel($pxeMenu->timeoutLabel)) {
+ $defaultLabel = $pxeMenu->timeoutLabel;
+ } elseif ($pxeMenu->hasLabel($pxeMenu->default)) {
+ $defaultLabel = $pxeMenu->default;
}
- $timeoutMs[] = $pxe->timeoutMs;
- $timeoutMs[] = $pxe->totalTimeoutMs;
- self::importPxeMenuEntries($pxe, $menuEntries);
+ $timeoutMs[] = $pxeMenu->timeoutMs;
+ $timeoutMs[] = $pxeMenu->totalTimeoutMs;
+ self::importPxeMenuEntries($pxeMenu, $menuEntries);
}
- if (is_array($append)) {
+ if (!empty($append)) {
$menuEntries += $append;
}
if (empty($menuEntries))
- return false;
+ return null;
// Make menu
$timeoutMs = array_filter($timeoutMs, function($x) { return is_int($x) && $x > 0; });
if (empty($timeoutMs)) {
@@ -195,25 +197,29 @@ class IPxe
// Figure out entryid for default label
// Fiddly diddly way of getting the mangled entryid for the wanted pxe menu label
$defaultEntryId = false;
+ $fallbackDefault = false;
foreach ($menuEntries as $entryId => $section) {
- if ($section instanceof PxeSection) {
- if ($section->isDefault) {
- $defaultEntryId = $entryId;
- break;
- }
- if ($section->label === $defaultLabel) {
- $defaultEntryId = $entryId;
- }
+ if ($section === null)
+ continue;
+ if ($section->isDefault) {
+ $defaultEntryId = $entryId;
+ break;
+ }
+ if ($section->label === $defaultLabel) {
+ $defaultEntryId = $entryId;
+ }
+ if ($fallbackDefault === false && !empty($entryId)) {
+ $fallbackDefault = $entryId;
}
}
if ($defaultEntryId === false) {
- $defaultEntryId = array_keys($menuEntries)[0];
+ $defaultEntryId = $fallbackDefault;
}
// Link boot entries to menu
$defaultMenuEntryId = null;
$order = 1000;
foreach ($menuEntries as $entryId => $entry) {
- if (is_string($entry)) {
+ if ($entry !== null && $entry->isTextOnly()) {
// Gap entry
Database::exec("INSERT INTO serversetup_menuentry
(menuid, entryid, hotkey, title, hidden, sortval, plainpass, md5pass)
@@ -221,7 +227,7 @@ class IPxe
'menuid' => $menuId,
'entryid' => null,
'hotkey' => '',
- 'title' => self::sanitizeIpxeString($entry),
+ 'title' => self::sanitizeIpxeString($entry->title),
'hidden' => 0,
'sortval' => $order += 100,
]);
@@ -232,7 +238,7 @@ class IPxe
continue;
$data['pass'] = '';
$data['hidden'] = 0;
- if ($entry instanceof PxeSection) {
+ if ($entry !== null) {
$data['hidden'] = (int)$entry->isHidden;
// Prefer explicit data from this imported menu over the defaults
$title = self::sanitizeIpxeString($entry->title);
@@ -243,7 +249,7 @@ class IPxe
$data['hotkey'] = $entry->hotkey;
}
if (!empty($entry->passwd)) {
- // Most likely it's a hash so we cannot recover; ask people to reset
+ // Most likely it's a hash, so we cannot recover; ask people to reset
$data['pass'] ='please_reset';
}
}
@@ -268,36 +274,28 @@ class IPxe
/**
* Import only the bootentries from the given PXELinux menu
- * @param PxeMenu $pxe
- * @param array $menuEntries Where to append the generated menu items to
+ *
+ * @param PxeSection[] $menuEntries Where to append the generated menu items to
*/
- public static function importPxeMenuEntries($pxe, &$menuEntries)
+ public static function importPxeMenuEntries(PxeMenu $pxe, array &$menuEntries): void
{
if (self::$allEntries === false) {
self::$allEntries = BootEntry::getAll();
}
foreach ($pxe->sections as $section) {
- if ($section->localBoot !== false || preg_match('/chain\.c32$/i', $section->kernel)) {
+ if ($section->isLocalboot()) {
$menuEntries['localboot'] = $section;
continue;
}
- if ($section->label === null) {
- if (!$section->isHidden && !empty($section->title)) {
- $menuEntries[] = $section->title;
- }
- continue;
- }
- if (empty($section->kernel)) {
- if (!$section->isHidden && !empty($section->title)) {
- $menuEntries[] = $section->title;
- }
+ if ($section->isTextOnly()) {
+ $menuEntries[] = $section;
continue;
}
$label = self::cleanLabelFixLocal($section);
$entry = self::pxe2BootEntry($section);
if ($entry === null)
continue; // Error? Ignore
- if ($label !== false || ($label = array_search($entry, self::$allEntries))) {
+ if ($label !== false || ($label = array_search($entry, self::$allEntries)) !== false) {
// Exact Duplicate, Do Nothing
error_log('Ignoring duplicate boot entry ' . $section->label . ' (' . $section->kernel . ')');
} else {
@@ -321,7 +319,7 @@ class IPxe
Database::exec('INSERT IGNORE INTO serversetup_bootentry (entryid, module, hotkey, title, builtin, data)
VALUES (:label, :module, :hotkey, :title, 0, :data)', [
'label' => $label,
- 'module' => ($entry instanceof \StandardBootEntry) ? '.exec' : '.script',
+ 'module' => ($entry instanceof StandardBootEntry) ? '.exec' : '.script',
'hotkey' => $hotkey,
'title' => $title,
'data' => json_encode($data),
@@ -408,10 +406,9 @@ class IPxe
* Also it patches the entry if it's referencing the local bwlp install
* but with different options.
*
- * @param PxeSection $section
* @return string|false existing label if match, false otherwise
*/
- private static function cleanLabelFixLocal($section)
+ private static function cleanLabelFixLocal(PxeSection $section)
{
$myip = Property::getServerIp();
// Detect our "old" entry types
@@ -434,10 +431,9 @@ class IPxe
}
/**
- * @param PxeSection $section
* @return BootEntry|null The according boot entry, null if it's unparsable
*/
- private static function pxe2BootEntry($section)
+ private static function pxe2BootEntry(PxeSection $section): ?BootEntry
{
if (preg_match('/(pxechain\.com|pxechn\.c32)$/i', $section->kernel)) {
// Chaining -- create script
@@ -466,7 +462,7 @@ class IPxe
$script .= "set netX/{$opt}:{$type} {$args[$i]} || goto %fail%\n";
}
}
- } elseif ($arg{0} === '-') {
+ } elseif ($arg[0] === '-') {
continue;
} elseif ($file === false) {
$file = self::parseFile($arg);
@@ -496,11 +492,8 @@ class IPxe
/**
* Parse PXELINUX file notion. Basically, turn
* server::file into tftp://server/file.
- *
- * @param string $file
- * @return string
*/
- private static function parseFile($file)
+ private static function parseFile(string $file): string
{
if (preg_match(',^([^:/]+)::(.*)$,', $file, $out)) {
return 'tftp://' . $out[1] . '/' . $out[2];
@@ -508,12 +501,12 @@ class IPxe
return $file;
}
- public static function sanitizeIpxeString($string)
+ public static function sanitizeIpxeString(string $string): string
{
return str_replace(['&', '|', ';', '$', "\r", "\n"], ['+', '/', ':', 'S', ' ', ' '], $string);
}
- public static function makeMd5Pass($plainpass, $salt)
+ public static function makeMd5Pass(string $plainpass, string $salt): string
{
if (empty($plainpass))
return '';
@@ -528,15 +521,16 @@ class IPxe
* remove any occurrence of either "option" or "option=something". If the argument starts with a
* '+', it will be added to the command line after removing the '+'. If the argument starts with any
* other character, it will also be added to the command line.
+ *
* @param string $cmdLine command line to modify
- * @param string $modifier modification string of space separated arguments
+ * @param string $modifier modification string of space separated arguments
* @return string the modified command line
*/
- public static function modifyCommandLine($cmdLine, $modifier)
+ public static function modifyCommandLine(string $cmdLine, string $modifier): string
{
$items = preg_split('/\s+/', $modifier, -1, PREG_SPLIT_NO_EMPTY);
foreach ($items as $item) {
- if ($item{0} === '-') {
+ if ($item[0] === '-') {
$item = preg_quote(substr($item, 1), '/');
$cmdLine = preg_replace('/(^|\s)' . $item . '(=\S*)?($|\s)/', ' ', $cmdLine);
} else {