mirror of
https://github.com/unraid/webgui.git
synced 2026-05-06 04:11:17 -05:00
Date and Time enhancements
- Support Precision Time Protocol (PTP) - time accuracy in nanoseconds - PTP requires a local time server which supports the PTP protocol - Show only the applicable fields for the selected time sync value (animated) - Add 'hints' to help the user in configuration - Do not restart time service when only date/time format is updated Note for Tom: to make PTP work the package "linuxptp-4.2-x86_64-1_BW.txz" needs to be installed with stock Unraid
This commit is contained in:
@@ -4,8 +4,8 @@ Icon="icon-clock"
|
||||
Tag="clock-o"
|
||||
---
|
||||
<?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,
|
||||
@@ -16,122 +16,270 @@ Tag="clock-o"
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
$keys = explode("\n",file_get_contents("$docroot/webGui/include/timezones.key"));
|
||||
$validIP4 = "^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$";
|
||||
$validIP6 = "^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|(:|([0-9a-fA-F]{1,4}:)+):(([0-9a-fA-F]{1,4}:)*[0-9a-fA-F]{1,4})?)$";
|
||||
$validMAC = "^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$";
|
||||
$tmzones = file("$docroot/webGui/include/timezones.key",FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES);
|
||||
$hwclock = [];
|
||||
|
||||
exec("ls --indicator-style=none /sys/class/net|grep -P '^eth[0-9]*$'",$ports);
|
||||
foreach ($ports as $port) $hwclock[$port] = exec("ethtool -T $port|grep -Pom1 '^PTP Hardware Clock: \K.+'")=='none' ? 'disabled' : '';
|
||||
?>
|
||||
<form markdown="1" name="datetime_settings" method="POST" action="/update.htm" target="progressFrame">
|
||||
<form markdown="1" name="datetime_settings" method="POST" action="/update.htm" target="progressFrame" onchange="signal(this)">
|
||||
<input type="hidden" name="setDateTime" value="apply">
|
||||
_(Current date and time)_:
|
||||
: <?=_(my_time(time()),0)?>
|
||||
|
||||
_(Date format)_:
|
||||
: <select name="display_date" onchange="presetTime(this.form)">
|
||||
<?=mk_option($display['date'], "%c","_(System Setting)_")?>
|
||||
<?=mk_option($display['date'], "%A, %Y %B %e",_('Day, YYYY Month D'))?>
|
||||
<?=mk_option($display['date'], "%A, %e %B %Y",_('Day, D Month YYYY'))?>
|
||||
<?=mk_option($display['date'], "%A, %B %e, %Y",_('Day, Month D, YYYY'))?>
|
||||
<?=mk_option($display['date'], "%A, %m/%d/%Y",_('Day, MM/DD/YYYY'))?>
|
||||
<?=mk_option($display['date'], "%A, %d-%m-%Y",_('Day, DD-MM-YYYY'))?>
|
||||
<?=mk_option($display['date'], "%A, %d.%m.%Y",_('Day, DD.MM.YYYY'))?>
|
||||
<?=mk_option($display['date'], "%A, %Y-%m-%d",_('Day, YYYY-MM-DD'))?>
|
||||
<?=mk_option($display['date'], "%c", _('System Setting'))?>
|
||||
<?=mk_option($display['date'], "%A, %Y %B %e", _('Day, YYYY Month D'))?>
|
||||
<?=mk_option($display['date'], "%A, %e %B %Y", _('Day, D Month YYYY'))?>
|
||||
<?=mk_option($display['date'], "%A, %B %e, %Y", _('Day, Month D, YYYY'))?>
|
||||
<?=mk_option($display['date'], "%A, %m/%d/%Y", _('Day, MM/DD/YYYY'))?>
|
||||
<?=mk_option($display['date'], "%A, %d-%m-%Y", _('Day, DD-MM-YYYY'))?>
|
||||
<?=mk_option($display['date'], "%A, %d.%m.%Y", _('Day, DD.MM.YYYY'))?>
|
||||
<?=mk_option($display['date'], "%A, %Y-%m-%d", _('Day, YYYY-MM-DD'))?>
|
||||
</select>
|
||||
|
||||
_(Time format)_:
|
||||
: <select name="display_time">
|
||||
<?=mk_option($display['time'], "%I:%M %p",_('12 hours'))?>
|
||||
<?=mk_option($display['time'], "%R",_('24 hours'))?>
|
||||
<?=mk_option($display['time'], "%I:%M %p", _('12 hours'))?>
|
||||
<?=mk_option($display['time'], "%R", _('24 hours'))?>
|
||||
</select>
|
||||
|
||||
_(Time zone)_:
|
||||
: <select name="timeZone"><?
|
||||
foreach ($keys as $key) {
|
||||
[$timezone, $city] = my_explode('|', $key);
|
||||
foreach ($tmzones as $zone) {
|
||||
[$timezone, $city] = my_explode('|', $zone);
|
||||
echo mk_option($var['timeZone'], $timezone, $city);
|
||||
}
|
||||
?></select>
|
||||
|
||||
:timezone_help:
|
||||
|
||||
_(Use NTP)_:
|
||||
: <select name="USE_NTP" onchange="checkDateTimeSettings(this.form)">
|
||||
<?=mk_option($var['USE_NTP'], "yes", _('Yes'))?>
|
||||
<?=mk_option($var['USE_NTP'], "no", _('No'))?>
|
||||
_(Time sync)_:
|
||||
: <select name="USE_NTP" onchange="updatePage(this.form,'slow')">
|
||||
<?=mk_option($var['USE_NTP'], "yes", _('NTP'))?>
|
||||
<?=mk_option($var['USE_NTP'], "yes", _('PTP'))?>
|
||||
<?=mk_option($var['USE_NTP'], "no", _('Manual'))?>
|
||||
</select>
|
||||
|
||||
:use_ntp_help:
|
||||
|
||||
<div markdown="1" id="ntp-setup" class="extra">
|
||||
_(NTP interval)_:
|
||||
: <select name="display_ntppoll">
|
||||
<?=mk_option(_var($display,'ntppoll'), "", _('Default'))?>
|
||||
<?=mk_option(_var($display,'ntppoll'), "8", _('Slow'))?>
|
||||
<?=mk_option(_var($display,'ntppoll'), "5", _('Medium'))?>
|
||||
<?=mk_option(_var($display,'ntppoll'), "3", _('Fast'))?>
|
||||
</select><span class="ntp orange-text">_(Use DEFAULT setting when public NTP servers are defined)_</span>
|
||||
: <select name="NTP_POLL">
|
||||
<?=mk_option(_var($NTP,'POLL'), "", _('Default'))?>
|
||||
<?=mk_option(_var($NTP,'POLL'), "8", _('Slow'))?>
|
||||
<?=mk_option(_var($NTP,'POLL'), "5", _('Medium'))?>
|
||||
<?=mk_option(_var($NTP,'POLL'), "3", _('Fast'))?>
|
||||
</select>
|
||||
<span class="orange-text">_(Use DEFAULT setting when public NTP servers are defined)_</span>
|
||||
|
||||
_(NTP server)_ 1:
|
||||
: <input type="text" name="NTP_SERVER1" maxlength="40" class="narrow" value="<?=htmlspecialchars($var['NTP_SERVER1'])?>">
|
||||
|
||||
:ntp_server1_help:
|
||||
<span class="orange-text">_(Input a NTP server name, NTP pool name or IP address)_</span>
|
||||
|
||||
_(NTP server)_ 2:
|
||||
: <input type="text" name="NTP_SERVER2" maxlength="40" class="narrow" value="<?=htmlspecialchars($var['NTP_SERVER2'])?>">
|
||||
|
||||
:ntp_server2_help:
|
||||
|
||||
_(NTP server)_ 3:
|
||||
: <input type="text" name="NTP_SERVER3" maxlength="40" class="narrow" value="<?=htmlspecialchars($var['NTP_SERVER3'])?>">
|
||||
|
||||
:ntp_server3_help:
|
||||
|
||||
_(NTP server)_ 4:
|
||||
: <input type="text" name="NTP_SERVER4" maxlength="40" class="narrow" value="<?=htmlspecialchars($var['NTP_SERVER4'])?>">
|
||||
|
||||
:ntp_server4_help:
|
||||
</div>
|
||||
<div markdown="1" id="ptp-setup" class="extra">
|
||||
_(PTP profile)_:
|
||||
: PTPv2 (IEEE 1588)
|
||||
|
||||
_(PTP transport)_:
|
||||
: <select name="PTP_TRANSPORT" onchange="updatePage(this.form,'slow')">
|
||||
<?=mk_option(_var($PTP,'TRANSPORT'), "UDPv4", _('UDPv4'))?>
|
||||
<?=mk_option(_var($PTP,'TRANSPORT'), "UDPv6", _('UDPv6'))?>
|
||||
<?=mk_option(_var($PTP,'TRANSPORT'), "L2", _('IEEE 802.3'))?>
|
||||
</select>
|
||||
|
||||
_(PTP mode)_:
|
||||
: <select name="PTP_MODE" onchange="updatePage(this.form,'slow')">
|
||||
<?=mk_option(_var($PTP,'MODE'), "multicast", _('Multicast'))?>
|
||||
<?=mk_option(_var($PTP,'MODE'), "unicast", _('Unicast'))?>
|
||||
</select>
|
||||
|
||||
<div markdown="1" id="unicast" class="extra">
|
||||
_(PTP server)_ 1:
|
||||
: <input type="text" name="PTP_SERVER1" maxlength="40" class="narrow" value="<?=htmlspecialchars(_var($PTP,'SERVER1'))?>">
|
||||
<span class="ipv4 orange-text">_(Input a IPv4 address)_</span><span class="ipv6 orange-text">_(Input a IPv6 address)_</span><span class="mac orange-text">_(Input a MAC address)_</span>
|
||||
|
||||
_(PTP server)_ 2:
|
||||
: <input type="text" name="PTP_SERVER2" maxlength="40" class="narrow" value="<?=htmlspecialchars(_var($PTP,'SERVER2'))?>">
|
||||
|
||||
_(PTP server)_ 3:
|
||||
: <input type="text" name="PTP_SERVER3" maxlength="40" class="narrow" value="<?=htmlspecialchars(_var($PTP,'SERVER3'))?>">
|
||||
|
||||
_(PTP server)_ 4:
|
||||
: <input type="text" name="PTP_SERVER4" maxlength="40" class="narrow" value="<?=htmlspecialchars(_var($PTP,'SERVER4'))?>">
|
||||
|
||||
</div>
|
||||
_(PTP interface)_:
|
||||
: <select name="PTP_PORT" onchange="hwclock(this.form,this.value)">
|
||||
<?foreach($ports as $port):?>
|
||||
<?=mk_option(_var($PTP,'PORT','eth0'), $port, $port)?>
|
||||
<?endforeach;?>
|
||||
</select>
|
||||
|
||||
_(PTP clock)_:
|
||||
: <select name="PTP_CLOCK">
|
||||
<?=mk_option(_var($PTP,'CLOCK'), "hardware", _('Hardware'), _var($hwclock,_var($PTP,'PORT','eth0')))?>
|
||||
<?=mk_option(_var($PTP,'CLOCK'), "software", _('Software'))?>
|
||||
</select>
|
||||
|
||||
</div>
|
||||
<div markdown="1" id="manual-setup" class="extra">
|
||||
_(New date and time)_:
|
||||
: <input type="text" name="newDateTime" maxlength="20" class="narrow" value="<?=my_time(time(), "%F %T")?>">
|
||||
: <input type="text" name="newDateTime" maxlength="20" class="narrow" value="<?=my_time(time(),"%F %T")?>">
|
||||
<span class="orange-text">_(Input the correct date and time manually)_</span>
|
||||
|
||||
:current_time_help:
|
||||
|
||||
</div>
|
||||
|
||||
: <input type="button" value="_(Apply)_" onclick="doDispatch(this.form)" disabled><input type="button" value="_(Done)_" onclick="done()">
|
||||
: <input type="button" value="_(Apply)_" onclick="dispatch(this.form)" disabled><input type="button" value="_(Done)_" onclick="done()">
|
||||
</form>
|
||||
|
||||
<script>
|
||||
function doDispatch(form) {
|
||||
var fields = {};
|
||||
var old_tz = "<?=$var['timeZone']?>";
|
||||
$(form).find('button').prop('disabled',true);
|
||||
fields['#cfg'] = "/boot/config/plugins/dynamix/dynamix.cfg";
|
||||
$(form).find('select[name^="display_"]').each(function(){fields[$(this).attr('name')] = $(this).val();});
|
||||
$.post('/webGui/include/Dispatcher.php',fields);
|
||||
if (form.timeZone.value != old_tz) $.post('/webGui/include/ResetTZ.php');
|
||||
form.submit();
|
||||
// update time service
|
||||
var service = false;
|
||||
var oldDate, oldTime, oldZone;
|
||||
|
||||
// ptp daemon is running?
|
||||
var ptpd = <?=exec("pgrep -cf /usr/sbin/ptp4l") ? 'true' : 'false'?>;
|
||||
|
||||
function hwclock(form,port) {
|
||||
// disable hardware clock if not supported
|
||||
var hwc = {};
|
||||
<?foreach ($hwclock as $port => $disabled):?>
|
||||
hwc.<?=$port?> = <?=$disabled ? 'true' : 'false'?>;
|
||||
<?endforeach;?>
|
||||
form.PTP_CLOCK.options[0].disabled = hwc[port];
|
||||
}
|
||||
|
||||
function signal(form) {
|
||||
if (service) return;
|
||||
if (form.display_date.selectedIndex != oldDate) {
|
||||
oldDate = form.display_date.selectedIndex;
|
||||
return;
|
||||
}
|
||||
if (form.display_time.selectedIndex != oldTime) {
|
||||
oldTime = form.display_time.selectedIndex;
|
||||
return
|
||||
}
|
||||
// time service needs update
|
||||
service = true;
|
||||
}
|
||||
|
||||
function disableButtons(state) {
|
||||
setTimeout(function(){$('input[type=button]').prop('disabled',state);});
|
||||
}
|
||||
|
||||
function dispatch(form) {
|
||||
var save = {};
|
||||
var valid = true;
|
||||
disableButtons(true);
|
||||
if (form.USE_NTP.selectedIndex==1 && form.PTP_MODE.selectedIndex==1) {
|
||||
let tr = form.PTP_TRANSPORT.value;
|
||||
let pattern = tr=='L2' ? /<?=$validMAC?>/ : (tr=='UDPv4' ? /<?=$validIP4?>/ : /<?=$validIP6?>/);
|
||||
// validate syntax of ptp server addresses
|
||||
$(form).find('input[name^="PTP_SERVER"]').each(function(){
|
||||
var text = $(this).val();
|
||||
if (text!='' && pattern.test(text)==false) valid = false;
|
||||
});
|
||||
} else if (form.USE_NTP.selectedIndex==1) {
|
||||
// clear ptp server addresses
|
||||
$('input[name^="PTP_SERVER"]').val('');
|
||||
}
|
||||
if (valid) {
|
||||
let index = form.USE_NTP.selectedIndex;
|
||||
let cmd = index==1 ? (ptpd ? 'restart' : 'start') : 'stop';
|
||||
save['#cfg'] = "/boot/config/plugins/dynamix/dynamix.cfg";
|
||||
save.PTP_SYNC = index==1 ? 'yes' : 'no';
|
||||
$(form).find('select[name^="display_"],select[name="NTP_POLL"],select[name^="PTP_"],input[name^="display_"],input[name^="PTP_"]').each(function(){
|
||||
save[$(this).attr('name')] = $(this).val();
|
||||
// exclude setting for emhttpd
|
||||
$(this).prop('disabled',true);
|
||||
});
|
||||
// save dispatched variables
|
||||
$.post('/webGui/include/Dispatcher.php',save,function(){
|
||||
if (service) {
|
||||
// start/stop ptp daemon separately (emhttpd does not support it)
|
||||
$.post('/webGui/include/StartStopPTP.php',{cmd:cmd},function(){
|
||||
// reset timezone when it has changed
|
||||
if (form.timeZone.selectedIndex != oldZone) $.post('/webGui/include/ResetTZ.php');
|
||||
// start/stop ntp daemon (using emhttpd)
|
||||
form.submit();
|
||||
});
|
||||
} else {
|
||||
// no time service update needed
|
||||
refresh();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
disableButtons(false);
|
||||
swal("_(Wrong PTP server address)_");
|
||||
}
|
||||
}
|
||||
|
||||
function presetTime(form) {
|
||||
var system = form.display_date.selectedIndex==0;
|
||||
if (system) form.display_time.selectedIndex = 0;
|
||||
form.display_time.disabled = system;
|
||||
}
|
||||
function checkDateTimeSettings(form) {
|
||||
if (form.USE_NTP.value=="yes") {
|
||||
|
||||
function updatePage(form,step) {
|
||||
if (form.USE_NTP.selectedIndex==0) {
|
||||
// ntp
|
||||
$('#ptp-setup,#manual-setup').hide(step);
|
||||
$('#ntp-setup').show(step);
|
||||
form.newDateTime.disabled=true;
|
||||
form.display_ntppoll.disabled=false;
|
||||
form.NTP_SERVER1.disabled=false;
|
||||
form.NTP_SERVER2.disabled=false;
|
||||
form.NTP_SERVER3.disabled=false;
|
||||
form.NTP_SERVER4.disabled=false;
|
||||
} else if (form.USE_NTP.selectedIndex==1) {
|
||||
// ptp
|
||||
$('#ntp-setup,#manual-setup').hide(step);
|
||||
$('#ptp-setup').show(step);
|
||||
if (form.PTP_MODE.selectedIndex==0) $('#unicast').hide(step); else $('#unicast').show(step);
|
||||
form.newDateTime.disabled=true;
|
||||
form.NTP_SERVER1.disabled=true;
|
||||
form.NTP_SERVER2.disabled=true;
|
||||
form.NTP_SERVER3.disabled=true;
|
||||
form.NTP_SERVER4.disabled=true;
|
||||
$('span.ipv4,span.ipv6,span.mac').hide();
|
||||
switch (form.PTP_TRANSPORT.selectedIndex) {
|
||||
case 0: $('span.ipv4').show(); break;
|
||||
case 1: $('span.ipv6').show(); break;
|
||||
case 2: $('span.mac').show(); break;
|
||||
}
|
||||
} else {
|
||||
// manual
|
||||
$('#ntp-setup,#ptp-setup').hide(step);
|
||||
$('#manual-setup').show(step);
|
||||
form.newDateTime.disabled=false;
|
||||
form.display_ntppoll.disabled=true;
|
||||
form.NTP_SERVER1.disabled=true;
|
||||
form.NTP_SERVER2.disabled=true;
|
||||
form.NTP_SERVER3.disabled=true;
|
||||
form.NTP_SERVER4.disabled=true;
|
||||
}
|
||||
}
|
||||
|
||||
$(function() {
|
||||
var form = document.datetime_settings;
|
||||
presetTime(form);
|
||||
checkDateTimeSettings(form);
|
||||
oldDate = form.display_date.selectedIndex;
|
||||
oldTime = form.display_time.selectedIndex;
|
||||
oldZone = form.timeZone.selectedIndex;
|
||||
form.USE_NTP.selectedIndex = <?=_var($PTP,'SYNC')=='yes' ? 1 : ($var['USE_NTP']=='yes' ? 0 : 2)?>;
|
||||
updatePage(form);
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -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.
|
||||
* Copyright 2014-2021, Guilherme Jardim, Eric Schultz, Jon Panozzo.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
@@ -21,10 +21,38 @@ require_once "$docroot/plugins/dynamix.docker.manager/include/DockerClient.php";
|
||||
require_once "$docroot/plugins/dynamix.vm.manager/include/libvirt_helpers.php";
|
||||
|
||||
if (isset($_POST['ntp'])) {
|
||||
if (exec("pgrep -cf /usr/sbin/ntpd")) {
|
||||
if (exec("pgrep -cf /usr/sbin/ptp4l")) {
|
||||
// ptp sync
|
||||
if (exec("pmc -ub0 'GET TIME_STATUS'|awk '$1==\"gmPresent\"{print $2;exit}'")=='true') {
|
||||
$ptp = abs(exec("pmc -ub0 'GET CURRENT'|awk '$1==\"offsetFromMaster\"{print $2;exit}'"));
|
||||
switch (true) {
|
||||
case ($ptp == 0) : $unit = 'ns'; $ptp = '???'; break;
|
||||
case ($ptp < 1E+3): $unit = 'ns'; $ptp = round($ptp); break;
|
||||
case ($ptp < 1E+6): $unit = 'μs'; $ptp = round($ptp/1E+3); break;
|
||||
case ($ptp < 1E+9): $unit = 'ms'; $ptp = round($ptp/1E+6); break;
|
||||
default : $unit = 's' ; $ptp = round($ptp/1E+9); break;
|
||||
}
|
||||
die(sprintf(_('Clock is synchronized using PTP, time offset is %s %s'),$ptp,$unit));
|
||||
} else {
|
||||
die(_('Clock is unsynchronized with no PTP servers'));
|
||||
}
|
||||
} elseif (exec("pgrep -cf /usr/sbin/ntpd")) {
|
||||
// ntp sync
|
||||
$ntp = exec("ntpq -pn|awk '$1~/^\*/{print $9;exit}'");
|
||||
die($ntp ? sprintf(_('Clock is synchronized using NTP, time offset: %s ms'),abs($ntp)) : _('Clock is unsynchronized with no NTP servers'));
|
||||
if ($ntp) {
|
||||
$ntp = abs($ntp);
|
||||
switch (true) {
|
||||
case ($ntp == 0) : $unit = 'μs'; $ntp = '< 1'; break;
|
||||
case ($ntp < 1) : $unit = 'μs'; $ntp = round($ntp*1E+3); break;
|
||||
case ($ntp < 1E+3): $unit = 'ms'; $ntp = round($ntp); break;
|
||||
default : $unit = 's' ; $ntp = round($ntp/1E+3); break;
|
||||
}
|
||||
die(sprintf(_('Clock is synchronized using NTP, time offset is %s %s'),$ntp,$unit));
|
||||
} else {
|
||||
die(_('Clock is unsynchronized with no NTP servers'));
|
||||
}
|
||||
}
|
||||
// manual sync
|
||||
die(_('Clock is unsynchronized, free-running clock'));
|
||||
}
|
||||
|
||||
@@ -99,32 +127,32 @@ if ($_POST['vms']) {
|
||||
$arrConfig = domain_to_config($uuid);
|
||||
if ($vmrcport > 0) {
|
||||
$wsport = $lv->domain_get_ws_port($res);
|
||||
$vmrcprotocol = $lv->domain_get_vmrc_protocol($res) ;
|
||||
$vmrcprotocol = $lv->domain_get_vmrc_protocol($res);
|
||||
if ($vmrcprotocol == "vnc") $vmrcscale = "&resize=scale"; else $vmrcscale = "";
|
||||
$vmrcurl = autov('/plugins/dynamix.vm.manager/'.$vmrcprotocol.'.html',true).$vmrcscale.'&autoconnect=true&host=' . $_SERVER['HTTP_HOST'] ;
|
||||
if ($vmrcprotocol == "spice") $vmrcurl .= '&vmname='. urlencode($vm) . '&port=/wsproxy/'.$vmrcport.'/' ; else $vmrcurl .= '&port=&path=/wsproxy/' . $wsport . '/';
|
||||
$vmrcurl = autov('/plugins/dynamix.vm.manager/'.$vmrcprotocol.'.html',true).$vmrcscale.'&autoconnect=true&host=' . $_SERVER['HTTP_HOST'];
|
||||
if ($vmrcprotocol == "spice") $vmrcurl .= '&vmname='. urlencode($vm) . '&port=/wsproxy/'.$vmrcport.'/'; else $vmrcurl .= '&port=&path=/wsproxy/' . $wsport . '/';
|
||||
} elseif ($vmrcport == -1 || $autoport) {
|
||||
$vmrcprotocol = $lv->domain_get_vmrc_protocol($res) ;
|
||||
if ($autoport == "yes") $auto = "auto" ; else $auto="manual" ;
|
||||
$vmrcprotocol = $lv->domain_get_vmrc_protocol($res);
|
||||
$auto = ($autoport == "yes") ? "auto" : "manual";
|
||||
} elseif (!empty($arrConfig['gpu'])) {
|
||||
$arrValidGPUDevices = getValidGPUDevices();
|
||||
foreach ($arrConfig['gpu'] as $arrGPU) {
|
||||
foreach ($arrValidGPUDevices as $arrDev) {
|
||||
if ($arrGPU['id'] == $arrDev['id']) {
|
||||
if (count(array_filter($arrValidGPUDevices, function($v) use ($arrDev) { return $v['name'] == $arrDev['name']; })) > 1) {
|
||||
$vmrcprotocol = "VGA" ;
|
||||
$vmrcprotocol = "VGA";
|
||||
} else {
|
||||
$vmrcprotocol = "VGA" ;
|
||||
$vmrcprotocol = "VGA";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$template = $lv->_get_single_xpath_result($res, '//domain/metadata/*[local-name()=\'vmtemplate\']/@name');
|
||||
if (empty($template)) $template = 'Custom';
|
||||
$log = (is_file("/var/log/libvirt/qemu/$vm.log") ? "libvirt/qemu/$vm.log" : '');
|
||||
if (!isset($domain_cfg["CONSOLE"])) $vmrcconsole = "web" ; else $vmrcconsole = $domain_cfg["CONSOLE"] ;
|
||||
if (!isset($domain_cfg["RDPOPT"])) $vmrcconsole .= ";no" ; else $vmrcconsole .= ";".$domain_cfg["RDPOPT"] ;
|
||||
if (!isset($domain_cfg["CONSOLE"])) $vmrcconsole = "web"; else $vmrcconsole = $domain_cfg["CONSOLE"];
|
||||
if (!isset($domain_cfg["RDPOPT"])) $vmrcconsole .= ";no"; else $vmrcconsole .= ";".$domain_cfg["RDPOPT"];
|
||||
$WebUI = html_entity_decode($arrConfig["template"]["webui"]);
|
||||
$menu = sprintf("onclick=\"addVMContext('%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s')\"", addslashes($vm), addslashes($uuid), addslashes($template), $state, addslashes($vmrcurl), strtoupper($vmrcprotocol), addslashes($log),addslashes($fstype), $vmrcconsole,false,addslashes(str_replace('"',"'",$WebUI)));
|
||||
$icon = $lv->domain_get_icon_url($res);
|
||||
@@ -153,7 +181,7 @@ if ($_POST['vms']) {
|
||||
#Build VM Usage array.
|
||||
$menuusage = sprintf("onclick=\"addVMContext('%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s')\"", addslashes($vm), addslashes($uuid), addslashes($template), $state, addslashes($vmrcurl), strtoupper($vmrcprotocol), addslashes($log),addslashes($fstype), $vmrcconsole,true,addslashes(str_replace('"',"'",$WebUI)));
|
||||
$vmusagehtml[] = "<span class='outer solid vmsuse $status'><span id='vmusage-$uuid' $menuusage class='hand'>$image</span><span class='inner'>$vm<br><i class='fa fa-$shape $status $color'></i><span class='state'>"._($status)."</span></span>";
|
||||
$vmusagehtml[] = "<br><br><span id='vmmetrics-gcpu-".$uuid."'>"._("Loading")."....</span>";
|
||||
$vmusagehtml[] = "<br><br><span id='vmmetrics-gcpu-".$uuid."'>"._("Loading")."....</span>";
|
||||
$vmusagehtml[] = "<br><span id='vmmetrics-hcpu-".$uuid."'>"._("Loading")."....</span>";
|
||||
$vmusagehtml[] = "<br><span id='vmmetrics-mem-".$uuid."'>"._("Loading")."....</span>";
|
||||
$vmusagehtml[] = "<br><span id='vmmetrics-disk-".$uuid."'>"._("Loading")."....</span>";
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
<?PHP
|
||||
// start/stop service
|
||||
exec("/etc/rc.d/rc.ptpd {$_POST['cmd']}");
|
||||
?>
|
||||
@@ -1 +1,3 @@
|
||||
span.ntp{margin-left:40px}
|
||||
div.extra,span.ipv4,span.ipv6,span.mac{display:none}
|
||||
select,input[type=text]{margin-right:40px}
|
||||
select[name=timeZone]{max-width:166px}
|
||||
|
||||
+6
-1
@@ -11,7 +11,7 @@
|
||||
# Heavily modified by Patrick Volkerding <volkerdi@slackware.com>
|
||||
#
|
||||
# LimeTech - modified for Unraid OS
|
||||
# Bergware - modified for Unraid OS, October 2023
|
||||
# Bergware - modified for Unraid OS, December 2024
|
||||
|
||||
# run & log functions
|
||||
. /etc/rc.d/rc.runlog
|
||||
@@ -108,6 +108,11 @@ fi
|
||||
# Mount any additional filesystem types that haven't already been mounted:
|
||||
mount -a -v 2>/dev/null | grep -v -e "already mounted" -e "ignored" | cut -f 1 -d : | tr -d ' ' | while read DEV; do mount | grep "$DEV "; done
|
||||
|
||||
# Start the Precision Time Protocol daemon:
|
||||
if [[ -x /etc/rc.d/rc.ptpd ]]; then
|
||||
/etc/rc.d/rc.ptpd start
|
||||
fi
|
||||
|
||||
# Start the Network Time Protocol daemon:
|
||||
if [[ -x /etc/rc.d/rc.ntpd ]]; then
|
||||
/etc/rc.d/rc.ntpd start
|
||||
|
||||
@@ -4,12 +4,20 @@
|
||||
#
|
||||
# Library used by nfsd, ntpd, rpc, samba, nginx, sshd, avahidaemon, show_interfaces
|
||||
#
|
||||
# Bergware - created for Unraid OS, December 2023
|
||||
# Bergware - created for Unraid OS, December 2024
|
||||
|
||||
WIREGUARD="/etc/wireguard"
|
||||
NETWORK_INI="/var/local/emhttp/network.ini"
|
||||
NETWORK_EXTRA="/boot/config/network-extra.cfg"
|
||||
|
||||
var(){
|
||||
if [[ $# -eq 3 ]]; then
|
||||
[[ -r "$3" ]] && sed -n "/^\[$1\]\$/,/^\[/p" "$3" | grep -Pom1 "^$2=\"\K[^\"]+"
|
||||
elif [[ $# -eq 2 ]]; then
|
||||
[[ -r "$2" ]] && grep -Pom1 "^$1=\"\K[^\"]+" "$2"
|
||||
fi
|
||||
}
|
||||
|
||||
ipv(){
|
||||
local t=${1//[^:]}
|
||||
[[ ${#t} -le 1 ]] && echo 4 || echo 6
|
||||
|
||||
+22
-21
@@ -5,15 +5,15 @@
|
||||
# Start/stop/restart ntpd.
|
||||
#
|
||||
# LimeTech - modified to initialize ntp.conf file from config
|
||||
# Bergware - modified for Unraid OS, October 2023
|
||||
# Bergware - modified for Unraid OS, December 2024
|
||||
|
||||
DAEMON="NTP server daemon"
|
||||
CALLER="ntp"
|
||||
NTPD="/usr/sbin/ntpd"
|
||||
OPTIONS="-g -u ntp:ntp"
|
||||
CONF="/etc/ntp.conf"
|
||||
CFG="/boot/config/plugins/dynamix/dynamix.cfg"
|
||||
IDENT="/boot/config/ident.cfg"
|
||||
CONFIG="/boot/config/plugins/dynamix/dynamix.cfg"
|
||||
|
||||
# run & log functions
|
||||
. /etc/rc.d/rc.runlog
|
||||
@@ -39,24 +39,25 @@ ntpd_build(){
|
||||
echo "interface listen $NET" >>$CONF
|
||||
done
|
||||
fi
|
||||
NTP_POLL=$(var NTP POLL $CFG)
|
||||
# ntp poll interval may be adjusted to predefined values
|
||||
if [[ -f $CONFIG ]]; then
|
||||
NTP_POLL=$(grep -Po '^ntppoll="\K[^"]+' $CONFIG)
|
||||
if [[ -n $NTP_POLL ]]; then
|
||||
MINPOLL="minpoll $NTP_POLL"
|
||||
MAXPOLL="maxpoll $NTP_POLL"
|
||||
fi
|
||||
if [[ -n $NTP_POLL ]]; then
|
||||
MINPOLL="minpoll $NTP_POLL"
|
||||
MAXPOLL="maxpoll $NTP_POLL"
|
||||
fi
|
||||
# allow ntp to use ptp as sync source
|
||||
if [[ $(var PTP SYNC $CFG) != yes ]]; then
|
||||
# add configured ntp servers or pools
|
||||
for n in {1..4}; do
|
||||
NTP="NTP_SERVER$n"
|
||||
if [[ -n ${!NTP} ]]; then
|
||||
# use either server or pool peers depending on remote ntp name
|
||||
# pools use a round-robin mechanism to get a server out of the pool
|
||||
[[ ${!NTP} =~ "pool" ]] && PEER=pool || PEER=server
|
||||
echo "$PEER ${!NTP} iburst $MINPOLL $MAXPOLL" >>$CONF
|
||||
fi
|
||||
done
|
||||
fi
|
||||
# add configured ntp servers or pools
|
||||
for n in {1..4}; do
|
||||
NTP="NTP_SERVER$n"
|
||||
if [[ -n ${!NTP} ]]; then
|
||||
# use either server or pool peers depending on remote ntp name
|
||||
# pools use a round-robin mechanism to get a server out of the pool
|
||||
[[ ${!NTP} =~ "pool" ]] && PEER=pool || PEER=server
|
||||
echo "$PEER ${!NTP} iburst $MINPOLL $MAXPOLL" >>$CONF
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
ntpd_start(){
|
||||
@@ -64,7 +65,7 @@ ntpd_start(){
|
||||
local REPLY
|
||||
# read Unraid settings
|
||||
[[ -r $IDENT ]] && . <(fromdos <$IDENT)
|
||||
# if ntp not enabled, don't start ntp
|
||||
# if time sync not enabled, don't start ntp
|
||||
if [[ $USE_NTP != yes ]]; then
|
||||
REPLY="Service not enabled"
|
||||
elif ntpd_running; then
|
||||
@@ -90,7 +91,7 @@ ntpd_stop(){
|
||||
kill -HUP $(cat /var/run/ntpd.pid)
|
||||
rm -f /var/run/ntpd.pid
|
||||
else
|
||||
killall --ns $$ -HUP -q ntpd
|
||||
killall --ns $$ -HUP -q ntpd
|
||||
fi
|
||||
if ! ntpd_running; then REPLY="Stopped"; else REPLY="Failed"; fi
|
||||
fi
|
||||
@@ -107,7 +108,7 @@ ntpd_restart(){
|
||||
}
|
||||
|
||||
ntpd_reload(){
|
||||
killall --ns $$ -HUP -q ntpd
|
||||
killall --ns $$ -HUP -q ntpd
|
||||
. <(fromdos <$IDENT)
|
||||
ntpd_build
|
||||
$NTPD $OPTIONS 2>/dev/null
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# script: rc.ptpd
|
||||
#
|
||||
# Start/stop/restart services ptp4l and phc2sys.
|
||||
#
|
||||
# Bergware - created for Unraid OS, December 2024
|
||||
|
||||
DAEMON="PTP server daemon"
|
||||
CALLER="ptp"
|
||||
PTPD="/usr/sbin/ptp4l"
|
||||
PHC="/usr/sbin/phc2sys"
|
||||
OPTIONS1="-s -l 5 -f /etc/ptp4l.conf"
|
||||
OPTIONS2="-a -r -l 5"
|
||||
CONF="/etc/ptp4l.conf"
|
||||
CFG="/boot/config/plugins/dynamix/dynamix.cfg"
|
||||
IDENT="/boot/config/ident.cfg"
|
||||
|
||||
# run & log functions
|
||||
. /etc/rc.d/rc.runlog
|
||||
|
||||
# library functions
|
||||
. /etc/rc.d/rc.library.source
|
||||
|
||||
ptpd_running(){
|
||||
sleep 0.1
|
||||
[[ $(pgrep -cf $PTPD) -gt 0 ]]
|
||||
}
|
||||
|
||||
ptpd_build(){
|
||||
echo "[global]" >$CONF
|
||||
TRANSPORT=$(var PTP TRANSPORT $CFG)
|
||||
echo "network_transport $TRANSPORT" >>$CONF
|
||||
echo "time_stamping $(var PTP CLOCK $CFG)" >>$CONF
|
||||
[[ $(var PTP MODE $CFG) == unicast ]] && UNICAST=1 || UNICAST=0
|
||||
if [[ $UNICAST == 1 ]]; then
|
||||
echo "unicast_req_duration 60" >>$CONF
|
||||
echo "" >>$CONF
|
||||
echo "[unicast_master_table]" >>$CONF
|
||||
echo "table_id 1" >>$CONF
|
||||
echo "logQueryInterval 1" >>$CONF
|
||||
for n in {1..4}; do
|
||||
PTP=$(var PTP "SERVER$n" $CFG)
|
||||
[[ -n $PTP ]] && echo "$TRANSPORT $PTP" >>$CONF
|
||||
done
|
||||
fi
|
||||
echo "" >>$CONF
|
||||
echo "[$(var PTP PORT $CFG)]" >>$CONF
|
||||
[[ $UNICAST == 1 ]] && echo "unicast_master_table 1" >>$CONF
|
||||
}
|
||||
|
||||
ptpd_start(){
|
||||
log "Starting $DAEMON..."
|
||||
local REPLY
|
||||
# read Unraid settings
|
||||
[[ -r $IDENT ]] && . <(fromdos <$IDENT)
|
||||
# if time sync not enabled, don't start ptp
|
||||
if [[ $USE_NTP != yes ]]; then
|
||||
REPLY="Service not enabled"
|
||||
elif [[ $(var PTP SYNC $CFG) == yes || $FORCE == yes ]]; then
|
||||
if ptpd_running; then
|
||||
REPLY="Already started"
|
||||
else
|
||||
# generate our config file
|
||||
ptpd_build
|
||||
$PTPD $OPTIONS1 &>/dev/null &
|
||||
if ptpd_running; then
|
||||
$PHC $OPTIONS2 &>/dev/null &
|
||||
REPLY="Started"
|
||||
else
|
||||
REPLY="Failed"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
REPLY="Not started"
|
||||
fi
|
||||
log "$DAEMON... $REPLY."
|
||||
}
|
||||
|
||||
ptpd_stop(){
|
||||
log "Stopping $DAEMON..."
|
||||
local REPLY
|
||||
if ! ptpd_running; then
|
||||
REPLY="Already stopped"
|
||||
else
|
||||
pkill -f $PTPD 2>/dev/null
|
||||
pkill -f $PHC 2>/dev/null
|
||||
if ! ptpd_running; then REPLY="Stopped"; else REPLY="Failed"; fi
|
||||
fi
|
||||
log "$DAEMON... $REPLY."
|
||||
}
|
||||
|
||||
ptpd_restart(){
|
||||
log "Restarting $DAEMON..."
|
||||
ptpd_stop
|
||||
sleep 1
|
||||
ptpd_start
|
||||
}
|
||||
|
||||
ptpd_status(){
|
||||
if ptpd_running; then
|
||||
echo "$DAEMON is currently running."
|
||||
else
|
||||
echo "$DAEMON is not running."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
'start')
|
||||
ptpd_start
|
||||
;;
|
||||
'forcestart')
|
||||
FORCE=yes
|
||||
ptpd_start
|
||||
;;
|
||||
'stop')
|
||||
ptpd_stop
|
||||
;;
|
||||
'restart')
|
||||
ptpd_restart
|
||||
;;
|
||||
'status')
|
||||
ptpd_status
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $BASENAME start|forcestart|stop|restart|status"
|
||||
exit 1
|
||||
esac
|
||||
exit 0
|
||||
Reference in New Issue
Block a user