vidalia/main.cpp

Go to the documentation of this file.
00001 /*
00002 **  This file is part of Vidalia, and is subject to the license terms in the
00003 **  LICENSE file, found in the top level directory of this distribution. If you
00004 **  did not receive the LICENSE file with this file, you may obtain it from the
00005 **  Vidalia source package distributed by the Vidalia Project at
00006 **  http://www.vidalia-project.net/. No part of Vidalia, including this file,
00007 **  may be copied, modified, propagated, or distributed except according to the
00008 **  terms described in the LICENSE file.
00009 */
00010 
00011 /*
00012 ** \file main.cpp
00013 ** \version $Id: main.cpp 4062 2009-08-21 03:42:25Z edmanm $
00014 ** \brief Main Vidalia entry point
00015 */
00016 
00017 #include "config.h"
00018 #include "Vidalia.h"
00019 #include "MainWindow.h"
00020 #include "VMessageBox.h"
00021 #if defined(USE_BREAKPAD)
00022 #include "CrashReporter.h"
00023 #endif
00024 
00025 #include "procutil.h"
00026 #include "stringutil.h"
00027 
00028 #include <QObject>
00029 #if defined(Q_OS_WIN32)
00030 #include <QSysInfo>
00031 #endif
00032 #if defined(HAVE_SIGNAL_H)
00033 #include <signal.h>
00034 #endif
00035 
00036 #if defined(USE_BREAKPAD)
00037 void
00038 setup_crash_reporter()
00039 {
00040   /* Set the crash reporting application used to submit minidumps. On Windows,
00041    * crashreporter.exe is assumed to live in the same directory as vidalia.exe.
00042    */
00043 #if defined(Q_OS_WIN32)
00044   QString crashReporter = Vidalia::applicationDirPath() + "\\crashreporter.exe";
00045 #elif defined(Q_OS_MAC)
00046   QString crashReporter = Vidalia::applicationDirPath() + "/CrashReporter.app";
00047 #endif
00048   if (! QFileInfo(crashReporter).isExecutable()) {
00049     vWarn("Unable to find crash reporting application. Crash reporting will "
00050           "be unavailable.");
00051     return;
00052   }
00053   if (! CrashReporter::set_crash_reporter(crashReporter)) {
00054     vWarn("Vidalia found the crash reporting application, but the path is "
00055           "longer than your platform supports. Skipping crash reporting.");
00056     return;
00057   }
00058 
00059   /* Set the Vidalia executable and options used to restart Vidalia after a 
00060    * crash. We strip off the first argument in Vidalia::arguments(), since
00061    * it's the application name again anyway. */
00062   CrashReporter::set_restart_options(Vidalia::applicationFilePath(),
00063                                      Vidalia::arguments().mid(1));
00064 
00065   /* Set the build version that gets saved with a minidump. */
00066   CrashReporter::set_build_version(VIDALIA_VERSION);
00067 
00068   /* Install the exception handler and give it the location to which Breakpad
00069    * should write its minidumps. */
00070   QString dumpPath = Vidalia::dataDirectory() + "/crashreports";
00071   if (! CrashReporter::install_exception_handler(dumpPath)) {
00072     vWarn("Unable to setup Breakpad exception handler. Crash reporting "
00073           "will be unavailable.");
00074   } else {
00075     vInfo("Installed Breakpad exception handler.");
00076   }
00077 }
00078 #endif
00079 
00080 extern "C" void
00081 signal_handler(int signal)
00082 {
00083 #ifdef HAVE_SIGNAL_H
00084   if (signal == SIGINT || signal == SIGTERM)
00085     vApp->quit();
00086 #endif
00087 }
00088 
00089 void
00090 install_signal_handler()
00091 {
00092 #if defined(HAVE_SIGACTION)
00093   struct sigaction action;
00094 
00095   sigemptyset(&action.sa_mask);
00096   action.sa_handler = signal_handler;
00097   action.sa_flags   = 0;
00098 
00099   if (sigaction(SIGINT,  &action, NULL) < 0)
00100     vWarn("Failed to install SIGINT handler.");
00101   if (sigaction(SIGTERM, &action, NULL) < 0)
00102     vWarn("Failed to install SIGTERM handler.");
00103 #elif defined(HAVE_SIGNAL)
00104   if (signal(SIGINT, signal_handler) == SIG_ERR)
00105     vWarn("Failed to install SIGINT handler.");
00106   if (signal(SIGTERM, signal_handler) == SIG_ERR)
00107     vWarn("Failed to install SIGTERM handler.");
00108 #endif
00109 }
00110 
00111 /** Returns true if there is already another Vidalia process running. */
00112 bool
00113 is_vidalia_running(const QString &pidfile)
00114 {
00115   /* Read the pidfile and find out if that process still exists */
00116   qint64 pid = read_pidfile(pidfile);
00117   if (pid > 0) {
00118 #if defined(Q_OS_WIN32)
00119     if (QSysInfo::WindowsVersion == QSysInfo::WV_NT) {
00120       /* We currently can't get a list of running processes on Windows NT, so
00121        * be pessimistic and assume the existence of a nonzero pidfile means
00122        * Vidalia is running. */
00123       return true;
00124     } else
00125       return (is_process_running(pid));
00126 #else
00127     return (is_process_running(pid));
00128 #endif
00129   }
00130   return false;
00131 }
00132 
00133 /** Main application entry point. */
00134 int
00135 main(int argc, char *argv[])
00136 {
00137   Q_INIT_RESOURCE(vidalia);
00138   QStringList args = char_array_to_stringlist(argv+1, argc-1);
00139  
00140   /* Construct the application object. Qt strips any command-line arguments
00141    * that it recognizes in argv, so we'll pass a stringlist of the original
00142    * list of command-line arguments too. */
00143   Vidalia vidalia(args, argc, argv);
00144   vNotice("Vidalia %1 using Qt %2").arg(Vidalia::version())
00145                                    .arg(QT_VERSION_STR);
00146 
00147 #if defined(USE_BREAKPAD)
00148   /* Set up the crash reporting application and exception handlers. */
00149   setup_crash_reporter();
00150 #endif
00151 #if defined(USE_MARBLE) && defined(Q_OS_WIN32)
00152   vApp->addLibraryPath(vApp->applicationDirPath() + "/plugins/qt");
00153 #endif
00154 
00155   /* Install a signal handler to clean up properly after a catching a 
00156    * SIGINT or SIGTERM. */
00157   install_signal_handler();
00158 
00159   /* Validate any command-line arguments, or show usage message box, if
00160    * necessary. */
00161   QString errmsg;
00162   if (vidalia.showUsage()) {
00163     Vidalia::showUsageMessageBox();
00164     return 0;
00165   } else if (!vidalia.validateArguments(errmsg)) {
00166     vError("Unable to apply command-line arguments: %1").arg(errmsg);
00167     VMessageBox::critical(0,
00168       vApp->translate("Vidalia",
00169         QT_TRANSLATE_NOOP("Vidalia", "Invalid Argument")), errmsg,
00170       VMessageBox::Ok);
00171     return 1;
00172   }
00173 
00174   /* Check if Vidalia is already running. */
00175   QString pidfile = vidalia.pidFile();
00176   if (is_vidalia_running(pidfile)) {
00177     vWarn("Detected another process with pid %1. Is Vidalia already running?")
00178                                                                .arg(get_pid());
00179     /* Let the user know another Vidalia is running and we are going to exit
00180      * now. */
00181     int ret = VMessageBox::critical(0, 
00182                 vApp->translate("Vidalia",
00183                   QT_TRANSLATE_NOOP("Vidalia", "Vidalia is already running")),
00184                 vApp->translate("Vidalia",
00185                   QT_TRANSLATE_NOOP("Vidalia", 
00186                     "Another Vidalia process is possibly already running. "
00187                     "If there really is not another Vidalia process running, "
00188                     "you can choose to continue anyway.\n\n"
00189                     "Would you like to continue starting Vidalia?")),
00190                 VMessageBox::Continue, VMessageBox::Quit|VMessageBox::Default);
00191     if (ret != VMessageBox::Continue) {
00192       /* Don't start a second instance of Vidalia */
00193       vError("Exiting duplicate Vidalia process.");
00194       return 1;
00195     }
00196   }
00197   write_pidfile(pidfile);
00198 
00199   /* Since we don't have a visible main window, if we were to display a
00200    * QMessageBox (for example, to display an error when starting or stopping
00201    * Tor) then the application would exit when that message box was closed.
00202    * Setting quitOnLastWindowClosed to false fixes this behavior. */
00203   Vidalia::setQuitOnLastWindowClosed(false);
00204 
00205   /* Create an instance of the main window  */
00206   MainWindow mainWin;
00207 
00208   /* Run Vidalia */
00209   int ret = vidalia.run();
00210 
00211   /* Vidalia exited, so cleanup our pidfile and return */
00212   QFile::remove(pidfile);
00213   vNotice("Vidalia is exiting cleanly (return code %1).").arg(ret);
00214 
00215 #if defined(USE_BREAKPAD)
00216   vInfo("Removing Breakpad exception handler.");
00217   CrashReporter::remove_exception_handler();
00218 #endif
00219 
00220   return ret;
00221 }
00222 
Generated on Mon Aug 30 22:58:54 2010 for Vidalia by  doxygen 1.6.3