llappviewerlinux.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:20k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /**
  2.  * @file llappviewerlinux.cpp
  3.  * @brief The LLAppViewerLinux class definitions
  4.  *
  5.  * $LicenseInfo:firstyear=2007&license=viewergpl$
  6.  * 
  7.  * Copyright (c) 2007-2010, Linden Research, Inc.
  8.  * 
  9.  * Second Life Viewer Source Code
  10.  * The source code in this file ("Source Code") is provided by Linden Lab
  11.  * to you under the terms of the GNU General Public License, version 2.0
  12.  * ("GPL"), unless you have obtained a separate licensing agreement
  13.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  14.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16.  * 
  17.  * There are special exceptions to the terms and conditions of the GPL as
  18.  * it is applied to this Source Code. View the full text of the exception
  19.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  20.  * online at
  21.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22.  * 
  23.  * By copying, modifying or distributing this software, you acknowledge
  24.  * that you have read and understood your obligations described above,
  25.  * and agree to abide by those obligations.
  26.  * 
  27.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29.  * COMPLETENESS OR PERFORMANCE.
  30.  * $/LicenseInfo$
  31.  */ 
  32. #include "llviewerprecompiledheaders.h"
  33. #include "llappviewerlinux.h"
  34. #include "llcommandlineparser.h"
  35. #include "llmemtype.h"
  36. #include "llurldispatcher.h" // SLURL from other app instance
  37. #include "llviewernetwork.h"
  38. #include "llviewercontrol.h"
  39. #include "llwindowsdl.h"
  40. #include "llmd5.h"
  41. #include "llfindlocale.h"
  42. #include <exception>
  43. #if LL_LINUX
  44. # include <dlfcn.h> // RTLD_LAZY
  45. # include <execinfo.h>  // backtrace - glibc only
  46. #elif LL_SOLARIS
  47. # include <sys/types.h>
  48. # include <unistd.h>
  49. # include <fcntl.h>
  50. # include <ucontext.h>
  51. #endif
  52. #ifdef LL_ELFBIN
  53. # ifdef __GNUC__
  54. #  include <cxxabi.h> // for symbol demangling
  55. # endif
  56. # include "ELFIO/ELFIO.h" // for better backtraces
  57. #endif
  58. #if LL_DBUS_ENABLED
  59. # include "llappviewerlinux_api_dbus.h"
  60. // regrettable hacks to give us better runtime compatibility with older systems inside llappviewerlinux_api.h:
  61. #define llg_return_if_fail(COND) do{if (!(COND)) return;}while(0)
  62. #undef g_return_if_fail
  63. #define g_return_if_fail(COND) llg_return_if_fail(COND)
  64. // The generated API
  65. # include "llappviewerlinux_api.h"
  66. #endif
  67. namespace
  68. {
  69. int gArgC = 0;
  70. char **gArgV = NULL;
  71. void (*gOldTerminateHandler)() = NULL;
  72. }
  73. static void exceptionTerminateHandler()
  74. {
  75. // reinstall default terminate() handler in case we re-terminate.
  76. if (gOldTerminateHandler) std::set_terminate(gOldTerminateHandler);
  77. // treat this like a regular viewer crash, with nice stacktrace etc.
  78. LLAppViewer::handleSyncViewerCrash();
  79. LLAppViewer::handleViewerCrash();
  80. // we've probably been killed-off before now, but...
  81. gOldTerminateHandler(); // call old terminate() handler
  82. }
  83. int main( int argc, char **argv ) 
  84. {
  85. LLMemType mt1(LLMemType::MTYPE_STARTUP);
  86. #if LL_SOLARIS && defined(__sparc)
  87. asm ("tat6");  // NOTE:  Make sure memory alignment is enforced on SPARC
  88. #endif
  89. gArgC = argc;
  90. gArgV = argv;
  91. LLAppViewer* viewer_app_ptr = new LLAppViewerLinux();
  92. // install unexpected exception handler
  93. gOldTerminateHandler = std::set_terminate(exceptionTerminateHandler);
  94. // install crash handlers
  95. viewer_app_ptr->setErrorHandler(LLAppViewer::handleViewerCrash);
  96. viewer_app_ptr->setSyncErrorHandler(LLAppViewer::handleSyncViewerCrash);
  97. bool ok = viewer_app_ptr->init();
  98. if(!ok)
  99. {
  100. llwarns << "Application init failed." << llendl;
  101. return -1;
  102. }
  103. // Run the application main loop
  104. if(!LLApp::isQuitting()) 
  105. {
  106. viewer_app_ptr->mainLoop();
  107. }
  108. if (!LLApp::isError())
  109. {
  110. //
  111. // We don't want to do cleanup here if the error handler got called -
  112. // the assumption is that the error handler is responsible for doing
  113. // app cleanup if there was a problem.
  114. //
  115. viewer_app_ptr->cleanup();
  116. }
  117. delete viewer_app_ptr;
  118. viewer_app_ptr = NULL;
  119. return 0;
  120. }
  121. #ifdef LL_SOLARIS
  122. static inline BOOL do_basic_glibc_backtrace()
  123. {
  124. BOOL success = FALSE;
  125. std::string strace_filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log");
  126. llinfos << "Opening stack trace file " << strace_filename << llendl;
  127. LLFILE* StraceFile = LLFile::fopen(strace_filename, "w");
  128. if (!StraceFile)
  129. {
  130. llinfos << "Opening stack trace file " << strace_filename << " failed. Using stderr." << llendl;
  131. StraceFile = stderr;
  132. }
  133. printstack(fileno(StraceFile));
  134. if (StraceFile != stderr)
  135. fclose(StraceFile);
  136. return success;
  137. }
  138. #else
  139. #define MAX_STACK_TRACE_DEPTH 40
  140. // This uses glibc's basic built-in stack-trace functions for a not very
  141. // amazing backtrace.
  142. static inline BOOL do_basic_glibc_backtrace()
  143. {
  144. void *stackarray[MAX_STACK_TRACE_DEPTH];
  145. size_t size;
  146. char **strings;
  147. size_t i;
  148. BOOL success = FALSE;
  149. size = backtrace(stackarray, MAX_STACK_TRACE_DEPTH);
  150. strings = backtrace_symbols(stackarray, size);
  151. std::string strace_filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log");
  152. llinfos << "Opening stack trace file " << strace_filename << llendl;
  153. LLFILE* StraceFile = LLFile::fopen(strace_filename, "w"); // Flawfinder: ignore
  154.         if (!StraceFile)
  155. {
  156. llinfos << "Opening stack trace file " << strace_filename << " failed. Using stderr." << llendl;
  157. StraceFile = stderr;
  158. }
  159. if (size)
  160. {
  161. for (i = 0; i < size; i++)
  162. {
  163. // the format of the StraceFile is very specific, to allow (kludgy) machine-parsing
  164. fprintf(StraceFile, "%-3lu ", (unsigned long)i);
  165. fprintf(StraceFile, "%-32st", "unknown");
  166. fprintf(StraceFile, "%p ", stackarray[i]);
  167. fprintf(StraceFile, "%sn", strings[i]);
  168. }
  169. success = TRUE;
  170. }
  171. if (StraceFile != stderr)
  172. fclose(StraceFile);
  173. free (strings);
  174. return success;
  175. }
  176. #if LL_ELFBIN
  177. // This uses glibc's basic built-in stack-trace functions together with
  178. // ELFIO's ability to parse the .symtab ELF section for better symbol
  179. // extraction without exporting symbols (which'd cause subtle, fatal bugs).
  180. static inline BOOL do_elfio_glibc_backtrace()
  181. {
  182. void *stackarray[MAX_STACK_TRACE_DEPTH];
  183. size_t btsize;
  184. char **strings;
  185. BOOL success = FALSE;
  186. std::string appfilename = gDirUtilp->getExecutablePathAndName();
  187. std::string strace_filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log");
  188. llinfos << "Opening stack trace file " << strace_filename << llendl;
  189. LLFILE* StraceFile = LLFile::fopen(strace_filename, "w"); // Flawfinder: ignore
  190.         if (!StraceFile)
  191. {
  192. llinfos << "Opening stack trace file " << strace_filename << " failed. Using stderr." << llendl;
  193. StraceFile = stderr;
  194. }
  195. // get backtrace address list and basic symbol info
  196. btsize = backtrace(stackarray, MAX_STACK_TRACE_DEPTH);
  197. strings = backtrace_symbols(stackarray, btsize);
  198. // create ELF reader for our app binary
  199. IELFI* pReader;
  200. const IELFISection* pSec = NULL;
  201. IELFISymbolTable* pSymTbl = 0;
  202. if (ERR_ELFIO_NO_ERROR != ELFIO::GetInstance()->CreateELFI(&pReader) ||
  203.     ERR_ELFIO_NO_ERROR != pReader->Load(appfilename.c_str()) ||
  204.     // find symbol table, create reader-object
  205.     NULL == (pSec = pReader->GetSection( ".symtab" )) ||
  206.     ERR_ELFIO_NO_ERROR != pReader->CreateSectionReader(IELFI::ELFI_SYMBOL, pSec, (void**)&pSymTbl) )
  207. {
  208. // Failed to open our binary and read its symbol table somehow
  209. llinfos << "Could not initialize ELF symbol reading - doing basic backtrace." << llendl;
  210. if (StraceFile != stderr)
  211. fclose(StraceFile);
  212. // note that we may be leaking some of the above ELFIO
  213. // objects now, but it's expected that we'll be dead soon
  214. // and we want to tread delicately until we get *some* kind
  215. // of useful backtrace.
  216. return do_basic_glibc_backtrace();
  217. }
  218. // iterate over trace and symtab, looking for plausible symbols
  219. std::string   name;
  220. Elf32_Addr    value;
  221. Elf32_Word    ssize;
  222. unsigned char bind;
  223. unsigned char type;
  224. Elf32_Half    section;
  225. int nSymNo = pSymTbl->GetSymbolNum();
  226. size_t btpos;
  227. for (btpos = 0; btpos < btsize; ++btpos)
  228. {
  229. // the format of the StraceFile is very specific, to allow (kludgy) machine-parsing
  230. fprintf(StraceFile, "%-3ld ", (long)btpos);
  231. int symidx;
  232. for (symidx = 0; symidx < nSymNo; ++symidx)
  233. {
  234. if (ERR_ELFIO_NO_ERROR ==
  235.     pSymTbl->GetSymbol(symidx, name, value, ssize,
  236.        bind, type, section))
  237. {
  238. // check if trace address within symbol range
  239. if (uintptr_t(stackarray[btpos]) >= value &&
  240.     uintptr_t(stackarray[btpos]) < value+ssize)
  241. {
  242. // symbol is inside viewer
  243. fprintf(StraceFile, "%-32st", "com.secondlife.indra.viewer");
  244. fprintf(StraceFile, "%p ", stackarray[btpos]);
  245. char *demangled_str = NULL;
  246. int demangle_result = 1;
  247. demangled_str =
  248. abi::__cxa_demangle
  249. (name.c_str(), NULL, NULL,
  250.  &demangle_result);
  251. if (0 == demangle_result &&
  252.     NULL != demangled_str) {
  253. fprintf(StraceFile,
  254. "%s", demangled_str);
  255. free(demangled_str);
  256. }
  257. else // failed demangle; print it raw
  258. {
  259. fprintf(StraceFile,
  260. "%s", name.c_str());
  261. }
  262. // print offset from symbol start
  263. fprintf(StraceFile,
  264. " + %lun",
  265. uintptr_t(stackarray[btpos]) -
  266. value);
  267. goto got_sym; // early escape
  268. }
  269. }
  270. }
  271. // Fallback:
  272. // Didn't find a suitable symbol in the binary - it's probably
  273. // a symbol in a DSO; use glibc's idea of what it should be.
  274. fprintf(StraceFile, "%-32st", "unknown");
  275. fprintf(StraceFile, "%p ", stackarray[btpos]);
  276. fprintf(StraceFile, "%sn", strings[btpos]);
  277. got_sym:;
  278. }
  279. if (StraceFile != stderr)
  280. fclose(StraceFile);
  281. pSymTbl->Release();
  282. pSec->Release();
  283. pReader->Release();
  284. free(strings);
  285. llinfos << "Finished generating stack trace." << llendl;
  286. success = TRUE;
  287. return success;
  288. }
  289. #endif // LL_ELFBIN
  290. #endif // LL_SOLARIS
  291. LLAppViewerLinux::LLAppViewerLinux()
  292. {
  293. }
  294. LLAppViewerLinux::~LLAppViewerLinux()
  295. {
  296. }
  297. bool LLAppViewerLinux::init()
  298. {
  299. // g_thread_init() must be called before *any* use of glib, *and*
  300. // before any mutexes are held, *and* some of our third-party
  301. // libraries likes to use glib functions; in short, do this here
  302. // really early in app startup!
  303. if (!g_thread_supported ()) g_thread_init (NULL);
  304. return LLAppViewer::init();
  305. }
  306. bool LLAppViewerLinux::restoreErrorTrap()
  307. {
  308. // *NOTE:Mani there is a case for implementing this on the mac.
  309. // Linux doesn't need it to my knowledge.
  310. return true;
  311. }
  312. /////////////////////////////////////////
  313. #if LL_DBUS_ENABLED
  314. typedef struct
  315. {
  316.         GObjectClass parent_class;
  317. } ViewerAppAPIClass;
  318. static void viewerappapi_init(ViewerAppAPI *server);
  319. static void viewerappapi_class_init(ViewerAppAPIClass *klass);
  320. ///
  321. // regrettable hacks to give us better runtime compatibility with older systems in general
  322. static GType llg_type_register_static_simple_ONCE(GType parent_type,
  323.   const gchar *type_name,
  324.   guint class_size,
  325.   GClassInitFunc class_init,
  326.   guint instance_size,
  327.   GInstanceInitFunc instance_init,
  328.   GTypeFlags flags)
  329. {
  330. static GTypeInfo type_info;
  331. memset(&type_info, 0, sizeof(type_info));
  332. type_info.class_size = class_size;
  333. type_info.class_init = class_init;
  334. type_info.instance_size = instance_size;
  335. type_info.instance_init = instance_init;
  336. return g_type_register_static(parent_type, type_name, &type_info, flags);
  337. }
  338. #define llg_intern_static_string(S) (S)
  339. #define g_intern_static_string(S) llg_intern_static_string(S)
  340. #define g_type_register_static_simple(parent_type, type_name, class_size, class_init, instance_size, instance_init, flags) llg_type_register_static_simple_ONCE(parent_type, type_name, class_size, class_init, instance_size, instance_init, flags)
  341. G_DEFINE_TYPE(ViewerAppAPI, viewerappapi, G_TYPE_OBJECT);
  342. void viewerappapi_class_init(ViewerAppAPIClass *klass)
  343. {
  344. }
  345. static bool dbus_server_init = false;
  346. void viewerappapi_init(ViewerAppAPI *server)
  347. {
  348. // Connect to the default DBUS, register our service/API.
  349. if (!dbus_server_init)
  350. {
  351. GError *error = NULL;
  352. server->connection = lldbus_g_bus_get(DBUS_BUS_SESSION, &error);
  353. if (server->connection)
  354. {
  355. lldbus_g_object_type_install_info(viewerappapi_get_type(), &dbus_glib_viewerapp_object_info);
  356. lldbus_g_connection_register_g_object(server->connection, VIEWERAPI_PATH, G_OBJECT(server));
  357. DBusGProxy *serverproxy = lldbus_g_proxy_new_for_name(server->connection, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS);
  358. guint request_name_ret_unused;
  359. // akin to org_freedesktop_DBus_request_name
  360. if (lldbus_g_proxy_call(serverproxy, "RequestName", &error, G_TYPE_STRING, VIEWERAPI_SERVICE, G_TYPE_UINT, 0, G_TYPE_INVALID, G_TYPE_UINT, &request_name_ret_unused, G_TYPE_INVALID))
  361. {
  362. // total success.
  363. dbus_server_init = true;
  364. }
  365. else 
  366. {
  367. llwarns << "Unable to register service name: " << error->message << llendl;
  368. }
  369. g_object_unref(serverproxy);
  370. }
  371. else
  372. {
  373. g_warning("Unable to connect to dbus: %s", error->message);
  374. }
  375. if (error)
  376. g_error_free(error);
  377. }
  378. }
  379. gboolean viewer_app_api_GoSLURL(ViewerAppAPI *obj, gchar *slurl, gboolean **success_rtn, GError **error)
  380. {
  381. bool success = false;
  382. llinfos << "Was asked to go to slurl: " << slurl << llendl;
  383. std::string url = slurl;
  384. LLMediaCtrl* web = NULL;
  385. const bool trusted_browser = false;
  386. if (LLURLDispatcher::dispatch(url, web, trusted_browser))
  387. {
  388. // bring window to foreground, as it has just been "launched" from a URL
  389. // todo: hmm, how to get there from here?
  390. //xxx->mWindow->bringToFront();
  391. success = true;
  392. }
  393. *success_rtn = g_new (gboolean, 1);
  394. (*success_rtn)[0] = (gboolean)success;
  395. return TRUE; // the invokation succeeded, even if the actual dispatch didn't.
  396. }
  397. ///
  398. //virtual
  399. bool LLAppViewerLinux::initSLURLHandler()
  400. {
  401. if (!grab_dbus_syms(DBUSGLIB_DYLIB_DEFAULT_NAME))
  402. {
  403. return false; // failed
  404. }
  405. g_type_init();
  406. //ViewerAppAPI *api_server = (ViewerAppAPI*)
  407. g_object_new(viewerappapi_get_type(), NULL);
  408. return true;
  409. }
  410. //virtual
  411. bool LLAppViewerLinux::sendURLToOtherInstance(const std::string& url)
  412. {
  413. if (!grab_dbus_syms(DBUSGLIB_DYLIB_DEFAULT_NAME))
  414. {
  415. return false; // failed
  416. }
  417. bool success = false;
  418. DBusGConnection *bus;
  419. GError *error = NULL;
  420. g_type_init();
  421. bus = lldbus_g_bus_get (DBUS_BUS_SESSION, &error);
  422. if (bus)
  423. {
  424. gboolean rtn = FALSE;
  425. DBusGProxy *remote_object =
  426. lldbus_g_proxy_new_for_name(bus, VIEWERAPI_SERVICE, VIEWERAPI_PATH, VIEWERAPI_INTERFACE);
  427. if (lldbus_g_proxy_call(remote_object, "GoSLURL", &error,
  428. G_TYPE_STRING, url.c_str(), G_TYPE_INVALID,
  429.        G_TYPE_BOOLEAN, &rtn, G_TYPE_INVALID))
  430. {
  431. success = rtn;
  432. }
  433. else
  434. {
  435. llinfos << "Call-out to other instance failed (perhaps not running): " << error->message << llendl;
  436. }
  437. g_object_unref(G_OBJECT(remote_object));
  438. }
  439. else
  440. {
  441. llwarns << "Couldn't connect to session bus: " << error->message << llendl;
  442. }
  443. if (error)
  444. g_error_free(error);
  445. return success;
  446. }
  447. #else // LL_DBUS_ENABLED
  448. bool LLAppViewerLinux::initSLURLHandler()
  449. {
  450. return false; // not implemented without dbus
  451. }
  452. bool LLAppViewerLinux::sendURLToOtherInstance(const std::string& url)
  453. {
  454. return false; // not implemented without dbus
  455. }
  456. #endif // LL_DBUS_ENABLED
  457. void LLAppViewerLinux::handleSyncCrashTrace()
  458. {
  459. // This backtrace writes into stack_trace.log
  460. #  if LL_ELFBIN
  461. do_elfio_glibc_backtrace(); // more useful backtrace
  462. #  else
  463. do_basic_glibc_backtrace(); // only slightly useful backtrace
  464. #  endif // LL_ELFBIN
  465. }
  466. void LLAppViewerLinux::handleCrashReporting(bool reportFreeze)
  467. {
  468. std::string cmd =gDirUtilp->getExecutableDir();
  469. cmd += gDirUtilp->getDirDelimiter();
  470. #if LL_LINUX
  471. cmd += "linux-crash-logger.bin";
  472. #elif LL_SOLARIS
  473. cmd += "solaris-crash-logger";
  474. #else
  475. # error Unknown platform
  476. #endif
  477. if(reportFreeze)
  478. {
  479. char* const cmdargv[] =
  480. {(char*)cmd.c_str(),
  481.  (char*)"-previous",
  482.  NULL};
  483. fflush(NULL); // flush all buffers before the child inherits them
  484. pid_t pid = fork();
  485. if (pid == 0)
  486. { // child
  487. execv(cmd.c_str(), cmdargv); /* Flawfinder: Ignore */
  488. llwarns << "execv failure when trying to start " << cmd << llendl;
  489. _exit(1); // avoid atexit()
  490. } else {
  491. if (pid > 0)
  492. {
  493. // wait for child proc to die
  494. int childExitStatus;
  495. waitpid(pid, &childExitStatus, 0);
  496. } else {
  497. llwarns << "fork failure." << llendl;
  498. }
  499. }
  500. }
  501. else
  502. {
  503. const S32 cb = gCrashSettings.getS32(CRASH_BEHAVIOR_SETTING);
  504. // Always generate the report, have the logger do the asking, and
  505. // don't wait for the logger before exiting (-> total cleanup).
  506. if (CRASH_BEHAVIOR_NEVER_SEND != cb)
  507. {
  508. // launch the actual crash logger
  509. const char* ask_dialog = "-dialog";
  510. if (CRASH_BEHAVIOR_ASK != cb)
  511. ask_dialog = ""; // omit '-dialog' option
  512. const char * cmdargv[] =
  513. {cmd.c_str(),
  514.  ask_dialog,
  515.  "-user",
  516.  (char*)LLViewerLogin::getInstance()->getGridLabel().c_str(),
  517.  "-name",
  518.  LLAppViewer::instance()->getSecondLifeTitle().c_str(),
  519.  NULL};
  520. fflush(NULL);
  521. pid_t pid = fork();
  522. if (pid == 0)
  523. { // child
  524. execv(cmd.c_str(), (char* const*) cmdargv); /* Flawfinder: ignore */
  525. llwarns << "execv failure when trying to start " << cmd << llendl;
  526. _exit(1); // avoid atexit()
  527. else
  528. {
  529. if (pid > 0)
  530. {
  531. // DO NOT wait for child proc to die; we want
  532. // the logger to outlive us while we quit to
  533. // free up the screen/keyboard/etc.
  534. ////int childExitStatus;
  535. ////waitpid(pid, &childExitStatus, 0);
  536. else
  537. {
  538. llwarns << "fork failure." << llendl;
  539. }
  540. }
  541. }
  542. // Sometimes signals don't seem to quit the viewer.  Also, we may
  543. // have been called explicitly instead of from a signal handler.
  544. // Make sure we exit so as to not totally confuse the user.
  545. _exit(1); // avoid atexit(), else we may re-crash in dtors.
  546. }
  547. }
  548. bool LLAppViewerLinux::beingDebugged()
  549. {
  550. static enum {unknown, no, yes} debugged = unknown;
  551. #if LL_SOLARIS
  552. return debugged == no; // BUG: fix this for Solaris
  553. #else
  554. if (debugged == unknown)
  555. {
  556. pid_t ppid = getppid();
  557. char *name;
  558. int ret;
  559. ret = asprintf(&name, "/proc/%d/exe", ppid);
  560. if (ret != -1)
  561. {
  562. char buf[1024];
  563. ssize_t n;
  564. n = readlink(name, buf, sizeof(buf) - 1);
  565. if (n != -1)
  566. {
  567. char *base = strrchr(buf, '/');
  568. buf[n + 1] = '';
  569. if (base == NULL)
  570. {
  571. base = buf;
  572. } else {
  573. base += 1;
  574. }
  575. if (strcmp(base, "gdb") == 0)
  576. {
  577. debugged = yes;
  578. }
  579. }
  580. free(name);
  581. }
  582. }
  583. return debugged == yes;
  584. #endif
  585. }
  586. bool LLAppViewerLinux::initLogging()
  587. {
  588. // Remove the last stack trace, if any
  589. std::string old_stack_file =
  590. gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log");
  591. LLFile::remove(old_stack_file);
  592. return LLAppViewer::initLogging();
  593. }
  594. bool LLAppViewerLinux::initParseCommandLine(LLCommandLineParser& clp)
  595. {
  596. if (!clp.parseCommandLine(gArgC, gArgV))
  597. {
  598. return false;
  599. }
  600. // Find the system language.
  601. FL_Locale *locale = NULL;
  602. FL_Success success = FL_FindLocale(&locale, FL_MESSAGES);
  603. if (success != 0)
  604. {
  605. if (success >= 2 && locale->lang) // confident!
  606. {
  607. LL_INFOS("AppInit") << "Language " << ll_safe_string(locale->lang) << LL_ENDL;
  608. LL_INFOS("AppInit") << "Location " << ll_safe_string(locale->country) << LL_ENDL;
  609. LL_INFOS("AppInit") << "Variant " << ll_safe_string(locale->variant) << LL_ENDL;
  610. LLControlVariable* c = gSavedSettings.getControl("SystemLanguage");
  611. if(c)
  612. {
  613. c->setValue(std::string(locale->lang), false);
  614. }
  615. }
  616. }
  617. FL_FreeLocale(&locale);
  618. return true;
  619. }
  620. std::string LLAppViewerLinux::generateSerialNumber()
  621. {
  622. char serial_md5[MD5HEX_STR_SIZE];
  623. serial_md5[0] = 0;
  624. std::string best;
  625. std::string uuiddir("/dev/disk/by-uuid/");
  626. // trawl /dev/disk/by-uuid looking for a good-looking UUID to grab
  627. std::string this_name;
  628. BOOL wrap = FALSE;
  629. while (gDirUtilp->getNextFileInDir(uuiddir, "*", this_name, wrap))
  630. {
  631. if (this_name.length() > best.length() ||
  632.     (this_name.length() == best.length() &&
  633.      this_name > best))
  634. {
  635. // longest (and secondarily alphabetically last) so far
  636. best = this_name;
  637. }
  638. }
  639. // we don't return the actual serial number, just a hash of it.
  640. LLMD5 md5( reinterpret_cast<const unsigned char*>(best.c_str()) );
  641. md5.hex_digest(serial_md5);
  642. return serial_md5;
  643. }