Split poll_ip_info into two phases: write IP info (addresses, subnets,
gateway, DNS, NTP) to the watch immediately, then fetch WAN IP in a
second pass. Previously the echoip HTTP fetch (5s timeout per URL)
blocked the write and was repeatedly cancelled by D-Bus signals during
interface activation, preventing the gateway from ever appearing.
Replace PolicyRoutingCleanup Drop with gc_policy_routing. The old Drop
spawned async route flushes that raced with new apply_policy_routing
calls when the watcher restarted on device_added, wiping freshly-created
routing tables for existing interfaces like eth0. Now policy routing is
managed idempotently by apply_policy_routing, and stale rules are
garbage-collected at the start of each watcher iteration.
- Fix parseInt callback in container-runtime to avoid extra map arguments
- Use proper error propagation in list_service_interfaces instead of unwrap_or_default
- Handle non-plain objects by reference in deepEqual
In TTY mode, pty_process already calls setsid() on the child before
our pre_exec runs. The second setsid() fails with EPERM since the
process is already a session leader. This is harmless — ignore it.
Tokio's multi-thread scheduler has an unfixed vulnerability where all
worker threads can end up parked on condvars with no worker driving the
I/O reactor. Condvar-parked workers have no timeout and sleep
indefinitely, so once in this state the runtime never recovers.
This was observed on a box migrating from 0.3.5.1: after heavy task
churn (package reinstalls, container operations, logging) all 16 workers
ended up on futex_wait with no thread on epoll_wait. The web server
listened on both HTTP and HTTPS but never replied. The box was stuck
for 7+ hours with 0% CPU.
Two mitigations:
1. Watchdog OS thread (startd.rs): a plain std::thread that every 30s
injects a no-op task via Handle::spawn. This forces a condvar-parked
worker to wake, cycle through park, and grab the driver TryLock —
breaking the stall regardless of what triggered it.
2. block_in_place in the logger (logger.rs): the TeeWriter holds a
std::sync::Mutex across blocking file + stderr writes on worker
threads. Wrapping in block_in_place tells tokio to hand off driver
duties before the worker blocks, reducing the window for starvation.
Guarded by runtime_flavor() to avoid panicking on current-thread
runtimes used by the CLI.
When the target VG is already active (e.g. the running system's own
VG), probe the block device directly instead of going through the
full import/activate/open/cleanup sequence.
Remove the backup_succeeded gate so the progress indicator updates
regardless of the backup outcome — the status field already captures
success/failure separately.
- Demote transient route-replace errors (vanishing interfaces) to trace
- Tolerate errors during policy routing cleanup on drop
- Use join_all instead of try_join_all for gateway watcher jobs
- Simplify wifi interface detection to always use find_wifi_iface()
- Write wifi enabled state to db instead of interface name
Load pre-saved container images from /usr/lib/startos/migration-images
before migrating packages, removing the need for internet access during
the v1→v2 s9pk conversion. Add a periodic progress logger so the user
can see which package is being migrated.
Bundle start9/compat, start9/utils, and tonistiigi/binfmt container
images into the OS image so the v1→v2 s9pk migration can run without
internet access.
The pipe-wrap binary guarantees FDs are always pipes (not sockets),
making the chown safe. The chown is still needed because anonymous
pipes have mode 0600 — without it, non-root users cannot re-open
/dev/stderr via /proc/self/fd/2.
Move BackupProgress { complete: true } into the same db.mutate() as the
DesiredStatus revert in the backup transition. Previously these were
separate mutations—the status would revert to Running before progress
showed complete, causing a visible gap in the UI.
After setuid, the kernel clears the dumpable flag, making /proc/self/
entries owned by root. This broke open("/dev/stderr") for non-root
users inside subcontainers. The previous fix (chowning /proc/self/fd/*)
was dangerous because it chowned whatever file the FD pointed to (could
be the journal socket).
The proper fix is prctl(PR_SET_DUMPABLE, 1) after setuid, which restores
/proc/self/ ownership to the current uid.
Additionally, adds a `pipe-wrap` subcommand that wraps a child process
with piped stdout/stderr, relaying to the original FDs. This ensures all
descendants inherit pipes (which support re-opening via /proc/self/fd/N)
even when the outermost FDs are journal sockets. container-runtime.service
now uses this wrapper.
With pipe-wrap guaranteeing pipe-based FDs, the exec and launch non-TTY
paths no longer need their own pipe+relay threads, eliminating the bug
where exec would hang when a child daemonized (e.g. pg_ctl start).
- Pre-create and chown dump file for postgres user before pg_dump
- Chown volume mountpoint to postgres before initdb on restore
- Add --no-privileges to pg_restore to skip GRANT/REVOKE for missing roles
Implemented pipe FD handoff from exec to launch via Unix socket +
SCM_RIGHTS for grandchild log capture. Superseded by the simpler
PR_SET_DUMPABLE approach which eliminates the need for pipes entirely.