view packaging/linux-installer.inc.in @ 1070:f110a3f6e387

(issue114) Fine tune ACL propagation using mkdir_p the ACL of the parent directories would propagate to all subdirectories and objects in the directory. Now we only use ACL propagation in the last directory to make sure that files we might create in that directory inherit the correct (resitricted) ACL
author Andre Heinecke <andre.heinecke@intevation.de>
date Wed, 10 Sep 2014 16:41:36 +0200
parents 709a7633a2c6
children 7e1fd6d96714
line wrap: on
line source
#!/bin/bash
# Um TrustBridge zu installieren:
# 1. Prüfen Sie ob Sie dieser Datei genügend vertrauen, um ihr die Kontrolle
#    über diesen Rechner zu übergeben. Beispielsweise durch Vergleich mit 
#    einer starken Prüfsumme aus einer zweiten, unabhängigen Quelle.
# 2. Öffnen Sie eine Kommandozeile, z.B. klicken Sie auf das "Terminal"-Symbol.
# 3. Wechseln Sie in das Verzeichnis, in welchem diese Datei gespeichert ist.
#    Geben Sie Z.B. in die Kommandozeile ein: cd ~/Schreibtisch
# 4. Starten Sie die Anwendung auf der Kommandozeile, beispielsweise
#    als Installation nur für den aktuellen Nutzer, indem Sie eingeben:
#    	bash TrustBridge-1.0.0-i386.sh
#    Tipp: Die Tab-Taste nach dem "Tr" ergänzt oft den ganzen Namen.
#
# NB: Wir konnten kein übliches .deb Paket verwenden, da wir Ihnen
# auch die Installation als reiner Nutzer ohne Admin-Rechte ermöglichen.
#
# To install TrustBridge:
# 1. Verify that you trust this specific file far enough, that you are willing
#    to hand over the control of your computer to it. For example compare
#    a strong checksum of the file to one from a second, independent source.
# 2. Open a command line, e.g. click on the "Terminal"-Symbol.
# 3. Change your working directory to where this file is stored.
#    For example type "cd ~/Desktop" on your command line.
# 4. Start the installation on the command line, e.g. for the current user
#    only by typing something like "bash TrustBridge-1.0.0-i386.sh". 
#    Hint: If you press the tab-key after "Tr" it may complete the filename.
#
# N.B. We could not have used a .deb package, because the installation must 
# also work without without adminstrator priviledges.
#
#
# Search the file for 'version()' to find the license information.
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
UPDATE=0
SHOWAFTERUPDATE=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,update,show-after-update,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
        ;;
      --update)
        UPDATE=1
        shift 1
        ;;
      --show-after-update)
        SHOWAFTERUPDATE=1
        shift 1
        ;;
      --help)
        usage 0
        ;;
      --version)
        version
        ;;
      --)
        shift
        break
        ;;
    esac
  done
}

init_vars()
{
  if [ -n "${SUDO_USER-}" ] ; then
    # Default to system wide installation when running with sudo
    SYSINST=1
  fi

  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}
    if [ $DEINSTALL -eq 1 ] ; then
        if [ ! -r ${instcfg_path}/${INSTCFGNAME} ]; then
            if [ -r ${SYSCFGPATH}/${INSTCFGNAME} ]; then
                # Fall back to system uninstallation if no user config found
                SYSINST=1
                init_vars
                check_priv
            fi
        fi
    fi
  fi
  instcfg_file="${instcfg_path}/${INSTCFGNAME}"
  extra_bin_path=`mktemp --tmpdir -d tmpbin.XXXXXXXXXX`
  HOST_ARCH=$(uname -m)
}

finished()
{
  echo
  echo "#################################################################################"
  if [ $SYSINST -eq 1 ]; then
    getxt "System wide installation successful.\n"
  else
    getxt "Single user installation successful.\n"
  fi
  getxt "TrustBridge has been installed to: '%s'\n\n" "${instcfg[PREFIX]}"

  if [ $SYSINST -eq 1 ]; then
    getxt "If you do not want to change the certificates of other users\n"
    getxt "uninstall it with:\n"
    echo "      'sudo $0 -d'"
    getxt "And install it again without sudo:\n"
    echo "       $0"
    RUNCMD="su -l $SUDO_USER -c "
  else
    getxt "If you want to change the certificates of all users\n"
    getxt "uninstall it with:\n"
    echo "      '$0 -d'"
    getxt "And install it again using sudo:\n"
    echo "       sudo $0"
    RUNCMD=""
  fi
  echo "#################################################################################"
  getxt "Press enter to launch '%s'\n" "${instcfg[PREFIX]}/bin/trustbridge"
  if [ $UPDATE -eq 0 ]; then
    read
    $RUNCMD "${instcfg[PREFIX]}/bin/trustbridge" &
  else
    if [ $SHOWAFTERUPDATE -eq 0 ]; then
      $RUNCMD "${instcfg[PREFIX]}/bin/trustbridge" --tray &
    else
      $RUNCMD "${instcfg[PREFIX]}/bin/trustbridge" &
    fi
  fi
}

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 or deinstallation 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 "$@"
check_priv
init_vars
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

finished

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

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