diff --git a/cdist/conf/explorer/hostname b/cdist/conf/explorer/hostname
index 7715c6b0..dca004d1 100755
--- a/cdist/conf/explorer/hostname
+++ b/cdist/conf/explorer/hostname
@@ -1,7 +1,6 @@
#!/bin/sh
#
-# 2010-2014 Nico Schottelius (nico-cdist at schottelius.org)
-# 2012 Steven Armstrong (steven-cdist at armstrong.cc)
+# 2019 Dennis Camera (dennis.camera at ssrq-sds-fds.ch)
#
# This file is part of cdist.
#
@@ -19,7 +18,12 @@
# along with cdist. If not, see .
#
#
+# Retrieve the running hostname
+#
-if command -v uname >/dev/null; then
- uname -n
+if command -v hostname >/dev/null
+then
+ hostname
+else
+ uname -n
fi
diff --git a/cdist/conf/type/__hostname/explorer/has_hostnamectl b/cdist/conf/type/__hostname/explorer/has_hostnamectl
index 9040023d..2f531f30 100755
--- a/cdist/conf/type/__hostname/explorer/has_hostnamectl
+++ b/cdist/conf/type/__hostname/explorer/has_hostnamectl
@@ -21,4 +21,4 @@
# Check whether system has hostnamectl
#
-command -v hostnamectl || true
+command -v hostnamectl 2>/dev/null || true
diff --git a/cdist/conf/type/__hostname/explorer/hostname_file b/cdist/conf/type/__hostname/explorer/hostname_file
deleted file mode 100755
index 6a00aa9f..00000000
--- a/cdist/conf/type/__hostname/explorer/hostname_file
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/bin/sh
-#
-# 2014 Nico Schottelius (nico-cdist at schottelius.org)
-#
-# This file is part of cdist.
-#
-# cdist 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.
-#
-# cdist 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 cdist. If not, see .
-#
-#
-# Retrieve the contents of /etc/hostname
-#
-
-# Almost any distribution
-if [ -f /etc/hostname ]; then
- cat /etc/hostname
-# SuSE
-elif [ -f /etc/HOSTNAME ]; then
- cat /etc/HOSTNAME
-fi
diff --git a/cdist/conf/type/__hostname/explorer/hostname_sysconfig b/cdist/conf/type/__hostname/explorer/hostname_sysconfig
deleted file mode 100755
index d0d7b4e7..00000000
--- a/cdist/conf/type/__hostname/explorer/hostname_sysconfig
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/bin/sh
-#
-# 2014 Nico Schottelius (nico-cdist at schottelius.org)
-#
-# This file is part of cdist.
-#
-# cdist 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.
-#
-# cdist 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 cdist. If not, see .
-#
-#
-# Retrieve the contents of /etc/hostname
-#
-
-if [ -f /etc/sysconfig/network ]; then
- awk -F= '/^HOSTNAME=/ { print $2 }' /etc/sysconfig/network
-fi
diff --git a/cdist/conf/type/__hostname/explorer/max_len b/cdist/conf/type/__hostname/explorer/max_len
new file mode 100644
index 00000000..fb863949
--- /dev/null
+++ b/cdist/conf/type/__hostname/explorer/max_len
@@ -0,0 +1,10 @@
+#!/bin/sh -e
+
+command -v getconf >/dev/null || exit 0
+
+val=$(getconf HOST_NAME_MAX 2>/dev/null) || exit 0
+
+if test -n "${val}" -a "${val}" != 'undefined'
+then
+ echo "${val}"
+fi
diff --git a/cdist/conf/type/__hostname/gencode-remote b/cdist/conf/type/__hostname/gencode-remote
index 8b5797dd..ae224611 100755
--- a/cdist/conf/type/__hostname/gencode-remote
+++ b/cdist/conf/type/__hostname/gencode-remote
@@ -2,6 +2,7 @@
#
# 2014-2017 Steven Armstrong (steven-cdist at armstrong.cc)
# 2014 Nico Schottelius (nico-cdist at schottelius.org)
+# 2019 Dennis Camera (dennis.camera at ssrq-sds-fds.ch)
#
# This file is part of cdist.
#
@@ -19,60 +20,81 @@
# along with cdist. If not, see .
#
-if [ -f "$__object/parameter/name" ]; then
- name_should="$(cat "$__object/parameter/name")"
-else
- name_should="${__target_host%%.*}"
-fi
-
os=$(cat "$__global/explorer/os")
name_running=$(cat "$__global/explorer/hostname")
-name_config=$(cat "$__object/explorer/hostname_file")
-name_sysconfig=$(cat "$__object/explorer/hostname_sysconfig")
has_hostnamectl=$(cat "$__object/explorer/has_hostnamectl")
+
+if test -s "$__object/parameter/name"
+then
+ name_should=$(cat "$__object/parameter/name")
+else
+ case $os
+ in
+ # RedHat-derivatives and BSDs
+ centos|fedora|redhat|scientific|freebsd|macosx|netbsd|openbsd)
+ # Hostname is FQDN
+ name_should="${__target_host}"
+ ;;
+ *)
+ # Hostname is only first component of FQDN
+ name_should="${__target_host%%.*}"
+ ;;
+ esac
+fi
+
+
################################################################################
-# If everything is ok -> exit
+# Check if the (running) hostname is already correct
#
-case "$os" in
- archlinux|debian|suse|ubuntu|devuan|coreos|alpine)
- if [ "$name_config" = "$name_should" ] && [ "$name_running" = "$name_should" ]; then
- exit 0
- fi
- ;;
- scientific|centos|freebsd|openbsd)
- if [ "$name_sysconfig" = "$name_should" ] && [ "$name_running" = "$name_should" ]; then
- exit 0
- fi
- ;;
- *)
- echo "Unsupported os: $os" >&2
- exit 1
- ;;
-esac
+test "$name_running" != "$name_should" || exit 0
+
################################################################################
# Setup hostname
#
-echo changed >> "$__messages_out"
+echo 'changed' >>"$__messages_out"
-# Use the good old way to set the hostname even on machines running systemd.
-case "$os" in
- archlinux|debian|ubuntu|devuan|centos|coreos|alpine)
- printf "printf '%%s\\\\n' '$name_should' > /etc/hostname\\n"
- echo "hostname -F /etc/hostname"
+# Use the good old way to set the hostname.
+case $os
+in
+ alpine|debian|devuan|ubuntu)
+ echo 'hostname -F /etc/hostname'
;;
- freebsd|openbsd)
+ archlinux)
+ echo 'command -v hostnamectl >/dev/null 2>&1' \
+ "&& hostnamectl set-hostname '$name_should'" \
+ "|| hostname '$name_should'"
+ ;;
+ centos|fedora|redhat|scientific|freebsd|netbsd|openbsd|gentoo|void)
echo "hostname '$name_should'"
;;
- suse)
+ macosx)
+ echo "scutil --set HostName '$name_should'"
+ ;;
+ solaris)
+ echo "uname -S '$name_should'"
+ ;;
+ slackware|suse|opensuse-leap)
+ # We do not read from /etc/HOSTNAME, because the running
+ # hostname is the first component only while the file contains
+ # the FQDN.
echo "hostname '$name_should'"
- printf "printf '%%s\\\\n' '$name_should' > /etc/HOSTNAME\\n"
+ ;;
+ *)
+ # Fall back to set the hostname using hostnamectl, if available.
+ if test -n "$has_hostnamectl"
+ then
+ # Don't use hostnamectl as the primary means to set the hostname for
+ # systemd systems, because it cannot be trusted to work reliably and
+ # exit with non-zero when it fails (e.g. hostname too long,
+ # D-Bus failure, etc.).
+
+ echo "hostnamectl set-hostname \"\$(cat /etc/hostname)\""
+ echo "test \"\$(hostname)\" = \"\$(cat /etc/hostname)\"" \
+ " || hostname -F /etc/hostname"
+ else
+ printf "echo 'Unsupported OS: %s' >&2\nexit 1\n" "$os"
+ fi
;;
esac
-
-if [ "$has_hostnamectl" ]; then
- # Allow hostnamectl set-hostname to fail silently.
- # Who the fuck invented a tool that needs dbus to set the hostname anyway ...
- echo "hostnamectl set-hostname '$name_should' || true"
-fi
diff --git a/cdist/conf/type/__hostname/man.rst b/cdist/conf/type/__hostname/man.rst
index d23a3b8a..72aefbab 100644
--- a/cdist/conf/type/__hostname/man.rst
+++ b/cdist/conf/type/__hostname/man.rst
@@ -8,7 +8,10 @@ cdist-type__hostname - Set the hostname
DESCRIPTION
-----------
-Set's the hostname on various operating systems.
+Sets the hostname on various operating systems.
+
+**Tip:** For advice on choosing a hostname, see
+`RFC 1178 `_.
REQUIRED PARAMETERS
@@ -18,7 +21,7 @@ None.
OPTIONAL PARAMETERS
-------------------
name
- The hostname to set. Defaults to the first segment of __target_host
+ The hostname to set. Defaults to the first segment of __target_host
(${__target_host%%.*})
diff --git a/cdist/conf/type/__hostname/manifest b/cdist/conf/type/__hostname/manifest
index 8f1adf12..75a90027 100755
--- a/cdist/conf/type/__hostname/manifest
+++ b/cdist/conf/type/__hostname/manifest
@@ -2,6 +2,7 @@
#
# 2012 Steven Armstrong (steven-cdist at armstrong.cc)
# 2014 Nico Schottelius (nico-cdist at schottelius.org)
+# 2019 Dennis Camera (dennis.camera at ssrq-sds-fds.ch)
#
# This file is part of cdist.
#
@@ -19,50 +20,170 @@
# along with cdist. If not, see .
#
+not_supported() {
+ 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
+}
+
+set_hostname_systemd() {
+ echo "$1" | __file /etc/hostname --source -
+}
+
os=$(cat "$__global/explorer/os")
-if [ -f "$__object/parameter/name" ]; then
- name_should="$(cat "$__object/parameter/name")"
+os_version=$(cat "$__global/explorer/os_version")
+os_major=$(echo "$os_version" | grep -o '^[0-9][0-9]*')
+
+max_len=$(cat "$__object/explorer/max_len")
+has_hostnamectl=$(cat "$__object/explorer/has_hostnamectl")
+
+if test -s "$__object/parameter/name"
+then
+ name_should=$(cat "$__object/parameter/name")
else
- case "$os" in
- openbsd)
- name_should="${__target_host}"
- ;;
- *)
- name_should="${__target_host%%.*}"
- ;;
+ case $os
+ in
+ # RedHat-derivatives and BSDs
+ centos|fedora|redhat|scientific|freebsd|netbsd|openbsd|slackware)
+ # Hostname is FQDN
+ name_should="${__target_host}"
+ ;;
+ suse|opensuse-leap)
+ # Classic SuSE stores the FQDN in /etc/HOSTNAME, while
+ # systemd does not. The running hostname is the first
+ # component in both cases.
+ # In versions before 15.x, the FQDN is stored in /etc/hostname.
+ if test -n "$has_hostnamectl" && test "$os_major" -ge 15 \
+ && test "$os_major" -ne 42
+ then
+ name_should="${__target_host%%.*}"
+ else
+ name_should="${__target_host}"
+ fi
+ ;;
+ *)
+ # Hostname is only first component of FQDN on all other systems.
+ name_should="${__target_host%%.*}"
+ ;;
esac
fi
+if test -n "$max_len" && test "$(printf '%s' "$name_should" | wc -c)" -gt "$max_len"
+then
+ printf "Host name too long. Up to %u characters allowed.\n" "${max_len}" >&2
+ exit 1
+fi
-not_supported() {
- 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
-}
+case $os
+in
+ alpine|debian|devuan|ubuntu|void)
+ echo "$name_should" | __file /etc/hostname --source -
+ ;;
+ archlinux)
+ if test -n "$has_hostnamectl"
+ then
+ set_hostname_systemd "$name_should"
+ else
+ echo 'Ancient ArchLinux variants without hostnamectl are not supported.' >&2
+ exit 1
+ # Only for ancient ArchLinux, write to /etc/rc.conf on pre-systemd
+ # versions. There are some versions which use /etc/hostname but not
+ # systemd. It is unclear which ones these are.
-case "$os" in
- archlinux|debian|suse|ubuntu|devuan|coreos|alpine)
+ # __key_value '/etc/rc.conf:HOSTNAME' \
+ # --file /etc/rc.conf \
+ # --delimiter '=' --exact_delimiter \
+ # --key 'HOSTNAME' \
+ # --value "\"$name_should\""
+ fi
+ ;;
+ centos|fedora|redhat|scientific)
+ if test -z "$has_hostnamectl"
+ then
+ # Only write to /etc/sysconfig/network on non-systemd versions.
+ # On systemd-based versions this entry is ignored.
+ __key_value '/etc/sysconfig/network:HOSTNAME' \
+ --file /etc/sysconfig/network \
+ --delimiter '=' --exact_delimiter \
+ --key HOSTNAME \
+ --value "\"$name_should\""
+ else
+ set_hostname_systemd "$name_should"
+ fi
+ ;;
+ gentoo)
+ # Only write to /etc/conf.d/hostname on OpenRC-based installations.
+ # On systemd use hostnamectl(1) in gencode-remote.
+ if test -z "$has_hostnamectl"
+ then
+ __key_value '/etc/conf.d/hostname:hostname' \
+ --file /etc/conf.d/hostname \
+ --delimiter '=' --exact_delimiter \
+ --key 'hostname' \
+ --value "\"$name_should\""
+ else
+ set_hostname_systemd "$name_should"
+ fi
+ ;;
+ freebsd)
+ __key_value '/etc/rc.conf:hostname' \
+ --file /etc/rc.conf \
+ --delimiter '=' --exact_delimiter \
+ --key 'hostname' \
+ --value "\"$name_should\""
+ ;;
+ macosx)
# handled in gencode-remote
:
;;
- scientific|centos)
- __key_value sysconfig-hostname \
- --file /etc/sysconfig/network \
- --delimiter '=' \
- --key HOSTNAME \
- --value "$name_should" --exact_delimiter
- ;;
- freebsd)
- __key_value rcconf-hostname \
+ netbsd)
+ __key_value '/etc/rc.conf:hostname' \
--file /etc/rc.conf \
- --delimiter '=' \
+ --delimiter '=' --exact_delimiter \
--key 'hostname' \
- --value "$name_should"
+ --value "\"$name_should\""
+
+ # To avoid confusion, ensure that the hostname is only stored once.
+ __file /etc/myname --state absent
;;
openbsd)
echo "$name_should" | __file /etc/myname --source -
;;
+ slackware)
+ # We write the FQDN into /etc/HOSTNAME. But /etc/rc.d/rc.M will only
+ # read the first component from this file and set it as the running
+ # hostname on boot.
+ echo "$name_should" | __file /etc/HOSTNAME --source -
+ ;;
+ solaris)
+ echo "$name_should" | __file /etc/nodename --source -
+ ;;
+ suse|opensuse-leap)
+ # Modern SuSE provides /etc/HOSTNAME as a symlink for
+ # backwards-compatibility. Unfortunately it cannot be used
+ # here as __file does not follow the symlink.
+ # Therefore, we use the presence of the hostnamectl binary as
+ # an indication of which file to use. This unfortunately does
+ # not work correctly on openSUSE 12.x which provides
+ # hostnamectl but not /etc/hostname.
+
+ if test -n "$has_hostnamectl" -a "$os_major" -gt 12
+ then
+ hostname_file='/etc/hostname'
+ else
+ hostname_file='/etc/HOSTNAME'
+ fi
+
+ echo "$name_should" | __file "$hostname_file" --source -
+ ;;
*)
- not_supported
+ # On other operating systems we fall back to systemd's
+ # hostnamectl if available…
+ if test -n "$has_hostnamectl"
+ then
+ set_hostname_systemd "$name_should"
+ else
+ not_supported
+ fi
;;
esac