diff options
-rw-r--r-- | indra/viewer_components/updater/scripts/linux/update_install | 164 |
1 files changed, 113 insertions, 51 deletions
diff --git a/indra/viewer_components/updater/scripts/linux/update_install b/indra/viewer_components/updater/scripts/linux/update_install index 167e2b7881..0f624c4dee 100644 --- a/indra/viewer_components/updater/scripts/linux/update_install +++ b/indra/viewer_components/updater/scripts/linux/update_install @@ -13,78 +13,136 @@ # Copyright (c) 2013, Linden Research, Inc. # $/LicenseInfo$ +# **************************************************************************** +# script parameters +# **************************************************************************** tarball="$1" # the file to install markerfile="$2" # create this file on failure mandatory="$3" # what to write to markerfile on failure +# **************************************************************************** +# helper functions +# **************************************************************************** +# empty array +cleanups=() + +# add a cleanup action to execute on exit +function cleanup { + # wacky bash syntax for appending to array + cleanups[${#cleanups[*]}]="$*" +} + +# called implicitly on exit +function onexit { + for action in "${cleanups[@]}" + do # don't quote, support actions consisting of multiple words + $action + done +} +trap 'onexit' EXIT + +# write to log file function log { # our log file will be open as stderr -- but until we set up that # redirection, logging to stderr is better than nothing echo "$*" 1>&2 } -function status { - log "$@" - # Prefix with '#' so xmenity will recognize it as a status message - echo "#$*" +# We display status by leaving one background xmessage process running. This +# is the pid of that process. +statuspid="" + +function clear_message { + [ -n "$statuspid" ] && kill $statuspid + statuspid="" } +# make sure we remove any message box we might have put up +cleanup clear_message + +# can we use zenity, or must we fall back to xmessage? +zenpath="$(which zenity)" +if [ -n "$zenpath" ] +then # zenity on PATH and is executable + # display a message box and continue + function status { + # clear any previous message + clear_message + # put up a new zenity box and capture its pid + "$zenpath" --info --title "Second Life Viewer Updater" \ + --width=320 --height=120 --text="$*" & + statuspid=$! + } + + # display an error box and wait for user + function errorbox { + "$zenpath" --error --title "Second Life Viewer Updater" \ + --width=320 --height=120 --text="$*" + } + +else # no zenity, use xmessage instead + # display a message box and continue + function status { + # clear any previous message + clear_message + # put up a new xmessage and capture its pid + xmessage -buttons OK:2 -center "$*" & + statuspid=$! + } + + # display an error box and wait for user + function errorbox { + xmessage -buttons OK:2 -center "$*" + } +fi + +# display an error box and terminate function fail { # Log the message log "$@" # tell subsequent viewer things went south echo "$mandatory" > "$markerfile" # add boilerplate - local msg="An error occurred while updating Second Life: + errorbox "An error occurred while updating Second Life: $* Please download the latest viewer from www.secondlife.com." - # Restate test from xmenity to detect whether we can use zenity or must - # fall back to xmessage - zenpath="$(which zenity)" - if [ -n "$zenpath" -a -x "$zenpath" ] - then "$zenpath" --error --title "Second Life Viewer Updater" \ - --width=320 --height=120 --text="$msg" - else xmessage -buttons -OK:2 -center "$msg" - fi exit 1 } +# Find a graphical sudo program and define mysudo function. On error, $? is +# nonzero; output is in $err instead of being written to stdout/stderr. +gksudo="$(which gksudo)" +kdesu="$(which kdesu)" +if [ -n "$gksudo" ] +then function mysudo { + # gksudo allows you to specify description + err="$("$gksudo" --description "Second Life Viewer Updater" "$@" 2>&1)" + } +elif [ -n "$kdesu" ] +then function mysudo { + err="$("$kdesu" "$@" 2>&1)" + } +else # couldn't find either one, just try it anyway + function mysudo { + err="$("$@" 2>&1)" + } +fi + +# Move directories, using mysudo if we think it necessary. On error, $? is +# nonzero; output is in $err instead of being written to stdout/stderr. function sudo_mv { # If we have write permission to both parent directories, shouldn't need # sudo. if [ -w "$(dirname "$1")" -a -w "$(dirname "$2")" ] - then mv "$1" "$2" - else # use one of the likely sudo programs - sudo="$(which gksudo)" - if [ -z "$sudo" ] - then sudo="$(which kdesu)" - fi - if [ -z "$sudo" ] - then # couldn't find either one, just try it anyway - mv "$1" "$2" - else # even with sudo, could fail, e.g. different filesystems - "$sudo" mv "$1" "$2" - fi + then err="$(mv "$@" 2>&1)" + else # use available sudo program; mysudo sets $? and $err + mysudo mv "$@" fi } -# empty array -cleanups=() - -function cleanup { - # wacky bash syntax for appending to array - cleanups[${#cleanups[*]}]="$*" -} - -function onexit { - for action in "${cleanups[@]}" - do # don't quote, support actions consisting of multiple words - $action - done -} - -trap 'onexit' EXIT - +# **************************************************************************** +# main script logic +# **************************************************************************** mydir="$(dirname "$0")" # We happen to know that the viewer specifies a marker-file pathname within # the logs directory. @@ -97,9 +155,6 @@ logname="$logsdir/updater.log" # Set up redirections for this script such that stderr is logged. (But first # move the previous stderr to file descriptor 3.) exec 3>&2- 2> "$logname" -# Piping to xmenity requires that we end with a line consisting of the string -# "100" to terminate zenity progress bar. -cleanup echo 100 # Rather than setting up a special pipeline to timestamp every line of stderr, # produce header lines into log file indicating timestamp and the arguments @@ -114,17 +169,19 @@ status 'Installing Second Life...' # Creating tempdir under /tmp means it's possible that tempdir is on a # different filesystem than INSTALL_DIR. One is tempted to create tempdir on a -# path derived from `dirname INSTALL_DIR`, but then we might need to add -# another sudo prompt to create it. +# path derived from `dirname INSTALL_DIR` -- but it seems modern 'mv' can +# handle moving across filesystems?? tempdir="/tmp/$(basename "$0").$$" tempinstall="$tempdir/install" -mkdir -p "$tempinstall" || fail "Couldn't create $tempinstall" +# capture the actual error message, if any +err="$(mkdir -p "$tempinstall" 2>&1)" || fail "$err" cleanup rm -rf "$tempdir" # If we already knew the name of the tarball's top-level directory, we could # just move that when all was said and done. Since we don't, untarring to the # 'install' subdir with --strip 1 effectively renames that top-level # directory. +# untar failures tend to be voluminous -- don't even try to capture, just log tar --strip 1 -xjf "$tarball" -C "$tempinstall" || fail "Untar command failed" INSTALL_DIR="$(cd "$mydir/.." ; pwd)" @@ -138,16 +195,21 @@ then backup="$INSTALL_DIR.backup" do backup="$INSTALL_DIR.backup.$backupn" ((backupn += 1)) done - sudo_mv "$INSTALL_DIR" "$backup" || fail "Couldn't move $INSTALL_DIR to $backup" + # on error, fail with actual error message from sudo_mv: permissions, + # cross-filesystem mv, ...? + sudo_mv "$INSTALL_DIR" "$backup" || fail "$err" fi # We unpacked the tarball into tempinstall. Move that. if ! sudo_mv "$tempinstall" "$INSTALL_DIR" then # If we failed to move the temp install to INSTALL_DIR, try to restore - # INSTALL_DIR from backup + # INSTALL_DIR from backup. Save $err because next sudo_mv will trash it! + realerr="$err" sudo_mv "$backup" "$INSTALL_DIR" - fail "Couldn't move $1 to $2" + fail "$realerr" fi +# Removing the tarball here, rather than with a 'cleanup' action, means we +# only remove it if we succeeded. rm -f "$tarball" # Launch the updated viewer. Restore original stderr from file descriptor 3, |