diff options
6 files changed, 194 insertions, 78 deletions
diff --git a/modules-available/serversetup-bwlp/api.inc.php b/modules-available/serversetup-bwlp/api.inc.php index 36f9063c..52f30440 100644 --- a/modules-available/serversetup-bwlp/api.inc.php +++ b/modules-available/serversetup-bwlp/api.inc.php @@ -1,5 +1,7 @@ <?php +// TODO: Check if required arguments are given; if not, spit out according script (identical to what is embedded) + $BOOT_METHODS = [ 'EXIT' => 'exit 1', 'COMBOOT' => 'chain /tftp/chain.c32 hd0', @@ -22,12 +24,14 @@ $platform = strtoupper(Request::any('platform', 'PCBIOS', 'string')); $localboot = false; $model = false; if ($uuid !== false && Module::get('statistics') !== false) { + // If we have the machine table, we rather try to look up the system model from there, using the UUID $row = Database::queryFirst('SELECT systemmodel FROM machine WHERE machineuuid = :uuid', ['uuid' => $uuid]); if ($row !== false && !empty($row['systemmodel'])) { $model = $row['systemmodel']; } } if ($model === false) { + // Otherwise use what iPXE sent us function modfilt($str) { if (empty($str) || preg_match('/product\s+name|be\s+filled|unknown|default\s+string/i', $str)) @@ -70,6 +74,8 @@ if (isset($BOOT_METHODS[$localboot])) { $BOOT_METHODS = array_reverse($BOOT_METHODS); } +// TODO: Feature check for our own iPXE extensions, stay compatible to stock iPXE + $output = <<<HERE #!ipxe @@ -139,7 +145,7 @@ console --left 55 --top 88 --right 63 --bottom 64 --quick --keep --picture bg-me HERE; -$output .= $menu->getMenuDefinition('target'); +$output .= $menu->getMenuDefinition('target', $platform); $output .= <<<HERE @@ -151,7 +157,9 @@ goto start HERE; -$output .= $menu->getItemsCode(); +$output .= $menu->getItemsCode($platform); + +// TODO: Work out memtest stuff. Needs to be put on server (install/update script) -- PCBIOS only? Chain EFI -> BIOS? /* :i1 diff --git a/modules-available/serversetup-bwlp/inc/bootentry.inc.php b/modules-available/serversetup-bwlp/inc/bootentry.inc.php index 930f4413..010b660c 100644 --- a/modules-available/serversetup-bwlp/inc/bootentry.inc.php +++ b/modules-available/serversetup-bwlp/inc/bootentry.inc.php @@ -14,7 +14,9 @@ abstract class BootEntry } } - public abstract function toScript($failLabel); + public abstract function supportsMode($mode); + + public abstract function toScript($failLabel, $mode); public abstract function toArray(); @@ -46,9 +48,19 @@ abstract class BootEntry public static function newStandardBootEntry($initData) { - if (empty($initData['executable'])) - return null; - return new StandardBootEntry($initData); + $ret = new StandardBootEntry($initData); + $list = []; + if ($ret->arch() !== StandardBootEntry::EFI) { + $list[] = StandardBootEntry::BIOS; + } + if ($ret->arch() === StandardBootEntry::EFI || $ret->arch() === StandardBootEntry::BOTH) { + $list[] = StandardBootEntry::EFI; + } + foreach ($list as $mode) { + if (empty($initData['executable'][$mode])) + return null; + } + return $ret; } public static function newCustomBootEntry($initData) @@ -83,6 +95,12 @@ class StandardBootEntry extends BootEntry protected $replace; protected $autoUnload; protected $resetConsole; + protected $arch; // true == available, false == not available + + const BIOS = 'PCBIOS'; // Only valid for legacy BIOS boot + const EFI = 'EFI'; // Only valid for EFI boot + const BOTH = 'PCBIOS-EFI'; // Supports both via distinct entry + const AGNOSTIC = 'agnostic'; // Supports both via same entry (PCBIOS entry) public function __construct($data = false) { @@ -109,38 +127,70 @@ class StandardBootEntry extends BootEntry } else { parent::__construct($data); } + // Convert legacy DB format + foreach (['executable', 'initRd', 'commandLine', 'replace', 'autoUnload', 'resetConsole'] as $key) { + if (!is_array($this->{$key})) { + $this->{$key} = [ 'PCBIOS' => $this->{$key}, 'EFI' => '' ]; + } + } + if ($this->arch === null) { + $this->arch = self::AGNOSTIC; + } + } + + public function arch() + { + return $this->arch; + } + + public function supportsMode($mode) + { + if ($mode === $this->arch || $this->arch === self::AGNOSTIC) + return true; + if ($mode === self::BIOS || $mode === self::EFI) { + return $this->arch === self::BOTH; + } + error_log('Unknown iPXE platform: ' . $mode); + return false; } - public function toScript($failLabel) + public function toScript($failLabel, $mode) { + if (!$this->supportsMode($mode)) { + return "prompt Entry doesn't have an executable for mode $mode\n"; + } + if ($this->arch === self::AGNOSTIC) { + $mode = self::BIOS; + } + $script = ''; - if ($this->resetConsole) { + if ($this->resetConsole[$mode]) { $script .= "console ||\n"; } - if (!empty($this->initRd)) { + if (!empty($this->initRd[$mode])) { $script .= "imgfree ||\n"; - if (!is_array($this->initRd)) { - $script .= "initrd {$this->initRd} || goto $failLabel\n"; + if (!is_array($this->initRd[$mode])) { + $script .= "initrd {$this->initRd[$mode]} || goto $failLabel\n"; } else { - foreach ($this->initRd as $initrd) { + foreach ($this->initRd[$mode] as $initrd) { $script .= "initrd $initrd || goto $failLabel\n"; } } } $script .= "boot "; - if ($this->autoUnload) { + if ($this->autoUnload[$mode]) { $script .= "-a "; } - if ($this->replace) { + if ($this->replace[$mode]) { $script .= "-r "; } - $script .= "{$this->executable}"; - $rdBase = basename($this->initRd); - if (!empty($this->commandLine)) { - $script .= " initrd=$rdBase {$this->commandLine}"; + $script .= $this->executable[$mode]; + $rdBase = basename($this->initRd[$mode]); + if (!empty($this->commandLine[$mode])) { + $script .= " initrd=$rdBase {$this->commandLine[$mode]}"; } $script .= " || goto $failLabel\n"; - if ($this->resetConsole) { + if ($this->resetConsole[$mode]) { $script .= "goto start ||\n"; } return $script; @@ -148,14 +198,19 @@ class StandardBootEntry extends BootEntry public function addFormFields(&$array) { - $array['entry'] = [ - 'executable' => $this->executable, - 'initRd' => $this->initRd, - 'commandLine' => $this->commandLine, - 'replace_checked' => $this->replace ? 'checked' : '', - 'autoUnload_checked' => $this->autoUnload ? 'checked' : '', - 'resetConsole_checked' => $this->resetConsole ? 'checked' : '', - ]; + $array[$this->arch . '_selected'] = 'selected'; + foreach ([self::BIOS, self::EFI] as $mode) { + $array['entries'][] = [ + 'is' . $mode => true, + 'mode' => $mode, + 'executable' => $this->executable[$mode], + 'initRd' => $this->initRd[$mode], + 'commandLine' => $this->commandLine[$mode], + 'replace_checked' => $this->replace[$mode] ? 'checked' : '', + 'autoUnload_checked' => $this->autoUnload[$mode] ? 'checked' : '', + 'resetConsole_checked' => $this->resetConsole[$mode] ? 'checked' : '', + ]; + } $array['exec_checked'] = 'checked'; } @@ -168,6 +223,7 @@ class StandardBootEntry extends BootEntry 'replace' => $this->replace, 'autoUnload' => $this->autoUnload, 'resetConsole' => $this->resetConsole, + 'arch' => $this->arch, ]; } } @@ -176,7 +232,12 @@ class CustomBootEntry extends BootEntry { protected $script; - public function toScript($failLabel) + public function supportsMode($mode) + { + return true; + } + + public function toScript($failLabel, $mode) { return str_replace('%fail%', $failLabel, $this->script) . "\n"; } diff --git a/modules-available/serversetup-bwlp/inc/ipxemenu.inc.php b/modules-available/serversetup-bwlp/inc/ipxemenu.inc.php index ed9f0986..56041c20 100644 --- a/modules-available/serversetup-bwlp/inc/ipxemenu.inc.php +++ b/modules-available/serversetup-bwlp/inc/ipxemenu.inc.php @@ -36,11 +36,11 @@ class IPxeMenu } } - public function getMenuDefinition($targetVar) + public function getMenuDefinition($targetVar, $mode) { $str = "menu {$this->title}\n"; foreach ($this->items as $item) { - $str .= $item->getMenuItemScript("m_{$this->menuid}", $this->defaultEntryId); + $str .= $item->getMenuItemScript("m_{$this->menuid}", $this->defaultEntryId, $mode); } if ($this->defaultEntryId === null) { $defaultLabel = "mx_{$this->menuid}_poweroff"; @@ -61,11 +61,11 @@ class IPxeMenu return $str; } - public function getItemsCode() + public function getItemsCode($mode) { $str = ''; foreach ($this->items as $item) { - $str .= $item->getBootEntryScript("m_{$this->menuid}", 'fail'); + $str .= $item->getBootEntryScript("m_{$this->menuid}", 'fail', $mode); $str .= "goto slx_menu\n"; } return $str; diff --git a/modules-available/serversetup-bwlp/inc/menuentry.inc.php b/modules-available/serversetup-bwlp/inc/menuentry.inc.php index 9d9d4163..03b860e8 100644 --- a/modules-available/serversetup-bwlp/inc/menuentry.inc.php +++ b/modules-available/serversetup-bwlp/inc/menuentry.inc.php @@ -58,8 +58,10 @@ class MenuEntry settype($this->menuentryid, 'int'); } - public function getMenuItemScript($lblPrefix, $requestedDefaultId) + public function getMenuItemScript($lblPrefix, $requestedDefaultId, $mode) { + if ($this->bootEntry !== null && !$this->bootEntry->supportsMode($mode)) + return ''; $str = 'item '; if ($this->gap) { $str .= '--gap '; @@ -81,9 +83,9 @@ class MenuEntry return $str . " || prompt Could not create menu item for {$lblPrefix}_{$this->menuentryid}\n"; } - public function getBootEntryScript($lblPrefix, $failLabel) + public function getBootEntryScript($lblPrefix, $failLabel, $mode) { - if ($this->bootEntry === null) + if ($this->bootEntry === null || !$this->bootEntry->supportsMode($mode)) return ''; $str = ":{$lblPrefix}_{$this->menuentryid}\n"; if (!empty($this->md5pass)) { @@ -94,7 +96,7 @@ class MenuEntry . "goto slx_pass_check || goto $failLabel\n" . ":{$lblPrefix}_ok\n"; } - return $str . $this->bootEntry->toScript($failLabel); + return $str . $this->bootEntry->toScript($failLabel, $mode); } /* diff --git a/modules-available/serversetup-bwlp/page.inc.php b/modules-available/serversetup-bwlp/page.inc.php index 25a31f06..ba2e5433 100644 --- a/modules-available/serversetup-bwlp/page.inc.php +++ b/modules-available/serversetup-bwlp/page.inc.php @@ -279,6 +279,7 @@ class Page_ServerSetup extends Page $entry->addFormFields($params); $params['title'] = $row['title']; $params['oldentryid'] = $params['entryid'] = $row['entryid']; + $params['builtin'] = $row['builtin']; } Render::addTemplate('ipxe-new-boot-entry', $params); } @@ -543,7 +544,7 @@ class Page_ServerSetup extends Page } if ($entry === null) { Message::addError('main.empty-field'); - return; + Util::redirect('?do=serversetup&show=bootentry'); } $params = [ 'entryid' => $newId, @@ -560,10 +561,10 @@ class Page_ServerSetup extends Page // Edit existing entry $params['oldid'] = $oldEntryId; Database::exec('UPDATE serversetup_bootentry SET entryid = :entryid, title = :title, data = :data - WHERE entryid = :oldid AND builtin = 0', $params); - // TODO: Redirect to &show=bootentry + WHERE entryid = :oldid', $params); Message::addSuccess('boot-entry-updated', $newId); } + Util::redirect('?do=serversetup&show=bootentry'); } } diff --git a/modules-available/serversetup-bwlp/templates/ipxe-new-boot-entry.html b/modules-available/serversetup-bwlp/templates/ipxe-new-boot-entry.html index fd9e1d72..33de1ee4 100644 --- a/modules-available/serversetup-bwlp/templates/ipxe-new-boot-entry.html +++ b/modules-available/serversetup-bwlp/templates/ipxe-new-boot-entry.html @@ -1,5 +1,11 @@ <h2>{{lang_newBootEntryHead}}</h2> +{{#builtin}} + <div class="alert alert-warning"> + {{lang_editBuiltinWarn}} + </div> +{{/builtin}} + <div class="panel panel-default"> <div class="panel-heading"> {{lang_bootEntryData}} @@ -33,47 +39,69 @@ </label> <input id="input-title" class="form-control" name="title" value="{{title}}" maxlength="100"> </div> + <div class="form-group"> + <label for="arch-selector"> + {{lang_archSelector}} + </label> + <select id="arch-selector" class="form-control" name="entry[arch]"> + <option value="agnostic" {{agnostic_selected}}>{{lang_archAgnostic}}</option> + <option value="PCBIOS" {{PCBIOS_selected}}>{{lang_biosOnly}}</option> + <option value="EFI" {{EFI_selected}}>{{lang_efiOnly}}</option> + <option value="PCBIOS-EFI" {{PCBIOS-EFI_selected}}>{{lang_archBoth}}</option> + </select> + </div> <div class="type-form" id="form-exec"> - <div class="form-group"> - <label for="input-ex"> - {{lang_imageToLoad}} - </label> - <input id="input-ex" class="form-control" name="entry[executable]" value="{{entry.executable}}"> - </div> - <div class="form-group"> - <label for="input-rd"> - {{lang_initRd}} - </label> - <input id="input-rd" class="form-control" name="entry[initRd]" value="{{entry.initRd}}"> - </div> - <div class="form-group"> - <label for="input-cmd"> - {{lang_commandLine}} - </label> - <input id="input-cmd" class="form-control" name="entry[commandLine]" - value="{{entry.commandLine}}"> - </div> - <div class="form-group"> - <div class="checkbox checkbox-inline"> - <input id="exec-replace" class="form-control" type="checkbox" - name="entry[replace]" {{entry.replace_checked}}> - <label for="exec-replace">{{lang_execReplace}}</label> - </div> - </div> - <div class="form-group"> - <div class="checkbox checkbox-inline"> - <input id="exec-au" class="form-control" type="checkbox" - name="entry[autoUnload]" {{entry.autoUnload_checked}}> - <label for="exec-au">{{lang_execAutoUnload}}</label> - </div> - </div> - <div class="form-group"> - <div class="checkbox checkbox-inline"> - <input id="exec-reset" class="form-control" type="checkbox" - name="entry[resetConsole]" {{entry.resetConsole_checked}}> - <label for="exec-reset">{{lang_execResetConsole}}</label> - </div> + <div class="row"> + {{#entries}} + <div class="mode-class col-md-6" id="col-{{mode}}"> + <div class="panel panel-default"> + <div class="panel-body"> + <h4 class="arch-heading">{{mode}}</h4> + <div class="form-group"> + <label for="input-ex"> + {{lang_imageToLoad}} + </label> + <input id="input-ex" class="form-control" name="entry[executable][{{mode}}]" value="{{executable}}"> + </div> + <div class="form-group"> + <label for="input-rd"> + {{lang_initRd}} + </label> + <input id="input-rd" class="form-control" name="entry[initRd][{{mode}}]" value="{{initRd}}"> + </div> + <div class="form-group"> + <label for="input-cmd"> + {{lang_commandLine}} + </label> + <input id="input-cmd" class="form-control" name="entry[commandLine][{{mode}}]" + value="{{commandLine}}"> + </div> + <div class="form-group"> + <div class="checkbox checkbox-inline"> + <input id="exec-replace-{{mode}}" class="form-control" type="checkbox" + name="entry[replace][{{mode}}]" {{replace_checked}}> + <label for="exec-replace-{{mode}}">{{lang_execReplace}}</label> + </div> + </div> + <div class="form-group"> + <div class="checkbox checkbox-inline"> + <input id="exec-au-{{mode}}" class="form-control" type="checkbox" + name="entry[autoUnload][{{mode}}]" {{autoUnload_checked}}> + <label for="exec-au-{{mode}}">{{lang_execAutoUnload}}</label> + </div> + </div> + <div class="form-group"> + <div class="checkbox checkbox-inline"> + <input id="exec-reset-{{mode}}" class="form-control" type="checkbox" + name="entry[resetConsole][{{mode}}]" {{resetConsole_checked}}> + <label for="exec-reset-{{mode}}">{{lang_execResetConsole}}</label> + </div> + </div> + </div> + </div> + </div> + {{/entries}} </div> </div> @@ -104,5 +132,21 @@ document.addEventListener('DOMContentLoaded', function () { $('#form-' + $(this).val()).show(); }); $('.type-radio[checked]').click(); + var $as = $('#arch-selector'); + $as.change(function() { + var v = $as.val(); + if (v === 'agnostic') { + v = 'PCBIOS'; + $('.arch-heading').hide(); + } else { + $('.arch-heading').show(); + } + var vs = v.split('-'); + var cols = 12 / vs.length; + $('.mode-class').hide(); + for (var i = 0; i < vs.length; ++i) { + $('#col-' + vs[i]).attr('class', 'mode-class col-md-' + cols).show(); + } + }).change(); }); // --></script>
\ No newline at end of file |