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:
bergware
2024-12-14 15:37:28 +01:00
parent fce3f56379
commit ff945bb6ce
8 changed files with 416 additions and 90 deletions
+199 -51
View File
@@ -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>
&nbsp;
: <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']}");
?>
+3 -1
View File
@@ -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
View File
@@ -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
+9 -1
View File
@@ -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
View File
@@ -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
+130
View File
@@ -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