From 2d64b9d8f57f28456eb27c4aed2dde26201b6770 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Tue, 12 Feb 2019 14:35:49 +0100 Subject: [serversetup-bwlp] Auto-import of old PXELinux config on bootup Also minor improvements to UI and structuring --- .../serversetup-bwlp/inc/bootentry.inc.php | 3 +- .../serversetup-bwlp/inc/ipxe.inc.php | 79 ++++++++++++++++++---- .../serversetup-bwlp/inc/pxelinux.inc.php | 40 +++++++++++ 3 files changed, 109 insertions(+), 13 deletions(-) (limited to 'modules-available/serversetup-bwlp/inc') diff --git a/modules-available/serversetup-bwlp/inc/bootentry.inc.php b/modules-available/serversetup-bwlp/inc/bootentry.inc.php index 010b660c..69adffd3 100644 --- a/modules-available/serversetup-bwlp/inc/bootentry.inc.php +++ b/modules-available/serversetup-bwlp/inc/bootentry.inc.php @@ -95,7 +95,7 @@ class StandardBootEntry extends BootEntry protected $replace; protected $autoUnload; protected $resetConsole; - protected $arch; // true == available, false == not available + protected $arch; // Constants below const BIOS = 'PCBIOS'; // Only valid for legacy BIOS boot const EFI = 'EFI'; // Only valid for EFI boot @@ -105,6 +105,7 @@ class StandardBootEntry extends BootEntry public function __construct($data = false) { if ($data instanceof PxeSection) { + // Gets arrayfied below $this->executable = $data->kernel; $this->initRd = $data->initrd; $this->commandLine = ' ' . str_replace('vga=current', '', $data->append) . ' '; diff --git a/modules-available/serversetup-bwlp/inc/ipxe.inc.php b/modules-available/serversetup-bwlp/inc/ipxe.inc.php index d5bbb4b2..d34839f0 100644 --- a/modules-available/serversetup-bwlp/inc/ipxe.inc.php +++ b/modules-available/serversetup-bwlp/inc/ipxe.inc.php @@ -3,8 +3,16 @@ 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 + */ public static function importPxeMenus($configPath) { + $importCount = 0; + $menus = []; foreach (glob($configPath . '/*', GLOB_NOSORT) as $file) { if (!is_file($file) || !preg_match('~/[A-F0-9]{1,8}$~', $file)) continue; @@ -29,14 +37,53 @@ class IPxe unset($loc); $locations[] = $row; } - $menuId = self::insertMenu($content, 'Imported', false, 0, [], []); + $menu = PxeLinux::parsePxeLinux($content); + $key = $menu->hash(true); + if (isset($menus[$key])) { + $menuId = $menus[$key]; + $defId = null; + // Figure out the default label, get it's label name + foreach ($menu->sections as $section) { + if ($section->isDefault) { + $defId = $section; + } elseif ($defId === null && $section->label === $menu->timeoutLabel) { + $defId = $section; + } + } + if ($defId !== null) { + $defId = self::cleanLabelFixLocal($defId); + // Confirm it actually exists (it should since the menu seems identical) and get menuEntryId + $me = Database::queryFirst('SELECT m.defaultentryid, me.menuentryid FROM serversetup_bootentry be + INNER JOIN serversetup_menuentry me ON (be.entryid = me.entryid) + INNER JOIN serversetup_menu m ON (m.menuid = me.menuid) + WHERE be.entryid = :id AND me.menuid = :menuid', + ['id' => $defId, 'menuid' => $menuId]); + if ($me === false || $me['defaultentryid'] == $me['menuentryid']) { + $defId = null; // Not found, or is already default - don't override if it's the same + } else { + $defId = $me['menuentryid']; + } + } + } else { + $menuId = self::insertMenu($menu, 'Imported', false, 0, [], []); + $menus[$key] = $menuId; + $defId = null; + $importCount++; + } if ($menuId === false) continue; foreach ($locations as $loc) { - Database::exec('INSERT IGNORE INTO serversetup_menu_x_location (menuid, locationid) - VALUES (:menuid, :locationid)', ['menuid' => $menuId, 'locationid' => $loc['locationid']]); + if ($loc === false) + continue; + Database::exec('INSERT IGNORE INTO serversetup_menu_location (menuid, locationid, defaultentryid) + VALUES (:menuid, :locationid, :def)', [ + 'menuid' => $menuId, + 'locationid' => $loc['locationid'], + 'def' => $defId, + ]); } } + return $importCount; } public static function importLegacyMenu($force = false) @@ -76,16 +123,25 @@ class IPxe '', 'poweroff' => false, ]; - return self::insertMenu($pxeConfig, $menuTitle, $defaultLabel, $timeoutSecs, $prepend, $append); + return self::insertMenu(PxeLinux::parsePxeLinux($pxeConfig), $menuTitle, $defaultLabel, $timeoutSecs, $prepend, $append); } - private static function insertMenu($pxeConfig, $menuTitle, $defaultLabel, $defaultTimeoutSeconds, $prepend, $append) + /** + * @param PxeMenu $pxeMenu + * @param string $menuTitle + * @param string|false $defaultLabel + * @param $defaultTimeoutSeconds + * @param $prepend + * @param $append + * @return bool|int + */ + private static function insertMenu($pxeMenu, $menuTitle, $defaultLabel, $defaultTimeoutSeconds, $prepend, $append) { $timeoutMs = []; $menuEntries = $prepend; settype($menuEntries, 'array'); - if (!empty($pxeConfig)) { - $pxe = PxeLinux::parsePxeLinux($pxeConfig); + if (!empty($pxeMenu)) { + $pxe =& $pxeMenu; if (!empty($pxe->title)) { $menuTitle = $pxe->title; } @@ -95,11 +151,10 @@ class IPxe $timeoutMs[] = $pxe->timeoutMs; $timeoutMs[] = $pxe->totalTimeoutMs; foreach ($pxe->sections as $section) { - if ($section->localBoot || preg_match('/chain.c32$/i', $section->kernel)) { + if ($section->localBoot || preg_match('/chain\.c32$/i', $section->kernel)) { $menuEntries['localboot'] = 'localboot'; continue; } - $section->mangle(); if ($section->label === null) { if (!$section->isHidden && !empty($section->title)) { $menuEntries[] = $section->title; @@ -221,7 +276,7 @@ class IPxe 'data' => json_encode([ 'executable' => '/boot/default/kernel', 'initRd' => '/boot/default/initramfs-stage31', - 'commandLine' => 'slxbase=boot/default quiet splash loglevel=5 rd.systemd.show_status=auto ${ipappend1} ${ipappend2}', + 'commandLine' => 'slxbase=boot/default quiet splash loglevel=5 rd.systemd.show_status=auto intel_iommu=igfx_off ${ipappend1} ${ipappend2}', 'replace' => true, 'autoUnload' => true, 'resetConsole' => true, @@ -235,7 +290,7 @@ class IPxe 'data' => json_encode([ 'executable' => '/boot/default/kernel', 'initRd' => '/boot/default/initramfs-stage31', - 'commandLine' => 'slxbase=boot/default loglevel=7 ${ipappend1} ${ipappend2}', + 'commandLine' => 'slxbase=boot/default loglevel=7 intel_iommu=igfx_off ${ipappend1} ${ipappend2}', 'replace' => true, 'autoUnload' => true, 'resetConsole' => true, @@ -314,7 +369,7 @@ class IPxe */ private static function pxe2BootEntry($section) { - if (preg_match('/(pxechain.com|pxechn.c32)$/i', $section->kernel)) { + if (preg_match('/(pxechain\.com|pxechn\.c32)$/i', $section->kernel)) { // Chaining -- create script $args = preg_split('/\s+/', $section->append); $script = ''; diff --git a/modules-available/serversetup-bwlp/inc/pxelinux.inc.php b/modules-available/serversetup-bwlp/inc/pxelinux.inc.php index db3dac4b..1d022fef 100644 --- a/modules-available/serversetup-bwlp/inc/pxelinux.inc.php +++ b/modules-available/serversetup-bwlp/inc/pxelinux.inc.php @@ -86,6 +86,9 @@ class PxeLinux if ($section !== null) { $menu->sections[] = $section; } + foreach ($menu->sections as $section) { + $section->mangle(); + } return $menu; } @@ -131,6 +134,7 @@ class PxeLinux */ class PxeMenu { + /** * @var string menu title, shown at the top of the menu */ @@ -160,6 +164,40 @@ class PxeMenu * @var PxeSection[] list of sections the menu contains */ public $sections = []; + + public function hash($fuzzy) + { + $ctx = hash_init('md5'); + if (!$fuzzy) { + hash_update($ctx, $this->title); + hash_update($ctx, $this->timeoutLabel); + } + hash_update($ctx, $this->timeoutMs); + foreach ($this->sections as $section) { + if ($fuzzy) { + hash_update($ctx, mb_strtolower(preg_replace('/[^a-zA-Z0-9]/', '', $section->title))); + } else { + hash_update($ctx, $section->label); + hash_update($ctx, $section->title); + hash_update($ctx, $section->indent); + hash_update($ctx, $section->helpText); + hash_update($ctx, $section->isDefault); + hash_update($ctx, $section->hotkey); + } + hash_update($ctx, $section->kernel); + hash_update($ctx, $section->append); + hash_update($ctx, $section->ipAppend); + hash_update($ctx, $section->passwd); + hash_update($ctx, $section->isHidden); + hash_update($ctx, $section->isDisabled); + hash_update($ctx, $section->localBoot); + foreach ($section->initrd as $initrd) { + hash_update($ctx, $initrd); + } + } + return hash_final($ctx, false); + } + } /** @@ -170,6 +208,7 @@ class PxeMenu */ class PxeSection { + /** * @var string label used internally in PXEMENU definition to address this entry */ @@ -258,5 +297,6 @@ class PxeSection $this->initrd = []; } } + } -- cgit v1.2.3-55-g7522