diff --git a/indra/viewer_components/updater/scripts/linux/update_install b/indra/viewer_components/updater/scripts/linux/update_install
index 167e2b7881c147e212913d5f565470f8a07f0630..0f624c4deeeb4c5b5fe5700a760a03a4d7964da0 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,