summaryrefslogtreecommitdiffstats
path: root/modules-available/minilinux
diff options
context:
space:
mode:
Diffstat (limited to 'modules-available/minilinux')
-rw-r--r--modules-available/minilinux/inc/linuxbootentryhook.inc.php64
-rw-r--r--modules-available/minilinux/inc/minilinux.inc.php186
-rw-r--r--modules-available/minilinux/install.inc.php32
-rw-r--r--modules-available/minilinux/lang/de/messages.json12
-rw-r--r--modules-available/minilinux/lang/de/module.json9
-rw-r--r--modules-available/minilinux/lang/de/permissions.json6
-rw-r--r--modules-available/minilinux/lang/de/template-tags.json2
-rw-r--r--modules-available/minilinux/lang/en/messages.json2
-rw-r--r--modules-available/minilinux/lang/en/module.json1
-rw-r--r--modules-available/minilinux/lang/en/permissions.json6
-rw-r--r--modules-available/minilinux/page.inc.php96
-rw-r--r--modules-available/minilinux/templates/branches.html5
-rw-r--r--modules-available/minilinux/templates/filelist.html7
-rw-r--r--modules-available/minilinux/templates/page-minilinux.html15
-rw-r--r--modules-available/minilinux/templates/versionlist.html15
15 files changed, 290 insertions, 168 deletions
diff --git a/modules-available/minilinux/inc/linuxbootentryhook.inc.php b/modules-available/minilinux/inc/linuxbootentryhook.inc.php
index e3090054..1424b6b9 100644
--- a/modules-available/minilinux/inc/linuxbootentryhook.inc.php
+++ b/modules-available/minilinux/inc/linuxbootentryhook.inc.php
@@ -10,29 +10,31 @@
class LinuxBootEntryHook extends BootEntryHook
{
- public function name()
+ public function name(): string
{
- return Dictionary::translateFileModule('minilinux', 'module', 'module_name', true);
+ return Dictionary::translateFileModule('minilinux', 'module', 'module_name');
}
- public function extraFields()
+ public function extraFields(): array
{
/* For translate module:
* Dictionary::translate('ipxe-kcl-extra');
* Dictionary::translate('ipxe-debug');
* Dictionary::translate('ipxe-insecure-cpu');
+ * Dictionary::translate('ipxe-force-init-dhcp');
*/
return [
new HookExtraField('kcl-extra', 'string', ''),
new HookExtraField('debug', 'bool', false),
new HookExtraField('insecure-cpu', 'bool', false),
+ new HookExtraField('force-init-dhcp', 'bool', false),
];
}
/**
* @return HookEntryGroup[]
*/
- protected function groupsInternal()
+ protected function groupsInternal(): array
{
/*
* Dictionary::translate('default_boot_entry');
@@ -42,7 +44,7 @@ class LinuxBootEntryHook extends BootEntryHook
$array = [];
$array[] = new HookEntryGroup($this->name(), [
new HookEntry('default',
- Dictionary::translateFileModule('minilinux', 'module', 'default_boot_entry', true),
+ Dictionary::translateFileModule('minilinux', 'module', 'default_boot_entry'),
MiniLinux::updateCurrentBootSetting())
]);
$branches = Database::queryAll('SELECT sourceid, branchid, title FROM minilinux_branch ORDER BY title');
@@ -54,29 +56,28 @@ class LinuxBootEntryHook extends BootEntryHook
new HookEntry($branch['branchid'],
$branch['branchid'] . ' '
. Dictionary::translateFileModule('minilinux', 'module',
- 'latest_of_branch', true),
+ 'latest_of_branch'),
true),
];
foreach ($versions[$branch['branchid']] as $version) {
- $valid = $version['installed'] != 0;
+ $valid = $version['installed'] != MiniLinux::INSTALL_MISSING;
$title = $version['versionid'] . ' ' . $version['title'];
if (!$valid) {
$title .= ' ' . Dictionary::translateFileModule('minilinux', 'module',
- 'not_installed_hint', true);
+ 'not_installed_hint');
}
$group[] = new HookEntry($version['versionid'], $title, $valid);
}
- $array[] = new HookEntryGroup($branch['title'] ? $branch['title'] : $branch['branchid'], $group);
+ $array[] = new HookEntryGroup($branch['title'] ?: $branch['branchid'], $group);
}
}
return $array;
}
/**
- * @param $localData
- * @return BootEntry the actual boot entry instance for given entry, false if invalid id
+ * @return ?BootEntry the actual boot entry instance for given entry, false if invalid id
*/
- public function getBootEntryInternal($localData)
+ public function getBootEntryInternal(array $localData): ?BootEntry
{
$id = $localData['id'];
if ($id === 'default') { // Special case
@@ -88,14 +89,12 @@ class LinuxBootEntryHook extends BootEntryHook
['id' => $effectiveId]);
if ($res === false) {
// Maybe this is a branchid, which means latest from according branch (installed only)
- $res = Database::queryFirst('SELECT versionid, installed, data FROM minilinux_version WHERE branchid = :id
- ORDER BY installed DESC, dateline DESC LIMIT 1', // Order by installed instead of WHERE for better errormsg
- ['id' => $effectiveId]);
+ $res = Database::queryFirst('SELECT versionid, installed, data FROM minilinux_version
+ WHERE branchid = :id AND installed = :ok
+ ORDER BY dateline DESC LIMIT 1',
+ ['id' => $effectiveId, 'ok' => MiniLinux::INSTALL_OK]);
}
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: ' . $effectiveId]);
}
$effectiveId = $res['versionid']; // In case we selected from a branchid, so above message doesn't show versionid
@@ -122,10 +121,10 @@ class LinuxBootEntryHook extends BootEntryHook
$arch = BootEntry::EFI;
}
}
- return BootEntry::newStandardBootEntry($bios, $efi, $arch);
+ return BootEntry::newStandardBootEntry($bios, $efi, $arch, 'ml-' . $id);
}
- private function generateExecData($effectiveId, $remoteData, $localData)
+ private function generateExecData($effectiveId, $remoteData, $localData): ExecData
{
$exec = new ExecData();
// Defaults
@@ -146,23 +145,34 @@ class LinuxBootEntryHook extends BootEntryHook
if (!empty($localData['debug'])) {
// Debug boot enabled
$exec->commandLine = IPxe::modifyCommandLine($exec->commandLine,
- isset($remoteData['debugCommandLineModifier'])
- ? $remoteData['debugCommandLineModifier']
- : '-vga -quiet -splash -loglevel loglevel=7'
+ $remoteData['debugCommandLineModifier'] ?? '-vga -quiet -splash -loglevel loglevel=7'
);
}
// disable all CPU sidechannel attack mitigations etc.
if (!empty($localData['insecure-cpu'])) {
$exec->commandLine = IPxe::modifyCommandLine($exec->commandLine,
- 'noibrs noibpb nopti nospectre_v2 nospectre_v1 l1tf=off nospec_store_bypass_disable no_stf_barrier mds=off mitigations=off');
+ 'noibrs noibpb nopti nospectre_v2 nospectre_v1 l1tf=off nospec_store_bypass_disable no_stf_barrier mds=off mitigations=off i915.mitigations=off');
+ }
+ // force that we
+ if (!empty($localData['force-init-dhcp'])) {
+ $exec->commandLine = IPxe::modifyCommandLine($exec->commandLine,
+ '-ipv4.router -ipv4.dns -ipv4.subnet');
+ }
+ // GVT, PCI Pass-thru etc.
+ if (Module::isAvailable('statistics')) {
+ $hwextra = HardwareInfo::getKclModifications();
+ if (!empty($hwextra)) {
+ $exec->commandLine = IPxe::modifyCommandLine($exec->commandLine, $hwextra);
+ }
}
+ // User-supplied modifications
if (!empty($localData['kcl-extra'])) {
$exec->commandLine = IPxe::modifyCommandLine($exec->commandLine, $localData['kcl-extra']);
}
$exec->commandLine = str_replace('%ID%', $effectiveId, $exec->commandLine);
$exec->executable = $root . $exec->executable;
foreach ($exec->initRd as &$rd) {
- if ($rd{0} !== '/') {
+ if ($rd[0] !== '/') {
$rd = $root . $rd;
}
}
@@ -170,12 +180,12 @@ class LinuxBootEntryHook extends BootEntryHook
return $exec;
}
- public function isValidId($id)
+ public function isValidId(string $id): bool
{
if ($id === 'default')
return true; // Meta-version that links to whatever the default is set to
$res = Database::queryFirst('SELECT installed FROM minilinux_version WHERE versionid = :id', ['id' => $id]);
- if ($res !== false && $res['installed'])
+ if ($res !== false && $res['installed'] != MiniLinux::INSTALL_MISSING)
return true;
$res = Database::queryFirst('SELECT branchid FROM minilinux_branch WHERE branchid = :id', ['id' => $id]);
return $res !== false;
diff --git a/modules-available/minilinux/inc/minilinux.inc.php b/modules-available/minilinux/inc/minilinux.inc.php
index d172d982..cbc797f2 100644
--- a/modules-available/minilinux/inc/minilinux.inc.php
+++ b/modules-available/minilinux/inc/minilinux.inc.php
@@ -11,21 +11,27 @@ class MiniLinux
const INVALID = 'invalid';
+ const INSTALL_MISSING = 0;
+
+ const INSTALL_OK = 1;
+
+ const INSTALL_BROKEN = 2;
+
/*
* Update of available versions by querying sources
*/
/**
- * Query all known sources for meta data
+ * Query all known sources for metadata
* @return int number of sources query was just initialized for
*/
- public static function updateList()
+ public static function updateList(): int
{
$stamp = time();
$last = Property::get(self::PROPERTY_KEY_FETCHTIME);
- if ($last !== false && $last + 10 > $stamp)
+ if ($last !== false && $last + 3 > $stamp)
return 0; // In progress...
- Property::set(self::PROPERTY_KEY_FETCHTIME, $stamp, 1);
+ Property::set(self::PROPERTY_KEY_FETCHTIME, $stamp, 10);
Database::exec('LOCK TABLES callback WRITE,
minilinux_source WRITE, minilinux_branch WRITE, minilinux_version WRITE');
Database::exec('UPDATE minilinux_source SET taskid = UUID()');
@@ -33,7 +39,8 @@ class MiniLinux
Database::exec("UPDATE minilinux_version
INNER JOIN minilinux_branch USING (branchid)
INNER JOIN minilinux_source USING (sourceid)
- SET orphan = orphan + 1 WHERE minilinux_source.lastupdate < $cutoff");
+ SET orphan = orphan + 1
+ WHERE minilinux_source.lastupdate < $cutoff AND orphan < 100");
$list = Database::queryAll('SELECT sourceid, url, taskid FROM minilinux_source');
foreach ($list as $source) {
Taskmanager::submit('DownloadText', array(
@@ -48,20 +55,22 @@ class MiniLinux
/**
* Called when downloading metadata from a specific update source is finished
- * @param mixed $task task structure
+ *
+ * @param array $task task structure
* @param string $sourceid see minilinux_source table
*/
- public static function listDownloadCallback($task, $sourceid)
+ public static function listDownloadCallback(array $task, string $sourceid): void
{
- if ($task['statusCode'] !== 'TASK_FINISHED')
+ if (!Taskmanager::isFinished($task))
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);
+ $data = json_decode($task['data']['content'] ?? '', true);
+ if (!is_array($data) || empty($data['systems'])) {
+ EventLog::warning('Cannot download Linux version meta data for ' . $sourceid,
+ ($task['data']['error'] ?? '') . "\n\nContent:\n" . ($task['data']['content'] ?? ''));
$lastupdate = 'lastupdate';
} else {
- if (@is_array($data['systems'])) {
+ if (is_array($data['systems'])) {
self::addBranches($sourceid, $data['systems']);
}
$lastupdate = 'UNIX_TIMESTAMP()';
@@ -70,7 +79,8 @@ class MiniLinux
WHERE sourceid = :sourceid AND taskid = :taskid",
['sourceid' => $sourceid, 'taskid' => $taskId]);
// Clean up -- delete orphaned versions that are not installed
- Database::exec('DELETE FROM minilinux_version WHERE orphan > 4 AND installed = 0');
+ Database::exec('DELETE FROM minilinux_version WHERE orphan > 4 AND installed = :missing',
+ ['missing' => self::INSTALL_MISSING]);
// FKC makes sure we only delete orphaned ones
Database::exec('DELETE IGNORE FROM minilinux_branch WHERE 1', [], true);
}
@@ -81,18 +91,31 @@ class MiniLinux
if (!self::isValidIdPart($system['id']))
continue;
$branchid = $sourceid . '/' . $system['id'];
- $title = empty($system['title']) ? $branchid : $system['title'];
- $description = empty($system['description']) ? '' : $system['description'];
- Database::exec('INSERT INTO minilinux_branch (branchid, sourceid, title, description)
- VALUES (:branchid, :sourceid, :title, :description)
- ON DUPLICATE KEY UPDATE title = VALUES(title), description = VALUES(description)', [
- 'branchid' => $branchid,
- 'sourceid' => $sourceid,
- 'title' => $title,
- 'description' => $description,
- ]);
- if (@is_array($system['versions'])) {
+ $title = mb_substr(empty($system['title']) ? $branchid : $system['title'], 0, 150);
+ $description = $system['description'] ?? '';
+ $color = $system['color'] ?? '';
+ if (!empty($system['versions']) && is_array($system['versions'])) {
+ Database::exec('INSERT INTO minilinux_branch (branchid, sourceid, title, color, description)
+ VALUES (:branchid, :sourceid, :title, :color, :description)
+ ON DUPLICATE KEY UPDATE title = VALUES(title), color = VALUES(color), description = VALUES(description)', [
+ 'branchid' => $branchid,
+ 'sourceid' => $sourceid,
+ 'title' => $title,
+ 'color' => $color,
+ 'description' => $description,
+ ]);
self::addVersions($branchid, $system['versions']);
+ } else {
+ // Empty branch - only update metadata if branch exists locally
+ Database::exec('UPDATE minilinux_branch
+ SET title = :title, color = :color, description = :description
+ WHERE sourceid = :sourceid AND branchid = :branchid', [
+ 'branchid' => $branchid,
+ 'sourceid' => $sourceid,
+ 'title' => $title,
+ 'color' => $color,
+ 'description' => $description,
+ ]);
}
}
}
@@ -115,7 +138,8 @@ class MiniLinux
return;
}
$versionid = $branchid . '/' . $version['version'];
- $title = empty($version['title']) ? '' : $version['title'];
+ $title = $version['title'] ?? '';
+ $description = $version['description'] ?? '';
$dateline = empty($version['releasedate']) ? time() : (int)$version['releasedate'];
unset($version['version'], $version['title'], $version['releasedate']);
// Sanitize files array
@@ -148,18 +172,20 @@ class MiniLinux
$version['files'] = array_values($version['files']);
}
$data = json_encode($version);
- Database::exec('INSERT INTO minilinux_version (versionid, branchid, title, dateline, data, orphan)
- VALUES (:versionid, :branchid, :title, :dateline, :data, 0)
- ON DUPLICATE KEY UPDATE title = VALUES(title), data = VALUES(data), orphan = 0', [
+ Database::exec('INSERT INTO minilinux_version (versionid, branchid, title, description, dateline, data, orphan)
+ VALUES (:versionid, :branchid, :title, :description, :dateline, :data, 0)
+ ON DUPLICATE KEY UPDATE title = VALUES(title), description = VALUES(description),
+ dateline = VALUES(dateline), data = VALUES(data), orphan = 0', [
'versionid' => $versionid,
'branchid' => $branchid,
- 'title' => $title,
+ 'title' => mb_substr($title, 0, 150),
+ 'description' => $description,
'dateline' => $dateline,
'data' => $data,
]);
}
- private static function isValidIdPart($str)
+ private static function isValidIdPart(string $str): bool
{
return preg_match('/^[a-z0-9_\-]+$/', $str) > 0;
}
@@ -168,10 +194,10 @@ class MiniLinux
* Download of specific version
*/
- public static function validateDownloadTask($versionid, $taskid)
+ public static function validateDownloadTask(string $versionid, ?string $taskid): ?string
{
if ($taskid === null)
- return false;
+ return null;
$task = Taskmanager::status($taskid);
if (Taskmanager::isTask($task) && !Taskmanager::isFailed($task)
&& (is_dir(CONFIG_HTTP_DIR . '/' . $versionid) || !Taskmanager::isFinished($task)))
@@ -179,15 +205,13 @@ class MiniLinux
Database::exec('UPDATE minilinux_version SET taskid = NULL
WHERE versionid = :versionid AND taskid = :taskid',
['versionid' => $versionid, 'taskid' => $taskid]);
- return false;
+ return null;
}
/**
* Download the files for the given version id
- * @param $versionid
- * @return bool
*/
- public static function downloadVersion($versionid)
+ public static function downloadVersion(string $versionid): ?string
{
$ver = Database::queryFirst('SELECT s.url, s.pubkey, v.versionid, v.taskid, v.data FROM minilinux_version v
INNER JOIN minilinux_branch b USING (branchid)
@@ -195,17 +219,17 @@ class MiniLinux
WHERE versionid = :versionid',
['versionid' => $versionid]);
if ($ver === false)
- return false;
+ return null;
$taskid = self::validateDownloadTask($versionid, $ver['taskid']);
- if ($taskid !== false)
+ if ($taskid !== null)
return $taskid;
$data = json_decode($ver['data'], true);
if (!is_array($data)) {
EventLog::warning("Cannot download Linux '$versionid': Corrupted meta data.", $ver['data']);
- return false;
+ return null;
}
if (empty($data['files']))
- return false;
+ return null;
$list = [];
$legacyDir = preg_replace(',^[^/]*/,', '', $versionid);
foreach ($data['files'] as $file) {
@@ -224,6 +248,7 @@ class MiniLinux
Database::exec('LOCK TABLES minilinux_version WRITE');
$aff = Database::exec('UPDATE minilinux_version SET taskid = :taskid WHERE versionid = :versionid AND taskid IS NULL',
['taskid' => $uuid, 'versionid' => $versionid]);
+ $task = false;
if ($aff > 0) {
$task = Taskmanager::submit('DownloadFiles', [
'id' => $uuid,
@@ -234,10 +259,8 @@ class MiniLinux
if (Taskmanager::isFailed($task)) {
$task = false;
} else {
- $task = $task['id'];
+ $task = (string)$task['id'];
}
- } else {
- $task = false;
}
Database::exec('UNLOCK TABLES');
if ($task !== false) {
@@ -251,7 +274,7 @@ class MiniLinux
return $task;
}
- public static function fileToId($versionid, $fileName)
+ public static function fileToId(string $versionid, string $fileName): string
{
return 'x' . substr(md5($fileName . $versionid), 0, 8);
}
@@ -264,7 +287,7 @@ class MiniLinux
* Generate messages regarding setup und update availability.
* @return bool true if severe problems were found, false otherwise
*/
- public static function generateUpdateNotice()
+ public static function generateUpdateNotice(): bool
{
// Messages in here are with module name, as required by the
// main-warning hook.
@@ -307,7 +330,7 @@ class MiniLinux
* actually installed locally.
* @return bool true if installed locally, false otherwise
*/
- public static function updateCurrentBootSetting()
+ public static function updateCurrentBootSetting(): bool
{
$default = Property::get(self::PROPERTY_DEFAULT_BOOT);
if ($default === false)
@@ -320,7 +343,7 @@ class MiniLinux
} 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]);
+ WHERE branchid = :branchid AND installed = :ok ORDER BY dateline DESC', ['branchid' => $default, 'ok' => self::INSTALL_OK]);
} else {
// Unknown
return false;
@@ -331,35 +354,36 @@ class MiniLinux
return false;
}
Property::set(self::PROPERTY_DEFAULT_BOOT_EFFECTIVE, $ver['versionid']);
- return $ver['installed'] != 0;
+ return $ver['installed'] != self::INSTALL_MISSING;
}
public static function linuxDownloadCallback($task, $versionid)
{
- self::setInstalledState($versionid, $task['statusCode'] === 'TASK_FINISHED');
+ self::setInstalledState($versionid, $task['statusCode'] === 'TASK_FINISHED' ? self::INSTALL_OK : self::INSTALL_BROKEN);
}
- public static function setInstalledState($versionid, int $installed)
+ public static function setInstalledState($versionid, int $installed): void
{
- error_log("Setting $versionid to $installed");
Database::exec('UPDATE minilinux_version SET installed = :installed WHERE versionid = :versionid', [
'versionid' => $versionid,
'installed' => $installed,
]);
- if ($installed) {
- $res = Database::queryFirst('SELECT Count(*) AS cnt FROM minilinux_version WHERE installed <> 0');
+ if ($installed === self::INSTALL_OK) {
+ $res = Database::queryFirst('SELECT Count(*) AS cnt FROM minilinux_version WHERE installed = :ok',
+ ['ok' => self::INSTALL_OK]);
if ($res['cnt'] == 1) {
self::setDefaultVersion($versionid);
}
}
}
- public static function queryAllVersionsByBranch()
+ public static function queryAllVersionsByBranch(): array
{
$list = [];
- $res = Database::simpleQuery('SELECT branchid, versionid, title, dateline, orphan, taskid, installed
+ $res = Database::simpleQuery('SELECT branchid, versionid, title, Length(description) AS desclen,
+ dateline, orphan, taskid, installed
FROM minilinux_version ORDER BY branchid, dateline, versionid');
- while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ foreach ($res as $row) {
$list[$row['branchid']][$row['versionid']] = $row;
}
return $list;
@@ -383,11 +407,12 @@ class MiniLinux
* Check whether an optionally required stage4 is available.
* Return true if there is no stage4, otherwise check filesystem,
* or try to request from local dnbd3-server.
+ *
* @param array $data decoded data column from minilinux_version
* @param string[] $errors in array of error messages if not available
* @return bool true if stage4 is available or none required
*/
- public static function checkStage4($data, &$errors = false)
+ public static function checkStage4(array $data, &$errors = false): bool
{
$errors = [];
$image = false;
@@ -405,12 +430,22 @@ class MiniLinux
}
if ($image === false)
return true; // No stage4
- $mask = $rid;
if ($rid === 0) {
- $mask = '*';
+ // Get latest local revision
+ foreach (glob(CONFIG_VMSTORE_DIR . '/' . $image . '.r*', GLOB_NOSORT) as $file) {
+ if (preg_match('/\.r(\d+)$/', $file, $out)) {
+ $cmp = (int)$out[1];
+ if ($cmp > $rid) {
+ $rid = $cmp;
+ }
+ }
+ }
+ }
+ if ($rid > 0 && file_exists(CONFIG_VMSTORE_DIR . '/' . $image . '.r' . $rid)
+ && !file_exists(CONFIG_VMSTORE_DIR . '/' . $image . '.r' . $rid . '.map')) {
+ // Accept if image exists locally and no map file (map file would mean incomplete)
+ return true;
}
- if (glob(CONFIG_VMSTORE_DIR . '/' . $image . '.r' . $mask, GLOB_NOSORT) !== [])
- return true; // Already exists locally
// Not found locally -- try to replicate
$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($sock === false) {
@@ -459,7 +494,7 @@ class MiniLinux
/**
* Determine by which menus/locations each MiniLinux version is being used.
*/
- public static function getBootMenuUsage()
+ public static function getBootMenuUsage(): array
{
if (!Module::isAvailable('serversetup') || !class_exists('BootEntryHook'))
return [];
@@ -472,34 +507,29 @@ class MiniLinux
WHERE module = 'minilinux'
GROUP BY be.data");
$return = [];
- while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ $usedMenuIds = [];
+ foreach ($res as $row) {
$data = json_decode($row['data'], true);
if (!isset($data['id']))
continue;
$id = self::resolveEntryId($data['id']);
- if ($id === false)
- continue;
$new = [
'entryids' => [$row['entryid']],
- 'menus' => explode(',', $row['menus']),
- 'locations' => explode(',', $row['locations']),
+ 'menus' => explode(',', $row['menus'] ?? ''),
+ 'locations' => explode(',', $row['locations'] ?? ''),
];
+ $usedMenuIds = array_merge($usedMenuIds, $new['menus']);
if (isset($return[$id])) {
$return[$id] = array_merge_recursive($return[$id], $new);
} else {
$return[$id] = $new;
}
}
- // Flatten and arrayfy the list of menu ids
- $ids = ArrayUtil::flattenByKey($return, 'menus');
- $ids = array_reduce($ids, function ($carry, $item) {
- return $carry + $item;
- }, []);
// Build id => title map for menus
$res = Database::simpleQuery("SELECT menuid, title FROM serversetup_menu m
- WHERE menuid IN (:menuid)", ['menuid' => $ids]);
+ WHERE menuid IN (:menuid)", ['menuid' => array_unique($usedMenuIds)]);
$menus = [];
- while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ foreach ($res as $row) {
$menus[$row['menuid']] = $row['title'];
}
// Build output array
@@ -521,16 +551,16 @@ class MiniLinux
* Take a configured versionid from a bootentry (serversetup module) and translate
* it, in case it's "default" or just a branch name.
*/
- private static function resolveEntryId($id)
+ private static function resolveEntryId(string $id): string
{
if ($id === 'default') { // Special case
$id = Property::get(MiniLinux::PROPERTY_DEFAULT_BOOT_EFFECTIVE);
}
if (substr_count($id, '/') < 2) {
// Maybe this is a branchid, which means latest from according branch (installed only)
- $res = Database::queryFirst('SELECT versionid FROM minilinux_version WHERE branchid = :id AND installed = 1
+ $res = Database::queryFirst('SELECT versionid FROM minilinux_version WHERE branchid = :id AND installed = :ok
ORDER BY dateline DESC LIMIT 1',
- ['id' => $id]);
+ ['id' => $id, 'ok' => self::INSTALL_OK]);
if ($res !== false) {
$id = $res['versionid'];
}
@@ -538,4 +568,4 @@ class MiniLinux
return $id;
}
-} \ No newline at end of file
+}
diff --git a/modules-available/minilinux/install.inc.php b/modules-available/minilinux/install.inc.php
index e71e3c10..7ef82d74 100644
--- a/modules-available/minilinux/install.inc.php
+++ b/modules-available/minilinux/install.inc.php
@@ -2,7 +2,7 @@
$result[] = tableCreate('minilinux_source', "
`sourceid` varchar(8) CHARACTER SET ascii NOT NULL,
- `title` varchar(100) NOT NULL,
+ `title` varchar(150) NOT NULL,
`url` varchar(200) NOT NULL,
`lastupdate` int(10) UNSIGNED NOT NULL DEFAULT '0',
`taskid` char(36) CHARACTER SET ascii DEFAULT NULL,
@@ -13,7 +13,8 @@ $result[] = tableCreate('minilinux_source', "
$result[] = tableCreate('minilinux_branch', "
`sourceid` varchar(8) CHARACTER SET ascii DEFAULT NULL,
`branchid` varchar(40) CHARACTER SET ascii NOT NULL,
- `title` varchar(100) NOT NULL,
+ `title` varchar(150) NOT NULL,
+ `color` varchar(7) NOT NULL,
`description` blob NOT NULL,
PRIMARY KEY (`branchid`),
KEY (`title`)
@@ -21,7 +22,8 @@ $result[] = tableCreate('minilinux_branch', "
$result[] = tableCreate('minilinux_version', "
`branchid` varchar(40) CHARACTER SET ascii NOT NULL,
`versionid` varchar(72) CHARACTER SET ascii NOT NULL,
- `title` varchar(100) NOT NULL,
+ `title` varchar(150) NOT NULL,
+ `description` blob NOT NULL,
`dateline` int(10) UNSIGNED NOT NULL,
`data` blob NOT NULL,
`orphan` tinyint(3) UNSIGNED NOT NULL,
@@ -39,4 +41,28 @@ $result[] = tableAddConstraint('minilinux_version', 'branchid', 'minilinux_branc
$result[] = tableAddConstraint('minilinux_branch', 'sourceid', 'minilinux_source', 'sourceid',
'ON UPDATE CASCADE ON DELETE SET NULL');
+// 2022-10-17: Add color to branch, description to version
+if (!tableHasColumn('minilinux_branch', 'color')) {
+ if (Database::exec("ALTER TABLE `minilinux_branch` ADD COLUMN `color` varchar(7) NOT NULL DEFAULT '' AFTER `title`") !== false) {
+ $result[] = UPDATE_DONE;
+ } else {
+ finalResponse(UPDATE_FAILED, Database::lastError());
+ }
+}
+if (!tableHasColumn('minilinux_version', 'description')) {
+ // BLOB/TEXT cannot have non-NULL default on older MariaDB
+ if (Database::exec("ALTER TABLE `minilinux_version` ADD COLUMN `description` blob NULL DEFAULT NULL AFTER `title`") !== false) {
+ $result[] = UPDATE_DONE;
+ } else {
+ finalResponse(UPDATE_FAILED, Database::lastError());
+ }
+}
+
+// 2023-07-17: Make title columns larger
+foreach (['minilinux_source', 'minilinux_branch', 'minilinux_version'] as $table) {
+ if (stripos(tableColumnType($table, 'title'), 'varchar(150)') === false) {
+ Database::exec("ALTER TABLE `$table` MODIFY `title` varchar(150) NOT NULL");
+ }
+}
+
responseFromArray($result);
diff --git a/modules-available/minilinux/lang/de/messages.json b/modules-available/minilinux/lang/de/messages.json
index e957ee09..c32fa20d 100644
--- a/modules-available/minilinux/lang/de/messages.json
+++ b/modules-available/minilinux/lang/de/messages.json
@@ -1,10 +1,10 @@
{
- "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",
+ "default-is-invalid": "Gew\u00e4hltes Netboot-Grundsystem ist ung\u00fcltig",
+ "default-not-installed": "Gew\u00e4hltes Netboot-Grundsystem {{0}} ist nicht (mehr) installiert",
+ "default-update-available": "F\u00fcr das Gew\u00e4hlte Netboot-Grundsystem {{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-default-set": "Kein Netboot-Grundsystem als Standard festgelegt",
"no-such-version": "Ung\u00fcltige\/Unbekannte Version: {{0}}",
- "please-download-minilinux": "Wichtige Dateien der MiniLinux-Installation fehlen",
+ "please-download-minilinux": "Wichtige Dateien der Netboot-Grundsysteminstallation fehlen",
"version-deleted": "Version {{0}} wurde gel\u00f6scht"
-} \ No newline at end of file
+}
diff --git a/modules-available/minilinux/lang/de/module.json b/modules-available/minilinux/lang/de/module.json
index 9cf5c1a1..f47249d5 100644
--- a/modules-available/minilinux/lang/de/module.json
+++ b/modules-available/minilinux/lang/de/module.json
@@ -6,12 +6,13 @@
"file-ok": "OK",
"file-size-mismatch": "Dateigr\u00f6\u00dfe stimmt nicht",
"ipxe-debug": "Debug-Ausgaben statt Bootlogo",
- "ipxe-insecure-cpu": "Alle Mitigations for CPU-Sicherheitsl\u00fccken deaktivieren",
+ "ipxe-force-init-dhcp": "Erzwinge erneuten DHCP-Request nach Laden des initramfs",
+ "ipxe-insecure-cpu": "Alle Mitigations f\u00fcr CPU-Sicherheitsl\u00fccken deaktivieren",
"ipxe-kcl-extra": "Modifikation der Kernel-Command-Line",
"latest_of_branch": "(Neueste lokal vorhandene Version)",
"menu-sources": "Update-Quellen",
"menu-versions": "Verf\u00fcgbare Versionen",
- "module_name": "Netboot Grundsystem",
+ "module_name": "Netboot-Grundsystem",
"not_installed_hint": "(nicht installiert)",
- "page_title": "Linuxvarianten f\u00fcr Netboot verwalten"
-} \ No newline at end of file
+ "page_title": "Netboot-Grundsystemverwaltung"
+}
diff --git a/modules-available/minilinux/lang/de/permissions.json b/modules-available/minilinux/lang/de/permissions.json
index c7d7df54..4773611a 100644
--- a/modules-available/minilinux/lang/de/permissions.json
+++ b/modules-available/minilinux/lang/de/permissions.json
@@ -1,5 +1,5 @@
{
- "delete": "Ein heruntergeladenes Linux l\u00f6schen.",
- "update": "Aktualisieren von Komponenten des Minilinux.",
- "view": "Zeige Komponenten des Minilinux. Wird nicht ben\u00f6tigt, wenn Nutzer eine der anderen Rechte hat."
+ "delete": "Ein heruntergeladenes Netboot-Grundsystem l\u00f6schen.",
+ "update": "Aktualisieren von Komponenten des Netboot-Grundsystems.",
+ "view": "Zeige Komponenten des Netboot-Grundsystems. Wird nicht ben\u00f6tigt, wenn Nutzer eine der anderen Rechte hat."
} \ 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 3be2bea1..894b864b 100644
--- a/modules-available/minilinux/lang/de/template-tags.json
+++ b/modules-available/minilinux/lang/de/template-tags.json
@@ -13,7 +13,7 @@
"lang_maybeMissingStage4": "Stage 4 m\u00f6glicherweise nicht verf\u00fcgbar",
"lang_menuEntries": "Men\u00fceintr\u00e4ge",
"lang_menus": "Men\u00fcs",
- "lang_minilinuxHeading": "Netboot Linux verwalten",
+ "lang_minilinuxHeading": "Netboot-Grundsystem verwalten",
"lang_orphanedVersion": "Verwaist",
"lang_orphanedVersionToolTip": "Diese Version wird vom Update-Server nicht mehr angeboten",
"lang_releaseDate": "Ver\u00f6ffentlichungsdatum",
diff --git a/modules-available/minilinux/lang/en/messages.json b/modules-available/minilinux/lang/en/messages.json
index 7c0b2c5d..193b18fa 100644
--- a/modules-available/minilinux/lang/en/messages.json
+++ b/modules-available/minilinux/lang/en/messages.json
@@ -5,6 +5,6 @@
"delete-error": "Error deleting version {{0}}: {{1}}",
"no-default-set": "No default system selected",
"no-such-version": "No such version: {{0}}",
- "please-download-minilinux": "Important files from the mini Linux installation are missing.",
+ "please-download-minilinux": "Important files from the netboot Linux installation are missing.",
"version-deleted": "Deleted version {{0}}"
} \ No newline at end of file
diff --git a/modules-available/minilinux/lang/en/module.json b/modules-available/minilinux/lang/en/module.json
index b58c48e2..ff5c7a49 100644
--- a/modules-available/minilinux/lang/en/module.json
+++ b/modules-available/minilinux/lang/en/module.json
@@ -6,6 +6,7 @@
"file-ok": "OK",
"file-size-mismatch": "File size mismatch",
"ipxe-debug": "Print debug messages instead of showing splash screen",
+ "ipxe-force-init-dhcp": "Force another DHCP request after loading initramfs",
"ipxe-insecure-cpu": "Disable all mitigations for CPU security flaws",
"ipxe-kcl-extra": "Modifications to the kernel command line",
"latest_of_branch": "(Latest locally available version)",
diff --git a/modules-available/minilinux/lang/en/permissions.json b/modules-available/minilinux/lang/en/permissions.json
index 124dcdb8..9d97ad00 100644
--- a/modules-available/minilinux/lang/en/permissions.json
+++ b/modules-available/minilinux/lang/en/permissions.json
@@ -1,5 +1,5 @@
{
- "delete": "Delete a downloaded Linux version.",
- "update": "Update minilinux components.",
- "view": "Show list of minilinux components. Not needed if User has any of the other permissions."
+ "delete": "Delete a downloaded netboot Linux version.",
+ "update": "Update netboot Linux components.",
+ "view": "Show list of netboot Linux components. Not needed if user has any of the other permissions."
} \ No newline at end of file
diff --git a/modules-available/minilinux/page.inc.php b/modules-available/minilinux/page.inc.php
index 03ec121e..8004f1ab 100644
--- a/modules-available/minilinux/page.inc.php
+++ b/modules-available/minilinux/page.inc.php
@@ -25,49 +25,72 @@ class Page_MiniLinux extends Page
}
User::assertPermission('view');
- Dashboard::addSubmenu('?do=minilinux', Dictionary::translate('menu-versions', true));
- Dashboard::addSubmenu('?do=minilinux&show=sources', Dictionary::translate('menu-sources', true));
+ Dashboard::addSubmenu('?do=minilinux', Dictionary::translate('menu-versions'));
+ Dashboard::addSubmenu('?do=minilinux&show=sources', Dictionary::translate('menu-sources'));
}
protected function doRender()
{
- 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));
- }
$show = Request::get('show', 'list', 'string');
if ($show === 'list') {
// List branches and versions
- $branches = Database::queryAll('SELECT sourceid, branchid, title, description FROM minilinux_branch ORDER BY title ASC');
+ $branches = Database::queryAll('SELECT sourceid, branchid, title, color, description FROM minilinux_branch ORDER BY title ASC');
$versions = MiniLinux::queryAllVersionsByBranch();
$usage = MiniLinux::getBootMenuUsage();
+ $sourceList = [];
// Group by branch for detailed listing, add usage info
foreach ($branches as &$branch) {
- $branch['bid'] = 'div-' . str_replace('/', '-', $branch['branchid']);
+ // Little hack: We abuse the title for ordering, so if the second char is a space, assume the first one
+ // is just for sort order and remove it.
+ if ($branch['title'][1] === ' ') {
+ $branch['title'] = substr($branch['title'], 2);
+ }
+ $bid = 'div-' . str_replace('/', '-', $branch['branchid']);
+ if (!isset($sourceList[$branch['sourceid']])) {
+ $sourceList[$branch['sourceid']] = ['sourceid' => $branch['sourceid'], 'list' => []];
+ }
+ $sourceList[$branch['sourceid']]['list'][] = [
+ 'title' => $branch['title'],
+ 'color' => $branch['color'],
+ 'bid' => $bid
+ ];
+ $branch['bid'] = $bid;
if (isset($versions[$branch['branchid']])) {
$branch['versionlist'] = $this->renderVersionList($versions[$branch['branchid']], $usage);
}
}
unset($branch);
- Render::addTemplate('branches', ['branches' => $branches]);
+ $sourceList = array_values($sourceList);
} elseif ($show === 'sources') {
// List sources
$res = Database::simpleQuery('SELECT sourceid, title, url, lastupdate, pubkey FROM minilinux_source ORDER BY title, sourceid');
- $data = ['list' => [], 'show_refresh' => true];
+ $sourceViewData = ['list' => [], 'show_refresh' => true];
$tooOld = strtotime('-7 days');
$showRefresh = strtotime('-5 minutes');
- while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ foreach ($res as $row) {
$row['lastupdate_s'] = Util::prettyTime($row['lastupdate']);
if ($row['lastupdate'] != 0 && $row['lastupdate'] < $tooOld) {
$row['update_class'] = 'text-danger';
}
if ($row['lastupdate'] > $showRefresh) {
- $data['show_refresh'] = false;
+ $sourceViewData['show_refresh'] = false;
}
- $data['list'][] = $row;
+ $sourceViewData['list'][] = $row;
}
- Render::addTemplate('sources', $data);
+ }
+ // Output
+ Render::addTemplate('page-minilinux', [
+ 'default' => Property::get(MiniLinux::PROPERTY_DEFAULT_BOOT),
+ 'sources' => $sourceList ?? null,
+ ]);
+ // Warning
+ if (!MiniLinux::updateCurrentBootSetting()) {
+ Message::addError('default-not-installed', Property::get(MiniLinux::PROPERTY_DEFAULT_BOOT));
+ }
+ if (isset($branches)) {
+ Render::addTemplate('branches', ['branches' => $branches]);
+ } elseif (isset($sourceViewData)) {
+ Render::addTemplate('sources', $sourceViewData);
} else {
Message::addError('main.invalid-action', $show);
}
@@ -84,20 +107,20 @@ class Page_MiniLinux extends Page
}
}
- private function renderVersionList($versions, $usage)
+ private function renderVersionList(array $versions, array $usage): string
{
$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'] > 0 && !$version['installed']) || ($version['orphan'] > 1);
+ $version['orphan'] = ($version['orphan'] > 0 && $version['installed'] == MiniLinux::INSTALL_MISSING) || ($version['orphan'] > 1);
$version['downloading'] = $version['taskid'] && Taskmanager::isRunning(Taskmanager::status($version['taskid']));
- if ($version['installed'] && $version['versionid'] !== $def) {
+ if ($version['installed'] != MiniLinux::INSTALL_MISSING && $version['versionid'] !== $def) {
$version['showsetdefault'] = true;
}
if ($version['versionid'] === $def) {
$version['isdefault'] = true;
- if (!$version['installed']) {
+ if (!$version['installed'] != MiniLinux::INSTALL_OK) {
$version['default_class'] = 'bg-danger';
}
}
@@ -116,7 +139,8 @@ class Page_MiniLinux extends Page
if ($versionid === false) {
die('What!');
}
- $ver = Database::queryFirst('SELECT versionid, taskid, data, installed FROM minilinux_version WHERE versionid = :versionid',
+ $ver = Database::queryFirst('SELECT versionid, description, taskid, data, installed
+ FROM minilinux_version WHERE versionid = :versionid',
['versionid' => $versionid]);
if ($ver === false) {
die('No such version');
@@ -128,7 +152,7 @@ class Page_MiniLinux extends Page
}
$data['versionid'] = $versionid;
$data['dltask'] = MiniLinux::validateDownloadTask($versionid, $ver['taskid']);
- $data['verify_button'] = !$verify && $data['dltask'] === false;
+ $data['verify_button'] = !$verify && $data['dltask'] === null;
if (is_array($data['files'])) {
$valid = true;
$sort = [];
@@ -152,7 +176,7 @@ class Page_MiniLinux extends Page
if (isset($file['mtime'])) {
$file['mtime_s'] = Util::prettyTime($file['mtime']);
}
- if ($data['dltask']) {
+ if ($data['dltask'] !== null) {
$file['fileid'] = MiniLinux::fileToId($versionid, $file['name']);
}
}
@@ -160,16 +184,17 @@ class Page_MiniLinux extends Page
array_multisort($sort, SORT_ASC, $data['files']);
if (!$valid) {
$data['verify_button'] = false;
- if ($ver['installed']) {
- MiniLinux::setInstalledState($versionid, false);
+ if ($ver['installed'] != MiniLinux::INSTALL_MISSING) {
+ MiniLinux::setInstalledState($versionid, MiniLinux::INSTALL_BROKEN);
}
- } elseif (!$ver['installed'] && $verify) {
- MiniLinux::setInstalledState($versionid, true);
+ } elseif ($ver['installed'] != MiniLinux::INSTALL_OK && $verify) {
+ MiniLinux::setInstalledState($versionid, MiniLinux::INSTALL_OK);
}
}
- if ($data['dltask'] !== false || $ver['installed']) {
+ if ($data['dltask'] !== null || $ver['installed'] != MiniLinux::INSTALL_MISSING) {
MiniLinux::checkStage4($data, $data['s4_errors']);
}
+ $data['changelog'] = Util::markup($ver['description'] ?? '');
echo Render::parse('filelist', $data);
}
@@ -179,7 +204,7 @@ class Page_MiniLinux extends Page
const FILE_CHECKSUM_BAD = 3;
const FILE_NOT_READABLE = 4;
- private function getFileState($versionid, $file, $verify)
+ private function getFileState(string $versionid, array $file, bool $verify): int
{
$path = CONFIG_HTTP_DIR . '/' . $versionid . '/' . $file['name'];
if (!is_file($path))
@@ -206,15 +231,15 @@ class Page_MiniLinux extends Page
{
switch ($state) {
case self::FILE_CHECKSUM_BAD:
- return Dictionary::translate('file-checksum-bad', true);
+ return Dictionary::translate('file-checksum-bad');
case self::FILE_SIZE_MISMATCH:
- return Dictionary::translate('file-size-mismatch', true);
+ return Dictionary::translate('file-size-mismatch');
case self::FILE_MISSING:
- return Dictionary::translate('file-missing', true);
+ return Dictionary::translate('file-missing');
case self::FILE_NOT_READABLE:
- return Dictionary::translate('file-not-readable', true);
+ return Dictionary::translate('file-not-readable');
case self::FILE_OK:
- return Dictionary::translate('file-ok', true);
+ return Dictionary::translate('file-ok');
}
return '???';
}
@@ -227,7 +252,7 @@ class Page_MiniLinux extends Page
die('No version');
}
$task = MiniLinux::downloadVersion($version);
- if ($task === false) {
+ if ($task === null) {
Message::addError('no-such-version', $version);
Message::renderList();
} else {
@@ -249,7 +274,6 @@ 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,
@@ -258,8 +282,10 @@ class Page_MiniLinux extends Page
if ($task !== false) {
$task = Taskmanager::waitComplete($task, 2500);
if (Taskmanager::isFailed($task)) {
+ MiniLinux::setInstalledState($version['versionid'], MiniLinux::INSTALL_BROKEN);
Message::addError('delete-error', $versionid, $task['data']['error']);
} else {
+ MiniLinux::setInstalledState($version['versionid'], MiniLinux::INSTALL_MISSING);
Message::addSuccess('version-deleted', $versionid);
}
}
diff --git a/modules-available/minilinux/templates/branches.html b/modules-available/minilinux/templates/branches.html
index 275f026c..372321e2 100644
--- a/modules-available/minilinux/templates/branches.html
+++ b/modules-available/minilinux/templates/branches.html
@@ -1,7 +1,10 @@
<h3>{{lang_branchesHeading}}</h3>
+<div class="clearfix"></div>
+
<div id="ibm-mainframe">
{{#branches}}
- <div class="panel panel-default">
+ <a id="a-{{bid}}"></a>
+ <div class="panel panel-default" {{#color}}style="background:linear-gradient(90deg, {{color}} 0%, {{color}} 4px, rgba(255,255,255,0) 4px)"{{/color}}>
<div class="panel-heading">
<div class="pull-right slx-pointer" data-toggle="collapse" data-target="#{{bid}}">
{{sourceid}} {{branchid}} <b class="caret"></b>
diff --git a/modules-available/minilinux/templates/filelist.html b/modules-available/minilinux/templates/filelist.html
index fdbef4ad..241d1264 100644
--- a/modules-available/minilinux/templates/filelist.html
+++ b/modules-available/minilinux/templates/filelist.html
@@ -49,7 +49,10 @@
<pre class="collapse" id="error-{{dltask}}"></pre>
{{/dltask}}
{{#changelog}}
-<h4>{{lang_changelog}}</h4>
-{{changelog}}
+ <div class="slx-space"></div>
+<div style="border:1px solid #bbb;padding:4px;border-radius: 3px">
+ <h4>{{lang_changelog}}</h4>
+ {{{changelog}}}
+</div>
{{/changelog}}
<div class="slx-space"></div> \ 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 161fa02f..c66de597 100644
--- a/modules-available/minilinux/templates/page-minilinux.html
+++ b/modules-available/minilinux/templates/page-minilinux.html
@@ -1,3 +1,18 @@
+{{#sources}}
+<div class="panel panel-default pull-right" style="margin:2px">
+ <table class="table table-condensed">
+ <tr style="background:#eee">
+ <th>{{sourceid}}</th>
+ </tr>
+ {{#list}}
+ <tr {{#color}}style="background:linear-gradient(90deg, {{color}} 0%, {{color}} 4px, rgba(255,255,255,0) 4px)"{{/color}}>
+ <td><a href="#a-{{bid}}">{{title}}</a></td>
+ </tr>
+ {{/list}}
+ </table>
+</div>
+{{/sources}}
+
<h1>{{lang_minilinuxHeading}}</h1>
{{lang_selectedDefaultIs}}: <b>{{default}}</b> \ No newline at end of file
diff --git a/modules-available/minilinux/templates/versionlist.html b/modules-available/minilinux/templates/versionlist.html
index 8ab6463c..e66960b2 100644
--- a/modules-available/minilinux/templates/versionlist.html
+++ b/modules-available/minilinux/templates/versionlist.html
@@ -16,7 +16,14 @@
<b class="caret"></b>
</a>
</td>
- <td class="text-nowrap">{{dateline_s}}</td>
+ <td class="text-nowrap">
+ {{#desclen}}
+ <div style="float:right;margin-right:-6px">
+ <span class="glyphicon glyphicon-list-alt"></span>
+ </div>
+ {{/desclen}}
+ {{dateline_s}}
+ </td>
<td>{{title}}</td>
<td class="text-nowrap">
{{#usage.entryids.0}}
@@ -26,18 +33,18 @@
<span class="caret"></span>
</button>
<ul class="dropdown-menu">
- <li role="separator" class="dropdown-header">{{lang_menuEntries}}</li>
+ <li role="separator" class="dropdown-header slx-bold">{{lang_menuEntries}}</li>
{{#usage.entryids}}
<li><a href="?do=serversetup&amp;show=editbootentry&amp;id={{.}}">{{.}}</a></li>
{{/usage.entryids}}
{{#usage.menus.0}}
- <li role="separator" class="dropdown-header">{{lang_menus}}</li>
+ <li role="separator" class="dropdown-header slx-bold">{{lang_menus}}</li>
{{/usage.menus.0}}
{{#usage.menus}}
<li><a href="?do=serversetup&amp;show=editmenu&amp;id={{menuid}}">{{menuname}}</a></li>
{{/usage.menus}}
{{#usage.locations.0}}
- <li role="separator" class="dropdown-header">{{lang_locations}}</li>
+ <li role="separator" class="dropdown-header slx-bold">{{lang_locations}}</li>
{{/usage.locations.0}}
{{#usage.locations}}
<li class="disabled"><a href="#">{{locationname}}</a></li>