Merge remote-tracking branch 'upstream/master' into New-VM-interface

This commit is contained in:
SimonFair
2024-04-13 07:58:36 +01:00
82 changed files with 1438 additions and 1257 deletions

View File

@@ -1203,7 +1203,7 @@ SSL certificate. Use this URL to access your server:
Note that use of a self-signed SSL certificate will generate a browser
warning.
Select **Strict** to enable *exclusive* use of an Unraid.net SSL
Select **Strict** to enable *exclusive* use of a myunraid.net SSL
certificate for https access (see **Provision** below). Note that a DNS
server must be reachable.
@@ -1267,10 +1267,10 @@ To adjust URLs or redirects, see the help text for "Use SSL/TLS".
:end
:mgmt_certificate_expiration_help:
**Provision** may be used to install a *free* Unraid.net SSL Certificate from
**Provision** may be used to install a *free* myunraid.net SSL Certificate from
[Let's Encrypt](https://letsencrypt.org/).
The Unraid.net SSL certificate can be used in two ways. First,
The myunraid.net SSL certificate can be used in two ways. First,
having the certificate present enables your server to respond to an
alternate URL of the form:
@@ -1284,24 +1284,20 @@ set to `*.<hash>.myunraid.net` thus validating the https connection.
You may enable this URL exclusively on your LAN by setting **Use
SSL/TLS** to **Strict**.
The second use for an Unraid.net certificate is to enable secure
remote access available through the My Servers plugin feature. Note
The second use for a myunraid.net certificate is to enable secure
remote access available through the Unraid Connect plugin feature. Note
that it is possible to use secure remote access in conjunction with
insecure local access.
After an Unraid.net SSL Certificate has been installed, two
background services are activated while the server is signed in to unraid.net:
- *updatedns* - This starts 30 seconds after server reboot has completed and contacts the Lime Technology
DNS service to register the servers local IP address. Thereafter it wakes up every 10 minutes in case
the local IP address has changed.
After a myunraid.net SSL Certificate has been installed, a
background service is activated:
- *renewcert* - This starts 60 seconds after server reboot has completed and contacts the Lime Technology
certificate renewal service to determine if your Unraid.net SSL certificate needs to be renewed.
certificate renewal service to determine if your myunraid.net SSL certificate needs to be renewed.
Thereafter it wakes up every 24 hours. If within 30 days of expiration, a new certificate is automatically
provisioned and downloaded to your server.
**Delete** may be used to delete the Unraid.net certificate file.
**Delete** may be used to delete the myunraid.net certificate file.
**nginx certificate handling details**
@@ -1309,7 +1305,7 @@ nginx makes use of two certificate files stored on the USB flash boot device:<br
- a self-signed certificate: `config/ssl/certs/<server-name>_unraid_bundle.pem`
- an Unraid.net certificate: `config/ssl/certs/certificate_bundle.pem`
- a myunraid.net certificate: `config/ssl/certs/certificate_bundle.pem`
The self-signed SSL certificate file is automatically created when nginx
starts; and re-created if the server hostname or local TLD is changed.
@@ -1493,7 +1489,7 @@ This will increase write performance but might possibly decrease read performanc
Let the server act as a central syslog server and collect syslog messages from other systems.
The server can listen on UDP, TCP or both with a selectable port number.
Syslog information is stored per IP address. That is every system gets its own syslog file.
Syslog information is stored either per IP address or per hostname. That is every system gets its own syslog file.
:end
:syslog_local_folder_help:
@@ -1501,6 +1497,15 @@ Select the share folder where the syslogs will be stored.
It is recommended that you use a share located on the cache drive to prevent array disk spinups.
:end
:syslog_remote_system_identifier_help:
Select the identifier for the remote system (used in the logfile name).
* "IP Address" uses the IP address (IPv4 or IPv6) of the sending system.
* "Hostname (from syslog message)" uses the hostname included in each syslog message.
* "Hostname (from DNS reverse lookup)" performs a DNS reverse lookup for the sending IP and uses the result.
:end
:syslog_local_rotation_help:
By default LOG rotation is disabled and will create a single LOG file of unlimited size.
@@ -2493,7 +2498,7 @@ If set to 'Yes' the bash history will persist reboots, set to 'No' to disable.
:WOL_intro_help:
This page allows the setup to start/resume and stop VMs, Containters(Docker and LXC) using WOL magic packets
It does setup wake up of the Unraid server.
It does not setup wake up of the Unraid server.
The process will look for the defined mac address defined within the service(VM or container) with the exception of dockers. Dockers do not have a mac address until they are running so you will need to define a user mac address to allow you to start them
@@ -2502,14 +2507,13 @@ If the service is paused a WOL Packet will resume.
For each service you can set: enable, disable or enable and shutdown
When the enable and shutdown is set if the service is running when the next WOL packet is recieved a shutdown will be performed.
:end:
:end
:WOL_enable_help:
If set to yes Unraidwold daemon is set to run.
:end
:WOL_docker_help:
:WOL_run_docker_help:
If set to yes when wake on lan packets are received checks are carrried out for dockers otherwise dockers will be ignored.
:end
@@ -2535,4 +2539,4 @@ Enable to set the NIC not to filer packets.
:WOL_log_file_help:
Default is to log to syslog but if you want a different log location set the file name.
:end
:end

View File

@@ -111,6 +111,7 @@ function LockButton() {
}
function loadlist(init) {
timers.docker = setTimeout(function(){$('div.spinner.fixed').show('slow');},500);
docker = [];
$.get('/plugins/dynamix.docker.manager/include/DockerContainers.php',function(d) {
clearTimeout(timers.docker);
var data = d.split(/\0/);

View File

@@ -748,6 +748,7 @@ _(Categories)_:
: <input type="hidden" name="contCategory">
<select id="catSelect" size="1" multiple="multiple" style="display:none" onchange="prepareCategory();">
<optgroup label="_(Categories)_">
<option value="AI:">_(AI)_</option>
<option value="Backup:">_(Backup)_</option>
<option value="Cloud:">_(Cloud)_</option>
<option value="Crypto:">_(Crypto Currency)_</option>

View File

@@ -176,7 +176,7 @@ class DockerTemplates {
}
// if after above we don't have a valid url, check for GitLab
if (empty($github_api['url'])) {
$source = file_get_contents($url);
$source = $this->download_url($url);
// the following should always exist for GitLab Community Edition or GitLab Enterprise Edition
if (preg_match("/<meta content='GitLab (Community|Enterprise) Edition' name='description'>/", $source) > 0) {
$parse = parse_url($url);
@@ -721,7 +721,7 @@ class DockerClient {
$fp = stream_socket_client('unix:///var/run/docker.sock', $errno, $errstr);
if ($fp === false) {
echo "Couldn't create socket: [$errno] $errstr";
return null;
return [];
}
$protocol = $unchunk ? 'HTTP/1.0' : 'HTTP/1.1';
$out = "$method {$api}{$url} $protocol\r\nHost:127.0.0.1\r\nConnection:Close\r\n";
@@ -915,6 +915,7 @@ class DockerClient {
$c['Volumes'] = $info['HostConfig']['Binds'];
$c['Created'] = $this->humanTiming($ct['Created']);
$c['NetworkMode'] = $ct['HostConfig']['NetworkMode'];
$c['Manager'] = $info['Config']['Labels']['net.unraid.docker.managed'] ?? false;
[$net, $id] = array_pad(explode(':',$c['NetworkMode']),2,'');
$c['CPUset'] = $info['HostConfig']['CpusetCpus'];
$c['BaseImage'] = $ct['Labels']['BASEIMAGE'] ?? false;
@@ -978,7 +979,7 @@ class DockerClient {
$c['Id'] = $this->extractID($ct['Id']);
$c['ParentId'] = $this->extractID($ct['ParentId']);
$c['Size'] = $this->formatBytes($ct['Size']);
$c['VirtualSize'] = $this->formatBytes($ct['VirtualSize']);
$c['VirtualSize'] = $this->formatBytes($ct['VirtualSize'] ?? null);
$c['Tags'] = array_map('htmlspecialchars', $ct['RepoTags'] ?? []);
$c['Repository'] = DockerUtil::parseImageTag($ct['RepoTags'][0]??'')['strRepo'];
$c['usedBy'] = $this->usedBy($c['Id']);

View File

@@ -120,20 +120,25 @@ foreach ($containers as $ct) {
switch ($updateStatus) {
case 0:
echo "<span class='green-text' style='white-space:nowrap;'><i class='fa fa-check fa-fw'></i> "._('up-to-date')."</span>";
echo "<div class='advanced'><a class='exec' onclick=\"updateContainer('".addslashes(htmlspecialchars($name))."');\"><span style='white-space:nowrap;'><i class='fa fa-cloud-download fa-fw'></i> "._('force update')."</span></a></div>";
break;
case 1:
echo "<div class='advanced'><span class='orange-text' style='white-space:nowrap;'><i class='fa fa-flash fa-fw'></i> "._('update ready')."</span></div>";
echo "<a class='exec' onclick=\"updateContainer('".addslashes(htmlspecialchars($name))."');\"><span style='white-space:nowrap;'><i class='fa fa-cloud-download fa-fw'></i> "._('apply update')."</span></a>";
break;
case 2:
echo "<div class='advanced'><span class='orange-text' style='white-space:nowrap;'><i class='fa fa-flash fa-fw'></i> "._('rebuild ready')."</span></div>";
echo "<a class='exec'><span style='white-space:nowrap;'><i class='fa fa-recycle fa-fw'></i> "._('rebuilding')."</span></a>";
break;
default:
echo "<span class='orange-text' style='white-space:nowrap;'><i class='fa fa-unlink'></i> "._('not available')."</span>";
echo "<div class='advanced'><a class='exec' onclick=\"updateContainer('".addslashes(htmlspecialchars($name))."');\"><span style='white-space:nowrap;'><i class='fa fa-cloud-download fa-fw'></i> "._('force update')."</span></a></div>";
if ($ct['Manager'] == "dockerman")
echo "<div class='advanced'><a class='exec' onclick=\"updateContainer('".addslashes(htmlspecialchars($name))."');\"><span style='white-space:nowrap;'><i class='fa fa-cloud-download fa-fw'></i> "._('force update')."</span></a></div>";
break;
case 1:
echo "<div class='advanced'><span class='orange-text' style='white-space:nowrap;'><i class='fa fa-flash fa-fw'></i> "._('update ready')."</span></div>";
if ($ct['Manager'] == "dockerman")
echo "<a class='exec' onclick=\"updateContainer('".addslashes(htmlspecialchars($name))."');\"><span style='white-space:nowrap;'><i class='fa fa-cloud-download fa-fw'></i> "._('apply update')."</span></a>";
else
echo "<span style='white-space:nowrap;'><i class='fa fa-cloud-download fa-fw'></i> "._('update available')."</span>";
break;
case 2:
echo "<div class='advanced'><span class='orange-text' style='white-space:nowrap;'><i class='fa fa-flash fa-fw'></i> "._('rebuild ready')."</span></div>";
echo "<a class='exec'><span style='white-space:nowrap;'><i class='fa fa-recycle fa-fw'></i> "._('rebuilding')."</span></a>";
break;
default:
echo "<span class='orange-text' style='white-space:nowrap;'><i class='fa fa-unlink'></i> "._('not available')."</span>";
if ($ct['Manager'] == "dockerman")
echo "<div class='advanced'><a class='exec' onclick=\"updateContainer('".addslashes(htmlspecialchars($name))."');\"><span style='white-space:nowrap;'><i class='fa fa-cloud-download fa-fw'></i> "._('force update')."</span></a></div>";
break;
}
echo "<div class='advanced'><i class='fa fa-info-circle fa-fw'></i> ".compress(_($version),12,0)."</div></td>";
echo "<td>{$ct['NetworkMode']}</td>";

View File

@@ -14,8 +14,9 @@
<?
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
require_once "$docroot/plugins/dynamix.docker.manager/include/DockerClient.php";
require_once "$docroot/webGui/include/Wrappers.php";
$ncsi = exec("wget --spider --no-check-certificate -nv -T10 -t1 https://www.msftncsi.com/ncsi.txt 2>&1|grep -o 'OK'")=='OK';
$ncsi = check_network_connectivity();
$DockerTemplates = new DockerTemplates();
if ($ncsi) $DockerTemplates->downloadTemplates();
$DockerTemplates->getAllInfo($ncsi,$ncsi);

View File

@@ -270,6 +270,8 @@ function xmlToCommand($xml, $create_paths=false) {
$Mode = strval($config['Mode']);
if ($confType != "device" && !strlen($containerConfig)) continue;
if ($confType == "path") {
if ( ! trim($hostConfig) || ! trim($containerConfig) )
continue;
$Volumes[] = escapeshellarg($hostConfig).':'.escapeshellarg($containerConfig).':'.escapeshellarg($Mode);
if (!file_exists($hostConfig) && $create_paths) {
@mkdir($hostConfig, 0777, true);

View File

@@ -1,7 +1,7 @@
#!/usr/bin/php -q
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
/* Copyright 2005-2024, Lime Technology
* Copyright 2012-2024, Bergware International.
* Copyright 2014-2021, Guilherme Jardim, Eric Schultz, Jon Panozzo.
*
* This program is free software; you can redistribute it and/or
@@ -16,6 +16,7 @@
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
require_once "$docroot/webGui/include/Wrappers.php";
require_once "$docroot/plugins/dynamix.docker.manager/include/DockerClient.php";
// this command will set the $notify array
extract(parse_plugin_cfg('dynamix', true));
// Multi-language support
@@ -43,7 +44,7 @@ if (!isset($check)) {
$DockerTemplates->getAllInfo(true);
echo " Done.";
} else {
$notify = "$docroot/webGui/scripts/notify";
$script = "$docroot/webGui/scripts/notify";
$var = (array)@parse_ini_file("/var/local/emhttp/var.ini");
$server = strtoupper(_var($var,'NAME','tower'));
$output = _var($notify,'docker_notify');
@@ -59,7 +60,7 @@ if (!isset($check)) {
$event = str_replace("&apos;","'",_("Docker")." - $name [$new]");
$subject = str_replace("&apos;","'",sprintf(_("Notice [%s] - Version update %s"),$server,$new));
$description = str_replace("&apos;","'",sprintf(_("A new version of %s is available"),$name));
exec("$notify -e ".escapeshellarg($event)." -s ".escapeshellarg($subject)." -d ".escapeshellarg($description)." -i ".escapeshellarg("normal $output")." -l '/Docker' -x");
exec("$script -e ".escapeshellarg($event)." -s ".escapeshellarg($subject)." -d ".escapeshellarg($description)." -i ".escapeshellarg("normal $output")." -l '/Docker' -x");
}
}
}

View File

@@ -30,8 +30,7 @@ if (!document.getElementsByTagName(modalsWebComponent).length) {
$i18nHost.appendChild($modals);
}
</script>
<?
echo "
<unraid-i18n-host>
<unraid-user-profile server='" . $serverState->getServerStateJson() . "'></unraid-user-profile>
</unraid-i18n-host>";
<unraid-user-profile server="<?= $serverState->getServerStateJsonForHtmlAttr() ?>"></unraid-user-profile>
</unraid-i18n-host>

View File

@@ -34,11 +34,20 @@ class ServerState
protected $webguiGlobals;
private $var;
private $flashbackupCfg;
private $apiKey = '';
private $apiVersion = '';
private $avatar = '';
private $email = '';
private $extraOrigins = [];
private $flashBackupActivated = '';
private $hasRemoteApikey = false;
private $registeredTime = '';
private $username = '';
private $connectPluginInstalled = '';
private $connectPluginVersion;
private $configErrorEnum = [
"error" => 'UNKNOWN_ERROR',
"ineligible" => 'INELIGIBLE',
"invalid" => 'INVALID',
"nokeyserver" => 'NO_KEY_SERVER',
"withdrawn" => 'WITHDRAWN',
@@ -58,9 +67,9 @@ class ServerState
public $host = 'unknown';
public $combinedKnownOrigins = [];
public $nginxCfg;
public $flashbackupStatus;
public $registered;
public $nginxCfg = [];
public $flashbackupStatus = [];
public $registered = false;
public $myServersMiniGraphConnected = false;
public $keyfileBase64 = '';
@@ -78,11 +87,42 @@ class ServerState
// echo "<pre>" . json_encode($this->webguiGlobals, JSON_PRETTY_PRINT) . "</pre>";
$this->var = (array)parse_ini_file('state/var.ini');
$this->nginxCfg = parse_ini_file('/var/local/emhttp/nginx.ini');
$this->nginxCfg = @parse_ini_file('/var/local/emhttp/nginx.ini') ?? [];
$this->flashbackupCfg = '/var/local/emhttp/flashbackup.ini';
$this->flashbackupStatus = (file_exists($this->flashbackupCfg)) ? @parse_ini_file($this->flashbackupCfg) : [];
$this->osVersion = $this->var['version'];
$this->osVersionBranch = trim(@exec('plugin category /var/log/plugins/unRAIDServer.plg') ?? 'stable');
$caseModelFile = '/boot/config/plugins/dynamix/case-model.cfg';
$this->caseModel = file_exists($caseModelFile) ? file_get_contents($caseModelFile) : '';
$this->rebootDetails = new RebootDetails();
$this->keyfileBase64 = empty($this->var['regFILE']) ? null : @file_get_contents($this->var['regFILE']);
if ($this->keyfileBase64 !== false) {
$this->keyfileBase64 = @base64_encode($this->keyfileBase64);
$this->keyfileBase64UrlSafe = str_replace(['+', '/', '='], ['-', '_', ''], trim($this->keyfileBase64));
}
$this->updateOsCheck = new UnraidOsCheck();
$this->updateOsIgnoredReleases = $this->updateOsCheck->getIgnoredReleases();
$this->updateOsNotificationsEnabled = !empty(@$this->getWebguiGlobal('notify', 'unraidos'));
$this->updateOsResponse = $this->updateOsCheck->getUnraidOSCheckResult();
$this->setConnectValues();
}
/**
* Retrieve the value of a webgui global setting.
*/
public function getWebguiGlobal(string $key, string $subkey = null) {
if (!$subkey) {
return _var($this->webguiGlobals, $key, '');
}
$keyArray = _var($this->webguiGlobals, $key, []);
return _var($keyArray, $subkey, '');
}
private function setConnectValues() {
if (file_exists('/var/lib/pkgtools/packages/dynamix.unraid.net')) {
$this->connectPluginInstalled = 'dynamix.unraid.net.plg';
}
@@ -93,11 +133,29 @@ class ServerState
$this->connectPluginInstalled .= '_installFailed';
}
// exit early if the plugin is not installed
if (!$this->connectPluginInstalled) {
return;
}
$this->connectPluginVersion = file_exists('/var/log/plugins/dynamix.unraid.net.plg')
? trim(@exec('/usr/local/sbin/plugin version /var/log/plugins/dynamix.unraid.net.plg 2>/dev/null'))
: (file_exists('/var/log/plugins/dynamix.unraid.net.staging.plg')
? trim(@exec('/usr/local/sbin/plugin version /var/log/plugins/dynamix.unraid.net.staging.plg 2>/dev/null'))
: 'base-' . $this->var['version']);
$this->getMyServersCfgValues();
$this->getConnectKnownOrigins();
$this->getFlashBackupStatus();
}
private function getFlashBackupStatus() {
$flashbackupCfg = '/var/local/emhttp/flashbackup.ini';
$this->flashbackupStatus = (file_exists($flashbackupCfg)) ? @parse_ini_file($flashbackupCfg) : [];
$this->flashBackupActivated = empty($this->flashbackupStatus['activated']) ? '' : 'true';
}
private function getMyServersCfgValues() {
/**
* @todo can we read this from somewhere other than the flash? Connect page uses this path and /boot/config/plugins/dynamix.my.servers/myservers.cfg…
* - $myservers_memory_cfg_path ='/var/local/emhttp/myservers.cfg';
@@ -122,15 +180,17 @@ class ServerState
$this->myServersFlashCfg['remote']['dynamicRemoteAccessType'] = "DISABLED";
}
$this->osVersion = $this->var['version'];
$this->osVersionBranch = trim(@exec('plugin category /var/log/plugins/unRAIDServer.plg') ?? 'stable');
$this->apiKey = $this->myServersFlashCfg['upc']['apikey'] ?? '';
$this->apiVersion = $this->myServersFlashCfg['api']['version'] ?? '';
$this->avatar = (!empty($this->myServersFlashCfg['remote']['avatar']) && $this->connectPluginInstalled) ? $this->myServersFlashCfg['remote']['avatar'] : '';
$this->email = $this->myServersFlashCfg['remote']['email'] ?? '';
$this->hasRemoteApikey = !empty($this->myServersFlashCfg['remote']['apikey']);
$this->registered = !empty($this->myServersFlashCfg['remote']['apikey']) && $this->connectPluginInstalled;
$this->registeredTime = $this->myServersFlashCfg['remote']['regWizTime'] ?? '';
$this->username = $this->myServersFlashCfg['remote']['username'] ?? '';
}
$caseModelFile = '/boot/config/plugins/dynamix/case-model.cfg';
$this->caseModel = file_exists($caseModelFile) ? file_get_contents($caseModelFile) : '';
$this->rebootDetails = new RebootDetails();
private function getConnectKnownOrigins() {
/**
* Allowed origins warning displayed when the current webGUI URL is NOT included in the known lists of allowed origins.
* Include localhost in the test, but only display HTTP(S) URLs that do not include localhost.
@@ -145,6 +205,11 @@ class ServerState
$combinedOrigins = $allowedOrigins . "," . $extraOrigins; // combine the two strings for easier searching
$combinedOrigins = str_replace(" ", "", $combinedOrigins); // replace any spaces with nothing
$hostNotKnown = stripos($combinedOrigins, $this->host) === false; // check if the current host is in the combined list of origins
if ($extraOrigins) {
$this->extraOrigins = explode(",", $extraOrigins);
}
if ($hostNotKnown) {
$this->combinedKnownOrigins = explode(",", $combinedOrigins);
@@ -161,29 +226,8 @@ class ServerState
}
}
}
$this->keyfileBase64 = empty($this->var['regFILE']) ? null : @file_get_contents($this->var['regFILE']);
if ($this->keyfileBase64 !== false) {
$this->keyfileBase64 = @base64_encode($this->keyfileBase64);
$this->keyfileBase64UrlSafe = str_replace(['+', '/', '='], ['-', '_', ''], trim($this->keyfileBase64));
}
$this->updateOsCheck = new UnraidOsCheck();
$this->updateOsIgnoredReleases = $this->updateOsCheck->getIgnoredReleases();
$this->updateOsNotificationsEnabled = !empty(@$this->getWebguiGlobal('notify', 'unraidos'));
$this->updateOsResponse = $this->updateOsCheck->getUnraidOSCheckResult();
}
/**
* Retrieve the value of a webgui global setting.
*/
public function getWebguiGlobal(string $key, string $subkey = null) {
if (!$subkey) {
return _var($this->webguiGlobals, $key, '');
}
$keyArray = _var($this->webguiGlobals, $key, []);
return _var($keyArray, $subkey, '');
}
/**
* Retrieve the server information as an associative array
*
@@ -192,13 +236,13 @@ class ServerState
public function getServerState()
{
$serverState = [
"apiKey" => $this->myServersFlashCfg['upc']['apikey'] ?? '',
"apiVersion" => $this->myServersFlashCfg['api']['version'] ?? '',
"avatar" => (!empty($this->myServersFlashCfg['remote']['avatar']) && $this->connectPluginInstalled) ? $this->myServersFlashCfg['remote']['avatar'] : '',
"apiKey" => $this->apiKey,
"apiVersion" => $this->apiVersion,
"avatar" => $this->avatar,
"caseModel" => $this->caseModel,
"config" => [
'valid' => ($this->var['configValid'] === 'yes'),
'error' => isset($this->configErrorEnum[$this->var['configValid']]) ? $this->configErrorEnum[$this->var['configValid']] : 'UNKNOWN_ERROR',
'error' => isset($this->configErrorEnum[$this->var['configValid']]) ? $this->configErrorEnum[$this->var['configValid']] : null,
],
"connectPluginInstalled" => $this->connectPluginInstalled,
"connectPluginVersion" => $this->connectPluginVersion,
@@ -207,35 +251,35 @@ class ServerState
"date" => @$this->getWebguiGlobal('display', 'date') ?? '',
"time" => @$this->getWebguiGlobal('display', 'time') ?? '',
],
"description" => $this->var['COMMENT'] ? htmlspecialchars($this->var['COMMENT']) : '',
"description" => $this->var['COMMENT'] ? htmlspecialchars($this->var['COMMENT'], ENT_HTML5, 'UTF-8') : '',
"deviceCount" => $this->var['deviceCount'],
"email" => $this->myServersFlashCfg['remote']['email'] ?? '',
"email" => $this->email,
"expireTime" => 1000 * (($this->var['regTy'] === 'Trial' || strstr($this->var['regTy'], 'expired')) ? $this->var['regTm2'] : 0),
"extraOrigins" => explode(',', $this->myServersFlashCfg['api']['extraOrigins'] ?? ''),
"extraOrigins" => $this->extraOrigins,
"flashProduct" => $this->var['flashProduct'],
"flashVendor" => $this->var['flashVendor'],
"flashBackupActivated" => empty($this->flashbackupStatus['activated']) ? '' : 'true',
"flashBackupActivated" => $this->flashBackupActivated,
"guid" => $this->var['flashGUID'],
"hasRemoteApikey" => !empty($this->myServersFlashCfg['remote']['apikey']),
"hasRemoteApikey" => $this->hasRemoteApikey,
"internalPort" => _var($_SERVER, 'SERVER_PORT'),
"keyfile" => $this->keyfileBase64UrlSafe,
"lanIp" => ipaddr(),
"locale" => (!empty($_SESSION) && $_SESSION['locale']) ? $_SESSION['locale'] : 'en_US',
"model" => $this->var['SYS_MODEL'],
"name" => htmlspecialchars($this->var['NAME']),
"model" => $this->var['SYS_MODEL'] ? htmlspecialchars($this->var['SYS_MODEL'], ENT_HTML5, 'UTF-8') : '',
"name" => htmlspecialchars($this->var['NAME'], ENT_HTML5, 'UTF-8'),
"osVersion" => $this->osVersion,
"osVersionBranch" => $this->osVersionBranch,
"protocol" => _var($_SERVER, 'REQUEST_SCHEME'),
"rebootType" => $this->rebootDetails->getRebootType(),
"regDev" => @(int)$this->var['regDev'] ?? 0,
"regDevs" => @(int)$this->var['regDevs'] ?? 0,
"regGen" => @(int)$this->var['regGen'],
"regGuid" => @$this->var['regGUID'] ?? '',
"regTo" => @htmlspecialchars($this->var['regTo']) ?? '',
"regTo" => @htmlspecialchars($this->var['regTo'], ENT_HTML5, 'UTF-8') ?? '',
"regTm" => $this->var['regTm'] ? @$this->var['regTm'] * 1000 : '', // JS expects milliseconds
"regTy" => @$this->var['regTy'] ?? '',
"regExp" => $this->var['regExp'] ? @$this->var['regExp'] * 1000 : '', // JS expects milliseconds
"registered" => $this->registered,
"registeredTime" => $this->myServersFlashCfg['remote']['regWizTime'] ?? '',
"registeredTime" => $this->registeredTime,
"site" => _var($_SERVER, 'REQUEST_SCHEME') . "://" . _var($_SERVER, 'HTTP_HOST'),
"state" => strtoupper(empty($this->var['regCheck']) ? $this->var['regTy'] : $this->var['regCheck']),
"theme" => [
@@ -249,8 +293,8 @@ class ServerState
],
"ts" => time(),
"uptime" => 1000 * (time() - round(strtok(exec("cat /proc/uptime"), ' '))),
"username" => $this->myServersFlashCfg['remote']['username'] ?? '',
"wanFQDN" => $this->nginxCfg['NGINX_WANFQDN'] ?? '',
"username" => $this->username,
"wanFQDN" => @$this->nginxCfg['NGINX_WANFQDN'] ?? '',
];
if ($this->combinedKnownOrigins) {
@@ -273,11 +317,21 @@ class ServerState
}
/**
* Retrieve the server information as a JSON string
* Retrieve the server information as JSON
*
* @return string A JSON string containing server information.
* @return string
*/
public function getServerStateJson() {
return json_encode($this->getServerState());
}
/**
* Retrieve the server information as JSON string with converted special characters to HTML entities
*
* @return string
*/
public function getServerStateJsonForHtmlAttr() {
$json = json_encode($this->getServerState());
return htmlspecialchars($json, ENT_QUOTES, 'UTF-8');
}
}

View File

@@ -72,13 +72,13 @@ class WebComponentTranslations
'<p>To continue using Unraid OS you may purchase a license key. Alternately, you may request a Trial extension.</p>' => '<p>' . _('To continue using Unraid OS you may purchase a license key.') . ' ' . _('Alternately, you may request a Trial extension.') . '</p>',
'<p>To support more storage devices as your server grows, click Upgrade Key.</p>' => '<p>' . _('To support more storage devices as your server grows, click Upgrade Key.') . '</p>',
'<p>You have used all your Trial extensions. To continue using Unraid OS you may purchase a license key.</p>' => '<p>' . _('You have used all your Trial extensions.') . ' ' . _('To continue using Unraid OS you may purchase a license key.') . '</p>',
'<p>Your <em>Trial</em> key includes all the functionality and device support of a <em>Pro</em> key.</p><p>After your <em>Trial</em> has reached expiration, your server <strong>still functions normally</strong> until the next time you Stop the array or reboot your server.</p><p>At that point you may either purchase a license key or request a <em>Trial</em> extension.</p>' => '<p>' . _('Your **Trial** key includes all the functionality and device support of a **Pro** key') . '</p><p>' . _('After your **Trial** has reached expiration, your server *still functions normally* until the next time you Stop the array or reboot your server') . '</p><p>' . _('At that point you may either purchase a license key or request a *Trial* extension.') . '</p>',
'<p>Your <em>Trial</em> key includes all the functionality and device support of an <em>Unleashed</em> key.</p><p>After your <em>Trial</em> has reached expiration, your server <strong>still functions normally</strong> until the next time you Stop the array or reboot your server.</p><p>At that point you may either purchase a license key or request a <em>Trial</em> extension.</p>' => '<p>' . _('Your **Trial** key includes all the functionality and device support of an **Unleashed** key') . '</p><p>' . _('After your **Trial** has reached expiration, your server *still functions normally* until the next time you Stop the array or reboot your server') . '</p><p>' . _('At that point you may either purchase a license key or request a *Trial* extension.') . '</p>',
'<p>Your license key file is corrupted or missing. The key file should be located in the /config directory on your USB Flash boot device.</p><p>If you do not have a backup copy of your license key file you may attempt to recover your key.</p><p>If this was an expired Trial installation, you may purchase a license key.</p>' => '<p>' . _('Your license key file is corrupted or missing.') . ' ' . _('The key file should be located in the /config directory on your USB Flash boot device') . '</p><p>' . _('If you do not have a backup copy of your license key file you may attempt to recover your key with your Unraid.net account') . '</p><p>' . _('If this was an expired Trial installation, you may purchase a license key.') . '</p>',
'<p>Your license key file is corrupted or missing. The key file should be located in the /config directory on your USB Flash boot device.</p><p>You may attempt to recover your key with your Unraid.net account.</p><p>If this was an expired Trial installation, you may purchase a license key.</p>' => '<p>' . _('Your license key file is corrupted or missing.') . ' ' . _('The key file should be located in the /config directory on your USB Flash boot device') . '</p><p>' . _('If you do not have a backup copy of your license key file you may attempt to recover your key with your Unraid.net account') . '</p><p>' . _('If this was an expired Trial installation, you may purchase a license key.') . '</p>',
'<p>Your server will not be usable until you purchase a Registration key or install a free 30 day <em>Trial</em> key. A <em>Trial</em> key provides all the functionality of a Pro Registration key.</p><p>Registration keys are bound to your USB Flash boot device serial number (GUID). Please use a high quality name brand device at least 1GB in size.</p><p>Note: USB memory card readers are generally not supported because most do not present unique serial numbers.</p><p><strong>Important:</strong></p><ul class="list-disc pl-16px"><li>Please make sure your server time is accurate to within 5 minutes</li><li>Please make sure there is a DNS server specified</li></ul>' => '<p>' . _('Your server will not be usable until you purchase a Registration key or install a free 30 day <em>Trial</em> key.') . ' ' . _('A <em>Trial</em> key provides all the functionality of a Pro Registration key.') . '</p><p>' . _('Registration keys are bound to your USB Flash boot device serial number (GUID).') . ' ' . _('Please use a high quality name brand device at least 1GB in size.') . '</p><p>' . _('Note: USB memory card readers are generally not supported because most do not present unique serial numbers.') . '</p><p>' . _('*Important:*') . '</p><ul class="list-disc pl-16px"><li>' . _('Please make sure your server time is accurate to within 5 minutes') . '</li><li>' . _('Please make sure there is a DNS server specified') . '</li>>' . '</ul>',
'<p>Your server will not be usable until you purchase a Registration key or install a free 30 day <em>Trial</em> key. A <em>Trial</em> key provides all the functionality of an Unleashed Registration key.</p><p>Registration keys are bound to your USB Flash boot device serial number (GUID). Please use a high quality name brand device at least 1GB in size.</p><p>Note: USB memory card readers are generally not supported because most do not present unique serial numbers.</p><p><strong>Important:</strong></p><ul class="list-disc pl-16px"><li>Please make sure your server time is accurate to within 5 minutes</li><li>Please make sure there is a DNS server specified</li></ul>' => '<p>' . _('Your server will not be usable until you purchase a Registration key or install a free 30 day <em>Trial</em> key.') . ' ' . _('A <em>Trial</em> key provides all the functionality of an Unleashed Registration key.') . '</p><p>' . _('Registration keys are bound to your USB Flash boot device serial number (GUID).') . ' ' . _('Please use a high quality name brand device at least 1GB in size.') . '</p><p>' . _('Note: USB memory card readers are generally not supported because most do not present unique serial numbers.') . '</p><p>' . _('*Important:*') . '</p><ul class="list-disc pl-16px"><li>' . _('Please make sure your server time is accurate to within 5 minutes') . '</li><li>' . _('Please make sure there is a DNS server specified') . '</li>>' . '</ul>',
'<p>Your Trial key requires an internet connection.</p><p><a href="/Settings/NetworkSettings" class="underline">Please check Settings > Network</a></p>' => '<p>' . _('Your Trial key requires an internet connection') . '</p><p><a href="/Settings/NetworkSettings" class="underline">' . _('Please check Settings > Network') . '</a></p>',
'<p>Your Unraid registration key is ineligible for replacement as it has been replaced within the last 12 months.</p>' => '<p>' . _('Your Unraid registration key is ineligible for replacement as it has been replaced within the last 12 months.') . '</p>',
'A Trial key provides all the functionality of a Pro Registration key' => _('A Trial key provides all the functionality of a Pro Registration key'),
'A Trial key provides all the functionality of an Unleashed Registration key' => _('A Trial key provides all the functionality of an Unleashed Registration key'),
'Acklowledge that you have made a Flash Backup to enable this action' => _('Acklowledge that you have made a Flash Backup to enable this action'),
'ago' => _('ago'),
'All you need is an active internet connection, an Unraid.net account, and the Connect plugin. Get started by installing the plugin.' => _('All you need is an active internet connection, an Unraid.net account, and the Connect plugin.') . ' ' . _('Get started by installing the plugin.'),
@@ -339,7 +339,7 @@ class WebComponentTranslations
'You may still update to releases dated prior to your update expiration date.' => _('You may still update to releases dated prior to your update expiration date.'),
'You\'re one step closer to enhancing your Unraid experience' => _('You\'re one step closer to enhancing your Unraid experience'),
'Your {0} Key has been replaced!' => sprintf(_('Your %s Key has been replaced!'), '{0}'),
'Your free Trial key provides all the functionality of a Pro Registration key' => _('Your free Trial key provides all the functionality of a Pro Registration key'),
'Your free Trial key provides all the functionality of an Unleashed Registration key' => _('Your free Trial key provides all the functionality of an Unleashed Registration key'),
'Your Trial has expired' => _('Your Trial has expired'),
'Your Trial key has been extended!' => _('Your Trial key has been extended!'),
];

File diff suppressed because one or more lines are too long

View File

@@ -7,7 +7,7 @@
"css": [
"_nuxt/unraid-components.client-fad7c220.css"
],
"file": "_nuxt/unraid-components.client-437ee6ff.js",
"file": "_nuxt/unraid-components.client-cd1b3939.js",
"isEntry": true,
"src": ".nuxt/nuxt-custom-elements/entries/unraid-components.client.mjs"
}

View File

@@ -11,6 +11,9 @@
*/
?>
<?
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
require_once "$docroot/webGui/include/Wrappers.php";
// Invoke the plugin command with indicated method
function plugin($method, $arg = '') {
global $docroot;
@@ -27,7 +30,7 @@ function language($method, $arg = '') {
function check_plugin($arg, &$ncsi) {
// Get network connection status indicator (NCSI)
if ($ncsi===null) $ncsi = exec("wget --spider --no-check-certificate -nv -T10 -t1 https://www.msftncsi.com/ncsi.txt 2>&1|grep -o 'OK'");
if ($ncsi===null) $ncsi = check_network_connectivity();
return $ncsi ? plugin('check',$arg) : false;
}

View File

@@ -1,6 +1,6 @@
<?php
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
/* Copyright 2005-2024, Lime Technology
* Copyright 2012-2024, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
@@ -108,6 +108,7 @@ class UnraidOsCheck
function _($text) {return $text;}
}
// this command will set the $notify array
extract(parse_plugin_cfg('dynamix', true));
$var = (array)@parse_ini_file('/var/local/emhttp/var.ini');
@@ -115,7 +116,7 @@ class UnraidOsCheck
$params = [];
$params['branch'] = plugin('category', self::PLG_PATH, 'stable');
$params['current_version'] = plugin('version', self::PLG_PATH) ?: _var($var,'version');
if (_var($var,'regExp')) $params['update_exp'] = date('m-d-Y', _var($var,'regExp')*1);
if (_var($var,'regExp')) $params['update_exp'] = date('Y-m-d', _var($var,'regExp')*1);
$defaultUrl = self::BASE_RELEASES_URL;
// pass a param of altUrl to use the provided url instead of the default
$parsedAltUrl = (array_key_exists('altUrl',$_GET) && $_GET['altUrl']) ? $_GET['altUrl'] : null;
@@ -123,21 +124,12 @@ class UnraidOsCheck
if ($parsedAltUrl) $params['altUrl'] = $parsedAltUrl;
$urlbase = $parsedAltUrl ?? $defaultUrl;
$url = $urlbase.'?'.http_build_query($params);
$response = "";
// use error handler to convert warnings from file_get_contents to errors so they can be captured
function warning_as_error($severity, $message, $filename, $lineno) {
throw new ErrorException($message, 0, $severity, $filename, $lineno);
$url = $urlbase.'?'.http_build_query($params);
$curlinfo = [];
$response = http_get_contents($url,[],$curlinfo);
if (array_key_exists('error', $curlinfo)) {
$response = json_encode(array('error' => $curlinfo['error']), JSON_PRETTY_PRINT);
}
set_error_handler("warning_as_error");
try {
$response = file_get_contents($url);
} catch (Exception $e) {
$response = json_encode(array('error' => $e->getMessage()), JSON_PRETTY_PRINT);
}
restore_error_handler();
$responseMutated = json_decode($response, true);
if (!$responseMutated) {
$response = json_encode(array('error' => 'Invalid response from '.$urlbase), JSON_PRETTY_PRINT);
@@ -159,14 +151,17 @@ class UnraidOsCheck
// send notification if a newer version is available and not ignored
$isNewerVersion = array_key_exists('isNewer',$responseMutated) ? $responseMutated['isNewer'] : false;
$isReleaseIgnored = in_array($responseMutated['version'], $this->getIgnoredReleases());
$isReleaseIgnored = array_key_exists('version',$responseMutated) ? in_array($responseMutated['version'], $this->getIgnoredReleases()) : false;
if ($responseMutated && $isNewerVersion && !$isReleaseIgnored) {
$output = _var($notify,'plugin');
$server = strtoupper(_var($var,'NAME','server'));
$newver = (array_key_exists('version',$responseMutated) && $responseMutated['version']) ? $responseMutated['version'] : 'unknown';
$script = '/usr/local/emhttp/webGui/scripts/notify';
exec("$script -e ".escapeshellarg("System - Unraid [$newver]")." -s ".escapeshellarg("Notice [$server] - Version update $newver")." -d ".escapeshellarg("A new version of Unraid is available")." -i ".escapeshellarg("normal $output")." -l '/Tools/Update' -x");
$event = "System - Unraid [$newver]";
$subject = "Notice [$server] - Version update $newver";
$description = "A new version of Unraid is available";
exec("$script -e ".escapeshellarg($event)." -s ".escapeshellarg($subject)." -d ".escapeshellarg($description)." -i ".escapeshellarg("normal $output")." -l '/Tools/Update' -x");
}
exit(0);

View File

@@ -44,7 +44,7 @@ function write(...$messages){
}
write(_("Checking connectivity")." ...\n");
if (exec("wget --spider --no-check-certificate -nv -T10 -t1 https://www.msftncsi.com/ncsi.txt 2>&1|grep -om1 'OK'")) {
if (check_network_connectivity()) {
$check = popen('plugin checkall','r');
while (!feof($check)) write(fgets($check));
pclose($check);

View File

@@ -1,7 +1,7 @@
#!/usr/bin/php -q
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
/* Copyright 2005-2024, Lime Technology
* Copyright 2012-2024, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
@@ -15,6 +15,7 @@
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
require_once "$docroot/webGui/include/Wrappers.php";
require_once "$docroot/plugins/dynamix.plugin.manager/include/PluginHelpers.php";
// this command will set the $notify array
extract(parse_plugin_cfg('dynamix', true));
// Multi-language support

View File

@@ -1,7 +1,7 @@
#!/usr/bin/php -q
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
/* Copyright 2005-2024, Lime Technology
* Copyright 2012-2024, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
@@ -15,6 +15,7 @@
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
require_once "$docroot/webGui/include/Wrappers.php";
require_once "$docroot/plugins/dynamix.plugin.manager/include/PluginHelpers.php";
// this command will set the $notify array
extract(parse_plugin_cfg('dynamix',true));
// Multi-language support

View File

@@ -49,7 +49,7 @@ function showCPUs($uuid) {
function vsize($size,$expand=true) {
$units = ['','K','M','G','T','P','E','Z','Y'];
if ($expand) {
$size = str_replace(['B',' ',',', '.'],'',strtoupper($size));
$size = str_replace(['B',' ',','],'',strtoupper($size));
[$c1,$c2] = my_preg_split('/(?<=[0-9])(?=[A-Z])/',$size);
return $c1 * pow(1024,array_search($c2,$units)?:0);
} else {

View File

@@ -52,7 +52,7 @@ foreach ($vms as $vm) {
$image = substr($icon,-4)=='.png' ? "<img src='$icon' class='img'>" : (substr($icon,0,5)=='icon-' ? "<i class='$icon img'></i>" : "<i class='fa fa-$icon img'></i>");
$arrConfig = domain_to_config($uuid);
$snapshots = getvmsnapshots($vm) ;
$cdroms = $lv->get_cdrom_stats($res) ;
$cdroms = $lv->get_cdrom_stats($res,true,true) ;
if ($state == 'running') {
$mem = $dom['memory']/1024;
} else {
@@ -214,7 +214,7 @@ foreach ($vms as $vm) {
$boot= $arrDisk["boot order"];
$serial = $arrDisk["serial"];
if ($boot < 1) $boot = _('Not set');
$reallocation = trim(shell_exec("getfattr --absolute-names --only-values -n system.LOCATION ".escapeshellarg($disk)." 2>/dev/null"));
$reallocation = trim(get_realvolume($disk));
if (!empty($reallocation)) $reallocationstr = "($reallocation)"; else $reallocationstr = "";
echo "<tr><td>$disk $reallocationstr</td><td>$serial</td><td>$bus</td>";
if ($state == 'shutoff') {
@@ -236,8 +236,10 @@ foreach ($vms as $vm) {
/* Display VM cdroms */
foreach ($cdroms as $arrCD) {
$tooltip = "";
$capacity = $lv->format_size($arrCD['capacity'], 0);
$allocation = $lv->format_size($arrCD['allocation'], 0);
if ($arrCD['spundown']) {$capacity = $allocation = "*"; $tooltip = "Drive spun down ISO volume is ".$arrCD['reallocation'];} else $tooltip = "ISO volume is ".$arrCD['reallocation'];
$disk = $arrCD['file'] ?? $arrCD['partition'] ?? "" ;
$dev = $arrCD['device'];
$bus = $arrValidDiskBuses[$arrCD['bus']] ?? 'VirtIO';
@@ -246,7 +248,7 @@ foreach ($vms as $vm) {
if ($disk != "" ) {
$title = _('Eject CD Drive');
$changemedia = "changemedia(\"{$uuid}\",\"{$dev}\",\"{$bus}\", \"--eject\")";
echo "<tr><td>$disk <a title='$title' href='#' onclick='$changemedia'> <i class='fa fa-eject'></i></a></td><td></td><td>$bus</td><td>$capacity</td><td>$allocation</td><td>$boot</td></tr>";
echo "<tr><td>$disk <a title='$title' href='#' onclick='$changemedia'> <i class='fa fa-eject'></i></a></td><td></td><td>$bus</td><td><span title='$tooltip' data-toggle='tooltip'>$capacity</span></td><td>$allocation</td><td>$boot</td></tr>";
} else {
$title = _('Insert CD');
$changemedia = "changemedia(\"{$uuid}\",\"{$dev}\",\"{$bus}\",\"--select\")";

View File

@@ -1250,33 +1250,44 @@
return $tmp;
}
function get_cdrom_stats($domain, $sort=true) {
function get_cdrom_stats($domain, $sort=true,$spincheck = false) {
$unraiddisks = array_merge_recursive(@parse_ini_file('state/disks.ini',true)?:[], @parse_ini_file('state/devs.ini',true)?:[]);
$dom = $this->get_domain_object($domain);
$tmp = false;
$buses = $this->get_xpath($dom, '//domain/devices/disk[@device="cdrom"]/target/@bus', false);
$disks = $this->get_xpath($dom, '//domain/devices/disk[@device="cdrom"]/target/@dev', false);
$cds = $this->get_xpath($dom, '//domain/devices/disk[@device="cdrom"]/target/@dev', false);
$files = $this->get_xpath($dom, '//domain/devices/disk[@device="cdrom"]/source/@file', false);
$boot = $this->get_xpath($dom, '//domain/devices/disk[@device="cdrom"]/boot/@*', false);
$ret = [];
for ($i = 0; $i < $disks['num']; $i++) {
$tmp = libvirt_domain_get_block_info($dom, $disks[$i]);
for ($i = 0; $i < $cds['num']; $i++) {
$spundown = 0;
$reallocation = null;
if (isset($files[$i])) $reallocation = trim(get_realvolume($files[$i]));
if ($spincheck) {
if (isset($unraiddisks[$reallocation]['spundown']) && $unraiddisks[$reallocation]['spundown'] == 1) $spundown = 1; else $tmp = libvirt_domain_get_block_info($dom, $cds[$i]);
} else $tmp = libvirt_domain_get_block_info($dom, $cds[$i]);
if ($tmp) {
$tmp['bus'] = $buses[$i];
$tmp["boot order"] = $boot[$i] ?? "";
$tmp['reallocation'] = $reallocation;
$tmp['spundown'] = $spundown;
$ret[] = $tmp;
}
else {
$this->_set_last_error();
$ret[] = [
'device' => $disks[$i],
'device' => $cds[$i],
'file' => $files[$i],
'type' => '-',
'capacity' => '-',
'allocation' => '-',
'physical' => '-',
'bus' => $buses[$i]
'bus' => $buses[$i],
'reallocation' => $reallocation,
'spundown' => $spundown
];
}
}
@@ -1294,7 +1305,7 @@
}
unset($buses);
unset($disks);
unset($cds);
unset($files);
return $ret;
@@ -1462,7 +1473,7 @@
$unit = strtoupper($unit);
switch ($unit) {
case 'T': return number_format($value / (float)1099511627776, $decimals).'T';
case 'T': return number_format($value / (float)1099511627776, $decimals +2).'T';
case 'G': return number_format($value / (float)(1 << 30), $decimals).'G';
case 'M': return number_format($value / (float)(1 << 20), $decimals).'M';
case 'K': return number_format($value / (float)(1 << 10), $decimals).'K';

View File

@@ -2527,6 +2527,7 @@ function addtemplatexml($post) {
'os' => $usertemplate['template']['os'],
'overrides' => $usertemplate
];
if (!is_dir(dirname($templateslocation))) mkdir(dirname($templateslocation));
file_put_contents($templateslocation,json_encode($savedtemplates,JSON_PRETTY_PRINT));
$reply = ['success' => true];

View File

@@ -0,0 +1,58 @@
#!/usr/bin/php
<?php
/* Copyright 2005-2024, Lime Technology
* Copyright 2024, Simon Fairweather
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
# Command for bash script /usr/libexec/virtiofsd
# eval exec /usr/bin/virtiofsd $(/usr/local/emhttp/plugins/dynamix.vm.manager/scripts/virtiofsd.php "$@")
$file = "/etc/libvirt/virtiofsd.opt";
$whole_cmd = '';
$long_options = ["fd:","print-capabilities","syslog","daemonize","rlimit-nofile","thread-pool-size:","socket-path:","socket-group:","help","version","source:"];
$short_options = "o:dfV";
$argoptions = getopt($short_options,$long_options);
array_shift($argv);
foreach ($argv as $i=>$arg) {
if (strpos($arg, "--fd") !== false) unset($argv[$i]) ;
if ($arg == "-o") { unset($argv[$i]);unset($argv[$i+1]); }
}
# Check if options file exists. Each option should be on a new line.
if (is_file($file)) $options = explode("\n",file_get_contents($file)) ; else $options = ['--syslog','--inode-file-handles=mandatory','--announce-submounts'];
$options[] = "--fd=".$argoptions['fd'];
if (isset($argoptions['o'])) {
$virtiofsoptions = explode(',',$argoptions["o"]);
foreach ($virtiofsoptions as $opt) {
$optsplit = explode('=',$opt);
switch ($optsplit[0]) {
case "source":
$options[] = "--shared-dir={$optsplit[1]}";
break;
case "cache":
$options[] = "--cache=never";
break;
case "xattr":
$options[] = "--xattr";
break;
case "sandbox":
$options[] = "--sandbox={$optsplit[1]}";
break;
}
}
}
$newargs = array_merge($options,$argv);
foreach($newargs as $arg) {
if ($arg != "") $whole_cmd.= escapeshellarg($arg).' ';
}
echo trim($whole_cmd);
?>

View File

@@ -545,6 +545,9 @@ window.onunload = function(){
<? elseif (_var($var,'configValid')=="invalid"):?>
<tr><td><?status_indicator()?>**_(Stopped)_.**</td><td><input type="submit" name="cmdStart" value="_(Start)_" disabled></td>
<td>_(Too many attached devices. Please consider upgrading your)_ <a href="/Tools/Registration">_(registration key)_</a>.</td></tr>
<? elseif (_var($var,'configValid')=="ineligible"):?>
<tr><td><?status_indicator()?>**_(Stopped)_.**</td><td><input type="submit" name="cmdStart" value="_(Start)_" disabled></td>
<td>_(Ineligible to run this version of Unraid OS. Please consider extending your)_ <a href="/Tools/Registration">_(registration key)_</a>.</td></tr>
<? elseif (_var($var,'configValid')=="nokeyserver"):?>
<tr><td><?status_indicator()?>**_(Stopped)_.**</td><td><input type="submit" name="cmdStart" value="_(Start)_" disabled></td>
<td>_(Cannot contact key-server. Please check your)_ <a href="/Settings/NetworkSettings">_(network settings)_</a>.</td></tr>

View File

@@ -279,10 +279,10 @@ foreach ($cpus as $pair) {
<a href='/Dashboard/Tools/Processes' title="_(View Running Processes)_"><i class='fa fa-fw fa-info-circle control'></i></a>
</td></tr><tr><td>
<span class='w26'><i class='ups fa fa-compress'></i>_(Usable size)_: <?=$ramsize?><br><i class='ups fa fa-expand'></i>_(Maximum size)_: <?="$memory_maximum $unit"?><?=$low?'*':''?></span>
<span class='w18 center'><a class='info hand none'>_(RAM usage)_<span>_(Percent of total used memory)_ (<?=$ramsize?>)</span></a></span>
<span class='w18 center'><a class='info hand none'>_(Flash device)_<span>_(Percent usage of flash usb device)_ (<?=$flashsize?>)</span></a></span>
<span class='w18 center'><a class='info hand none'>_(Log filesystem)_<span>_(Percent usage of LOG file system)_ (<?=$logsize?>)</span></a></span>
<span class='w18 center'><a class='info hand none'><?=$vdisk?><span><?=_("Percent usage of $vdisk")?> (<?=$dockersize?>)</span></a></span>
<span class='w18 center static'><a class='info hand none'>_(RAM usage)_<span>_(Percent of total used memory)_ (<?=$ramsize?>)</span></a></span>
<span class='w18 center static'><a class='info hand none'>_(Flash device)_<span>_(Percent usage of flash usb device)_ (<?=$flashsize?>)</span></a></span>
<span class='w18 center static'><a class='info hand none'>_(Log filesystem)_<span>_(Percent usage of LOG file system)_ (<?=$logsize?>)</span></a></span>
<span class='w18 center static'><a class='info hand none'><?=$vdisk?><span><?=_("Percent usage of $vdisk")?> (<?=$dockersize?>)</span></a></span>
</td></tr><tr><td>
<span class='w26'><legend>_(Legend)_</legend><span id='dynamic'></span></span>
<span class='w18 center'><div class='pie' id='sys0'><span class='sys0'></span><span class='var0'></span></div></span>
@@ -1223,7 +1223,7 @@ function addProperties() {
$('div#sys3').hover(function(){$('.sys3').hide();$('.var3').show();},function(){$('.sys3').show();$('.var3').hide();});
$('#current_time').hover(function(){$.post('/webGui/include/DashboardApps.php',{ntp:'ntp'},function(ntp){$('#current_time').prop('title',ntp+"\n_(Go to date and time settings)_");});});
// make truncated descriptions fully visible when hovering over them
$('span.w18').hover(
$('span.w18').not('.static').hover(
function(){if ($(this)[0].offsetWidth < $(this)[0].scrollWidth) {recall = $(this).next(); recover=recall.html(); recall.html('&nbsp;');}},
function(){if ($(this)[0].offsetWidth < $(this)[0].scrollWidth) {recall.html(recover); recall=null;}}
);

View File

@@ -313,7 +313,14 @@ function setGlue(form,reset) {
{glue:'/',more:3,dev:1,type:'',min1:1,max1:4,min2:1,max2:128,min3:1,max3:4}, // highpoint
{glue:'' ,more:1,dev:1,type:'',min1:0,max1:15}, // hp cciss
{glue:'' ,more:0,dev:0,type:''}, // marvell
{glue:',',more:1,dev:1,type:'',min1:0,max1:127} // megaraid
{glue:',',more:1,dev:1,type:'',min1:0,max1:127}, // megaraid
{glue:',',more:1,dev:0,type:'input',min1:'',max1:'0xffffffff'}, // cypress
{glue:',',more:3,dev:0,type:'select',min1:'',max1:'p',min2:'',max2:'x',min3:1,max3:128},// jmicron ata
{glue:'' ,more:0,dev:0,type:''}, // prolific
{glue:'' ,more:0,dev:0,type:''}, // sunplus
{glue:'' ,more:0,dev:0,type:''}, // asmedia
{glue:'' ,more:0,dev:0,type:''}, // jmicron nvme
{glue:'' ,more:0,dev:0,type:''}, // realtek
];
var n = form.smType.selectedIndex>0 ? form.smType.selectedIndex-1 : <?=_var($var,'smIndex',0)?>;
var x = data[n]['more'];
@@ -603,7 +610,7 @@ _(Spin down delay)_:
_(File system status)_:
: <?=_(_var($disk,'fsStatus'))?>&nbsp;
<?$disabled = (_var($var,'fsState')=="Stopped" && !empty(_var($disk,'uuid'))) || (_var($var,'fsState')=="Started" && _var($disk,'fsStatus')=='Mounted') ? "disabled" : ""?>
<?$disabled = (_var($var,'fsState')=="Stopped" && !empty(_var($disk,'uuid'))) || (_var($var,'fsState')=="Started" && _var($disk,'fsType')!='auto') ? "disabled" : ""?>
<?if (diskType('Data') || (!isSubpool($name) && _var($disk,'slots',0)==1)):?>
_(File system type)_:
: <select id="diskFsType" name="diskFsType.<?=_var($disk,'idx',0)?>" onchange="changeFsType()" <?=$disabled?>>
@@ -1246,6 +1253,13 @@ _(SMART controller type)_:
<?=mk_option(_var($disk,'smType'), "-d cciss", "HP cciss")?>
<?=mk_option(_var($disk,'smType'), "-d marvell", "Marvell")?>
<?=mk_option(_var($disk,'smType'), "-d megaraid", "MegaRAID")?>
<?=mk_option(_var($disk,'smType'), "-d usbcypress", "Cypress ATACB")?>
<?=mk_option(_var($disk,'smType'), "-d usbjmicron", "JMicron ATA pass-through")?>
<?=mk_option(_var($disk,'smType'), "-d usbprolific", "Prolific ATA pass-through")?>
<?=mk_option(_var($disk,'smType'), "-d usbsunplus", "Sunplus ATA pass-through")?>
<?=mk_option(_var($disk,'smType'), "-d sntasmedia", "ASMedia NVMe pass-through")?>
<?=mk_option(_var($disk,'smType'), "-d sntjmicron", "JMicron NVMe pass-through")?>
<?=mk_option(_var($disk,'smType'), "-d sntrealtek", "Realtek NVMe pass-through")?>
</select>
<input type="text" name="smPort1" value="<?=_var($disk,'smPort1')?>" class="option"><select name="smPort1" class="narrow option" disabled></select>
<input type="text" name="smPort2" value="<?=_var($disk,'smPort2')?>" class="option"><select name="smPort2" class="narrow option" disabled></select>

View File

@@ -364,6 +364,13 @@ _(Default SMART controller type)_:
<?=mk_option(_var($var,'smType'), "-d cciss", "HP cciss")?>
<?=mk_option(_var($var,'smType'), "-d marvell", "Marvell")?>
<?=mk_option(_var($var,'smType'), "-d megaraid", "MegaRAID")?>
<?=mk_option(_var($var,'smType'), "-d usbcypress", "Cypress ATACB")?>
<?=mk_option(_var($var,'smType'), "-d usbjmicron", "JMicron ATA pass-through")?>
<?=mk_option(_var($var,'smType'), "-d usbprolific", "Prolific ATA pass-through")?>
<?=mk_option(_var($var,'smType'), "-d usbsunplus", "Sunplus ATA pass-through")?>
<?=mk_option(_var($var,'smType'), "-d sntasmedia", "ASMedia NVMe pass-through")?>
<?=mk_option(_var($var,'smType'), "-d sntjmicron", "JMicron NVMe pass-through")?>
<?=mk_option(_var($var,'smType'), "-d sntrealtek", "Realtek NVMe pass-through")?>
</select>
:disk_default_smart_controller_help:

View File

@@ -5,8 +5,8 @@ Icon="icon-key"
Tag="expeditedssl"
---
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
/* Copyright 2005-2024, Lime Technology
* Copyright 2012-2024, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
@@ -75,7 +75,7 @@ if ($cert1Present) {
$cert1SelfSigned = ($cert1Subject == $cert1Issuer);
}
// unraid.net, myunraid.net LE cert. could potentially be user provided as well
// myunraid.net LE cert. could potentially be user provided as well
$cert2File = "/boot/config/ssl/certs/certificate_bundle.pem";
$cert2Present = file_exists("$cert2File");
if ($cert2Present) {
@@ -84,6 +84,8 @@ if ($cert2Present) {
$cert2Expires = exec("/usr/bin/openssl x509 -in $cert2File -noout -text | sed -n -e 's/^.*Not After : //p'");
$isWildcardCert = preg_match('/.*\.myunraid\.net$/', $cert2Subject);
$subject2URL = $cert2Subject;
$dnsValid = false;
$dnsRebindingProtection = false;
if ($isWildcardCert) {
exec("openssl x509 -checkend 2592000 -noout -in $cert2File 2>/dev/null", $arrout, $retval_expired);
if (!$addr) {
@@ -115,12 +117,12 @@ if ($cert2Present) {
}
}
$http_port = _var($var,'PORT',80) != 80 ? ":{$var['PORT']}" : '';
$https_port = _var($var,'PORTSSL',443) != 443 ? ":{$var['PORTSSL']}" : '';
$http_port = _var($var,'PORT','80') != '80' ? ":{$var['PORT']}" : '';
$https_port = _var($var,'PORTSSL','443') != '443' ? ":{$var['PORTSSL']}" : '';
$http_ip_url = "http://"._var($nginx,'NGINX_LANIP')."{$http_port}/";
$https_ip_url = "https://"._var($nginx,'NGINX_LANIP')."{$https_port}/";
$http_ip6_url = "http://"._var($nginx,'NGINX_LANIP6')."{$http_port}/";
$https_ip6_url = "https://"._var($nginx,'NGINX_LANIP6')."{$https_port}/";
$http_ip6_url = "http://["._var($nginx,'NGINX_LANIP6')."]{$http_port}/";
$https_ip6_url = "https://["._var($nginx,'NGINX_LANIP6')."]{$https_port}/";
$http_mdns_url = "http://"._var($nginx,'NGINX_LANMDNS')."{$http_port}/";
$https_mdns_url = "https://"._var($nginx,'NGINX_LANMDNS')."{$https_port}/";
$https_fqdn_url = "https://"._var($nginx,'NGINX_LANFQDN')."{$https_port}/";
@@ -164,7 +166,6 @@ $cert_time_format = $display['date'].($display['date']!='%c' ? ', '.str_replac
$provisionlabel = $isWildcardCert ? _('Renew') : _('Provision');
$disabled_provision = $keyfile===false || ($isWildcardCert && $retval_expired===0) || !$addr ? 'disabled' : '';
$disabled_provision_msg = !$addr ? _('Ensure the primary network card eth0 has an IP address.') : '';
$disabled_updatedns = $keyfile!==false && $isWildcardCert ? '' : 'disabled';
$disabled_delete = $cert2Present && $var['USE_SSL']!='auto' ? '' : 'disabled';
$disabled_auto = $isWildcardCert && !$dnsRebindingProtection && $dnsValid ? '' : 'disabled';
@@ -189,23 +190,6 @@ function provisionHandler(event, form) { // provisions and renewals require bein
if (event.submitter.value === 'Renew') return true; // always allow renewals
};
function updateDNS(button) {
$(button).prop("disabled", true).html("<i class='fa fa-circle-o-notch fa-spin fa-fw'></i>_(Update DNS)_");
var failure = function(data) {
var status = data.status;
var obj = data.responseJSON;
var msg = "_(Sorry, an error occurred updating unraid.net DNS records)_. _(The error is)_: "+obj.error+".";
$(button).prop("disabled", false).html("_(Update DNS)_");
swal({title:"_(Oops)_",text:msg,type:"error",html:true,confirmButtonText:"_(Ok)_"});
};
var success = function(data) {
$(button).prop("disabled", false).html("_(Update DNS)_");
<?$text = _('Your local IP address %s has been updated for unraid.net')?>
swal({title:"",text:"<?=sprintf($text,$addr)?>",type:"success",html:true,confirmButtonText:"_(Ok)_"});
};
$.post("/webGui/include/UpdateDNS.php",success).fail(failure);
}
function checkPorts(form) {
var portsInUse = [<?=implode(',',$portsInUse)?>];
var range = [], list = [], duplicates = [];
@@ -359,12 +343,10 @@ _(Local access URLs)_:
$n = 0;
foreach($urls as $url) {
$msg = "";
$url0 = substr_count($url[0]??'',':')>3 ? preg_replace('#(://)(.+?)(:?\d*)/$#','$1[$2]$3/',$url[0]) : $url[0]; // IPv6 - IPv4 notation
$url1 = substr_count($url[1]??'',':')>3 ? preg_replace('#(://)(.+?)(:?\d*)/$#','$1[$2]$3/',$url[1]) : $url[1]; // IPv6 - IPv4 notation
if ($url[1]) $msg .= " "._("redirects to")." <a href='$url1'>$url1</a>";
if ($url[1]) $msg .= " "._("redirects to")." <a href='$url[1]'>$url[1]</a>";
if ($url[2]) $msg .= " "._("uses")." ".$url[2];
if ($url[3]) $msg .= "<span class='warning'> <i class='fa fa-warning fa-fw'></i> "._("is a self-signed certificate, ignore the browser's warning and proceed to the GUI")."</span>";
echo ($n ? "<dt>&nbsp;</dt><dd>" : ""),"<a href='$url0'>$url0</a>$msg",($n++ ? "</dd>" : "");
echo ($n ? "<dt>&nbsp;</dt><dd>" : ""),"<a href='$url[0]'>$url[0]</a>$msg",($n++ ? "</dd>" : "");
}?>
:mgmt_local_access_urls_help:
@@ -431,7 +413,7 @@ _(CA-signed certificate file)_:
<?endif;?>
&nbsp;
: <button type="submit" name="changePorts" value="Provision" <?=$disabled_provision?>><?=$provisionlabel?></button><button type="submit" name="changePorts" value="Delete" <?=$disabled_delete?> >_(Delete)_</button><!-- <button type="button" onclick="updateDNS(this)" <?=$disabled_updatedns?>>_(Update DNS)_</button> --><?=$disabled_provision_msg?>
: <button type="submit" name="changePorts" value="Provision" <?=$disabled_provision?>><?=$provisionlabel?></button><button type="submit" name="changePorts" value="Delete" <?=$disabled_delete?> >_(Delete)_</button><?=$disabled_provision_msg?>
:mgmt_certificate_expiration_help:

View File

@@ -18,8 +18,7 @@ Tag="folder-o"
<?
$width = [166,300];
function data_disks($disk) {
global $pools;
return (_var($disk,'type')=="Data" || (_var($disk,'type')=="Cache" && in_array(_var($disk,'name'),$pools))) && _var($disk,'status')=='DISK_OK';
return in_array(_var($disk,'type'),['Data','Cache']) && array_key_exists('exportable',$disk) && _var($disk,'fsStatus')=='Mounted';
}
?>
<script>

View File

@@ -0,0 +1,311 @@
Menu="NetworkServices"
Type="xmenu"
Title="Outgoing Proxy Manager"
Icon="icon-network"
Tag="icon-network"
---
<?php
/* Copyright 2024, Lime Technology
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
$opmPlugin = "dynamix";
require_once("plugins/".$opmPlugin."/include/OutgoingProxyLib.php");
/* Parse the plugin config file. */
$cfg = parse_plugin_config();
/* Pid file used to track the Running/Stopped status. */
$opm_pid = "OutgoingProxy";
$pid_file = "/var/run/".$opm_pid.".pid";
$cfg['proxy_active'] = $cfg['proxy_active'] ?? "0";
if ($cfg['proxy_active'] != "0") {
file_put_contents($pid_file, "running");
} else if (file_exists($pid_file)) {
unlink($pid_file);
}
/* Be sure proxy_mames are defined */
$cfg['proxy_name_1'] = $cfg['proxy_name_1'] ?? "";
$cfg['proxy_name_2'] = $cfg['proxy_name_2'] ?? "";
$cfg['proxy_name_3'] = $cfg['proxy_name_3'] ?? "";
/* Parse the url, user, and password from the full url for proxy 1. */
$url_array = get_proxy_info($cfg['proxy_url_1'] ?? "", $cfg['proxy_user_1'] ?? "", $cfg['proxy_pass_1'] ?? "");
$cfg['proxy_url_1'] = $url_array['url'];
$cfg['proxy_user_1'] = $url_array['user'];
$cfg['proxy_pass_1'] = $url_array['pass'];
$proxy_1_url = $url_array['full_url'];
/* Parse the url, user, and password from the full url for proxy 2. */
$url_array = get_proxy_info($cfg['proxy_url_2'] ?? "", $cfg['proxy_user_2'] ?? "", $cfg['proxy_pass_2'] ?? "");
$cfg['proxy_url_2'] = $url_array['url'];
$cfg['proxy_user_2'] = $url_array['user'];
$cfg['proxy_pass_2'] = $url_array['pass'];
$proxy_2_url = $url_array['full_url'];
/* Parse the url, user, and password from the full url for proxy 3. */
$url_array = get_proxy_info($cfg['proxy_url_3'] ?? "", $cfg['proxy_user_3'] ?? "", $cfg['proxy_pass_3'] ?? "");
$cfg['proxy_url_3'] = $url_array['url'];
$cfg['proxy_user_3'] = $url_array['user'];
$cfg['proxy_pass_3'] = $url_array['pass'];
$proxy_3_url = $url_array['full_url'];
?>
<form markdown="1" name="outgoing_proxy_manager" method="POST" action="/update.php" target="progressFrame">
<input type="hidden" name="#file" value="<?=$plg_config_file;?>">
<input type="hidden" name="#command" value="/plugins/<?=$opmPlugin;?>/scripts/outgoingproxy">
<input type="hidden" name="#arg[1]" value="apply">
<p><strong>_(Enable Outgoing Proxy)_</strong></p>
_(Select Proxy)_:
: <select name="proxy_active" style="width:20%;" size="1">
<?=mk_option($cfg['proxy_active'], "0", "_(None)_");?>
<?if (($cfg['proxy_url_1']) && ($cfg['proxy_name_1'])):?>
<?=mk_option($cfg['proxy_active'], "1", $cfg['proxy_name_1'], "disabled");?>
<?endif;?>
<?if (($cfg['proxy_url_2']) && ($cfg['proxy_name_2'])):?>
<?=mk_option($cfg['proxy_active'], "2", $cfg['proxy_name_2'], "disabled");?>
<?endif;?>
<?if (($cfg['proxy_url_3']) && ($cfg['proxy_name_3'])):?>
<?=mk_option($cfg['proxy_active'], "3", $cfg['proxy_name_3'], "disabled");?>
<?endif;?>
</select>
:outgoing_proxy_enable_plug:
> Select the Proxy to use. Only online Proxies will be selectable.
>
> If your network environment requires an outgoing http proxy, define that here.
>
> Outgoing connections from the webgui and some system processes will use the specified http proxy. Docker container installs and updates will use the proxy, but the container itself will not, neither will any VMs.
>
> For a more comprehensive solution you might consider setting up <u><a href='https://docs.unraid.net/unraid-os/manual/security/vpn/#configuring-vpn-tunneled-access-for-system/' target='_blank'>_(VPN tunnel access for System)_</a></u>.
:end
<p><strong>_(Outgoing Proxy)_ 1</strong></p>
_(Name)_:
: <input type="text" name="proxy_name_1" style="width:20%;" maxlength="25" value="<?=$cfg['proxy_name_1'];?>" placeholder="(_(Required)_)"><span id="proxy-status-1"></span>
:outgoing_proxy_name_plug:
> Outgoing Proxy name for this Proxy.
:end
_(URL)_:
: <input type="text" name="proxy_url_1" style="width:30%;" maxlength="100" value="<?=$cfg['proxy_url_1'];?>" onchange="verifyUrl(this)" placeholder="_(http://IP:port or http://host:port)_">
:outgoing_proxy_url_plug:
> Outgoing Proxy URL for this Proxy. The URL can be entered with or without credentials. The credentials will be parsed from the URL.
>
> If you enter a User and Password, they will be used as new credentials.
:end
_(User)_:
: <input type="text" name="proxy_user_1" class="wide" maxlength="100" value="<?=$cfg['proxy_user_1'];?>" placeholder="(_(Optional)_)">
:outgoing_proxy_user_plug:
> Outgoing Proxy User Name for this Proxy.
:end
_(Password)_:
: <input type="text" name="proxy_pass_1" class="wide" maxlength="100" value="<?=$cfg['proxy_pass_1'];?>" placeholder="(_(Optional)_)">
:outgoing_proxy_password_plug:
> Outgoing Proxy Password for this Proxy.
:end
<p><strong>_(Outgoing Proxy)_ 2</strong></p>
_(Name)_:
: <input type="text" name="proxy_name_2" style="width:20%;" maxlength="25" value="<?=$cfg['proxy_name_2'];?>" placeholder="(_(Required)_)"><span id="proxy-status-2"></span>
:outgoing_proxy_name_plug:
> Outgoing Proxy name for this Proxy.
:end
_(URL)_:
: <input type="text" name="proxy_url_2" style="width:30%;" maxlength="100" value="<?=$cfg['proxy_url_2'];?>" onchange="verifyUrl(this)" placeholder="_(http://IP:port or http://host:port)_">
:outgoing_proxy_url_plug:
> Outgoing Proxy URL for this Proxy. The URL can be entered with or without credentials. The credentials will be parsed from the URL.
>
> If you enter a User and Password, they will be used as new credentials.
:end
_(User)_:
: <input type="text" name="proxy_user_2" class="wide" maxlength="100" value="<?=$cfg['proxy_user_2'];?>" placeholder="(_(Optional)_)">
:outgoing_proxy_user_plug:
> Outgoing Proxy User Name for this Proxy.
:end
_(Password)_:
: <input type="text" name="proxy_pass_2" class="wide" maxlength="100" value="<?=$cfg['proxy_pass_2'];?>" placeholder="(_(Optional)_)">
:outgoing_proxy_password_plug:
> Outgoing Proxy Password for this Proxy.
:end
<p><strong>_(Outgoing Proxy)_ 3</strong></p>
_(Name)_:
: <input type="text" name="proxy_name_3" style="width:20%;" maxlength="25" value="<?=$cfg['proxy_name_3'];?>" placeholder="(_(Required)_)"><span id="proxy-status-3"></span>
:outgoing_proxy_name_plug:
> Outgoing Proxy name for this Proxy.
:end
_(URL)_:
: <input type="text" name="proxy_url_3" style="width:30%;" maxlength="100" value="<?=$cfg['proxy_url_3'];?>" onchange="verifyUrl(this)" placeholder="_(http://IP:port or http://host:port)_">
:outgoing_proxy_url_plug:
> Outgoing Proxy URL for this Proxy. The URL can be entered with or without credentials. The credentials will be parsed from the URL.
>
> If you enter a User and Password, they will be used as new credentials.
:end
_(User)_:
: <input type="text" name="proxy_user_3" class="wide" maxlength="100" value="<?=$cfg['proxy_user_3'];?>" placeholder="(_(Optional)_)">
:outgoing_proxy_user_plug:
> Outgoing Proxy User Name for this Proxy.
:end
_(Password)_:
: <input type="text" name="proxy_pass_3" class="wide" maxlength="100" value="<?=$cfg['proxy_pass_3'];?>" placeholder="(_(Optional)_)">
:outgoing_proxy_password_plug:
> Outgoing Proxy Password for this Proxy.
:end
&nbsp;
: <input type="submit" value='_(Apply)_'><input type="button" value="_(Done)_" onclick="done()">
</form>
<script>
/* Refresh Proxy Manager page showing updated proxy status. */
function refreshPage() {
$.post(OPMURL, {
action: "proxy_status",
proxy_1_url: "<?=$proxy_1_url;?>",
proxy_2_url: "<?=$proxy_2_url;?>",
proxy_3_url: "<?=$proxy_3_url;?>",
proxy_active: "<?=$cfg['proxy_active'];?>"
}, function(data) {
/* Refresh the proxy status. */
/* Update the proxy status div */
$('#proxy-status-1').html('<strong>' + data.proxy_status_1 + '</strong>');
/* Update the proxy status div */
$('#proxy-status-2').html('<strong>' + data.proxy_status_2 + '</strong>');
/* Update the proxy status div */
$('#proxy-status-3').html('<strong>' + data.proxy_status_3 + '</strong>');
//*Get a reference to the dropdown element. */
const dropdown = document.querySelector('select[name="proxy_active"]');
const options = dropdown.getElementsByTagName('option');
/* Enable the dropdown element if the proxy is available or active. */
const condition_1 = $('#proxy-status-1').text().trim() === '' || $('#proxy-status-1').text().trim() === 'Active';
const optionToEnableOrDisable_1 = options[1];
if (optionToEnableOrDisable_1) {
if (condition_1) {
/* Enable the option. */
optionToEnableOrDisable_1.removeAttribute('disabled');
} else {
/* Disable the option. */
optionToEnableOrDisable_1.setAttribute('disabled', 'disabled');
}
}
/* Enable the dropdown element if the proxy is available or active. */
const condition_2 = $('#proxy-status-2').text().trim() === '' || $('#proxy-status-2').text().trim() === 'Active';
const optionToEnableOrDisable_2 = options[2];
if (optionToEnableOrDisable_2) {
if (condition_2) {
/* Enable the option. */
optionToEnableOrDisable_2.removeAttribute('disabled');
} else {
/* Disable the option. */
optionToEnableOrDisable_2.setAttribute('disabled', 'disabled');
}
}
/* Enable the dropdown element if the proxy is available or active. */
const condition_3 = $('#proxy-status-3').text().trim() === '' || $('#proxy-status-3').text().trim() === 'Active';
const optionToEnableOrDisable_3 = options[3];
if (optionToEnableOrDisable_3) {
if (condition_3) {
/* Enable the option. */
optionToEnableOrDisable_3.removeAttribute('disabled');
} else {
/* Disable the option. */
optionToEnableOrDisable_3.setAttribute('disabled', 'disabled');
}
}
}, 'json');
}
/* polyfill to fix reportValidity() for Firefox. */
if (!HTMLInputElement.prototype.reportValidity || (navigator.userAgent.indexOf("Firefox") !== -1)) {
HTMLInputElement.prototype.reportValidity = function () {
if (this.checkValidity()) {
return true;
} else {
var labelText = "_(Invalid data)_";
try {
labelText = $(this).closest('dl').children().first()[0].textContent;
} catch (err) { }
/* the browser generates the validationMessage, we cannot translate it. */
swal({title:labelText,text:this.validationMessage,html:true,type:'error',confirmButtonText:"_(Ok)_"});
return false;
}
};
}
/* Verify the format of the url. */
function verifyUrl(inputElement) {
const fieldValue = inputElement.value;
/* Return true if the field is blank. */
if (fieldValue.trim() === '') {
return true;
}
/* Verify the url is in the correct format. */
if (fieldValue.startsWith("http://") && fieldValue.match(/:\d+$/)) {
inputElement.setCustomValidity("");
return true;
} else {
inputElement.setCustomValidity("_(Please match the requested format)_:\n\n"+"'_(http://IP:port or http://host:port)_'");
inputElement.reportValidity();
return false;
}
}
$(function() {
/* Status indicator on upper right of page. */
showStatus('pid','<?=$opm_pid;?>');
/* Page refresh rate in milliseconds. */
const REFRESH_INTERVAL = 15000;
/* Set page refresh interval every 15 seconds. */
window.setInterval(refreshPage, REFRESH_INTERVAL);
/* Do an initial page refresh to fill in values. */
refreshPage();
});
/* URL for Outgoing Proxy PHP file. */
const OPMURL = '/plugins/<?=$opmPlugin;?>/include/OutgoingProxy.php';
</script>

View File

@@ -101,7 +101,7 @@ function textsave(module,remove = false) {
if (data.modprobe == "") $('#text'+module).attr('hidden', true); else $('#text'+module).attr('rows', 3);
if (data.supportpage == true) {
if (data.support == true) {
document.getElementById("link" + module).innerHTML = "<a href='" + data.supporturl + "'target='_blank'><i title='"+_("Support page")_+"' class='fa fa-phone-square'></i></a>";
document.getElementById("link" + module).innerHTML = "<a href='" + data.supporturl + "'target='_blank'><i title='"+"_(Support page)_"+"' class='fa fa-phone-square'></i></a>";
}
}
}

View File

@@ -108,6 +108,15 @@ _(Local syslog folder)_:
:syslog_local_folder_help:
_(System identifier for logfile name)_:
: <select name="server_filename">
<?=mk_option($syslog['server_filename'], "syslog-%FROMHOST-IP%.log", _("IP Address"))?>
<?=mk_option($syslog['server_filename'], "syslog-%HOSTNAME%.log", _("Hostname (from syslog message)"))?>
<?=mk_option($syslog['server_filename'], "syslog-%FROMHOST%.log", _("Hostname (from DNS reverse lookup)"))?>
</select>
:syslog_remote_system_identifier_help:
_(Local syslog rotation)_:
: <select name="log_rotation" onchange="logOptions(this.value,'slow')">
<?=mk_option(_var($syslog,'log_rotation'), "", _("Disabled"))?>
@@ -146,7 +155,7 @@ _(Local syslog number of files)_:
</div>
_(Remote syslog server)_:
: <span class="span"><input type="text" name="remote_server" class="narrow" value="<?=_var($syslog,'remote_server')?>" maxlength="23" placeholder="_(name or ip address)_"></span>
: <span class="span"><input type="text" name="remote_server" class="narrow" value="<?=_var($syslog,'remote_server')?>" maxlength="50" placeholder="_(name or ip address)_"></span>
<select name="remote_protocol" class="narrow">
<?=mk_option(_var($syslog,'remote_protocol'), "udp", _("UDP"))?>
<?=mk_option(_var($syslog,'remote_protocol'), "tcp", _("TCP"))?>

View File

@@ -30,6 +30,8 @@ $(function() {
$globals = [];
$names = ['_SERVER','devs','disks','sec','sec_nfs','shares','users','var'];
foreach ($names as $name) $globals[$name] = $$name;
// show outgoing proxy information, is in the environment but not a superglobal
$globals['environment'] = ['http_proxy' => getenv('http_proxy'), 'no_proxy' => getenv('no_proxy')];
echo "<pre class='up'>",htmlspecialchars(print_r($globals,true)),"</pre>";
?>
<input type="button" value="_(Done)_" onclick="done()">

View File

@@ -1,121 +0,0 @@
Menu="UNRAID-OS"
Title="Wake On LAN"
Icon="fa-bell"
Tag="server"
---
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
if (count($_POST)) {
$cfg = NULL ;
if ($_POST['#apply'] == "_(Save)_") {
foreach($_POST as $postkey=>$data) {
if ($postkey=="#apply") continue;
$keys = explode(";",$postkey);
if (count($keys) >1) $update_file[$keys[1]][$keys[2]][$keys[0]]=$data;
}
foreach($update_file as $type => $types) {
foreach($types as $name => $details) {
if ($details['user_mac'] == "") $details['user_mac'] = "None Defined";
if ($details['user_mac'] == "None Defined" && ($details['enable'] == "enable" || $details['enable'] == "shutdown")) unset($update_file[$type][$name]) ;
}
}
}
unset($_POST) ;
file_put_contents("/boot/config/wol.json",json_encode($update_file));
#echo '<meta http-equiv="refresh" content="0;url=/Tools">';
echo '<meta http-equiv="refresh" content="0">';
#unset($_SESSION['csrf_token']);
}
?>
<script src="/webGui/javascript/jquery.tablesorter.widgets.js"></script>
<script>
function showWOL(options, init = false) {
option = options;
if (init) {
$('#wolsearch').prop('disabled', true);
$.post('/webGui/include/WOL.php',{table:'t1load',option:"all"},function(data){
clearTimeout(timers.refresh);
filter = [];
$("#t1").trigger("destroy");
$('#t1').html(data.html);
$('#t1').tablesorter({
sortList: [[0,0]],
sortAppend: [[0,0]],
widgets: ['stickyHeaders','filter','zebra'],
widgetOptions: {
// on black and white, offset is height of #menu
// on azure and gray, offset is height of #header
stickyHeaders_offset: ($('#menu').height() < 50) ? $('#menu').height() : $('#header').height(),
filter_columnFilters: false,
zebra: ["normal-row","alt-row"]
}
});
$('div.spinner.fixed').hide('slow');
$('#wolsearch').prop('disabled', false);
$('#select').prop('disabled', false);
$('#rebuild').prop('disabled', data.init);
},"json");
} else {
filter = [];
filterWOL();
}
}
function filterWOL() {
var totalColumns = $('#t1')[0].config.columns;
var filter = [];
filter[totalColumns] = $('#wolsearch').val(); // this searches all columns
$('#t1').trigger('search', [filter]);
}
function showWOLupdate() {
$('#rebuild').prop('disabled', true);
$('#t1').html("");
$('#wolsearch').prop('disabled', true);
$('#select').prop('disabled', true);
$('div.spinner.fixed').show('slow');
$.post('/webGui/include/WOL.php',{table:'t1create',option:"all"},function(data){
$('#rebuild').prop('disabled', false);
showWOL("all",true);
$('div.spinner.fixed').hide('slow');
});
}
function maccreate(name) {
$.post('/webGui/include/WOL.php',{table:'macaddress'}, function( data ) {
if (data.mac) {
$('#'+name).val(data.mac);
}
},'json');
}
showWOL("all",true);
</script>
:WOL_intro_help:
<form autocomplete="off" onsubmit="return false;"><span><input class="t1 search" id="wolsearch" type="search" placeholder="Search..." onchange="filterWOL();"></span></form>
<pre><form name="WOL" id="WOL" method="POST" class="js-confirm-leave" >
<table name="t1"id='t1' class="t1 unraid tablesorter" >
<tr><td><div class="spinner"></div></td></tr></table></pre><br>
<input type="button" value="_(Done)_" onclick="done()">
<input type="submit" name="#apply" id='#apply' value="_(Save)_" >
</form>

View File

@@ -1,102 +0,0 @@
Menu="OtherSettings"
Type="xmenu"
Title="Wake on Lan Settings"
Icon="fa-bell"
Tag="share-alt"
---
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
exec("ls --indicator-style=none /sys/class/net|grep -P '^eth[1-9][0-9]*$'",$ports);
$disabled = _var($var,'fsState')!='Stopped' ? 'disabled' : '';
$width = [166,300];
$file = '/boot/config/wol.cfg';
$current = parse_ini_file($file);
if (!isset($current['LOGFILE'])) $current['LOGFILE'] = "syslog"
?>
<script>
showStatus('pid','unraidwold');
</script>
<form markdown="1" name="WOLsettings" method="POST" action="/update.php" target="progressFrame" >
<input type="hidden" name="#file" value="<?=$file;?>">
<input type="hidden" name="#command" value="/webGui/scripts/WOL_action">
<input type="hidden" name="#arg[1]" value="load">
_(Enable Wake on Lan)_:
: <select name="WOLENABLED" >
<?=mk_option($current['WOLENABLED'], "no", _('No'))?>
<?=mk_option($current['WOLENABLED'], "yes", _('Yes'))?>
</select>
:WOL_enable_help:
_(Enable Docker actions)_:
: <select name="RUNDOCKER" >
<?=mk_option($current['RUNDOCKER'], "y", _('Yes'))?>
<?=mk_option($current['RUNDOCKER'], "n", _('No'))?>
</select>
:WOL_run_docker_help:
_(Enable LXC actions)_:
: <select name="RUNLXC" >
<?=mk_option($current['RUNLXC'], "y", _('Yes'))?>
<?=mk_option($current['RUNLXC'], "n", _('No'))?>
</select>
:WOL_run_LXC_help:
_(Enable VM actions)_:
: <select name="RUNVM" >
<?=mk_option($current['RUNVM'], "y", _('Yes'))?>
<?=mk_option($current['RUNVM'], "n", _('No'))?>
</select>
:WOL_run_VM_help:
_(Enable Shutdown actions)_:
: <select name="RUNSHUT" >
<?=mk_option($current['RUNSHUT'], "n", _('No'))?>
<?=mk_option($current['RUNSHUT'], "y", _('Yes'))?>
</select>
:WOL_run_shutdown_help:
_(Interface to listern on)_:
: <select id="INTERFACE" name="INTERFACE" >
<?=mk_option(_var($eth0,'INTERFACE'),'eth0','eth0','selected')?>
<?foreach ($ports as $port):?>
<?if (!locked('eth0',$port)) echo mk_option_check($current['INTERFACE'],$port,$port)?>
<?endforeach;?>
</select>
:WOL_interface_help:
_(Interface promiscuous mode)_:
: <select id="IFMODE" name="IFMODE" >
<?=mk_option($current['IFMODE'], "n", _('No'))?>
<?=mk_option($current['IFMODE'], "y", _('Yes'))?>
</select>
:WOL_promiscuous_mode_help:
_(Log file)_:
: <input name="LOGFILE" class="narrow"type="text" value=<?=$current['LOGFILE']?>>
:WOL_log_file_help:
&nbsp;
: <input type="submit" value="_(Apply)_" disabled><input type="button" value="_(Done)_" onclick="done()">
</form>

View File

@@ -1,3 +0,0 @@
#!/bin/bash
/usr/local/emhttp/plugins/dynamix/scripts/WOL_action load &

View File

@@ -1,3 +0,0 @@
#!/bin/bash
/usr/local/emhttp/plugins/dynamix/include/script/WOL_action stop &

View File

@@ -72,6 +72,57 @@ function my_devs(&$devs,$name,$menu) {
}
return implode($text);
}
function icon_class($ext) {
switch ($ext) {
case '3gp': case 'asf': case 'avi': case 'f4v': case 'flv': case 'm4v': case 'mkv': case 'mov': case 'mp4': case 'mpeg': case 'mpg': case 'm2ts': case 'ogm': case 'ogv': case 'vob': case 'webm': case 'wmv':
return 'fa fa-film';
case '7z': case 'bz2': case 'gz': case 'rar': case 'tar': case 'xz': case 'zip':
return 'fa fa-file-archive-o';
case 'aac': case 'ac3': case 'dsf': case 'flac': case 'm4a': case 'mka': case 'mp2': case 'mp3': case 'oga': case 'ogg': case 'tds': case 'wav': case 'wma':
return 'fa fa-music';
case 'ai': case 'eps': case 'fla': case 'psd': case 'swf':
return 'fa fa-file-image-o';
case 'avif': case 'bmp': case 'gif': case 'ico': case 'jp2': case 'jpc': case 'jpeg': case 'jpg': case 'jpx': case 'png': case 'svg': case 'tif': case 'tiff': case 'wbmp': case 'webp': case 'xbm':
return 'fa fa-picture-o';
case 'bak': case 'swp':
return 'fa fa-clipboard';
case 'bat':
return 'fa fa-terminal';
case 'bot': case 'cfg': case 'conf': case 'dat': case 'htaccess': case 'htpasswd': case 'ini': case 'log': case 'pl': case 'tmp': case 'toml': case 'top': case 'txt': case 'yaml': case 'yml':
return 'fa fa-file-text-o';
case 'c': case 'config': case 'cpp': case 'cs': case 'dtd': case 'exe': case 'ftpquota': case 'gitignore': case 'hbs': case 'json': case 'jsx': case 'lock': case 'map': case 'md': case 'msi': case 'passwd': case 'rs': case 'sh': case 'sql': case 'tpl': case 'ts': case 'tsx': case 'twig':
return 'fa fa-file-code-o';
case 'css': case 'less': case 'sass': case 'scss':
return 'fa fa-css3';
case 'csv':
return 'fa fa-file-text-o';
case 'cue': case 'm3u': case 'm3u8': case 'pls': case 'xspf':
return 'fa fa-headphones';
case 'doc': case 'docm': case 'docx': case 'dot': case 'dotm': case 'dotx': case 'odt':
return 'fa fa-file-word-o';
case 'eml': case 'msg':
return 'fa fa-envelope-o';
case 'eot': case 'fon': case 'otf': case 'ttc': case 'ttf': case 'woff': case 'woff2':
return 'fa fa-font';
case 'htm': case 'html': case 'shtml': case 'xhtml':
return 'fa fa-html5';
case 'js': case 'php': case 'php4': case 'php5': case 'phps': case 'phtml': case 'py':
return 'fa fa-code';
case 'key':
return 'fa fa-key';
case 'ods': case 'xla': case 'xls': case 'xlsb': case 'xlsm': case 'xlsx': case 'xlt': case 'xltm': case 'xltx':
return 'fa fa-file-excel-o';
case 'pdf':
return 'fa fa-file-pdf-o';
case 'pot': case 'potx': case 'ppt': case 'pptm': case 'pptx':
return 'fa fa-file-powerpoint-o';
case 'xml': case 'xsl':
return 'fa fa-file-excel-o';
default:
return 'fa fa-file-o';
}
}
$dir = validdir(htmlspecialchars_decode(rawurldecode($_GET['dir'])));
if (!$dir) {echo '<tbody><tr><td></td><td></td><td colspan="6">',_('Invalid path'),'</td><td></td></tr></tbody>'; exit;}
@@ -102,7 +153,7 @@ while (($row = fgets($stat))!==false) {
$text = [];
if ($type[0]=='d') {
$text[] = '<tr><td><i id="check_'.$objs.'" class="fa fa-fw fa-square-o" onclick="selectOne(this.id)"></i></td>';
$text[] = '<td data=""><div class="icon-dir"></div></td>';
$text[] = '<td data=""><i class="fa fa-folder-o"></i></td>';
$text[] = '<td><a id="name_'.$objs.'" oncontextmenu="folderContextMenu(this.id,\'right\');return false" href="/'.$path.'?dir='.rawurlencode(htmlspecialchars($name)).'">'.htmlspecialchars(basename($name)).'</a></td>';
$text[] = '<td id="owner_'.$objs.'">'.$owner.'</td>';
$text[] = '<td id="perm_'.$objs.'">'.$perm.'</td>';
@@ -115,7 +166,7 @@ while (($row = fgets($stat))!==false) {
$ext = strtolower(pathinfo($name,PATHINFO_EXTENSION));
$tag = count($devs)>1 ? 'warning' : '';
$text[] = '<tr><td><i id="check_'.$objs.'" class="fa fa-fw fa-square-o" onclick="selectOne(this.id)"></i></td>';
$text[] = '<td class="ext" data="'.$ext.'"><div class="icon-file icon-'.$ext.'"></div></td>';
$text[] = '<td class="ext" data="'.$ext.'"><i class="'.icon_class($ext).'"></i></td>';
$text[] = '<td id="name_'.$objs.'" class="'.$tag.'" onclick="fileEdit(this.id)" oncontextmenu="fileContextMenu(this.id,\'right\');return false">'.htmlspecialchars(basename($name)).'</td>';
$text[] = '<td id="owner_'.$objs.'" class="'.$tag.'">'.$owner.'</td>';
$text[] = '<td id="perm_'.$objs.'" class="'.$tag.'">'.$perm.'</td>';
@@ -128,6 +179,6 @@ while (($row = fgets($stat))!==false) {
}
}
pclose($stat);
if ($link = parent_link()) echo '<tbody class="tablesorter-infoOnly"><tr><td></td><td><div><img src="/webGui/icons/folderup.png"></div></td><td>',$link,'</td><td colspan="6"></td></tr></tbody>';
if ($link = parent_link()) echo '<tbody class="tablesorter-infoOnly"><tr><td></td><td><i class="fa fa-folder-open-o"></i></td><td>',$link,'</td><td colspan="6"></td></tr></tbody>';
echo write($dirs),write($files),'<tfoot><tr><td></td><td></td><td colspan="7">',add($objs,'object'),': ',add($dirs,'director','y','ies'),', ',add($files,'file'),' (',my_scale($total,$unit),' ',$unit,' ',_('total'),')</td></tr></tfoot>';
?>

View File

@@ -165,7 +165,7 @@ if ($_POST['vms']) {
echo $vmhtml;
}
if (!count($vmusagehtml)) echo "<span id='no_usagevms'><br> "._('No running virtual machines')."<br></span>";
if ($running < 1 && count($vmsusagehtml)) echo "<span id='no_usagevms'><br>". _('No running virtual machines')."<br></span>";
if ($running < 1 && count($vmusagehtml)) echo "<span id='no_usagevms'><br>". _('No running virtual machines')."<br></span>";
echo "</td></tr>";
}
}

View File

@@ -291,4 +291,13 @@ function my_mkdir($dirname,$permissions = 0777,$recursive = false) {
break;
}
}
function get_realvolume($path) {
if (strpos($path,"/mnt/user/",0) === 0)
$reallocation = trim(shell_exec("getfattr --absolute-names --only-values -n system.LOCATION ".escapeshellarg($path)." 2>/dev/null"));
else {
$realexplode = explode("/",str_replace("/mnt/","",$path));
$reallocation = $realexplode[0];
}
return $reallocation;
}
?>

View File

@@ -73,3 +73,11 @@ class KeyInstaller
}
}
}
$isGetRequest = !empty($_SERVER) && isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'GET';
$getHasUrlParam = $_GET !== null && !empty($_GET) && isset($_GET['url']);
if ($isGetRequest && $getHasUrlParam) {
$keyInstaller = new KeyInstaller();
$keyInstaller->installKey();
}

View File

@@ -39,13 +39,13 @@ foreach ($files as $file) {
$c = 0;
foreach ($fields as $field) {
if ($c==5) break;
$text = $field ? explode('=',$field,2)[1] : "-";
$text = $field ? (explode('=',$field,2)[1]??"") : "-";
$tag = ($c<4) ? "" : " data='".str_replace(['alert','warning','normal'],['0','1','2'],$text)."'";
echo (!$c++) ? "<tr>".str_replace('*',$text,$td_).date($dynamix['notify']['date'].' '.$dynamix['notify']['time'],$text)."$_td" : "<td$tag>"._($text)."</td>";
}
echo "<td><a href='#' onclick='$(this).hide();$.post(\"/webGui/include/DeleteLogFile.php\",{log:\"$archive\"},function(){archiveList();});return false' title=\""._('Delete notification')."\"><i class='fa fa-trash-o'></i></a></td></tr>";
if ($extra) {
$text = explode('=',$field,2)[1];
$text = explode('=',$field,2)[1]??"";
echo "<tr class='tablesorter-childRow row$row'><td colspan='4'>$text</td><td></td></tr><tr class='tablesorter-childRow row$row'><td colspan='5'></td></tr>";
$row++;
}

View File

@@ -0,0 +1,50 @@
<?php
/* Copyright 2024, Lime Technology
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
$opmPlugin = "dynamix";
require_once("plugins/".$opmPlugin."/include/OutgoingProxyLib.php");
switch ($_POST['action']) {
case 'proxy_status':
/* Get the active proxy. */
$proxy_active = urldecode($_POST['proxy_active']);
/* Get the proxy 1 status. */
$proxy_1_url = urldecode($_POST['proxy_1_url']);
if ($proxy_1_url) {
$proxy_1_status = proxy_online($proxy_1_url) ? ($proxy_active == "1" ? "Active" : "") : ($proxy_active == "1" ? "Offline" : "Not Available");
} else {
$proxy_1_status = "";
}
/* Get the proxy 2 status. */
$proxy_2_url = urldecode($_POST['proxy_2_url']);
if ($proxy_2_url) {
$proxy_2_status = proxy_online($proxy_2_url) ? ($proxy_active == "2" ? "Active" : "") : ($proxy_active == "2" ? "Offline" : "Not Available");
} else {
$proxy_2_status = "";
}
/* Get the proxy 3 status. */
$proxy_3_url = urldecode($_POST['proxy_3_url']);
if ($proxy_3_url) {
$proxy_3_status = proxy_online($proxy_3_url) ? ($proxy_active == "3" ? "Active" : "") : ($proxy_active == "3" ? "Offline" : "Not Available");
} else {
$proxy_3_status = "";
}
echo json_encode(array( 'proxy_status_1' => $proxy_1_status, 'proxy_status_2' => $proxy_2_status, 'proxy_status_3' => $proxy_3_status ));
break;
default:
outgoingproxy_log("Undefined POST action - ".$_POST['action'].".");
break;
}
?>

View File

@@ -0,0 +1,191 @@
<?php
/* Copyright 2024, Lime Technology
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
$opmPlugin = "dynamix";
/* UI config file location. */
$plg_config_file = "/boot/config/plugins/".$opmPlugin."/outgoingproxy.cfg";
/* Outgoing Proxy Manager logging tag. */
$opm_log = "Outgoing Proxy Manager";
/* Outgoing Proxy logging. */
function outgoingproxy_log($m) {
global $opm_log;
$m = print_r($m,true);
$m = str_replace("\n", " ", $m);
$m = str_replace('"', "'", $m);
exec("/usr/bin/logger"." ".escapeshellarg($m)." -t ".escapeshellarg($opm_log));
}
/* Parse plugin config file. */
function parse_plugin_config() {
global $plg_config_file;
$cfg = is_file($plg_config_file) ? @parse_ini_file($plg_config_file, true) : array();
return($cfg);
}
/* Write values to plugin config file. */
function write_plugin_config($config) {
global $plg_config_file;
/* Rewrite config file. */
/* Convert the array to an INI string. */
$iniString = '';
foreach ($config as $key => $value) {
$iniString .= "$key=\"$value\"\n";
}
/* Write the INI string to a file. */
file_put_contents($plg_config_file, $iniString);
}
/* Check to see if the proxy is online and available. */
function proxy_online($proxyUrl) {
$rc = true;
if ($proxyUrl) {
/* Initialize cURL session. */
$ch = curl_init("http://www.msftncsi.com/ncsi.txt");
/* Set cURL options. */
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3); /* Timeout in seconds. */
curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, true);
curl_setopt($ch, CURLOPT_PROXY, $proxyUrl); /* Url is a proxy. */
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); /* Return transfer as a string. */
/* Execute cURL request. */
$response = curl_exec($ch);
if ($response === false) {
/* Proxy is not available. */
$rc = false;
}
/* Close cURL session. */
curl_close($ch);
}
return ($rc);
}
/* Get the URL with the user and password parsed from the url. */
function get_proxy_info($cfg_url, $cfg_user = "", $cfg_pass = "") {
/* Passed in values:
cfg_url - can be with or without credentials (user and password).
cfg_user - user from config file.
cfg_pass - encrypted password from the config file.
*/
/* An array is returned with the following values. */
$return = [
'url' => '', /* URL without credentials. */
'user' => '', /* User. */
'pass' => '', /* Unencrypted password. */
'full_url' => '', /* Full URL with credentials urlencoded. */
];
if ($cfg_url) {
/* Decrypt password. */
$cfg_pass = decrypt_data($cfg_pass);
/* Parse the URL by removing the user and password. */
$urlComponents = parse_url($cfg_url);
/* Parse user, password, host, and port from stored URL. */
$host = isset($urlComponents['host']) ? $urlComponents['host'] : '';
$port = isset($urlComponents['port']) ? $urlComponents['port'] : '';
$user = isset($urlComponents['user']) ? $urlComponents['user'] : '';
$pass = isset($urlComponents['pass']) ? $urlComponents['pass'] : '';
/* Return array of url, user, and password. */
$return['url'] = "http://".$host.':'.$port;
/* Extract the credentials. */
if (strpos($cfg_url, '%') !== false) {
/* The credentials are urlencoded. */
$return['user'] = $user ? urldecode($user) : $cfg_user;
$return['pass'] = $pass ? urldecode($pass) : $cfg_pass;
} else {
/* The credentials are not urlencoded. */
$return['user'] = $user ? $user : $cfg_user;
$return['pass'] = $pass ? $pass : $cfg_pass;
}
/* Put together the full url. */
if (($return['user']) && ($return['pass'])) {
$return['full_url'] = "http://".urlencode($return['user']).":".urlencode($return['pass'])."@".$host.":".$port;
} else {
$return['full_url'] = $return['url'];
}
}
return($return);
}
/* Get configuration parameter. */
function get_config($variable) {
$config = parse_plugin_config();
return $config[$variable] ?? "";
}
/* Set configuration parameter. */
function set_config($variable, $value) {
$config = parse_plugin_config();
$config[$variable] = $value;
write_plugin_config($config);
}
/* Encrypt data. */
function encrypt_data($data) {
$key = get_config("key");
if ((! $key) || strlen($key) != 32) {
$key = substr(base64_encode(openssl_random_pseudo_bytes(32)), 0, 32);
set_config("key", $key);
}
$iv = get_config("iv");
if ((! $iv) || strlen($iv) != 16) {
$iv = substr(base64_encode(openssl_random_pseudo_bytes(16)), 0, 16);
set_config("iv", $iv);
}
/* Encrypt the data using aes256. */
$value = trim(openssl_encrypt($data, 'aes256', $key, $options=0, $iv));
return $value;
}
/* Decrypt data. */
function decrypt_data($data) {
$key = get_config("key");
$iv = get_config("iv");
/* Decrypt the data using aes256. */
$value = openssl_decrypt($data, 'aes256', $key, $options=0, $iv);
/* Make sure the data is UTF-8 encoded. */
if (! mb_check_encoding($value, 'UTF-8')) {
outgoingproxy_log("Warning: Data is not UTF-8 encoded");
$value = "";
}
return $value;
}
?>

View File

@@ -73,7 +73,7 @@ case 't1load':
} else {
$supporturl = $module['supporturl'];
$pluginname = $module['plugin'];
$supporthtml = "<span id='link$modname'><a href='$supporturl' target='_blank'><i title='"._("Support page $pluginname")."' class='fa fa-phone-square'></i></a></span>";
$supporthtml = "<span id='link$modname'><a href='$supporturl' target='_blank'><i title='"._("Support page")." $pluginname' class='fa fa-phone-square'></i></a></span>";
}
}
if (!empty($module["version"])) $version = " (".$module["version"].")"; else $version = "";

View File

@@ -1,6 +1,6 @@
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
/* Copyright 2005-2024, Lime Technology
* Copyright 2012-2024, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
@@ -12,353 +12,15 @@
?>
<?
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
require_once "$docroot/webGui/include/Helpers.php";
// add translations
$_SERVER['REQUEST_URI'] = 'settings';
require_once "$docroot/webGui/include/Translations.php";
function host_lookup_ip($host) {
$result = @dns_get_record($host, DNS_A);
$ip = $result ? _var($result[0],'ip') : '';
return($ip);
}
function rebindDisabled() {
global $isLegacyCert;
$rebindtesturl = $isLegacyCert ? "rebindtest.unraid.net" : "rebindtest.myunraid.net";
// DNS Rebind Protection - this checks the server but clients could still have issues
$validResponse = ["192.168.42.42", "fd42"];
$response = host_lookup_ip($rebindtesturl);
return in_array(explode('::',$response)[0], $validResponse);
}
function format_port($port) {
return ($port != 80 && $port != 443) ? ':'.$port : '';
}
function anonymize_host($host) {
global $anon;
if ($anon) {
$host = preg_replace('/.*\.myunraid\.net/', '*.hash.myunraid.net', $host);
$host = preg_replace('/.*\.unraid\.net/', 'hash.unraid.net', $host);
}
return $host;
}
function anonymize_ip($ip) {
global $anon;
if ($anon && filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE)) {
$ip = "[redacted]";
}
return $ip;
}
function generate_internal_host($host, $ip) {
if (strpos($host,'.myunraid.net') !== false) {
$host = str_replace('*', str_replace('.', '-', $ip), $host);
}
return $host;
}
function generate_external_host($host, $ip) {
if (strpos($host,'.myunraid.net') !== false) {
$host = str_replace('*', str_replace('.', '-', $ip), $host);
} elseif (strpos($host,'.unraid.net') !== false) {
$host = "www.".$host;
}
return $host;
}
function verbose_output($httpcode, $result) {
global $cli, $verbose, $anon, $plgversion, $post, $var, $isRegistered, $myservers, $reloadNginx, $nginx, $isLegacyCert;
global $remoteaccess;
global $icon_warn, $icon_ok;
if (!$cli || !$verbose) return;
if ($anon) echo "(Output is anonymized, use '-vv' to see full details)".PHP_EOL;
echo "Unraid OS "._var($var,'version','???').((strpos($plgversion, "base-") === false) ? " with My Servers plugin version {$plgversion}" : '').PHP_EOL;
echo ($isRegistered) ? "{$icon_ok}Signed in to Unraid.net as {$myservers['remote']['username']}".PHP_EOL : "{$icon_warn}Not signed in to Unraid.net".PHP_EOL ;
echo "Use SSL is "._var($nginx,'NGINX_USESSL','No').PHP_EOL;
echo (rebindDisabled()) ? "{$icon_ok}Rebind protection is disabled" : "{$icon_warn}Rebind protection is enabled";
echo " for ".($isLegacyCert ? "unraid.net" : "myunraid.net").PHP_EOL;
if ($post) {
$wanip = trim(@file_get_contents("https://wanip4.unraid.net/"));
// check the data
$certhostname = _var($nginx,'NGINX_CERTNAME');
if ($certhostname) {
// $certhostname is $nginx['NGINX_CERTNAME'] (certificate_bundle.pem)
$certhostip = host_lookup_ip(generate_internal_host($certhostname, _var($post,'internalip')));
$certhosterr = ($certhostip != _var($post,'internalip'));
}
if (_var($post,'internalhostname') != $certhostname) {
// $post['internalhostname'] is $nginx['NGINX_LANMDNS'] (no cert, or Server_unraid_bundle.pem) || $nginx['NGINX_CERTNAME'] (certificate_bundle.pem)
$internalhostip = host_lookup_ip(generate_internal_host(_var($post,'internalhostname'), _var($post,'internalip')));
$internalhosterr = ($internalhostip != _var($post,'internalip'));
}
if (!empty($post['externalhostname'])) {
// $post['externalhostname'] is $nginx['NGINX_CERTNAME'] (certificate_bundle.pem)
$externalhostip = host_lookup_ip(generate_external_host($post['externalhostname'], $wanip));
$externalhosterr = ($externalhostip != $wanip);
}
// anonymize data. no caclulations can be done with this data beyond this point.
if ($anon) {
if (!empty($certhostip)) $certhostip = anonymize_ip($certhostip);
if (!empty($certhostname)) $certhostname = anonymize_host($certhostname);
if (!empty($internalhostip)) $internalhostip = anonymize_ip($internalhostip);
if (!empty($externalhostip)) $externalhostip = anonymize_ip($externalhostip);
if (!empty($wanip)) $wanip = anonymize_ip($wanip);
if (!empty($post['internalip'])) $post['internalip'] = anonymize_ip($post['internalip']);
if (!empty($post['internalhostname'])) $post['internalhostname'] = anonymize_host($post['internalhostname']);
if (!empty($post['externalhostname'])) $post['externalhostname'] = anonymize_host($post['externalhostname']);
if (!empty($post['externalport'])) $post['externalport'] = "[redacted]";
}
// always anonymize the keyfile
if (!empty($post['keyfile'])) $post['keyfile'] = "[redacted]";
// output notes
if (!empty($post['internalprotocol']) && !empty($post['internalhostname']) && !empty($post['internalport'])) {
$localurl = $post['internalprotocol']."://".generate_internal_host($post['internalhostname'], _var($post,'internalip')).format_port($post['internalport']);
echo 'Local Access url: '.$localurl.PHP_EOL;
if ($internalhostip) {
// $internalhostip will not be defined for .local domains, ok to skip
echo ($internalhosterr) ? $icon_warn : $icon_ok;
echo generate_internal_host($post['internalhostname'], _var($post,'internalip'))." resolves to {$internalhostip}";
echo ($internalhosterr) ? ", it should resolve to "._var($post,'internalip') : "";
echo PHP_EOL;
}
if ($certhostname) {
echo ($certhosterr) ? $icon_warn : $icon_ok;
echo generate_internal_host($certhostname, _var($post,'internalip')).' ';
echo ($certhostip) ? "resolves to {$certhostip}" : "does not resolve to an IP address";
echo ($certhosterr) ? ", it should resolve to "._var($post,'internalip') : "";
echo PHP_EOL;
}
if ($remoteaccess == 'yes' && !empty($post['externalprotocol']) && !empty($post['externalhostname']) && !empty($post['externalport'])) {
$remoteurl = $post['externalprotocol']."://".generate_external_host($post['externalhostname'], $wanip).format_port($post['externalport']);
echo 'Remote Access url: '.$remoteurl.PHP_EOL;
echo ($externalhosterr) ? $icon_warn : $icon_ok;
echo generate_external_host($post['externalhostname'], $wanip).' ';
echo ($externalhosterr) ? "does not resolve to an IP address" : "resolves to ".($externalhostip??'');
echo PHP_EOL;
}
if ($reloadNginx) {
echo "IP address changes were detected, nginx was reloaded".PHP_EOL;
}
}
// output post data
echo PHP_EOL.'Request:'.PHP_EOL;
echo @json_encode($post, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT) . PHP_EOL;
}
if ($result) {
echo "Response (HTTP $httpcode):".PHP_EOL;
$mutatedResult = is_array($result) ? json_encode($result) : $result;
echo @json_encode(@json_decode($mutatedResult, true), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT) . PHP_EOL;
}
}
/**
* @name response_complete
* @param {HTTP Response Status Code} $httpcode https://developer.mozilla.org/en-US/docs/Web/HTTP/Status
* @param {String|Array} $result - strings are assumed to be encoded JSON. Arrays will be encoded to JSON.
* @param {String} $cli_success_msg
*/
function response_complete($httpcode, $result, $cli_success_msg='') {
global $cli, $verbose;
$mutatedResult = is_array($result) ? json_encode($result) : $result;
if ($cli) {
if ($verbose) verbose_output($httpcode, $result);
$json = @json_decode($mutatedResult,true);
if (!empty($json['error'])) {
echo 'Error: '.$json['error'].PHP_EOL;
exit(1);
}
exit($cli_success_msg.PHP_EOL);
}
header('Content-Type: application/json');
http_response_code($httpcode);
exit((string)$mutatedResult);
}
require_once "$docroot/webGui/include/Wrappers.php";
// This is a stub, does nothing but return success
my_logger("This is a stub and should not be called", "UpdateDNS");
$cli = php_sapi_name()=='cli';
$verbose = $anon = false;
if ($cli && ($argc > 1) && $argv[1] == "-v") {
$verbose = true;
$anon = true;
}
if ($cli && ($argc > 1) && $argv[1] == "-vv") {
$verbose = true;
}
$var = (array)@parse_ini_file('/var/local/emhttp/var.ini');
$nginx = (array)@parse_ini_file('/var/local/emhttp/nginx.ini');
$is69 = version_compare(_var($var,'version'),"6.9.9","<");
$reloadNginx = false;
$dnserr = false;
$icon_warn = "⚠️ ";
$icon_ok = "✅ ";
$myservers_flash_cfg_path='/boot/config/plugins/dynamix.my.servers/myservers.cfg';
$myservers = (array)@parse_ini_file($myservers_flash_cfg_path,true);
// ensure some vars are defined here so we don't have to test them later
if (empty($myservers['remote']['apikey'])) {
$myservers['remote']['apikey'] = "";
}
if (empty($myservers['remote']['wanaccess'])) {
$myservers['remote']['wanaccess'] = "no";
}
if (empty($myservers['remote']['wanport'])) {
$myservers['remote']['wanport'] = 443;
}
// remoteaccess, externalport
if ($cli) {
$remoteaccess = empty($nginx['NGINX_WANFQDN']) ? 'no' : 'yes';
$externalport = $myservers['remote']['wanport'];
} else {
$remoteaccess = _var($_POST,'remoteaccess','no');
$externalport = intval(_var($_POST,'externalport',443));
if ($remoteaccess != 'yes') {
$remoteaccess = 'no';
}
if ($externalport < 1 || $externalport > 65535) {
$externalport = 443;
}
if ($myservers['remote']['wanaccess'] != $remoteaccess) {
// update the wanaccess ini value
$orig = file_exists($myservers_flash_cfg_path) ? parse_ini_file($myservers_flash_cfg_path,true) : [];
if (!$orig) {
$orig = ['remote' => $myservers['remote']];
}
$orig['remote']['wanaccess'] = $remoteaccess;
$text = '';
foreach ($orig as $section => $block) {
$pairs = "";
foreach ($block as $key => $value) if (strlen($value)) $pairs .= "$key=\"$value\"\n";
if ($pairs) $text .= "[$section]\n".$pairs;
}
if ($text) file_put_contents($myservers_flash_cfg_path, $text);
// need nginx reload
$reloadNginx = true;
}
exit("success".PHP_EOL);
}
$isRegistered = !empty($myservers['remote']['username']);
// protocols, hostnames, ports
$internalprotocol = 'http';
$internalport = _var($nginx,'NGINX_PORT');
$internalhostname = _var($nginx,'NGINX_LANMDNS');
$externalprotocol = 'https';
// keyserver will expand *.hash.myunraid.net or add www to hash.unraid.net as needed
$externalhostname = _var($nginx,'NGINX_CERTNAME');
$isLegacyCert = preg_match('/.*\.unraid\.net$/', _var($nginx,'NGINX_CERTNAME'));
$isWildcardCert = preg_match('/.*\.myunraid\.net$/', _var($nginx,'NGINX_CERTNAME'));
$internalip = _var($nginx,'NGINX_LANIP');
if (_var($nginx,'NGINX_USESSL')=='yes') {
// When NGINX_USESSL is 'yes' in 6.9, it could be using either Server_unraid_bundle.pem or certificate_bundle.pem
// When NGINX_USESSL is 'yes' in 6.10, it is is using Server_unraid_bundle.pem
$internalprotocol = 'https';
$internalport = _var($nginx,'NGINX_PORTSSL');
if ($is69 && _var($nginx,'NGINX_CERTNAME')) {
// this is from certificate_bundle.pem
$internalhostname = _var($nginx,'NGINX_CERTNAME');
}
}
if (_var($nginx,'NGINX_USESSL')=='auto') {
// NGINX_USESSL cannot be 'auto' in 6.9, it is either 'yes' or 'no'
// When NGINX_USESSL is 'auto' in 6.10, it is using certificate_bundle.pem
$internalprotocol = 'https';
$internalport = _var($nginx,'NGINX_PORTSSL');
// keyserver will expand *.hash.myunraid.net as needed
$internalhostname = _var($nginx,'NGINX_CERTNAME');
}
// My Servers version
$plgversion = file_exists("/var/log/plugins/dynamix.unraid.net.plg") ? trim(exec('/usr/local/sbin/plugin version /var/log/plugins/dynamix.unraid.net.plg 2>/dev/null'))
: (file_exists("/var/log/plugins/dynamix.unraid.net.staging.plg") ? trim(exec('/usr/local/sbin/plugin version /var/log/plugins/dynamix.unraid.net.staging.plg 2>/dev/null'))
: 'base-'._var($var,'version'));
// only proceed when when signed in or when legacy unraid.net SSL certificate exists
if (!$isRegistered && !$isLegacyCert) {
response_complete(406, ['error' => _('Nothing to do')]);
}
// keyfile
$keyfile = empty($var['regFILE']) ? false : @file_get_contents($var['regFILE']);
if ($keyfile === false) {
response_complete(406, ['error' => _('Registration key required')]);
}
$keyfile = @base64_encode($keyfile);
// build post array
$post = [
'keyfile' => $keyfile,
'plgversion' => $plgversion
];
if ($isLegacyCert) {
// sign in not required to maintain local ddns for unraid.net cert
// enable local ddns regardless of use_ssl value
$post['internalip'] = $internalip;
// if host.unraid.net does not resolve to the internalip and DNS Rebind Protection is disabled, disable caching
if (host_lookup_ip(generate_internal_host(_var($nginx,'NGINX_CERTNAME'), $post['internalip'])) != $post['internalip'] && rebindDisabled()) $dnserr = true;
}
if ($isRegistered) {
// if signed in, send data needed to maintain My Servers Dashboard
$post['internalhostname'] = $internalhostname;
$post['internalport'] = $internalport;
$post['internalprotocol'] = $internalprotocol;
$post['remoteaccess'] = $remoteaccess;
$post['servercomment'] = _var($var,'COMMENT');
$post['servername'] = _var($var,'NAME');
if ($isWildcardCert) {
// keyserver needs the internalip to generate the local access url
$post['internalip'] = $internalip;
}
if ($remoteaccess == 'yes') {
// include wanip in the cache file so we can track if it changes
$post['_wanip'] = trim(@file_get_contents("https://wanip4.unraid.net/"));
$post['externalhostname'] = $externalhostname;
$post['externalport'] = $externalport;
$post['externalprotocol'] = $externalprotocol;
// if wanip.hash.myunraid.net or www.hash.unraid.net does not resolve to the wanip, disable caching
if (host_lookup_ip(generate_external_host($post['externalhostname'], $post['_wanip'])) != $post['_wanip']) $dnserr = true;
}
}
// if remoteaccess is enabled in 6.10.0-rc3+ and WANIP has changed since nginx started, reload nginx
if (_var($post,'_wanip') != _var($nginx,'NGINX_WANIP') && version_compare(_var($var,'version'),"6.10.0-rc2",">")) $reloadNginx = true;
// if remoteaccess is currently disabled (perhaps because a wanip was not available when nginx was started)
// BUT the system is configured to have it enabled AND a wanip is now available
// then reload nginx
if ($remoteaccess == 'no' && _var($nginx,'NGINX_WANACCESS') == 'yes' && !empty(trim(@file_get_contents("https://wanip4.unraid.net/")))) $reloadNginx = true;
if ($reloadNginx) {
exec("/etc/rc.d/rc.nginx reload &>/dev/null");
}
// maxage is 36 hours
$maxage = 36*60*60;
if ($dnserr || $verbose) $maxage = 0;
$datafile = "/tmp/UpdateDNS.txt";
$datafiletmp = "/tmp/UpdateDNS.txt.new";
$dataprev = @file_get_contents($datafile) ?: '';
$datanew = implode("\n",$post)."\n";
if ($datanew == $dataprev && (time()-filemtime($datafile) < $maxage)) {
response_complete(204, null, _('No change to report'));
}
file_put_contents($datafiletmp,$datanew);
rename($datafiletmp, $datafile);
// do not submit the wanip, it will be captured from the submission if needed for remote access
unset($post['_wanip']);
// report necessary server details to limetech for DNS updates
$ch = curl_init('https://keys.lime-technology.com/account/server/register');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
curl_close($ch);
if ( ($result === false) || ($httpcode != "200") ) {
// delete cache file to retry submission on next run
@unlink($datafile);
response_complete($httpcode ?? "500", ['error' => $error]);
}
response_complete($httpcode, $result, _('success'));
header('Content-Type: application/json');
http_response_code(204);
exit(0);
?>

View File

@@ -1,125 +0,0 @@
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
global $lv;
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
require_once "$docroot/webGui/include/Helpers.php";
require_once "$docroot/webGui/include/SysDriversHelpers.php";
require_once "$docroot/plugins/dynamix.plugin.manager/include/PluginHelpers.php";
require_once "$docroot/plugins/dynamix.vm.manager/include/libvirt_helpers.php";
// add translations
$_SERVER['REQUEST_URI'] = 'tools';
require_once "$docroot/webGui/include/Translations.php";
require_once "$docroot/plugins/dynamix.docker.manager/include/DockerClient.php";
require_once "$docroot/plugins/dynamix.vm.manager/include/libvirt.php";
function macbyte($val) {
if ($val < 16)
return '0'.dechex($val);
return dechex($val);
}
$arrEntries = [];
$vms = $lv->get_domains() ?:[];
sort($vms,SORT_NATURAL);
foreach($vms as $vm){
$arrEntries['VM'][$vm]['interfaces'] = $lv->get_nic_info($vm);
$arrEntries['VM'][$vm]['name'] = $vm;
}
$DockerClient = new DockerClient();
$containers = $DockerClient->getDockerJSON("/containers/json?all=1");
foreach($containers as $ct)
$arrEntries['Docker'][substr($ct["Names"][0],1)] = [
'interfaces' => ['0 '=> ['mac' => isset($ct["NetworkSettings"]["Networks"]["bridge"]["MacAddress"]) ? $ct["NetworkSettings"]["Networks"]["bridge"]["MacAddress"] : ""]],
'name' => substr($ct["Names"][0],1),
];
$lxc = explode("\n",shell_exec("lxc-ls -1")) ;
$lxcpath = trim(shell_exec("lxc-config lxc.lxcpath"));
foreach ($lxc as $lxcname) {
if ($lxcname == "") continue;
$value = explode("=",shell_exec("cat $lxcpath/$lxcname/config | grep 'hwaddr'"));
$arrEntries['LXC'][$lxcname]['interfaces'][0]['mac'] = trim($value[1]);
$arrEntries['LXC'][$lxcname]['name'] = $lxcname;
}
if (is_file("/boot/config/wol.json")) $user_mac = json_decode(file_get_contents("/boot/config/wol.json"),true); else $user_mac = [];
foreach($arrEntries as $key => $data) {
$type=$key;
foreach($data as $data2){
$name=$data2['name'];
if (isset($user_mac[$type][$name])) {
$name=$name;
$arrEntries[$type][$name]['enable'] = $user_mac[$type][$name]['enable'];
$arrEntries[$type][$name]['user_mac'] = strtolower($user_mac[$type][$name]['user_mac']);
} else {
$arrEntries[$type][$name]['enable'] = 'enable';
$arrEntries[$type][$name]['user_mac'] = 'None Defined';
}
}
}
switch ($_POST['table']) {
case 't1load':
$arrMacs = $arrEntries;
$html = "<thead><tr><th>"._('Service')."</th><th>"._('Name')."</th><th>"._('Mac Address')."</th><th>"._('Enabled')."</th><th>"._('User Mac Address')."</th></tr></thead>";
$html .= "<tbody>";
ksort($arrMacs);
foreach($arrMacs as $systype => $m) {
foreach($m as $macaddr) {
if ($systype == "") continue;
$html .= "<tr id='row$systype'>";
$macs = "";
foreach($macaddr['interfaces'] as $intdetail)
{
$macs .= " {$intdetail['mac']}" ;
}
$html .= "<td>$systype</td>";
$selecttypename="enable;".$systype.";".$macaddr['name'];
$mactypename=htmlspecialchars("user_mac;".$systype.";".$macaddr['name']);
$mactypeid=htmlspecialchars("user_mac".$systype."".$macaddr['name']);
$user_mac_str = '<input type="text" name="'.$mactypename.'" id="'.$mactypeid.'" class="narrow" value="'.htmlspecialchars($macaddr['user_mac']).'" title="'._("random mac, you can supply your own").'" /><a><i onclick="maccreate(\''.$mactypeid.'\')" class="fa fa-refresh mac_generate" title="re-generate random mac address"></i></a>';
$html .= "<td>{$macaddr['name']}</td><td id=\"status$systype\">$macs</td><td>";
$html .="<select name='$selecttypename' class='audio narrow'>";
$html .= mk_option($macaddr["enable"] , "disable", _("Disabled"));
$html .= mk_option($macaddr["enable"] , "enable", _("Enabled"));
$html .= mk_option($macaddr["enable"] , "shutdown", _("Enabled and Shutdown"));
$html .= "</select></td><td>".$user_mac_str."</td></tr>";
$text = "";
}
}
if (count($arrMacs) < 1) {
$html .= "<tr id='row'>";
$html .= "<td></td><td></td><td>"._("No Entries")."</td><td></td><td></td></tr>";
}
$html .= "</tbody>";
$rtn = array();
$rtn['html'] = $html;
echo json_encode($rtn);
break;
case "macaddress":
$seed = 1;
$prefix = '62:00:00';
$prefix .=':'.macbyte(($seed * rand()) % 256).':'.macbyte(($seed * rand()) % 256).':'.macbyte(($seed * rand()) % 256);
echo json_encode(['mac' => $prefix]);
break;
}
?>

View File

@@ -1,180 +0,0 @@
#!/usr/bin/php
<?php
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
require_once "$docroot/webGui/include/Helpers.php";
require_once "$docroot/webGui/include/Custom.php";
require_once "$docroot/plugins/dynamix.vm.manager/include/libvirt_helpers.php";
require_once "$docroot/plugins/dynamix.vm.manager/include/libvirt.php";
require_once "$docroot/plugins/dynamix.plugin.manager/include/PluginHelpers.php";
require_once "$docroot/plugins/dynamix.docker.manager/include/DockerClient.php";
function getContainerStats($container, $option) {
exec("lxc-info " . $container, $content);
foreach($content as $index => $string) {
if (strpos($string, $option) !== FALSE)
return trim(explode(':', $string)[1]);
}
}
$mac = strtolower($argv[1]);
$libvirtd_running = is_file('/var/run/libvirt/libvirtd.pid') ;
$dockerd_running = is_file('/var/run/dockerd.pid');
$lxc_ls_exist = is_file('/usr/bin/lxc-ls');
#$RUNDOCKER = $RUNLXC = $RUNVM = true;
extract(parse_ini_file("/boot/config/wol.cfg")) ;
if (!isset($RUNLXC)) $RUNLXC = "y";
if (!isset($RUNVM)) $RUNVM = "y";
if (!isset($RUNDocker)) $RUNDocker = "y";
if (!isset($RUNSHUT)) $RUNSHUT = "n";
$arrEntries = [] ;
if ($libvirtd_running && $RUNVM == "y") {
$vms = $lv->get_domains();
sort($vms,SORT_NATURAL);
foreach($vms as $vm){
$arrEntries['VM'][$vm]['interfaces'] = $lv->get_nic_info($vm);
$arrEntries['VM'][$vm]['name'] = $vm;
}
}
if ($dockerd_running && $RUNDOCKER == "y") {
$DockerClient = new DockerClient();
$containers = $DockerClient->getDockerJSON("/containers/json?all=1");
foreach($containers as $container)
$arrEntries['Docker'][ substr($container["Names"][0],1) ] = [
'interfaces' => ['0' => ['mac' => isset($container["NetworkSettings"]["Networks"]["bridge"]["MacAddress"]) ? $container["NetworkSettings"]["Networks"]["bridge"]["MacAddress"]:""]],
'name' => substr($container["Names"][0],1),
'state' => $container["State"],
];
}
if ($lxc_ls_exist && $RUNLXC == "y") {
$lxc = explode("\n",shell_exec("lxc-ls -1")) ;
$lxcpath = trim(shell_exec("lxc-config lxc.lxcpath"));
foreach ($lxc as $lxcname) {
if ($lxcname == "") continue;
$values = explode("=",shell_exec("cat $lxcpath/$lxcname/config | grep 'hwaddr'"));
$arrEntries['LXC'][$lxcname]['interfaces'][0]['mac'] = trim($values[1]);
$arrEntries['LXC'][$lxcname]['name'] = $lxcname;
}
}
if (is_file("/boot/config/wol.json")) $user_mac = json_decode(file_get_contents("/boot/config/wol.json"),true); else $user_mac = [];
foreach($arrEntries as $typekey => $typedata)
{
foreach($typedata as $typeEntry){
$name=$typeEntry['name'];
if (isset($user_mac[$typekey][$name])) {
$name=$name;
$arrEntries[$typekey][$name]['enable'] = $user_mac[$typekey][$name]['enable'];
$arrEntries[$typekey][$name]['user_mac'] = strtolower($user_mac[$typekey][$name]['user_mac']);
} else {
$arrEntries[$typekey][$name]['enable'] = "enable";
$arrEntries[$typekey][$name]['user_mac'] = 'None Defined';
}
}
}
$mac_list=[];
foreach($arrEntries as $type => $detail)
{
foreach($detail as $name => $entryDetail)
{
foreach($entryDetail['interfaces'] as $interfaces)
{
$interfaces['mac'] = strtolower($interfaces['mac']);
if($interfaces['mac'] == "" && $entryDetail['user_mac'] == "None Defined") continue;
if (isset($entryDetail['state'])) $state = $entryDetail['state']; else $state = "";
if (isset($entryDetail['enable']) && !$entryDetail['enable'] ) $enable = false; else $enable = true;
if ($entryDetail['user_mac'] != "None Defined") {
$mac_list[$entryDetail['user_mac']] = [
'type' => $type,
'name' => $name,
'state' => $state,
'enable' => $entryDetail['enable'],
];
}
if ($interfaces['mac'] != "") {
$mac_list[$interfaces['mac']] = [
'type' => $type,
'name' => $name,
'state' => $state,
'enable' => $entryDetail['enable'],
];
}
}
}
}
$found = array_key_exists($mac,$mac_list);
if ($found && $mac_list[$mac]['enable'] != "disable") {
echo _("Found"). " " . $mac . " " .$mac_list[$mac]['type'] . " " . $mac_list[$mac]['name'];
switch ($mac_list[$mac]['type']) {
case "VM":
if ($libvirtd_running && $RUNVM == "y") {
$res = $lv->get_domain_by_name($mac_list[$mac]['name']);
$dom = $lv->domain_get_info($res);
$state = $lv->domain_state_translate($dom['state']);
switch ($state) {
case 'running':
if ($RUNSHUT == "y" && $mac_list[$mac]['enable'] == "shutdown") $lv->domain_shutdown("{$mac_list[$mac]['name']}");
break;
case 'paused':
case 'pmsuspended':
$lv->domain_resume("{$mac_list[$mac]['name']}");
break;
default:
$lv->domain_start("{$mac_list[$mac]['name']}");
}
}
break;
case "LXC":
if ($lxc_ls_exist && $RUNLXC == "y") {
$state = getContainerStats($mac_list[$mac]['name'], "State");
switch ($state) {
case 'RUNNING':
if ($RUNSHUT == "y" && $mac_list[$mac]['enable'] == "shutdown") shell_exec("lxc-stop {$mac_list[$mac]['name']}");
break;
case 'FROZEN':
shell_exec("lxc-unfreeze {$mac_list[$mac]['name']}");
break;
default:
shell_exec("lxc-start {$mac_list[$mac]['name']}");
}
}
break;
case "Docker":
if ($dockerd_running && $RUNDOCKER == "y") {
switch ($mac_list[$mac]['state']) {
case "running":
if ($RUNSHUT == "y" && $mac_list[$mac]['enable'] == "shutdown") shell_exec("docker stop {$mac_list[$mac]['name']}");
break;
case "exited":
case "created":
shell_exec("docker start {$mac_list[$mac]['name']}");
break;
case "paused":
shell_exec("docker unpause {$mac_list[$mac]['name']}");
}
}
break;
}
} else {
if ($mac_list[$mac]['enable'] == "disable") echo $mac . " " . _(" has not been actioned as set to disabled");
else echo _("Not Found"). " " . $mac . " " . _("ignoring or Maybe actions disabled for type(Docker/VM/LXC)");
}
?>

View File

@@ -149,4 +149,56 @@ function my_date($fmt, $time) {
function my_logger($message, $logger='webgui') {
exec('logger -t '.escapeshellarg($logger).' -- '.escapeshellarg($message));
}
// Original PHP code by Chirp Internet: www.chirpinternet.eu
// Please acknowledge use of this code by including this header.
// https://www.the-art-of-web.com/php/http-get-contents/
// Modified for Unraid
/**
* Fetches URL and returns content
* @param string $url The URL to fetch
* @param array $opts Array of options to pass to curl_setopt()
* @param array $getinfo Empty array passed by reference, will contain results of curl_getinfo and curl_error
* @return string|false $out The fetched content
*/
function http_get_contents(string $url, array $opts = [], array &$getinfo = NULL) {
$ch = curl_init();
if(isset($getinfo)) {
curl_setopt($ch, CURLINFO_HEADER_OUT, TRUE);
}
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_FRESH_CONNECT, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 15);
curl_setopt($ch, CURLOPT_TIMEOUT, 45);
curl_setopt($ch, CURLOPT_ENCODING, "");
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_REFERER, "");
curl_setopt($ch, CURLOPT_FAILONERROR, true);
if(is_array($opts) && $opts) {
foreach($opts as $key => $val) {
curl_setopt($ch, $key, $val);
}
}
$out = curl_exec($ch);
if(isset($getinfo)) {
$getinfo = curl_getinfo($ch);
}
if (curl_errno($ch)) {
$msg = curl_error($ch) . " {$url}";
if(isset($getinfo)) {
$getinfo['error'] = $msg;
}
my_logger($msg, "http_get_contents");
}
return $out;
}
/**
* Detect network connectivity via Network Connectivity Status Indicator
* @return bool
*/
function check_network_connectivity(): bool {
$url = 'http://www.msftncsi.com/ncsi.txt';
$out = http_get_contents($url);
return ($out=="Microsoft NCSI");
}
?>

View File

@@ -39,4 +39,8 @@ if ($_SERVER['SCRIPT_NAME'] != '/login.php' && $_SERVER['SCRIPT_NAME'] != '/auth
if ($var['csrf_token'] != $_POST['csrf_token']) csrf_terminate("wrong");
unset($_POST['csrf_token']);
}
$proxy_cfg = (array)@parse_ini_file('/var/local/emhttp/proxy.ini',true);
putenv('http_proxy='.((array_key_exists('http_proxy', $proxy_cfg)) ? $proxy_cfg['http_proxy'] : ''));
putenv('https_proxy='.((array_key_exists('https_proxy', $proxy_cfg)) ? $proxy_cfg['https_proxy'] : ''));
putenv('no_proxy='.((array_key_exists('http_proxy', $proxy_cfg)) ? $proxy_cfg['no_proxy'] : ''));
?>

View File

@@ -13,6 +13,7 @@
<?
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
require_once "$docroot/webGui/include/Helpers.php";
require_once "$docroot/webGui/include/Wrappers.php";
// add translations
$_SERVER['REQUEST_URI'] = 'settings';
@@ -425,11 +426,10 @@ case 'public':
$ip = _var($_POST,'#ip');
$v4 = _var($_POST,'#prot')!='6';
$v6 = _var($_POST,'#prot')!='';
$context = stream_context_create(['https'=>['timeout'=>12]]);
$int_ipv4 = $v4 ? (preg_match("/^$validIP4$/",$ip) ? $ip : (@dns_get_record($ip,DNS_A)[0]['ip'] ?: '')) : '';
$ext_ipv4 = $v4 ? (@file_get_contents('https://wanip4.unraid.net',false,$context) ?: '') : '';
$ext_ipv4 = $v4 ? (http_get_contents('https://wanip4.unraid.net') ?: '') : '';
$int_ipv6 = $v6 ? (preg_match("/^$validIP6$/",$ip) ? $ip : (@dns_get_record($ip,DNS_AAAA)[0]['ipv6'] ?: '')) : '';
$ext_ipv6 = $v6 ? (@file_get_contents('https://wanip6.unraid.net',false,$context) ?: '') : '';
$ext_ipv6 = $v6 ? (http_get_contents('https://wanip6.unraid.net') ?: '') : '';
echo "$int_ipv4;$ext_ipv4;$int_ipv6;$ext_ipv6";
break;
case 'addtunnel':

View File

@@ -78,7 +78,7 @@ function device_info(&$disk,$online) {
$help .= "<br>"._("Click to spin $action device");
}
$status = "<a class='info'><i ".($ctrl?"id='dev-$named' ":"")."class='fa fa-$orb orb $color-orb'$ctrl></i><span>$help</span></a>";
$link = (($parity || $data || $pool) && !str_contains($disk_status,'_NP')) || $name=='flash' || in_array($name,$pools) || $type=='New'
$link = (($parity || $data || $pool) && $disk_status!='DISK_NP') || $name=='flash' || in_array($name,$pools) || $type=='New'
? "<a href=\"".htmlspecialchars("/Main/Settings/$source?name=$name")."\">$fancy</a>"
: $fancy;
return $view.$status.$link;

View File

@@ -20,10 +20,12 @@ require_once "$docroot/webGui/include/publish.php";
while (true) {
$echo = shell_exec("$notify get");
$md5_new = md5($echo,true);
if ($md5_new !== $md5_old) {
publish('notify', $echo);
$md5_old = $md5_new;
if ( $echo ) {
$md5_new = md5($echo,true);
if ($md5_new !== $md5_old) {
publish('notify', $echo);
$md5_old = $md5_new;
}
}
sleep(3);
}

View File

@@ -20,6 +20,10 @@ require_once "$docroot/webGui/include/Helpers.php";
require_once "$docroot/webGui/include/publish.php";
require_once "$docroot/plugins/dynamix.vm.manager/include/libvirt_helpers.php";
global $vmusagestats;
exec("/etc/rc.d/rc.libvirt status >/dev/null",$dummy,$libvirtd);
$libvirtd = $libvirtd==0;
if (!$libvirtd) return;
extract(parse_plugin_cfg('dynamix',true));
get_vm_usage_stats();
sleep(1);

View File

@@ -1,93 +0,0 @@
#!/bin/bash
#
# script: WOL_action
#
# Startup script for unraidwold
#
# Simon Fairweather - Initial Script October 2023
DAEMON="unraidwold"
BINARY="/usr/local/bin/unraidwold"
# run & log functions
. /etc/rc.d/rc.runlog
. /boot/config/wol.cfg
unraidwold_running(){
sleep 0.1
ps axc | grep -q ' unraidwold'
}
unraidwold_start(){
log "Starting $DAEMON..."
local REPLY
if unraidwold_running; then
REPLY="Already started"
else
nohup $BINARY $1 $2 $3 $4 $5 $6 > /dev/null &
fi
log "$DAEMON... $REPLY."
}
unraidwold_stop(){
log "Stopping $DAEMON..."
local REPLY
if ! unraidwold_running; then
REPLY="Already stopped"
else
killall -TERM $DAEMON
if ! unraidwold_running; then REPLY="Stopped"; else REPLY="Failed"; fi
fi
log "$DAEMON... $REPLY."
}
unraidwold_status(){
if unraidwold_running; then
echo "$DAEMON is currently running."
else
echo "$DAEMON is not running."
exit 1
fi
}
unraidwold_load()
{
if unraidwold_running; then
unraidwold_stop
fi
sleep 1
if [ "$WOLENABLED" == "yes" ]; then
interfacemode=""
logoptions=""
if [ "$IFMODE" == "y" ]; then
interfacemode="--promiscuous"
fi
if [ "$LOGFILE" != "syslog" ]; then
logoptions="--log $LOGFILE"
fi
unraidwold_start --interface $INTERFACE $interfacemode $logoptions
fi
}
case "$1" in
'start')
unraidwold_start $2 $3 $4 $5 $6
;;
'stop')
unraidwold_stop
;;
'status')
unraidwold_status
;;
'load')
unraidwold_load
;;
*)
echo "Usage: $BDAEMON start|stop|restart|status"
exit 1
esac
exit 0

View File

@@ -25,6 +25,7 @@ $zip = $all ? ($argv[2]??'') : ($argv[1]??'');
$cli = empty($zip);
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
require_once "$docroot/webGui/include/Helpers.php";
require_once "$docroot/webGui/include/Wrappers.php";
$folders = ['/boot','/boot/config','/boot/config/plugins','/boot/syslinux','/var/log','/var/log/plugins','/boot/extra','/var/log/packages','/var/lib/pkgtools/packages','/tmp'];
@@ -115,16 +116,6 @@ function maskIP($file) {
// anonymize full IPv6 addresses
run("sed -ri 's/([\"\[ ]([0-9a-f]{1,4}:){4})(([0-9a-f]{1,4}:){3}|:)([0-9a-f]{1,4})([/\" .]|$)/\\1XXXX:XXXX:XXXX:\\5\\6/g' ".escapeshellarg($file)." 2>/dev/null");
}
function cache_only($disk) {
return _var($disk,'type')=='Cache';
}
function cache_filter($disks) {
return array_filter($disks,'cache_only');
}
function pools_filter($disks) {
return array_unique(array_map('prefix',array_keys(cache_filter($disks))));
}
function download_url($url, $path="", $bg=false, $timeout=15) {
$ch = curl_init();
curl_setopt_array($ch,[
@@ -661,6 +652,13 @@ if (file_exists($dhcplog)) {
if (!$all) maskIP($log);
}
// copy phplog
$phplog = "/var/log/phplog";
if (file_exists($phplog)) {
$log = "/$diag/logs/phplog.txt";
run("todos <$phplog >".escapeshellarg($log));
}
// copy graphql-api.log
$graphql = "/var/log/graphql-api.log";
if (file_exists($graphql)) {

View File

@@ -0,0 +1,111 @@
#!/usr/bin/php
<?php
/* Copyright 2024, Lime Technology
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
$opmPlugin = "dynamix";
require_once("plugins/".$opmPlugin."/include/OutgoingProxyLib.php");
/* Save settings and update config. */
function apply() {
global $opmPlugin, $plg_config_file;
/* Process the new configuration. */
$cfg = parse_plugin_config();
/* Generate encryption keys if they have not been generated. */
if ((! isset($cfg['key'])) || (! isset($cfg['iv']))) {
/* Doing an encryption will generate keys. */
encrypt_data("test");
/* Get new keys. */
$cfg['key'] = get_config("key");
$cfg['iv'] = get_config("iv");
}
for ($i = 1; $i <= 3; $i++) {
$proxy_name = "proxy_name_".$i;
$name = trim($cfg[$proxy_name]);
$proxy_url = "proxy_url_".$i;
$url = trim($cfg[$proxy_url]);
$proxy_user = "proxy_user_".$i;
$proxy_pass = "proxy_pass_".$i;
if (($name) && ($url)) {
/* Confirm the url is in the proper format. */
if (strpos($url, 'http://') !== false && preg_match('/:\d+$/', $url)) {
/* The string contains 'http://' and a port designation at the end */
/* Parse the URL components. */
$urlComponents = parse_url($url);
/* Replace user and password in the url. */
$host = $urlComponents['host'] ?? "";
$port = $urlComponents['port'] ?? "";
$user = $urlComponents['user'] ?? "";
$pass = $urlComponents['pass'] ?? "";
/* Remove credentials from the entered URL. */
$cfg[$proxy_url] = "http://".$host.':'.$port;
/* Use the entered user if not blank. */
$cfg_user = $cfg[$proxy_user] ?? "";
$cfg[$proxy_user] = $cfg_user ? $cfg_user : urldecode($user);
$encodedUser = (strpos($cfg[$proxy_user], '%') === false) ? urlencode($cfg[$proxy_user]) : $cfg[$proxy_user];
/* Use the entered pass if not blank. */
$cfg_pass = $cfg[$proxy_pass] ?? "";
$cfg[$proxy_pass] = $cfg_pass ? $cfg_pass : urldecode($pass);
$encodedPass = (strpos($cfg[$proxy_pass], '%') === false) ? urlencode($cfg[$proxy_pass]) : $cfg[$proxy_pass];
$cfg[$proxy_pass] = encrypt_data($cfg[$proxy_pass]);
} else {
/* The string does not contain 'http://' and/or a port designation at the end */
$cfg[$proxy_url] = "";
}
} else if (! $name) {
$cfg[$proxy_url] = "";
}
}
/* Rewrite config file. */
/* Convert the array to an INI string. */
$iniString = '';
foreach ($cfg as $key => $value) {
$iniString .= "$key=\"$value\"\n";
}
/* Write the INI string to the plugin config file. */
file_put_contents($plg_config_file, $iniString);
/* Let things settle. */
sleep(1);
/* Now run the proxy setup script. */
if (is_executable("/usr/local/sbin/set_proxy")) {
exec("/usr/local/sbin/set_proxy 1>/dev/null");
outgoingproxy_log("'set_proxy' script executed");
} else {
outgoingproxy_log("'set_proxy' script does not exist");
}
}
/* Main entry point, */
switch ($argv[1]) {
case 'apply':
apply();
break;
default:
echo("Error: 'outgoingproxy {$argv[1]}' not understood\n");
echo("outgoingproxy usage: 'apply'\n");
exit(0);
break;
}
?>

View File

@@ -35,7 +35,7 @@ if [[ -n $local_server ]]; then
sed -ri "\$a\\\$InputUDPServerBindRuleset remote\n\\\$UDPServerRun ${server_port:-514}" $ETC
[[ $server_protocol == udp ]] && sed -ri 's/^(\$ModLoad imtcp)/#\1/;/^\$InputTCPServerBindRuleset remote$/d;/^\$InputTCPServerRun [0-9]+$/d' $ETC
fi
sed -ri "/^\\\$template remote,.*$/d;/^#\\\$UDPServerRun [0-9]+.*$/a\\\$template remote,\"${server_folder:-/mnt/user/system}/syslog-%FROMHOST-IP%.log\"" $ETC
sed -ri "/^\\\$template remote,.*$/d;/^#\\\$UDPServerRun [0-9]+.*$/a\\\$template remote,\"${server_folder:-/mnt/user/system}/${server_filename:-syslog-%FROMHOST-IP%.log}\"" $ETC
else
sed -ri '/^\$RuleSet remote$/d;/^\$FileOwner nobody$/d;/^\$FileGroup users$/d;/^\$FileCreateMode 06[46][46]$/d;/^\$IncludeConfig \/etc\/rsyslog\.d\/\*\.conf # remote$/d;/^\*\.\* \?remote$/d;/^\$template remote,".*"$/d;/^\$Input(TCP|UDP)ServerBindRuleset remote$/d;/^\$(InputTCP|UDP)ServerRun [0-9]+$/d;s/^#?\$(ModLoad imtcp|ModLoad imudp)/#\$\1/' $ETC
fi

View File

@@ -1,7 +1,7 @@
#!/usr/bin/php -q
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
/* Copyright 2005-2024, Lime Technology
* Copyright 2012-2024, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
@@ -21,6 +21,7 @@ $disks = (array)@parse_ini_file("/var/local/emhttp/disks.ini",true);
require_once "$docroot/webGui/include/CustomMerge.php";
$script = "$docroot/webGui/scripts/notify";
// this command will set the $notify array
extract(parse_plugin_cfg("dynamix",true));
$output = _var($notify,'report');
$server = strtoupper(_var($var,'NAME','tower'));
@@ -178,7 +179,8 @@ $warn = ($error0 || $error3) ? "alert" : (($error1 || $error2) ? "warning" : "no
$stat = $warn=="normal" ? "[PASS]" : "[FAIL]";
$info = "Array has $size disk".($size==1 ? "" : "s").($parity ? " ({$word}parity".($pools ? " & pools)" : ")") : ($pools ? " ({$word}pools)" : ""));
$message = implode('\n', $data);
exec("$script -s ".escapeshellarg("Notice [$server] - array health report $stat")." -d ".escapeshellarg("$info")." -m ".escapeshellarg("$message")." -i ".escapeshellarg("$warn $output")." -l '/Main'");
$subject = "Notice [$server] - array health report $stat";
exec("$script -s ".escapeshellarg($subject)." -d ".escapeshellarg("$info")." -m ".escapeshellarg("$message")." -i ".escapeshellarg("$warn $output")." -l '/Main'");
exit(0);
?>

View File

@@ -1,11 +0,0 @@
table#t1{margin-top:0;font-family:clear-sans}
table#t1 thead tr th{font-weight:bold}
table#t1 tbody tr td{padding:4px 20px 4px 0;margin:0;text-align:left;white-space:normal}
table#t1 tbody tr td:nth-child(1){width:10%}
table#t1 tbody tr td:nth-child(2){width:30%}
table#t1 tbody tr td:nth-child(3){width:15%}
table#t1 tbody tr td:nth-child(4){width:20%}
table#t1 tbody tr td:nth-child(5){width:25%;padding-right:0}
table.t1.tablesorter .filtered{display:none}
.tablesorter-header-inner{font-family:clear-sans;font-weight:bold}
#macform .mac_generate{cursor:pointer;margin-left:-5px;color:#08C;font-size:1.3rem;transform:translate(0px, 2px)}

View File

@@ -122,7 +122,9 @@ table.unraid thead tr:first-child>td{font-size:1.2rem;text-transform:uppercase;l
table.unraid tbody tr:not(.tr_last):hover>td{background-color:rgba(0,0,0,0.05)}
table.unraid tr>td{overflow:hidden;text-overflow:ellipsis;padding-left:8px}
table.unraid tr>td:hover{overflow:visible}
table.legacy{table-layout:auto}
table.legacy{table-layout:auto!important}
table.legacy thead td{line-height:normal;height:auto;padding:7px 0}
table.legacy tbody td{line-height:normal;height:auto;padding:5px 0}
table.disk_status{table-layout:fixed}
table.disk_status tr>td:last-child{padding-right:8px}
table.disk_status tr>td:nth-child(1){width:13%}

View File

@@ -120,7 +120,9 @@ table.unraid tbody tr:nth-child(even){background-color:#212121}
table.unraid tbody tr:not(.tr_last):hover>td{background-color:rgba(255,255,255,0.1)}
table.unraid tr>td{overflow:hidden;text-overflow:ellipsis;padding-left:8px}
table.unraid tr>td:hover{overflow:visible}
table.legacy{table-layout:auto}
table.legacy{table-layout:auto!important}
table.legacy thead td{line-height:normal;height:auto;padding:7px 0}
table.legacy tbody td{line-height:normal;height:auto;padding:5px 0}
table.disk_status{table-layout:fixed}
table.disk_status tr>td:last-child{padding-right:8px}
table.disk_status tr>td:nth-child(1){width:13%}

View File

@@ -122,7 +122,9 @@ table.unraid thead tr:first-child>td{font-size:1.2rem;text-transform:uppercase;l
table.unraid tbody tr:not(.tr_last):hover>td{background-color:rgba(255,255,255,0.05)}
table.unraid tr>td{overflow:hidden;text-overflow:ellipsis;padding-left:8px}
table.unraid tr>td:hover{overflow:visible}
table.legacy{table-layout:auto}
table.legacy{table-layout:auto!important}
table.legacy thead td{line-height:normal;height:auto;padding:7px 0}
table.legacy tbody td{line-height:normal;height:auto;padding:5px 0}
table.disk_status{table-layout:fixed}
table.disk_status tr>td:last-child{padding-right:8px}
table.disk_status tr>td:nth-child(1){width:13%}

View File

@@ -120,7 +120,9 @@ table.unraid tbody tr:nth-child(even){background-color:#ededed}
table.unraid tbody tr:not(.tr_last):hover>td{background-color:rgba(0,0,0,0.1)}
table.unraid tr>td{overflow:hidden;text-overflow:ellipsis;padding-left:8px}
table.unraid tr>td:hover{overflow:visible}
table.legacy{table-layout:auto}
table.legacy{table-layout:auto!important}
table.legacy thead td{line-height:normal;height:auto;padding:7px 0}
table.legacy tbody td{line-height:normal;height:auto;padding:5px 0}
table.disk_status{table-layout:fixed}
table.disk_status tr>td:last-child{padding-right:8px}
table.disk_status tr>td:nth-child(1){width:13%}

View File

@@ -1,4 +1,4 @@
.jGrowl{position:fixed;font-size:1.3rem}
.jGrowl{position:fixed;font-size:1.3rem;z-index:10001}
.jGrowl.top-left{left:10px;top:90px}
.jGrowl.top-right{right:10px;top:90px}
.jGrowl.bottom-left{left:10px;bottom:24px}

View File

@@ -1,4 +1,4 @@
.jGrowl{position:fixed;font-size:1.3rem}
.jGrowl{position:fixed;font-size:1.3rem;z-index:10001}
.jGrowl.top-left{left:10px;top:130px}
.jGrowl.top-right{right:10px;top:130px}
.jGrowl.bottom-left{left:10px;bottom:24px}

View File

@@ -1,4 +1,4 @@
.jGrowl{position:fixed;font-size:1.3rem}
.jGrowl{position:fixed;font-size:1.3rem;z-index:10001}
.jGrowl.top-left{left:10px;top:90px}
.jGrowl.top-right{right:10px;top:90px}
.jGrowl.bottom-left{left:10px;bottom:24px}

View File

@@ -1,4 +1,4 @@
.jGrowl{position:fixed;font-size:1.3rem}
.jGrowl{position:fixed;font-size:1.3rem;z-index:10001}
.jGrowl.top-left{left:10px;top:130px}
.jGrowl.top-right{right:10px;top:130px}
.jGrowl.bottom-left{left:10px;bottom:24px}

View File

@@ -43,13 +43,16 @@ flush();
$docroot = $_SERVER['DOCUMENT_ROOT'];
if (isset($_POST['#file'])) {
$file = $_POST['#file'];
$raw_file = isset($_POST['#raw_file']) ? ($_POST['#raw_file'] === 'true') : false;
// prepend with boot (flash) if path is relative
if ($file && $file[0]!='/') $file = "/boot/config/plugins/$file";
$section = $_POST['#section'] ?? false;
$cleanup = isset($_POST['#cleanup']);
$default = ($file && isset($_POST['#default'])) ? @parse_ini_file("$docroot/plugins/".basename(dirname($file))."/default.cfg", $section) : [];
$keys = is_file($file) ? (parse_ini_file($file, $section) ?: []) : [];
// if the file is not a raw file, it can be parsed
$keys = (is_file($file) && !$raw_file) ? (parse_ini_file($file, $section) ?: []) : [];
// the 'save' switch can be reset by the include file to disallow settings saving
$save = true;
if (isset($_POST['#include'])) {

View File

@@ -50,7 +50,7 @@ fi
# initrd has already done so):
if [[ -d /run ]]; then
if ! /bin/grep -wq "tmpfs /run tmpfs" /proc/mounts; then
/sbin/mount -v -n -t tmpfs tmpfs /run -o mode=0755,size=32M,nodev,nosuid,noexec
/sbin/mount -v -n -t tmpfs tmpfs /run -o mode=0755,size=128M,nodev,nosuid,noexec
fi
fi

View File

@@ -68,7 +68,7 @@ if /bin/grep -wq cgroup /proc/filesystems; then
if [[ -d /sys/fs/cgroup ]]; then
# See https://docs.kernel.org/admin-guide/cgroup-v2.html (section Mounting)
# Mount cgroup2 filesystem
mount -t cgroup2 -o rw,nosuid,nodev,noexec,relatime,nsdelegate,memory_recursiveprot cgroup2 /sys/fs/cgroup
/sbin/mount -t cgroup2 -o rw,nosuid,nodev,noexec,relatime,nsdelegate,memory_recursiveprot cgroup2 /sys/fs/cgroup
else
# Display message if /sys/fs/cgroup does not exist
echo "/sys/fs/cgroup does not exist. cgroup2 cannot be mounted."

View File

@@ -42,7 +42,8 @@ SYSTEM="/sys/devices/system/cpu"
# provides power savings on Intel processors while avoiding the ramp-up lag
# present when using the powersave governor (which is the default if ondemand
# is requested on these machines):
if [[ $(cat $SYSTEM/cpu0/cpufreq/scaling_driver 2>/dev/null) == intel_pstate ]]; then
if [[ $(cat $SYSTEM/cpu0/cpufreq/scaling_driver 2>/dev/null) == intel_pstate ||
$(cat $SYSTEM/cpu0/cpufreq/scaling_driver 2>/dev/null) == amd-pstate-epp ]]; then
SCALING_GOVERNOR="performance"
fi

View File

@@ -501,7 +501,7 @@ docker_container_start(){
log "$CONTAINER: $OUT" &
else
run container_add_route $CONTAINER
log "$CONTAINER: started succesfully!" &
log "$CONTAINER: started successfully!" &
if [[ $WAIT -gt 0 ]]; then
log "$CONTAINER: wait $WAIT seconds" &
sleep $WAIT
@@ -566,7 +566,7 @@ docker_service_stop(){
run ip link del docker0
fi
REPLY="Stopped"
# signal succesful stop
# signal successful stop
TIMER=-1
else
# show waiting message

View File

@@ -69,7 +69,10 @@
# Adapted by Bergware for use in Unraid OS - December 2023
# - remove leading zeros in IPv4 and IPv6 addresses
# Bergware - modified for Unraid OS, December 2023
# Adapted by Bergware for use in Unraid OS - February 2024
# - revised bond interface creation for linux kernel 6.6.14 and later point releases
# Bergware - modified for Unraid OS, February 2024
###########
# LOGGING #
@@ -175,8 +178,8 @@ bond_up(){
for BONDIF in ${BONDNICS[$i]}; do
if [[ -e $SYSTEM/$BONDIF ]]; then
[[ -z $PRIMARY ]] && PRIMARY=$BONDIF
run ip link set $BONDIF down
run ip link set $BONDIF master ${BONDNAME[$i]} up type bond_slave
run ip link set $BONDIF up
run ip link set $BONDIF master ${BONDNAME[$i]} down type bond_slave
else
[[ $DEBUG_ETH_UP == yes ]] && log "interface $BONDIF not present, can't add to ${BONDNAME[$i]}"
fi

View File

@@ -237,6 +237,7 @@ libvirtd_start(){
check_processor
modprobe -a $MODULE $MODULES
echo 0 > /sys/module/kvm/parameters/report_ignored_msrs
libvirtd -d -l $LIBVIRTD_OPTS
log "$DAEMON... Started."
}

View File

@@ -14,6 +14,28 @@
# run & log functions
. /etc/rc.d/rc.runlog
# import CA proxy
UnProxy=/boot/config/plugins/dynamix/outgoingproxy.cfg
CAProxy=/boot/config/plugins/community.applications/proxy.cfg
if [[ -f "${CAProxy}" && ! -f "${UnProxy}" ]]; then
proxy=
port=
. "${CAProxy}"
# proxy and port were set by the previous command
if [[ -n "${proxy}" && -n "${port}" ]]; then
cat << EOF > "${UnProxy}"
proxy_active="1"
proxy_url_1="${proxy}:${port}"
proxy_name_1="Imported from CA"
EOF
fi
mv "${CAProxy}" "${CAProxy}.bak"
fi
# load proxy environment vars so it is used for plugin updates and the go script
/usr/local/sbin/set_proxy
[[ -x /etc/profile.d/proxy.sh ]] && . /etc/profile.d/proxy.sh
# irqbalance daemon distributes interrupts over processors and cores
# if [[ -x /usr/sbin/irqbalance ]]; then
# /usr/sbin/irqbalance
@@ -69,7 +91,7 @@ rm -f /boot/plugins/unRAIDServer.plg
rm -f $CONFIG/plugins/unRAIDServer.plg
# These plugins are now integrated in the OS or obsolete and may interfere
OBSOLETE="vfio.pci dynamix.wireguard dynamix.ssd.trim dynamix.file.manager gui.search unlimited-width"
OBSOLETE="vfio.pci dynamix.wireguard dynamix.ssd.trim dynamix.file.manager gui.search unlimited-width proxy.editor"
for PLUGIN in $OBSOLETE; do
if [[ -e $CONFIG/plugins/$PLUGIN.plg ]]; then
log "moving obsolete plugin $PLUGIN.plg to $CONFIG/plugins-error"
@@ -166,6 +188,21 @@ if [[ $PERSISTENT_BASH_HISTORY == 1 ]]; then
ln -s /boot/config/history/bash_history /root/.bash_history
fi
# cleanup the 'go' script
# delete non-commented line with emhttp and trailing & (could also have leading env vars)
# add new line with call to emhttp (preserve any params to emhttp and CRLF line endings)
GOTEST1='^[^#]*/usr/local/sbin/emhttp(.*)&(.*)$'
if grep -q -E "$GOTEST1" $CONFIG/go; then
cp $CONFIG/go $CONFIG/go~
sed -i -E "s@$GOTEST1@/usr/local/sbin/emhttp\1\2@g" $CONFIG/go
fi
# delete lines added by ProxyEditor
GOTEST2='# Added by ProxyEditor'
if grep -q "$GOTEST2" $CONFIG/go; then
[[ ! -f $CONFIG/go~ ]] && cp $CONFIG/go $CONFIG/go~
sed -i "/$GOTEST2/d" $CONFIG/go
fi
# Invoke the 'go' script
if [[ -f $CONFIG/go ]]; then
log "Starting go script"

View File

@@ -686,8 +686,6 @@ nginx_reload(){
if nginx_check; then
log "Reloading $DAEMON configuration..."
kill -HUP $(cat $PID)
# update DNS
php -f /usr/local/emhttp/webGui/include/UpdateDNS.php
sleep 3
else
log "Invalid configuration, $DAEMON not reloaded"
@@ -705,8 +703,6 @@ nginx_renew(){
build_ssl
# start unconditionally
$NGINX -c $CONF 2>/dev/null
# update DNS
php -f /usr/local/emhttp/webGui/include/UpdateDNS.php
}
nginx_update(){

View File

@@ -227,7 +227,7 @@ mv $INI ${INI%.*}
log "interface=${interface:-$1}, reason=$reason, protocol=$protocol"
# delayed execution
/usr/local/emhttp/webGui/scripts/update_services 30
/usr/local/emhttp/webGui/scripts/update_services 45
# send update information
if [[ -n $DATA && -e /var/run/nginx.socket ]]; then

View File

@@ -3,7 +3,7 @@ DISABLE="no"
source /boot/config/domain.cfg
if [ $DISABLE == "yes" ]
then
printf '%s\n' "Start/autostart is disabled in VM settings." >&2 ## Send message to stderr.
printf '\n%s\n' "Start/autostart is disabled in VM settings." >&2 ## Send message to stderr.
exit 1 ;
fi
eval exec /usr/bin/qemu-system-x86_64 $(/usr/local/emhttp/plugins/dynamix.vm.manager/scripts/qemu.php "$@")

156
sbin/set_proxy Executable file
View File

@@ -0,0 +1,156 @@
#!/usr/bin/php
<?php
/**
* script: set_proxy
*
* Copyright 2005-2024, Lime Technology
*
* Call this script (/usr/local/sbin/set_proxy.php) to set up proxy files.
*/
$opmPlugin = "dynamix";
require_once("plugins/".$opmPlugin."/include/OutgoingProxyLib.php");
/* Files generated by this script based on the data in proxy.cfg. */
$proxy_sh = '/etc/profile.d/proxy.sh';
$proxy_ini = '/usr/local/emhttp/state/proxy.ini';
/* Random file extension for atomic writes. */
$rnd = rand();
/* Comments to beginning of the proxy_sh file. */
$comments = "#!/bin/bash\n"."# Do not edit. This file is autogenerated by /usr/local/sbin/set_proxy.\n";
/* Set verbose if command line switch is set. */
$verbose = false;
if (isset($argv[1]) && ($argv[1] == '-v')) {
$verbose = true;
}
/* Initialize global variables. */
$proxy_active = "";
$proxy_url = "";
$no_proxy = "";
/* Write comments and content to a file. */
function write_file($file, $content, $show_comments = false) {
global $rnd, $comments;
$tmpFile = "{$file}.{$rnd}";
file_put_contents($tmpFile, ($show_comments ? $comments : "").$content);
chmod($tmpFile, 0755);
rename($tmpFile, $file);
}
/* Write environment variables to /etc/profile.d/proxy.sh. */
function set_proxy_sh() {
global $proxy_sh, $proxy_url, $no_proxy;
$content = "export http_proxy=".$proxy_url."\n";
$content .= "export https_proxy=".$proxy_url."\n";
$content .= "export no_proxy=".$no_proxy."\n";
write_file($proxy_sh, $content, true);
}
/* Clear environment variables from /etc/profile.d/proxy.sh. */
function unset_proxy_sh() {
global $proxy_sh;
$content = "unset http_proxy\n";
$content .= "unset https_proxy\n";
$content .= "unset no_proxy\n";
write_file($proxy_sh, $content, true);
}
/* Write proxy information to /usr/local/emhttp/state/proxy.ini. */
function set_proxy_ini() {
global $proxy_ini, $proxy_url, $no_proxy;
$content = "http_proxy=".$proxy_url."\n";
$content .= "https_proxy=".$proxy_url."\n";
$content .= "no_proxy=".$no_proxy."\n";
write_file($proxy_ini, $content);
}
/* Clear /usr/local/emhttp/state/proxy.ini. */
function unset_proxy_ini() {
/* Vars are empty now, call set_proxy_ini to add empty vars to proxy.ini. */
set_proxy_ini();
}
/* Generate proxy files. */
function add_proxy_to_generated_files() {
global $verbose;
echo("generating proxy files\n");
set_proxy_sh();
set_proxy_ini();
if ($verbose) {
display_generated_files();
}
}
/* Remove proxy info from all generated files. */
function remove_proxy_from_generated_files() {
global $verbose;
echo("removing proxy info from generated files\n");
unset_proxy_sh();
unset_proxy_ini();
if ($verbose) {
display_generated_files();
}
}
/* When verbose mode is enabled. */
function display_generated_files() {
global $proxy_sh, $proxy_ini;
echo("\n");
display_generated_file($proxy_sh);
echo("\n");
display_generated_file($proxy_ini);
}
/* When verbose mode is enabled. */
function display_generated_file($file) {
echo("file: ".$file."\n");
if (file_exists($file)) {
echo(file_get_contents($file));
} else {
echo("file does not exist\n");
}
}
/* Read current proxy information from Outgoing Proxy Manager config file. */
$config = parse_plugin_config();
/* Get the current active proxy. */
$proxy_active = $config['proxy_active'] ?? "0";
$proxy_url = "";
/* Only build full url for an active proxy. */
if ($proxy_active != "0") {
/* Get the active proxy url, user, and pass. */
$proxy_url = "proxy_url_".$proxy_active;
$proxy_user = "proxy_user_".$proxy_active;
$proxy_pass = "proxy_pass_".$proxy_active;
/* Get the full url for the active proxy. */
$url_array = get_proxy_info($config[$proxy_url] ?? "", $config[$proxy_user] ?? "", $config[$proxy_pass] ?? "");
$proxy_url = $proxy_active ? $url_array['full_url'] : "";
/* If the active proxy url is defined, create the generated files. */
if ($proxy_url) {
/* Proxies are defined, write generated files. */
$no_proxy = "127.0.0.1,localhost";
add_proxy_to_generated_files();
}
} else {
/* If no active proxies, remove proxy info from all generated files. */
remove_proxy_from_generated_files();
}
?>

2
sbin/virtiofsd Executable file
View File

@@ -0,0 +1,2 @@
#!/bin/bash
eval exec /usr/bin/virtiofsd $(/usr/local/emhttp/plugins/dynamix.vm.manager/scripts/virtiofsd.php "$@")