view packaging/linux-installer.inc.in @ 1038:f5306f8c02f3

packaging/linux-installer: Copyright header changed to standard text.
author Bernhard Reiter <bernhard@intevation.de>
date Thu, 04 Sep 2014 15:09:44 +0200
parents 8be2f510adbf
children 43734932e2ea
line wrap: on
line source
#!/bin/bash
set -u

ME=`basename "$0"`
DEFAULT_PREFIX="$HOME/TrustBridge"
SYSDEFAULT_PREFIX="/usr/local"
CFGPATH="${XDG_CONFIG_HOME:-$HOME/.config}/BSI"
DATAPATH="${XDG_DATA_HOME:-$HOME/.local/share}/BSI/TrustBridge"
SYSCFGPATH="/etc/TrustBridge"
# FIXME:
# Set the real data path for system wide installation once its known.
SYSDATAPATH="$DATAPATH"
INSTCFGNAME="TrustBridge-inst.cfg"
FORCE=0
SYSINST=0
DEINSTALL=0
BINNAMES="###BINNAMES###"
ICONNAME="###ICONNAME###"
HELPNAMES="###HELPNAMES###"
HELPNAMES_SOURCES="###HELPNAMES_SOURCES###"
HELPNAMES_STATIC="###HELPNAMES_STATIC###"
HELPNAMES_IMG="###HELPNAMES_IMG###"
ARCH="###ARCH###"

declare -A instcfg oldinstcfg
declare inst_default_prefix instdata_path instcfg_path instcfg_file
instcfg=(
  [TIMESTMP]=`date -u +%Y%m%d%H%M%S`
  [VERSION]='@PROJECT_VERSION@'
  [PREFIX]=''
)
oldinstcfg=(
  [TIMESTMP]=''
  [VERSION]=''
  [PREFIX]=''
)

declare -A L10N_DE
###L10N_DE###

getxt()
{
  # Poor mans gettext for l10n completely self contained in one shell
  # script.
  MSGID="$1"
  shift
  case ${LANGUAGE:-${LC_ALL:-${LC_MESSAGES:-$LANG}}} in
    de*)
      if [ "${L10N_DE[$MSGID]}" ] ; then
          MSG="${L10N_DE[$MSGID]}"
      else
        MSG="$MSGID"
      fi
      ;;
    *)
      MSG="$MSGID"
      ;;
  esac

  printf "$MSG" "$@"
}

version()
{
  cat <<EOF
TrustBridge ${instcfg[VERSION]} Installer

Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik
Software engineering by Intevation GmbH

This file is Free Software under the GNU GPL (v>=2)
and comes with ABSOLUTELY NO WARRANTY!
See LICENSE.txt for details.
EOF
  exit 0
}

fatal()
{
  getxt "$1" >&2
  if [ $DEINSTALL -eq 1 ] ; then
      getxt "Deinstallation failed.\n" >&2
  else
    getxt "Installation failed.\n" >&2
  fi
  exit 1
}

usage()
{
  getxt "Usage: %s [OPTION]...\n" "$ME"
  getxt "Install TrustBridge.\n\n"
  getxt "Options:\n"
  getxt "  -p, --prefix=PATH  install files in PATH\n"
  getxt "  -f, --force        install to given prefix, even when a current\n"
  getxt "                     installation with different prefix exists.\n"
  getxt "  -d, --deinstall    deinstall files from current installation\n"
  getxt "  -s, --system       create a system wide (de)installation\n"
  getxt "      --help         display this help and exit\n"
  getxt "      --version      output version information and exit\n"
  exit $1
}

yorn()
{
  local c
  while true ; do
    read -n 1 c
    echo
    case "$c" in
      y|Y|j|J)
        return 0
        ;;
      n|N)
        return 1
        ;;
      *)
        getxt >&2 "Answer [Y]es or [N]o:\n"
    esac
  done
}

parse_args()
{
  OPTS=`getopt \
      -l deinstall,force,help,prefix:,system,version \
      -o d,f,p:,s -n "$ME" -- "$@"`
  [ $? -eq 0 ] || usage 23

  eval set -- "$OPTS"

  while true ; do
    case "$1" in
      --prefix|-p)
        instcfg[PREFIX]="$2"
        shift 2
        ;;
      --system|-s)
        SYSINST=1
        shift 1
        ;;
      --force|-f)
        FORCE=1
        shift 1
        ;;
      --deinstall|-d)
        DEINSTALL=1
        shift 1
        ;;
      --help)
        usage 0
        ;;
      --version)
        version
        ;;
      --)
        shift
        break
        ;;
    esac
  done
}

init_vars()
{
  if [ $SYSINST -eq 1 ] ; then
      inst_default_prefix="$SYSDEFAULT_PREFIX"
      instcfg_path="${SYSCFGPATH}"
      instdata_path="${SYSDATAPATH}"
      autostart_path="$(getent passwd "${SUDO_USER}" | cut -d ':' -f 6)/.config/autostart"
      startmenu_path="/usr/share/applications"
  else
    inst_default_prefix="$DEFAULT_PREFIX"
    instcfg_path="${CFGPATH}"
    instdata_path="${DATAPATH}"
    autostart_path=${XDG_CONFIG_HOME:-~/.config/autostart}
    startmenu_path=${XDG_DATA_HOME:-~/.local/share/applications}
  fi
  instcfg_file="${instcfg_path}/${INSTCFGNAME}"
  extra_bin_path=`mktemp --tmpdir -d tmpbin.XXXXXXXXXX`
  HOST_ARCH=$(uname -m)
}

cleanup()
{
  getxt "Cleaning up temporary stuff ...\n"
  # remove temporary directories,
  # $lock_dir is generate by the shar
  if [ -z "${lock_dir-}" ]; then
    exit
  fi
  for dir in "${instcfg[PREFIX]}/$lock_dir" "$extra_bin_path" ; do
    [ -d "$dir" ] &&
        rm -rf "$dir"
  done
}

write_instcfg()
{
  install -d `dirname "$instcfg_file"`
  echo "# Created by TrustBridge-Installer, don't touch!" >"$instcfg_file"
  for key in "${!instcfg[@]}" ; do
    echo "${key}=${instcfg[$key]}" >>"$instcfg_file"
  done
}

read_oldinstcfg()
{
  if [ -r "$instcfg_file" ] ; then
      getxt "Reading '%s' ...\n" "$instcfg_file"
      for key in "${!oldinstcfg[@]}" ; do
        oldinstcfg[$key]=`sed -n "/$key/s/[^=]*=\(.*\)/\1/p" "$instcfg_file"`
      done
  fi
}

check_priv()
{
  if [ $SYSINST -eq 1 -a "$UID" -ne 0 ] ; then
      fatal "System wide installation requires root privileges!\n"
  fi
}

rm_empty_dirs()
{
  # Args: $1 - DIRECTORY
  #
  # Recursively remove DIRECTORY and all it _parent_ directories as
  # long as they are empty.
  local directory="$1"
  while [ -d "$directory" -a -z "$(ls 2>/dev/null -A "$directory")" ] ; do
    getxt "Deleting empty directory '%s' ...\n" "$directory"
    rmdir "$directory"
    directory=`dirname "$directory"`
  done
}

rm_files()
{
  for file in "$@" ; do
    if [ -e "$file" ] ; then
        getxt "Deleting '%s' ...\n" "$file"
        rm "$file"
    fi
  done
}

setup_cronjob()
{
  local tmpcrontab=`mktemp`

  if [ $SYSINST -eq 1 -a "${SUDO_USER+X}" ] ; then
      local crontabopt="-u $SUDO_USER"
  else
      local crontabopt=''
  fi

  if [ "$1" != "deinstall" ] ; then
      local trustbridge_tray_starter="${instcfg[PREFIX]}/bin/trustbridge-tray-starter.sh"
  else
    local trustbridge_tray_starter="${oldinstcfg[PREFIX]}/bin/trustbridge-tray-starter.sh"
  fi

  crontab $crontabopt -l | \
      grep -vF "$trustbridge_tray_starter" \
           >"$tmpcrontab"
  if [ "$1" != "deinstall" ] ; then
      echo "$(( $RANDOM / 555 )) 12  * * * \"$trustbridge_tray_starter\"" \
           >>"$tmpcrontab"
  fi
  crontab $crontabopt "$tmpcrontab"
  rm "$tmpcrontab"
}

remove_cronjob()
{
  setup_cronjob deinstall
}

deinstall_certs()
{
  local cinst="${oldinstcfg[PREFIX]}/bin/cinst"
  local certlist=`ls 2>/dev/null -1  ${instdata_path}/list-installed.txt`

  getxt "Uninstalling certificates ...\n"

  if [ "$certlist" ] ; then
      getxt "Using certificate list '%s'.\n" "$certlist"
      if [ -x "$cinst" ] ; then
          "$cinst" "list=$certlist" "choices=uninstall"
      else
        getxt >&2 "WARNING: can't execute %s for certificate deinstallation.\n" "$cinst"
      fi
  else
    getxt "No certificate list found.  Nothing to do.\n"
  fi
}

deinstall_etc()
{
  getxt "Removing cron job ...\n"
  remove_cronjob

  # FIXME: delete all files created by the application.
  local tbcfg_files=( "${instcfg_path}/TrustBridge.ini"
                      "${instcfg_path}/trustbridge-tray-starter.cfg"
                      "$instcfg_file" )

  getxt "Removing certificate lists from: %s:\n" "$instdata_path"
  rm_files "$instdata_path"/list-*.txt

  getxt "Removing PID file from: %s:\n" "$instdata_path"
  rm_files "$instdata_path"/*.pid
  rm_empty_dirs "$instdata_path"

  getxt "Removing configuration files:\n"
  rm_files "${tbcfg_files[@]}"
  rm_empty_dirs "$instcfg_path"

  getxt "Removing TrustBridge from autostart\n"
  rm_files "${autostart_path}/trustbridge.desktop"
  update-desktop-database 2>&1 || true

  getxt "Removing TrustBridge from start menu\n"
  rm_files "${startmenu_path}/trustbridge.desktop"
}

deinstall()
{
  if [ "${oldinstcfg[PREFIX]}" ] ; then
      getxt "Really deinstall TrustBridge from '%s'? [y/n]\n" "${oldinstcfg[PREFIX]}"
      yorn || exit 0
      deinstall_certs
      local deinstdir="${oldinstcfg[PREFIX]}/bin"
      getxt "Deinstalling from '%s'.\n" "${oldinstcfg[PREFIX]}"
      for file in $BINNAMES ; do
        local path="${deinstdir}/$file"
        getxt "Deleting '%s' ...\n" "$path"
        rm "$path" || getxt >&2 "WARNING: Could not delete: '%s'!\n" "$path"
      done
      rm_empty_dirs "$deinstdir"

      # images
      deinstdir="${oldinstcfg[PREFIX]}/share/doc/trustbridge/_images"
      for file in $HELPNAMES_IMG; do
        local path="${deinstdir}/$file"
        if [ -f "$path" ]; then
          getxt "Deleting '%s' ...\n" "$path"
          rm "$path" || getxt >&2 "WARNING: Could not delete: '%s'!\n" "$path"
        fi
      done
      rm_empty_dirs "$deinstdir"

      # Javascript sources
      deinstdir="${oldinstcfg[PREFIX]}/share/doc/trustbridge/_sources"
      for file in $HELPNAMES_SOURCES; do
        local path="${deinstdir}/$file"
        if [ -f "$path" ]; then
          getxt "Deleting '%s' ...\n" "$path"
          rm "$path" || getxt >&2 "WARNING: Could not delete: '%s'!\n" "$path"
        fi
      done
      rm_empty_dirs "$deinstdir"

      # Static files
      deinstdir="${oldinstcfg[PREFIX]}/share/doc/trustbridge/_static"
      for file in $HELPNAMES_STATIC; do
        local path="${deinstdir}/$file"
        if [ -f "$path" ]; then
          getxt "Deleting '%s' ...\n" "$path"
          rm "$path" || getxt >&2 "WARNING: Could not delete: '%s'!\n" "$path"
        fi
      done
      rm_empty_dirs "$deinstdir"

      # The actual html
      deinstdir="${oldinstcfg[PREFIX]}/share/doc/trustbridge"
      for file in $HELPNAMES; do
        local path="${deinstdir}/$file"
        if [ -f "$path" ]; then
          getxt "Deleting '%s' ...\n" "$path"
          rm "$path" || getxt >&2 "WARNING: Could not delete: '%s'!\n" "$path"
        fi
      done
      rm_empty_dirs "$deinstdir"
      deinstdir="${oldinstcfg[PREFIX]}/share/pixmaps/trustbridge"
      getxt "Deinstalling from '%s'.\n" "${oldinstcfg[PREFIX]}"
      for file in $ICONNAME; do
        local path="${deinstdir}/$file"
        getxt "Deleting '%s' ...\n" "$path"
        rm "$path" || getxt >&2 "WARNING: Could not delete: '%s'!\n" "$path"
      done
      deinstdir="${oldinstcfg[PREFIX]}/share/pixmaps/trustbridge"
      rm_empty_dirs "$deinstdir"
      deinstdir="${oldinstcfg[PREFIX]}/share/pixmaps"
      rm_empty_dirs "$deinstdir"
      deinstdir="${oldinstcfg[PREFIX]}/share"
      rm_empty_dirs "$deinstdir"
      deinstall_etc
      getxt "Deinstallation finished.\n"
  else
    getxt "No current installation found!  No harm done.\n"
  fi
}

write_autostart()
{
  cat > "$1" << EOF
[Desktop Entry]
Type=Application
Name=TrustBridge
Exec="${instcfg[PREFIX]}/bin/trustbridge" --tray
EOF
  chown "${SUDO_USER:-${USER}}" "$1"
  chmod 700 "$1"
}

write_startmenu()
{
  cat > "$1" << EOF
[Desktop Entry]
Type=Application
Name=TrustBridge
Comment=Install and update trusted root certificates
Comment[de]=Vertrauenswürdige Wurzelzertifikate installieren und aktualisieren
Exec=${instcfg[PREFIX]}/bin/trustbridge
Icon=${instcfg[PREFIX]}/share/pixmaps/trustbridge/trustbridge.png
Terminal=false
Categories=Network;Qt;
StartupNotify=false
EOF
}

setup_startmenu()
{
  # Supported desktop environments: Unity, GNOME, XFCE, LXDE, KDE
  # System wide installation with a nonstandard XDG_DATA_HOME is not
  # respected with regards to autostart.
  if [ ! -d "${startmenu_path}" ]; then
    install -d "${startmenu_path}" || \
      fatal "Failed to create startmenu directory: '%s'\n" "$startmenu_path"
  fi

  write_startmenu "${startmenu_path}/trustbridge.desktop"
  update-desktop-database 2>&1 || true
}

setup_autostart()
{
  # Supported desktop environments: Unity, GNOME, XFCE, LXDE, KDE
  # System wide installation with a nonstandard XDG_CONFIG_HOME or KDEHOME is not
  # respected with regards to autostart.
  if [ ! -d "${autostart_path}" ]; then
    install -d "${autostart_path}" || \
      fatal "Failed to create autostart directory: '%s'\n" "$autostart_path"
  fi

  write_autostart "${autostart_path}/trustbridge.desktop"
}

provide_uudecode_maybe()
{
  # The shar needs uudecode, which might not be installed.  If its not
  # available we will provide our own python based implementation.
  if which uudecode >/dev/null 2>&1 ; then
      getxt "Found system uudecode.\n"
  else
    local myuudecode="$extra_bin_path/uudecode"
    cat >"$myuudecode" <<EOF
#!/usr/bin/python2
import os
import sys
import uu
os.path.chmod = os.chmod
def rm_if_exists(file):
    try:
        os.remove(file)
    except OSError:
        pass
os.path.exists = rm_if_exists
if len(sys.argv) > 1:
    f = open(sys.argv[1], 'r')
else:
    f = sys.stdin
uu.decode(f, None, None, 1)
EOF
    chmod 755 "$myuudecode"
    PATH="${extra_bin_path}:$PATH"
    getxt "Using python uudecode provided by installer.\n"
  fi
}

#======================================================================
# main()
trap cleanup EXIT

parse_args "$@"
init_vars
check_priv
read_oldinstcfg

cat <<EOF
------------------------------------------------------------------------

   TrustBridge - Installer
   Version ${instcfg[VERSION]} - ${ARCH} (Testversion)

------------------------------------------------------------------------
EOF

if [ "$ARCH" == "x86_64" -a "$ARCH" != "$HOST_ARCH" ]; then
    getxt "It appears your system architecture is %s.\n" "$HOST_ARCH"
    getxt "This installer is for 64 bit systems.\n"
    getxt "Really install TrustBridge for '%s' systems? [y/n]\n" "${ARCH}"
    yorn || exit 0
fi

if [ "$ARCH" == "i386" ]; then
    if [[ "$HOST_ARCH" != *86 ]]; then
        getxt "It appears your system architecture is %s.\n" "$HOST_ARCH"
        getxt "This installer is for 32 bit systems.\n"
        getxt "Really install TrustBridge for '%s' systems? [y/n]\n" "${ARCH}"
        yorn || exit 0
    fi
fi

if [ $DEINSTALL -eq 1 ] ; then
    deinstall
    # Stop after deinstallation:
    exit 0
fi

if [ -z "${instcfg[PREFIX]}" ] ; then

    if [ "${oldinstcfg[PREFIX]}" ] ; then
        inst_default_prefix="${oldinstcfg[PREFIX]}"
        getxt "An existing installation (v%s) was detected!\n" "${oldinstcfg[VERSION]}"
        getxt "It is HIGHLY RECOMMENDED to accept the default prefix\n"
        getxt "to update the current installation.\n"
        getxt "For a new prefix you should deinstall first!\n"
    fi
    getxt "Select installation prefix for TrustBridge [%s]: " "${inst_default_prefix}"
    read -e instcfg[PREFIX]

    [ -z "${instcfg[PREFIX]}" ] && instcfg[PREFIX]="${inst_default_prefix}"
else
  # Prefix was given on invocation:
  if [ "${oldinstcfg[PREFIX]}" -a \
       "${instcfg[PREFIX]}" != "${oldinstcfg[PREFIX]}" -a \
       $FORCE -ne 1 ] ; then
      fatal "Prefix differs from current installation (%s).  Aborting!\n" "${oldinstcfg[PREFIX]}"
  fi
fi

getxt "Installing to '%s':\n" "${instcfg[PREFIX]}"

if [ ! -d "${instcfg[PREFIX]}" ] ; then
    getxt "creating installation directory ...\n"
    install -d "${instcfg[PREFIX]}" || fatal "Could not create '%s'!\n" "${instcfg[PREFIX]}"
fi

getxt "checking for uudecode ...\n"
provide_uudecode_maybe

getxt "unpacking files ...\n"
cd "${instcfg[PREFIX]}"

set +u
set -- '-c'
# ----------------------------------------------------------------------
# regular shar archive inserted here:
###SHAR###
# ----------------------------------------------------------------------

getxt "Preparing trustbridge-tray-starter ...\n"
sed -i "/^PREFIX=/c\PREFIX='${instcfg[PREFIX]}'" \
    "${instcfg[PREFIX]}/bin/trustbridge-tray-starter.sh"

getxt "Setting up cronjob ...\n"
setup_cronjob

getxt "Setting up autostart ...\n"
setup_autostart

getxt "Setting up start menu entries ...\n"
setup_startmenu

getxt "Writing installation configuration to: %s ...\n" "$instcfg_file"
write_instcfg

# cleanup
# is called implicitly at exit via trap...
exit 0

http://wald.intevation.org/projects/trustbridge/