Vidalia 0.3.1
vidalia/main.cpp
Go to the documentation of this file.
1/*
2** This file is part of Vidalia, and is subject to the license terms in the
3** LICENSE file, found in the top level directory of this distribution. If you
4** did not receive the LICENSE file with this file, you may obtain it from the
5** Vidalia source package distributed by the Vidalia Project at
6** http://www.torproject.org/projects/vidalia.html. No part of Vidalia,
7** including this file, may be copied, modified, propagated, or distributed
8** except according to the terms described in the LICENSE file.
9*/
10
11/*
12** \file main.cpp
13** \brief Main Vidalia entry point
14*/
15
16#include "config.h"
17#include "Vidalia.h"
18#include "MainWindow.h"
19#include "VMessageBox.h"
20#if defined(USE_BREAKPAD)
21#include "CrashReporter.h"
22#endif
23
24#include "procutil.h"
25#include "stringutil.h"
26
27#include <QObject>
28#if defined(Q_OS_WIN32)
29#include <QSysInfo>
30#endif
31#if defined(HAVE_SIGNAL_H)
32#include <signal.h>
33#endif
34
35#if defined(USE_BREAKPAD)
36void
37setup_crash_reporter()
38{
39 /* Set the crash reporting application used to submit minidumps. On Windows,
40 * crashreporter.exe is assumed to live in the same directory as vidalia.exe.
41 */
42#if defined(Q_OS_WIN32)
43 QString crashReporter = Vidalia::applicationDirPath() + "\\crashreporter.exe";
44#elif defined(Q_OS_MAC)
45 QString crashReporter = Vidalia::applicationDirPath() + "/CrashReporter.app";
46#else
47 QString crashReporter = Vidalia::applicationDirPath() + "/crashreporter";
48#endif
49 if (! QFileInfo(crashReporter).isExecutable()) {
50 vWarn("Unable to find crash reporting application. Crash reporting will "
51 "be unavailable.");
52 return;
53 }
54 if (! CrashReporter::set_crash_reporter(crashReporter)) {
55 vWarn("Vidalia found the crash reporting application, but the path is "
56 "longer than your platform supports. Skipping crash reporting.");
57 return;
58 }
59
60 /* Set the Vidalia executable and options used to restart Vidalia after a
61 * crash. We strip off the first argument in Vidalia::arguments(), since
62 * it's the application name again anyway. */
63 CrashReporter::set_restart_options(Vidalia::applicationFilePath(),
64 Vidalia::arguments().mid(1));
65
66 /* Set the build version that gets saved with a minidump. */
68
69 /* Install the exception handler and give it the location to which Breakpad
70 * should write its minidumps. */
71 QString dumpPath = Vidalia::dataDirectory() + "/crashreports";
73 vWarn("Unable to setup Breakpad exception handler. Crash reporting "
74 "will be unavailable.");
75 } else {
76 vInfo("Installed Breakpad exception handler.");
77 }
78}
79#endif
80
81extern "C" void
83{
84#ifdef HAVE_SIGNAL_H
85 if (signal == SIGINT || signal == SIGTERM)
86 vApp->quit();
87#endif
88}
89
90void
92{
93#if defined(HAVE_SIGACTION)
94 struct sigaction action;
95
96 sigemptyset(&action.sa_mask);
97 action.sa_handler = signal_handler;
98 action.sa_flags = 0;
99
100 if (sigaction(SIGINT, &action, NULL) < 0)
101 vWarn("Failed to install SIGINT handler.");
102 if (sigaction(SIGTERM, &action, NULL) < 0)
103 vWarn("Failed to install SIGTERM handler.");
104#elif defined(HAVE_SIGNAL)
105 if (signal(SIGINT, signal_handler) == SIG_ERR)
106 vWarn("Failed to install SIGINT handler.");
107 if (signal(SIGTERM, signal_handler) == SIG_ERR)
108 vWarn("Failed to install SIGTERM handler.");
109#endif
110}
111
112/** Returns true if there is already another Vidalia process running. */
113bool
114is_vidalia_running(const QString &pidfile)
115{
116 /* Read the pidfile and find out if that process still exists */
117 qint64 pid = read_pidfile(pidfile);
118 if (pid > 0) {
119#if defined(Q_OS_WIN32)
120 if (QSysInfo::WindowsVersion == QSysInfo::WV_NT) {
121 /* We currently can't get a list of running processes on Windows NT, so
122 * be pessimistic and assume the existence of a nonzero pidfile means
123 * Vidalia is running. */
124 return true;
125 } else
126 return (is_process_running(pid));
127#else
128 return (is_process_running(pid));
129#endif
130 }
131 return false;
132}
133
134/** Main application entry point. */
135int
136main(int argc, char *argv[])
137{
138 Q_INIT_RESOURCE(vidalia);
139 QStringList args = char_array_to_stringlist(argv+1, argc-1);
140
141 /* Construct the application object. Qt strips any command-line arguments
142 * that it recognizes in argv, so we'll pass a stringlist of the original
143 * list of command-line arguments too. */
144 Vidalia vidalia(args, argc, argv);
145 vNotice("Vidalia %1 using Qt %2").arg(Vidalia::version())
146 .arg(QT_VERSION_STR);
147
148#if defined(USE_BREAKPAD)
149 /* Set up the crash reporting application and exception handlers. */
150 setup_crash_reporter();
151#endif
152#if defined(USE_MARBLE) && defined(Q_OS_WIN32)
153 vApp->addLibraryPath(vApp->applicationDirPath() + "/plugins/qt");
154#endif
155
156 /* Install a signal handler to clean up properly after a catching a
157 * SIGINT or SIGTERM. */
159
160 /* Validate any command-line arguments, or show usage message box, if
161 * necessary. */
162 QString errmsg;
163 if (vidalia.showUsage()) {
165 return 0;
166 } else if (!vidalia.validateArguments(errmsg)) {
167 vError("Unable to apply command-line arguments: %1").arg(errmsg);
169 vApp->translate("Vidalia",
170 QT_TRANSLATE_NOOP("Vidalia", "Invalid Argument")), errmsg,
172 return 1;
173 }
174
175 /* Check if Vidalia is already running. */
176 QString pidfile = vidalia.pidFile();
177 if (is_vidalia_running(pidfile)) {
178 vWarn("Detected another process with pid %1. Is Vidalia already running?")
179 .arg(get_pid());
180 /* Let the user know another Vidalia is running and we are going to exit
181 * now. */
182 int ret = VMessageBox::critical(0,
183 vApp->translate("Vidalia",
184 QT_TRANSLATE_NOOP("Vidalia", "Vidalia is already running")),
185 vApp->translate("Vidalia",
186 QT_TRANSLATE_NOOP("Vidalia",
187 "Another Vidalia process is possibly already running. "
188 "If there really is not another Vidalia process running, "
189 "you can choose to continue anyway.\n\n"
190 "Would you like to continue starting Vidalia?")),
191 VMessageBox::Continue, VMessageBox::Quit|VMessageBox::Default);
192 if (ret != VMessageBox::Continue) {
193 /* Don't start a second instance of Vidalia */
194 vError("Exiting duplicate Vidalia process.");
195 return 1;
196 }
197 }
198 write_pidfile(pidfile);
199
200 /* Since we don't have a visible main window, if we were to display a
201 * QMessageBox (for example, to display an error when starting or stopping
202 * Tor) then the application would exit when that message box was closed.
203 * Setting quitOnLastWindowClosed to false fixes this behavior. */
204 Vidalia::setQuitOnLastWindowClosed(false);
205
206 /* Create an instance of the main window */
207 MainWindow *mainWin = new MainWindow();
208
209 /* Run Vidalia */
210 int ret = vidalia.run();
211
212 delete mainWin;;
213
214 /* Vidalia exited, so cleanup our pidfile and return */
215 QFile::remove(pidfile);
216 vNotice("Vidalia is exiting cleanly (return code %1).").arg(ret);
217
218#if defined(USE_BREAKPAD)
219 vInfo("Removing Breakpad exception handler.");
221#endif
222
223 return ret;
224}
225
stop errmsg signal(TorSignal::Signal sig)
#define vNotice(fmt)
Definition: Vidalia.h:41
#define vError(fmt)
Definition: Vidalia.h:43
#define vWarn(fmt)
Definition: Vidalia.h:42
#define vInfo(fmt)
Definition: Vidalia.h:40
#define vApp
Definition: Vidalia.h:37
static int critical(QWidget *parent, QString caption, QString text, int button0, int button1=NoButton, int button2=NoButton)
static int run()
Definition: Vidalia.cpp:157
static QString dataDirectory()
Definition: Vidalia.cpp:355
static QString pidFile()
Definition: Vidalia.cpp:378
static void showUsageMessageBox()
Definition: Vidalia.cpp:194
static bool showUsage()
Definition: Vidalia.cpp:187
static QString version()
Definition: Vidalia.h:73
bool validateArguments(QString &errmsg)
Definition: Vidalia.cpp:272
#define VIDALIA_VERSION
Definition: config.h:17
bool set_build_version(const QString &version)
bool set_crash_reporter(const QString &crashReporter)
bool install_exception_handler(const QString &dumpPath)
void remove_exception_handler(void)
bool set_restart_options(const QString &executable, const QStringList &arguments)
qint64 read_pidfile(const QString &pidFileName, QString *errmsg)
Definition: procutil.cpp:89
bool write_pidfile(const QString &pidFileName, QString *errmsg)
Definition: procutil.cpp:66
qint64 get_pid()
Definition: procutil.cpp:33
bool is_process_running(qint64 pid)
Definition: procutil.cpp:44
QStringList char_array_to_stringlist(char **arr, int len)
Definition: stringutil.cpp:24
int main(int argc, char *argv[])
void signal_handler(int signal)
void install_signal_handler()
bool is_vidalia_running(const QString &pidfile)