mailinabox/setup/functions.sh

143 lines
4.2 KiB
Bash

function hide_output {
# This function hides the output of a command unless the command fails
# and returns a non-zero exit code.
# Get a temporary file.
OUTPUT=$(tempfile)
# Execute command, redirecting stderr/stdout to the temporary file.
$@ &> $OUTPUT
# If the command failed, show the output that was captured in the temporary file.
if [ $? != 0 ]; then
# Something failed.
echo
echo FAILED: $@
echo -----------------------------------------
cat $OUTPUT
echo -----------------------------------------
fi
# Remove temporary file.
rm -f $OUTPUT
}
function apt_install {
# Report any packages already installed.
PACKAGES=$@
TO_INSTALL=""
ALREADY_INSTALLED=""
for pkg in $PACKAGES; do
if dpkg -s $pkg 2>/dev/null | grep "^Status: install ok installed" > /dev/null; then
if [[ ! -z "$ALREADY_INSTALLED" ]]; then ALREADY_INSTALLED="$ALREADY_INSTALLED, "; fi
ALREADY_INSTALLED="$ALREADY_INSTALLED$pkg (`dpkg -s $pkg | grep ^Version: | sed -e 's/.*: //'`)"
else
TO_INSTALL="$TO_INSTALL""$pkg "
fi
done
# List the packages already installed.
if [[ ! -z "$ALREADY_INSTALLED" ]]; then
echo already installed: $ALREADY_INSTALLED
fi
# List the packages about to be installed.
if [[ ! -z "$TO_INSTALL" ]]; then
echo installing $TO_INSTALL...
fi
# 'DEBIAN_FRONTEND=noninteractive' is to prevent dbconfig-common from asking you questions.
# Although we could pass -qq to apt-get to make output quieter, many packages write to stdout
# and stderr things that aren't really important. Use our hide_output function to capture
# all of that and only show it if there is a problem (i.e. if apt_get returns a failure exit status).
DEBIAN_FRONTEND=noninteractive \
hide_output \
apt-get -y install $PACKAGES
}
function get_default_hostname {
# Guess the machine's hostname. It should be a fully qualified
# domain name suitable for DNS. None of these calls may provide
# the right value, but it's the best guess we can make.
set -- $(hostname --fqdn 2>/dev/null ||
hostname --all-fqdns 2>/dev/null ||
hostname 2>/dev/null)
printf '%s\n' "$1" # return this value
}
function get_default_publicip {
# Get the machine's public IP address. The machine might have
# an IP on a private network, but the IP address that we put
# into DNS must be one on the public Internet. Try a public
# API, but if that fails (maybe we don't have Internet access
# right now) then use the IP address that this machine knows
# itself as.
get_publicip_from_web_service || get_publicip_fallback
}
function get_default_publicipv6 {
get_publicipv6_from_web_service || get_publicipv6_fallback
}
function get_publicip_from_web_service {
# This seems to be the most reliable way to determine the
# machine's public IP address: asking a very nice web API
# for how they see us. Thanks go out to icanhazip.com.
curl -4 --fail --silent icanhazip.com 2>/dev/null
}
function get_publicipv6_from_web_service {
curl -6 --fail --silent icanhazip.com 2>/dev/null
}
function get_publicip_fallback {
# Return the IP address that this machine knows itself as.
# It certainly may not be the IP address that this machine
# operates as on the public Internet. The machine might
# have multiple addresses if it has multiple network adapters.
set -- $(hostname --ip-address 2>/dev/null) \
$(hostname --all-ip-addresses 2>/dev/null)
while (( $# )) && { ! is_ipv4 "$1" || is_loopback_ip "$1"; }; do
shift
done
printf '%s\n' "$1" # return this value
}
function get_publicipv6_fallback {
set -- $(hostname --ip-address 2>/dev/null) \
$(hostname --all-ip-addresses 2>/dev/null)
while (( $# )) && { ! is_ipv6 "$1" || is_loopback_ipv6 "$1"; }; do
shift
done
printf '%s\n' "$1" # return this value
}
function is_ipv4 {
# helper for get_publicip_fallback
[[ "$1" == *.*.*.* ]]
}
function is_ipv6 {
[[ "$1" == *:*:* ]]
}
function is_loopback_ip {
# helper for get_publicip_fallback
[[ "$1" == 127.* ]]
}
function is_loopback_ipv6 {
[[ "$1" == ::1 ]]
}
function ufw_allow {
if [ -z "$DISABLE_FIREWALL" ]; then
# ufw has completely unhelpful output
ufw allow $1 > /dev/null;
fi
}
function restart_service {
hide_output service $1 restart
}