- das-helpers replaces the dsv package and adds shared functions in /usr/lib/das/helpers.sh (bilingual messages, sudo re-exec, prompts). - dsv new creates a runit service (command, user, directory, environment, svlogd log) and checks it stays up; dsv rm deletes one not from a package. - duser: list, add (installer groups, --admin, key, password), del, passwd, lock/unlock (key logins too), key add|list|rm, groups +/-. - dfw: allow/deny/status/reload for the tcp_ports and udp_ports sets of the inet das table, kept in /etc/nftables.d/dfw.nft and checked with nft -c. - dsys: info, hostname, timezone, locale, keymap. - xtools-minimal on both images. - nftables.conf no longer suggests restarting the nftables service: its finish script flushes the whole ruleset, fail2ban's and Docker's included. - das-server-install 0.2.0 mentions the helpers when it finishes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
248 lines
8.8 KiB
Bash
Executable File
248 lines
8.8 KiB
Bash
Executable File
#!/bin/bash
|
||
# dsys - system settings on Das OS: host name, time zone, language and
|
||
# console keyboard, in place of hostnamectl, timedatectl and localectl.
|
||
set -euo pipefail
|
||
|
||
# shellcheck source=helpers.sh
|
||
. "${DAS_HELPERS:-/usr/lib/das/helpers.sh}"
|
||
|
||
zoneinfo=/usr/share/zoneinfo
|
||
libc_locales=/etc/default/libc-locales
|
||
keymaps=/usr/share/kbd/keymaps
|
||
|
||
usage() {
|
||
if [[ -n $uk ]]; then
|
||
cat <<'EOF'
|
||
Використання: dsys [КОМАНДА] [ЗНАЧЕННЯ]
|
||
|
||
info огляд системи (типова команда)
|
||
hostname [ІМ'Я] показати або змінити ім'я хоста
|
||
timezone [ЗОНА] показати або змінити часовий пояс (Europe/Kyiv,
|
||
достатньо й частини назви: Kyiv)
|
||
timezone list [ФІЛЬТР] усі часові пояси
|
||
locale [МОВА] показати або змінити мову системи (uk_UA, en_US)
|
||
locale list [ФІЛЬТР] доступні мови; * — уже зібрані
|
||
keymap [РОЗКЛАДКА] показати або змінити розкладку консолі (us, ua-utf)
|
||
keymap list [ФІЛЬТР] доступні розкладки консолі
|
||
|
||
Мову й розкладку графічного сеансу кожен користувач задає в налаштуваннях
|
||
Xfce і в das-welcome; dsys змінює типові для системи й консолі.
|
||
EOF
|
||
else
|
||
cat <<'EOF'
|
||
Usage: dsys [COMMAND] [VALUE]
|
||
|
||
info system overview (the default)
|
||
hostname [NAME] show or change the host name
|
||
timezone [ZONE] show or change the time zone (Europe/Kyiv,
|
||
part of the name will do: Kyiv)
|
||
timezone list [FILTER] all time zones
|
||
locale [LANGUAGE] show or change the system language (uk_UA, en_US)
|
||
locale list [FILTER] available languages; * marks the built ones
|
||
keymap [MAP] show or change the console keyboard map (us, ua-utf)
|
||
keymap list [FILTER] available console keyboard maps
|
||
|
||
In the graphical session every user picks the language and keyboard in the
|
||
Xfce settings and in das-welcome; dsys changes the system and console defaults.
|
||
EOF
|
||
fi
|
||
}
|
||
|
||
current_hostname() {
|
||
cat /etc/hostname 2>/dev/null || hostname
|
||
}
|
||
|
||
current_timezone() {
|
||
local tz
|
||
tz=$(readlink /etc/localtime 2>/dev/null || true)
|
||
echo "${tz#*zoneinfo/}"
|
||
}
|
||
|
||
current_locale() {
|
||
sed -n 's/^LANG=//p' /etc/locale.conf 2>/dev/null | tr -d '"'
|
||
}
|
||
|
||
rc_value() {
|
||
sed -n "s/^$1=//p" /etc/rc.conf 2>/dev/null | tr -d '"' | tail -n 1
|
||
}
|
||
|
||
# A graphical session keeps its X authority under the old host name
|
||
session_warning() {
|
||
if pgrep -x lightdm >/dev/null || [[ -n ${DISPLAY:-} ]]; then
|
||
say "Перезавантажте комп'ютер: графічний сеанс не відкриватиме нових вікон зі старим іменем." \
|
||
"Reboot: the graphical session will not open new windows under the old name."
|
||
fi
|
||
}
|
||
|
||
# 3 д 4 год 5 хв / 3 d 4 h 5 min
|
||
uptime_text() {
|
||
local s d h m
|
||
read -r s _ </proc/uptime
|
||
s=${s%.*}
|
||
d=$((s / 86400))
|
||
h=$((s % 86400 / 3600))
|
||
m=$((s % 3600 / 60))
|
||
if ((d > 0)); then
|
||
say "$d д $h год $m хв" "$d d $h h $m min"
|
||
elif ((h > 0)); then
|
||
say "$h год $m хв" "$h h $m min"
|
||
else
|
||
say "$m хв" "$m min"
|
||
fi
|
||
}
|
||
|
||
cmd_info() {
|
||
local ntp line
|
||
pad "$(say "Ім'я хоста:" "Host name:")" 16; current_hostname
|
||
pad "$(say "Система:" "System:")" 16; echo "$(uname -sr), $(uname -m)"
|
||
pad "$(say "Працює:" "Up:")" 16; uptime_text
|
||
pad "$(say "Час:" "Time:")" 16; date '+%Y-%m-%d %H:%M:%S %Z'
|
||
pad "$(say "Часовий пояс:" "Time zone:")" 16; current_timezone
|
||
if ntp=$(chronyc -n tracking 2>/dev/null); then
|
||
if grep -q '^Leap status *: Normal' <<<"$ntp"; then
|
||
ntp=$(say "синхронізовано (chrony)" "synchronized (chrony)")
|
||
else
|
||
ntp=$(say "не синхронізовано (chrony)" "not synchronized (chrony)")
|
||
fi
|
||
else
|
||
ntp=$(say "не працює (dsv enable chronyd)" "not running (dsv enable chronyd)")
|
||
fi
|
||
pad "$(say "Синхронізація:" "Time sync:")" 16; echo "$ntp"
|
||
pad "$(say "Мова:" "Language:")" 16; current_locale
|
||
pad "$(say "Консоль:" "Console:")" 16
|
||
echo "$(say розкладка keymap) $(rc_value KEYMAP || true), $(say шрифт font) $(rc_value FONT || true)"
|
||
say "Мережа:" "Network:"
|
||
ip -brief address 2>/dev/null | while read -r line; do
|
||
[[ $line == lo\ * ]] || echo " $line"
|
||
done
|
||
}
|
||
|
||
cmd_hostname() {
|
||
local new=${1:-} old
|
||
if [[ -z $new ]]; then
|
||
current_hostname
|
||
return
|
||
fi
|
||
[[ $new =~ ^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?(\.[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*$ ]] ||
|
||
die "'$new': малі латинські літери, цифри й дефіс (не на початку й не в кінці)" \
|
||
"'$new': lowercase Latin letters, digits and hyphens (not first or last)"
|
||
need_root hostname "$new"
|
||
old=$(current_hostname)
|
||
echo "$new" >/etc/hostname
|
||
# The installers add "127.0.1.1 <name>"; keep the line in step
|
||
if grep -qw -- "$old" /etc/hosts; then
|
||
sed -i "/^[^#]/s/\([[:space:]]\)${old//./\\.}\([[:space:]]\|$\)/\1$new\2/g" /etc/hosts
|
||
fi
|
||
grep -qw -- "$new" /etc/hosts || printf '127.0.1.1\t%s\n' "$new" >>/etc/hosts
|
||
hostname "$new"
|
||
say "Ім'я хоста: $new" "Host name: $new"
|
||
session_warning
|
||
}
|
||
|
||
# All time zones, from tzdata's table plus UTC
|
||
timezones() {
|
||
{ awk '!/^#/ { print $3 }' "$zoneinfo/zone1970.tab"; echo UTC; } | sort -u
|
||
}
|
||
|
||
cmd_timezone() {
|
||
local zone=${1:-} matches line
|
||
if [[ -z $zone ]]; then
|
||
current_timezone
|
||
return
|
||
fi
|
||
if [[ $zone == list ]]; then
|
||
timezones | grep -i -- "${2:-}" || true
|
||
return
|
||
fi
|
||
if ! timezones | grep -qx -- "$zone"; then
|
||
# Kyiv -> Europe/Kyiv, when only one zone matches
|
||
matches=$(timezones | grep -i -- "$zone" || true)
|
||
if [[ $(grep -c . <<<"$matches") -eq 1 ]]; then
|
||
zone=$matches
|
||
elif [[ -n $matches ]]; then
|
||
say "Кілька часових поясів підходять, уточніть:" "Several time zones match, be more specific:" >&2
|
||
head -n 20 <<<"$matches" | while read -r line; do echo " $line"; done >&2
|
||
(($(grep -c . <<<"$matches") <= 20)) || echo " ..." >&2
|
||
exit 1
|
||
else
|
||
die "невідомий часовий пояс '$zone' (dsys timezone list)" "unknown time zone '$zone' (dsys timezone list)"
|
||
fi
|
||
fi
|
||
need_root timezone "$zone"
|
||
ln -sfn "$zoneinfo/$zone" /etc/localtime
|
||
say "Часовий пояс: $zone, зараз $(date '+%H:%M %Z')" "Time zone: $zone, now $(date '+%H:%M %Z')"
|
||
}
|
||
|
||
# Every UTF-8 locale glibc can build, with * for the enabled ones
|
||
locales() {
|
||
sed -n 's/^\(#\?\)\([^ ]*\.UTF-8\) UTF-8[[:space:]]*$/\2 \1/p' "$libc_locales" |
|
||
awk '{ print ($2 == "#" ? " " : "* ") $1 }'
|
||
}
|
||
|
||
cmd_locale() {
|
||
local lang=${1:-} re
|
||
if [[ -z $lang ]]; then
|
||
current_locale
|
||
return
|
||
fi
|
||
if [[ $lang == list ]]; then
|
||
locales | grep -i -- "${2:-}" || true
|
||
return
|
||
fi
|
||
[[ $lang == *.* ]] || lang+=.UTF-8
|
||
re=${lang//./\\.}
|
||
locales | grep -q "^. $re\$" ||
|
||
die "невідома мова '$lang' (dsys locale list)" "unknown language '$lang' (dsys locale list)"
|
||
need_root locale "$lang"
|
||
if grep -q "^#$re " "$libc_locales"; then
|
||
sed -i "s/^#\($re \)/\1/" "$libc_locales"
|
||
say "Збираю $lang..." "Building $lang..."
|
||
xbps-reconfigure -f glibc-locales >/dev/null
|
||
fi
|
||
# Keep the other settings, Void's default file also has LC_COLLATE=C
|
||
if grep -q '^LANG=' /etc/locale.conf 2>/dev/null; then
|
||
sed -i "s/^LANG=.*/LANG=$lang/" /etc/locale.conf
|
||
else
|
||
echo "LANG=$lang" >>/etc/locale.conf
|
||
fi
|
||
say "Мова системи: $lang (діє з наступного входу)" "System language: $lang (from the next login)"
|
||
}
|
||
|
||
cmd_keymap() {
|
||
local map=${1:-}
|
||
if [[ -z $map ]]; then
|
||
rc_value KEYMAP
|
||
return
|
||
fi
|
||
if [[ $map == list ]]; then
|
||
find "$keymaps" -name '*.map.gz' -printf '%f\n' | sed 's/\.map\.gz$//' | sort -u | grep -i -- "${2:-}" || true
|
||
return
|
||
fi
|
||
[[ -n $(find "$keymaps" -name "$map.map.gz" -print -quit) ]] ||
|
||
die "невідома розкладка '$map' (dsys keymap list)" "unknown keyboard map '$map' (dsys keymap list)"
|
||
need_root keymap "$map"
|
||
set_rc KEYMAP "$map"
|
||
# The default console font has no Cyrillic letters
|
||
if [[ $map == @(ua|ru|by|bg|mk|sr)* && -z $(rc_value FONT) ]]; then
|
||
set_rc FONT cyr-sun16
|
||
fi
|
||
loadkeys "$map" >/dev/null 2>&1 || true
|
||
say "Розкладка консолі: $map" "Console keyboard map: $map"
|
||
}
|
||
|
||
cmd=${1:-info}
|
||
[[ $# -gt 0 ]] && shift
|
||
|
||
case $cmd in
|
||
info | status) cmd_info ;;
|
||
hostname | host) cmd_hostname "$@" ;;
|
||
timezone | tz) cmd_timezone "$@" ;;
|
||
locale | lang) cmd_locale "$@" ;;
|
||
keymap | keyboard) cmd_keymap "$@" ;;
|
||
-h | --help | help) usage ;;
|
||
*)
|
||
usage >&2
|
||
exit 1
|
||
;;
|
||
esac
|