diff --git a/type/__timezone/explorer/timezone_is b/type/__timezone/explorer/timezone_is deleted file mode 100755 index 6f72a9248..000000000 --- a/type/__timezone/explorer/timezone_is +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/sh -e -# -# 2017 Ander Punnar (ander at kvlt.ee) -# -# This file is part of skonfig-base. -# -# skonfig-base is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# skonfig-base is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with skonfig-base. If not, see . -# -# Prints the contents of /etc/timezone. -# - -[ -f /etc/timezone ] && cat /etc/timezone - -exit 0 diff --git a/type/__timezone/explorer/zoneinfo_file b/type/__timezone/explorer/zoneinfo_file new file mode 100755 index 000000000..e8990774f --- /dev/null +++ b/type/__timezone/explorer/zoneinfo_file @@ -0,0 +1,61 @@ +#!/bin/sh -e +# +# 2020 Dennis Camera (dennis.camera at riiengineering.ch) +# +# This file is part of skonfig-base. +# +# skonfig-base is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# skonfig-base is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with skonfig-base. If not, see . +# +# Determine and print the path of the --tz zoneinfo file. +# If the zone is invalid, the explorer produces empty output. +# + +TZ=$(cat "${__object:?}/parameter/tz") + +if test -s "${__object:?}/parameter/tzdir" +then + TZDIR=$(cat "${__object:?}/parameter/tzdir") + + test -d "${TZDIR}" || { + printf 'Invalid --tzdir: no such directory: %s\n' "${TZDIR}" >&2 + exit 1 + } +else + case $(uname -s) + in + (Darwin) + TZDIR=/var/db/timezone/zoneinfo + ;; + (SunOS) + TZDIR=/usr/share/lib/zoneinfo + ;; + (*) + # According to glibc's tzfile(5) there are two typical directories: + if test -d /usr/share/zoneinfo + then + # Linux, FreeBSD, OpenBSD, NetBSD. And others? + TZDIR=/usr/share/zoneinfo + elif test -d /usr/lib/zoneinfo + then + # Old libc4, libc5 apparently. + TZDIR=/usr/lib/zoneinfo + fi + ;; + esac +fi + +if test -n "${TZDIR-}" && test -e "${TZDIR}/${TZ}" +then + echo "${TZDIR}/${TZ}" +fi diff --git a/type/__timezone/gencode-remote b/type/__timezone/gencode-remote deleted file mode 100755 index a3101122d..000000000 --- a/type/__timezone/gencode-remote +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/sh -e -# -# 2012 Steven Armstrong (steven-cdist at armstrong.cc) -# 2019 Nico Schottelius (nico-cdist at schottelius.org) -# -# This file is part of skonfig-base. -# -# skonfig-base is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# skonfig-base is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with skonfig-base. If not, see . -# - -timezone_is=$(cat "${__object:?}/explorer/timezone_is") -timezone_should=$(cat "${__object:?}/parameter/tz") -os=$(cat "${__global:?}/explorer/os") - -if [ "${timezone_is}" = "${timezone_should}" ] -then - exit 0 -fi - -case ${os} -in - (ubuntu|debian|devuan|coreos|alpine) - echo "echo \"${timezone_should}\" >/etc/timezone" - ;; -esac diff --git a/type/__timezone/man.rst b/type/__timezone/man.rst index 801671d1a..b4106ad37 100644 --- a/type/__timezone/man.rst +++ b/type/__timezone/man.rst @@ -3,13 +3,18 @@ cdist-type__timezone(7) NAME ---- -cdist-type__timezone - Allows one to configure the desired localtime timezone. +cdist-type__timezone - Configure the system timezone. DESCRIPTION ----------- -This type creates a symlink (/etc/localtime) to the selected timezone -(which should be available in /usr/share/zoneinfo). +This type creates a symlink (``/etc/localtime``) to the selected +timezone (which should be available in ``--tzdir`` which is usually +``/usr/share/zoneinfo``). + +On some operating systems, other system-specific files are modified as well. + +If necessary, the zoneinfo database (``tzdata``) will be installed on the target. REQUIRED PARAMETERS @@ -17,6 +22,16 @@ REQUIRED PARAMETERS tz The name of the timezone to set. + It should map to a file present in ``--tzdir``. + + +OPTIONAL PARAMETERS +------------------- +tzdir + The directory containing the timezone data files on the target. + + Default: detected based on OS, usually ``/usr/share/zoneinfo``. + EXAMPLES -------- @@ -29,6 +44,12 @@ EXAMPLES # Set up US/Central as our timezone. __timezone --tz US/Central + # Some operating systems (e.g. Debian, RedHat, SuSE) have a separate + # directory for POSIX timezones (time values interpreted as seconds since + # the epoch, not counting leap seconds). + # It can be used by manually specifying the TZDIR. + __timezone --tz Europe/Vaduz --tzdir /usr/share/zoneinfo/posix + AUTHORS ------- @@ -40,7 +61,7 @@ AUTHORS COPYING ------- -Copyright \(C) 2012-2020 the `AUTHORS`_. +Copyright \(C) 2012-2025 the `AUTHORS`_. You can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. diff --git a/type/__timezone/manifest b/type/__timezone/manifest index 05bd90375..7322cfd3e 100755 --- a/type/__timezone/manifest +++ b/type/__timezone/manifest @@ -3,6 +3,7 @@ # 2011 Ramon Salvadó (rsalvado at gnuine.com) # 2012-2015 Steven Armstrong (steven-cdist at armstrong.cc) # 2012-2019 Nico Schottelius (nico-cdist at schottelius.org) +# 2020,2025 Dennis Camera (dennis.camera at riiengineering.ch) # # This file is part of skonfig-base. # @@ -20,47 +21,173 @@ # along with skonfig-base. If not, see . # -timezone=$(cat "${__object:?}/parameter/tz") +TZ=$(cat "${__object:?}/parameter/tz") os=$(cat "${__global:?}/explorer/os") +localtime_file=/etc/localtime +zoneinfo_file=$(cat "${__object:?}/explorer/zoneinfo_file") +canonicalize_path() { + # NOTE: Only works for absolute paths + # shellcheck disable=SC2016 + printf '%s\n' "${1:?}" \ + | tr '/' '\n' \ + | sed -n -e ' + # ignore empty lines (produced by // in original path and leading /) + /^$/bq + # ignore /./ components + /^\.$/bq + # drop a component from the "stack" if a .. is met + /^\.\.$/{ + # delete last line from hold space + x + s/^\(.*\)\n.*$/\1/ + x + bq + } + # push component to "stack" (append to hold space) + H + :q + # print stack contents (hold space) at the end + ${x;p;}' \ + | sed -n -e 'H;${g;s/^\n//;s/\n/\//g;p;}' +} + +count_path_components() ( + components=$(canonicalize_path "$1") + IFS=/ + # shellcheck disable=SC2048,SC2086 + set -f -- ${components#/} + echo $# +) + +backdirs() { + test "${1:-0}" -gt 0 || { printf './\n'; return 0; } + until test "${1:-0}" -le 0 + do + printf '../' + set -- $(($1 - 1)) + done + printf '\n' +} + +invalid_timezone() { + # NOTE: When the tzdata package was just installed, this might produce an + # invalid timezone error because the explorer has been run before the + # installation. + printf 'Invalid timezone: %s\n' "${TZ}" >&2 + exit 1 +} + +# some OSes require a timezone package to be installed first +case ${os} +in + (adelie|alpine|archlinux|debian|devuan|ubuntu|centos|redhat|scientific|voidlinux) + __package tzdata + export require=__package/tzdata + ;; + (gentoo) + __package sys-libs/timezone-data + export require=__package/sys-libs/timezone-data + ;; + (suse) + __package timezone + export require=__package/timezone + ;; + (slackware) + __package glibc-zoneinfo + export require=__package/glibc-zoneinfo + ;; +esac + +# configure the timezone case ${os} in - (archlinux|debian|ubuntu|devuan|alpine) - __package tzdata - export require='__package/tzdata' - ;; - (suse) - __package timezone - export require='__package/timezone' - ;; - (freebsd|netbsd|openbsd) - # whitelist - : - ;; - (coreos) - # whitelist - : - ;; - (scientific|centos) - __package tzdata --state present - export require='__package/tzdata' - __file /etc/sysconfig/clock \ - --owner root --group root --mode 644 \ - --state exists - require='__file/etc/sysconfig/clock' \ - __key_value ZONE \ - --file /etc/sysconfig/clock \ - --delimiter '=' \ - --value "\"${timezone}\"" - ;; - (*) - : "${__type:?}" # make shellcheck happy - echo "Your operating system (${os}) is currently not supported by this type (${__type##*/})." >&2 - echo 'Please contribute an implementation for it if you can.' >&2 - exit 1 - ;; + (adelie|alpine|slackware) + test -n "${zoneinfo_file}" || invalid_timezone + ;; + (coreos|debian|devuan|ubuntu) + test -n "${zoneinfo_file}" || invalid_timezone + + __file /etc/timezone \ + --owner 0 --group 0 --mode 0644 \ + --source - <<-EOF + ${TZ} + EOF + ;; + (centos|redhat|scientific) + test -n "${zoneinfo_file}" || invalid_timezone + + __file /etc/sysconfig/clock \ + --state exists \ + --owner 0 --group 0 --mode 0644 + require=__file/etc/sysconfig/clock \ + __key_value /etc/sysconfig/clock:ZONE \ + --file /etc/sysconfig/clock \ + --delimiter '=' --exact_delimiter \ + --key 'ZONE' \ + --value "\"${TZ}\"" + ;; + (gentoo) + test -n "${zoneinfo_file}" || invalid_timezone + + # XXX: systemd? + + __file /etc/timezone \ + --owner 0 --group 0 --mode 0644 \ + --source - <<-EOF + ${TZ} + EOF + + # XXX: Should /etc/TZ be updated?? + __file /etc/TZ \ + --owner 0 --group 0 --mode 0644 \ + --source - <<-EOF + ${TZ} + EOF + ;; + (freebsd) + test -n "${zoneinfo_file}" || invalid_timezone + + __file /var/db/zoneinfo \ + --owner 0 --group 0 --mode 0644 \ + --source - <<-EOF + ${TZ} + EOF + ;; + (suse) + os_version=$(cat "${__global:?}/explorer/os_version") + os_major=${os_version%%[!0-9]*} + + # TODO: Consider using `yast2 timezone ...` instead + if test $((os_major)) -lt 15 || test $((os_major)) -eq 42 + then + # It seems that starting with SuSE 15 /etc/sysconfig/clock is + # abandoned. The file still exists but only contains a + # DEFAULT_TIMEZONE entry. + __key_value /etc/sysconfig/clock:TIMEZONE \ + --file /etc/sysconfig/clock \ + --delimiter '=' --exact_delimiter \ + --key TIMEZONE --value "\"${TZ}\"" + fi + ;; + (voidlinux) + test -n "${zoneinfo_file}" || invalid_timezone + + __key_value /etc/rc.conf:TIMEZONE \ + --file /etc/rc.conf \ + --key TIMEZONE \ + --delimiter '=' --exact_delimiter \ + --value "\"${TZ}\"" + ;; + (*) + : "${__type:?}" # make shellcheck happy + echo "Your operating system (${os}) is currently not supported by this type (${__type##*/})." >&2 + echo 'Please contribute an implementation for it if you can.' >&2 + exit 1 + ;; esac -__link /etc/localtime \ - --source "/usr/share/zoneinfo/${timezone}" \ - --type symbolic +rel_zoneinfo_file="$(backdirs "$(count_path_components "${localtime_file%/*}")")${zoneinfo_file#/}" +__link "${localtime_file}" \ + --type symbolic \ + --source "${rel_zoneinfo_file}" diff --git a/type/__timezone/parameter/optional b/type/__timezone/parameter/optional new file mode 100644 index 000000000..d0719869f --- /dev/null +++ b/type/__timezone/parameter/optional @@ -0,0 +1 @@ +tzdir