2014-05-30 12:53:19 +04:00
/*
This file is part of Telegram Desktop ,
2014-12-01 13:47:38 +03:00
the official desktop version of Telegram messaging app , see https : //telegram.org
2014-05-30 12:53:19 +04:00
Telegram Desktop is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
It 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 General Public License for more details .
2015-10-03 16:16:42 +03:00
In addition , as a special exception , the copyright holders give permission
to link the code of portions of this program with the OpenSSL library .
2014-05-30 12:53:19 +04:00
Full license : https : //github.com/telegramdesktop/tdesktop/blob/master/LICENSE
2016-02-08 13:56:18 +03:00
Copyright ( c ) 2014 - 2016 John Preston , https : //desktop.telegram.org
2014-05-30 12:53:19 +04:00
*/
# include "stdafx.h"
2016-02-01 15:09:23 +03:00
# include <signal.h>
2014-05-30 12:53:19 +04:00
# include "pspecific.h"
2016-03-20 12:10:16 +03:00
# ifndef TDESKTOP_DISABLE_CRASH_REPORTS
2016-01-31 21:01:43 +03:00
// see https://blog.inventic.eu/2012/08/qt-and-google-breakpad/
# ifdef Q_OS_WIN
2016-02-07 18:38:49 +03:00
# pragma warning(push)
# pragma warning(disable:4091)
2016-01-31 21:01:43 +03:00
# include "client/windows/handler/exception_handler.h"
2016-02-07 18:38:49 +03:00
# pragma warning(pop)
2016-03-20 12:10:16 +03:00
# elif defined Q_OS_MAC // Q_OS_WIN
2016-02-02 14:48:46 +03:00
# ifdef MAC_USE_BREAKPAD
2016-01-31 21:01:43 +03:00
# include "client/mac/handler/exception_handler.h"
2016-03-20 12:10:16 +03:00
# else // MAC_USE_BREAKPAD
2016-02-02 14:48:46 +03:00
# include "client/crashpad_client.h"
2016-03-20 12:10:16 +03:00
# endif // else for MAC_USE_BREAKPAD
2016-02-02 14:48:46 +03:00
2016-03-20 12:10:16 +03:00
# elif defined Q_OS_LINUX64 || defined Q_OS_LINUX32 // Q_OS_MAC
2016-01-31 21:01:43 +03:00
# include "client/linux/handler/exception_handler.h"
2016-03-20 12:10:16 +03:00
# endif // Q_OS_LINUX64 || Q_OS_LINUX32
# endif // !TDESKTOP_DISABLE_CRASH_REPORTS
2016-01-31 21:01:43 +03:00
2016-01-11 23:43:29 +08:00
enum LogDataType {
LogDataMain ,
LogDataDebug ,
LogDataTcp ,
LogDataMtp ,
LogDataCount
} ;
2016-01-17 13:01:14 +08:00
QMutex * _logsMutex ( LogDataType type , bool clear = false ) {
static QMutex * LogsMutexes = 0 ;
if ( clear ) {
delete [ ] LogsMutexes ;
LogsMutexes = 0 ;
} else if ( ! LogsMutexes ) {
2016-01-11 23:43:29 +08:00
LogsMutexes = new QMutex [ LogDataCount ] ;
}
return & LogsMutexes [ type ] ;
}
2016-01-17 13:01:14 +08:00
2016-01-11 23:43:29 +08:00
QString _logsFilePath ( LogDataType type , const QString & postfix = QString ( ) ) {
QString path ( cWorkingDir ( ) ) ;
switch ( type ) {
2016-01-17 13:01:14 +08:00
case LogDataMain : path + = qstr ( " log " ) + postfix + qstr ( " .txt " ) ; break ;
2016-01-11 23:43:29 +08:00
case LogDataDebug : path + = qstr ( " DebugLogs/log " ) + postfix + qstr ( " .txt " ) ; break ;
case LogDataTcp : path + = qstr ( " DebugLogs/tcp " ) + postfix + qstr ( " .txt " ) ; break ;
case LogDataMtp : path + = qstr ( " DebugLogs/mtp " ) + postfix + qstr ( " .txt " ) ; break ;
}
return path ;
}
2014-05-30 12:53:19 +04:00
2016-01-17 13:01:14 +08:00
int32 LogsStartIndexChosen = - 1 ;
QString _logsEntryStart ( ) {
static int32 index = 0 ;
QDateTime tm ( QDateTime : : currentDateTime ( ) ) ;
QThread * thread = QThread : : currentThread ( ) ;
MTPThread * mtpThread = qobject_cast < MTPThread * > ( thread ) ;
uint threadId = mtpThread ? mtpThread - > getThreadId ( ) : 0 ;
return QString ( " [%1 %2-%3] " ) . arg ( tm . toString ( " hh:mm:ss.zzz " ) ) . arg ( QString ( " %1 " ) . arg ( threadId , 2 , 10 , QChar ( ' 0 ' ) ) ) . arg ( + + index , 7 , 10 , QChar ( ' 0 ' ) ) ;
}
2016-01-11 23:43:29 +08:00
class LogsDataFields {
public :
2016-01-10 14:05:23 +08:00
2016-01-17 13:01:14 +08:00
LogsDataFields ( ) {
for ( int32 i = 0 ; i < LogDataCount ; + + i ) {
files [ i ] . reset ( new QFile ( ) ) ;
}
2016-01-11 23:43:29 +08:00
}
bool openMain ( ) {
2016-01-17 13:01:14 +08:00
return reopen ( LogDataMain , 0 , qsl ( " start " ) ) ;
}
2016-02-08 13:50:56 +03:00
void closeMain ( ) {
QMutexLocker lock ( _logsMutex ( LogDataMain ) ) ;
if ( files [ LogDataMain ] ) {
streams [ LogDataMain ] . setDevice ( 0 ) ;
files [ LogDataMain ] - > close ( ) ;
}
}
2016-01-17 13:01:14 +08:00
bool instanceChecked ( ) {
2016-01-11 23:43:29 +08:00
return reopen ( LogDataMain , 0 , QString ( ) ) ;
2014-05-30 12:53:19 +04:00
}
2016-01-17 13:01:14 +08:00
QString full ( ) {
if ( ! streams [ LogDataMain ] . device ( ) ) {
return QString ( ) ;
}
QFile out ( files [ LogDataMain ] - > fileName ( ) ) ;
if ( out . open ( QIODevice : : ReadOnly ) ) {
return QString : : fromUtf8 ( out . readAll ( ) ) ;
}
return QString ( ) ;
}
2016-01-11 23:43:29 +08:00
void write ( LogDataType type , const QString & msg ) {
QMutexLocker lock ( _logsMutex ( type ) ) ;
if ( type ! = LogDataMain ) reopenDebug ( ) ;
if ( ! streams [ type ] . device ( ) ) return ;
2014-05-30 12:53:19 +04:00
2016-01-11 23:43:29 +08:00
streams [ type ] < < msg ;
streams [ type ] . flush ( ) ;
2014-05-30 12:53:19 +04:00
}
2016-01-11 23:43:29 +08:00
private :
2016-01-17 13:01:14 +08:00
QSharedPointer < QFile > files [ LogDataCount ] ;
2016-01-11 23:43:29 +08:00
QTextStream streams [ LogDataCount ] ;
2016-01-30 21:24:18 +03:00
int32 part = - 1 ;
2016-01-11 23:43:29 +08:00
bool reopen ( LogDataType type , int32 dayIndex , const QString & postfix ) {
if ( streams [ type ] . device ( ) ) {
if ( type = = LogDataMain ) {
2016-01-17 13:01:14 +08:00
if ( ! postfix . isEmpty ( ) ) {
return true ;
}
} else {
streams [ type ] . setDevice ( 0 ) ;
files [ type ] - > close ( ) ;
2016-01-11 23:43:29 +08:00
}
}
QFlags < QIODevice : : OpenModeFlag > mode = QIODevice : : WriteOnly | QIODevice : : Text ;
2016-01-17 13:01:14 +08:00
if ( type = = LogDataMain ) { // we can call LOG() in LogDataMain reopen - mutex not locked
if ( postfix . isEmpty ( ) ) { // instance checked, need to move to log.txt
t_assert ( ! files [ type ] - > fileName ( ) . isEmpty ( ) ) ; // one of log_startXX.txt should've been opened already
QSharedPointer < QFile > to ( new QFile ( _logsFilePath ( type , postfix ) ) ) ;
if ( to - > exists ( ) & & ! to - > remove ( ) ) {
LOG ( ( " Could not delete '%1' file to start new logging! " ) . arg ( to - > fileName ( ) ) ) ;
return false ;
}
if ( ! QFile ( files [ type ] - > fileName ( ) ) . copy ( to - > fileName ( ) ) ) { // don't close files[type] yet
LOG ( ( " Could not copy '%1' to '%2' to start new logging! " ) . arg ( files [ type ] - > fileName ( ) ) . arg ( to - > fileName ( ) ) ) ;
return false ;
}
if ( to - > open ( mode | QIODevice : : Append ) ) {
qSwap ( files [ type ] , to ) ;
streams [ type ] . setDevice ( files [ type ] . data ( ) ) ;
streams [ type ] . setCodec ( " UTF-8 " ) ;
LOG ( ( " Moved logging from '%1' to '%2'! " ) . arg ( to - > fileName ( ) ) . arg ( files [ type ] - > fileName ( ) ) ) ;
to - > remove ( ) ;
LogsStartIndexChosen = - 1 ;
QDir working ( cWorkingDir ( ) ) ; // delete all other log_startXX.txt that we can
QStringList oldlogs = working . entryList ( QStringList ( " log_start*.txt " ) , QDir : : Files ) ;
for ( QStringList : : const_iterator i = oldlogs . cbegin ( ) , e = oldlogs . cend ( ) ; i ! = e ; + + i ) {
QString oldlog = cWorkingDir ( ) + * i , oldlogend = i - > mid ( qstr ( " log_start " ) . size ( ) ) ;
if ( oldlogend . size ( ) = = 1 + qstr ( " .txt " ) . size ( ) & & oldlogend . at ( 0 ) . isDigit ( ) & & oldlogend . midRef ( 1 ) = = qstr ( " .txt " ) ) {
bool removed = QFile ( * i ) . remove ( ) ;
LOG ( ( " Old start log '%1' found, deleted: %2 " ) . arg ( * i ) . arg ( Logs : : b ( removed ) ) ) ;
}
}
return true ;
}
LOG ( ( " Could not open '%1' file to start new logging! " ) . arg ( to - > fileName ( ) ) ) ;
return false ;
} else {
bool found = false ;
int32 oldest = - 1 ; // find not existing log_startX.txt or pick the oldest one (by lastModified)
QDateTime oldestLastModified ;
for ( int32 i = 0 ; i < 10 ; + + i ) {
QString trying = _logsFilePath ( type , qsl ( " _start%1 " ) . arg ( i ) ) ;
files [ type ] - > setFileName ( trying ) ;
if ( ! files [ type ] - > exists ( ) ) {
LogsStartIndexChosen = i ;
found = true ;
break ;
}
QDateTime lastModified = QFileInfo ( trying ) . lastModified ( ) ;
if ( oldest < 0 | | lastModified < oldestLastModified ) {
oldestLastModified = lastModified ;
oldest = i ;
}
}
if ( ! found ) {
files [ type ] - > setFileName ( _logsFilePath ( type , qsl ( " _start%1 " ) . arg ( oldest ) ) ) ;
LogsStartIndexChosen = oldest ;
}
}
} else {
files [ type ] - > setFileName ( _logsFilePath ( type , postfix ) ) ;
if ( files [ type ] - > exists ( ) ) {
if ( files [ type ] - > open ( QIODevice : : ReadOnly | QIODevice : : Text ) ) {
if ( QString : : fromUtf8 ( files [ type ] - > readLine ( ) ) . toInt ( ) = = dayIndex ) {
2016-01-11 23:43:29 +08:00
mode | = QIODevice : : Append ;
}
2016-01-17 13:01:14 +08:00
files [ type ] - > close ( ) ;
2016-01-11 23:43:29 +08:00
}
} else {
QDir ( ) . mkdir ( cWorkingDir ( ) + qstr ( " DebugLogs " ) ) ;
}
}
2016-01-17 13:01:14 +08:00
if ( files [ type ] - > open ( mode ) ) {
streams [ type ] . setDevice ( files [ type ] . data ( ) ) ;
2016-01-11 23:43:29 +08:00
streams [ type ] . setCodec ( " UTF-8 " ) ;
if ( type ! = LogDataMain ) {
streams [ type ] < < ( ( mode & QIODevice : : Append ) ? qsl ( " ---------------------------------------------------------------- \n NEW LOGGING INSTANCE STARTED!!! \n ---------------------------------------------------------------- \n " ) : qsl ( " %1 \n " ) . arg ( dayIndex ) ) ;
streams [ type ] . flush ( ) ;
}
return true ;
2016-01-17 13:01:14 +08:00
} else if ( type ! = LogDataMain ) {
LOG ( ( " Could not open debug log '%1'! " ) . arg ( files [ type ] - > fileName ( ) ) ) ;
2016-01-11 23:43:29 +08:00
}
return false ;
2014-05-30 12:53:19 +04:00
}
2016-01-11 23:43:29 +08:00
void reopenDebug ( ) {
time_t t = time ( NULL ) ;
struct tm tm ;
mylocaltime ( & tm , & t ) ;
static const int switchEach = 15 ; // minutes
int32 newPart = ( tm . tm_min + tm . tm_hour * 60 ) / switchEach ;
if ( newPart = = part ) return ;
part = newPart ;
int32 dayIndex = ( tm . tm_year + 1900 ) * 10000 + ( tm . tm_mon + 1 ) * 100 + tm . tm_mday ;
QString postfix = QString ( " _%4_%5 " ) . arg ( ( part * switchEach ) / 60 , 2 , 10 , QChar ( ' 0 ' ) ) . arg ( ( part * switchEach ) % 60 , 2 , 10 , QChar ( ' 0 ' ) ) ;
reopen ( LogDataDebug , dayIndex , postfix ) ;
reopen ( LogDataTcp , dayIndex , postfix ) ;
reopen ( LogDataMtp , dayIndex , postfix ) ;
2014-05-30 12:53:19 +04:00
}
2016-01-11 23:43:29 +08:00
} ;
2014-09-30 07:11:09 -07:00
2016-01-11 23:43:29 +08:00
LogsDataFields * LogsData = 0 ;
2014-09-30 07:11:09 -07:00
2016-01-11 23:43:29 +08:00
typedef QList < QPair < LogDataType , QString > > LogsInMemoryList ;
LogsInMemoryList * LogsInMemory = 0 ;
LogsInMemoryList * DeletedLogsInMemory = SharedMemoryLocation < LogsInMemoryList , 0 > ( ) ;
2016-01-17 13:01:14 +08:00
QString LogsBeforeSingleInstanceChecked ; // LogsInMemory already dumped in LogsData, but LogsData is about to be deleted
2016-01-11 23:43:29 +08:00
void _logsWrite ( LogDataType type , const QString & msg ) {
2016-01-17 13:01:14 +08:00
if ( LogsData & & ( type = = LogDataMain | | LogsStartIndexChosen < 0 ) ) {
2016-01-11 23:43:29 +08:00
if ( type = = LogDataMain | | cDebug ( ) ) {
LogsData - > write ( type , msg ) ;
}
} else if ( LogsInMemory ! = DeletedLogsInMemory ) {
if ( ! LogsInMemory ) {
LogsInMemory = new LogsInMemoryList ;
}
2016-01-17 13:01:14 +08:00
LogsInMemory - > push_back ( qMakePair ( type , msg ) ) ;
} else if ( ! LogsBeforeSingleInstanceChecked . isEmpty ( ) & & type = = LogDataMain ) {
LogsBeforeSingleInstanceChecked + = msg ;
2014-05-30 12:53:19 +04:00
}
}
2016-01-11 23:43:29 +08:00
void _moveOldDataFiles ( const QString & from ) ;
2016-01-31 21:01:43 +03:00
namespace SignalHandlers {
2016-03-20 12:10:16 +03:00
void StartCrashHandler ( ) ;
void FinishCrashHandler ( ) ;
2016-01-31 21:01:43 +03:00
}
2016-01-11 23:43:29 +08:00
namespace Logs {
2016-02-29 19:53:26 +03:00
void start ( ) {
2016-01-11 23:43:29 +08:00
t_assert ( LogsData = = 0 ) ;
2016-02-08 17:54:55 +03:00
if ( ! Sandbox : : CheckBetaVersionDir ( ) ) {
2016-01-11 23:43:29 +08:00
return ;
}
bool workingDirChosen = cBetaVersion ( ) ;
2016-01-21 14:58:58 +08:00
QString initialWorkingDir = QDir ( cWorkingDir ( ) ) . absolutePath ( ) + ' / ' , moveOldDataFrom ;
2016-01-11 23:43:29 +08:00
if ( cBetaVersion ( ) ) {
cSetDebug ( true ) ;
2016-03-20 12:10:16 +03:00
# if defined Q_OS_MAC || defined Q_OS_LINUX
2016-01-11 23:43:29 +08:00
} else {
# ifdef _DEBUG
cForceWorkingDir ( cExeDir ( ) ) ;
2016-03-20 12:10:16 +03:00
# else // _DEBUG
2016-01-11 23:43:29 +08:00
if ( cWorkingDir ( ) . isEmpty ( ) ) {
cForceWorkingDir ( psAppDataPath ( ) ) ;
}
2016-03-20 12:10:16 +03:00
# endif // else for _DEBUG
2016-01-11 23:43:29 +08:00
workingDirChosen = true ;
2014-09-30 07:11:09 -07:00
2016-03-20 12:10:16 +03:00
# if defined Q_OS_LINUX && !defined _DEBUG // fix first version
2016-01-21 14:58:58 +08:00
moveOldDataFrom = initialWorkingDir ;
2016-03-20 12:10:16 +03:00
# endif // Q_OS_LINUX && !_DEBUG
2016-01-11 23:43:29 +08:00
2016-03-20 12:10:16 +03:00
# endif // Q_OS_MAC || Q_OS_LINUX
2016-01-11 23:43:29 +08:00
}
2014-09-30 07:11:09 -07:00
2016-01-11 23:43:29 +08:00
LogsData = new LogsDataFields ( ) ;
if ( ! workingDirChosen ) {
cForceWorkingDir ( cWorkingDir ( ) ) ;
if ( ! LogsData - > openMain ( ) ) {
cForceWorkingDir ( cExeDir ( ) ) ;
if ( ! LogsData - > openMain ( ) ) {
cForceWorkingDir ( psAppDataPath ( ) ) ;
}
}
}
cForceWorkingDir ( QDir ( cWorkingDir ( ) ) . absolutePath ( ) + ' / ' ) ;
QDir ( ) . setCurrent ( cWorkingDir ( ) ) ;
2016-01-21 14:58:58 +08:00
QDir ( ) . mkpath ( cWorkingDir ( ) + qstr ( " tdata " ) ) ;
2016-01-11 23:43:29 +08:00
2016-02-08 17:54:55 +03:00
Sandbox : : WorkingDirReady ( ) ;
2016-03-20 12:10:16 +03:00
SignalHandlers : : StartCrashHandler ( ) ;
2016-01-11 23:43:29 +08:00
2016-01-21 14:58:58 +08:00
if ( ! LogsData - > openMain ( ) ) {
delete LogsData ;
LogsData = 0 ;
}
2016-01-11 23:43:29 +08:00
LOG ( ( " Launched version: %1, dev: %2, beta: %3, debug mode: %4, test dc: %5 " ) . arg ( AppVersion ) . arg ( Logs : : b ( cDevVersion ( ) ) ) . arg ( cBetaVersion ( ) ) . arg ( Logs : : b ( cDebug ( ) ) ) . arg ( Logs : : b ( cTestMode ( ) ) ) ) ;
LOG ( ( " Executable dir: %1, name: %2 " ) . arg ( cExeDir ( ) ) . arg ( cExeName ( ) ) ) ;
2016-01-21 14:58:58 +08:00
LOG ( ( " Initial working dir: %1 " ) . arg ( initialWorkingDir ) ) ;
2016-01-11 23:43:29 +08:00
LOG ( ( " Working dir: %1 " ) . arg ( cWorkingDir ( ) ) ) ;
LOG ( ( " Arguments: %1 " ) . arg ( cArguments ( ) ) ) ;
2016-01-21 14:58:58 +08:00
if ( ! LogsData ) {
2016-02-04 15:44:39 +03:00
LOG ( ( " FATAL: Could not open '%1' for writing log! " ) . arg ( _logsFilePath ( LogDataMain , qsl ( " _startXX " ) ) ) ) ;
2016-01-11 23:43:29 +08:00
return ;
}
# ifdef Q_OS_WIN
if ( cWorkingDir ( ) = = psAppDataPath ( ) ) { // fix old "Telegram Win (Unofficial)" version
moveOldDataFrom = psAppDataPathOld ( ) ;
}
# endif
if ( ! moveOldDataFrom . isEmpty ( ) ) {
_moveOldDataFiles ( moveOldDataFrom ) ;
}
if ( LogsInMemory ) {
t_assert ( LogsInMemory ! = DeletedLogsInMemory ) ;
LogsInMemoryList list = * LogsInMemory ;
for ( LogsInMemoryList : : const_iterator i = list . cbegin ( ) , e = list . cend ( ) ; i ! = e ; + + i ) {
2016-01-17 13:01:14 +08:00
if ( i - > first = = LogDataMain ) {
_logsWrite ( i - > first , i - > second ) ;
2016-01-21 14:58:58 +08:00
LOG ( ( " First: %1, %2 " ) . arg ( i - > first ) . arg ( i - > second ) ) ;
2016-01-17 13:01:14 +08:00
}
2016-01-11 23:43:29 +08:00
}
}
2016-01-21 14:58:58 +08:00
LOG ( ( " Logs started " ) ) ;
2014-05-30 12:53:19 +04:00
}
2016-02-29 19:53:26 +03:00
void finish ( ) {
2016-01-11 23:43:29 +08:00
delete LogsData ;
LogsData = 0 ;
2016-01-17 13:01:14 +08:00
if ( LogsInMemory & & LogsInMemory ! = DeletedLogsInMemory ) {
delete LogsInMemory ;
}
LogsInMemory = DeletedLogsInMemory ;
_logsMutex ( LogDataMain , true ) ;
2016-01-31 21:01:43 +03:00
2016-03-20 12:10:16 +03:00
SignalHandlers : : FinishCrashHandler ( ) ;
2016-01-11 23:43:29 +08:00
}
bool started ( ) {
return LogsData ! = 0 ;
}
2014-05-30 12:53:19 +04:00
2016-01-17 13:01:14 +08:00
bool instanceChecked ( ) {
if ( ! LogsData ) return false ;
if ( ! LogsData - > instanceChecked ( ) ) {
LogsBeforeSingleInstanceChecked = Logs : : full ( ) ;
delete LogsData ;
LogsData = 0 ;
2016-02-04 15:44:39 +03:00
LOG ( ( " FATAL: Could not move logging to '%1'! " ) . arg ( _logsFilePath ( LogDataMain ) ) ) ;
2016-01-17 13:01:14 +08:00
return false ;
}
if ( LogsInMemory ) {
t_assert ( LogsInMemory ! = DeletedLogsInMemory ) ;
LogsInMemoryList list = * LogsInMemory ;
for ( LogsInMemoryList : : const_iterator i = list . cbegin ( ) , e = list . cend ( ) ; i ! = e ; + + i ) {
if ( i - > first ! = LogDataMain ) {
_logsWrite ( i - > first , i - > second ) ;
}
}
}
if ( LogsInMemory ) {
t_assert ( LogsInMemory ! = DeletedLogsInMemory ) ;
delete LogsInMemory ;
}
LogsInMemory = DeletedLogsInMemory ;
DEBUG_LOG ( ( " Debug logs started. " ) ) ;
LogsBeforeSingleInstanceChecked . clear ( ) ;
return true ;
}
void multipleInstances ( ) {
if ( LogsInMemory ) {
t_assert ( LogsInMemory ! = DeletedLogsInMemory ) ;
delete LogsInMemory ;
}
LogsInMemory = DeletedLogsInMemory ;
if ( cDebug ( ) ) {
LOG ( ( " WARNING: debug logs are not written in multiple instances mode! " ) ) ;
}
LogsBeforeSingleInstanceChecked . clear ( ) ;
}
2016-02-08 13:50:56 +03:00
void closeMain ( ) {
LOG ( ( " Explicitly closing main log and finishing crash handlers. " ) ) ;
if ( LogsData ) {
LogsData - > closeMain ( ) ;
}
}
2016-01-11 23:43:29 +08:00
void writeMain ( const QString & v ) {
time_t t = time ( NULL ) ;
struct tm tm ;
mylocaltime ( & tm , & t ) ;
2014-09-30 07:11:09 -07:00
2016-01-11 23:43:29 +08:00
QString msg ( QString ( " [%1.%2.%3 %4:%5:%6] %7 \n " ) . arg ( tm . tm_year + 1900 ) . arg ( tm . tm_mon + 1 , 2 , 10 , QChar ( ' 0 ' ) ) . arg ( tm . tm_mday , 2 , 10 , QChar ( ' 0 ' ) ) . arg ( tm . tm_hour , 2 , 10 , QChar ( ' 0 ' ) ) . arg ( tm . tm_min , 2 , 10 , QChar ( ' 0 ' ) ) . arg ( tm . tm_sec , 2 , 10 , QChar ( ' 0 ' ) ) . arg ( v ) ) ;
_logsWrite ( LogDataMain , msg ) ;
2014-09-30 07:11:09 -07:00
2016-01-17 13:01:14 +08:00
QString debugmsg ( QString ( " %1 %2 \n " ) . arg ( _logsEntryStart ( ) ) . arg ( v ) ) ;
2016-01-11 23:43:29 +08:00
_logsWrite ( LogDataDebug , debugmsg ) ;
}
void writeDebug ( const char * file , int32 line , const QString & v ) {
const char * last = strstr ( file , " / " ) , * found = 0 ;
while ( last ) {
found = last ;
last = strstr ( last + 1 , " / " ) ;
}
last = strstr ( file , " \\ " ) ;
while ( last ) {
found = last ;
last = strstr ( last + 1 , " \\ " ) ;
}
if ( found ) {
file = found + 1 ;
}
2016-01-17 13:01:14 +08:00
QString msg ( QString ( " %1 %2 (%3 : %4) \ n " ).arg(_logsEntryStart()).arg(v).arg(file).arg(line)) ;
2016-01-11 23:43:29 +08:00
_logsWrite ( LogDataDebug , msg ) ;
# ifdef Q_OS_WIN
//OutputDebugString(reinterpret_cast<const wchar_t *>(msg.utf16()));
# elif defined Q_OS_MAC
//objc_outputDebugString(msg);
# elif defined Q_OS_LINUX && defined _DEBUG
//std::cout << msg.toUtf8().constData();
# endif
2014-05-30 12:53:19 +04:00
}
2016-01-11 23:43:29 +08:00
void writeTcp ( const QString & v ) {
2016-01-17 13:01:14 +08:00
QString msg ( QString ( " %1 %2 \n " ) . arg ( _logsEntryStart ( ) ) . arg ( v ) ) ;
2016-01-11 23:43:29 +08:00
_logsWrite ( LogDataTcp , msg ) ;
}
2014-05-30 12:53:19 +04:00
2016-01-11 23:43:29 +08:00
void writeMtp ( int32 dc , const QString & v ) {
2016-01-17 13:01:14 +08:00
QString msg ( QString ( " %1 (dc:%2) % 3 \ n " ).arg(_logsEntryStart()).arg(dc).arg(v)) ;
2016-01-11 23:43:29 +08:00
_logsWrite ( LogDataMtp , msg ) ;
}
2014-05-30 12:53:19 +04:00
2016-01-17 13:01:14 +08:00
QString full ( ) {
if ( LogsData ) {
return LogsData - > full ( ) ;
}
if ( ! LogsInMemory | | LogsInMemory = = DeletedLogsInMemory ) {
return LogsBeforeSingleInstanceChecked ;
}
2016-02-08 13:50:56 +03:00
int32 size = LogsBeforeSingleInstanceChecked . size ( ) ;
2016-01-17 13:01:14 +08:00
for ( LogsInMemoryList : : const_iterator i = LogsInMemory - > cbegin ( ) , e = LogsInMemory - > cend ( ) ; i ! = e ; + + i ) {
if ( i - > first = = LogDataMain ) {
size + = i - > second . size ( ) ;
}
}
QString result ;
result . reserve ( size ) ;
2016-02-08 13:50:56 +03:00
if ( ! LogsBeforeSingleInstanceChecked . isEmpty ( ) ) {
result . append ( LogsBeforeSingleInstanceChecked ) ;
}
2016-01-17 13:01:14 +08:00
for ( LogsInMemoryList : : const_iterator i = LogsInMemory - > cbegin ( ) , e = LogsInMemory - > cend ( ) ; i ! = e ; + + i ) {
if ( i - > first = = LogDataMain ) {
result + = i - > second ;
}
}
return result ;
}
2016-01-11 23:43:29 +08:00
QString vector ( const QVector < MTPlong > & ids ) {
if ( ! ids . size ( ) ) return " [] " ;
QString idsStr = QString ( " [%1 " ) . arg ( ids . cbegin ( ) - > v ) ;
for ( QVector < MTPlong > : : const_iterator i = ids . cbegin ( ) + 1 , e = ids . cend ( ) ; i ! = e ; + + i ) {
idsStr + = QString ( " , %2 " ) . arg ( i - > v ) ;
}
return idsStr + " ] " ;
}
2015-06-01 13:58:46 +03:00
2016-01-11 23:43:29 +08:00
QString vector ( const QVector < uint64 > & ids ) {
if ( ! ids . size ( ) ) return " [] " ;
QString idsStr = QString ( " [%1 " ) . arg ( * ids . cbegin ( ) ) ;
for ( QVector < uint64 > : : const_iterator i = ids . cbegin ( ) + 1 , e = ids . cend ( ) ; i ! = e ; + + i ) {
idsStr + = QString ( " , %2 " ) . arg ( * i ) ;
}
return idsStr + " ] " ;
2014-05-30 12:53:19 +04:00
}
}
2016-01-11 23:43:29 +08:00
void _moveOldDataFiles ( const QString & wasDir ) {
2014-09-30 07:11:09 -07:00
QFile data ( wasDir + " data " ) , dataConfig ( wasDir + " data_config " ) , tdataConfig ( wasDir + " tdata/config " ) ;
if ( data . exists ( ) & & dataConfig . exists ( ) & & ! QFileInfo ( cWorkingDir ( ) + " data " ) . exists ( ) & & ! QFileInfo ( cWorkingDir ( ) + " data_config " ) . exists ( ) ) { // move to home dir
LOG ( ( " Copying data to home dir '%1' from '%2' " ) . arg ( cWorkingDir ( ) ) . arg ( wasDir ) ) ;
if ( data . copy ( cWorkingDir ( ) + " data " ) ) {
LOG ( ( " Copied 'data' to home dir " ) ) ;
if ( dataConfig . copy ( cWorkingDir ( ) + " data_config " ) ) {
LOG ( ( " Copied 'data_config' to home dir " ) ) ;
bool tdataGood = true ;
if ( tdataConfig . exists ( ) ) {
tdataGood = false ;
QDir ( ) . mkpath ( cWorkingDir ( ) + " tdata " ) ;
if ( tdataConfig . copy ( cWorkingDir ( ) + " tdata/config " ) ) {
LOG ( ( " Copied 'tdata/config' to home dir " ) ) ;
tdataGood = true ;
} else {
LOG ( ( " Copied 'data' and 'data_config', but could not copy 'tdata/config'! " ) ) ;
}
}
if ( tdataGood ) {
if ( data . remove ( ) ) {
LOG ( ( " Removed 'data' " ) ) ;
} else {
LOG ( ( " Could not remove 'data' " ) ) ;
}
if ( dataConfig . remove ( ) ) {
LOG ( ( " Removed 'data_config' " ) ) ;
} else {
LOG ( ( " Could not remove 'data_config' " ) ) ;
}
if ( ! tdataConfig . exists ( ) | | tdataConfig . remove ( ) ) {
LOG ( ( " Removed 'tdata/config' " ) ) ;
LOG ( ( " Could not remove 'tdata/config' " ) ) ;
} else {
}
QDir ( ) . rmdir ( wasDir + " tdata " ) ;
}
} else {
LOG ( ( " Copied 'data', but could not copy 'data_config'!! " ) ) ;
}
} else {
LOG ( ( " Could not copy 'data'! " ) ) ;
}
}
}
2016-01-21 14:58:58 +08:00
2016-01-31 14:32:29 +03:00
# if defined Q_OS_MAC || defined Q_OS_LINUX32 || defined Q_OS_LINUX64
2016-01-31 21:01:01 +03:00
2016-01-31 14:32:29 +03:00
# include <execinfo.h>
# include <signal.h>
# include <sys/syscall.h>
# ifdef Q_OS_MAC
# include <dlfcn.h>
# endif
# endif
2016-01-21 14:58:58 +08:00
namespace SignalHandlers {
2016-03-20 12:10:16 +03:00
typedef std : : map < std : : string , std : : string > AnnotationsMap ;
AnnotationsMap ProcessAnnotations ;
# ifndef TDESKTOP_DISABLE_CRASH_REPORTS
2016-02-09 19:05:08 +03:00
QString CrashDumpPath ;
2016-03-11 23:07:13 +03:00
FILE * CrashDumpFile = nullptr ;
2016-01-21 14:58:58 +08:00
int CrashDumpFileNo = 0 ;
2016-01-25 13:22:58 +03:00
char LaunchedDateTimeStr [ 32 ] = { 0 } ;
2016-01-30 19:31:10 +03:00
char LaunchedBinaryName [ 256 ] = { 0 } ;
2016-01-21 14:58:58 +08:00
void _writeChar ( char ch ) {
fwrite ( & ch , 1 , 1 , CrashDumpFile ) ;
}
dump : : ~ dump ( ) {
if ( CrashDumpFile ) {
fflush ( CrashDumpFile ) ;
}
}
const dump & operator < < ( const dump & stream , const char * str ) {
if ( ! CrashDumpFile ) return stream ;
fwrite ( str , 1 , strlen ( str ) , CrashDumpFile ) ;
return stream ;
}
2016-02-01 14:50:07 +03:00
const dump & operator < < ( const dump & stream , const wchar_t * str ) {
if ( ! CrashDumpFile ) return stream ;
for ( int i = 0 , l = wcslen ( str ) ; i < l ; + + i ) {
if ( str [ i ] > = 0 & & str [ i ] < 128 ) {
_writeChar ( char ( str [ i ] ) ) ;
} else {
_writeChar ( ' ? ' ) ;
}
}
return stream ;
}
2016-03-20 11:16:35 +03:00
template < bool Unsigned , typename Type >
struct _writeNumberSignAndRemoveIt {
static void call ( Type & number ) {
if ( number < 0 ) {
_writeChar ( ' - ' ) ;
number = - number ;
}
}
} ;
template < typename Type >
struct _writeNumberSignAndRemoveIt < true , Type > {
static void call ( Type & number ) {
}
} ;
2016-01-25 13:22:58 +03:00
template < typename Type >
const dump & _writeNumber ( const dump & stream , Type number ) {
2016-01-21 14:58:58 +08:00
if ( ! CrashDumpFile ) return stream ;
2016-03-20 11:16:35 +03:00
_writeNumberSignAndRemoveIt < ( Type ( - 1 ) > Type ( 0 ) ) , Type > : : call ( number ) ;
2016-01-25 13:22:58 +03:00
Type upper = 1 , prev = number / 10 ;
2016-01-21 14:58:58 +08:00
while ( prev > = upper ) {
upper * = 10 ;
}
while ( upper > 0 ) {
2016-01-25 13:22:58 +03:00
int digit = ( number / upper ) ;
2016-01-21 14:58:58 +08:00
_writeChar ( ' 0 ' + digit ) ;
2016-01-25 13:22:58 +03:00
number - = digit * upper ;
2016-01-21 14:58:58 +08:00
upper / = 10 ;
}
return stream ;
}
2016-01-25 13:22:58 +03:00
const dump & operator < < ( const dump & stream , int num ) {
return _writeNumber ( stream , num ) ;
}
2016-01-30 21:38:33 +03:00
const dump & operator < < ( const dump & stream , unsigned int num ) {
2016-01-25 13:22:58 +03:00
return _writeNumber ( stream , num ) ;
}
2016-01-30 21:38:33 +03:00
const dump & operator < < ( const dump & stream , unsigned long num ) {
return _writeNumber ( stream , num ) ;
}
const dump & operator < < ( const dump & stream , unsigned long long num ) {
2016-01-25 13:22:58 +03:00
return _writeNumber ( stream , num ) ;
}
2016-01-30 21:24:18 +03:00
const dump & operator < < ( const dump & stream , double num ) {
if ( num < 0 ) {
_writeChar ( ' - ' ) ;
num = - num ;
}
_writeNumber ( stream , uint64 ( floor ( num ) ) ) ;
_writeChar ( ' . ' ) ;
num - = floor ( num ) ;
for ( int i = 0 ; i < 4 ; + + i ) {
num * = 10 ;
int digit = int ( floor ( num ) ) ;
_writeChar ( ' 0 ' + digit ) ;
num - = digit ;
}
return stream ;
}
2016-01-25 13:22:58 +03:00
Qt : : HANDLE LoggingCrashThreadId = 0 ;
bool LoggingCrashHeaderWritten = false ;
QMutex LoggingCrashMutex ;
2016-02-02 14:58:28 +03:00
const char * BreakpadDumpPath = 0 ;
2016-02-01 14:50:07 +03:00
const wchar_t * BreakpadDumpPathW = 0 ;
2016-01-31 14:32:29 +03:00
# if defined Q_OS_MAC || defined Q_OS_LINUX32 || defined Q_OS_LINUX64
struct sigaction SIG_def [ 32 ] ;
void Handler ( int signum , siginfo_t * info , void * ucontext ) {
2016-02-01 13:12:37 +03:00
if ( signum > 0 ) {
sigaction ( signum , & SIG_def [ signum ] , 0 ) ;
}
2016-01-31 14:32:29 +03:00
2016-03-20 12:10:16 +03:00
# else // Q_OS_MAC || Q_OS_LINUX32 || Q_OS_LINUX64
2016-01-21 14:58:58 +08:00
void Handler ( int signum ) {
2016-03-20 12:10:16 +03:00
# endif // else for Q_OS_MAC || Q_OS_LINUX || Q_OS_LINUX64
2016-01-31 14:32:29 +03:00
2016-01-21 14:58:58 +08:00
const char * name = 0 ;
switch ( signum ) {
case SIGABRT : name = " SIGABRT " ; break ;
case SIGSEGV : name = " SIGSEGV " ; break ;
case SIGILL : name = " SIGILL " ; break ;
case SIGFPE : name = " SIGFPE " ; break ;
# ifndef Q_OS_WIN
case SIGBUS : name = " SIGBUS " ; break ;
case SIGSYS : name = " SIGSYS " ; break ;
2016-03-20 12:10:16 +03:00
# endif // !Q_OS_WIN
2016-01-21 14:58:58 +08:00
}
2016-01-25 13:22:58 +03:00
Qt : : HANDLE thread = QThread : : currentThreadId ( ) ;
if ( thread = = LoggingCrashThreadId ) return ;
QMutexLocker lock ( & LoggingCrashMutex ) ;
LoggingCrashThreadId = thread ;
if ( ! LoggingCrashHeaderWritten ) {
LoggingCrashHeaderWritten = true ;
2016-02-02 15:50:12 +03:00
const AnnotationsMap c_ProcessAnnotations ( ProcessAnnotations ) ;
2016-03-14 12:25:48 +03:00
for ( const auto & i : c_ProcessAnnotations ) {
dump ( ) < < i . first . c_str ( ) < < " : " < < i . second . c_str ( ) < < " \n " ;
2016-01-25 13:22:58 +03:00
}
psWriteDump ( ) ;
dump ( ) < < " \n " ;
}
2016-01-21 14:58:58 +08:00
if ( name ) {
2016-01-25 13:22:58 +03:00
dump ( ) < < " Caught signal " < < signum < < " ( " < < name < < " ) in thread " < < uint64 ( thread ) < < " \n " ;
2016-02-01 14:09:11 +03:00
} else if ( signum = = - 1 ) {
dump ( ) < < " Google Breakpad caught a crash, minidump written in thread " < < uint64 ( thread ) < < " \n " ;
2016-02-01 14:50:07 +03:00
if ( BreakpadDumpPath ) {
dump ( ) < < " Minidump: " < < BreakpadDumpPath < < " \n " ;
} else if ( BreakpadDumpPathW ) {
dump ( ) < < " Minidump: " < < BreakpadDumpPathW < < " \n " ;
}
2016-02-01 14:09:11 +03:00
} else {
2016-01-25 13:22:58 +03:00
dump ( ) < < " Caught signal " < < signum < < " in thread " < < uint64 ( thread ) < < " \n " ;
2016-01-21 14:58:58 +08:00
}
2016-01-25 13:22:58 +03:00
2016-02-02 14:58:28 +03:00
// see https://github.com/benbjohnson/bandicoot
2016-01-31 14:32:29 +03:00
# if defined Q_OS_MAC || defined Q_OS_LINUX32 || defined Q_OS_LINUX64
ucontext_t * uc = ( ucontext_t * ) ucontext ;
void * caller = 0 ;
2016-02-01 13:12:37 +03:00
if ( uc ) {
2016-01-31 14:32:29 +03:00
# if defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_6)
/* OSX < 10.6 */
# if defined(__x86_64__)
2016-01-31 19:13:51 +03:00
caller = ( void * ) uc - > uc_mcontext - > __ss . __rip ;
2016-01-31 14:32:29 +03:00
# elif defined(__i386__)
2016-01-31 19:13:51 +03:00
caller = ( void * ) uc - > uc_mcontext - > __ss . __eip ;
2016-01-31 14:32:29 +03:00
# else
2016-01-31 19:13:51 +03:00
caller = ( void * ) uc - > uc_mcontext - > __ss . __srr0 ;
2016-01-31 14:32:29 +03:00
# endif
# elif defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)
/* OSX >= 10.6 */
# if defined(_STRUCT_X86_THREAD_STATE64) && !defined(__i386__)
caller = ( void * ) uc - > uc_mcontext - > __ss . __rip ;
# else
2016-01-31 19:13:51 +03:00
caller = ( void * ) uc - > uc_mcontext - > __ss . __eip ;
2016-01-31 14:32:29 +03:00
# endif
# elif defined(__linux__)
/* Linux */
# if defined(__i386__)
2016-01-31 19:13:51 +03:00
caller = ( void * ) uc - > uc_mcontext . gregs [ 14 ] ; /* Linux 32 */
2016-01-31 14:32:29 +03:00
# elif defined(__X86_64__) || defined(__x86_64__)
2016-01-31 19:13:51 +03:00
caller = ( void * ) uc - > uc_mcontext . gregs [ 16 ] ; /* Linux 64 */
2016-01-31 14:32:29 +03:00
# elif defined(__ia64__) /* Linux IA64 */
2016-01-31 19:13:51 +03:00
caller = ( void * ) uc - > uc_mcontext . sc_ip ;
2016-01-31 14:32:29 +03:00
# endif
# endif
2016-02-01 13:12:37 +03:00
}
2016-01-31 14:32:29 +03:00
2016-01-31 19:13:51 +03:00
void * addresses [ 132 ] = { 0 } ;
2016-01-31 14:32:29 +03:00
size_t size = backtrace ( addresses , 128 ) ;
/* overwrite sigaction with caller's address */
2016-01-31 19:13:51 +03:00
if ( caller ) {
for ( int i = size ; i > 1 ; - - i ) {
addresses [ i + 3 ] = addresses [ i ] ;
}
addresses [ 2 ] = ( void * ) 0x1 ;
addresses [ 3 ] = caller ;
addresses [ 4 ] = ( void * ) 0x1 ;
}
2016-01-31 14:32:29 +03:00
# ifdef Q_OS_MAC
dump ( ) < < " \n Base image addresses: \n " ;
for ( size_t i = 0 ; i < size ; + + i ) {
Dl_info info ;
dump ( ) < < i < < " " ;
if ( dladdr ( addresses [ i ] , & info ) ) {
dump ( ) < < uint64 ( info . dli_fbase ) < < " ( " < < info . dli_fname < < " ) \n " ;
} else {
dump ( ) < < " _unknown_module_ \n " ;
}
}
2016-03-20 12:10:16 +03:00
# endif // Q_OS_MAC
2016-01-31 14:32:29 +03:00
2016-01-25 13:22:58 +03:00
dump ( ) < < " \n Backtrace: \n " ;
2016-01-31 14:32:29 +03:00
backtrace_symbols_fd ( addresses , size , CrashDumpFileNo ) ;
2016-01-30 21:24:18 +03:00
2016-03-20 12:10:16 +03:00
# else // Q_OS_MAC || Q_OS_LINUX32 || Q_OS_LINUX64
2016-01-31 21:01:43 +03:00
dump ( ) < < " \n Backtrace: \n " ;
2016-01-31 14:32:29 +03:00
psWriteStackTrace ( ) ;
2016-03-20 12:10:16 +03:00
# endif // else for Q_OS_MAC || Q_OS_LINUX32 || Q_OS_LINUX64
2016-01-31 14:32:29 +03:00
dump ( ) < < " \n " ;
LoggingCrashThreadId = 0 ;
2016-01-21 14:58:58 +08:00
}
2016-02-02 14:48:46 +03:00
bool SetSignalHandlers = true ;
2016-03-14 12:25:48 +03:00
bool CrashLogged = false ;
2016-02-02 14:48:46 +03:00
# if !defined Q_OS_MAC || defined MAC_USE_BREAKPAD
2016-02-01 13:12:37 +03:00
google_breakpad : : ExceptionHandler * BreakpadExceptionHandler = 0 ;
# ifdef Q_OS_WIN
bool DumpCallback ( const wchar_t * _dump_dir , const wchar_t * _minidump_id , void * context , EXCEPTION_POINTERS * exinfo , MDRawAssertionInfo * assertion , bool success )
2016-03-20 12:10:16 +03:00
# elif defined Q_OS_MAC // Q_OS_WIN
2016-02-01 13:12:37 +03:00
bool DumpCallback ( const char * _dump_dir , const char * _minidump_id , void * context , bool success )
2016-03-20 12:10:16 +03:00
# elif defined Q_OS_LINUX64 || defined Q_OS_LINUX32 // Q_OS_MAC
2016-02-01 13:12:37 +03:00
bool DumpCallback ( const google_breakpad : : MinidumpDescriptor & md , void * context , bool success )
2016-03-20 12:10:16 +03:00
# endif // Q_OS_LINUX64 || Q_OS_LINUX32
2016-02-01 13:12:37 +03:00
{
2016-03-14 12:25:48 +03:00
if ( CrashLogged ) return success ;
CrashLogged = true ;
2016-02-01 14:50:07 +03:00
# ifdef Q_OS_WIN
BreakpadDumpPathW = _minidump_id ;
Handler ( - 1 ) ;
2016-03-20 12:10:16 +03:00
# else // Q_OS_WIN
2016-02-01 14:50:07 +03:00
# ifdef Q_OS_MAC
BreakpadDumpPath = _minidump_id ;
2016-03-20 12:10:16 +03:00
# else // Q_OS_MAC
2016-02-01 14:50:07 +03:00
BreakpadDumpPath = md . path ( ) ;
2016-03-20 12:10:16 +03:00
# endif // else for Q_OS_MAC
2016-02-01 13:12:37 +03:00
Handler ( - 1 , 0 , 0 ) ;
2016-03-20 12:10:16 +03:00
# endif // else for Q_OS_WIN
2016-02-01 13:12:37 +03:00
return success ;
}
2016-03-20 12:10:16 +03:00
# endif // !Q_OS_MAC || MAC_USE_BREAKPAD
# endif // !TDESKTOP_DISABLE_CRASH_REPORTS
2016-02-01 13:12:37 +03:00
2016-03-20 12:10:16 +03:00
void StartCrashHandler ( ) {
# ifndef TDESKTOP_DISABLE_CRASH_REPORTS
2016-02-02 15:50:12 +03:00
ProcessAnnotations [ " Binary " ] = cExeName ( ) . toUtf8 ( ) . constData ( ) ;
ProcessAnnotations [ " ApiId " ] = QString : : number ( ApiId ) . toUtf8 ( ) . constData ( ) ;
ProcessAnnotations [ " Version " ] = ( cBetaVersion ( ) ? qsl ( " %1 beta " ) . arg ( cBetaVersion ( ) ) : ( cDevVersion ( ) ? qsl ( " %1 dev " ) : qsl ( " %1 " ) ) . arg ( AppVersion ) ) . toUtf8 ( ) . constData ( ) ;
ProcessAnnotations [ " Launched " ] = QDateTime : : currentDateTime ( ) . toString ( " dd.MM.yyyy hh:mm:ss " ) . toUtf8 ( ) . constData ( ) ;
ProcessAnnotations [ " Platform " ] = cPlatformString ( ) . toUtf8 ( ) . constData ( ) ;
2016-02-15 18:52:11 +03:00
ProcessAnnotations [ " UserTag " ] = QString : : number ( Sandbox : : UserTag ( ) , 16 ) . toUtf8 ( ) . constData ( ) ;
2016-02-02 14:48:46 +03:00
QString dumpspath = cWorkingDir ( ) + qsl ( " tdata/dumps " ) ;
QDir ( ) . mkpath ( dumpspath ) ;
2016-02-01 13:12:37 +03:00
# ifdef Q_OS_WIN
BreakpadExceptionHandler = new google_breakpad : : ExceptionHandler (
2016-02-02 14:48:46 +03:00
dumpspath . toStdWString ( ) ,
2016-02-01 13:12:37 +03:00
/*FilterCallback*/ 0 ,
DumpCallback ,
/*context*/ 0 ,
true
) ;
2016-03-20 12:10:16 +03:00
# elif defined Q_OS_MAC // Q_OS_WIN
2016-02-02 14:48:46 +03:00
# ifdef MAC_USE_BREAKPAD
2016-02-04 15:44:39 +03:00
# ifndef _DEBUG
2016-02-01 13:12:37 +03:00
BreakpadExceptionHandler = new google_breakpad : : ExceptionHandler (
2016-02-09 17:42:36 +03:00
QFile : : encodeName ( dumpspath ) . toStdString ( ) ,
2016-02-01 13:12:37 +03:00
/*FilterCallback*/ 0 ,
DumpCallback ,
/*context*/ 0 ,
true ,
0
) ;
2016-03-20 12:10:16 +03:00
# endif // !_DEBUG
2016-02-02 14:48:46 +03:00
SetSignalHandlers = false ;
2016-03-20 12:10:16 +03:00
# else // MAC_USE_BREAKPAD
2016-02-02 14:48:46 +03:00
crashpad : : CrashpadClient crashpad_client ;
2016-02-02 15:50:12 +03:00
std : : string handler = ( cExeDir ( ) + cExeName ( ) + qsl ( " /Contents/Helpers/crashpad_handler " ) ) . toUtf8 ( ) . constData ( ) ;
2016-02-09 17:42:36 +03:00
std : : string database = QFile : : encodeName ( dumpspath ) . constData ( ) ;
2016-02-02 14:48:46 +03:00
if ( crashpad_client . StartHandler ( base : : FilePath ( handler ) ,
base : : FilePath ( database ) ,
std : : string ( ) ,
ProcessAnnotations ,
std : : vector < std : : string > ( ) ,
false ) ) {
crashpad_client . UseHandler ( ) ;
}
2016-03-20 12:10:16 +03:00
# endif // else for MAC_USE_BREAKPAD
2016-02-01 13:12:37 +03:00
# elif defined Q_OS_LINUX64 || defined Q_OS_LINUX32
BreakpadExceptionHandler = new google_breakpad : : ExceptionHandler (
2016-02-09 17:42:36 +03:00
google_breakpad : : MinidumpDescriptor ( QFile : : encodeName ( dumpspath ) . toStdString ( ) ) ,
2016-02-01 13:12:37 +03:00
/*FilterCallback*/ 0 ,
DumpCallback ,
/*context*/ 0 ,
true ,
- 1
) ;
2016-03-20 12:10:16 +03:00
# endif // Q_OS_LINUX64 || Q_OS_LINUX32
# endif // !TDESKTOP_DISABLE_CRASH_REPORTS
2016-02-01 13:12:37 +03:00
}
2016-03-20 12:10:16 +03:00
void FinishCrashHandler ( ) {
# ifndef TDESKTOP_DISABLE_CRASH_REPORTS
2016-02-02 14:48:46 +03:00
# if !defined Q_OS_MAC || defined MAC_USE_BREAKPAD
2016-02-01 13:12:37 +03:00
if ( BreakpadExceptionHandler ) {
google_breakpad : : ExceptionHandler * h = BreakpadExceptionHandler ;
BreakpadExceptionHandler = 0 ;
delete h ;
}
2016-03-20 12:10:16 +03:00
# endif // !Q_OS_MAC || MAC_USE_BREAKPAD
# endif // !TDESKTOP_DISABLE_CRASH_REPORTS
2016-02-01 13:12:37 +03:00
}
2016-01-21 14:58:58 +08:00
Status start ( ) {
2016-03-20 12:10:16 +03:00
# ifndef TDESKTOP_DISABLE_CRASH_REPORTS
2016-02-09 19:05:08 +03:00
CrashDumpPath = cWorkingDir ( ) + qsl ( " tdata/working " ) ;
2016-03-20 12:10:16 +03:00
2016-02-09 19:05:08 +03:00
# ifdef Q_OS_WIN
2016-03-20 11:16:35 +03:00
FILE * f = nullptr ;
if ( _wfopen_s ( & f , CrashDumpPath . toStdWString ( ) . c_str ( ) , L " rb " ) ! = 0 ) {
f = nullptr ;
} else {
2016-03-20 12:10:16 +03:00
# else // !Q_OS_WIN
2016-02-09 19:05:08 +03:00
if ( FILE * f = fopen ( QFile : : encodeName ( CrashDumpPath ) . constData ( ) , " rb " ) ) {
2016-03-20 12:10:16 +03:00
# endif // else for !Q_OS_WIN
2016-01-21 14:58:58 +08:00
QByteArray lastdump ;
2016-03-11 22:10:56 +03:00
char buffer [ 256 * 1024 ] = { 0 } ;
int32 read = fread ( buffer , 1 , 256 * 1024 , f ) ;
if ( read > 0 ) {
2016-01-21 14:58:58 +08:00
lastdump . append ( buffer , read ) ;
}
fclose ( f ) ;
2016-02-08 17:54:55 +03:00
Sandbox : : SetLastCrashDump ( lastdump ) ;
2016-01-21 14:58:58 +08:00
2016-02-09 19:05:08 +03:00
LOG ( ( " Opened '%1' for reading, the previous Telegram Desktop launch was not finished properly :( Crash log size: %2 " ) . arg ( CrashDumpPath ) . arg ( lastdump . size ( ) ) ) ;
2016-01-21 14:58:58 +08:00
return LastCrashed ;
}
2016-03-20 12:10:16 +03:00
# endif // !TDESKTOP_DISABLE_CRASH_REPORTS
2016-01-21 14:58:58 +08:00
return restart ( ) ;
}
Status restart ( ) {
2016-03-20 12:10:16 +03:00
# ifndef TDESKTOP_DISABLE_CRASH_REPORTS
2016-01-30 19:31:10 +03:00
if ( CrashDumpFile ) {
return Started ;
}
2016-02-09 19:05:08 +03:00
# ifdef Q_OS_WIN
2016-03-20 11:16:35 +03:00
if ( _wfopen_s ( & CrashDumpFile , CrashDumpPath . toStdWString ( ) . c_str ( ) , L " wb " ) ! = 0 ) {
CrashDumpFile = nullptr ;
}
2016-03-20 12:10:16 +03:00
# else // Q_OS_WIN
2016-02-09 19:05:08 +03:00
CrashDumpFile = fopen ( QFile : : encodeName ( CrashDumpPath ) . constData ( ) , " wb " ) ;
2016-03-20 12:10:16 +03:00
# endif // else for Q_OS_WIN
2016-01-21 14:58:58 +08:00
if ( CrashDumpFile ) {
2016-03-20 11:16:35 +03:00
# ifdef Q_OS_WIN
CrashDumpFileNo = _fileno ( CrashDumpFile ) ;
2016-03-20 12:10:16 +03:00
# else // Q_OS_WIN
2016-01-21 14:58:58 +08:00
CrashDumpFileNo = fileno ( CrashDumpFile ) ;
2016-03-20 12:10:16 +03:00
# endif // else for Q_OS_WIN
2016-02-02 14:48:46 +03:00
if ( SetSignalHandlers ) {
2016-01-31 14:32:29 +03:00
# ifndef Q_OS_WIN
2016-02-02 14:48:46 +03:00
struct sigaction sigact ;
sigact . sa_sigaction = SignalHandlers : : Handler ;
sigemptyset ( & sigact . sa_mask ) ;
sigact . sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO ;
sigaction ( SIGABRT , & sigact , & SIG_def [ SIGABRT ] ) ;
sigaction ( SIGSEGV , & sigact , & SIG_def [ SIGSEGV ] ) ;
sigaction ( SIGILL , & sigact , & SIG_def [ SIGILL ] ) ;
sigaction ( SIGFPE , & sigact , & SIG_def [ SIGFPE ] ) ;
sigaction ( SIGBUS , & sigact , & SIG_def [ SIGBUS ] ) ;
sigaction ( SIGSYS , & sigact , & SIG_def [ SIGSYS ] ) ;
2016-03-20 12:10:16 +03:00
# else // !Q_OS_WIN
2016-02-02 14:48:46 +03:00
signal ( SIGABRT , SignalHandlers : : Handler ) ;
signal ( SIGSEGV , SignalHandlers : : Handler ) ;
signal ( SIGILL , SignalHandlers : : Handler ) ;
signal ( SIGFPE , SignalHandlers : : Handler ) ;
2016-03-20 12:10:16 +03:00
# endif // else for !Q_OS_WIN
2016-02-02 14:48:46 +03:00
}
2016-01-21 14:58:58 +08:00
return Started ;
}
2016-02-09 19:05:08 +03:00
LOG ( ( " FATAL: Could not open '%1' for writing! " ) . arg ( CrashDumpPath ) ) ;
2016-01-21 14:58:58 +08:00
return CantOpen ;
2016-03-20 12:10:16 +03:00
# else // !TDESKTOP_DISABLE_CRASH_REPORTS
return Started ;
# endif // else for !TDESKTOP_DISABLE_CRASH_REPORTS
2016-01-21 14:58:58 +08:00
}
void finish ( ) {
2016-03-20 12:10:16 +03:00
# ifndef TDESKTOP_DISABLE_CRASH_REPORTS
2016-02-02 14:48:46 +03:00
FinishBreakpad ( ) ;
2016-01-21 14:58:58 +08:00
if ( CrashDumpFile ) {
fclose ( CrashDumpFile ) ;
2016-03-11 23:07:13 +03:00
CrashDumpFile = nullptr ;
2016-02-09 19:05:08 +03:00
# ifdef Q_OS_WIN
_wunlink ( CrashDumpPath . toStdWString ( ) . c_str ( ) ) ;
2016-03-20 12:10:16 +03:00
# else // Q_OS_WIN
2016-02-09 19:05:08 +03:00
unlink ( CrashDumpPath . toUtf8 ( ) . constData ( ) ) ;
2016-03-20 12:10:16 +03:00
# endif // else for Q_OS_WIN
2016-01-21 14:58:58 +08:00
}
2016-03-20 12:10:16 +03:00
# endif // !TDESKTOP_DISABLE_CRASH_REPORTS
2016-01-21 14:58:58 +08:00
}
2016-03-14 12:25:48 +03:00
void setSelfUsername ( const QString & username ) {
if ( username . trimmed ( ) . isEmpty ( ) ) {
ProcessAnnotations . erase ( " Username " ) ;
} else {
ProcessAnnotations [ " Username " ] = username . toUtf8 ( ) . constData ( ) ;
}
}
2016-03-15 15:18:12 +03:00
void setAssertionInfo ( const QString & info ) {
ProcessAnnotations [ " Assertion " ] = info . toUtf8 ( ) . constData ( ) ;
}
2016-01-21 14:58:58 +08:00
}