summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOz Linden <oz@lindenlab.com>2014-08-25 14:26:29 -0400
committerOz Linden <oz@lindenlab.com>2014-08-25 14:26:29 -0400
commit97877202f3a00868bbd31db7f3f8e3fe4b889766 (patch)
tree8b07a6253fad2d25620bcf4301d6a6a04d1cedd3
parentae60558141ccac3c2ca3371171015f42d50cb9cd (diff)
parentb603812fac01591951092c0ceba30277f2fb013d (diff)
merge changes for DRTVWR-376
-rwxr-xr-xindra/CMakeLists.txt6
-rw-r--r--indra/linux_updater/CMakeLists.txt57
-rw-r--r--indra/linux_updater/linux_updater.cpp926
-rw-r--r--indra/mac_updater/mac_updater.cpp1266
-rwxr-xr-xindra/newview/CMakeLists.txt2
-rwxr-xr-xindra/win_updater/CMakeLists.txt45
-rwxr-xr-xindra/win_updater/updater.cpp516
7 files changed, 2 insertions, 2816 deletions
diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt
index 410d25ad97..24ea59ca49 100755
--- a/indra/CMakeLists.txt
+++ b/indra/CMakeLists.txt
@@ -71,7 +71,6 @@ add_subdirectory(${LIBS_OPEN_PREFIX}media_plugins)
if (LINUX)
add_subdirectory(${VIEWER_PREFIX}linux_crash_logger)
- add_subdirectory(${VIEWER_PREFIX}linux_updater)
if (INSTALL_PROPRIETARY)
include(LLAppearanceUtility)
add_subdirectory(${LLAPPEARANCEUTILITY_SRC_DIR} ${LLAPPEARANCEUTILITY_BIN_DIR})
@@ -86,9 +85,8 @@ elseif (WINDOWS)
if (EXISTS ${VIEWER_DIR}win_setup)
add_subdirectory(${VIEWER_DIR}win_setup)
endif (EXISTS ${VIEWER_DIR}win_setup)
- add_subdirectory(${VIEWER_PREFIX}win_updater)
- # add_dependencies(viewer windows-updater windows-setup windows-crash-logger)
- add_dependencies(viewer windows-updater windows-crash-logger)
+ # add_dependencies(viewer windows-setup windows-crash-logger)
+ add_dependencies(viewer windows-crash-logger)
elseif (SOLARIS)
add_subdirectory(solaris_crash_logger)
add_dependencies(viewer solaris-crash-logger)
diff --git a/indra/linux_updater/CMakeLists.txt b/indra/linux_updater/CMakeLists.txt
deleted file mode 100644
index 4a9e82f9b6..0000000000
--- a/indra/linux_updater/CMakeLists.txt
+++ /dev/null
@@ -1,57 +0,0 @@
-# -*- cmake -*-
-
-project(linux_updater)
-
-include(00-Common)
-include(CURL)
-include(CARes)
-include(OpenSSL)
-include(UI)
-include(LLCommon)
-include(LLMessage)
-include(LLVFS)
-include(LLXML)
-include(LLUI)
-include(Linking)
-
-include_directories(
- ${LLCOMMON_INCLUDE_DIRS}
- ${LLVFS_INCLUDE_DIRS}
- ${LLXML_INCLUDE_DIRS}
- ${LLUI_INCLUDE_DIRS}
- ${CURL_INCLUDE_DIRS}
- ${CARES_INCLUDE_DIRS}
- ${OPENSSL_INCLUDE_DIRS}
- ${UI_INCLUDE_DIRS}
- )
-include_directories(SYSTEM
- ${LLCOMMON_SYSTEM_INCLUDE_DIRS}
- ${LLXML_SYSTEM_INCLUDE_DIRS}
- )
-
-set(linux_updater_SOURCE_FILES linux_updater.cpp)
-
-set(linux_updater_HEADER_FILES CMakeLists.txt)
-
-set_source_files_properties(${linux_updater_HEADER_FILES}
- PROPERTIES HEADER_FILES_ONLY TRUE)
-
-list(APPEND linux_updater_SOURCE_FILES ${linux_updater_HEADER_FILES})
-
-add_executable(linux-updater ${linux_updater_SOURCE_FILES})
-
-target_link_libraries(linux-updater
- ${CURL_LIBRARIES}
- ${CARES_LIBRARIES}
- ${OPENSSL_LIBRARIES}
- ${CRYPTO_LIBRARIES}
- ${LLMESSAGE_LIBRARIES}
- ${UI_LIBRARIES}
- ${LLXML_LIBRARIES}
- ${LLUI_LIBRARIES}
- ${LLVFS_LIBRARIES}
- ${LLCOMMON_LIBRARIES}
- )
-
-add_custom_target(linux-updater-target ALL
- DEPENDS linux-updater)
diff --git a/indra/linux_updater/linux_updater.cpp b/indra/linux_updater/linux_updater.cpp
deleted file mode 100644
index 5c94deba02..0000000000
--- a/indra/linux_updater/linux_updater.cpp
+++ /dev/null
@@ -1,926 +0,0 @@
-/**
- * @file linux_updater.cpp
- * @author Kyle Ambroff <ambroff@lindenlab.com>, Tofu Linden
- * @brief Viewer update program for unix platforms that support GTK+
- *
- * $LicenseInfo:firstyear=2008&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include <unistd.h>
-#include <signal.h>
-#include <errno.h>
-#include <set>
-#include <iostream>
-
-#include "linden_common.h"
-#include "llerrorcontrol.h"
-#include "llfile.h"
-#include "lldir.h"
-#include "lldiriterator.h"
-
-/*==========================================================================*|
-// IQA-490: Use of LLTrans -- by this program at least -- appears to be buggy.
-// With it, the 3.3.2 beta 1 linux-updater.bin crashes; without it seems stable.
-#include "llxmlnode.h"
-#include "lltrans.h"
-|*==========================================================================*/
-
-static class LLTrans
-{
-public:
- LLTrans();
- static std::string getString(const std::string& key);
-
-private:
- std::string _getString(const std::string& key) const;
-
- typedef std::map<std::string, std::string> MessageMap;
- MessageMap mMessages;
-} sLLTransInstance;
-
-#include <curl/curl.h>
-#include <map>
-#include <boost/foreach.hpp>
-
-extern "C" {
-#include <gtk/gtk.h>
-}
-
-const guint UPDATE_PROGRESS_TIMEOUT = 100;
-const guint UPDATE_PROGRESS_TEXT_TIMEOUT = 1000;
-const guint ROTATE_IMAGE_TIMEOUT = 8000;
-
-typedef struct _updater_app_state {
- std::string app_name;
- std::string url;
- std::string file;
- std::string image_dir;
- std::string dest_dir;
- std::string strings_dirs;
- std::string strings_file;
-
- LLDirIterator *image_dir_iter;
-
- GtkWidget *window;
- GtkWidget *progress_bar;
- GtkWidget *image;
-
- double progress_value;
- bool activity_mode;
-
- guint image_rotation_timeout_id;
- guint progress_update_timeout_id;
- guint update_progress_text_timeout_id;
-
- bool failure;
-} UpdaterAppState;
-
-// List of entries from strings.xml to always replace
-static std::set<std::string> default_trans_args;
-void init_default_trans_args()
-{
- default_trans_args.insert("SECOND_LIFE"); // World
- default_trans_args.insert("APP_NAME");
- default_trans_args.insert("SECOND_LIFE_GRID");
- default_trans_args.insert("SUPPORT_SITE");
-}
-
-bool translate_init(std::string comma_delim_path_list,
- std::string base_xml_name)
-{
- return true;
-/*==========================================================================*|
- init_default_trans_args();
-
- // extract paths string vector from comma-delimited flat string
- std::vector<std::string> paths;
- LLStringUtil::getTokens(comma_delim_path_list, paths, ","); // split over ','
-
- for(std::vector<std::string>::iterator it = paths.begin(), end_it = paths.end();
- it != end_it;
- ++it)
- {
- (*it) = gDirUtilp->findSkinnedFilename(*it, base_xml_name);
- }
-
- // suck the translation xml files into memory
- LLXMLNodePtr root;
- bool success = LLXMLNode::getLayeredXMLNode(root, paths);
- if (!success)
- {
- // couldn't load string table XML
- return false;
- }
- else
- {
- // get those strings out of the XML
- LLTrans::parseStrings(root, default_trans_args);
- return true;
- }
-|*==========================================================================*/
-}
-
-
-void updater_app_ui_init(void);
-void updater_app_quit(UpdaterAppState *app_state);
-void parse_args_and_init(int argc, char **argv, UpdaterAppState *app_state);
-std::string next_image_filename(std::string& image_path, LLDirIterator& iter);
-void display_error(GtkWidget *parent, std::string title, std::string message);
-BOOL install_package(std::string package_file, std::string destination);
-BOOL spawn_viewer(UpdaterAppState *app_state);
-
-extern "C" {
- void on_window_closed(GtkWidget *sender, GdkEvent *event, gpointer state);
- gpointer worker_thread_cb(gpointer *data);
- int download_progress_cb(gpointer data, double t, double d, double utotal, double ulnow);
- gboolean rotate_image_cb(gpointer data);
- gboolean progress_update_timeout(gpointer data);
- gboolean update_progress_text_timeout(gpointer data);
-}
-
-void updater_app_ui_init(UpdaterAppState *app_state)
-{
- GtkWidget *vbox;
- GtkWidget *summary_label;
- GtkWidget *description_label;
- GtkWidget *frame;
-
- llassert(app_state != NULL);
-
- // set up window and main container
- std::string window_title = LLTrans::getString("UpdaterWindowTitle");
- app_state->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- gtk_window_set_title(GTK_WINDOW(app_state->window),
- window_title.c_str());
- gtk_window_set_resizable(GTK_WINDOW(app_state->window), FALSE);
- gtk_window_set_position(GTK_WINDOW(app_state->window),
- GTK_WIN_POS_CENTER_ALWAYS);
-
- gtk_container_set_border_width(GTK_CONTAINER(app_state->window), 12);
- g_signal_connect(G_OBJECT(app_state->window), "delete-event",
- G_CALLBACK(on_window_closed), app_state);
-
- vbox = gtk_vbox_new(FALSE, 6);
- gtk_container_add(GTK_CONTAINER(app_state->window), vbox);
-
- // set top label
- std::ostringstream label_ostr;
- label_ostr << "<big><b>"
- << LLTrans::getString("UpdaterNowUpdating")
- << "</b></big>";
-
- summary_label = gtk_label_new(NULL);
- gtk_label_set_use_markup(GTK_LABEL(summary_label), TRUE);
- gtk_label_set_markup(GTK_LABEL(summary_label),
- label_ostr.str().c_str());
- gtk_misc_set_alignment(GTK_MISC(summary_label), 0, 0.5);
- gtk_box_pack_start(GTK_BOX(vbox), summary_label, FALSE, FALSE, 0);
-
- // create the description label
- description_label = gtk_label_new(LLTrans::getString("UpdaterUpdatingDescriptive").c_str());
- gtk_label_set_line_wrap(GTK_LABEL(description_label), TRUE);
- gtk_misc_set_alignment(GTK_MISC(description_label), 0, 0.5);
- gtk_box_pack_start(GTK_BOX(vbox), description_label, FALSE, FALSE, 0);
-
- // If an image path has been set, load the background images
- if (!app_state->image_dir.empty()) {
- frame = gtk_frame_new(NULL);
- gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
- gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 0);
-
- // load the first image
- app_state->image = gtk_image_new_from_file
- (next_image_filename(app_state->image_dir, *app_state->image_dir_iter).c_str());
- gtk_widget_set_size_request(app_state->image, 340, 310);
- gtk_container_add(GTK_CONTAINER(frame), app_state->image);
-
- // rotate the images every 5 seconds
- app_state->image_rotation_timeout_id = g_timeout_add
- (ROTATE_IMAGE_TIMEOUT, rotate_image_cb, app_state);
- }
-
- // set up progress bar, and update it roughly every 1/10 of a second
- app_state->progress_bar = gtk_progress_bar_new();
- gtk_progress_bar_set_text(GTK_PROGRESS_BAR(app_state->progress_bar),
- LLTrans::getString("UpdaterProgressBarTextWithEllipses").c_str());
- gtk_box_pack_start(GTK_BOX(vbox),
- app_state->progress_bar, FALSE, TRUE, 0);
- app_state->progress_update_timeout_id = g_timeout_add
- (UPDATE_PROGRESS_TIMEOUT, progress_update_timeout, app_state);
- app_state->update_progress_text_timeout_id = g_timeout_add
- (UPDATE_PROGRESS_TEXT_TIMEOUT, update_progress_text_timeout, app_state);
-
- gtk_widget_show_all(app_state->window);
-}
-
-gboolean rotate_image_cb(gpointer data)
-{
- UpdaterAppState *app_state;
- std::string filename;
-
- llassert(data != NULL);
- app_state = (UpdaterAppState *) data;
-
- filename = next_image_filename(app_state->image_dir, *app_state->image_dir_iter);
-
- gdk_threads_enter();
- gtk_image_set_from_file(GTK_IMAGE(app_state->image), filename.c_str());
- gdk_threads_leave();
-
- return TRUE;
-}
-
-std::string next_image_filename(std::string& image_path, LLDirIterator& iter)
-{
- std::string image_filename;
- iter.next(image_filename);
- return gDirUtilp->add(image_path, image_filename);
-}
-
-void on_window_closed(GtkWidget *sender, GdkEvent* event, gpointer data)
-{
- UpdaterAppState *app_state;
-
- llassert(data != NULL);
- app_state = (UpdaterAppState *) data;
-
- updater_app_quit(app_state);
-}
-
-void updater_app_quit(UpdaterAppState *app_state)
-{
- if (app_state != NULL)
- {
- g_source_remove(app_state->progress_update_timeout_id);
-
- if (!app_state->image_dir.empty())
- {
- g_source_remove(app_state->image_rotation_timeout_id);
- }
- }
-
- gtk_main_quit();
-}
-
-void display_error(GtkWidget *parent, std::string title, std::string message)
-{
- GtkWidget *dialog;
-
- dialog = gtk_message_dialog_new(GTK_WINDOW(parent),
- GTK_DIALOG_DESTROY_WITH_PARENT,
- GTK_MESSAGE_ERROR,
- GTK_BUTTONS_OK,
- "%s", message.c_str());
- gtk_window_set_title(GTK_WINDOW(dialog), title.c_str());
- gtk_dialog_run(GTK_DIALOG(dialog));
- gtk_widget_destroy(dialog);
-}
-
-gpointer worker_thread_cb(gpointer data)
-{
- UpdaterAppState *app_state;
- CURL *curl;
- CURLcode result;
- FILE *package_file;
- GError *error = NULL;
- int fd;
-
- //g_return_val_if_fail (data != NULL, NULL);
- app_state = (UpdaterAppState *) data;
-
- try {
-
- if(!app_state->url.empty())
- {
- char* tmp_local_filename = NULL;
- // create temporary file to store the package.
- fd = g_file_open_tmp
- ("secondlife-update-XXXXXX", &tmp_local_filename, &error);
- if (error != NULL)
- {
- LL_ERRS() << "Unable to create temporary file: "
- << error->message
- << LL_ENDL;
-
- g_error_free(error);
- throw 0;
- }
-
- if(tmp_local_filename != NULL)
- {
- app_state->file = tmp_local_filename;
- g_free(tmp_local_filename);
- }
-
- package_file = fdopen(fd, "wb");
- if (package_file == NULL)
- {
- LL_ERRS() << "Failed to create temporary file: "
- << app_state->file.c_str()
- << LL_ENDL;
-
- gdk_threads_enter();
- display_error(app_state->window,
- LLTrans::getString("UpdaterFailDownloadTitle"),
- LLTrans::getString("UpdaterFailUpdateDescriptive"));
- gdk_threads_leave();
- throw 0;
- }
-
- // initialize curl and start downloading the package
- LL_INFOS() << "Downloading package: " << app_state->url << LL_ENDL;
-
- curl = curl_easy_init();
- if (curl == NULL)
- {
- LL_ERRS() << "Failed to initialize libcurl" << LL_ENDL;
-
- gdk_threads_enter();
- display_error(app_state->window,
- LLTrans::getString("UpdaterFailDownloadTitle"),
- LLTrans::getString("UpdaterFailUpdateDescriptive"));
- gdk_threads_leave();
- throw 0;
- }
-
- curl_easy_setopt(curl, CURLOPT_URL, app_state->url.c_str());
- curl_easy_setopt(curl, CURLOPT_NOSIGNAL, TRUE);
- curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, TRUE);
- curl_easy_setopt(curl, CURLOPT_WRITEDATA, package_file);
- curl_easy_setopt(curl, CURLOPT_NOPROGRESS, FALSE);
- curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION,
- &download_progress_cb);
- curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, app_state);
-
- result = curl_easy_perform(curl);
- fclose(package_file);
- curl_easy_cleanup(curl);
-
- if (result)
- {
- LL_ERRS() << "Failed to download update: "
- << app_state->url
- << LL_ENDL;
-
- gdk_threads_enter();
- display_error(app_state->window,
- LLTrans::getString("UpdaterFailDownloadTitle"),
- LLTrans::getString("UpdaterFailUpdateDescriptive"));
- gdk_threads_leave();
-
- throw 0;
- }
- }
-
- // now pulse the progres bar back and forth while the package is
- // being unpacked
- gdk_threads_enter();
- std::string installing_msg = LLTrans::getString("UpdaterNowInstalling");
- gtk_progress_bar_set_text(
- GTK_PROGRESS_BAR(app_state->progress_bar),
- installing_msg.c_str());
- app_state->activity_mode = TRUE;
- gdk_threads_leave();
-
- // *TODO: if the destination is not writable, terminate this
- // thread and show file chooser?
- if (!install_package(app_state->file.c_str(), app_state->dest_dir))
- {
- LL_WARNS() << "Failed to install package to destination: "
- << app_state->dest_dir
- << LL_ENDL;
-
- gdk_threads_enter();
- display_error(app_state->window,
- LLTrans::getString("UpdaterFailInstallTitle"),
- LLTrans::getString("UpdaterFailUpdateDescriptive"));
- //"Failed to update " + app_state->app_name,
- gdk_threads_leave();
- throw 0;
- }
-
- // try to spawn the new viewer
- if (!spawn_viewer(app_state))
- {
- LL_WARNS() << "Viewer was not installed properly in : "
- << app_state->dest_dir
- << LL_ENDL;
-
- gdk_threads_enter();
- display_error(app_state->window,
- LLTrans::getString("UpdaterFailStartTitle"),
- LLTrans::getString("UpdaterFailUpdateDescriptive"));
- gdk_threads_leave();
- throw 0;
- }
- }
- catch (...)
- {
- app_state->failure = TRUE;
- }
-
- gdk_threads_enter();
- updater_app_quit(app_state);
- gdk_threads_leave();
-
- return NULL;
-}
-
-
-gboolean less_anal_gspawnsync(gchar **argv,
- gchar **stderr_output,
- gint *child_exit_status,
- GError **spawn_error)
-{
- // store current SIGCHLD handler if there is one, replace with default
- // handler to make glib happy
- struct sigaction sigchld_backup;
- struct sigaction sigchld_appease_glib;
- sigchld_appease_glib.sa_handler = SIG_DFL;
- sigemptyset(&sigchld_appease_glib.sa_mask);
- sigchld_appease_glib.sa_flags = 0;
- sigaction(SIGCHLD, &sigchld_appease_glib, &sigchld_backup);
-
- gboolean rtn = g_spawn_sync(NULL,
- argv,
- NULL,
- (GSpawnFlags) (G_SPAWN_STDOUT_TO_DEV_NULL),
- NULL,
- NULL,
- NULL,
- stderr_output,
- child_exit_status,
- spawn_error);
-
- // restore SIGCHLD handler
- sigaction(SIGCHLD, &sigchld_backup, NULL);
-
- return rtn;
-}
-
-
-// perform a rename, or perform a (prompted) root rename if that fails
-int
-rename_with_sudo_fallback(const std::string& filename, const std::string& newname)
-{
- int rtncode = ::rename(filename.c_str(), newname.c_str());
- LL_DEBUGS() << "rename result is: " << rtncode << " / " << errno << LL_ENDL;
- if (rtncode && (EACCES == errno || EPERM == errno || EXDEV == errno))
- {
- LL_INFOS() << "Permission problem in rename, or moving between different mount points. Retrying as a mv under a sudo." << LL_ENDL;
- // failed due to permissions, try again as a gksudo or kdesu mv wrapper hack
- char *sudo_cmd = NULL;
- sudo_cmd = g_find_program_in_path("gksudo");
- if (!sudo_cmd)
- {
- sudo_cmd = g_find_program_in_path("kdesu");
- }
- if (sudo_cmd)
- {
- char *mv_cmd = NULL;
- mv_cmd = g_find_program_in_path("mv");
- if (mv_cmd)
- {
- char *src_string_copy = g_strdup(filename.c_str());
- char *dst_string_copy = g_strdup(newname.c_str());
- char* argv[] =
- {
- sudo_cmd,
- mv_cmd,
- src_string_copy,
- dst_string_copy,
- NULL
- };
-
- gchar *stderr_output = NULL;
- gint child_exit_status = 0;
- GError *spawn_error = NULL;
- if (!less_anal_gspawnsync(argv, &stderr_output,
- &child_exit_status, &spawn_error))
- {
- LL_WARNS() << "Failed to spawn child process: "
- << spawn_error->message
- << LL_ENDL;
- }
- else if (child_exit_status)
- {
- LL_WARNS() << "mv command failed: "
- << (stderr_output ? stderr_output : "(no reason given)")
- << LL_ENDL;
- }
- else
- {
- // everything looks good, clear the error code
- rtncode = 0;
- }
-
- g_free(src_string_copy);
- g_free(dst_string_copy);
- if (spawn_error) g_error_free(spawn_error);
- }
- }
- }
- return rtncode;
-}
-
-gboolean install_package(std::string package_file, std::string destination)
-{
- char *tar_cmd = NULL;
- std::ostringstream command;
-
- // Find the absolute path to the 'tar' command.
- tar_cmd = g_find_program_in_path("tar");
- if (!tar_cmd)
- {
- LL_ERRS() << "`tar' was not found in $PATH" << LL_ENDL;
- return FALSE;
- }
- LL_INFOS() << "Found tar command: " << tar_cmd << LL_ENDL;
-
- // Unpack the tarball in a temporary place first, then move it to
- // its final destination
- std::string tmp_dest_dir = gDirUtilp->getTempFilename();
- if (LLFile::mkdir(tmp_dest_dir, 0744))
- {
- LL_ERRS() << "Failed to create directory: "
- << destination
- << LL_ENDL;
-
- return FALSE;
- }
-
- char *package_file_string_copy = g_strdup(package_file.c_str());
- char *tmp_dest_dir_string_copy = g_strdup(tmp_dest_dir.c_str());
- gchar *argv[8] = {
- tar_cmd,
- const_cast<gchar*>("--strip"), const_cast<gchar*>("1"),
- const_cast<gchar*>("-xjf"),
- package_file_string_copy,
- const_cast<gchar*>("-C"), tmp_dest_dir_string_copy,
- NULL,
- };
-
- LL_INFOS() << "Untarring package: " << package_file << LL_ENDL;
-
- // store current SIGCHLD handler if there is one, replace with default
- // handler to make glib happy
- struct sigaction sigchld_backup;
- struct sigaction sigchld_appease_glib;
- sigchld_appease_glib.sa_handler = SIG_DFL;
- sigemptyset(&sigchld_appease_glib.sa_mask);
- sigchld_appease_glib.sa_flags = 0;
- sigaction(SIGCHLD, &sigchld_appease_glib, &sigchld_backup);
-
- gchar *stderr_output = NULL;
- gint child_exit_status = 0;
- GError *untar_error = NULL;
- if (!less_anal_gspawnsync(argv, &stderr_output,
- &child_exit_status, &untar_error))
- {
- LL_WARNS() << "Failed to spawn child process: "
- << untar_error->message
- << LL_ENDL;
- return FALSE;
- }
-
- if (child_exit_status)
- {
- LL_WARNS() << "Untar command failed: "
- << (stderr_output ? stderr_output : "(no reason given)")
- << LL_ENDL;
- return FALSE;
- }
-
- g_free(tar_cmd);
- g_free(package_file_string_copy);
- g_free(tmp_dest_dir_string_copy);
- g_free(stderr_output);
- if (untar_error) g_error_free(untar_error);
-
- // move the existing package out of the way if it exists
- if (gDirUtilp->fileExists(destination))
- {
- std::string backup_dir = destination + ".backup";
- int oldcounter = 1;
- while (gDirUtilp->fileExists(backup_dir))
- {
- // find a foo.backup.N folder name that isn't taken yet
- backup_dir = destination + ".backup." + llformat("%d", oldcounter);
- ++oldcounter;
- }
-
- if (rename_with_sudo_fallback(destination, backup_dir))
- {
- LL_WARNS() << "Failed to move directory: '"
- << destination << "' -> '" << backup_dir
- << LL_ENDL;
- return FALSE;
- }
- }
-
- // The package has been unpacked in a staging directory, now we just
- // need to move it to its destination.
- if (rename_with_sudo_fallback(tmp_dest_dir, destination))
- {
- LL_WARNS() << "Failed to move installation to the destination: "
- << destination
- << LL_ENDL;
- return FALSE;
- }
-
- // \0/ Success!
- return TRUE;
-}
-
-gboolean progress_update_timeout(gpointer data)
-{
- UpdaterAppState *app_state;
-
- llassert(data != NULL);
-
- app_state = (UpdaterAppState *) data;
-
- gdk_threads_enter();
- if (app_state->activity_mode)
- {
- gtk_progress_bar_pulse
- (GTK_PROGRESS_BAR(app_state->progress_bar));
- }
- else
- {
- gtk_progress_set_value(GTK_PROGRESS(app_state->progress_bar),
- app_state->progress_value);
- }
- gdk_threads_leave();
-
- return TRUE;
-}
-
-gboolean update_progress_text_timeout(gpointer data)
-{
- UpdaterAppState *app_state;
-
- llassert(data != NULL);
- app_state = (UpdaterAppState *) data;
-
- if (app_state->activity_mode == TRUE)
- {
- // We no longer need this timeout, it will be removed.
- return FALSE;
- }
-
- if (!app_state->progress_value)
- {
- return TRUE;
- }
-
- std::string progress_text = llformat((LLTrans::getString("UpdaterProgressBarText")+" (%.0f%%)").c_str(), app_state->progress_value);
-
- gdk_threads_enter();
- gtk_progress_bar_set_text(GTK_PROGRESS_BAR(app_state->progress_bar),
- progress_text.c_str());
- gdk_threads_leave();
-
- return TRUE;
-}
-
-int download_progress_cb(gpointer data,
- double t,
- double d,
- double utotal,
- double ulnow)
-{
- UpdaterAppState *app_state;
-
- llassert(data != NULL);
- app_state = (UpdaterAppState *) data;
-
- if (t <= 0.0)
- {
- app_state->progress_value = 0;
- }
- else
- {
- app_state->progress_value = d * 100.0 / t;
- }
- return 0;
-}
-
-BOOL spawn_viewer(UpdaterAppState *app_state)
-{
- llassert(app_state != NULL);
-
- std::string cmd = app_state->dest_dir + "/secondlife";
- GError *error = NULL;
-
- // We want to spawn the Viewer on the same display as the updater app
- gboolean success = gdk_spawn_command_line_on_screen
- (gtk_widget_get_screen(app_state->window), cmd.c_str(), &error);
-
- if (!success)
- {
- LL_WARNS() << "Failed to launch viewer: " << error->message
- << LL_ENDL;
- }
-
- if (error) g_error_free(error);
-
- return success;
-}
-
-void show_usage_and_exit()
-{
- std::cout << "Usage: linux-updater <--url URL | --file FILE> --name NAME --dest PATH --stringsdir PATH1,PATH2 --stringsfile FILE"
- << "[--image-dir PATH]"
- << std::endl;
- exit(1);
-}
-
-void parse_args_and_init(int argc, char **argv, UpdaterAppState *app_state)
-{
- int i;
-
- for (i = 1; i < argc; i++)
- {
- if ((!strcmp(argv[i], "--url")) && (++i < argc))
- {
- app_state->url = argv[i];
- }
- else if ((!strcmp(argv[i], "--file")) && (++i < argc))
- {
- app_state->file = argv[i];
- }
- else if ((!strcmp(argv[i], "--name")) && (++i < argc))
- {
- app_state->app_name = argv[i];
- }
- else if ((!strcmp(argv[i], "--image-dir")) && (++i < argc))
- {
- app_state->image_dir = argv[i];
- app_state->image_dir_iter = new LLDirIterator(argv[i], "*.jpg");
- }
- else if ((!strcmp(argv[i], "--dest")) && (++i < argc))
- {
- app_state->dest_dir = argv[i];
- }
- else if ((!strcmp(argv[i], "--stringsdir")) && (++i < argc))
- {
- app_state->strings_dirs = argv[i];
- }
- else if ((!strcmp(argv[i], "--stringsfile")) && (++i < argc))
- {
- app_state->strings_file = argv[i];
- }
- else
- {
- // show usage, an invalid option was given.
- show_usage_and_exit();
- }
- }
-
- if (app_state->app_name.empty()
- || (app_state->url.empty() && app_state->file.empty())
- || app_state->dest_dir.empty())
- {
- show_usage_and_exit();
- }
-
- app_state->progress_value = 0.0;
- app_state->activity_mode = FALSE;
- app_state->failure = FALSE;
-
- translate_init(app_state->strings_dirs, app_state->strings_file);
-}
-
-int main(int argc, char **argv)
-{
- UpdaterAppState* app_state = new UpdaterAppState;
-
- parse_args_and_init(argc, argv, app_state);
-
- // Initialize logger, and rename old log file
- gDirUtilp->initAppDirs("SecondLife");
- LLError::initForApplication
- (gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
- std::string old_log_file = gDirUtilp->getExpandedFilename
- (LL_PATH_LOGS, "updater.log.old");
- std::string log_file =
- gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "updater.log");
- LLFile::rename(log_file, old_log_file);
- LLError::logToFile(log_file);
-
- // initialize gthreads and gtk+
- if (!g_thread_supported())
- {
- g_thread_init(NULL);
- gdk_threads_init();
- }
-
- gtk_init(&argc, &argv);
-
- // create UI
- updater_app_ui_init(app_state);
-
- //LL_INFOS() << "SAMPLE TRANSLATION IS: " << LLTrans::getString("LoginInProgress") << LL_ENDL;
-
- // create download thread
- g_thread_create(GThreadFunc(worker_thread_cb), app_state, FALSE, NULL);
-
- gdk_threads_enter();
- gtk_main();
- gdk_threads_leave();
-
- // Delete the file only if created from url download.
- if(!app_state->url.empty() && !app_state->file.empty())
- {
- if (gDirUtilp->fileExists(app_state->file))
- {
- LLFile::remove(app_state->file);
- }
- }
-
- bool success = !app_state->failure;
- delete app_state->image_dir_iter;
- delete app_state;
- return success ? 0 : 1;
-}
-
-/*****************************************************************************
-* Dummy LLTrans implementation (IQA-490)
-*****************************************************************************/
-static LLTrans sStaticStrings;
-
-// lookup
-std::string LLTrans::_getString(const std::string& key) const
-{
- MessageMap::const_iterator found = mMessages.find(key);
- if (found != mMessages.end())
- {
- return found->second;
- }
- LL_WARNS("linux_updater") << "No message for key '" << key
- << "' -- add to LLTrans::LLTrans() in linux_updater.cpp"
- << LL_ENDL;
- return key;
-}
-
-// static lookup
-std::string LLTrans::getString(const std::string& key)
-{
- return sLLTransInstance._getString(key);
-}
-
-// initialization
-LLTrans::LLTrans()
-{
- typedef std::pair<const char*, const char*> Pair;
- static const Pair data[] =
- {
- Pair("UpdaterFailDownloadTitle",
- "Failed to download update"),
- Pair("UpdaterFailInstallTitle",
- "Failed to install update"),
- Pair("UpdaterFailStartTitle",
- "Failed to start viewer"),
- Pair("UpdaterFailUpdateDescriptive",
- "An error occurred while updating Second Life. "
- "Please download the latest version from www.secondlife.com."),
- Pair("UpdaterNowInstalling",
- "Installing Second Life..."),
- Pair("UpdaterNowUpdating",
- "Now updating Second Life..."),
- Pair("UpdaterProgressBarText",
- "Downloading update"),
- Pair("UpdaterProgressBarTextWithEllipses",
- "Downloading update..."),
- Pair("UpdaterUpdatingDescriptive",
- "Your Second Life Viewer is being updated to the latest release. "
- "This may take some time, so please be patient."),
- Pair("UpdaterWindowTitle",
- "Second Life Update")
- };
-
- BOOST_FOREACH(Pair pair, data)
- {
- mMessages[pair.first] = pair.second;
- }
-}
diff --git a/indra/mac_updater/mac_updater.cpp b/indra/mac_updater/mac_updater.cpp
deleted file mode 100644
index f533d47b18..0000000000
--- a/indra/mac_updater/mac_updater.cpp
+++ /dev/null
@@ -1,1266 +0,0 @@
-/**
- * @file mac_updater.cpp
- * @brief
- *
- * $LicenseInfo:firstyear=2006&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "linden_common.h"
-
-#include <boost/format.hpp>
-
-#include <libgen.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include <curl/curl.h>
-#include <pthread.h>
-
-#include "llerror.h"
-#include "lltimer.h"
-#include "lldir.h"
-#include "llfile.h"
-
-#include "llstring.h"
-
-#include <Carbon/Carbon.h>
-
-#include "llerrorcontrol.h"
-
-#if LL_DARWIN
-// FSPathMakeRef, FSObjectCopy, deprecations...
-#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-#endif
-
-enum
-{
- kEventClassCustom = 'Cust',
- kEventCustomProgress = 'Prog',
- kEventParamCustomCurValue = 'Cur ',
- kEventParamCustomMaxValue = 'Max ',
- kEventParamCustomText = 'Text',
- kEventCustomDone = 'Done',
-};
-
-WindowRef gWindow = NULL;
-EventHandlerRef gEventHandler = NULL;
-OSStatus gFailure = noErr;
-Boolean gCancelled = false;
-
-const char *gUpdateURL;
-const char *gProductName;
-const char *gBundleID;
-const char *gDmgFile;
-const char *gMarkerPath;
-
-void *updatethreadproc(void*);
-
-pthread_t updatethread;
-
-OSStatus setProgress(int cur, int max)
-{
- OSStatus err;
- ControlRef progressBar = NULL;
- ControlID id;
-
- id.signature = 'prog';
- id.id = 0;
-
- err = GetControlByID(gWindow, &id, &progressBar);
- if(err == noErr)
- {
- Boolean indeterminate;
-
- if(max == 0)
- {
- indeterminate = true;
- err = SetControlData(progressBar, kControlEntireControl, kControlProgressBarIndeterminateTag, sizeof(Boolean), (Ptr)&indeterminate);
- }
- else
- {
- double percentage = (double)cur / (double)max;
- SetControlMinimum(progressBar, 0);
- SetControlMaximum(progressBar, 100);
- SetControlValue(progressBar, (SInt16)(percentage * 100));
-
- indeterminate = false;
- err = SetControlData(progressBar, kControlEntireControl, kControlProgressBarIndeterminateTag, sizeof(Boolean), (Ptr)&indeterminate);
-
- Draw1Control(progressBar);
- }
- }
-
- return(err);
-}
-
-OSStatus setProgressText(CFStringRef text)
-{
- OSStatus err;
- ControlRef progressText = NULL;
- ControlID id;
-
- id.signature = 'what';
- id.id = 0;
-
- err = GetControlByID(gWindow, &id, &progressText);
- if(err == noErr)
- {
- err = SetControlData(progressText, kControlEntireControl, kControlStaticTextCFStringTag, sizeof(CFStringRef), (Ptr)&text);
- Draw1Control(progressText);
- }
-
- return(err);
-}
-
-OSStatus sendProgress(long cur, long max, CFStringRef text = NULL)
-{
- OSStatus result;
- EventRef evt;
-
- result = CreateEvent(
- NULL,
- kEventClassCustom,
- kEventCustomProgress,
- 0,
- kEventAttributeNone,
- &evt);
-
- // This event needs to be targeted at the window so it goes to the window's handler.
- if(result == noErr)
- {
- EventTargetRef target = GetWindowEventTarget(gWindow);
- result = SetEventParameter (
- evt,
- kEventParamPostTarget,
- typeEventTargetRef,
- sizeof(target),
- &target);
- }
-
- if(result == noErr)
- {
- result = SetEventParameter (
- evt,
- kEventParamCustomCurValue,
- typeLongInteger,
- sizeof(cur),
- &cur);
- }
-
- if(result == noErr)
- {
- result = SetEventParameter (
- evt,
- kEventParamCustomMaxValue,
- typeLongInteger,
- sizeof(max),
- &max);
- }
-
- if(result == noErr)
- {
- if(text != NULL)
- {
- result = SetEventParameter (
- evt,
- kEventParamCustomText,
- typeCFStringRef,
- sizeof(text),
- &text);
- }
- }
-
- if(result == noErr)
- {
- // Send the event
- PostEventToQueue(
- GetMainEventQueue(),
- evt,
- kEventPriorityStandard);
-
- }
-
- return(result);
-}
-
-OSStatus sendDone(void)
-{
- OSStatus result;
- EventRef evt;
-
- result = CreateEvent(
- NULL,
- kEventClassCustom,
- kEventCustomDone,
- 0,
- kEventAttributeNone,
- &evt);
-
- // This event needs to be targeted at the window so it goes to the window's handler.
- if(result == noErr)
- {
- EventTargetRef target = GetWindowEventTarget(gWindow);
- result = SetEventParameter (
- evt,
- kEventParamPostTarget,
- typeEventTargetRef,
- sizeof(target),
- &target);
- }
-
- if(result == noErr)
- {
- // Send the event
- PostEventToQueue(
- GetMainEventQueue(),
- evt,
- kEventPriorityStandard);
-
- }
-
- return(result);
-}
-
-OSStatus dialogHandler(EventHandlerCallRef handler, EventRef event, void *userdata)
-{
- OSStatus result = eventNotHandledErr;
- OSStatus err;
- UInt32 evtClass = GetEventClass(event);
- UInt32 evtKind = GetEventKind(event);
-
- if((evtClass == kEventClassCommand) && (evtKind == kEventCommandProcess))
- {
- HICommand cmd;
- err = GetEventParameter(event, kEventParamDirectObject, typeHICommand, NULL, sizeof(cmd), NULL, &cmd);
-
- if(err == noErr)
- {
- switch(cmd.commandID)
- {
- case kHICommandCancel:
- gCancelled = true;
-// QuitAppModalLoopForWindow(gWindow);
- result = noErr;
- break;
- }
- }
- }
- else if((evtClass == kEventClassCustom) && (evtKind == kEventCustomProgress))
- {
- // Request to update the progress dialog
- long cur = 0;
- long max = 0;
- CFStringRef text = NULL;
- (void) GetEventParameter(event, kEventParamCustomCurValue, typeLongInteger, NULL, sizeof(cur), NULL, &cur);
- (void) GetEventParameter(event, kEventParamCustomMaxValue, typeLongInteger, NULL, sizeof(max), NULL, &max);
- (void) GetEventParameter(event, kEventParamCustomText, typeCFStringRef, NULL, sizeof(text), NULL, &text);
-
- err = setProgress(cur, max);
- if(err == noErr)
- {
- if(text != NULL)
- {
- setProgressText(text);
- }
- }
-
- result = noErr;
- }
- else if((evtClass == kEventClassCustom) && (evtKind == kEventCustomDone))
- {
- // We're done. Exit the modal loop.
- QuitAppModalLoopForWindow(gWindow);
- result = noErr;
- }
-
- return(result);
-}
-
-#if 0
-size_t curl_download_callback(void *data, size_t size, size_t nmemb,
- void *user_data)
-{
- S32 bytes = size * nmemb;
- char *cdata = (char *) data;
- for (int i =0; i < bytes; i += 1)
- {
- gServerResponse.append(cdata[i]);
- }
- return bytes;
-}
-#endif
-
-int curl_progress_callback_func(void *clientp,
- double dltotal,
- double dlnow,
- double ultotal,
- double ulnow)
-{
- int max = (int)(dltotal / 1024.0);
- int cur = (int)(dlnow / 1024.0);
- sendProgress(cur, max);
-
- if(gCancelled)
- return(1);
-
- return(0);
-}
-
-int parse_args(int argc, char **argv)
-{
- int j;
-
- for (j = 1; j < argc; j++)
- {
- if ((!strcmp(argv[j], "-url")) && (++j < argc))
- {
- gUpdateURL = argv[j];
- }
- else if ((!strcmp(argv[j], "-name")) && (++j < argc))
- {
- gProductName = argv[j];
- }
- else if ((!strcmp(argv[j], "-bundleid")) && (++j < argc))
- {
- gBundleID = argv[j];
- }
- else if ((!strcmp(argv[j], "-dmg")) && (++j < argc))
- {
- gDmgFile = argv[j];
- }
- else if ((!strcmp(argv[j], "-marker")) && (++j < argc))
- {
- gMarkerPath = argv[j];;
- }
- }
-
- return 0;
-}
-
-int main(int argc, char **argv)
-{
- // We assume that all the logs we're looking for reside on the current drive
- gDirUtilp->initAppDirs("SecondLife");
-
- LLError::initForApplication( gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
-
- // Rename current log file to ".old"
- std::string old_log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "updater.log.old");
- std::string log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "updater.log");
- LLFile::rename(log_file.c_str(), old_log_file.c_str());
-
- // Set the log file to updater.log
- LLError::logToFile(log_file);
-
- /////////////////////////////////////////
- //
- // Process command line arguments
- //
- gUpdateURL = NULL;
- gProductName = NULL;
- gBundleID = NULL;
- gDmgFile = NULL;
- gMarkerPath = NULL;
- parse_args(argc, argv);
- if ((gUpdateURL == NULL) && (gDmgFile == NULL))
- {
- llinfos << "Usage: mac_updater -url <url> | -dmg <dmg file> [-name <product_name>] [-program <program_name>]" << llendl;
- exit(1);
- }
- else
- {
- llinfos << "Update url is: " << gUpdateURL << llendl;
- if (gProductName)
- {
- llinfos << "Product name is: " << gProductName << llendl;
- }
- else
- {
- gProductName = "Second Life";
- }
- if (gBundleID)
- {
- llinfos << "Bundle ID is: " << gBundleID << llendl;
- }
- else
- {
- gBundleID = "com.secondlife.indra.viewer";
- }
- }
-
- llinfos << "Starting " << gProductName << " Updater" << llendl;
-
- // Real UI...
- OSStatus err;
- IBNibRef nib = NULL;
-
- err = CreateNibReference(CFSTR("AutoUpdater"), &nib);
-
- char windowTitle[MAX_PATH]; /* Flawfinder: ignore */
- snprintf(windowTitle, sizeof(windowTitle), "%s Updater", gProductName);
- CFStringRef windowTitleRef = NULL;
- windowTitleRef = CFStringCreateWithCString(NULL, windowTitle, kCFStringEncodingUTF8);
-
- if(err == noErr)
- {
- err = CreateWindowFromNib(nib, CFSTR("Updater"), &gWindow);
- }
-
- if (err == noErr)
- {
- err = SetWindowTitleWithCFString(gWindow, windowTitleRef);
- }
- CFRelease(windowTitleRef);
-
- if(err == noErr)
- {
- // Set up an event handler for the window.
- EventTypeSpec handlerEvents[] =
- {
- { kEventClassCommand, kEventCommandProcess },
- { kEventClassCustom, kEventCustomProgress },
- { kEventClassCustom, kEventCustomDone }
- };
- InstallStandardEventHandler(GetWindowEventTarget(gWindow));
- InstallWindowEventHandler(
- gWindow,
- NewEventHandlerUPP(dialogHandler),
- GetEventTypeCount (handlerEvents),
- handlerEvents,
- 0,
- &gEventHandler);
- }
-
- if(err == noErr)
- {
- ShowWindow(gWindow);
- SelectWindow(gWindow);
- }
-
- if(err == noErr)
- {
- pthread_create(&updatethread,
- NULL,
- &updatethreadproc,
- NULL);
-
- }
-
- if(err == noErr)
- {
- RunAppModalLoopForWindow(gWindow);
- }
-
- void *threadresult;
-
- pthread_join(updatethread, &threadresult);
-
- if(!gCancelled && (gFailure != noErr))
- {
- // Something went wrong. Since we always just tell the user to download a new version, we don't really care what.
- AlertStdCFStringAlertParamRec params;
- SInt16 retval_mac = 1;
- DialogRef alert = NULL;
- OSStatus err;
-
- params.version = kStdCFStringAlertVersionOne;
- params.movable = false;
- params.helpButton = false;
- params.defaultText = (CFStringRef)kAlertDefaultOKText;
- params.cancelText = 0;
- params.otherText = 0;
- params.defaultButton = 1;
- params.cancelButton = 0;
- params.position = kWindowDefaultPosition;
- params.flags = 0;
-
- err = CreateStandardAlert(
- kAlertStopAlert,
- CFSTR("Error"),
- CFSTR("An error occurred while updating Second Life. Please download the latest version from www.secondlife.com."),
- &params,
- &alert);
-
- if(err == noErr)
- {
- err = RunStandardAlert(
- alert,
- NULL,
- &retval_mac);
- }
-
- if(gMarkerPath != 0)
- {
- // Create a install fail marker that can be used by the viewer to
- // detect install problems.
- std::ofstream stream(gMarkerPath);
- if(stream) stream << -1;
- }
- exit(-1);
- } else {
- exit(0);
- }
-
- if(gWindow != NULL)
- {
- DisposeWindow(gWindow);
- }
-
- if(nib != NULL)
- {
- DisposeNibReference(nib);
- }
-
- return 0;
-}
-
-bool isDirWritable(FSRef &dir)
-{
- bool result = false;
-
- // Test for a writable directory by creating a directory, then deleting it again.
- // This is kinda lame, but will pretty much always give the right answer.
-
- OSStatus err = noErr;
- char temp[PATH_MAX] = ""; /* Flawfinder: ignore */
-
- err = FSRefMakePath(&dir, (UInt8*)temp, sizeof(temp));
-
- if(err == noErr)
- {
- strncat(temp, "/.test_XXXXXX", (sizeof(temp) - strlen(temp)) - 1);
-
- if(mkdtemp(temp) != NULL)
- {
- // We were able to make the directory. This means the directory is writable.
- result = true;
-
- // Clean up.
- rmdir(temp);
- }
- }
-
-#if 0
- // This seemed like a good idea, but won't tell us if we're on a volume mounted read-only.
- UInt8 perm;
- err = FSGetUserPrivilegesPermissions(&targetParentRef, &perm, NULL);
- if(err == noErr)
- {
- if(perm & kioACUserNoMakeChangesMask)
- {
- // Parent directory isn't writable.
- llinfos << "Target parent directory not writable." << llendl;
- err = -1;
- replacingTarget = false;
- }
- }
-#endif
-
- return result;
-}
-
-static std::string HFSUniStr255_to_utf8str(const HFSUniStr255* src)
-{
- llutf16string string16((U16*)&(src->unicode), src->length);
- std::string result = utf16str_to_utf8str(string16);
- return result;
-}
-
-int restoreObject(const char* aside, const char* target, const char* path, const char* object)
-{
- char source[PATH_MAX] = ""; /* Flawfinder: ignore */
- char dest[PATH_MAX] = ""; /* Flawfinder: ignore */
- snprintf(source, sizeof(source), "%s/%s/%s", aside, path, object);
- snprintf(dest, sizeof(dest), "%s/%s", target, path);
- FSRef sourceRef;
- FSRef destRef;
- OSStatus err;
- err = FSPathMakeRef((UInt8 *)source, &sourceRef, NULL);
- if(err != noErr) return false;
- err = FSPathMakeRef((UInt8 *)dest, &destRef, NULL);
- if(err != noErr) return false;
-
- llinfos << "Copying " << source << " to " << dest << llendl;
-
- err = FSCopyObjectSync(
- &sourceRef,
- &destRef,
- NULL,
- NULL,
- kFSFileOperationOverwrite);
-
- if(err != noErr) return false;
- return true;
-}
-
-// Replace any mention of "Second Life" with the product name.
-void filterFile(const char* filename)
-{
- char temp[PATH_MAX] = ""; /* Flawfinder: ignore */
- // First copy the target's version, so we can run it through sed.
- snprintf(temp, sizeof(temp), "cp '%s' '%s.tmp'", filename, filename);
- system(temp); /* Flawfinder: ignore */
-
- // Now run it through sed.
- snprintf(temp, sizeof(temp),
- "sed 's/Second Life/%s/g' '%s.tmp' > '%s'", gProductName, filename, filename);
- system(temp); /* Flawfinder: ignore */
-}
-
-static bool isFSRefViewerBundle(FSRef *targetRef)
-{
- bool result = false;
- CFURLRef targetURL = NULL;
- CFBundleRef targetBundle = NULL;
- CFStringRef targetBundleID = NULL;
- CFStringRef sourceBundleID = NULL;
-
- targetURL = CFURLCreateFromFSRef(NULL, targetRef);
-
- if(targetURL == NULL)
- {
- llinfos << "Error creating target URL." << llendl;
- }
- else
- {
- targetBundle = CFBundleCreate(NULL, targetURL);
- }
-
- if(targetBundle == NULL)
- {
- llinfos << "Failed to create target bundle." << llendl;
- }
- else
- {
- targetBundleID = CFBundleGetIdentifier(targetBundle);
- }
-
- if(targetBundleID == NULL)
- {
- llinfos << "Couldn't retrieve target bundle ID." << llendl;
- }
- else
- {
- sourceBundleID = CFStringCreateWithCString(NULL, gBundleID, kCFStringEncodingUTF8);
- if(CFStringCompare(sourceBundleID, targetBundleID, 0) == kCFCompareEqualTo)
- {
- // This is the bundle we're looking for.
- result = true;
- }
- else
- {
- llinfos << "Target bundle ID mismatch." << llendl;
- }
- }
-
- // Don't release targetBundleID -- since we don't retain it, it's released when targetBundle is released.
- if(targetURL != NULL)
- CFRelease(targetURL);
- if(targetBundle != NULL)
- CFRelease(targetBundle);
-
- return result;
-}
-
-// Search through the directory specified by 'parent' for an item that appears to be a Second Life viewer.
-static OSErr findAppBundleOnDiskImage(FSRef *parent, FSRef *app)
-{
- FSIterator iterator;
- bool found = false;
-
- OSErr err = FSOpenIterator( parent, kFSIterateFlat, &iterator );
- if(!err)
- {
- do
- {
- ItemCount actualObjects = 0;
- Boolean containerChanged = false;
- FSCatalogInfo info;
- FSRef ref;
- HFSUniStr255 unicodeName;
- err = FSGetCatalogInfoBulk(
- iterator,
- 1,
- &actualObjects,
- &containerChanged,
- kFSCatInfoNodeFlags,
- &info,
- &ref,
- NULL,
- &unicodeName );
-
- if(actualObjects == 0)
- break;
-
- if(!err)
- {
- // Call succeeded and not done with the iteration.
- std::string name = HFSUniStr255_to_utf8str(&unicodeName);
-
- llinfos << "Considering \"" << name << "\"" << llendl;
-
- if(info.nodeFlags & kFSNodeIsDirectoryMask)
- {
- // This is a directory. See if it's a .app
- if(name.find(".app") != std::string::npos)
- {
- // Looks promising. Check to see if it has the right bundle identifier.
- if(isFSRefViewerBundle(&ref))
- {
- llinfos << name << " is the one" << llendl;
- // This is the one. Return it.
- *app = ref;
- found = true;
- break;
- } else {
- llinfos << name << " is not the bundle we are looking for; move along" << llendl;
- }
-
- }
- }
- }
- }
- while(!err);
-
- llinfos << "closing the iterator" << llendl;
-
- FSCloseIterator(iterator);
-
- llinfos << "closed" << llendl;
- }
-
- if(!err && !found)
- err = fnfErr;
-
- return err;
-}
-
-void *updatethreadproc(void*)
-{
- char tempDir[PATH_MAX] = ""; /* Flawfinder: ignore */
- FSRef tempDirRef;
- char temp[PATH_MAX] = ""; /* Flawfinder: ignore */
- // *NOTE: This buffer length is used in a scanf() below.
- char deviceNode[1024] = ""; /* Flawfinder: ignore */
- LLFILE *downloadFile = NULL;
- OSStatus err;
- ProcessSerialNumber psn;
- char target[PATH_MAX] = ""; /* Flawfinder: ignore */
- FSRef targetRef;
- FSRef targetParentRef;
- FSVolumeRefNum targetVol;
- FSRef trashFolderRef;
- Boolean replacingTarget = false;
-
- memset(&tempDirRef, 0, sizeof(tempDirRef));
- memset(&targetRef, 0, sizeof(targetRef));
- memset(&targetParentRef, 0, sizeof(targetParentRef));
-
- try
- {
- // Attempt to get a reference to the Second Life application bundle containing this updater.
- // Any failures during this process will cause us to default to updating /Applications/Second Life.app
- {
- FSRef myBundle;
-
- err = GetCurrentProcess(&psn);
- if(err == noErr)
- {
- err = GetProcessBundleLocation(&psn, &myBundle);
- }
-
- if(err == noErr)
- {
- // Sanity check: Make sure the name of the item referenced by targetRef is "Second Life.app".
- FSRefMakePath(&myBundle, (UInt8*)target, sizeof(target));
-
- llinfos << "Updater bundle location: " << target << llendl;
- }
-
- // Our bundle should be in Second Life.app/Contents/Resources/AutoUpdater.app
- // so we need to go up 3 levels to get the path to the main application bundle.
- if(err == noErr)
- {
- err = FSGetCatalogInfo(&myBundle, kFSCatInfoNone, NULL, NULL, NULL, &targetRef);
- }
- if(err == noErr)
- {
- err = FSGetCatalogInfo(&targetRef, kFSCatInfoNone, NULL, NULL, NULL, &targetRef);
- }
- if(err == noErr)
- {
- err = FSGetCatalogInfo(&targetRef, kFSCatInfoNone, NULL, NULL, NULL, &targetRef);
- }
-
- // And once more to get the parent of the target
- if(err == noErr)
- {
- err = FSGetCatalogInfo(&targetRef, kFSCatInfoNone, NULL, NULL, NULL, &targetParentRef);
- }
-
- if(err == noErr)
- {
- FSRefMakePath(&targetRef, (UInt8*)target, sizeof(target));
- llinfos << "Path to target: " << target << llendl;
- }
-
- // Sanity check: make sure the target is a bundle with the right identifier
- if(err == noErr)
- {
- // Assume the worst...
- err = -1;
-
- if(isFSRefViewerBundle(&targetRef))
- {
- // This is the bundle we're looking for.
- err = noErr;
- replacingTarget = true;
- }
- }
-
- // Make sure the target's parent directory is writable.
- if(err == noErr)
- {
- if(!isDirWritable(targetParentRef))
- {
- // Parent directory isn't writable.
- llinfos << "Target parent directory not writable." << llendl;
- err = -1;
- replacingTarget = false;
- }
- }
-
- if(err != noErr)
- {
- Boolean isDirectory;
- llinfos << "Target search failed, defaulting to /Applications/" << gProductName << ".app." << llendl;
-
- // Set up the parent directory
- err = FSPathMakeRef((UInt8*)"/Applications", &targetParentRef, &isDirectory);
- if((err != noErr) || (!isDirectory))
- {
- // We're so hosed.
- llinfos << "Applications directory not found, giving up." << llendl;
- throw 0;
- }
-
- snprintf(target, sizeof(target), "/Applications/%s.app", gProductName);
-
- memset(&targetRef, 0, sizeof(targetRef));
- err = FSPathMakeRef((UInt8*)target, &targetRef, NULL);
- if(err == fnfErr)
- {
- // This is fine, just means we're not replacing anything.
- err = noErr;
- replacingTarget = false;
- }
- else
- {
- replacingTarget = true;
- }
-
- // Make sure the target's parent directory is writable.
- if(err == noErr)
- {
- if(!isDirWritable(targetParentRef))
- {
- // Parent directory isn't writable.
- llinfos << "Target parent directory not writable." << llendl;
- err = -1;
- replacingTarget = false;
- }
- }
-
- }
-
- // If we haven't fixed all problems by this point, just bail.
- if(err != noErr)
- {
- llinfos << "Unable to pick a target, giving up." << llendl;
- throw 0;
- }
- }
-
- // Find the volID of the volume the target resides on
- {
- FSCatalogInfo info;
- err = FSGetCatalogInfo(
- &targetParentRef,
- kFSCatInfoVolume,
- &info,
- NULL,
- NULL,
- NULL);
-
- if(err != noErr)
- throw 0;
-
- targetVol = info.volume;
- }
-
- // Find the temporary items and trash folders on that volume.
- err = FSFindFolder(
- targetVol,
- kTrashFolderType,
- true,
- &trashFolderRef);
-
- if(err != noErr)
- throw 0;
-
-#if 0 // *HACK for DEV-11935 see below for details.
-
- FSRef tempFolderRef;
-
- err = FSFindFolder(
- targetVol,
- kTemporaryFolderType,
- true,
- &tempFolderRef);
-
- if(err != noErr)
- throw 0;
-
- err = FSRefMakePath(&tempFolderRef, (UInt8*)temp, sizeof(temp));
-
- if(err != noErr)
- throw 0;
-
-#else
-
- // *HACK for DEV-11935 the above kTemporaryFolderType query was giving
- // back results with path names that seem to be too long to be used as
- // mount points. I suspect this incompatibility was introduced in the
- // Leopard 10.5.2 update, but I have not verified this.
- char const HARDCODED_TMP[] = "/tmp";
- strncpy(temp, HARDCODED_TMP, sizeof(HARDCODED_TMP));
-
-#endif // 0 *HACK for DEV-11935
-
- // Skip downloading the file if the dmg was passed on the command line.
- std::string dmgName;
- if(gDmgFile != NULL) {
- dmgName = basename((char *)gDmgFile);
- char * dmgDir = dirname((char *)gDmgFile);
- strncpy(tempDir, dmgDir, sizeof(tempDir));
- err = FSPathMakeRef((UInt8*)tempDir, &tempDirRef, NULL);
- if(err != noErr) throw 0;
- chdir(tempDir);
- goto begin_install;
- } else {
- // Continue on to download file.
- dmgName = "SecondLife.dmg";
- }
-
-
- strncat(temp, "/SecondLifeUpdate_XXXXXX", (sizeof(temp) - strlen(temp)) - 1);
- if(mkdtemp(temp) == NULL)
- {
- throw 0;
- }
-
- strncpy(tempDir, temp, sizeof(tempDir));
- temp[sizeof(tempDir) - 1] = '\0';
-
- llinfos << "tempDir is " << tempDir << llendl;
-
- err = FSPathMakeRef((UInt8*)tempDir, &tempDirRef, NULL);
-
- if(err != noErr)
- throw 0;
-
- chdir(tempDir);
-
- snprintf(temp, sizeof(temp), "SecondLife.dmg");
-
- downloadFile = LLFile::fopen(temp, "wb"); /* Flawfinder: ignore */
- if(downloadFile == NULL)
- {
- throw 0;
- }
-
- {
- CURL *curl = curl_easy_init();
-
- curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
- // curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &curl_download_callback);
- curl_easy_setopt(curl, CURLOPT_FILE, downloadFile);
- curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
- curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, &curl_progress_callback_func);
- curl_easy_setopt(curl, CURLOPT_URL, gUpdateURL);
- curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
-
- sendProgress(0, 1, CFSTR("Downloading..."));
-
- CURLcode result = curl_easy_perform(curl);
-
- curl_easy_cleanup(curl);
-
- if(gCancelled)
- {
- llinfos << "User cancel, bailing out."<< llendl;
- throw 0;
- }
-
- if(result != CURLE_OK)
- {
- llinfos << "Error " << result << " while downloading disk image."<< llendl;
- throw 0;
- }
-
- fclose(downloadFile);
- downloadFile = NULL;
- }
-
- begin_install:
- sendProgress(0, 0, CFSTR("Mounting image..."));
- LLFile::mkdir("mnt", 0700);
-
- // NOTE: we could add -private at the end of this command line to keep the image from showing up in the Finder,
- // but if our cleanup fails, this makes it much harder for the user to unmount the image.
- std::string mountOutput;
- boost::format cmdFormat("hdiutil attach %s -mountpoint mnt");
- cmdFormat % dmgName;
- FILE* mounter = popen(cmdFormat.str().c_str(), "r"); /* Flawfinder: ignore */
-
- if(mounter == NULL)
- {
- llinfos << "Failed to mount disk image, exiting."<< llendl;
- throw 0;
- }
-
- // We need to scan the output from hdiutil to find the device node it uses to attach the disk image.
- // If we don't have this information, we can't detach it later.
- while(mounter != NULL)
- {
- size_t len = fread(temp, 1, sizeof(temp)-1, mounter);
- temp[len] = 0;
- mountOutput.append(temp);
- if(len < sizeof(temp)-1)
- {
- // End of file or error.
- int result = pclose(mounter);
- if(result != 0)
- {
- // NOTE: We used to abort here, but pclose() started returning
- // -1, possibly when the size of the DMG passed a certain point
- llinfos << "Unexpected result closing pipe: " << result << llendl;
- }
- mounter = NULL;
- }
- }
-
- if(!mountOutput.empty())
- {
- const char *s = mountOutput.c_str();
- const char *prefix = "/dev/";
- char *sub = strstr(s, prefix);
-
- if(sub != NULL)
- {
- sub += strlen(prefix); /* Flawfinder: ignore */
- sscanf(sub, "%1023s", deviceNode); /* Flawfinder: ignore */
- }
- }
-
- if(deviceNode[0] != 0)
- {
- llinfos << "Disk image attached on /dev/" << deviceNode << llendl;
- }
- else
- {
- llinfos << "Disk image device node not found!" << llendl;
- throw 0;
- }
-
- // Get an FSRef to the new application on the disk image
- FSRef sourceRef;
- FSRef mountRef;
- snprintf(temp, sizeof(temp), "%s/mnt", tempDir);
-
- llinfos << "Disk image mount point is: " << temp << llendl;
-
- err = FSPathMakeRef((UInt8 *)temp, &mountRef, NULL);
- if(err != noErr)
- {
- llinfos << "Couldn't make FSRef to disk image mount point." << llendl;
- throw 0;
- }
-
- sendProgress(0, 0, CFSTR("Searching for the app bundle..."));
- err = findAppBundleOnDiskImage(&mountRef, &sourceRef);
- if(err != noErr)
- {
- llinfos << "Couldn't find application bundle on mounted disk image." << llendl;
- throw 0;
- }
- else
- {
- llinfos << "found the bundle." << llendl;
- }
-
- sendProgress(0, 0, CFSTR("Preparing to copy files..."));
-
- FSRef asideRef;
- char aside[MAX_PATH]; /* Flawfinder: ignore */
-
- // this will hold the name of the destination target
- CFStringRef appNameRef;
-
- if(replacingTarget)
- {
- // Get the name of the target we're replacing
- HFSUniStr255 appNameUniStr;
- err = FSGetCatalogInfo(&targetRef, 0, NULL, &appNameUniStr, NULL, NULL);
- if(err != noErr)
- throw 0;
- appNameRef = FSCreateStringFromHFSUniStr(NULL, &appNameUniStr);
-
- // Move aside old version (into work directory)
- err = FSMoveObject(&targetRef, &tempDirRef, &asideRef);
- if(err != noErr)
- {
- llwarns << "failed to move aside old version (error code " <<
- err << ")" << llendl;
- throw 0;
- }
-
- // Grab the path for later use.
- err = FSRefMakePath(&asideRef, (UInt8*)aside, sizeof(aside));
- }
- else
- {
- // Construct the name of the target based on the product name
- char appName[MAX_PATH]; /* Flawfinder: ignore */
- snprintf(appName, sizeof(appName), "%s.app", gProductName);
- appNameRef = CFStringCreateWithCString(NULL, appName, kCFStringEncodingUTF8);
- }
-
- sendProgress(0, 0, CFSTR("Copying files..."));
-
- llinfos << "Starting copy..." << llendl;
-
- // Copy the new version from the disk image to the target location.
- err = FSCopyObjectSync(
- &sourceRef,
- &targetParentRef,
- appNameRef,
- &targetRef,
- kFSFileOperationDefaultOptions);
-
- // Grab the path for later use.
- err = FSRefMakePath(&targetRef, (UInt8*)target, sizeof(target));
- if(err != noErr)
- throw 0;
-
- llinfos << "Copy complete. Target = " << target << llendl;
-
- if(err != noErr)
- {
- // Something went wrong during the copy. Attempt to put the old version back and bail.
- (void)FSDeleteObject(&targetRef);
- if(replacingTarget)
- {
- (void)FSMoveObject(&asideRef, &targetParentRef, NULL);
- }
- throw 0;
- }
- else
- {
- // The update has succeeded. Clear the cache directory.
-
- sendProgress(0, 0, CFSTR("Clearing cache..."));
-
- llinfos << "Clearing cache..." << llendl;
-
- gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""), "*.*");
-
- llinfos << "Clear complete." << llendl;
-
- }
- }
- catch(...)
- {
- if(!gCancelled)
- if(gFailure == noErr)
- gFailure = -1;
- }
-
- // Failures from here on out are all non-fatal and not reported.
- sendProgress(0, 3, CFSTR("Cleaning up..."));
-
- // Close disk image file if necessary
- if(downloadFile != NULL)
- {
- llinfos << "Closing download file." << llendl;
-
- fclose(downloadFile);
- downloadFile = NULL;
- }
-
- sendProgress(1, 3);
- // Unmount image
- if(deviceNode[0] != 0)
- {
- llinfos << "Detaching disk image." << llendl;
-
- snprintf(temp, sizeof(temp), "hdiutil detach '%s'", deviceNode);
- system(temp); /* Flawfinder: ignore */
- }
-
- sendProgress(2, 3);
-
- // Move work directory to the trash
- if(tempDir[0] != 0)
- {
- llinfos << "Moving work directory to the trash." << llendl;
-
- FSRef trashRef;
- OSStatus err = FSMoveObjectToTrashSync(&tempDirRef, &trashRef, 0);
- if(err != noErr) {
- llwarns << "failed to move files to trash, (error code " <<
- err << ")" << llendl;
- }
- }
-
- if(!gCancelled && !gFailure && (target[0] != 0))
- {
- llinfos << "Touching application bundle." << llendl;
-
- snprintf(temp, sizeof(temp), "touch '%s'", target);
- system(temp); /* Flawfinder: ignore */
-
- llinfos << "Launching updated application." << llendl;
-
- snprintf(temp, sizeof(temp), "open '%s'", target);
- system(temp); /* Flawfinder: ignore */
- }
-
- sendDone();
-
- return(NULL);
-}
-
-#if LL_DARWIN
-#pragma GCC diagnostic warning "-Wdeprecated-declarations"
-#endif
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index b81b2aa9cf..279d98e5c0 100755
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -1767,7 +1767,6 @@ if (WINDOWS)
media_plugin_webkit
winmm_shim
windows-crash-logger
- windows-updater
)
if (FMODEX)
@@ -1813,7 +1812,6 @@ if (WINDOWS)
add_dependencies(${VIEWER_BINARY_NAME}
SLPlugin
- windows-updater
windows-crash-logger
)
diff --git a/indra/win_updater/CMakeLists.txt b/indra/win_updater/CMakeLists.txt
deleted file mode 100755
index 210486c668..0000000000
--- a/indra/win_updater/CMakeLists.txt
+++ /dev/null
@@ -1,45 +0,0 @@
-# -*- cmake -*-
-
-project(win_updater)
-
-include(00-Common)
-include(LLCommon)
-include(Linking)
-
-# *HACK - override msvcrt implementation (intialized on 00-Common) to be
-# statically linked for the installer this relies on vc taking the last flag on
-# the command line
-set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
-set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /MT")
-set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
-
-include_directories(
- ${LLCOMMON_INCLUDE_DIRS}
- )
-
-set(win_updater_SOURCE_FILES updater.cpp)
-
-set(win_updater_HEADER_FILES CMakeLists.txt)
-
-set_source_files_properties(${win_updater_HEADER_FILES}
- PROPERTIES HEADER_FILE_ONLY TRUE)
-
-list(APPEND win_updater_SOURCE_FILES ${win_updater_HEADER_FILES})
-
-add_executable(windows-updater WIN32 ${win_updater_SOURCE_FILES})
-
-target_link_libraries(windows-updater
- wininet
- user32
- gdi32
- shell32
- )
-
-set_target_properties(windows-updater
- PROPERTIES
- LINK_FLAGS "/NODEFAULTLIB:MSVCRT"
- LINK_FLAGS_DEBUG "/NODEFAULTLIB:\"LIBCMT;MSVCRT\""
- )
-
-# The windows-updater doesn't link against anything non-system, apparently
-#ll_deploy_sharedlibs_command(windows-updater)
diff --git a/indra/win_updater/updater.cpp b/indra/win_updater/updater.cpp
deleted file mode 100755
index aeab5a3b13..0000000000
--- a/indra/win_updater/updater.cpp
+++ /dev/null
@@ -1,516 +0,0 @@
-/**
- * @file updater.cpp
- * @brief Windows auto-updater
- *
- * $LicenseInfo:firstyear=2002&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-//
-// Usage: updater -url <url>
-//
-
-// We use dangerous fopen, strtok, mbstowcs, sprintf
-// which generates warnings on VC2005.
-// *TODO: Switch to fopen_s, strtok_s, etc.
-#define _CRT_SECURE_NO_DEPRECATE
-
-#include <windows.h>
-#include <wininet.h>
-#include <stdio.h>
-#include <string>
-#include <iostream>
-#include <stdexcept>
-#include <sstream>
-#include <fstream>
-
-#define BUFSIZE 8192
-
-int gTotalBytesRead = 0;
-DWORD gTotalBytes = -1;
-HWND gWindow = NULL;
-WCHAR gProgress[256];
-char* gUpdateURL = NULL;
-
-#if _DEBUG
-std::ofstream logfile;
-#define DEBUG(expr) logfile << expr << std::endl
-#else
-#define DEBUG(expr) /**/
-#endif
-
-char* wchars_to_utf8chars(const WCHAR* in_chars)
-{
- int tlen = 0;
- const WCHAR* twc = in_chars;
- while (*twc++ != 0)
- {
- tlen++;
- }
- char* outchars = new char[tlen];
- char* res = outchars;
- for (int i=0; i<tlen; i++)
- {
- int cur_char = (int)(*in_chars++);
- if (cur_char < 0x80)
- {
- *outchars++ = (char)cur_char;
- }
- else
- {
- *outchars++ = '?';
- }
- }
- *outchars = 0;
- return res;
-}
-
-class Fetcher
-{
-public:
- Fetcher(const std::wstring& uri)
- {
- // These actions are broken out as separate methods not because it
- // makes the code clearer, but to avoid triggering AntiVir and
- // McAfee-GW-Edition virus scanners (DEV-31680).
- mInet = openInet();
- mDownload = openUrl(uri);
- }
-
- ~Fetcher()
- {
- DEBUG("Calling InternetCloseHandle");
- InternetCloseHandle(mDownload);
- InternetCloseHandle(mInet);
- }
-
- unsigned long read(char* buffer, size_t bufflen) const;
-
- DWORD getTotalBytes() const
- {
- DWORD totalBytes;
- DWORD sizeof_total_bytes = sizeof(totalBytes);
- HttpQueryInfo(mDownload, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER,
- &totalBytes, &sizeof_total_bytes, NULL);
- return totalBytes;
- }
-
- struct InetError: public std::runtime_error
- {
- InetError(const std::string& what): std::runtime_error(what) {}
- };
-
-private:
- // We test results from a number of different MS functions with different
- // return types -- but the common characteristic is that 0 (i.e. (! result))
- // means an error of some kind.
- template <typename RESULT>
- static RESULT check(const std::string& desc, RESULT result)
- {
- if (result)
- {
- // success, show caller
- return result;
- }
- DWORD err = GetLastError();
- std::ostringstream out;
- out << desc << " Failed: " << err;
- DEBUG(out.str());
- throw InetError(out.str());
- }
-
- HINTERNET openUrl(const std::wstring& uri) const;
- HINTERNET openInet() const;
-
- HINTERNET mInet, mDownload;
-};
-
-HINTERNET Fetcher::openInet() const
-{
- DEBUG("Calling InternetOpen");
- // Init wininet subsystem
- return check("InternetOpen",
- InternetOpen(L"LindenUpdater", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0));
-}
-
-HINTERNET Fetcher::openUrl(const std::wstring& uri) const
-{
- DEBUG("Calling InternetOpenUrl: " << wchars_to_utf8chars(uri.c_str()));
- return check("InternetOpenUrl",
- InternetOpenUrl(mInet, uri.c_str(), NULL, 0, INTERNET_FLAG_NEED_FILE, NULL));
-}
-
-unsigned long Fetcher::read(char* buffer, size_t bufflen) const
-{
- unsigned long bytes_read = 0;
- DEBUG("Calling InternetReadFile");
- check("InternetReadFile",
- InternetReadFile(mDownload, buffer, bufflen, &bytes_read));
- return bytes_read;
-}
-
-int WINAPI get_url_into_file(const std::wstring& uri, const std::string& path, int *cancelled)
-{
- int success = FALSE;
- *cancelled = FALSE;
-
- DEBUG("Opening '" << path << "'");
-
- FILE* fp = fopen(path.c_str(), "wb"); /* Flawfinder: ignore */
-
- if (!fp)
- {
- DEBUG("Failed to open '" << path << "'");
- return success;
- }
-
- // Note, ctor can throw, since it uses check() function.
- Fetcher fetcher(uri);
- gTotalBytes = fetcher.getTotalBytes();
-
-/*==========================================================================*|
- // nobody uses total_bytes?!? What's this doing here?
- DWORD total_bytes = 0;
- success = check("InternetQueryDataAvailable",
- InternetQueryDataAvailable(hdownload, &total_bytes, 0, 0));
-|*==========================================================================*/
-
- success = FALSE;
- while(!success && !(*cancelled))
- {
- char data[BUFSIZE]; /* Flawfinder: ignore */
- unsigned long bytes_read = fetcher.read(data, sizeof(data));
-
- if (!bytes_read)
- {
- DEBUG("InternetReadFile Read " << bytes_read << " bytes.");
- }
-
- DEBUG("Reading Data, bytes_read = " << bytes_read);
-
- if (bytes_read == 0)
- {
- // If InternetFileRead returns TRUE AND bytes_read == 0
- // we've successfully downloaded the entire file
- wsprintf(gProgress, L"Download complete.");
- success = TRUE;
- }
- else
- {
- // write what we've got, then continue
- fwrite(data, sizeof(char), bytes_read, fp);
-
- gTotalBytesRead += int(bytes_read);
-
- if (gTotalBytes != -1)
- wsprintf(gProgress, L"Downloaded: %d%%", 100 * gTotalBytesRead / gTotalBytes);
- else
- wsprintf(gProgress, L"Downloaded: %dK", gTotalBytesRead / 1024);
-
- }
-
- DEBUG("Calling InvalidateRect");
-
- // Mark the window as needing redraw (of the whole thing)
- InvalidateRect(gWindow, NULL, TRUE);
-
- // Do the redraw
- DEBUG("Calling UpdateWindow");
- UpdateWindow(gWindow);
-
- DEBUG("Calling PeekMessage");
- MSG msg;
- while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
- {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
-
- if (msg.message == WM_QUIT)
- {
- // bail out, user cancelled
- *cancelled = TRUE;
- }
- }
- }
-
- fclose(fp);
- return success;
-}
-
-LRESULT CALLBACK WinProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
-{
- HDC hdc; // Drawing context
- PAINTSTRUCT ps;
-
- switch(message)
- {
- case WM_PAINT:
- {
- hdc = BeginPaint(hwnd, &ps);
-
- RECT rect;
- GetClientRect(hwnd, &rect);
- DrawText(hdc, gProgress, -1, &rect,
- DT_SINGLELINE | DT_CENTER | DT_VCENTER);
-
- EndPaint(hwnd, &ps);
- return 0;
- }
- case WM_CLOSE:
- case WM_DESTROY:
- // Get out of full screen
- // full_screen_mode(false);
- PostQuitMessage(0);
- return 0;
- }
- return DefWindowProc(hwnd, message, wparam, lparam);
-}
-
-#define win_class_name L"FullScreen"
-
-int parse_args(int argc, char **argv)
-{
- int j;
-
- for (j = 1; j < argc; j++)
- {
- if ((!strcmp(argv[j], "-url")) && (++j < argc))
- {
- gUpdateURL = argv[j];
- }
- }
-
- // If nothing was set, let the caller know.
- if (!gUpdateURL)
- {
- return 1;
- }
- return 0;
-}
-
-int WINAPI
-WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
-{
- // Parse the command line.
- LPSTR cmd_line_including_exe_name = GetCommandLineA();
-
- const int MAX_ARGS = 100;
- int argc = 0;
- char* argv[MAX_ARGS]; /* Flawfinder: ignore */
-
-#if _DEBUG
- logfile.open("updater.log", std::ios_base::out);
- DEBUG("Parsing command arguments");
-#endif
-
- char *token = NULL;
- if( cmd_line_including_exe_name[0] == '\"' )
- {
- // Exe name is enclosed in quotes
- token = strtok( cmd_line_including_exe_name, "\"" );
- argv[argc++] = token;
- token = strtok( NULL, " \t," );
- }
- else
- {
- // Exe name is not enclosed in quotes
- token = strtok( cmd_line_including_exe_name, " \t," );
- }
-
- while( (token != NULL) && (argc < MAX_ARGS) )
- {
- argv[argc++] = token;
- /* Get next token: */
- if (*(token + strlen(token) + 1) == '\"') /* Flawfinder: ignore */
- {
- token = strtok( NULL, "\"");
- }
- else
- {
- token = strtok( NULL, " \t," );
- }
- }
-
- gUpdateURL = NULL;
-
- /////////////////////////////////////////
- //
- // Process command line arguments
- //
-
- DEBUG("Processing command arguments");
-
- //
- // Parse the command line arguments
- //
- int parse_args_result = parse_args(argc, argv);
-
- WNDCLASSEX wndclassex = { 0 };
- //DEVMODE dev_mode = { 0 };
-
- const int WINDOW_WIDTH = 250;
- const int WINDOW_HEIGHT = 100;
-
- wsprintf(gProgress, L"Connecting...");
-
- /* Init the WNDCLASSEX */
- wndclassex.cbSize = sizeof(WNDCLASSEX);
- wndclassex.style = CS_HREDRAW | CS_VREDRAW;
- wndclassex.hInstance = hInstance;
- wndclassex.lpfnWndProc = WinProc;
- wndclassex.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
- wndclassex.lpszClassName = win_class_name;
-
- RegisterClassEx(&wndclassex);
-
- // Get the size of the screen
- //EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode);
-
- gWindow = CreateWindowEx(NULL, win_class_name,
- L"Second Life Updater",
- WS_OVERLAPPEDWINDOW,
- CW_USEDEFAULT,
- CW_USEDEFAULT,
- WINDOW_WIDTH,
- WINDOW_HEIGHT,
- NULL, NULL, hInstance, NULL);
-
- ShowWindow(gWindow, nShowCmd);
- UpdateWindow(gWindow);
-
- if (parse_args_result)
- {
- MessageBox(gWindow,
- L"Usage: updater -url <url> [-name <window_title>] [-program <program_name>] [-silent]",
- L"Usage", MB_OK);
- return parse_args_result;
- }
-
- // Did we get a userserver to work with?
- if (!gUpdateURL)
- {
- MessageBox(gWindow, L"Please specify the download url from the command line",
- L"Error", MB_OK);
- return 1;
- }
-
- // Can't feed GetTempPath into GetTempFile directly
- char temp_path[MAX_PATH]; /* Flawfinder: ignore */
- if (0 == GetTempPathA(sizeof(temp_path), temp_path))
- {
- MessageBox(gWindow, L"Problem with GetTempPath()",
- L"Error", MB_OK);
- return 1;
- }
- std::string update_exec_path(temp_path);
- update_exec_path.append("Second_Life_Updater.exe");
-
- WCHAR update_uri[4096];
- mbstowcs(update_uri, gUpdateURL, sizeof(update_uri));
-
- int success = 0;
- int cancelled = 0;
-
- // Actually do the download
- try
- {
- DEBUG("Calling get_url_into_file");
- success = get_url_into_file(update_uri, update_exec_path, &cancelled);
- }
- catch (const Fetcher::InetError& e)
- {
- (void)e;
- success = FALSE;
- DEBUG("Caught: " << e.what());
- }
-
- // WinInet can't tell us if we got a 404 or not. Therefor, we check
- // for the size of the downloaded file, and assume that our installer
- // will always be greater than 1MB.
- if (gTotalBytesRead < (1024 * 1024) && ! cancelled)
- {
- MessageBox(gWindow,
- L"The Second Life auto-update has failed.\n"
- L"The problem may be caused by other software installed \n"
- L"on your computer, such as a firewall.\n"
- L"Please visit http://secondlife.com/download/ \n"
- L"to download the latest version of Second Life.\n",
- NULL, MB_OK);
- return 1;
- }
-
- if (cancelled)
- {
- // silently exit
- return 0;
- }
-
- if (!success)
- {
- MessageBox(gWindow,
- L"Second Life download failed.\n"
- L"Please try again later.",
- NULL, MB_OK);
- return 1;
- }
-
- // TODO: Make updates silent (with /S to NSIS)
- //char params[256]; /* Flawfinder: ignore */
- //sprintf(params, "/S"); /* Flawfinder: ignore */
- //MessageBox(gWindow,
- // L"Updating Second Life.\n\nSecond Life will automatically start once the update is complete. This may take a minute...",
- // L"Download Complete",
- // MB_OK);
-
-/*==========================================================================*|
- // DEV-31680: ShellExecuteA() causes McAfee-GW-Edition and AntiVir
- // scanners to flag this executable as a probable virus vector.
- // Less than or equal to 32 means failure
- if (32 >= (int) ShellExecuteA(gWindow, "open", update_exec_path.c_str(), NULL,
- "C:\\", SW_SHOWDEFAULT))
-|*==========================================================================*/
- // from http://msdn.microsoft.com/en-us/library/ms682512(VS.85).aspx
- STARTUPINFOA si;
- PROCESS_INFORMATION pi;
- ZeroMemory(&si, sizeof(si));
- si.cb = sizeof(si);
- ZeroMemory(&pi, sizeof(pi));
-
- if (! CreateProcessA(update_exec_path.c_str(), // executable file
- NULL, // command line
- NULL, // process cannot be inherited
- NULL, // thread cannot be inherited
- FALSE, // do not inherit existing handles
- 0, // process creation flags
- NULL, // inherit parent's environment
- NULL, // inherit parent's current dir
- &si, // STARTUPINFO
- &pi)) // PROCESS_INFORMATION
- {
- MessageBox(gWindow, L"Update failed. Please try again later.", NULL, MB_OK);
- return 1;
- }
-
- // Give installer some time to open a window
- Sleep(1000);
-
- return 0;
-}