Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions docs/networking/userland.md
Original file line number Diff line number Diff line change
Expand Up @@ -770,6 +770,16 @@ daemon solo aporta transporte, configuración y estado. La documentación
completa (configuración, ciclo de vida, estado y limitaciones) está en
[`docs/services/ntpd.md`](../services/ntpd.md).

**Modo one-shot (`ntpdate`).** Invocado como `ntpd once` (o `-q`/`--once`),
`ntpd` realiza una única sincronización y sale (0 si sincronizó, 1 si no). Es el
papel de `ntpdate`: no hay un binario aparte, se reutiliza el mismo daemon.

**Servidores.** La lista se configura por Registry en
`Ntpd\Parameters\Servers` (separados por `;`). El hive por defecto trae
`pool.ntp.org;time.cloudflare.com;time.google.com` — los fallbacks van en la
configuración, no en el código, para que el primer sync sea fiable detrás de
NAT. `Interval` (segundos) y `Timeout` (ms) también son valores del Registry.

---

## 4. NeoInit System Configuration
Expand Down
2 changes: 1 addition & 1 deletion tools/gen-hiv/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ fn build_default_system_hive(enable_tests: bool, enable_network_test: bool) -> H
// subkey; it never writes configuration (single source of truth: Registry).
b.add_value(_V_NTP_TO, "Timeout", REG_DWORD, &3000u32.to_le_bytes(), NULL_CELL, _NTPPARAM);
b.add_value(_V_NTP_INT, "Interval", REG_DWORD, &3600u32.to_le_bytes(), _V_NTP_TO, _NTPPARAM);
b.add_value(_V_NTP_SRV, "Servers", REG_SZ, b"pool.ntp.org\0", _V_NTP_INT, _NTPPARAM);
b.add_value(_V_NTP_SRV, "Servers", REG_SZ, b"pool.ntp.org;time.cloudflare.com;time.google.com\0", _V_NTP_INT, _NTPPARAM);
b.add_value(_V_NTP_EN, "Enabled", REG_DWORD, &1u32.to_le_bytes(), _V_NTP_SRV, _NTPPARAM);

// Interfaces\0: DHCPEnabled + DNS servers (default 0.0.0.0 = unset/automatic;
Expand Down
30 changes: 30 additions & 0 deletions userbin/ntpd/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -406,13 +406,31 @@ fn network_ready() -> bool {
libnet::iface_info(0, &mut iface) == 0 && iface.ip != [0u8; 4]
}

/// True when invoked as `ntpd once` / `-q` / `--once` (one-shot, `ntpdate` role).
fn arg_once() -> bool {
let a = libneodos::args::read_args();
for w in a.split(|&b| b == b' ' || b == b'\t' || b == b'\0' || b == b'\r' || b == b'\n') {
if w.eq_ignore_ascii_case(b"once") || w == b"-q" || w == b"--once" {
return true;
}
}
false
}

#[no_mangle]
pub extern "C" fn _start() -> ! {
write_str(b"\r\n[ntpd] NeoDOS NTP Service v0.1\r\n");

// `ntpd once` (or `-q`): synchronize a single time and exit — the `ntpdate`
// role. Without it the daemon runs the periodic loop.
let once = arg_once();

let cfg = load_config();
if !cfg.enabled {
write_str(b"[ntpd] NTP disabled by configuration; idling\r\n");
if once {
syscall::sys_exit(1);
}
publish("Disabled", "", 0, 0, 0, 0, "", 0);
loop {
// #358: observe graceful shutdown even while idling.
Expand All @@ -429,6 +447,10 @@ pub extern "C" fn _start() -> ! {
loop {
if !network_ready() {
write_str(b"[ntpd] network not ready; waiting\r\n");
if once {
write_str(b"[ntpd] one-shot: network not ready\r\n");
syscall::sys_exit(1);
}
publish("WaitingNetwork", "", 0, 0, 0, 0, "network unavailable", sync_count);
if wait_seconds(backoff) {
graceful_exit();
Expand Down Expand Up @@ -496,13 +518,21 @@ pub extern "C" fn _start() -> ! {

if synced {
backoff = INITIAL_BACKOFF_SECS;
if once {
write_str(b"[ntpd] one-shot sync complete\r\n");
syscall::sys_exit(0);
}
if wait_seconds(cfg.interval) {
graceful_exit();
}
} else {
write_str(b"[ntpd] all servers failed; backoff ");
write_u32(backoff);
write_str(b"s\r\n");
if once {
write_str(b"[ntpd] one-shot sync failed\r\n");
syscall::sys_exit(1);
}
if wait_seconds(backoff) {
graceful_exit();
}
Expand Down
Loading