diff --git a/birdnet-pi/rootfs/helpers/timedatectl2 b/birdnet-pi/rootfs/helpers/timedatectl2 new file mode 100644 index 000000000..3a181da94 --- /dev/null +++ b/birdnet-pi/rootfs/helpers/timedatectl2 @@ -0,0 +1,268 @@ +#!/usr/bin/env bash +# +# A simple bash script to replicate essential "timedatectl" functionality: +# - Show current time and time zone +# - List available time zones +# - Set time or time zone +# - Enable/disable/verify NTP +# - Configure RTC as localtime or UTC + +# ------------------------------------------------------------------------------ +# Utility functions +# ------------------------------------------------------------------------------ + +print_usage() { + cat <&2 + exit 1 +} + +# ------------------------------------------------------------------------------ +# Functions for each major operation +# ------------------------------------------------------------------------------ + +show_status() { + echo "=== System Time/Date ===" + date + + echo + echo "=== Time Zone ===" + # Attempt to parse the symlink at /etc/localtime + # On many systems, /etc/localtime is a symlink to /usr/share/zoneinfo/Region/City + if [ -L /etc/localtime ]; then + local tz_target + tz_target=$(readlink -f /etc/localtime) + # Remove the /usr/share/zoneinfo/ part to display just Region/City + local tz_name + tz_name="${tz_target#/usr/share/zoneinfo/}" + echo "Time zone: $tz_name" + else + # Some distros have /etc/localtime as a copy of the zone file + # Try to read /etc/timezone as a fallback (Debian-based) + if [ -f /etc/timezone ]; then + echo "Time zone: $(cat /etc/timezone)" + else + echo "Time zone: Unknown (not a symlink, and /etc/timezone missing)" + fi + fi + + echo + echo "=== RTC in local TZ? ===" + # If /etc/adjtime exists and the last line is "LOCAL", that typically indicates localtime + # If it’s "UTC" or absent, the RTC is typically in UTC. + if [ -f /etc/adjtime ]; then + local rtc_mode + rtc_mode=$(tail -n 1 /etc/adjtime) + if [ "$rtc_mode" = "LOCAL" ]; then + echo "RTC is in local time." + else + echo "RTC is in UTC." + fi + else + echo "Cannot determine RTC mode (no /etc/adjtime)." + fi + + echo + echo "=== NTP Service Status ===" + # Attempt to detect if systemd-timesyncd is enabled/active + if command -v systemctl &>/dev/null; then + if systemctl is-enabled systemd-timesyncd &>/dev/null; then + echo "systemd-timesyncd service is enabled." + else + echo "systemd-timesyncd service is disabled." + fi + + if systemctl is-active systemd-timesyncd &>/dev/null; then + echo "systemd-timesyncd service is active (running)." + else + echo "systemd-timesyncd service is not running." + fi + else + echo "systemctl is not available. Cannot determine NTP status this way." + fi + + echo +} + +set_time() { + local new_time="$1" + + if [ -z "$new_time" ]; then + abort "Please specify a time, e.g. '2025-03-21 18:00:00'" + fi + + echo "Setting system time to: $new_time" + # Using 'date' to set system time. + # Format can be e.g. "YYYY-MM-DD HH:MM:SS" + # Usually you need root privileges for this: + if ! date -s "$new_time"; then + abort "Failed to set system time. Check your permissions?" + fi + + # Also sync to hardware clock: + if command -v hwclock &>/dev/null; then + hwclock --systohc || echo "Warning: couldn't sync with HW clock." + fi +} + +list_timezones() { + local zoneinfo_dir="/usr/share/zoneinfo" + if [ ! -d "$zoneinfo_dir" ]; then + abort "Cannot find $zoneinfo_dir directory." + fi + + echo "List of available time zones (under $zoneinfo_dir):" + # We filter out possible files that are not real zone data. + # On some systems, zone data might be in subdirectories (Region/City). + find "$zoneinfo_dir" -type f | sed "s|^$zoneinfo_dir/||" +} + +set_timezone() { + local tz="$1" + + if [ -z "$tz" ]; then + abort "Please specify a time zone, e.g. 'America/New_York'" + fi + + local zoneinfo_file="/usr/share/zoneinfo/$tz" + if [ ! -f "$zoneinfo_file" ]; then + abort "Time zone '$tz' not found under /usr/share/zoneinfo" + fi + + echo "Linking /etc/localtime to $zoneinfo_file" + ln -sf "$zoneinfo_file" /etc/localtime || abort "Failed to link /etc/localtime" + + # Some distros use /etc/timezone to store the name of the current timezone + if [ -w /etc/timezone ]; then + echo "$tz" >/etc/timezone + fi + + echo "Time zone changed to $tz." +} + +set_local_rtc() { + local is_local="$1" + + if [ -z "$is_local" ]; then + abort "Please specify 0 or 1. Example: set-local-rtc 1" + fi + + # We update /etc/adjtime accordingly: + # - If local time: last line should be LOCAL + # - If UTC: last line should be UTC + # We also update the hardware clock accordingly. + if [ "$is_local" = "1" ]; then + echo "Configuring RTC to use local time." + # "hwclock --localtime" is fairly ambiguous (it sets hardware clock from system time). + # We use the below approach: + hwclock --systohc --localtime || echo "Warning: couldn't set HW clock localtime." + # Overwrite /etc/adjtime fully: + cat </etc/adjtime +0.0 0 0.0 +0 +LOCAL +EOF + else + echo "Configuring RTC to use UTC." + hwclock --systohc --utc || echo "Warning: couldn't set HW clock to UTC." + cat </etc/adjtime +0.0 0 0.0 +0 +UTC +EOF + fi +} + +set_ntp() { + local enable_ntp="$1" + if ! command -v systemctl &>/dev/null; then + echo "systemctl not available. Cannot manage systemd-timesyncd. Exiting." + return 1 + fi + + # systemd-timesyncd is the typical built-in NTP client for systemd-based systems + case "$enable_ntp" in + true|True|1|on) + echo "Enabling and starting systemd-timesyncd..." + systemctl enable systemd-timesyncd || echo "Failed to enable timesyncd." + systemctl start systemd-timesyncd || echo "Failed to start timesyncd." + ;; + false|False|0|off) + echo "Disabling and stopping systemd-timesyncd..." + systemctl disable systemd-timesyncd || echo "Failed to disable timesyncd." + systemctl stop systemd-timesyncd || echo "Failed to stop timesyncd." + ;; + *) + abort "Unknown argument '$enable_ntp'. Use 'true' or 'false'." + ;; + esac +} + +# ------------------------------------------------------------------------------ +# Main +# ------------------------------------------------------------------------------ + +main() { + local cmd="$1" + shift || true + + case "$cmd" in + status) + show_status + ;; + set-time) + set_time "$@" + ;; + set-timezone) + set_timezone "$@" + ;; + list-timezones) + list_timezones + ;; + set-local-rtc) + set_local_rtc "$@" + ;; + set-ntp) + set_ntp "$@" + ;; + ""|help|--help|-h) + print_usage + ;; + *) + echo "Unknown command: $cmd" + print_usage + exit 1 + ;; + esac +} + +if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then + if [ $# -lt 1 ]; then + print_usage + exit 0 + fi + main "$@" +fi