Improve crash reporter errors.
b=385359, r=luser
--- a/toolkit/crashreporter/client/crashreporter.cpp
+++ b/toolkit/crashreporter/client/crashreporter.cpp
@@ -63,16 +63,32 @@ string gSettingsPath;
int gArgc;
char** gArgv;
static string gDumpFile;
static string gExtraFile;
static string kExtraDataExtension = ".extra";
+void UIError(const string& message)
+{
+ string errorMessage;
+ if (!gStrings[ST_CRASHREPORTERERROR].empty()) {
+ char buf[2048];
+ UI_SNPRINTF(buf, 2048,
+ gStrings[ST_CRASHREPORTERERROR].c_str(),
+ message.c_str());
+ errorMessage = buf;
+ } else {
+ errorMessage = message;
+ }
+
+ UIError_impl(errorMessage);
+}
+
static string Unescape(const string& str)
{
string ret;
for (string::const_iterator iter = str.begin();
iter != str.end();
iter++) {
if (*iter == '\\') {
iter++;
@@ -205,24 +221,30 @@ static string Basename(const string& fil
return file;
}
static bool MoveCrashData(const string& toDir,
string& dumpfile,
string& extrafile)
{
if (!UIEnsurePathExists(toDir)) {
+ UIError(gStrings[ST_ERROR_CREATEDUMPDIR]);
return false;
}
string newDump = toDir + UI_DIR_SEPARATOR + Basename(dumpfile);
string newExtra = toDir + UI_DIR_SEPARATOR + Basename(extrafile);
- if (!UIMoveFile(dumpfile, newDump) ||
- !UIMoveFile(extrafile, newExtra)) {
+ if (!UIMoveFile(dumpfile, newDump)) {
+ UIError(gStrings[ST_ERROR_DUMPFILEMOVE]);
+ return false;
+ }
+
+ if (!UIMoveFile(extrafile, newExtra)) {
+ UIError(gStrings[ST_ERROR_EXTRAFILEMOVE]);
return false;
}
dumpfile = newDump;
extrafile = newExtra;
return true;
}
@@ -283,69 +305,121 @@ bool SendCompleted(bool success, const s
}
return true;
}
} // namespace CrashReporter
using namespace CrashReporter;
+void RewriteStrings(StringTable& queryParameters)
+{
+ // rewrite some UI strings with the values from the query parameters
+ string product = queryParameters["ProductName"];
+ string vendor = queryParameters["Vendor"];
+ if (vendor.empty()) {
+ // Assume Mozilla if no vendor is specified
+ vendor = "Mozilla";
+ }
+
+ char buf[4096];
+ UI_SNPRINTF(buf, sizeof(buf),
+ gStrings[ST_CRASHREPORTERVENDORTITLE].c_str(),
+ vendor.c_str());
+ gStrings[ST_CRASHREPORTERTITLE] = buf;
+
+ // Leave a format specifier for UIError to fill in
+ UI_SNPRINTF(buf, sizeof(buf),
+ gStrings[ST_CRASHREPORTERPRODUCTERROR].c_str(),
+ product.c_str(),
+ "%s");
+ gStrings[ST_CRASHREPORTERERROR] = buf;
+
+ UI_SNPRINTF(buf, sizeof(buf),
+ gStrings[ST_CRASHREPORTERDESCRIPTION].c_str(),
+ product.c_str());
+ gStrings[ST_CRASHREPORTERDESCRIPTION] = buf;
+
+ UI_SNPRINTF(buf, sizeof(buf),
+ gStrings[ST_CHECKSUBMIT].c_str(),
+ vendor.c_str());
+ gStrings[ST_CHECKSUBMIT] = buf;
+
+ UI_SNPRINTF(buf, sizeof(buf),
+ gStrings[ST_RESTART].c_str(),
+ product.c_str());
+ gStrings[ST_RESTART] = buf;
+}
+
int main(int argc, char** argv)
{
gArgc = argc;
gArgv = argv;
if (!ReadConfig()) {
- UIError("Couldn't read configuration");
+ UIError("Couldn't read configuration.");
return 0;
}
if (!UIInit())
return 0;
if (argc > 1) {
gDumpFile = argv[1];
}
if (gDumpFile.empty()) {
// no dump file specified, run the default UI
UIShowDefaultUI();
} else {
gExtraFile = GetExtraDataFilename(gDumpFile);
if (gExtraFile.empty()) {
- UIError("Couldn't get extra data filename");
+ UIError(gStrings[ST_ERROR_BADARGUMENTS]);
+ return 0;
+ }
+
+ if (!UIFileExists(gExtraFile)) {
+ UIError(gStrings[ST_ERROR_EXTRAFILEEXISTS]);
return 0;
}
StringTable queryParameters;
if (!ReadStringsFromFile(gExtraFile, queryParameters, true)) {
- UIError("Couldn't read extra data");
+ UIError(gStrings[ST_ERROR_EXTRAFILEREAD]);
return 0;
}
if (queryParameters.find("ProductName") == queryParameters.end()) {
- UIError("No product name specified");
+ UIError(gStrings[ST_ERROR_NOPRODUCTNAME]);
return 0;
}
+ // There is enough information in the extra file to rewrite strings
+ // to be product specific
+ RewriteStrings(queryParameters);
+
if (queryParameters.find("ServerURL") == queryParameters.end()) {
- UIError("No server URL specified");
+ UIError(gStrings[ST_ERROR_NOSERVERURL]);
return 0;
}
string product = queryParameters["ProductName"];
string vendor = queryParameters["Vendor"];
if (!UIGetSettingsPath(vendor, product, gSettingsPath)) {
- UIError("Couldn't get settings path");
+ UIError(gStrings[ST_ERROR_NOSETTINGSPATH]);
+ return 0;
+ }
+
+ if (!UIFileExists(gDumpFile)) {
+ UIError(gStrings[ST_ERROR_DUMPFILEEXISTS]);
return 0;
}
string pendingDir = gSettingsPath + UI_DIR_SEPARATOR + "pending";
if (!MoveCrashData(pendingDir, gDumpFile, gExtraFile)) {
- UIError("Couldn't move crash data");
return 0;
}
string sendURL = queryParameters["ServerURL"];
// we don't need to actually send this
queryParameters.erase("ServerURL");
vector<string> restartArgs;
@@ -365,38 +439,16 @@ int main(int argc, char** argv)
// allow override of the server url via environment variable
//XXX: remove this in the far future when our robot
// masters force everyone to use XULRunner
char* urlEnv = getenv("MOZ_CRASHREPORTER_URL");
if (urlEnv && *urlEnv) {
sendURL = urlEnv;
}
- // rewrite some UI strings with the values from the query parameters
- char buf[4096];
- UI_SNPRINTF(buf, sizeof(buf),
- gStrings[ST_RESTART].c_str(),
- product.c_str());
- gStrings[ST_RESTART] = buf;
-
- UI_SNPRINTF(buf, sizeof(buf),
- gStrings[ST_CRASHREPORTERDESCRIPTION].c_str(),
- product.c_str());
- gStrings[ST_CRASHREPORTERDESCRIPTION] = buf;
-
- UI_SNPRINTF(buf, sizeof(buf),
- gStrings[ST_CHECKSUBMIT].c_str(),
- vendor.empty() ? "Mozilla" : vendor.c_str());
- gStrings[ST_CHECKSUBMIT] = buf;
-
- UI_SNPRINTF(buf, sizeof(buf),
- gStrings[ST_CRASHREPORTERTITLE].c_str(),
- vendor.empty() ? "Mozilla" : vendor.c_str());
- gStrings[ST_CRASHREPORTERTITLE] = buf;
-
UIShowCrashUI(gDumpFile, queryParameters, sendURL, restartArgs);
}
UIShutdown();
return 0;
}
--- a/toolkit/crashreporter/client/crashreporter.h
+++ b/toolkit/crashreporter/client/crashreporter.h
@@ -24,38 +24,54 @@
#define UI_SNPRINTF snprintf
#define UI_DIR_SEPARATOR "/"
#endif
typedef std::map<std::string, std::string> StringTable;
-#define ST_CRASHREPORTERTITLE "CrashReporterTitle"
-#define ST_CRASHREPORTERHEADER "CrashReporterHeader"
-#define ST_CRASHREPORTERDESCRIPTION "CrashReporterDescription"
-#define ST_CRASHREPORTERDEFAULT "CrashReporterDefault"
-#define ST_VIEWREPORT "ViewReport"
-#define ST_EXTRAREPORTINFO "ExtraReportInfo"
-#define ST_CHECKSUBMIT "CheckSubmit"
-#define ST_CHECKEMAIL "CheckEmail"
-#define ST_CLOSE "Close"
-#define ST_RESTART "Restart"
-#define ST_SUBMITFAILED "SubmitFailed"
+#define ST_CRASHREPORTERTITLE "CrashReporterTitle"
+#define ST_CRASHREPORTERVENDORTITLE "CrashReporterVendorTitle"
+#define ST_CRASHREPORTERERROR "CrashReporterError"
+#define ST_CRASHREPORTERPRODUCTERROR "CrashReporterProductError"
+#define ST_CRASHREPORTERHEADER "CrashReporterHeader"
+#define ST_CRASHREPORTERDESCRIPTION "CrashReporterDescription"
+#define ST_CRASHREPORTERDEFAULT "CrashReporterDefault"
+#define ST_VIEWREPORT "ViewReport"
+#define ST_EXTRAREPORTINFO "ExtraReportInfo"
+#define ST_CHECKSUBMIT "CheckSubmit"
+#define ST_CHECKEMAIL "CheckEmail"
+#define ST_CLOSE "Close"
+#define ST_RESTART "Restart"
+#define ST_SUBMITFAILED "SubmitFailed"
+
+#define ST_ERROR_BADARGUMENTS "ErrorBadArguments"
+#define ST_ERROR_EXTRAFILEEXISTS "ErrorExtraFileExists"
+#define ST_ERROR_EXTRAFILEREAD "ErrorExtraFileRead"
+#define ST_ERROR_EXTRAFILEMOVE "ErrorExtraFileMove"
+#define ST_ERROR_DUMPFILEEXISTS "ErrorDumpFileExists"
+#define ST_ERROR_DUMPFILEMOVE "ErrorDumpFileMove"
+#define ST_ERROR_NOPRODUCTNAME "ErrorNoProductName"
+#define ST_ERROR_NOSERVERURL "ErrorNoServerURL"
+#define ST_ERROR_NOSETTINGSPATH "ErrorNoSettingsPath"
+#define ST_ERROR_CREATEDUMPDIR "ErrorCreateDumpDir"
//=============================================================================
// implemented in crashreporter.cpp
//=============================================================================
namespace CrashReporter {
extern StringTable gStrings;
extern std::string gSettingsPath;
extern int gArgc;
extern char** gArgv;
+ void UIError(const std::string& message);
+
// The UI finished sending the report
bool SendCompleted(bool success, const std::string& serverResponse);
bool ReadStrings(std::istream& in,
StringTable& strings,
bool unescape);
bool ReadStringsFromFile(const std::string& path,
StringTable& strings,
@@ -82,23 +98,24 @@ void UIShutdown();
void UIShowDefaultUI();
// Run the UI for when the app was launched with a dump file
void UIShowCrashUI(const std::string& dumpfile,
const StringTable& queryParameters,
const std::string& sendURL,
const std::vector<std::string>& restartArgs);
-void UIError(const std::string& message);
+void UIError_impl(const std::string& message);
bool UIGetIniPath(std::string& path);
bool UIGetSettingsPath(const std::string& vendor,
const std::string& product,
std::string& settingsPath);
bool UIEnsurePathExists(const std::string& path);
+bool UIFileExists(const std::string& path);
bool UIMoveFile(const std::string& oldfile, const std::string& newfile);
bool UIDeleteFile(const std::string& oldfile);
#ifdef _MSC_VER
# pragma warning( pop )
#endif
#endif
--- a/toolkit/crashreporter/client/crashreporter.ini
+++ b/toolkit/crashreporter/client/crashreporter.ini
@@ -1,15 +1,30 @@
; This file is in the UTF-8 encoding
[Strings]
-CrashReporterTitle=%s Crash Reporter
+CrashReporterTitle=Crash Reporter
+CrashReporterVendorTitle=%s Crash Reporter
+CrashReporterError=We're sorry, but the application hit an unexpected problem and crashed.\n\nUnfortunately the crash reporter is unable to submit a report for this crash.\n\nDetails: %s
+CrashReporterProductError=We're sorry, but %s hit an unexpected problem and crashed. We'll try to restore your tabs and windows when it restarts.\n\nUnfortunately the crash reporter is unable to submit a crash report.\n\nDetails: %s
CrashReporterHeader=Crash! Bang! Boom!
CrashReporterDescription=We're sorry, but %s hit an unexpected problem and crashed. We'll try to restore your tabs and windows when it restarts.\n\nTo help us diagnose and repair this problem, you can send us a crash report.
CrashReporterDefault=This application is run after a crash to report the problem to the application vendor. It should not be run directly.
ViewReport=View Report
ExtraReportInfo=This report also contains information about the state of the application when it crashed.
CheckSubmit=Submit crash report to %s
CheckEmail=Email me when the problem is fixed
Close=Close
Restart=Restart %s
SubmitFailed=Failed to submit crash report
CrashID=Crash ID: %s
CrashDetailsURL=You can view details of this crash at %s
+
+ErrorBadArguments=The application passed an invalid argument.
+ErrorExtraFileExists=The application didn't leave an application data file.
+ErrorExtraFileRead=Couldn't read the application data file.
+ErrorExtraFileMove=Couldn't move application data file.
+ErrorDumpFileExists=The application did not leave a crash dump file.
+ErrorDumpFileMove=Couldn't move crash dump.
+ErrorNoProductName=The application did not identify itself.
+ErrorNoServerURL=The application did not specify a crash reporting server.
+ErrorNoSettingsPath=Couldn't find the crash reporter's settings.
+ErrorCreateDumpDir=Couldn't create pending dump directory.
+
--- a/toolkit/crashreporter/client/crashreporter_linux.cpp
+++ b/toolkit/crashreporter/client/crashreporter_linux.cpp
@@ -407,17 +407,17 @@ void UIShowCrashUI(const string& dumpfil
LoadSettings();
ShowReportInfo();
gtk_widget_show_all(gWindow);
gtk_main();
}
-void UIError(const string& message)
+void UIError_impl(const string& message)
{
if (!gInitialized) {
// Didn't initialize, this is the best we can do
printf("Error: %s\n", message.c_str());
return;
}
GtkWidget* errorDialog =
@@ -472,16 +472,26 @@ bool UIEnsurePathExists(const string& pa
int ret = mkdir(path.c_str(), S_IRWXU);
int e = errno;
if (ret == -1 && e != EEXIST)
return false;
return true;
}
+bool UIFileExists(const string& path)
+{
+ struct stat sb;
+ int ret = stat(path.c_str(), &sb);
+ if (ret == -1 || !(sb.st_mode & S_IFREG))
+ return false;
+
+ return true;
+}
+
bool UIMoveFile(const string& file, const string& newfile)
{
return (rename(file.c_str(), newfile.c_str()) != -1);
}
bool UIDeleteFile(const string& file)
{
return (unlink(file.c_str()) != -1);
--- a/toolkit/crashreporter/client/crashreporter_osx.mm
+++ b/toolkit/crashreporter/client/crashreporter_osx.mm
@@ -423,33 +423,34 @@ bool UIInit()
void UIShutdown()
{
[gMainPool release];
}
void UIShowDefaultUI()
{
- UIError(gStrings[ST_CRASHREPORTERDEFAULT]);
+ [gUI showErrorUI: gStrings[ST_CRASHREPORTERDEFAULT]];
+ [NSApp run];
}
void UIShowCrashUI(const string& dumpfile,
const StringTable& queryParameters,
const string& sendURL,
const vector<string>& restartArgs)
{
gRestartArgs = restartArgs;
[gUI showCrashUI: dumpfile
queryParameters: queryParameters
sendURL: sendURL];
[NSApp run];
}
-void UIError(const string& message)
+void UIError_impl(const string& message)
{
if (!gUI) {
// UI failed to initialize, printing is the best we can do
printf("Error: %s\n", message.c_str());
return;
}
[gUI showErrorUI: message];
@@ -497,16 +498,26 @@ bool UIEnsurePathExists(const string& pa
int ret = mkdir(path.c_str(), S_IRWXU);
int e = errno;
if (ret == -1 && e != EEXIST)
return false;
return true;
}
+bool UIFileExists(const string& path)
+{
+ struct stat sb;
+ int ret = stat(path.c_str(), &sb);
+ if (ret == -1 || !(sb.st_mode & S_IFREG))
+ return false;
+
+ return true;
+}
+
bool UIMoveFile(const string& file, const string& newfile)
{
return (rename(file.c_str(), newfile.c_str()) != -1);
}
bool UIDeleteFile(const string& file)
{
return (unlink(file.c_str()) != -1);
--- a/toolkit/crashreporter/client/crashreporter_win.cpp
+++ b/toolkit/crashreporter/client/crashreporter_win.cpp
@@ -701,17 +701,17 @@ void UIShowCrashUI(const string& dumpFil
}
gRestartArgs = restartArgs;
DialogBoxParam(NULL, MAKEINTRESOURCE(IDD_SENDDIALOG), NULL,
(DLGPROC)CrashReporterDialogProc, 0);
}
-void UIError(const string& message)
+void UIError_impl(const string& message)
{
wstring title = Str(ST_CRASHREPORTERTITLE);
if (title.empty())
title = L"Crash Reporter Error";
MessageBox(NULL, UTF8ToWide(message).c_str(), title.c_str(),
MB_OK | MB_ICONSTOP);
}
@@ -760,16 +760,22 @@ bool UIEnsurePathExists(const string& pa
if (CreateDirectory(UTF8ToWide(path).c_str(), NULL) == 0) {
if (GetLastError() != ERROR_ALREADY_EXISTS)
return false;
}
return true;
}
+bool UIFileExists(const string& path)
+{
+ DWORD attrs = GetFileAttributes(UTF8ToWide(path).c_str());
+ return (attrs != INVALID_FILE_ATTRIBUTES);
+}
+
bool UIMoveFile(const string& oldfile, const string& newfile)
{
if (oldfile == newfile)
return true;
return MoveFile(UTF8ToWide(oldfile).c_str(), UTF8ToWide(newfile).c_str())
== TRUE;
}