From 36e47dcdfb7d19d4c8982a77b4dd3b87d8c4ca31 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Wed, 16 Oct 2019 18:12:17 +0200 Subject: [serversetup-bwlp-ipxe/minilinux] Implement minilinux hook for ipxe --- inc/taskmanagercallback.inc.php | 11 +- .../minilinux/hooks/ipxe-bootentry.inc.php | 125 ++++++++++++++++--- .../minilinux/hooks/main-warning.inc.php | 4 +- modules-available/minilinux/inc/minilinux.inc.php | 138 ++++++++++++++++++++- modules-available/minilinux/install.inc.php | 4 +- modules-available/minilinux/lang/de/messages.json | 4 + modules-available/minilinux/lang/de/module.json | 5 + .../minilinux/lang/de/template-tags.json | 5 + modules-available/minilinux/lang/en/module.json | 1 + modules-available/minilinux/page.inc.php | 92 ++++++++++---- .../minilinux/templates/branches.html | 20 ++- .../minilinux/templates/filelist.html | 4 + .../minilinux/templates/page-minilinux.html | 4 +- modules-available/minilinux/templates/sources.html | 79 ++++++------ .../minilinux/templates/versionlist.html | 40 ++++-- .../serversetup-bwlp-ipxe/inc/bootentry.inc.php | 1 + .../inc/bootentryhook.inc.php | 134 +++++++++++++++++++- .../serversetup-bwlp-ipxe/inc/execdata.inc.php | 2 +- .../lang/de/template-tags.json | 2 + .../serversetup-bwlp-ipxe/page.inc.php | 43 ++++--- .../templates/ipxe-new-boot-entry.html | 14 ++- 21 files changed, 599 insertions(+), 133 deletions(-) diff --git a/inc/taskmanagercallback.inc.php b/inc/taskmanagercallback.inc.php index d1152bfd..0c4b116a 100644 --- a/inc/taskmanagercallback.inc.php +++ b/inc/taskmanagercallback.inc.php @@ -184,7 +184,7 @@ class TaskmanagerCallback } } - public static function mlDownload($task, $args) + public static function mlGotList($task, $args) { $mod = Module::get('minilinux'); if ($mod === false) @@ -193,6 +193,15 @@ class TaskmanagerCallback MiniLinux::listDownloadCallback($task, $args); } + public static function mlGotLinux($task, $args) + { + $mod = Module::get('minilinux'); + if ($mod === false) + return; + $mod->activate(1, false); + MiniLinux::linuxDownloadCallback($task, $args); + } + public static function uploadimg($task) { //$string=var_export($task, true); diff --git a/modules-available/minilinux/hooks/ipxe-bootentry.inc.php b/modules-available/minilinux/hooks/ipxe-bootentry.inc.php index 4e2cbb5e..090a14da 100644 --- a/modules-available/minilinux/hooks/ipxe-bootentry.inc.php +++ b/modules-available/minilinux/hooks/ipxe-bootentry.inc.php @@ -1,11 +1,23 @@ name(), [ + new HookEntry('default', + Dictionary::translateFileModule('minilinux', 'module', 'default_boot_entry', true), + 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 = []; + foreach ($versions[$branch['branchid']] as $version) { + $valid = $version['installed'] != 0; + $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['title'] : $branch['branchid'], $group); + } + } + return $array; } /** * @param $id * @return BootEntry the actual boot entry instance for given entry, false if invalid id */ - public function getBootEntry($id) + public function getBootEntryInternal($data) + { + $id = $data['id']; + if ($id === 'default') { // Special case + $effectiveId = Property::get(MiniLinux::PROPERTY_DEFAULT_BOOT_EFFECTIVE); + } else { + $effectiveId = $id; + } + $res = Database::queryFirst('SELECT installed, data FROM minilinux_version WHERE versionid = :id', ['id' => $effectiveId]); + if ($res === false) { + return BootEntry::newCustomBootEntry(['script' => 'prompt Invalid minilinux boot entry id: ' . $id]); + } + if ($res['installed'] == 0) { + return BootEntry::newCustomBootEntry(['script' => 'prompt Selected version not currently installed on server: ' . $id]); + } + $exec = new ExecData(); + // Defaults + $root = '/boot/' . $id . '/'; + $exec->executable = 'kernel'; + $exec->initRd = ['initramfs-stage31']; + $exec->imageFree = true; + $exec->commandLine = 'slxbase=boot/%ID% slxsrv=${serverip} quiet splash ${ipappend1} ${ipappend2}'; + // Overrides + $remoteData = json_decode($res['data'], true); + // TODO: agnostic hard coded, support EFI and PCBIOS + if (isset($remoteData['agnostic']) && is_array($remoteData['agnostic'])) { + foreach (['executable', 'commandLine', 'initRd', 'imageFree'] as $key) { + if (isset($remoteData['agnostic'][$key])) { + $exec->{$key} = $remoteData['agnostic'][$key]; + } + } + } + unset($rd); + // KCL hacks + if (isset($data['debug']) && $data['debug']) { + if (!isset($data['kcl-extra'])) { + $data['kcl-extra'] = ''; + } + $data['kcl-extra'] = '-quiet -splash -loglevel loglevel=7 ' . $data['kcl-extra']; + } + if (isset($data['kcl-extra'])) { + $items = preg_split('/\s+/', $data['kcl-extra'], -1, PREG_SPLIT_NO_EMPTY); + // TODO: Make this a function, somewhere in serversetup-ipxe, this could be useful for other stuff + foreach ($items as $item) { + if ($item{0} === '-') { + $item = preg_quote(substr($item, 1), '/'); + $exec->commandLine = preg_replace('/(^|\s)' . $item . '(=\S*)?($|\s)/', ' ', $exec->commandLine); + } else { + $exec->commandLine .= ' ' . $item; + } + } + } + $exec->commandLine = str_replace('%ID%', $id, $exec->commandLine); + $exec->executable = $root . $exec->executable; + foreach ($exec->initRd as &$rd) { + $rd = $root . $rd; + } + return BootEntry::newStandardBootEntry($exec, false, 'agnostic'); + } + + public function isValidId($id) { - $bios = new ExecData(); - $bios->executable = 'mspaint.exe'; - $bios->initRd = 'www.google.de'; - $bios->commandLine = '-q'; - return BootEntry::newStandardBootEntry($bios, false, 'agnostic'); + $res = Database::queryFirst('SELECT installed FROM minilinux_version WHERE versionid = :id', ['id' => $id]); + return $res !== false && $res['installed']; } } -return new Wurst(); \ No newline at end of file +return new LinuxBootEntryHook(); \ No newline at end of file diff --git a/modules-available/minilinux/hooks/main-warning.inc.php b/modules-available/minilinux/hooks/main-warning.inc.php index 31668e6c..8b052471 100644 --- a/modules-available/minilinux/hooks/main-warning.inc.php +++ b/modules-available/minilinux/hooks/main-warning.inc.php @@ -1,6 +1,8 @@ $source['taskid'], 'url' => $source['url'], ), true); - TaskmanagerCallback::addCallback($source['taskid'], 'mlDownload', $source['sourceid']); + TaskmanagerCallback::addCallback($source['taskid'], 'mlGotList', $source['sourceid']); } Database::exec('UNLOCK TABLES'); return count($list); } + /** + * Called when downloading metadata from a specific update source is finished + * @param mixed $task task structure + * @param string $sourceid see minilinux_source table + */ public static function listDownloadCallback($task, $sourceid) { + if ($task['statusCode'] !== 'TASK_FINISHED') + return; $taskId = $task['id']; $data = json_decode($task['data']['content'], true); if (!is_array($data)) { EventLog::warning('Cannot download Linux version meta data for ' . $sourceid); - error_log(print_r($task, true)); $lastupdate = 'lastupdate'; } else { if (isset($data['systems']) && is_array($data['systems'])) { @@ -141,6 +161,10 @@ class MiniLinux return preg_match('/^[a-z0-9_\-]+$/', $str) > 0; } + /* + * Download of specific version + */ + public static function validateDownloadTask($versionid, $taskid) { if ($taskid === null) @@ -193,7 +217,6 @@ class MiniLinux 'gpg' => $file['gpg'], ]; } - error_log(print_r($list, true)); $uuid = Util::randomUuid(); Database::exec('LOCK TABLES minilinux_version WRITE'); $aff = Database::exec('UPDATE minilinux_version SET taskid = :taskid WHERE versionid = :versionid AND taskid IS NULL', @@ -206,7 +229,6 @@ class MiniLinux 'files' => $list, ]); if (Taskmanager::isFailed($task)) { - error_log(print_r($task, true)); $task = false; } else { $task = $task['id']; @@ -215,6 +237,10 @@ class MiniLinux $task = false; } Database::exec('UNLOCK TABLES'); + if ($task !== false) { + // Callback for db column + TaskmanagerCallback::addCallback($task, 'mlGotLinux', $versionid); + } if ($aff === 0) return self::downloadVersion($versionid); return $task; @@ -225,4 +251,108 @@ class MiniLinux return 'x' . substr(md5($fileName . $versionid), 0, 8); } + /* + * Check status, availability of updates + */ + + /** + * Geenrate messages regarding setup und update availability. + * @return bool true if severe problems were found, false otherwise + */ + public static function generateUpdateNotice() + { + // Messages in here are with module name, as required by the + // main-warning hook. + $default = Property::get(self::PROPERTY_DEFAULT_BOOT); + if ($default === false) { + Message::addError('minilinux.no-default-set', true); + return true; + } + $installed = self::updateCurrentBootSetting(); + $effective = Property::get(self::PROPERTY_DEFAULT_BOOT_EFFECTIVE); + $slashes = substr_count($default, '/'); + if ($slashes === 1) { + // BrĂ´nche, always latest version + $latest = Database::queryFirst('SELECT versionid FROM minilinux_version + WHERE branchid = :branchid ORDER BY dateline DESC', ['branchid' => $default]); + if ($latest === false) { + Message::addError('minilinux.default-is-invalid', true); + return true; + } elseif ($latest['versionid'] !== $effective) { + Message::addInfo('minilinux.default-update-available', true, $default, $latest['versionid']); + } + } elseif ($slashes === 2) { + // Specific version selected + if ($effective === self::INVALID) { + Message::addError('minilinux.default-is-invalid', true); + return true; + } + } + if (!$installed) { + Message::addError('minilinux.default-not-installed', true, $default); + return true; + } + return false; + } + + /** + * Update the effective current default version to boot. + * If the version does not exist, it is set to INVALID. + * Function returns whether the currently selected version is + * actually installed locally. + * @return bool true if installed locally, false otherwise + */ + public static function updateCurrentBootSetting() + { + $default = Property::get(self::PROPERTY_DEFAULT_BOOT); + if ($default === false) + return false; + $slashes = substr_count($default, '/'); + if ($slashes === 2) { + // Specific version + $ver = Database::queryFirst('SELECT versionid, installed FROM minilinux_version + WHERE versionid = :versionid', ['versionid' => $default]); + } elseif ($slashes === 1) { + // Latest from branch + $ver = Database::queryFirst('SELECT versionid, installed FROM minilinux_version + WHERE branchid = :branchid AND installed = 1 ORDER BY dateline DESC', ['branchid' => $default]); + } else { + // Unknown + return false; + } + // Determine state + if ($ver === false) { // Doesn't exist + Property::set(self::PROPERTY_DEFAULT_BOOT_EFFECTIVE, self::INVALID); + return false; + } + Property::set(self::PROPERTY_DEFAULT_BOOT_EFFECTIVE, $ver['versionid']); + return $ver['installed'] != 0; + } + + public static function linuxDownloadCallback($task, $versionid) + { + self::setInstalledState($versionid, $task['statusCode'] === 'TASK_FINISHED'); + } + + public static function setInstalledState($versionid, $installed) + { + settype($installed, 'int'); + error_log("Setting $versionid to $installed"); + Database::exec('UPDATE minilinux_version SET installed = :installed WHERE versionid = :versionid', [ + 'versionid' => $versionid, + 'installed' => $installed, + ]); + } + + public static function queryAllVersionsByBranch() + { + $list = []; + $res = Database::simpleQuery('SELECT branchid, versionid, title, dateline, orphan, taskid, installed + FROM minilinux_version ORDER BY branchid, dateline, versionid'); + while ($row = $res->fetch(PDO::FETCH_ASSOC)) { + $list[$row['branchid']][$row['versionid']] = $row; + } + return $list; + } + } \ No newline at end of file diff --git a/modules-available/minilinux/install.inc.php b/modules-available/minilinux/install.inc.php index 50be13a5..5387542e 100644 --- a/modules-available/minilinux/install.inc.php +++ b/modules-available/minilinux/install.inc.php @@ -26,9 +26,11 @@ $result[] = tableCreate('minilinux_version', " `data` blob NOT NULL, `orphan` tinyint(3) UNSIGNED NOT NULL, `taskid` char(36) CHARACTER SET ascii DEFAULT NULL, + `installed` tinyint(1) NOT NULL DEFAULT '0', PRIMARY KEY (`versionid`), KEY (`title`), - KEY (`branchid`, `dateline`, `versionid`) + KEY (`branchid`, `dateline`, `versionid`), + KEY (`branchid`, `installed`, `dateline`) "); $result[] = tableAddConstraint('minilinux_version', 'branchid', 'minilinux_branch', 'branchid', diff --git a/modules-available/minilinux/lang/de/messages.json b/modules-available/minilinux/lang/de/messages.json index 1c38a8c1..e957ee09 100644 --- a/modules-available/minilinux/lang/de/messages.json +++ b/modules-available/minilinux/lang/de/messages.json @@ -1,5 +1,9 @@ { + "default-is-invalid": "Gew\u00e4hltes Linux-Standardsystem ist ung\u00fcltig", + "default-not-installed": "Gew\u00e4hltes Linux-Standardsystem {{0}} ist nicht (mehr) installiert", + "default-update-available": "F\u00fcr das Gew\u00e4hlte Linux-Standardsystem {{0}} ist die Aktualisierung {{1}} verf\u00fcgbar", "delete-error": "Fehler beim L\u00f6schen der Version {{0}}: {{1}}", + "no-default-set": "Kein Linux-Standardsystem festgelegt", "no-such-version": "Ung\u00fcltige\/Unbekannte Version: {{0}}", "please-download-minilinux": "Wichtige Dateien der MiniLinux-Installation fehlen", "version-deleted": "Version {{0}} wurde gel\u00f6scht" diff --git a/modules-available/minilinux/lang/de/module.json b/modules-available/minilinux/lang/de/module.json index 3ad539ca..da6ea4bb 100644 --- a/modules-available/minilinux/lang/de/module.json +++ b/modules-available/minilinux/lang/de/module.json @@ -1,8 +1,13 @@ { + "default_boot_entry": "(Globalen Standard verwenden)", "file-checksum-bad": "Pr\u00fcfsummenfehler", "file-missing": "Datei fehlt", + "file-not-readable": "Datei nicht lesbar", "file-ok": "OK", "file-size-mismatch": "Dateigr\u00f6\u00dfe stimmt nicht", + "ipxe-debug": "Debug-Ausgaben statt Bootlogo", + "ipxe-kcl-extra": "Modifikation der Kernel-Command-Line", "module_name": "bwLehrpool MiniLinux", + "not_installed_hint": "(nicht installiert)", "page_title": "Linuxvarianten f\u00fcr Netboot verwalten" } \ No newline at end of file diff --git a/modules-available/minilinux/lang/de/template-tags.json b/modules-available/minilinux/lang/de/template-tags.json index 144887c8..2054896c 100644 --- a/modules-available/minilinux/lang/de/template-tags.json +++ b/modules-available/minilinux/lang/de/template-tags.json @@ -1,14 +1,19 @@ { + "lang_branchesHeading": "Verf\u00fcgbare Varianten und Versionen", + "lang_changelog": "Changelog", "lang_confirmDeleteVersion": "Diese Version wirklich l\u00f6schen?", "lang_download": "Herunterladen", "lang_id": "ID", + "lang_installed": "Installiert", "lang_introText": "Hier gibts MiniLinux.", "lang_key": "GPG-Key", "lang_lastUpdate": "Zuletzt \u00fcberpr\u00fcft", "lang_minilinuxHeading": "Netboot Linux verwalten", "lang_orphanedVersion": "Verwaiste Version", "lang_releaseDate": "Ver\u00f6ffentlichungsdatum", + "lang_selectedDefaultIs": "Gew\u00e4hltes Standardsystem ist", "lang_sources": "Quellen", + "lang_sourcesIntro": "Liste der Quellen, aus denen Updates bezogen werden k\u00f6nnen.", "lang_title": "Titel", "lang_updateSourcesButton": "Nach neuen Updates suchen", "lang_url": "URL", diff --git a/modules-available/minilinux/lang/en/module.json b/modules-available/minilinux/lang/en/module.json index 899435e7..b1526869 100644 --- a/modules-available/minilinux/lang/en/module.json +++ b/modules-available/minilinux/lang/en/module.json @@ -1,6 +1,7 @@ { "file-checksum-bad": "Bad checksum", "file-missing": "File missing", + "file-not-readable": "File not readable", "file-ok": "OK", "file-size-mismatch": "File size mismatch", "module_name": "Minilinux", diff --git a/modules-available/minilinux/page.inc.php b/modules-available/minilinux/page.inc.php index b54050bf..53632699 100644 --- a/modules-available/minilinux/page.inc.php +++ b/modules-available/minilinux/page.inc.php @@ -18,6 +18,8 @@ class Page_MiniLinux extends Page $this->deleteVersion(); } elseif ($show === 'updatesources') { $this->updateSources(); + } elseif ($show === 'setdefault') { + $this->setDefault(); } Util::redirect('?do=minilinux'); } @@ -27,15 +29,21 @@ class Page_MiniLinux extends Page protected function doRender() { - Render::addTemplate('page-minilinux'); + Render::addTemplate('page-minilinux', ['default' => Property::get(MiniLinux::PROPERTY_DEFAULT_BOOT)]); + // Warning + if (!MiniLinux::updateCurrentBootSetting()) { + Message::addError('default-not-installed', Property::get(MiniLinux::PROPERTY_DEFAULT_BOOT)); + } // List branches and versions $branches = Database::queryAll('SELECT sourceid, branchid, title FROM minilinux_branch ORDER BY title ASC'); - $versions = $this->queryAllVersionsByBranch(); + $versions = MiniLinux::queryAllVersionsByBranch(); + // Group by branch for detailed listing foreach ($branches as &$branch) { if (isset($versions[$branch['branchid']])) { $branch['versionlist'] = $this->renderVersionList($versions[$branch['branchid']]); } } + unset($branch); Render::addTemplate('branches', ['branches' => $branches]); // List sources $res = Database::simpleQuery('SELECT sourceid, title, url, lastupdate, pubkey FROM minilinux_source ORDER BY title, sourceid'); @@ -60,35 +68,34 @@ class Page_MiniLinux extends Page User::load(); $show = Request::post('show', false, 'string'); if ($show === 'version') { - $this->ajaxVersion(); + $this->ajaxVersionDetails(); } elseif ($show === 'download') { $this->ajaxDownload(); } } - private function queryAllVersionsByBranch() - { - $list = []; - $res = Database::simpleQuery('SELECT branchid, versionid, title, dateline, orphan, taskid - FROM minilinux_version ORDER BY branchid, dateline, versionid'); - while ($row = $res->fetch(PDO::FETCH_ASSOC)) { - $list[$row['branchid']][] = $row; - } - return $list; - } - private function renderVersionList($versions) { + $def = Property::get(MiniLinux::PROPERTY_DEFAULT_BOOT); + $eff = Property::get(MiniLinux::PROPERTY_DEFAULT_BOOT_EFFECTIVE); foreach ($versions as &$version) { $version['dateline_s'] = Util::prettyTime($version['dateline']); $version['orphan'] = ($version['orphan'] > 5); - $version['installed'] = is_dir(CONFIG_HTTP_DIR . '/' . $version['versionid']); $version['downloading'] = $version['taskid'] && Taskmanager::isRunning(Taskmanager::status($version['taskid'])); + if ($version['installed'] && $version['versionid'] !== $def) { + $version['showsetdefault'] = true; + } + if ($version['versionid'] === $def) { + $version['isdefault'] = true; + if (!$version['installed']) { + $version['default_class'] = 'bg-danger'; + } + } } - return Render::parse('versionlist', ['versions' => $versions]); + return Render::parse('versionlist', ['versions' => array_values($versions)]); } - private function ajaxVersion() + private function ajaxVersionDetails() { User::assertPermission('view'); $verify = Request::post('verify', false, 'bool'); @@ -96,7 +103,7 @@ class Page_MiniLinux extends Page if ($versionid === false) { die('What!'); } - $ver = Database::queryFirst('SELECT versionid, taskid, data FROM minilinux_version WHERE versionid = :versionid', + $ver = Database::queryFirst('SELECT versionid, taskid, data, installed FROM minilinux_version WHERE versionid = :versionid', ['versionid' => $versionid]); if ($ver === false) { die('No such version'); @@ -110,6 +117,7 @@ class Page_MiniLinux extends Page $data['dltask'] = MiniLinux::validateDownloadTask($versionid, $ver['taskid']); $data['verify_button'] = !$verify && $data['dltask'] === false; if (is_array($data['files'])) { + $valid = true; $sort = []; foreach ($data['files'] as &$file) { if (empty($file['name'])) { @@ -119,8 +127,7 @@ class Page_MiniLinux extends Page $sort[] = $file['name']; $s = $this->getFileState($versionid, $file, $verify); if ($s !== self::FILE_OK) { - $data['verify_button'] = false; - $data['download_button'] = !$data['dltask']; + $valid = false; } if ($s !== self::FILE_MISSING) { $data['delete_button'] = true; @@ -138,6 +145,15 @@ class Page_MiniLinux extends Page } unset($file); array_multisort($sort, SORT_ASC, $data['files']); + if (!$valid) { + $data['verify_button'] = false; + $data['download_button'] = !$data['dltask']; + if ($ver['installed']) { + MiniLinux::setInstalledState($versionid, false); + } + } elseif (!$ver['installed'] && $verify) { + MiniLinux::setInstalledState($versionid, true); + } } echo Render::parse('filelist', $data); } @@ -146,6 +162,7 @@ class Page_MiniLinux extends Page const FILE_MISSING = 1; const FILE_SIZE_MISMATCH = 2; const FILE_CHECKSUM_BAD = 3; + const FILE_NOT_READABLE = 4; private function getFileState($versionid, $file, $verify) { @@ -154,11 +171,17 @@ class Page_MiniLinux extends Page return self::FILE_MISSING; if (isset($file['size']) && filesize($path) != $file['size']) return self::FILE_SIZE_MISMATCH; + if (!is_readable($path)) + return self::FILE_NOT_READABLE; if ($verify) { - // TODO: Others - if (isset($file['md5'])) { - if (md5_file($path) !== $file['md5']) - return self::FILE_CHECKSUM_BAD; + foreach (['sha512', 'sha384', 'sha256', 'sha224', 'sha1', 'md5'] as $algo) { + if (isset($file[$algo])) { + $calced = hash_file($algo, $path); + if ($calced === false) + continue; // Algo not supported? + if ($calced !== $file['md5']) + return self::FILE_CHECKSUM_BAD; + } } } return self::FILE_OK; @@ -173,6 +196,8 @@ class Page_MiniLinux extends Page return Dictionary::translate('file-size-mismatch', true); case self::FILE_MISSING: return Dictionary::translate('file-missing', true); + case self::FILE_NOT_READABLE: + return Dictionary::translate('file-not-readable', true); case self::FILE_OK: return Dictionary::translate('file-ok', true); } @@ -191,7 +216,7 @@ class Page_MiniLinux extends Page Message::addError('no-such-version', $version); Message::renderList(); } else { - $this->ajaxVersion(); + $this->ajaxVersionDetails(); } } @@ -209,6 +234,7 @@ class Page_MiniLinux extends Page Message::addError('no-such-version'); return; } + MiniLinux::setInstalledState($version['versionid'], false); $path = CONFIG_HTTP_DIR . '/' . $version['versionid']; $task = Taskmanager::submit('DeleteDirectory', [ 'path' => $path, @@ -233,4 +259,20 @@ class Page_MiniLinux extends Page } } + private function setDefault() + { + $versionid = Request::post('version', false, 'string'); + if ($versionid === false) { + Message::addError('main.parameter-missing', 'versionid'); + return; + } + $version = Database::queryFirst('SELECT versionid FROM minilinux_version WHERE versionid = :versionid', + ['versionid' => $versionid]); + if ($version === false) { + Message::addError('no-such-version'); + return; + } + Property::set(MiniLinux::PROPERTY_DEFAULT_BOOT, $version['versionid']); + } + } diff --git a/modules-available/minilinux/templates/branches.html b/modules-available/minilinux/templates/branches.html index 1ba9497c..64adda16 100644 --- a/modules-available/minilinux/templates/branches.html +++ b/modules-available/minilinux/templates/branches.html @@ -1,17 +1,19 @@ +

{{lang_branchesHeading}}

{{#branches}}
{{sourceid}} {{branchid}}
- {{title}} + {{title}}
- + {{description}}
{{{versionlist}}}
{{/branches}} + \ No newline at end of file diff --git a/modules-available/minilinux/templates/filelist.html b/modules-available/minilinux/templates/filelist.html index 2c26edf9..9aa175bd 100644 --- a/modules-available/minilinux/templates/filelist.html +++ b/modules-available/minilinux/templates/filelist.html @@ -50,4 +50,8 @@ {{#dltask}} {{/dltask}} +{{#changelog}} +

{{lang_changelog}}

+{{changelog}} +{{/changelog}}
\ No newline at end of file diff --git a/modules-available/minilinux/templates/page-minilinux.html b/modules-available/minilinux/templates/page-minilinux.html index 2cbde608..3059e827 100644 --- a/modules-available/minilinux/templates/page-minilinux.html +++ b/modules-available/minilinux/templates/page-minilinux.html @@ -1,3 +1,5 @@

{{lang_minilinuxHeading}}

-

{{lang_introText}}

\ No newline at end of file +

{{lang_introText}}

+ +{{lang_selectedDefaultIs}}: {{default}} \ No newline at end of file diff --git a/modules-available/minilinux/templates/sources.html b/modules-available/minilinux/templates/sources.html index f2e54745..dabc7f4d 100644 --- a/modules-available/minilinux/templates/sources.html +++ b/modules-available/minilinux/templates/sources.html @@ -1,42 +1,41 @@ -
-
- {{lang_sources}} -
- - - - - - - - - - - - {{#list}} - - - - - - - - {{/list}} - -
{{lang_id}}{{lang_title}}{{lang_url}}{{lang_lastUpdate}}{{lang_key}}
{{sourceid}}{{title}}{{url}}{{lastupdate_s}} - - -
-
-
- - +
\ No newline at end of file diff --git a/modules-available/minilinux/templates/versionlist.html b/modules-available/minilinux/templates/versionlist.html index 1e5c7c96..4ef4e631 100644 --- a/modules-available/minilinux/templates/versionlist.html +++ b/modules-available/minilinux/templates/versionlist.html @@ -1,22 +1,45 @@ - - + + + {{#versions}} - - + - + + - - + {{/versions}}
{{lang_version}}{{lang_releaseDate}}{{lang_version}}{{lang_releaseDate}} {{lang_title}}
+ {{versionid}} {{dateline_s}}{{dateline_s}} {{title}} + + {{#orphan}} + {{lang_orphanedVersion}} + {{/orphan}} + + {{#showsetdefault}} +
+ + + +
+ {{/showsetdefault}} + {{#isdefault}} + + {{/isdefault}} +
+ {{#installed}} + {{lang_installed}} + {{/installed}} {{^installed}} {{^downloading}} - {{#orphan}} - {{lang_orphanedVersion}} - {{/orphan}} -
\ No newline at end of file diff --git a/modules-available/serversetup-bwlp-ipxe/inc/bootentry.inc.php b/modules-available/serversetup-bwlp-ipxe/inc/bootentry.inc.php index e97d1389..174f4459 100644 --- a/modules-available/serversetup-bwlp-ipxe/inc/bootentry.inc.php +++ b/modules-available/serversetup-bwlp-ipxe/inc/bootentry.inc.php @@ -260,6 +260,7 @@ class StandardBootEntry extends BootEntry } else { $entry = $this->efi; } + $entry->sanitize(); $script = ''; if ($entry->resetConsole) { diff --git a/modules-available/serversetup-bwlp-ipxe/inc/bootentryhook.inc.php b/modules-available/serversetup-bwlp-ipxe/inc/bootentryhook.inc.php index 2e2e5009..f89031a3 100644 --- a/modules-available/serversetup-bwlp-ipxe/inc/bootentryhook.inc.php +++ b/modules-available/serversetup-bwlp-ipxe/inc/bootentryhook.inc.php @@ -14,18 +14,24 @@ abstract class BootEntryHook private $selectedId; + private $data = []; + + /** + * @return string + */ public abstract function name(); /** - * @return HookEntryGroup[] + * @return HookExtraField[] */ - protected abstract function groupsInternal(); + public abstract function extraFields(); + + public abstract function isValidId($id); /** - * @param $id - * @return BootEntry|null the actual boot entry instance for given entry, null if invalid id + * @return HookEntryGroup[] */ - public abstract function getBootEntry($id); + protected abstract function groupsInternal(); /** * @return HookEntryGroup[] @@ -43,11 +49,40 @@ abstract class BootEntryHook return $groups; } + /** + * @param $id + * @return BootEntry|null the actual boot entry instance for given entry, null if invalid id + */ + public abstract function getBootEntryInternal($data); + + public final function getBootEntry($data) + { + if (!is_array($data)) { + $data = json_decode($data, true); + } + return $this->getBootEntryInternal($data); + } + public function setSelected($id) { + $json = @json_decode($id, true); + if (is_array($json)) { + $id = $json['id']; + $this->data = $json; + } $this->selectedId = $id; } + public function renderExtraFields() + { + $list = $this->extraFields(); + foreach ($list as &$entry) { + $entry->currentValue = isset($this->data[$entry->name]) ? $this->data[$entry->name] : $entry->default; + $entry->hook = $this; + } + return $list; + } + } class HookEntryGroup @@ -78,14 +113,101 @@ class HookEntry * @var string */ public $name; + /** + * @var bool + */ + public $valid; + /** + * @var string if !valid, this will be the string 'disabled', empty otherwise + */ + public $disabled; /** * @var string internal - to be set by ipxe module */ public $selected; - public function __construct($id, $name) + /** + * HookEntry constructor. + * + * @param string $id + * @param string $name + * @param bool $valid + */ + public function __construct($id, $name, $valid) { $this->id = $id; $this->name = $name; + $this->valid = $valid; + $this->disabled = $valid ? '' : 'disabled'; } +} + +class HookExtraField +{ + /** + * @var string ID of extra field, [a-z0-9\-] please. Must not be 'id' + */ + public $name; + /** + * @var string type of field, use string, bool, or an array of predefined options + */ + public $type; + /** + * @var mixed default value + */ + public $default; + + public $currentValue; + + /** + * @var BootEntryHook + */ + public $hook; + + public function __construct($name, $type, $default) + { + $this->name = $name; + $this->type = $type; + $this->default = $default; + } + + public function fromPost($typePrefix) + { + if (is_array($this->type)) { + $val = Request::post('extra-' . $typePrefix . '-' . $this->name, '', 'array'); + if (!in_array($val, $this->type)) { + $val = $this->default; + } + } else { + $val = Request::post('extra-' . $typePrefix . '-' . $this->name, '', $this->type); + settype($val, $this->type); + } + return $val; + } + + public function html() + { + $fieldId = 'extra-' . $this->hook->moduleId . '-' . $this->name; + $fieldText = htmlspecialchars(Dictionary::translateFileModule($this->hook->moduleId, 'module', 'ipxe-' . $this->name, true)); + if (is_array($this->type)) { + $out = ''; + return $out; + } + if ($this->type === 'bool') { + $checked = $this->currentValue ? 'checked' : ''; + return '
'; + } + // Default + return '' + . ''; + } + } \ No newline at end of file diff --git a/modules-available/serversetup-bwlp-ipxe/inc/execdata.inc.php b/modules-available/serversetup-bwlp-ipxe/inc/execdata.inc.php index b82ce2e7..97f98b94 100644 --- a/modules-available/serversetup-bwlp-ipxe/inc/execdata.inc.php +++ b/modules-available/serversetup-bwlp-ipxe/inc/execdata.inc.php @@ -73,7 +73,7 @@ class ExecData ], ]; - private function sanitize() + public function sanitize() { settype($this->executable, 'string'); settype($this->initRd, 'array'); diff --git a/modules-available/serversetup-bwlp-ipxe/lang/de/template-tags.json b/modules-available/serversetup-bwlp-ipxe/lang/de/template-tags.json index 07cf8fa3..f7a62091 100644 --- a/modules-available/serversetup-bwlp-ipxe/lang/de/template-tags.json +++ b/modules-available/serversetup-bwlp-ipxe/lang/de/template-tags.json @@ -11,6 +11,7 @@ "lang_biosOnly": "Nur BIOS", "lang_bootAddress": "Boot-Adresse des Servers", "lang_bootEntryData": "Daten des Men\u00fceintrags", + "lang_bootEntryDetailsHeading": "Typspezifische Konfiguration", "lang_bootentryDeleteConfirm": "Sind Sie sicher, dass Sie diesen Men\u00fceintrag l\u00f6schen wollen?", "lang_bootentryHead": "Men\u00fceintr\u00e4ge", "lang_bootentryIntro": "Hier k\u00f6nnen Sie Men\u00fceintr\u00e4ge definieren, die sich sp\u00e4ter einem Men\u00fc zuweisen lassen. Ein Men\u00fceintrag besteht entweder aus einem zu ladenden Kernel\/Image plus optional initrd, oder aus einem iPXE-Skript.", @@ -38,6 +39,7 @@ "lang_forceRecompile": "Jetzt neu kompilieren", "lang_generationFailed": "Erzeugen des Bootmen\u00fcs fehlgeschlagen. Der Netzwerkboot von bwLehrpool wird wahrscheinlich nicht funktionieren. Wenn Sie den Fehler nicht selbst beheben k\u00f6nnen, melden Sie bitte die Logausgabe an das bwLehrpool-Projekt.", "lang_hex": "Hex", + "lang_hookExtraOptionHeading": "Weitere Angaben", "lang_hotkey": "Hotkey", "lang_idFormatHint": "(Max. 16 Zeichen, nur a-z 0-9 - _)", "lang_imageToLoad": "Zu ladendes Image (z.B. Kernel)", diff --git a/modules-available/serversetup-bwlp-ipxe/page.inc.php b/modules-available/serversetup-bwlp-ipxe/page.inc.php index 40b75dd2..f14c1e57 100644 --- a/modules-available/serversetup-bwlp-ipxe/page.inc.php +++ b/modules-available/serversetup-bwlp-ipxe/page.inc.php @@ -519,25 +519,25 @@ class Page_ServerSetup extends Page $params['oldentryid'] = $params['entryid'] = $row['entryid']; $params['builtin'] = $row['builtin']; } - if (!is_array($params['entries'])) { - $params['entries'] = []; - } - $f = []; - foreach ($params['entries'] as $e) { - if (isset($e['mode'])) { - $f[] = $e['mode']; - } - } - if (!in_array('PCBIOS', $f)) { - $params['entries'][] = ['mode' => 'PCBIOS']; - } - if (!in_array('EFI', $f)) { - $params['entries'][] = ['mode' => 'EFI']; - } $params['menus'] = Database::queryAll('SELECT m.menuid, m.title FROM serversetup_menu m INNER JOIN serversetup_menuentry me ON (me.menuid = m.menuid) WHERE me.entryid = :entryid', ['entryid' => $row['entryid']]); } + if (!isset($params['entries']) || !is_array($params['entries'])) { + $params['entries'] = []; + } + $f = []; + foreach ($params['entries'] as $e) { + if (isset($e['mode'])) { + $f[] = $e['mode']; + } + } + if (!in_array('PCBIOS', $f)) { + $params['entries'][] = ['mode' => 'PCBIOS']; + } + if (!in_array('EFI', $f)) { + $params['entries'][] = ['mode' => 'EFI']; + } $params['disabled'] = User::hasPermission('ipxe.bootentry.edit') ? '' : 'disabled'; Render::addTemplate('ipxe-new-boot-entry', $params); @@ -823,12 +823,19 @@ class Page_ServerSetup extends Page } /** @var BootEntryHook $module */ $module = $hook->run(); - $entryData = Request::post('selection-' . $type, false, 'string'); - $entry = $module->getBootEntry($entryData); + $id = Request::post('selection-' . $type, false, 'string'); + $entry = $module->isValidId($id); if ($entry === null) { - Message::addError('invalid-custom-entry-id', $type, $entryData); + Message::addError('invalid-custom-entry-id', $type, $id); return; } + $entryData = ['id' => $id]; + foreach ($module->extraFields() as $field) { + if ($field->name === 'id') + continue; + $entryData[$field->name] = $field->fromPost($type); + } + $entryData = json_encode($entryData); } $params = [ 'entryid' => $newId, diff --git a/modules-available/serversetup-bwlp-ipxe/templates/ipxe-new-boot-entry.html b/modules-available/serversetup-bwlp-ipxe/templates/ipxe-new-boot-entry.html index fd76c1d5..5b7e3134 100644 --- a/modules-available/serversetup-bwlp-ipxe/templates/ipxe-new-boot-entry.html +++ b/modules-available/serversetup-bwlp-ipxe/templates/ipxe-new-boot-entry.html @@ -52,6 +52,8 @@
+

{{lang_bootEntryDetailsHeading}}

+
+
+ {{#renderExtraFields.0}} +

{{lang_hookExtraOptionHeading}}

+ {{/renderExtraFields.0}} + {{#renderExtraFields}} + {{{html}}} + {{/renderExtraFields}} +
{{/hooks}} @@ -185,6 +195,8 @@ {{/builtin}} +
+

{{lang_referencingMenus}}: